summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2015-07-30 11:14:54 +0200
committerAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-07-30 09:17:53 +0000
commit154d7a3611197845352b3e1d3ebeaf429d37e656 (patch)
treecf16ceb8d3f3a4768108e97e4a677e8fd3550396
parent337abb1a5c73f76ffb8f989c5031cc7a908f472c (diff)
parentf61ab1ac7f855cd281809255c0aedbb1895e1823 (diff)
downloadqtwebengine-chromium-154d7a3611197845352b3e1d3ebeaf429d37e656.tar.gz
Merge branch 'upstream-master' into 44-based
Change-Id: Ie5db510a9470dacbb91c4ab8fa7c73e2dee7d6a1
-rw-r--r--chromium/DEPS12
-rw-r--r--chromium/base/base_switches.cc5
-rw-r--r--chromium/base/base_switches.h4
-rw-r--r--chromium/base/win/win_util.cc92
-rw-r--r--chromium/base/win/win_util.h5
-rw-r--r--chromium/build/util/LASTCHANGE2
-rw-r--r--chromium/build/util/LASTCHANGE.blink2
-rw-r--r--chromium/chrome/VERSION2
-rw-r--r--chromium/chrome/app/resources/chromium_strings_kn.xtb2
-rw-r--r--chromium/chrome/app/resources/generated_resources_es.xtb2
-rw-r--r--chromium/chrome/app/resources/generated_resources_fa.xtb2
-rw-r--r--chromium/chrome/app/resources/generated_resources_ml.xtb8
-rw-r--r--chromium/chrome/app/resources/generated_resources_no.xtb2
-rw-r--r--chromium/chrome/app/resources/generated_resources_sk.xtb2
-rw-r--r--chromium/chrome/app/resources/google_chrome_strings_kn.xtb2
-rw-r--r--chromium/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js3
-rw-r--r--chromium/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js9
-rw-r--r--chromium/chrome/browser/resources/inspect/inspect.css21
-rw-r--r--chromium/chrome/chrome_browser.gypi2
-rw-r--r--chromium/chrome/chrome_installer.gypi5
-rw-r--r--chromium/chrome/chrome_tests_unit.gypi1
-rw-r--r--chromium/chrome_elf/blacklist/blacklist.cc1
-rw-r--r--chromium/content/browser/android/content_view_core_impl.cc1
-rw-r--r--chromium/content/browser/android/download_controller_android_impl.cc102
-rw-r--r--chromium/content/browser/android/download_controller_android_impl.h13
-rw-r--r--chromium/content/browser/appcache/appcache_backend_impl.cc6
-rw-r--r--chromium/content/browser/appcache/appcache_host.cc10
-rw-r--r--chromium/content/browser/appcache/appcache_host.h4
-rw-r--r--chromium/content/browser/appcache/appcache_response.cc5
-rw-r--r--chromium/content/browser/appcache/view_appcache_internals_job.cc4
-rw-r--r--chromium/content/browser/download/download_stats.cc17
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_request_job.cc79
-rw-r--r--chromium/content/browser/web_contents/web_contents_android.cc4
-rw-r--r--chromium/content/common/gpu/gpu_command_buffer_stub.cc3
-rw-r--r--chromium/content/content_browser.gypi1
-rw-r--r--chromium/content/public/browser/android/download_controller_android.cc13
-rw-r--r--chromium/content/public/browser/android/download_controller_android.h19
-rw-r--r--chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc20
-rw-r--r--chromium/device/hid/hid_connection_mac.cc7
-rw-r--r--chromium/google_apis/gcm/base/socket_stream.cc2
-rw-r--r--chromium/gpu/config/gpu_driver_bug_list_json.cc18
-rw-r--r--chromium/gpu/config/gpu_driver_bug_workaround_type.h2
-rw-r--r--chromium/media/cdm/aes_decryptor.cc9
-rw-r--r--chromium/media/cdm/aes_decryptor.h2
-rw-r--r--chromium/media/renderers/video_renderer_impl.cc2
-rw-r--r--chromium/media/renderers/video_renderer_impl.h2
-rw-r--r--chromium/net/base/io_buffer.cc46
-rw-r--r--chromium/net/base/io_buffer.h12
-rw-r--r--chromium/net/log/net_log_event_type_list.h69
-rw-r--r--chromium/net/quic/quic_http_stream.cc3
-rw-r--r--chromium/net/quic/quic_packet_reader.cc2
-rw-r--r--chromium/net/socket/ssl_client_socket_nss.cc2
-rw-r--r--chromium/net/socket/ssl_server_socket_nss.cc2
-rw-r--r--chromium/net/websockets/websocket_deflater.cc5
-rw-r--r--chromium/net/websockets/websocket_inflater.cc6
-rw-r--r--chromium/third_party/WebKit/Source/core/css/parser/CSSParser.cpp4
-rw-r--r--chromium/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp4
-rw-r--r--chromium/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h2
-rw-r--r--chromium/third_party/WebKit/Source/core/dom/NodeRareData.cpp6
-rw-r--r--chromium/third_party/WebKit/Source/core/dom/NodeRareData.h5
-rw-r--r--chromium/third_party/WebKit/Source/core/editing/htmlediting.cpp4
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/LocalFrame.cpp2
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/UseCounter.cpp2
-rw-r--r--chromium/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp4
-rw-r--r--chromium/third_party/WebKit/Source/core/html/HTMLImageElement.cpp6
-rw-r--r--chromium/third_party/WebKit/Source/core/loader/FrameLoader.cpp3
-rw-r--r--chromium/third_party/WebKit/Source/core/timing/ConsoleMemory.cpp11
-rw-r--r--chromium/third_party/WebKit/Source/core/timing/ConsoleMemory.h4
-rw-r--r--chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp3
-rw-r--r--chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequestProgressEventThrottle.cpp14
-rw-r--r--chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequestProgressEventThrottle.h6
-rw-r--r--chromium/third_party/WebKit/Source/devtools/front_end/elements/spectrum.css1
-rw-r--r--chromium/third_party/WebKit/Source/devtools/front_end/emulation/EmulatedDevices.js1
-rw-r--r--chromium/third_party/WebKit/Source/modules/accessibility/AXMenuListOption.cpp4
-rw-r--r--chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp1
-rw-r--r--chromium/third_party/ashmem/BUILD.gn12
-rw-r--r--chromium/third_party/ashmem/LICENSE202
-rw-r--r--chromium/third_party/ashmem/OWNERS1
-rw-r--r--chromium/third_party/ashmem/README.chromium6
-rw-r--r--chromium/third_party/ashmem/ashmem-dev.c100
-rw-r--r--chromium/third_party/ashmem/ashmem.h46
-rw-r--r--chromium/third_party/expat/README.chromium5
-rw-r--r--chromium/third_party/expat/files/lib/xmlparse.c23
-rw-r--r--chromium/third_party/expat/files/lib/xmlparse.c.original6403
-rw-r--r--chromium/third_party/pdfium/pdfium.gyp1
-rw-r--r--chromium/third_party/skia/PRESUBMIT.py8
-rw-r--r--chromium/third_party/skia/include/core/SkMatrix.h6
-rw-r--r--chromium/third_party/skia/include/core/SkPackBits.h47
-rw-r--r--chromium/third_party/skia/include/core/SkPicture.h5
-rw-r--r--chromium/third_party/skia/src/core/SkData.cpp9
-rw-r--r--chromium/third_party/skia/src/core/SkMatrix.cpp95
-rw-r--r--chromium/third_party/skia/src/core/SkPackBits.cpp352
-rw-r--r--chromium/third_party/skia/src/core/SkPictureShader.cpp37
-rw-r--r--chromium/third_party/skia/src/core/SkReadBuffer.h3
-rw-r--r--chromium/third_party/skia/src/effects/SkTableColorFilter.cpp7
-rw-r--r--chromium/third_party/undoview/LICENSE502
-rw-r--r--chromium/third_party/undoview/README.chromium13
-rw-r--r--chromium/third_party/undoview/undo_manager.c1110
-rw-r--r--chromium/third_party/undoview/undo_manager.h86
-rw-r--r--chromium/third_party/undoview/undo_view.c83
-rw-r--r--chromium/third_party/undoview/undo_view.h50
-rw-r--r--chromium/third_party/webrtc/modules/audio_processing/aec/aec_core.c107
-rw-r--r--chromium/third_party/webrtc/modules/audio_processing/aec/aec_core_internal.h1
-rw-r--r--chromium/third_party/webrtc/modules/audio_processing/aec/echo_cancellation.c18
-rw-r--r--chromium/third_party/webrtc/modules/audio_processing/aec/system_delay_unittest.cc433
-rw-r--r--chromium/third_party/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.cc40
-rw-r--r--chromium/third_party/webrtc/modules/rtp_rtcp/source/fec_receiver_unittest.cc176
-rw-r--r--chromium/third_party/webrtc/modules/rtp_rtcp/source/forward_error_correction.cc49
-rw-r--r--chromium/third_party/webrtc/modules/rtp_rtcp/source/forward_error_correction.h6
-rw-r--r--chromium/third_party/webrtc/modules/rtp_rtcp/source/h264_sps_parser.cc4
-rw-r--r--chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc24
-rw-r--r--chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc32
-rw-r--r--chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc3
-rw-r--r--chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc4
-rw-r--r--chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc7
-rw-r--r--chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc3
-rw-r--r--chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc2
-rw-r--r--chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc4
-rw-r--r--chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_utility.cc2
-rw-r--r--chromium/third_party/webrtc/video/rampup_tests.cc9
-rwxr-xr-xchromium/tools/compile_test/compile_test.py65
-rw-r--r--chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_kn.xtb2
-rw-r--r--chromium/ui/base/ime/input_method_win.cc16
-rw-r--r--chromium/ui/views/controls/textfield/textfield.cc11
-rw-r--r--chromium/ui/views/controls/textfield/textfield.h1
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc12
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h5
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc27
-rw-r--r--chromium/ui/views/widget/native_widget_aura.cc5
-rw-r--r--chromium/v8/include/v8-version.h2
-rw-r--r--chromium/v8/src/arm64/code-stubs-arm64.cc32
-rw-r--r--chromium/v8/src/flag-definitions.h2
-rw-r--r--chromium/v8/src/ic/ic.cc48
-rw-r--r--chromium/v8/src/objects.cc80
-rw-r--r--chromium/v8/src/snapshot/serialize.cc24
-rw-r--r--chromium/v8/src/unicode-decoder.cc10
-rw-r--r--chromium/v8/src/unicode-decoder.h8
137 files changed, 8092 insertions, 3159 deletions
diff --git a/chromium/DEPS b/chromium/DEPS
index df3a48d0b90..932d24e37dd 100644
--- a/chromium/DEPS
+++ b/chromium/DEPS
@@ -6,7 +6,7 @@ vars = {
'boringssl_revision':
'a07c0fc8f2181d086b1118712e2ceb0d1496fa0b',
'buildspec_platforms':
- 'all',
+ 'android,',
'buildtools_revision':
'b73e5f70d7ac6be98fb2555461f631afc90216ce',
'chromium_git':
@@ -84,7 +84,7 @@ deps = {
'src/testing/gtest':
(Var("chromium_git")) + '/external/googletest.git@23574bf2333f834ff665f894c97bef8a5b33a0a9',
'src/third_party/WebKit':
- (Var("chromium_git")) + '/chromium/blink.git@9efa5a2a3268eb19abfb6ef748267617cdd6adc4',
+ (Var("chromium_git")) + '/chromium/blink.git@2a6ea957194f0008cc4ab0763e0d35d29fe18310',
'src/third_party/angle':
(Var("chromium_git")) + '/angle/angle.git@fa9744b09e2478c75a25fd1b497469d429e81591',
'src/third_party/bidichecker':
@@ -140,7 +140,7 @@ deps = {
'src/third_party/opus/src':
(Var("chromium_git")) + '/chromium/deps/opus.git@cae696156f1e60006e39821e79a1811ae1933c69',
'src/third_party/pdfium':
- (Var("pdfium_git")) + '/pdfium.git@a967306a353cce18b2276e9d8f653e989c6fa6e5',
+ (Var("pdfium_git")) + '/pdfium.git@12d0f7b4eae9c2b40433500b15955f61050132aa',
'src/third_party/py_trace_event/src':
(Var("chromium_git")) + '/external/py_trace_event.git@dd463ea9e2c430de2b9e53dea57a77b4c3ac9b30',
'src/third_party/pyftpdlib/src':
@@ -154,7 +154,7 @@ deps = {
'src/third_party/sfntly/cpp/src':
(Var("chromium_git")) + '/external/sfntly/cpp/src.git@1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
'src/third_party/skia':
- (Var("chromium_git")) + '/skia.git@31cd6a030218373587a7ba943e4d76e96a71f207',
+ (Var("chromium_git")) + '/skia.git@ee68678f0051e71efeb6affc3f4a071b7ac1c1bd',
'src/third_party/smhasher/src':
(Var("chromium_git")) + '/external/smhasher.git@e87738e57558e0ec472b2fc3a643b838e5b6e88f',
'src/third_party/snappy/src':
@@ -170,7 +170,7 @@ deps = {
'src/third_party/webpagereplay':
(Var("chromium_git")) + '/external/github.com/chromium/web-page-replay.git@e53550b73e8e098938a651bc8ceb3681e5980567',
'src/third_party/webrtc':
- (Var("chromium_git")) + '/external/webrtc/trunk/webrtc.git@1cb9d1223356c551a92bd9da41a3eddce15bee64',
+ (Var("chromium_git")) + '/external/webrtc/trunk/webrtc.git@e725d9de25a3809bce4626831f385830e91695ff',
'src/third_party/yasm/source/patched-yasm':
(Var("chromium_git")) + '/chromium/deps/yasm/patched-yasm.git@4671120cd8558ce62ee8672ebf3eb6f5216f909b',
'src/tools/deps2git':
@@ -184,7 +184,7 @@ deps = {
'src/tools/swarming_client':
(Var("chromium_git")) + '/external/swarming.client.git@b39a448d8522392389b28f6997126a6ab04bfe87',
'src/v8':
- (Var("chromium_git")) + '/v8/v8.git@d30aacbd824b9a10afc352417c70e2ea3004cd68'
+ (Var("chromium_git")) + '/v8/v8.git@3809b683c9c90d7b9a9020ea0118417e8b13e6ad'
}
deps_os = {
diff --git a/chromium/base/base_switches.cc b/chromium/base/base_switches.cc
index 30765405de1..7f3be7f516c 100644
--- a/chromium/base/base_switches.cc
+++ b/chromium/base/base_switches.cc
@@ -67,6 +67,11 @@ const char kProfilerTiming[] = "profiler-timing";
// chrome://profiler.
const char kProfilerTimingDisabledValue[] = "0";
+#if defined(OS_WIN)
+// Disables the USB keyboard detection for blocking the OSK on Win8+.
+const char kDisableUsbKeyboardDetect[] = "disable-usb-keyboard-detect";
+#endif
+
#if defined(OS_POSIX)
// Used for turning on Breakpad crash reporting in a debug environment where
// crash reporting is typically compiled but disabled.
diff --git a/chromium/base/base_switches.h b/chromium/base/base_switches.h
index c579f6a240d..bbd590bad05 100644
--- a/chromium/base/base_switches.h
+++ b/chromium/base/base_switches.h
@@ -27,6 +27,10 @@ extern const char kV[];
extern const char kVModule[];
extern const char kWaitForDebugger[];
+#if defined(OS_WIN)
+extern const char kDisableUsbKeyboardDetect[];
+#endif
+
#if defined(OS_POSIX)
extern const char kEnableCrashReporterForTesting[];
#endif
diff --git a/chromium/base/win/win_util.cc b/chromium/base/win/win_util.cc
index c5b06c48f8a..6f8cdaf5fda 100644
--- a/chromium/base/win/win_util.cc
+++ b/chromium/base/win/win_util.cc
@@ -19,11 +19,14 @@
#include <signal.h>
#include <stdlib.h>
+#include "base/base_switches.h"
+#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "base/win/metro.h"
#include "base/win/registry.h"
@@ -32,6 +35,9 @@
#include "base/win/scoped_propvariant.h"
#include "base/win/windows_version.h"
+namespace base {
+namespace win {
+
namespace {
// Sets the value of |property_key| to |property_value| in |property_store|.
@@ -55,24 +61,50 @@ const wchar_t kWindows8OSKRegPath[] =
L"Software\\Classes\\CLSID\\{054AAE20-4BEA-4347-8A35-64A533254A9D}"
L"\\LocalServer32";
+} // namespace
+
// Returns true if a physical keyboard is detected on Windows 8 and up.
// Uses the Setup APIs to enumerate the attached keyboards and returns true
// if the keyboard count is 1 or more.. While this will work in most cases
// it won't work if there are devices which expose keyboard interfaces which
// are attached to the machine.
-bool IsKeyboardPresentOnSlate() {
+bool IsKeyboardPresentOnSlate(std::string* reason) {
+ bool result = false;
+
+ if (GetVersion() < VERSION_WIN7) {
+ if (reason)
+ *reason = "Detection not supported";
+ return false;
+ }
+
// This function is only supported for Windows 8 and up.
- DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN8);
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableUsbKeyboardDetect)) {
+ if (reason)
+ *reason = "Detection disabled";
+ return false;
+ }
// This function should be only invoked for machines with touch screens.
if ((GetSystemMetrics(SM_DIGITIZER) & NID_INTEGRATED_TOUCH)
!= NID_INTEGRATED_TOUCH) {
- return true;
+ if (reason) {
+ *reason += "NID_INTEGRATED_TOUCH\n";
+ result = true;
+ } else {
+ return true;
+ }
}
// If the device is docked, the user is treating the device as a PC.
- if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0)
- return true;
+ if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0) {
+ if (reason) {
+ *reason += "SM_SYSTEMDOCKED\n";
+ result = true;
+ } else {
+ return true;
+ }
+ }
// To determine whether a keyboard is present on the device, we do the
// following:-
@@ -103,7 +135,13 @@ bool IsKeyboardPresentOnSlate() {
// If there is no auto rotation sensor or rotation is not supported in
// the current configuration, then we can assume that this is a desktop
// or a traditional laptop.
- return true;
+ if (reason) {
+ *reason += (auto_rotation_state & AR_NOSENSOR) ? "AR_NOSENSOR\n" :
+ "AR_NOT_SUPPORTED\n";
+ result = true;
+ } else {
+ return true;
+ }
}
}
@@ -114,8 +152,15 @@ bool IsKeyboardPresentOnSlate() {
POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole();
if (((role == PlatformRoleMobile) || (role == PlatformRoleSlate)) &&
- (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0))
- return false;
+ (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0)) {
+ if (reason) {
+ *reason += (role == PlatformRoleMobile) ? "PlatformRoleMobile\n" :
+ "PlatformRoleSlate\n";
+ // Don't change result here if it's already true.
+ } else {
+ return false;
+ }
+ }
const GUID KEYBOARD_CLASS_GUID =
{ 0x4D36E96B, 0xE325, 0x11CE,
@@ -124,13 +169,15 @@ bool IsKeyboardPresentOnSlate() {
// Query for all the keyboard devices.
HDEVINFO device_info =
SetupDiGetClassDevs(&KEYBOARD_CLASS_GUID, NULL, NULL, DIGCF_PRESENT);
- if (device_info == INVALID_HANDLE_VALUE)
- return false;
+ if (device_info == INVALID_HANDLE_VALUE) {
+ if (reason)
+ *reason += "No keyboard info\n";
+ return result;
+ }
// Enumerate all keyboards and look for ACPI\PNP and HID\VID devices. If
// the count is more than 1 we assume that a keyboard is present. This is
// under the assumption that there will always be one keyboard device.
- int keyboard_count = 0;
for (DWORD i = 0;; ++i) {
SP_DEVINFO_DATA device_info_data = { 0 };
device_info_data.cbSize = sizeof(device_info_data);
@@ -148,21 +195,22 @@ bool IsKeyboardPresentOnSlate() {
// prefixes in the keyboard device ids.
if (StartsWith(device_id, L"ACPI", false) ||
StartsWith(device_id, L"HID\\VID", false)) {
- keyboard_count++;
+ if (reason) {
+ *reason += "device: ";
+ *reason += WideToUTF8(device_id);
+ *reason += '\n';
+ }
+ // The heuristic we are using is to check the count of keyboards and
+ // return true if the API's report one or more keyboards. Please note
+ // that this will break for non keyboard devices which expose a
+ // keyboard PDO.
+ result = true;
}
}
}
- // The heuristic we are using is to check the count of keyboards and return
- // true if the API's report one or more keyboards. Please note that this
- // will break for non keyboard devices which expose a keyboard PDO.
- return keyboard_count >= 1;
+ return result;
}
-} // namespace
-
-namespace base {
-namespace win {
-
static bool g_crash_on_process_detach = false;
void GetNonClientMetrics(NONCLIENTMETRICS_XP* metrics) {
@@ -352,7 +400,7 @@ bool DisplayVirtualKeyboard() {
if (base::win::GetVersion() < base::win::VERSION_WIN8)
return false;
- if (IsKeyboardPresentOnSlate())
+ if (IsKeyboardPresentOnSlate(nullptr))
return false;
static base::LazyInstance<string16>::Leaky osk_path =
diff --git a/chromium/base/win/win_util.h b/chromium/base/win/win_util.h
index 8513f62bf19..9f42e445748 100644
--- a/chromium/base/win/win_util.h
+++ b/chromium/base/win/win_util.h
@@ -132,6 +132,11 @@ BASE_EXPORT void SetAbortBehaviorForCrashReporting();
// insight into how users use Chrome.
BASE_EXPORT bool IsTabletDevice();
+// A slate is a touch device that may have a keyboard attached. This function
+// returns true if a keyboard is attached and optionally will set the reason
+// parameter to the detection method that was used to detect the keyboard.
+BASE_EXPORT bool IsKeyboardPresentOnSlate(std::string* reason);
+
// Get the size of a struct up to and including the specified member.
// This is necessary to set compatible struct sizes for different versions
// of certain Windows APIs (e.g. SystemParametersInfo).
diff --git a/chromium/build/util/LASTCHANGE b/chromium/build/util/LASTCHANGE
index f943281196c..5cecdbfc2ca 100644
--- a/chromium/build/util/LASTCHANGE
+++ b/chromium/build/util/LASTCHANGE
@@ -1 +1 @@
-LASTCHANGE=d86a20264058bb1fb3cae639239a2cadfaf0bce6
+LASTCHANGE=5aba4ca83214d51422f8b1804c68fa1762456d5c
diff --git a/chromium/build/util/LASTCHANGE.blink b/chromium/build/util/LASTCHANGE.blink
index f5a592d2728..8fb14b5668b 100644
--- a/chromium/build/util/LASTCHANGE.blink
+++ b/chromium/build/util/LASTCHANGE.blink
@@ -1 +1 @@
-LASTCHANGE=08d1e41ccde43ed7bb38137c9d05e4ba4da473f3
+LASTCHANGE=9d63410d9b510e7261ccd72b017e6dbee5f4891d
diff --git a/chromium/chrome/VERSION b/chromium/chrome/VERSION
index 5c7647f906a..b789fa10bf0 100644
--- a/chromium/chrome/VERSION
+++ b/chromium/chrome/VERSION
@@ -1,4 +1,4 @@
MAJOR=44
MINOR=0
BUILD=2403
-PATCH=80
+PATCH=91
diff --git a/chromium/chrome/app/resources/chromium_strings_kn.xtb b/chromium/chrome/app/resources/chromium_strings_kn.xtb
index 8f99c62da0d..59b3c4028ee 100644
--- a/chromium/chrome/app/resources/chromium_strings_kn.xtb
+++ b/chromium/chrome/app/resources/chromium_strings_kn.xtb
@@ -14,7 +14,7 @@
<translation id="59625444380784159">ನಿಮ್ಮ ಸಂಪರ್ಕಗಳಲ್ಲಿರುವ ವಿವರಗಳು Chromium ನಲ್ಲಿ ಹೆಚ್ಚು ತ್ವರಿತವಾಗಿ ಫಾರ್ಮ್‌ಗಳನ್ನು ತುಂಬಲು ನಿಮಗೆ ನೆರವಾಗಬಹುದು.</translation>
<translation id="3748537968684000502">ನೀವು ಸುರಕ್ಷಿತ Chromium ಪುಟವನ್ನು ವೀಕ್ಷಿಸುತ್ತಿರುವಿರಿ.</translation>
<translation id="2077129598763517140">ಲಭ್ಯವಿರುವಾಗ ಹಾರ್ಡ್‌ವೇರ್ ಆಕ್ಸಲರೇಶನ್ ಬಳಸು</translation>
-<translation id="1065672644894730302">ನಿಮ್ಮ ಪ್ರಾಶಸ್ತ್ಯಗಳನ್ನು ಓದಲಾಗುವುದಿಲ್ಲ. ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳು ಲಭ್ಯವಿಲ್ಲದಿರಬಹುದು ಮತ್ತು ಆದ್ಯತೆಗಳ ಬದಲಾವಣೆಗಳನ್ನು ಉಳಿಸಲಾಗುವುದಿಲ್ಲ.</translation>
+<translation id="1065672644894730302">ನಿಮ್ಮ ಪ್ರಾಶಸ್ತ್ಯಗಳನ್ನು ರೀಡ್‌ ಮಾಡಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಅಲ್ಲದೇ, ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳು ಲಭ್ಯವಿಲ್ಲದಿರಬಹುದು ಮತ್ತು ಪ್ರಾಶಸ್ತ್ಯಗಳಲ್ಲಿ ಮಾಡಿದ ಬದಲಾವಣೆಗಳನ್ನು ಉಳಿಸಲಾಗುವುದಿಲ್ಲ.</translation>
<translation id="7861509383340276692">ಇದಕ್ಕೆ ಹೋಗಿ
Chromium ಮೆನು &gt;
<ph name="SETTINGS_TITLE"/>
diff --git a/chromium/chrome/app/resources/generated_resources_es.xtb b/chromium/chrome/app/resources/generated_resources_es.xtb
index d869bfa4f67..2dd8d16216a 100644
--- a/chromium/chrome/app/resources/generated_resources_es.xtb
+++ b/chromium/chrome/app/resources/generated_resources_es.xtb
@@ -4675,7 +4675,7 @@ Después de crear un nuevo usuario supervisado, podrás administrar su configura
<translation id="7199540622786492483"><ph name="PRODUCT_NAME"/> no está actualizado porque no se ha reiniciado en algún tiempo. Hay una actualización disponible, que se aplicará en cuanto reinicies la aplicación.</translation>
<translation id="2171101176734966184">Has intentado acceder a <ph name="DOMAIN"/>, pero el servidor ha presentado un certificado firmado con un algoritmo de firma no seguro. Una posible causa de este problema es que se hayan falsificado las credenciales de seguridad presentadas por el servidor y que hayas accedido a la página de un atacante en lugar de establecer conexión con el servidor en cuestión.</translation>
<translation id="3726527440140411893">Se han habilitado las siguientes cookies al visitar esta página:</translation>
-<translation id="6989763994942163495">Mostrar opciones avanzadas...</translation>
+<translation id="6989763994942163495">Mostrar configuración avanzada...</translation>
<translation id="3320859581025497771">tu operador de telefonía</translation>
<translation id="580961539202306967">Preguntarme cuando un sitio quiera enviarme mensajes push (recomendado)</translation>
<translation id="2233502537820838181">&amp;Más información</translation>
diff --git a/chromium/chrome/app/resources/generated_resources_fa.xtb b/chromium/chrome/app/resources/generated_resources_fa.xtb
index ebc639aaef9..e03e3165e1c 100644
--- a/chromium/chrome/app/resources/generated_resources_fa.xtb
+++ b/chromium/chrome/app/resources/generated_resources_fa.xtb
@@ -2205,7 +2205,7 @@
<translation id="8525306231823319788">تمام صفحه</translation>
<translation id="5892507820957994680">‏لیست تفسیر و اجرای نرم‌افزار داخلی را لغو می‌کند و شتاب دهنده GPU را در پیکربندی های سیستم پشتیبانی نشده فعال می‌کند.</translation>
<translation id="255632937203580977">اعلان‌های کشف دستگاه</translation>
-<translation id="6407080938771313237">‏HUD لمسی سه‌بعدی</translation>
+<translation id="6407080938771313237">رابط لمسی پروژکتوری</translation>
<translation id="6122093587541546701">ایمیل (اختیاری):</translation>
<translation id="3058212636943679650">‏در صورتی که لازم شود سیستم عامل رایانهٔ خود را بازیابی کنید، به یک کارت SD بازیابی یا کارت حافظهٔ USB نیاز خواهید داشت.</translation>
<translation id="3630740432041748414">مدیریت تنظیمات وب‌سایت را در صفحه تنظیمات فعال می‌کند.</translation>
diff --git a/chromium/chrome/app/resources/generated_resources_ml.xtb b/chromium/chrome/app/resources/generated_resources_ml.xtb
index fda463b6780..36d44d794d4 100644
--- a/chromium/chrome/app/resources/generated_resources_ml.xtb
+++ b/chromium/chrome/app/resources/generated_resources_ml.xtb
@@ -228,7 +228,7 @@
<translation id="4152670763139331043">{NUM_TABS,plural, =1{ഒരു ടാബ്}other{# ടാബുകൾ}}</translation>
<translation id="2846816712032308263">വേഗത്തിലുള്ള ടാബ്/വിൻഡോ അടയ്‌ക്കൽ പ്രവർത്തനക്ഷമമാക്കുന്നു - ഒരു ടാബിന്റെ onunload js ഹാൻഡ്ലർ GUI അവലംബിക്കാതെ പ്രവർത്തിപ്പിക്കുന്നു.</translation>
<translation id="1514215615641002767">ഡെസ്‌ക്‌ടോപ്പിൽ ചേർക്കുക</translation>
-<translation id="9134410174832249455"><ph name="HOST_NAME"/> എന്നത് പ്രതികരിക്കാന്‍ കൂടുതല്‍ സമയം എടുത്തതിനാല്‍ <ph name="PRODUCT_NAME"/> എന്നതിന് വെബ്പേജ് ലോഡ് ചെയ്യാന്‍ സാധിക്കുന്നില്ല. വെബ്പേജ് ഡൌണ്‍ ആയിരിക്കാം, അല്ലെങ്കില്‍ ഇന്‍റര്‍നെറ്റ് കണക്ഷനുമായി ബന്ധപ്പെട്ട് പ്രശ്നങ്ങള്‍ നിങ്ങള്‍ നേരിടുന്നുണ്ടാകാം.</translation>
+<translation id="9134410174832249455"><ph name="HOST_NAME"/> എന്നത് പ്രതികരിക്കാന്‍ കൂടുതല്‍ സമയം എടുത്തതിനാല്‍ <ph name="PRODUCT_NAME"/> എന്നതിന് വെബ്പേജ് ലോഡ് ചെയ്യാന്‍ സാധിക്കുന്നില്ല. വെബ്പേജ് ഡൗൺ ആയിരിക്കാം, അല്ലെങ്കില്‍ ഇന്‍റര്‍നെറ്റ് കണക്ഷനുമായി ബന്ധപ്പെട്ട് പ്രശ്നങ്ങള്‍ നിങ്ങള്‍ നേരിടുന്നുണ്ടാകാം.</translation>
<translation id="2239921694246509981">സൂപ്പർവൈസുചെയ്‌ത വ്യക്തിയെ ചേർക്കുക</translation>
<translation id="7624154074265342755">വയര്‍ലെസ്സ് നെറ്റ്‍വര്‍ക്കുകള്‍</translation>
<translation id="3899968422636198696"><ph name="ORGNAME"/> <ph name="HOSTNAME"/></translation>
@@ -2375,7 +2375,7 @@ Google Chrome മൊബൈൽ ഡാറ്റ ഉപയോഗിക്കും.
<translation id="7627262197844840899">ഈ സൈറ്റ് MasterCard-നെ അംഗീകരിക്കുന്നില്ല.</translation>
<translation id="1679068421605151609">ഡവലപ്പർ ഉപകരണങ്ങൾ</translation>
<translation id="2596092989116824292">പരീക്ഷണാത്‌മക SurfaceWorker ഫീച്ചർ പ്രവർത്തനക്ഷമമാക്കുക.</translation>
-<translation id="7014051144917845222"><ph name="HOST_NAME"/> എന്നതിലേക്കുള്ള <ph name="PRODUCT_NAME"/> എന്നതിന്‍റെ കണക്ഷന്‍ ശ്രമം നിരസിച്ചു. വെബ്സൈറ്റ് ഡൌണ്‍ ആയിരിക്കാം, അല്ലെങ്കില്‍ നിങ്ങളുടെ നെറ്റ്‌വര്‍ക്ക് ശരിയായി കോണ്‍ഫിഗര്‍ ചെയ്തിട്ടുണ്ടാകില്ല.</translation>
+<translation id="7014051144917845222"><ph name="HOST_NAME"/> എന്നതിലേക്കുള്ള <ph name="PRODUCT_NAME"/> എന്നതിന്‍റെ കണക്ഷന്‍ ശ്രമം നിരസിച്ചു. വെബ്സൈറ്റ് ഡൗൺ ആയിരിക്കാം, അല്ലെങ്കില്‍ നിങ്ങളുടെ നെറ്റ്‌വര്‍ക്ക് ശരിയായി കോണ്‍ഫിഗര്‍ ചെയ്തിട്ടുണ്ടാകില്ല.</translation>
<translation id="2097372108957554726">പുതിയ ഉപകരണങ്ങൾ രജിസ്റ്റർ ചെയ്യാൻ നിങ്ങൾ Chrome-ൽ സൈൻ ഇൻ ചെയ്യണം</translation>
<translation id="4332213577120623185">ഈ വാങ്ങൽ പൂർത്തിയാക്കാൻ കൂടുതൽ വിവരങ്ങൾ ആവശ്യമാണ്.</translation>
<translation id="9201305942933582053">Chrome-നായുള്ള 'Google ഇപ്പോൾ'!</translation>
@@ -2983,9 +2983,9 @@ Google Chrome മൊബൈൽ ഡാറ്റ ഉപയോഗിക്കും.
<translation id="6707389671160270963">SSL ക്ലയന്‍റ് സര്‍‌ട്ടിഫിക്കറ്റ്</translation>
<translation id="6083557600037991373">വെബ്പേജുകള്‍ വേഗത്തിലാക്കാന്‍, <ph name="PRODUCT_NAME"/>
ഡൗൺലോഡ് ചെയ്ത ഫയലുകളെ ഡിസ്കില്‍ താല്‍ക്കാലികമായി സംരക്ഷിക്കുന്നു. <ph name="PRODUCT_NAME"/>
- ശരിയായവിധം ഷട്ട് ഡൌണ്‍ ചെയ്യാത്തപ്പോള്‍, ഈ ഫയലുകള്‍ കേടായേക്കാം, അത്
+ ശരിയായവിധം ഷട്ട് ഡൗൺ ചെയ്യാത്തപ്പോള്‍, ഈ ഫയലുകള്‍ കേടായേക്കാം, അത്
ഈ പിശകിന് കാരണമാകുന്നു. പേജ് വീണ്ടും ലോഡുചെയ്യുന്നത് ഈ പ്രശ്നത്തെ പരിഹരിക്കേണ്ടതാണ്, മാത്രമല്ല
- ശരിയായവിധം ഷട്ട് ഡൌണ്‍ ചെയ്യുന്നത് ഇങ്ങനെ ഭാവിയില്‍ സംഭവിക്കുന്നതിനെ തടയുന്നു. <ph name="LINE_BREAK"/>
+ ശരിയായവിധം ഷട്ട് ഡൗൺ ചെയ്യുന്നത് ഇങ്ങനെ ഭാവിയില്‍ സംഭവിക്കുന്നതിനെ തടയുന്നു. <ph name="LINE_BREAK"/>
പ്രശ്നം നിലനില്‍ക്കുകയാണെങ്കില്‍, കാഷെ വൃത്തിയാക്കിക്കൊണ്ട് ശ്രമിക്കുക. ചില സാഹചര്യങ്ങളില്‍, ഇത് ഹാര്‍ഡ്‌വെയര്‍ പരാജയപ്പെടാന്‍ പോകുന്നതിന്‍റെ ലക്ഷണവും ആകാം.</translation>
<translation id="5154176924561037127">F8</translation>
<translation id="5298219193514155779">തീം സൃഷ്‌ടിച്ചത്</translation>
diff --git a/chromium/chrome/app/resources/generated_resources_no.xtb b/chromium/chrome/app/resources/generated_resources_no.xtb
index ce818f876dd..cf63c761d58 100644
--- a/chromium/chrome/app/resources/generated_resources_no.xtb
+++ b/chromium/chrome/app/resources/generated_resources_no.xtb
@@ -1583,7 +1583,7 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY"/>) kan være kjekt neste gang
<translation id="7791543448312431591">Legg til</translation>
<translation id="8569764466147087991">Velg en fil du vil åpne</translation>
<translation id="3010279545267083280">Passordet er slettet</translation>
-<translation id="4275663329226226506">Media</translation>
+<translation id="4275663329226226506">Medier</translation>
<translation id="4467100756425880649">Chrome Nettmarked Galleri</translation>
<translation id="5649768706273821470">Lytt</translation>
<translation id="4096508467498758490">Deaktiver utvidelser for utviklermodus</translation>
diff --git a/chromium/chrome/app/resources/generated_resources_sk.xtb b/chromium/chrome/app/resources/generated_resources_sk.xtb
index 744ad5d9982..976a2b06d91 100644
--- a/chromium/chrome/app/resources/generated_resources_sk.xtb
+++ b/chromium/chrome/app/resources/generated_resources_sk.xtb
@@ -5439,7 +5439,7 @@ Prebieha výpočet času do úplného nabitia</translation>
<translation id="8848709220963126773">Prepnutie módu klávesom Shift</translation>
<translation id="8336579025507394412">Islandská klávesnica</translation>
<translation id="6316806695097060329">Toto zariadenie <ph name="SHORT_PRODUCT_NAME"/> bolo navrhnuté tak, aby vám poskytlo tú najlepšiu skúsenosť pri prehliadaní webu.</translation>
-<translation id="3241720467332021590">Írčina However, the Google Toolbar either is not present on your system or is not functioning properly.</translation>
+<translation id="3241720467332021590">Írčina</translation>
<translation id="5144820558584035333">Hangul 3 Set (390)</translation>
<translation id="8828933418460119530">Názov DNS</translation>
<translation id="424546999567421758">Zistilo sa vysoké využitie disku</translation>
diff --git a/chromium/chrome/app/resources/google_chrome_strings_kn.xtb b/chromium/chrome/app/resources/google_chrome_strings_kn.xtb
index 86da58edf96..45902e394b1 100644
--- a/chromium/chrome/app/resources/google_chrome_strings_kn.xtb
+++ b/chromium/chrome/app/resources/google_chrome_strings_kn.xtb
@@ -19,7 +19,7 @@
<translation id="2770231113462710648">ಡೀಫಾಲ್ಟ್ ಬ್ರೌಸರ್ ಅನ್ನು ಇದ್ಕಕೆ ಬದಲಿಸಿ:</translation>
<translation id="7400722733683201933">Google Chrome ಬಗ್ಗೆ</translation>
<translation id="2077129598763517140">ಲಭ್ಯವಿರುವಾಗ ಹಾರ್ಡ್‌ವೇರ್ ಆಕ್ಸಲರೇಶನ್ ಬಳಸು</translation>
-<translation id="1065672644894730302">ನಿಮ್ಮ ಪ್ರಾಶಸ್ತ್ಯಗಳನ್ನು ಓದಲಾಗುವುದಿಲ್ಲ. ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳು ಲಭ್ಯವಿಲ್ಲದಿರಬಹುದು ಮತ್ತು ಆದ್ಯತೆಗಳ ಬದಲಾವಣೆಗಳನ್ನು ಉಳಿಸಲಾಗುವುದಿಲ್ಲ.</translation>
+<translation id="1065672644894730302">ನಿಮ್ಮ ಪ್ರಾಶಸ್ತ್ಯಗಳನ್ನು ರೀಡ್‌ ಮಾಡಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಅಲ್ಲದೇ, ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳು ಲಭ್ಯವಿಲ್ಲದಿರಬಹುದು ಮತ್ತು ಪ್ರಾಶಸ್ತ್ಯಗಳಲ್ಲಿ ಮಾಡಿದ ಬದಲಾವಣೆಗಳನ್ನು ಉಳಿಸಲಾಗುವುದಿಲ್ಲ.</translation>
<translation id="7781002470561365167">Google Chrome ನ ಹೊಸ ಆವೃತ್ತಿ ಲಭ್ಯವಿದೆ.</translation>
<translation id="5251420635869119124">ಅತಿಥಿಗಳು ಏನನ್ನೂ ಉಳಿಸದೇ Chrome ಬಳಸಬಹುದು.</translation>
<translation id="4891791193823137474">Google Chrome ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಚಾಲನೆಯಾಗಲು ಅನುಮತಿಸಿ</translation>
diff --git a/chromium/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js b/chromium/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js
index a473875bc0f..9db03d4ccf3 100644
--- a/chromium/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js
+++ b/chromium/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js
@@ -349,7 +349,8 @@ cr.define('wallpapers', function() {
var dataModelId = self.dataModelId_;
self.pendingItems_++;
return WallpaperThumbnailsGridItem(value, dataModelId,
- self.thumbnailList_[value.wallpaperId],
+ (value.wallpaperId == null) ?
+ null : self.thumbnailList_[value.wallpaperId],
self.pendingItemComplete.bind(self));
};
this.selectionModel = new ListSingleSelectionModel();
diff --git a/chromium/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js b/chromium/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
index f490701afb1..8c6c867a3c4 100644
--- a/chromium/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
+++ b/chromium/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
@@ -1004,14 +1004,13 @@ function WallpaperManager(dialogDom) {
};
var self = this;
- // Need this check for test purpose.
- var numOnlineWallpaper = (this.enableOnlineWallpaper_ && this.manifest_) ?
- this.manifest_.wallpaper_list.length : 0;
var processResults = function(entries) {
for (var i = 0; i < entries.length; i++) {
var entry = entries[i];
var wallpaperInfo = {
- wallpaperId: numOnlineWallpaper + i,
+ // Set wallpaperId to null to avoid duplicate thumbnail images,
+ // see crbug.com/506135 for details.
+ wallpaperId: null,
baseURL: entry.name,
// The layout will be replaced by the actual value saved in
// local storage when requested later. Layout is not important
@@ -1026,7 +1025,7 @@ function WallpaperManager(dialogDom) {
}
if (loadTimeData.getBoolean('isOEMDefaultWallpaper')) {
var oemDefaultWallpaperElement = {
- wallpaperId: numOnlineWallpaper + entries.length,
+ wallpaperId: null,
baseURL: 'OemDefaultWallpaper',
layout: 'CENTER_CROPPED',
source: Constants.WallpaperSourceEnum.OEM,
diff --git a/chromium/chrome/browser/resources/inspect/inspect.css b/chromium/chrome/browser/resources/inspect/inspect.css
index 664a20cfdef..60c3592db4e 100644
--- a/chromium/chrome/browser/resources/inspect/inspect.css
+++ b/chromium/chrome/browser/resources/inspect/inspect.css
@@ -32,16 +32,12 @@ img {
}
#navigation {
- max-height: 100vh;
- overflow: auto;
padding-top: 20px;
width: 150px;
}
#content {
-webkit-flex: 1;
- max-height: 100vh;
- overflow: auto;
}
#caption {
@@ -410,3 +406,20 @@ img {
#port-forwarding-config-buttons > label {
flex-grow: 1
}
+
+@media (max-width: 47em) {
+ #navigation,
+ #content {
+ overflow: visible;
+ }
+}
+@media (min-width: 47em) {
+ #container {
+ height: 100vh;
+ }
+ #navigation,
+ #content {
+ height: 100vh;
+ overflow: auto;
+ }
+}
diff --git a/chromium/chrome/chrome_browser.gypi b/chromium/chrome/chrome_browser.gypi
index 1aaedba2808..ec8b1e036d7 100644
--- a/chromium/chrome/chrome_browser.gypi
+++ b/chromium/chrome/chrome_browser.gypi
@@ -92,6 +92,8 @@
'browser/android/download/chrome_download_manager_overwrite_infobar_delegate.h',
'browser/android/download/download_overwrite_infobar_delegate.cc',
'browser/android/download/download_overwrite_infobar_delegate.h',
+ 'browser/android/download/mock_download_controller_android.cc',
+ 'browser/android/download/mock_download_controller_android.h',
'browser/android/favicon_helper.cc',
'browser/android/favicon_helper.h',
'browser/android/feature_utilities.cc',
diff --git a/chromium/chrome/chrome_installer.gypi b/chromium/chrome/chrome_installer.gypi
index 99ccd5c3ba9..d7ef07456da 100644
--- a/chromium/chrome/chrome_installer.gypi
+++ b/chromium/chrome/chrome_installer.gypi
@@ -253,6 +253,8 @@
'installer/setup/setup_util.h',
'installer/setup/uninstall.cc',
'installer/setup/uninstall.h',
+ 'installer/setup/update_active_setup_version_work_item.cc',
+ 'installer/setup/update_active_setup_version_work_item.h',
],
'msvs_settings': {
'VCLinkerTool': {
@@ -356,6 +358,9 @@
'installer/setup/setup_util.cc',
'installer/setup/setup_util_unittest.cc',
'installer/setup/setup_util_unittest.h',
+ 'installer/setup/update_active_setup_version_work_item.cc', # Move to lib
+ 'installer/setup/update_active_setup_version_work_item.h', # Move to lib
+ 'installer/setup/update_active_setup_version_work_item_unittest.cc',
],
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
'msvs_disabled_warnings': [ 4267, ],
diff --git a/chromium/chrome/chrome_tests_unit.gypi b/chromium/chrome/chrome_tests_unit.gypi
index 89e31b522cc..bc955751eda 100644
--- a/chromium/chrome/chrome_tests_unit.gypi
+++ b/chromium/chrome/chrome_tests_unit.gypi
@@ -86,6 +86,7 @@
'browser/download/download_history_unittest.cc',
'browser/download/download_item_model_unittest.cc',
'browser/download/download_path_reservation_tracker_unittest.cc',
+ 'browser/download/download_prefs_unittest.cc',
'browser/download/download_query_unittest.cc',
'browser/download/download_request_infobar_delegate_unittest.cc',
'browser/download/download_request_limiter_unittest.cc',
diff --git a/chromium/chrome_elf/blacklist/blacklist.cc b/chromium/chrome_elf/blacklist/blacklist.cc
index d778b90434e..e862cfa0f47 100644
--- a/chromium/chrome_elf/blacklist/blacklist.cc
+++ b/chromium/chrome_elf/blacklist/blacklist.cc
@@ -54,6 +54,7 @@ const wchar_t* g_troublesome_dlls[kTroublesomeDllsMaxCount] = {
L"lmrn.dll", // Unknown.
L"minisp.dll", // Unknown (suspected malware).
L"minisp32.dll", // Unknown (suspected malware).
+ L"offerswizarddll.dll", // Unknown (suspected adware).
L"safetynut.dll", // Unknown (suspected adware).
L"smdmf.dll", // Unknown (suspected adware).
L"spappsv32.dll", // Unknown (suspected adware).
diff --git a/chromium/content/browser/android/content_view_core_impl.cc b/chromium/content/browser/android/content_view_core_impl.cc
index 6188375b9c5..98f3db1be85 100644
--- a/chromium/content/browser/android/content_view_core_impl.cc
+++ b/chromium/content/browser/android/content_view_core_impl.cc
@@ -223,6 +223,7 @@ ContentViewCoreImpl::ContentViewCoreImpl(
web_contents_(static_cast<WebContentsImpl*>(web_contents)),
root_layer_(cc::SolidColorLayer::Create()),
dpi_scale_(GetPrimaryDisplayDeviceScaleFactor()),
+ page_scale_(1),
view_android_(new ui::ViewAndroid(view_android_delegate, window_android)),
window_android_(window_android),
device_orientation_(0),
diff --git a/chromium/content/browser/android/download_controller_android_impl.cc b/chromium/content/browser/android/download_controller_android_impl.cc
index 353e2611b3e..85412a9f88f 100644
--- a/chromium/content/browser/android/download_controller_android_impl.cc
+++ b/chromium/content/browser/android/download_controller_android_impl.cc
@@ -7,8 +7,10 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/bind.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "content/browser/android/content_view_core_impl.h"
#include "content/browser/android/deferred_download_observer.h"
@@ -37,6 +39,11 @@
using base::android::ConvertUTF8ToJavaString;
using base::android::ScopedJavaLocalRef;
+namespace {
+// Guards download_controller_
+base::LazyInstance<base::Lock> g_download_controller_lock_;
+}
+
namespace content {
// JNI methods
@@ -44,6 +51,19 @@ static void Init(JNIEnv* env, jobject obj) {
DownloadControllerAndroidImpl::GetInstance()->Init(env, obj);
}
+static void OnRequestFileAccessResult(
+ JNIEnv* env, jobject obj, jlong callback_id, jboolean granted) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(callback_id);
+
+ // Convert java long long int to c++ pointer, take ownership.
+ scoped_ptr<DownloadControllerAndroid::AcquireFileAccessPermissionCallback> cb(
+ reinterpret_cast<
+ DownloadControllerAndroid::AcquireFileAccessPermissionCallback*>(
+ callback_id));
+ cb->Run(granted);
+}
+
struct DownloadControllerAndroidImpl::JavaObject {
ScopedJavaLocalRef<jobject> Controller(JNIEnv* env) {
return GetRealObject(env, obj);
@@ -58,7 +78,17 @@ bool DownloadControllerAndroidImpl::RegisterDownloadController(JNIEnv* env) {
// static
DownloadControllerAndroid* DownloadControllerAndroid::Get() {
- return DownloadControllerAndroidImpl::GetInstance();
+ base::AutoLock lock(g_download_controller_lock_.Get());
+ if (!DownloadControllerAndroid::download_controller_)
+ download_controller_ = DownloadControllerAndroidImpl::GetInstance();
+ return DownloadControllerAndroid::download_controller_;
+}
+
+//static
+void DownloadControllerAndroid::SetDownloadControllerAndroid(
+ DownloadControllerAndroid* download_controller) {
+ base::AutoLock lock(g_download_controller_lock_.Get());
+ DownloadControllerAndroid::download_controller_ = download_controller;
}
// static
@@ -96,6 +126,48 @@ void DownloadControllerAndroidImpl::CancelDeferredDownload(
}
}
+void DownloadControllerAndroidImpl::AcquireFileAccessPermission(
+ WebContents* web_contents,
+ const DownloadControllerAndroid::AcquireFileAccessPermissionCallback& cb) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!web_contents) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE, base::Bind(cb, false));
+ return;
+ }
+
+ ScopedJavaLocalRef<jobject> view =
+ GetContentViewCoreFromWebContents(web_contents);
+ if (view.is_null()) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE, base::Bind(cb, false));
+ return;
+ }
+
+ if (HasFileAccessPermission(view)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE, base::Bind(cb, true));
+ return;
+ }
+
+ JNIEnv* env = base::android::AttachCurrentThread();
+ // Make copy on the heap so we can pass the pointer through JNI.
+ intptr_t callback_id = reinterpret_cast<intptr_t>(
+ new DownloadControllerAndroid::AcquireFileAccessPermissionCallback(cb));
+ Java_DownloadController_requestFileAccess(
+ env, GetJavaObject()->Controller(env).obj(), view.obj(), callback_id);
+}
+
+bool DownloadControllerAndroidImpl::HasFileAccessPermission(
+ ScopedJavaLocalRef<jobject> j_content_view_core) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(!j_content_view_core.is_null());
+
+ JNIEnv* env = base::android::AttachCurrentThread();
+ return Java_DownloadController_hasFileAccess(
+ env, GetJavaObject()->Controller(env).obj(), j_content_view_core.obj());
+}
+
void DownloadControllerAndroidImpl::CreateGETDownload(
int render_process_id, int render_view_id, int request_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -210,9 +282,7 @@ void DownloadControllerAndroidImpl::StartAndroidDownload(
int render_process_id, int render_view_id,
const DownloadInfoAndroid& info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- JNIEnv* env = base::android::AttachCurrentThread();
- // Call newHttpGetDownload
WebContents* web_contents = GetWebContents(render_process_id, render_view_id);
if (!web_contents) {
// The view went away. Can't proceed.
@@ -232,6 +302,32 @@ void DownloadControllerAndroidImpl::StartAndroidDownload(
info)));
return;
}
+
+ AcquireFileAccessPermission(
+ web_contents,
+ base::Bind(&DownloadControllerAndroidImpl::StartAndroidDownloadInternal,
+ base::Unretained(this), render_process_id, render_view_id,
+ info));
+}
+
+void DownloadControllerAndroidImpl::StartAndroidDownloadInternal(
+ int render_process_id, int render_view_id,
+ const DownloadInfoAndroid& info, bool allowed) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!allowed)
+ return;
+
+ // Call newHttpGetDownload
+ WebContents* web_contents = GetWebContents(render_process_id, render_view_id);
+ // The view went away. Can't proceed.
+ if (!web_contents)
+ return;
+ ScopedJavaLocalRef<jobject> view =
+ GetContentViewCoreFromWebContents(web_contents);
+ if (view.is_null())
+ return;
+
+ JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jstring> jurl =
ConvertUTF8ToJavaString(env, info.url.spec());
ScopedJavaLocalRef<jstring> juser_agent =
diff --git a/chromium/content/browser/android/download_controller_android_impl.h b/chromium/content/browser/android/download_controller_android_impl.h
index dd391238cde..fe9cdbb8cc2 100644
--- a/chromium/content/browser/android/download_controller_android_impl.h
+++ b/chromium/content/browser/android/download_controller_android_impl.h
@@ -54,6 +54,11 @@ class DownloadControllerAndroidImpl : public DownloadControllerAndroid,
// Removes a deferred download from |deferred_downloads_|.
void CancelDeferredDownload(DeferredDownloadObserver* observer);
+ // DownloadControllerAndroid implementation.
+ void AcquireFileAccessPermission(
+ WebContents* web_contents,
+ const AcquireFileAccessPermissionCallback& callback) override;
+
private:
// Used to store all the information about an Android download.
struct DownloadInfoAndroid {
@@ -81,6 +86,10 @@ class DownloadControllerAndroidImpl : public DownloadControllerAndroid,
DownloadControllerAndroidImpl();
~DownloadControllerAndroidImpl() override;
+ // Helper method for implementing AcquireFileAccessPermission().
+ bool HasFileAccessPermission(
+ base::android::ScopedJavaLocalRef<jobject> j_content_view_core);
+
// DownloadControllerAndroid implementation.
void CreateGETDownload(int render_process_id,
int render_view_id,
@@ -115,6 +124,10 @@ class DownloadControllerAndroidImpl : public DownloadControllerAndroid,
void StartAndroidDownload(int render_process_id,
int render_view_id,
const DownloadInfoAndroid& info);
+ void StartAndroidDownloadInternal(int render_process_id,
+ int render_view_id,
+ const DownloadInfoAndroid& info,
+ bool allowed);
// The download item contains dangerous file types.
void OnDangerousDownload(DownloadItem *item);
diff --git a/chromium/content/browser/appcache/appcache_backend_impl.cc b/chromium/content/browser/appcache/appcache_backend_impl.cc
index 099c54e55ad..e055f1a1de8 100644
--- a/chromium/content/browser/appcache/appcache_backend_impl.cc
+++ b/chromium/content/browser/appcache/appcache_backend_impl.cc
@@ -68,7 +68,7 @@ bool AppCacheBackendImpl::SelectCache(
const int64 cache_document_was_loaded_from,
const GURL& manifest_url) {
AppCacheHost* host = GetHost(host_id);
- if (!host)
+ if (!host || host->was_select_cache_called())
return false;
host->SelectCache(document_url, cache_document_was_loaded_from,
@@ -79,7 +79,7 @@ bool AppCacheBackendImpl::SelectCache(
bool AppCacheBackendImpl::SelectCacheForWorker(
int host_id, int parent_process_id, int parent_host_id) {
AppCacheHost* host = GetHost(host_id);
- if (!host)
+ if (!host || host->was_select_cache_called())
return false;
host->SelectCacheForWorker(parent_process_id, parent_host_id);
@@ -89,7 +89,7 @@ bool AppCacheBackendImpl::SelectCacheForWorker(
bool AppCacheBackendImpl::SelectCacheForSharedWorker(
int host_id, int64 appcache_id) {
AppCacheHost* host = GetHost(host_id);
- if (!host)
+ if (!host || host->was_select_cache_called())
return false;
host->SelectCacheForSharedWorker(appcache_id);
diff --git a/chromium/content/browser/appcache/appcache_host.cc b/chromium/content/browser/appcache/appcache_host.cc
index 4ec19ffe624..dbdaf308fcd 100644
--- a/chromium/content/browser/appcache/appcache_host.cc
+++ b/chromium/content/browser/appcache/appcache_host.cc
@@ -49,6 +49,7 @@ AppCacheHost::AppCacheHost(int host_id, AppCacheFrontend* frontend,
parent_host_id_(kAppCacheNoHostId), parent_process_id_(0),
pending_main_resource_cache_id_(kAppCacheNoCacheId),
pending_selected_cache_id_(kAppCacheNoCacheId),
+ was_select_cache_called_(false),
is_cache_selection_enabled_(true),
frontend_(frontend), service_(service),
storage_(service->storage()),
@@ -85,8 +86,9 @@ void AppCacheHost::SelectCache(const GURL& document_url,
DCHECK(pending_start_update_callback_.is_null() &&
pending_swap_cache_callback_.is_null() &&
pending_get_status_callback_.is_null() &&
- !is_selection_pending());
+ !is_selection_pending() && !was_select_cache_called_);
+ was_select_cache_called_ = true;
if (!is_cache_selection_enabled_) {
FinishCacheSelection(NULL, NULL);
return;
@@ -152,8 +154,9 @@ void AppCacheHost::SelectCacheForWorker(int parent_process_id,
DCHECK(pending_start_update_callback_.is_null() &&
pending_swap_cache_callback_.is_null() &&
pending_get_status_callback_.is_null() &&
- !is_selection_pending());
+ !is_selection_pending() && !was_select_cache_called_);
+ was_select_cache_called_ = true;
parent_process_id_ = parent_process_id;
parent_host_id_ = parent_host_id;
FinishCacheSelection(NULL, NULL);
@@ -163,8 +166,9 @@ void AppCacheHost::SelectCacheForSharedWorker(int64 appcache_id) {
DCHECK(pending_start_update_callback_.is_null() &&
pending_swap_cache_callback_.is_null() &&
pending_get_status_callback_.is_null() &&
- !is_selection_pending());
+ !is_selection_pending() && !was_select_cache_called_);
+ was_select_cache_called_ = true;
if (appcache_id != kAppCacheNoCacheId) {
LoadSelectedCache(appcache_id);
return;
diff --git a/chromium/content/browser/appcache/appcache_host.h b/chromium/content/browser/appcache/appcache_host.h
index 7525ea2f7b8..f43952006f7 100644
--- a/chromium/content/browser/appcache/appcache_host.h
+++ b/chromium/content/browser/appcache/appcache_host.h
@@ -163,6 +163,7 @@ class CONTENT_EXPORT AppCacheHost
AppCacheStorage* storage() const { return storage_; }
AppCacheFrontend* frontend() const { return frontend_; }
AppCache* associated_cache() const { return associated_cache_.get(); }
+ bool was_select_cache_called() const { return was_select_cache_called_; }
void enable_cache_selection(bool enable) {
is_cache_selection_enabled_ = enable;
@@ -269,6 +270,9 @@ class CONTENT_EXPORT AppCacheHost
int64 pending_selected_cache_id_;
GURL pending_selected_manifest_url_;
+ // Used to defend against bad IPC messages.
+ bool was_select_cache_called_;
+
// Used to avoid stepping on pages controlled by ServiceWorkers.
bool is_cache_selection_enabled_;
diff --git a/chromium/content/browser/appcache/appcache_response.cc b/chromium/content/browser/appcache/appcache_response.cc
index 8b7c2188233..0c0f4bf1e3e 100644
--- a/chromium/content/browser/appcache/appcache_response.cc
+++ b/chromium/content/browser/appcache/appcache_response.cc
@@ -9,6 +9,7 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "base/numerics/safe_math.h"
#include "base/pickle.h"
#include "base/profiler/scoped_tracker.h"
#include "base/strings/string_util.h"
@@ -272,8 +273,8 @@ void AppCacheResponseReader::OnIOComplete(int result) {
int64 metadata_size = entry_->GetSize(kResponseMetadataIndex);
if (metadata_size > 0) {
reading_metadata_size_ = metadata_size;
- info_buffer_->http_info->metadata =
- new net::IOBufferWithSize(metadata_size);
+ info_buffer_->http_info->metadata = new net::IOBufferWithSize(
+ base::CheckedNumeric<size_t>(metadata_size).ValueOrDie());
ReadRaw(kResponseMetadataIndex, 0,
info_buffer_->http_info->metadata.get(), metadata_size);
return;
diff --git a/chromium/content/browser/appcache/view_appcache_internals_job.cc b/chromium/content/browser/appcache/view_appcache_internals_job.cc
index 84912b733d4..57848da3089 100644
--- a/chromium/content/browser/appcache/view_appcache_internals_job.cc
+++ b/chromium/content/browser/appcache/view_appcache_internals_job.cc
@@ -13,6 +13,7 @@
#include "base/i18n/time_formatting.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
+#include "base/numerics/safe_math.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -596,7 +597,8 @@ class ViewEntryJob : public BaseInternalsJob,
const int64 kLimit = 100 * 1000;
int64 amount_to_read =
std::min(kLimit, response_info->response_data_size());
- response_data_ = new net::IOBuffer(amount_to_read);
+ response_data_ = new net::IOBuffer(
+ base::CheckedNumeric<size_t>(amount_to_read).ValueOrDie());
reader_.reset(appcache_storage_->CreateResponseReader(
manifest_url_, group_id_, response_id_));
diff --git a/chromium/content/browser/download/download_stats.cc b/chromium/content/browser/download/download_stats.cc
index 42bb0754a87..7b0b9adc1b6 100644
--- a/chromium/content/browser/download/download_stats.cc
+++ b/chromium/content/browser/download/download_stats.cc
@@ -70,6 +70,8 @@ void RecordContentDispositionCountFlag(
// Do not insert, delete, or reorder; this is being histogrammed. Append only.
// All of the download_extensions.cc file types should be in this list.
+// TODO(asanka): This enum and the UMA metrics for dangerous/malicious downloads
+// should be moved to //chrome/browser/download.
const base::FilePath::CharType* kDangerousFileTypes[] = {
FILE_PATH_LITERAL(".ad"),
FILE_PATH_LITERAL(".ade"),
@@ -194,8 +196,19 @@ const base::FilePath::CharType* kDangerousFileTypes[] = {
FILE_PATH_LITERAL(".xhtml"),
FILE_PATH_LITERAL(".xml"),
FILE_PATH_LITERAL(".xsl"),
- FILE_PATH_LITERAL(".xslt")
- FILE_PATH_LITERAL(".website")
+ FILE_PATH_LITERAL(".xslt"),
+ FILE_PATH_LITERAL(".website"),
+ FILE_PATH_LITERAL(".msh1"),
+ FILE_PATH_LITERAL(".msh2"),
+ FILE_PATH_LITERAL(".msh1xml"),
+ FILE_PATH_LITERAL(".msh2xml"),
+ FILE_PATH_LITERAL(".ps1"),
+ FILE_PATH_LITERAL(".ps1xml"),
+ FILE_PATH_LITERAL(".ps2"),
+ FILE_PATH_LITERAL(".ps2xml"),
+ FILE_PATH_LITERAL(".psc1"),
+ FILE_PATH_LITERAL(".psc2"),
+ FILE_PATH_LITERAL(".xnk"),
};
// Maps extensions to their matching UMA histogram int value.
diff --git a/chromium/content/browser/service_worker/service_worker_url_request_job.cc b/chromium/content/browser/service_worker/service_worker_url_request_job.cc
index 3a94d857b21..607c9b0c401 100644
--- a/chromium/content/browser/service_worker/service_worker_url_request_job.cc
+++ b/chromium/content/browser/service_worker/service_worker_url_request_job.cc
@@ -30,6 +30,7 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/http/http_util.h"
+#include "net/log/net_log.h"
#include "storage/browser/blob/blob_data_builder.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "storage/browser/blob/blob_storage_context.h"
@@ -38,6 +39,59 @@
namespace content {
+namespace {
+
+net::NetLog::EventType RequestJobResultToNetEventType(
+ ServiceWorkerMetrics::URLRequestJobResult result) {
+ using n = net::NetLog;
+ using m = ServiceWorkerMetrics;
+ switch (result) {
+ case m::REQUEST_JOB_FALLBACK_RESPONSE:
+ return n::TYPE_SERVICE_WORKER_FALLBACK_RESPONSE;
+ case m::REQUEST_JOB_FALLBACK_FOR_CORS:
+ return n::TYPE_SERVICE_WORKER_FALLBACK_FOR_CORS;
+ case m::REQUEST_JOB_HEADERS_ONLY_RESPONSE:
+ return n::TYPE_SERVICE_WORKER_HEADERS_ONLY_RESPONSE;
+ case m::REQUEST_JOB_STREAM_RESPONSE:
+ return n::TYPE_SERVICE_WORKER_STREAM_RESPONSE;
+ case m::REQUEST_JOB_BLOB_RESPONSE:
+ return n::TYPE_SERVICE_WORKER_BLOB_RESPONSE;
+ case m::REQUEST_JOB_ERROR_RESPONSE_STATUS_ZERO:
+ return n::TYPE_SERVICE_WORKER_ERROR_RESPONSE_STATUS_ZERO;
+ case m::REQUEST_JOB_ERROR_BAD_BLOB:
+ return n::TYPE_SERVICE_WORKER_ERROR_BAD_BLOB;
+ case m::REQUEST_JOB_ERROR_NO_PROVIDER_HOST:
+ return n::TYPE_SERVICE_WORKER_ERROR_NO_PROVIDER_HOST;
+ case m::REQUEST_JOB_ERROR_NO_ACTIVE_VERSION:
+ return n::TYPE_SERVICE_WORKER_ERROR_NO_ACTIVE_VERSION;
+ case m::REQUEST_JOB_ERROR_FETCH_EVENT_DISPATCH:
+ return n::TYPE_SERVICE_WORKER_ERROR_FETCH_EVENT_DISPATCH;
+ case m::REQUEST_JOB_ERROR_BLOB_READ:
+ return n::TYPE_SERVICE_WORKER_ERROR_BLOB_READ;
+ case m::REQUEST_JOB_ERROR_STREAM_ABORTED:
+ return n::TYPE_SERVICE_WORKER_ERROR_STREAM_ABORTED;
+ case m::REQUEST_JOB_ERROR_KILLED:
+ return n::TYPE_SERVICE_WORKER_ERROR_KILLED;
+ case m::REQUEST_JOB_ERROR_KILLED_WITH_BLOB:
+ return n::TYPE_SERVICE_WORKER_ERROR_KILLED_WITH_BLOB;
+ case m::REQUEST_JOB_ERROR_KILLED_WITH_STREAM:
+ return n::TYPE_SERVICE_WORKER_ERROR_KILLED_WITH_STREAM;
+ // We can't log if there's no request; fallthrough.
+ case m::REQUEST_JOB_ERROR_NO_REQUEST:
+ // Obsolete types; fallthrough.
+ case m::REQUEST_JOB_ERROR_DESTROYED:
+ case m::REQUEST_JOB_ERROR_DESTROYED_WITH_BLOB:
+ case m::REQUEST_JOB_ERROR_DESTROYED_WITH_STREAM:
+ // Invalid type.
+ case m::NUM_REQUEST_JOB_RESULT_TYPES:
+ NOTREACHED() << result;
+ }
+ NOTREACHED() << result;
+ return n::TYPE_FAILED;
+}
+
+} // namespace
+
ServiceWorkerURLRequestJob::ServiceWorkerURLRequestJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
@@ -86,16 +140,6 @@ void ServiceWorkerURLRequestJob::Start() {
}
void ServiceWorkerURLRequestJob::Kill() {
- if (ShouldRecordResult()) {
- ServiceWorkerMetrics::URLRequestJobResult result =
- ServiceWorkerMetrics::REQUEST_JOB_ERROR_KILLED;
- if (response_body_type_ == STREAM)
- result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_KILLED_WITH_STREAM;
- else if (response_body_type_ == BLOB)
- result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_KILLED_WITH_BLOB;
- RecordResult(result);
- }
-
net::URLRequestJob::Kill();
ClearStream();
fetch_dispatcher_.reset();
@@ -353,14 +397,12 @@ ServiceWorkerURLRequestJob::~ServiceWorkerURLRequestJob() {
if (!ShouldRecordResult())
return;
- // TODO(falken): If we don't see many of these, we might merge KILLED and
- // DESTROYED results together.
ServiceWorkerMetrics::URLRequestJobResult result =
- ServiceWorkerMetrics::REQUEST_JOB_ERROR_DESTROYED;
+ ServiceWorkerMetrics::REQUEST_JOB_ERROR_KILLED;
if (response_body_type_ == STREAM)
- result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_DESTROYED_WITH_STREAM;
+ result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_KILLED_WITH_STREAM;
else if (response_body_type_ == BLOB)
- result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_DESTROYED_WITH_BLOB;
+ result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_KILLED_WITH_BLOB;
RecordResult(result);
}
@@ -375,6 +417,11 @@ void ServiceWorkerURLRequestJob::MaybeStartRequest() {
}
void ServiceWorkerURLRequestJob::StartRequest() {
+ if (request()) {
+ request()->net_log().AddEvent(
+ net::NetLog::TYPE_SERVICE_WORKER_START_REQUEST);
+ }
+
switch (response_type_) {
case NOT_DETERMINED:
NOTREACHED();
@@ -726,6 +773,8 @@ void ServiceWorkerURLRequestJob::RecordResult(
did_record_result_ = true;
ServiceWorkerMetrics::RecordURLRequestJobResult(is_main_resource_load_,
result);
+ if (request())
+ request()->net_log().AddEvent(RequestJobResultToNetEventType(result));
}
void ServiceWorkerURLRequestJob::ClearStream() {
diff --git a/chromium/content/browser/web_contents/web_contents_android.cc b/chromium/content/browser/web_contents/web_contents_android.cc
index cb98e75f323..2f6a6eadad5 100644
--- a/chromium/content/browser/web_contents/web_contents_android.cc
+++ b/chromium/content/browser/web_contents/web_contents_android.cc
@@ -74,13 +74,13 @@ ScopedJavaLocalRef<jobject> WalkAXTreeDepthFirst(JNIEnv* env,
size = node->GetFloatAttribute(ui::AX_ATTR_FONT_SIZE);
text_style = node->GetIntAttribute(ui::AX_ATTR_TEXT_STYLE);
}
-
ScopedJavaLocalRef<jobject> j_node =
Java_WebContentsImpl_createAccessibilitySnapshotNode(env,
scale_factor * location.x(), scale_factor * location.y(),
scale_factor * node->GetScrollX(), scale_factor * node->GetScrollY(),
scale_factor * location.width(), scale_factor * location.height(),
- j_text.obj(), color, bgcolor, size, text_style, j_class.obj());
+ j_text.obj(), color, bgcolor, scale_factor * size, text_style,
+ j_class.obj());
for(uint32 i = 0; i < node->PlatformChildCount(); i++) {
BrowserAccessibilityAndroid* child =
diff --git a/chromium/content/common/gpu/gpu_command_buffer_stub.cc b/chromium/content/common/gpu/gpu_command_buffer_stub.cc
index 9033d7c5317..ea83554c3e5 100644
--- a/chromium/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/chromium/content/common/gpu/gpu_command_buffer_stub.cc
@@ -582,7 +582,8 @@ void GpuCommandBufferStub::OnInitialize(
if (!context->GetTotalGpuMemory(&total_gpu_memory_))
total_gpu_memory_ = 0;
- if (!context_group_->has_program_cache()) {
+ if (!context_group_->has_program_cache() &&
+ !context_group_->feature_info()->workarounds().disable_program_cache) {
context_group_->set_program_cache(
channel_->gpu_channel_manager()->program_cache());
}
diff --git a/chromium/content/content_browser.gypi b/chromium/content/content_browser.gypi
index 7c04e0330c1..7352db1686a 100644
--- a/chromium/content/content_browser.gypi
+++ b/chromium/content/content_browser.gypi
@@ -62,6 +62,7 @@
'public/browser/android/content_view_core.h',
'public/browser/android/content_view_layer_renderer.h',
'public/browser/android/devtools_auth.h',
+ 'public/browser/android/download_controller_android.cc',
'public/browser/android/download_controller_android.h',
'public/browser/android/external_video_surface_container.h',
'public/browser/android/synchronous_compositor.h',
diff --git a/chromium/content/public/browser/android/download_controller_android.cc b/chromium/content/public/browser/android/download_controller_android.cc
new file mode 100644
index 00000000000..fc5f82e0172
--- /dev/null
+++ b/chromium/content/public/browser/android/download_controller_android.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/android/download_controller_android.h"
+
+namespace content {
+
+// static
+DownloadControllerAndroid* DownloadControllerAndroid::download_controller_ =
+ nullptr;
+
+} // namespace content
diff --git a/chromium/content/public/browser/android/download_controller_android.h b/chromium/content/public/browser/android/download_controller_android.h
index 65da4b82f8f..00844928dd7 100644
--- a/chromium/content/public/browser/android/download_controller_android.h
+++ b/chromium/content/public/browser/android/download_controller_android.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_PUBLIC_BROWSER_ANDROID_DOWNLOAD_CONTROLLER_ANDROID_H_
#define CONTENT_PUBLIC_BROWSER_ANDROID_DOWNLOAD_CONTROLLER_ANDROID_H_
+#include "base/callback.h"
#include "content/common/content_export.h"
#include "content/public/common/context_menu_params.h"
@@ -19,6 +20,10 @@ class CONTENT_EXPORT DownloadControllerAndroid {
// Returns the singleton instance of the DownloadControllerAndroid.
static DownloadControllerAndroid* Get();
+ // Called to set the DownloadControllerAndroid instance.
+ static void SetDownloadControllerAndroid(
+ DownloadControllerAndroid* download_controller);
+
// Starts a new download request with Android. Should be called on the
// UI thread.
virtual void CreateGETDownload(int render_process_id, int render_view_id,
@@ -38,8 +43,22 @@ class CONTENT_EXPORT DownloadControllerAndroid {
virtual void DangerousDownloadValidated(
WebContents* web_contents, int download_id, bool accept) = 0;
+ // Callback when user permission prompt finishes. Args: whether file access
+ // permission is acquired.
+ typedef base::Callback<void(bool)> AcquireFileAccessPermissionCallback;
+
+ // Called to prompt the user for file access permission. When finished,
+ // |callback| will be executed.
+ virtual void AcquireFileAccessPermission(
+ WebContents* web_contents,
+ const AcquireFileAccessPermissionCallback& callback) = 0;
+
+ // Called by unit test to approve or disapprove file access request.
+ virtual void SetApproveFileAccessRequestForTesting(bool approve) {};
+
protected:
virtual ~DownloadControllerAndroid() {};
+ static DownloadControllerAndroid* download_controller_;
};
} // namespace content
diff --git a/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc b/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc
index 85dfd025883..73c4c13877a 100644
--- a/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -2627,8 +2627,19 @@ PP_Bool PepperPluginInstanceImpl::SetFullscreen(PP_Instance instance,
PP_Bool PepperPluginInstanceImpl::GetScreenSize(PP_Instance instance,
PP_Size* size) {
- blink::WebScreenInfo info = render_frame()->GetRenderWidget()->screenInfo();
- *size = PP_MakeSize(info.rect.width, info.rect.height);
+ if (flash_fullscreen_) {
+ // Workaround for Flash rendering bug: Flash is assuming the fullscreen view
+ // size will be equal to the physical screen size. However, the fullscreen
+ // view is sized by the browser UI, and may not be the same size as the
+ // screen or the desktop. Therefore, report the view size as the screen
+ // size when in fullscreen mode. http://crbug.com/506016
+ // TODO(miu): Remove this workaround once Flash has been fixed.
+ *size = view_data_.rect.size;
+ } else {
+ // All other cases: Report the screen size.
+ blink::WebScreenInfo info = render_frame()->GetRenderWidget()->screenInfo();
+ *size = PP_MakeSize(info.rect.width, info.rect.height);
+ }
return PP_TRUE;
}
@@ -3243,6 +3254,11 @@ void PepperPluginInstanceImpl::KeepSizeAttributesBeforeFullscreen() {
void PepperPluginInstanceImpl::SetSizeAttributesForFullscreen() {
if (!render_frame_)
return;
+
+ // TODO(miu): Revisit this logic. If the style must be modified for correct
+ // behavior, the width and height should probably be set to 100%, rather than
+ // a fixed screen size.
+
blink::WebScreenInfo info = render_frame_->GetRenderWidget()->screenInfo();
screen_size_for_fullscreen_ = gfx::Size(info.rect.width, info.rect.height);
std::string width = StringPrintf("%d", screen_size_for_fullscreen_.width());
diff --git a/chromium/device/hid/hid_connection_mac.cc b/chromium/device/hid/hid_connection_mac.cc
index de93cc66da3..57f56af4a39 100644
--- a/chromium/device/hid/hid_connection_mac.cc
+++ b/chromium/device/hid/hid_connection_mac.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/mac/foundation_util.h"
+#include "base/numerics/safe_math.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/thread_task_runner_handle.h"
@@ -135,10 +136,12 @@ void HidConnectionMac::InputReportCallback(void* context,
scoped_refptr<net::IOBufferWithSize> buffer;
if (connection->device_info()->has_report_id()) {
// report_id is already contained in report_bytes
- buffer = new net::IOBufferWithSize(report_length);
+ buffer = new net::IOBufferWithSize(
+ base::CheckedNumeric<size_t>(report_length).ValueOrDie());
memcpy(buffer->data(), report_bytes, report_length);
} else {
- buffer = new net::IOBufferWithSize(report_length + 1);
+ buffer = new net::IOBufferWithSize(
+ (base::CheckedNumeric<size_t>(report_length) + 1).ValueOrDie());
buffer->data()[0] = 0;
memcpy(buffer->data() + 1, report_bytes, report_length);
}
diff --git a/chromium/google_apis/gcm/base/socket_stream.cc b/chromium/google_apis/gcm/base/socket_stream.cc
index edf723cdabd..48c7da89b40 100644
--- a/chromium/google_apis/gcm/base/socket_stream.cc
+++ b/chromium/google_apis/gcm/base/socket_stream.cc
@@ -15,7 +15,7 @@ namespace {
// TODO(zea): consider having dynamically-sized buffers if this becomes too
// expensive.
-const uint32 kDefaultBufferSize = 8*1024;
+const size_t kDefaultBufferSize = 8*1024;
} // namespace
diff --git a/chromium/gpu/config/gpu_driver_bug_list_json.cc b/chromium/gpu/config/gpu_driver_bug_list_json.cc
index c9722b8f254..7a270dfc20a 100644
--- a/chromium/gpu/config/gpu_driver_bug_list_json.cc
+++ b/chromium/gpu/config/gpu_driver_bug_list_json.cc
@@ -19,7 +19,7 @@ const char kGpuDriverBugListJson[] = LONG_STRING_CONST(
{
"name": "gpu driver bug list",
// Please update the version number whenever you change this file.
- "version": "8.12",
+ "version": "8.19",
"entries": [
{
"id": 1,
@@ -1352,6 +1352,22 @@ LONG_STRING_CONST(
"features": [
"exit_on_context_lost"
]
+ },
+ {
+ "id": 124,
+ "description": "Certain Adreno 4xx drivers often crash in glProgramBinary.",
+ "cr_bugs": [486117],
+ "os": {
+ "type": "android"
+ },
+ "driver_version": {
+ "op": "=",
+ "value": "103.0"
+ },
+ "gl_renderer": "Adreno \\(TM\\) 4.*",
+ "features": [
+ "disable_program_cache"
+ ]
}
]
}
diff --git a/chromium/gpu/config/gpu_driver_bug_workaround_type.h b/chromium/gpu/config/gpu_driver_bug_workaround_type.h
index b9dbb295425..27243563291 100644
--- a/chromium/gpu/config/gpu_driver_bug_workaround_type.h
+++ b/chromium/gpu/config/gpu_driver_bug_workaround_type.h
@@ -50,6 +50,8 @@
disable_oes_standard_derivatives) \
GPU_OP(DISABLE_POST_SUB_BUFFERS_FOR_ONSCREEN_SURFACES, \
disable_post_sub_buffers_for_onscreen_surfaces) \
+ GPU_OP(DISABLE_PROGRAM_CACHE, \
+ disable_program_cache) \
GPU_OP(ETC1_POWER_OF_TWO_ONLY, \
etc1_power_of_two_only) \
GPU_OP(EXIT_ON_CONTEXT_LOST, \
diff --git a/chromium/media/cdm/aes_decryptor.cc b/chromium/media/cdm/aes_decryptor.cc
index 77783e3319c..4a2ad43c181 100644
--- a/chromium/media/cdm/aes_decryptor.cc
+++ b/chromium/media/cdm/aes_decryptor.cc
@@ -463,7 +463,8 @@ void AesDecryptor::Decrypt(StreamType stream_type,
encrypted->data_size());
} else {
const std::string& key_id = encrypted->decrypt_config()->key_id();
- DecryptionKey* key = GetKey(key_id);
+ base::AutoLock auto_lock(key_map_lock_);
+ DecryptionKey* key = GetKey_Locked(key_id);
if (!key) {
DVLOG(1) << "Could not find a matching key for the given key ID.";
decrypt_cb.Run(kNoKey, NULL);
@@ -544,9 +545,9 @@ bool AesDecryptor::AddDecryptionKey(const std::string& session_id,
return true;
}
-AesDecryptor::DecryptionKey* AesDecryptor::GetKey(
+AesDecryptor::DecryptionKey* AesDecryptor::GetKey_Locked(
const std::string& key_id) const {
- base::AutoLock auto_lock(key_map_lock_);
+ key_map_lock_.AssertAcquired();
KeyIdToSessionKeysMap::const_iterator key_id_found = key_map_.find(key_id);
if (key_id_found == key_map_.end())
return NULL;
@@ -569,7 +570,7 @@ void AesDecryptor::DeleteKeysForSession(const std::string& session_id) {
base::AutoLock auto_lock(key_map_lock_);
// Remove all keys associated with |session_id|. Since the data is
- // optimized for access in GetKey(), we need to look at each entry in
+ // optimized for access in GetKey_Locked(), we need to look at each entry in
// |key_map_|.
KeyIdToSessionKeysMap::iterator it = key_map_.begin();
while (it != key_map_.end()) {
diff --git a/chromium/media/cdm/aes_decryptor.h b/chromium/media/cdm/aes_decryptor.h
index 278be9534b8..e2540265af5 100644
--- a/chromium/media/cdm/aes_decryptor.h
+++ b/chromium/media/cdm/aes_decryptor.h
@@ -124,7 +124,7 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys,
// Gets a DecryptionKey associated with |key_id|. The AesDecryptor still owns
// the key. Returns NULL if no key is associated with |key_id|.
- DecryptionKey* GetKey(const std::string& key_id) const;
+ DecryptionKey* GetKey_Locked(const std::string& key_id) const;
// Determines if |key_id| is already specified for |session_id|.
bool HasKey(const std::string& session_id, const std::string& key_id);
diff --git a/chromium/media/renderers/video_renderer_impl.cc b/chromium/media/renderers/video_renderer_impl.cc
index 6033782c838..91967848a66 100644
--- a/chromium/media/renderers/video_renderer_impl.cc
+++ b/chromium/media/renderers/video_renderer_impl.cc
@@ -734,9 +734,9 @@ bool VideoRendererImpl::HaveReachedBufferingCap() {
void VideoRendererImpl::StartSink() {
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK_GT(algorithm_->frames_queued(), 0u);
- sink_->Start(this);
sink_started_ = true;
was_background_rendering_ = false;
+ sink_->Start(this);
}
void VideoRendererImpl::StopSink() {
diff --git a/chromium/media/renderers/video_renderer_impl.h b/chromium/media/renderers/video_renderer_impl.h
index a2e89c557d4..7af8bb724f6 100644
--- a/chromium/media/renderers/video_renderer_impl.h
+++ b/chromium/media/renderers/video_renderer_impl.h
@@ -268,7 +268,7 @@ class MEDIA_EXPORT VideoRendererImpl
// Indicates that Render() was called with |background_rendering| set to true,
// so we've entered a background rendering mode where dropped frames are not
- // counted.
+ // counted. Must be accessed under |lock_| once |sink_| is started.
bool was_background_rendering_;
// Indicates whether or not media time is currently progressing or not.
diff --git a/chromium/net/base/io_buffer.cc b/chromium/net/base/io_buffer.cc
index a375381bfd9..d722b449148 100644
--- a/chromium/net/base/io_buffer.cc
+++ b/chromium/net/base/io_buffer.cc
@@ -5,15 +5,38 @@
#include "net/base/io_buffer.h"
#include "base/logging.h"
+#include "base/numerics/safe_math.h"
namespace net {
+namespace {
+
+// TODO(eroman): IOBuffer is being converted to require buffer sizes and offsets
+// be specified as "size_t" rather than "int" (crbug.com/488553). To facilitate
+// this move (since LOTS of code needs to be updated), both "size_t" and "int
+// are being accepted. When using "size_t" this function ensures that it can be
+// safely converted to an "int" without truncation.
+void AssertValidBufferSize(size_t size) {
+ base::CheckedNumeric<int>(size).ValueOrDie();
+}
+
+void AssertValidBufferSize(int size) {
+ CHECK_GE(size, 0);
+}
+
+} // namespace
+
IOBuffer::IOBuffer()
: data_(NULL) {
}
IOBuffer::IOBuffer(int buffer_size) {
- CHECK_GE(buffer_size, 0);
+ AssertValidBufferSize(buffer_size);
+ data_ = new char[buffer_size];
+}
+
+IOBuffer::IOBuffer(size_t buffer_size) {
+ AssertValidBufferSize(buffer_size);
data_ = new char[buffer_size];
}
@@ -29,11 +52,22 @@ IOBuffer::~IOBuffer() {
IOBufferWithSize::IOBufferWithSize(int size)
: IOBuffer(size),
size_(size) {
+ AssertValidBufferSize(size);
+}
+
+IOBufferWithSize::IOBufferWithSize(size_t size) : IOBuffer(size), size_(size) {
+ // Note: Size check is done in superclass' constructor.
}
IOBufferWithSize::IOBufferWithSize(char* data, int size)
: IOBuffer(data),
size_(size) {
+ AssertValidBufferSize(size);
+}
+
+IOBufferWithSize::IOBufferWithSize(char* data, size_t size)
+ : IOBuffer(data), size_(size) {
+ AssertValidBufferSize(size);
}
IOBufferWithSize::~IOBufferWithSize() {
@@ -42,13 +76,13 @@ IOBufferWithSize::~IOBufferWithSize() {
StringIOBuffer::StringIOBuffer(const std::string& s)
: IOBuffer(static_cast<char*>(NULL)),
string_data_(s) {
- CHECK_LT(s.size(), static_cast<size_t>(INT_MAX));
+ AssertValidBufferSize(s.size());
data_ = const_cast<char*>(string_data_.data());
}
StringIOBuffer::StringIOBuffer(scoped_ptr<std::string> s)
: IOBuffer(static_cast<char*>(NULL)) {
- CHECK_LT(s->size(), static_cast<size_t>(INT_MAX));
+ AssertValidBufferSize(s->size());
string_data_.swap(*s.get());
data_ = const_cast<char*>(string_data_.data());
}
@@ -64,6 +98,12 @@ DrainableIOBuffer::DrainableIOBuffer(IOBuffer* base, int size)
base_(base),
size_(size),
used_(0) {
+ AssertValidBufferSize(size);
+}
+
+DrainableIOBuffer::DrainableIOBuffer(IOBuffer* base, size_t size)
+ : IOBuffer(base->data()), base_(base), size_(size), used_(0) {
+ AssertValidBufferSize(size);
}
void DrainableIOBuffer::DidConsume(int bytes) {
diff --git a/chromium/net/base/io_buffer.h b/chromium/net/base/io_buffer.h
index 04bbc883e97..83f81a8485e 100644
--- a/chromium/net/base/io_buffer.h
+++ b/chromium/net/base/io_buffer.h
@@ -73,7 +73,10 @@ namespace net {
class NET_EXPORT IOBuffer : public base::RefCountedThreadSafe<IOBuffer> {
public:
IOBuffer();
+
+ // TODO(eroman): Deprecated. Use the size_t flavor instead. crbug.com/488553
explicit IOBuffer(int buffer_size);
+ explicit IOBuffer(size_t buffer_size);
char* data() { return data_; }
@@ -95,15 +98,20 @@ class NET_EXPORT IOBuffer : public base::RefCountedThreadSafe<IOBuffer> {
// argument to IO functions. Please keep using IOBuffer* for API declarations.
class NET_EXPORT IOBufferWithSize : public IOBuffer {
public:
+ // TODO(eroman): Deprecated. Use the size_t flavor instead. crbug.com/488553
explicit IOBufferWithSize(int size);
+ explicit IOBufferWithSize(size_t size);
int size() const { return size_; }
protected:
+ // TODO(eroman): Deprecated. Use the size_t flavor instead. crbug.com/488553
+ IOBufferWithSize(char* data, int size);
+
// Purpose of this constructor is to give a subclass access to the base class
// constructor IOBuffer(char*) thus allowing subclass to use underlying
// memory it does not own.
- IOBufferWithSize(char* data, int size);
+ IOBufferWithSize(char* data, size_t size);
~IOBufferWithSize() override;
int size_;
@@ -143,7 +151,9 @@ class NET_EXPORT StringIOBuffer : public IOBuffer {
//
class NET_EXPORT DrainableIOBuffer : public IOBuffer {
public:
+ // TODO(eroman): Deprecated. Use the size_t flavor instead. crbug.com/488553
DrainableIOBuffer(IOBuffer* base, int size);
+ DrainableIOBuffer(IOBuffer* base, size_t size);
// DidConsume() changes the |data_| pointer so that |data_| always points
// to the first unconsumed byte.
diff --git a/chromium/net/log/net_log_event_type_list.h b/chromium/net/log/net_log_event_type_list.h
index 60f42a32e06..c582a257503 100644
--- a/chromium/net/log/net_log_event_type_list.h
+++ b/chromium/net/log/net_log_event_type_list.h
@@ -1795,6 +1795,75 @@ EVENT_TYPE(APPCACHE_DELIVERING_ERROR_RESPONSE)
EVENT_TYPE(APPCACHE_DELIVERING_EXECUTABLE_RESPONSE)
// ------------------------------------------------------------------------
+// Service Worker
+// ------------------------------------------------------------------------
+// This event is emitted when Service Worker starts to handle a request.
+EVENT_TYPE(SERVICE_WORKER_START_REQUEST)
+
+// This event is emitted when Service Worker results in a fallback to network
+// response.
+EVENT_TYPE(SERVICE_WORKER_FALLBACK_RESPONSE)
+
+// This event is emitted when Service Worker results in a fallback to network
+// response, and asks the renderer rather than the browser to do the fallback
+// due to CORS.
+EVENT_TYPE(SERVICE_WORKER_FALLBACK_FOR_CORS)
+
+// This event is emitted when Service Worker responds with a headers-only
+// response.
+EVENT_TYPE(SERVICE_WORKER_HEADERS_ONLY_RESPONSE)
+
+// This event is emitted when Service Worker responds with a stream.
+EVENT_TYPE(SERVICE_WORKER_STREAM_RESPONSE)
+
+// This event is emitted when Service Worker responds with a blob.
+EVENT_TYPE(SERVICE_WORKER_BLOB_RESPONSE)
+
+// This event is emitted when Service Worker instructs the browser
+// to respond with a network error.
+EVENT_TYPE(SERVICE_WORKER_ERROR_RESPONSE_STATUS_ZERO)
+
+// This event is emitted when Service Worker attempts to respond with
+// a blob, but it was not readable.
+EVENT_TYPE(SERVICE_WORKER_ERROR_BAD_BLOB)
+
+// This event is emitted when Service Worker fails to respond because
+// the provider host was null.
+EVENT_TYPE(SERVICE_WORKER_ERROR_NO_PROVIDER_HOST)
+
+// This event is emitted when Service Worker fails to respond because
+// the registration had no active version.
+EVENT_TYPE(SERVICE_WORKER_ERROR_NO_ACTIVE_VERSION)
+
+// This event is emitted when Service Worker fails to respond because
+// the underlying request was detached.
+EVENT_TYPE(SERVICE_WORKER_ERROR_NO_REQUEST)
+
+// This event is emitted when Service Worker fails to respond because
+// the fetch event could not be dispatched to the worker.
+EVENT_TYPE(SERVICE_WORKER_ERROR_FETCH_EVENT_DISPATCH)
+
+// This event is emitted when Service Worker fails to respond because
+// of an error when reading the blob response.
+EVENT_TYPE(SERVICE_WORKER_ERROR_BLOB_READ)
+
+// This event is emitted when Service Worker fails to respond because
+// of an error when reading the stream response.
+EVENT_TYPE(SERVICE_WORKER_ERROR_STREAM_ABORTED)
+
+// This event is emitted when Service Worker is destroyed before it
+// responds.
+EVENT_TYPE(SERVICE_WORKER_ERROR_KILLED)
+
+// This event is emitted when Service Worker is destroyed before it
+// finishes responding with a blob.
+EVENT_TYPE(SERVICE_WORKER_ERROR_KILLED_WITH_BLOB)
+
+// This event is emitted when Service Worker is destroyed before it
+// finishes responding with a stream.
+EVENT_TYPE(SERVICE_WORKER_ERROR_KILLED_WITH_STREAM)
+
+// ------------------------------------------------------------------------
// Global events
// ------------------------------------------------------------------------
// These are events which are not grouped by source id, as they have no
diff --git a/chromium/net/quic/quic_http_stream.cc b/chromium/net/quic/quic_http_stream.cc
index ac73d67fc82..cce1512c788 100644
--- a/chromium/net/quic/quic_http_stream.cc
+++ b/chromium/net/quic/quic_http_stream.cc
@@ -146,7 +146,8 @@ int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
// request_body_stream_->is_chunked()))
// Use 10 packets as the body buffer size to give enough space to
// help ensure we don't often send out partial packets.
- raw_request_body_buf_ = new IOBufferWithSize(10 * kMaxPacketSize);
+ raw_request_body_buf_ =
+ new IOBufferWithSize(static_cast<size_t>(10 * kMaxPacketSize));
// The request body buffer is empty at first.
request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), 0);
}
diff --git a/chromium/net/quic/quic_packet_reader.cc b/chromium/net/quic/quic_packet_reader.cc
index 5087870c206..93451daaaba 100644
--- a/chromium/net/quic/quic_packet_reader.cc
+++ b/chromium/net/quic/quic_packet_reader.cc
@@ -16,7 +16,7 @@ QuicPacketReader::QuicPacketReader(DatagramClientSocket* socket,
visitor_(visitor),
read_pending_(false),
num_packets_read_(0),
- read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
+ read_buffer_(new IOBufferWithSize(static_cast<size_t>(kMaxPacketSize))),
net_log_(net_log),
weak_factory_(this) {
}
diff --git a/chromium/net/socket/ssl_client_socket_nss.cc b/chromium/net/socket/ssl_client_socket_nss.cc
index 7c5264db81b..c31995042ea 100644
--- a/chromium/net/socket/ssl_client_socket_nss.cc
+++ b/chromium/net/socket/ssl_client_socket_nss.cc
@@ -1762,7 +1762,7 @@ int SSLClientSocketNSS::Core::BufferSend() {
// return ERR_ABORTED. See https://crbug.com/381160.
return ERR_ABORTED;
}
- const unsigned int len = len1 + len2;
+ const size_t len = len1 + len2;
int rv = 0;
if (len) {
diff --git a/chromium/net/socket/ssl_server_socket_nss.cc b/chromium/net/socket/ssl_server_socket_nss.cc
index 6f505affdd7..4483c911134 100644
--- a/chromium/net/socket/ssl_server_socket_nss.cc
+++ b/chromium/net/socket/ssl_server_socket_nss.cc
@@ -560,7 +560,7 @@ int SSLServerSocketNSS::BufferSend(void) {
// The error code itself is ignored, so just return ERR_ABORTED.
return ERR_ABORTED;
}
- const unsigned int len = len1 + len2;
+ const size_t len = len1 + len2;
int rv = 0;
if (len) {
diff --git a/chromium/net/websockets/websocket_deflater.cc b/chromium/net/websockets/websocket_deflater.cc
index a4c56bccb19..9144c0116dc 100644
--- a/chromium/net/websockets/websocket_deflater.cc
+++ b/chromium/net/websockets/websocket_deflater.cc
@@ -97,10 +97,11 @@ void WebSocketDeflater::PushSyncMark() {
}
scoped_refptr<IOBufferWithSize> WebSocketDeflater::GetOutput(size_t size) {
+ size_t length_to_copy = std::min(size, buffer_.size());
std::deque<char>::iterator begin = buffer_.begin();
- std::deque<char>::iterator end = begin + std::min(size, buffer_.size());
+ std::deque<char>::iterator end = begin + length_to_copy;
- scoped_refptr<IOBufferWithSize> result = new IOBufferWithSize(end - begin);
+ scoped_refptr<IOBufferWithSize> result = new IOBufferWithSize(length_to_copy);
std::copy(begin, end, result->data());
buffer_.erase(begin, end);
return result;
diff --git a/chromium/net/websockets/websocket_inflater.cc b/chromium/net/websockets/websocket_inflater.cc
index 1d6122bf953..7767821f462 100644
--- a/chromium/net/websockets/websocket_inflater.cc
+++ b/chromium/net/websockets/websocket_inflater.cc
@@ -18,11 +18,11 @@ namespace {
class ShrinkableIOBufferWithSize : public IOBufferWithSize {
public:
- explicit ShrinkableIOBufferWithSize(int size)
- : IOBufferWithSize(size) {}
+ explicit ShrinkableIOBufferWithSize(size_t size) : IOBufferWithSize(size) {}
void Shrink(int new_size) {
- DCHECK_LE(new_size, size_);
+ CHECK_GE(new_size, 0);
+ CHECK_LE(new_size, size_);
size_ = new_size;
}
diff --git a/chromium/third_party/WebKit/Source/core/css/parser/CSSParser.cpp b/chromium/third_party/WebKit/Source/core/css/parser/CSSParser.cpp
index 58d12275e2e..746cbfdde9a 100644
--- a/chromium/third_party/WebKit/Source/core/css/parser/CSSParser.cpp
+++ b/chromium/third_party/WebKit/Source/core/css/parser/CSSParser.cpp
@@ -43,7 +43,7 @@ void CSSParser::parseSelector(const CSSParserContext& context, const String& sel
PassRefPtrWillBeRawPtr<StyleRuleBase> CSSParser::parseRule(const CSSParserContext& context, StyleSheetContents* styleSheet, const String& rule)
{
if (RuntimeEnabledFeatures::newCSSParserEnabled())
- return CSSParserImpl::parseRule(rule, context, CSSParserImpl::AllowImportRules);
+ return CSSParserImpl::parseRule(rule, context, styleSheet, CSSParserImpl::AllowImportRules);
return BisonCSSParser(context).parseRule(styleSheet, rule);
}
@@ -109,7 +109,7 @@ PassOwnPtr<Vector<double>> CSSParser::parseKeyframeKeyList(const String& keyList
PassRefPtrWillBeRawPtr<StyleRuleKeyframe> CSSParser::parseKeyframeRule(const CSSParserContext& context, StyleSheetContents* styleSheet, const String& rule)
{
if (RuntimeEnabledFeatures::newCSSParserEnabled()) {
- RefPtrWillBeRawPtr<StyleRuleBase> keyframe = CSSParserImpl::parseRule(rule, context, CSSParserImpl::KeyframeRules);
+ RefPtrWillBeRawPtr<StyleRuleBase> keyframe = CSSParserImpl::parseRule(rule, context, nullptr, CSSParserImpl::KeyframeRules);
return toStyleRuleKeyframe(keyframe.get());
}
return BisonCSSParser(context).parseKeyframeRule(styleSheet, rule);
diff --git a/chromium/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp b/chromium/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp
index 96da29cb822..e1509b5695e 100644
--- a/chromium/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp
+++ b/chromium/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp
@@ -101,9 +101,9 @@ bool CSSParserImpl::parseDeclarationList(MutableStylePropertySet* declaration, c
return declaration->addParsedProperties(parser.m_parsedProperties);
}
-PassRefPtrWillBeRawPtr<StyleRuleBase> CSSParserImpl::parseRule(const String& string, const CSSParserContext& context, AllowedRulesType allowedRules)
+PassRefPtrWillBeRawPtr<StyleRuleBase> CSSParserImpl::parseRule(const String& string, const CSSParserContext& context, StyleSheetContents* styleSheet, AllowedRulesType allowedRules)
{
- CSSParserImpl parser(context);
+ CSSParserImpl parser(context, styleSheet);
CSSTokenizer::Scope scope(string);
CSSParserTokenRange range = scope.tokenRange();
range.consumeWhitespace();
diff --git a/chromium/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h b/chromium/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h
index daedf0b4a28..b3e81f90bbe 100644
--- a/chromium/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h
+++ b/chromium/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h
@@ -57,7 +57,7 @@ public:
static bool parseValue(MutableStylePropertySet*, CSSPropertyID, const String&, bool important, const CSSParserContext&);
static PassRefPtrWillBeRawPtr<ImmutableStylePropertySet> parseInlineStyleDeclaration(const String&, Element*);
static bool parseDeclarationList(MutableStylePropertySet*, const String&, const CSSParserContext&);
- static PassRefPtrWillBeRawPtr<StyleRuleBase> parseRule(const String&, const CSSParserContext&, AllowedRulesType);
+ static PassRefPtrWillBeRawPtr<StyleRuleBase> parseRule(const String&, const CSSParserContext&, StyleSheetContents*, AllowedRulesType);
static void parseStyleSheet(const String&, const CSSParserContext&, StyleSheetContents*);
static PassOwnPtr<Vector<double>> parseKeyframeKeyList(const String&);
diff --git a/chromium/third_party/WebKit/Source/core/dom/NodeRareData.cpp b/chromium/third_party/WebKit/Source/core/dom/NodeRareData.cpp
index 65d14a36a2c..6365a9caeeb 100644
--- a/chromium/third_party/WebKit/Source/core/dom/NodeRareData.cpp
+++ b/chromium/third_party/WebKit/Source/core/dom/NodeRareData.cpp
@@ -73,6 +73,12 @@ void NodeRareData::finalizeGarbageCollectedObject()
this->~NodeRareData();
}
+void NodeRareData::incrementConnectedSubframeCount(unsigned amount)
+{
+ RELEASE_ASSERT_WITH_SECURITY_IMPLICATION((m_connectedFrameCount + amount) <= FrameHost::maxNumberOfFrames);
+ m_connectedFrameCount += amount;
+}
+
// Ensure the 10 bits reserved for the m_connectedFrameCount cannot overflow
static_assert(FrameHost::maxNumberOfFrames < (1 << NodeRareData::ConnectedFrameCountBits), "Frame limit should fit in rare data count");
diff --git a/chromium/third_party/WebKit/Source/core/dom/NodeRareData.h b/chromium/third_party/WebKit/Source/core/dom/NodeRareData.h
index f19088c088d..2f43c45bba6 100644
--- a/chromium/third_party/WebKit/Source/core/dom/NodeRareData.h
+++ b/chromium/third_party/WebKit/Source/core/dom/NodeRareData.h
@@ -82,10 +82,7 @@ public:
}
unsigned connectedSubframeCount() const { return m_connectedFrameCount; }
- void incrementConnectedSubframeCount(unsigned amount)
- {
- m_connectedFrameCount += amount;
- }
+ void incrementConnectedSubframeCount(unsigned amount);
void decrementConnectedSubframeCount(unsigned amount)
{
ASSERT(m_connectedFrameCount);
diff --git a/chromium/third_party/WebKit/Source/core/editing/htmlediting.cpp b/chromium/third_party/WebKit/Source/core/editing/htmlediting.cpp
index f874952bfcb..5931c1f11ca 100644
--- a/chromium/third_party/WebKit/Source/core/editing/htmlediting.cpp
+++ b/chromium/third_party/WebKit/Source/core/editing/htmlediting.cpp
@@ -958,11 +958,11 @@ void updatePositionForNodeRemoval(Position& position, Node& node)
return;
switch (position.anchorType()) {
case Position::PositionIsBeforeChildren:
- if (position.containerNode() == node)
+ if (node.containsIncludingShadowDOM(position.containerNode()))
position = positionInParentBeforeNode(node);
break;
case Position::PositionIsAfterChildren:
- if (position.containerNode() == node)
+ if (node.containsIncludingShadowDOM(position.containerNode()))
position = positionInParentAfterNode(node);
break;
case Position::PositionIsOffsetInAnchor:
diff --git a/chromium/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/chromium/third_party/WebKit/Source/core/frame/LocalFrame.cpp
index 103113f0c0b..3397abcacff 100644
--- a/chromium/third_party/WebKit/Source/core/frame/LocalFrame.cpp
+++ b/chromium/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -693,8 +693,6 @@ bool LocalFrame::isURLAllowed(const KURL& url) const
{
// We allow one level of self-reference because some sites depend on that,
// but we don't allow more than one.
- if (host()->subframeCount() >= FrameHost::maxNumberOfFrames)
- return false;
bool foundSelfReference = false;
for (const Frame* frame = this; frame; frame = frame->tree().parent()) {
if (!frame->isLocalFrame())
diff --git a/chromium/third_party/WebKit/Source/core/frame/UseCounter.cpp b/chromium/third_party/WebKit/Source/core/frame/UseCounter.cpp
index 380aea184e1..1c8e52f49e4 100644
--- a/chromium/third_party/WebKit/Source/core/frame/UseCounter.cpp
+++ b/chromium/third_party/WebKit/Source/core/frame/UseCounter.cpp
@@ -884,7 +884,7 @@ String UseCounter::deprecationMessage(Feature feature)
return "'SVGSVGElement.unsuspendRedrawAll()' is deprecated, please do not use it. It is a no-op, as per SVG2 (https://svgwg.org/svg2-draft/struct.html#__svg__SVGSVGElement__unsuspendRedrawAll).";
case ServiceWorkerClientPostMessage:
- return "'Client.postMessage()' is an experimental API and may change. See https://github.com/slightlyoff/ServiceWorker/issues/609.";
+ return "'Client.postMessage()' will change to fire an event on 'navigator.serviceWorker' instead of 'window' in M45 (see: https://www.chromestatus.com/feature/5163630974730240).";
case AttrChildAccess:
case AttrChildChange:
diff --git a/chromium/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp b/chromium/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
index 259bf143cf9..3f278b43f71 100644
--- a/chromium/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
+++ b/chromium/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
@@ -26,6 +26,7 @@
#include "core/dom/AXObjectCache.h"
#include "core/dom/ExceptionCode.h"
#include "core/events/Event.h"
+#include "core/frame/FrameHost.h"
#include "core/frame/FrameView.h"
#include "core/frame/LocalFrame.h"
#include "core/layout/LayoutPart.h"
@@ -257,6 +258,9 @@ bool HTMLFrameOwnerElement::loadOrRedirectSubframe(const KURL& url, const Atomic
if (!SubframeLoadingDisabler::canLoadFrame(*this))
return false;
+ if (document().frame()->host()->subframeCount() >= FrameHost::maxNumberOfFrames)
+ return false;
+
return parentFrame->loader().client()->createFrame(FrameLoadRequest(&document(), url, "_self", CheckContentSecurityPolicy), frameName, this);
}
diff --git a/chromium/third_party/WebKit/Source/core/html/HTMLImageElement.cpp b/chromium/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
index b725d6b2984..d46f9de78ae 100644
--- a/chromium/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
+++ b/chromium/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
@@ -330,12 +330,12 @@ ImageCandidate HTMLImageElement::findBestFitImageFromPictureParent()
LayoutObject* HTMLImageElement::createLayoutObject(const ComputedStyle& style)
{
- if (style.hasContent())
- return LayoutObject::createObject(this, style);
-
if (m_useFallbackContent)
return new LayoutBlockFlow(this);
+ if (style.hasContent())
+ return LayoutObject::createObject(this, style);
+
LayoutImage* image = new LayoutImage(this);
image->setImageResource(LayoutImageResource::create());
image->setImageDevicePixelRatio(m_imageDevicePixelRatio);
diff --git a/chromium/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/chromium/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index 669439d1da1..78d81b97ca4 100644
--- a/chromium/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/chromium/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -562,8 +562,6 @@ bool FrameLoader::allowPlugins(ReasonForCallingAllowPlugins reason)
void FrameLoader::updateForSameDocumentNavigation(const KURL& newURL, SameDocumentNavigationSource sameDocumentNavigationSource, PassRefPtr<SerializedScriptValue> data, HistoryScrollRestorationType scrollRestorationType, FrameLoadType type)
{
- saveScrollState();
-
// Update the data source's request with the new URL to fake the URL change
m_frame->document()->setURL(newURL);
documentLoader()->setReplacesCurrentHistoryItem(type != FrameLoadTypeStandard);
@@ -601,6 +599,7 @@ void FrameLoader::loadInSameDocument(const KURL& url, PassRefPtr<SerializedScrip
return;
}
m_loadType = type;
+ saveScrollState();
KURL oldURL = m_frame->document()->url();
// If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
diff --git a/chromium/third_party/WebKit/Source/core/timing/ConsoleMemory.cpp b/chromium/third_party/WebKit/Source/core/timing/ConsoleMemory.cpp
index a44ff10768f..bd1bdf74812 100644
--- a/chromium/third_party/WebKit/Source/core/timing/ConsoleMemory.cpp
+++ b/chromium/third_party/WebKit/Source/core/timing/ConsoleMemory.cpp
@@ -10,12 +10,6 @@
namespace blink {
-DEFINE_TRACE(ConsoleMemory)
-{
- visitor->trace(m_memory);
- HeapSupplement<Console>::trace(visitor);
-}
-
// static
ConsoleMemory& ConsoleMemory::from(Console& console)
{
@@ -35,10 +29,7 @@ MemoryInfo* ConsoleMemory::memory(Console& console)
MemoryInfo* ConsoleMemory::memory()
{
- if (!m_memory)
- m_memory = MemoryInfo::create();
-
- return m_memory.get();
+ return MemoryInfo::create();
}
} // namespace blink
diff --git a/chromium/third_party/WebKit/Source/core/timing/ConsoleMemory.h b/chromium/third_party/WebKit/Source/core/timing/ConsoleMemory.h
index 0276bc70eaa..ad7c0dbadad 100644
--- a/chromium/third_party/WebKit/Source/core/timing/ConsoleMemory.h
+++ b/chromium/third_party/WebKit/Source/core/timing/ConsoleMemory.h
@@ -19,13 +19,11 @@ public:
static MemoryInfo* memory(Console&);
static void setMemory(Console&, MemoryInfo*) { }
- DECLARE_VIRTUAL_TRACE();
+ DEFINE_INLINE_VIRTUAL_TRACE() { HeapSupplement<Console>::trace(visitor); }
private:
static const char* supplementName() { return "ConsoleMemory"; }
MemoryInfo* memory();
-
- Member<MemoryInfo> m_memory;
};
} // namespace blink
diff --git a/chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp b/chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
index 286a38138ac..12ac82bcadd 100644
--- a/chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
+++ b/chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
@@ -665,6 +665,9 @@ void XMLHttpRequest::dispatchReadyStateChangeEvent()
if (!executionContext())
return;
+ // We need this protection because dispatchReadyStateChangeEvent may
+ // dispatch multiple events.
+ ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel);
if (m_async || (m_state <= OPENED || m_state == DONE)) {
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "XHRReadyStateChange", "data", InspectorXhrReadyStateChangeEvent::data(executionContext(), this));
XMLHttpRequestProgressEventThrottle::DeferredEventAction action = XMLHttpRequestProgressEventThrottle::Ignore;
diff --git a/chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequestProgressEventThrottle.cpp b/chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequestProgressEventThrottle.cpp
index 5f9e9d15cb0..f3d619673fd 100644
--- a/chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequestProgressEventThrottle.cpp
+++ b/chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequestProgressEventThrottle.cpp
@@ -28,7 +28,7 @@
#include "core/xmlhttprequest/XMLHttpRequestProgressEventThrottle.h"
#include "core/EventTypeNames.h"
-#include "core/events/EventTarget.h"
+#include "core/xmlhttprequest/XMLHttpRequest.h"
#include "core/xmlhttprequest/XMLHttpRequestProgressEvent.h"
#include "wtf/Assertions.h"
#include "wtf/text/AtomicString.h"
@@ -66,7 +66,7 @@ private:
const double XMLHttpRequestProgressEventThrottle::minimumProgressEventDispatchingIntervalInSeconds = .05; // 50 ms per specification.
-XMLHttpRequestProgressEventThrottle::XMLHttpRequestProgressEventThrottle(EventTarget* target)
+XMLHttpRequestProgressEventThrottle::XMLHttpRequestProgressEventThrottle(XMLHttpRequest* target)
: m_target(target)
, m_deferred(adoptPtr(new DeferredEvent))
{
@@ -96,17 +96,25 @@ void XMLHttpRequestProgressEventThrottle::dispatchProgressEvent(const AtomicStri
void XMLHttpRequestProgressEventThrottle::dispatchReadyStateChangeEvent(PassRefPtrWillBeRawPtr<Event> event, DeferredEventAction action)
{
+ XMLHttpRequest::State state = m_target->readyState();
// Given that ResourceDispatcher doesn't deliver an event when suspended,
// we don't have to worry about event dispatching while suspended.
if (action == Flush) {
dispatchDeferredEvent();
+ // |m_target| is protected by the caller.
stop();
} else if (action == Clear) {
m_deferred->clear();
stop();
}
- m_target->dispatchEvent(event);
+ if (state == m_target->readyState()) {
+ // We don't dispatch the event when an event handler associated with
+ // the previously dispatched event changes the readyState (e.g. when
+ // the event handler calls xhr.abort()). In such cases a
+ // readystatechange should have been already dispatched if necessary.
+ m_target->dispatchEvent(event);
+ }
}
void XMLHttpRequestProgressEventThrottle::dispatchDeferredEvent()
diff --git a/chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequestProgressEventThrottle.h b/chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequestProgressEventThrottle.h
index edb3e13bf48..839d14e348f 100644
--- a/chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequestProgressEventThrottle.h
+++ b/chromium/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequestProgressEventThrottle.h
@@ -36,7 +36,7 @@
namespace blink {
class Event;
-class EventTarget;
+class XMLHttpRequest;
// This class implements the XHR2 ProgressEvent dispatching:
// "dispatch a progress event named progress about every 50ms or for every
@@ -58,7 +58,7 @@ public:
Flush,
};
- explicit XMLHttpRequestProgressEventThrottle(EventTarget*);
+ explicit XMLHttpRequestProgressEventThrottle(XMLHttpRequest*);
virtual ~XMLHttpRequestProgressEventThrottle();
// Dispatches a ProgressEvent.
@@ -93,7 +93,7 @@ private:
// the one holding us. With Oilpan, a simple strong Member can be used -
// this XMLHttpRequestProgressEventThrottle (part) object dies together
// with the XMLHttpRequest object.
- RawPtrWillBeMember<EventTarget> m_target;
+ RawPtrWillBeMember<XMLHttpRequest> m_target;
// A slot for the deferred "progress" ProgressEvent. When multiple events
// arrive, only the last one is stored and others are discarded.
diff --git a/chromium/third_party/WebKit/Source/devtools/front_end/elements/spectrum.css b/chromium/third_party/WebKit/Source/devtools/front_end/elements/spectrum.css
index 90b8303ff2f..3d5b6bfbc54 100644
--- a/chromium/third_party/WebKit/Source/devtools/front_end/elements/spectrum.css
+++ b/chromium/third_party/WebKit/Source/devtools/front_end/elements/spectrum.css
@@ -114,7 +114,6 @@
.spectrum-text-value {
display: inline-block;
width: 36px;
- max-width: 36px;
overflow: hidden;
text-align: center;
border: 1px solid #dadada;
diff --git a/chromium/third_party/WebKit/Source/devtools/front_end/emulation/EmulatedDevices.js b/chromium/third_party/WebKit/Source/devtools/front_end/emulation/EmulatedDevices.js
index 115572f6794..59660fce004 100644
--- a/chromium/third_party/WebKit/Source/devtools/front_end/emulation/EmulatedDevices.js
+++ b/chromium/third_party/WebKit/Source/devtools/front_end/emulation/EmulatedDevices.js
@@ -424,6 +424,7 @@ WebInspector.EmulatedDevice.Images.prototype = {
WebInspector.EmulatedDevicesList = function()
{
WebInspector.Object.call(this);
+ WebInspector.settings.createSetting("standardEmulatedDeviceList", []).remove();
/**
* @param {!Array.<*>} list
diff --git a/chromium/third_party/WebKit/Source/modules/accessibility/AXMenuListOption.cpp b/chromium/third_party/WebKit/Source/modules/accessibility/AXMenuListOption.cpp
index 68973631a95..d4fa94d2b96 100644
--- a/chromium/third_party/WebKit/Source/modules/accessibility/AXMenuListOption.cpp
+++ b/chromium/third_party/WebKit/Source/modules/accessibility/AXMenuListOption.cpp
@@ -102,9 +102,13 @@ bool AXMenuListOption::computeAccessibilityIsIgnored(IgnoredReasons* ignoredReas
LayoutRect AXMenuListOption::elementRect() const
{
AXObject* parent = parentObject();
+ if (!parent)
+ return LayoutRect();
ASSERT(parent->isMenuListPopup());
AXObject* grandparent = parent->parentObject();
+ if (!grandparent)
+ return LayoutRect();
ASSERT(grandparent->isMenuList());
return grandparent->elementRect();
diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp b/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
index 53c5cb0c534..5719923e76d 100644
--- a/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
+++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
@@ -138,6 +138,7 @@ bool ImageFrameGenerator::decodeAndScale(const SkImageInfo& info, size_t index,
ASSERT(bitmap.height() == scaledSize.height());
bool result = true;
+ SkAutoLockPixels bitmapLock(bitmap);
// Check to see if decoder has written directly to the memory provided
// by Skia. If not make a copy.
if (bitmap.getPixels() != pixels)
diff --git a/chromium/third_party/ashmem/BUILD.gn b/chromium/third_party/ashmem/BUILD.gn
deleted file mode 100644
index 5e92b3773f5..00000000000
--- a/chromium/third_party/ashmem/BUILD.gn
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-assert(is_android)
-
-source_set("ashmem") {
- sources = [
- "ashmem-dev.c",
- "ashmem.h",
- ]
-}
diff --git a/chromium/third_party/ashmem/LICENSE b/chromium/third_party/ashmem/LICENSE
deleted file mode 100644
index d6456956733..00000000000
--- a/chromium/third_party/ashmem/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/chromium/third_party/ashmem/OWNERS b/chromium/third_party/ashmem/OWNERS
deleted file mode 100644
index 938d2b5c483..00000000000
--- a/chromium/third_party/ashmem/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-digit@chromium.org
diff --git a/chromium/third_party/ashmem/README.chromium b/chromium/third_party/ashmem/README.chromium
deleted file mode 100644
index 833e1f5b017..00000000000
--- a/chromium/third_party/ashmem/README.chromium
+++ /dev/null
@@ -1,6 +0,0 @@
-Name: Android
-URL: http://source.android.com
-Description: Android shared memory implementation. Only applies to OS_ANDROID.
-Version: 7203eb2a8a29a7b721a48cd291700f38f3da1456
-Security Critical: yes
-License: Apache 2.0
diff --git a/chromium/third_party/ashmem/ashmem-dev.c b/chromium/third_party/ashmem/ashmem-dev.c
deleted file mode 100644
index 2303369d816..00000000000
--- a/chromium/third_party/ashmem/ashmem-dev.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Implementation of the user-space ashmem API for devices, which have our
- * ashmem-enabled kernel. See ashmem-sim.c for the "fake" tmp-based version,
- * used by the simulator.
- */
-
-#include <unistd.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-
-#include <linux/ashmem.h>
-#include "ashmem.h"
-
-#define ASHMEM_DEVICE "/dev/ashmem"
-
-/*
- * ashmem_create_region - creates a new ashmem region and returns the file
- * descriptor, or <0 on error
- *
- * `name' is an optional label to give the region (visible in /proc/pid/maps)
- * `size' is the size of the region, in page-aligned bytes
- */
-int ashmem_create_region(const char *name, size_t size)
-{
- int fd, ret;
-
- fd = open(ASHMEM_DEVICE, O_RDWR);
- if (fd < 0)
- return fd;
-
- if (name) {
- char buf[ASHMEM_NAME_LEN];
-
- strlcpy(buf, name, sizeof(buf));
- ret = ioctl(fd, ASHMEM_SET_NAME, buf);
- if (ret < 0)
- goto error;
- }
-
- ret = ioctl(fd, ASHMEM_SET_SIZE, size);
- if (ret < 0)
- goto error;
-
- return fd;
-
-error:
- close(fd);
- return ret;
-}
-
-int ashmem_set_prot_region(int fd, int prot)
-{
- return ioctl(fd, ASHMEM_SET_PROT_MASK, prot);
-}
-
-int ashmem_pin_region(int fd, size_t offset, size_t len)
-{
- struct ashmem_pin pin = { offset, len };
- return ioctl(fd, ASHMEM_PIN, &pin);
-}
-
-int ashmem_unpin_region(int fd, size_t offset, size_t len)
-{
- struct ashmem_pin pin = { offset, len };
- return ioctl(fd, ASHMEM_UNPIN, &pin);
-}
-
-int ashmem_get_size_region(int fd)
-{
- return ioctl(fd, ASHMEM_GET_SIZE, NULL);
-}
-
-int ashmem_purge_all(void)
-{
- const int fd = open(ASHMEM_DEVICE, O_RDWR);
- if (fd < 0)
- return fd;
- const int ret = ioctl(fd, ASHMEM_PURGE_ALL_CACHES, 0);
- close(fd);
- return ret;
-}
diff --git a/chromium/third_party/ashmem/ashmem.h b/chromium/third_party/ashmem/ashmem.h
deleted file mode 100644
index 7d411cc064b..00000000000
--- a/chromium/third_party/ashmem/ashmem.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* third_party/ashmem/ashmem.h
- **
- ** Copyright 2008 The Android Open Source Project
- **
- ** This file is dual licensed. It may be redistributed and/or modified
- ** under the terms of the Apache 2.0 License OR version 2 of the GNU
- ** General Public License.
- */
-
-#ifndef _THIRD_PARTY_ASHMEM_H
-#define _THIRD_PARTY_ASHMEM_H
-
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int ashmem_create_region(const char *name, size_t size);
-int ashmem_set_prot_region(int fd, int prot);
-int ashmem_pin_region(int fd, size_t offset, size_t len);
-int ashmem_unpin_region(int fd, size_t offset, size_t len);
-int ashmem_get_size_region(int fd);
-int ashmem_purge_all(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#ifndef __ASHMEMIOC /* in case someone included <linux/ashmem.h> too */
-
-#define ASHMEM_NAME_LEN 256
-
-#define ASHMEM_NAME_DEF "dev/ashmem"
-
-/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
-#define ASHMEM_NOT_PURGED 0
-#define ASHMEM_WAS_PURGED 1
-
-/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
-#define ASHMEM_IS_UNPINNED 0
-#define ASHMEM_IS_PINNED 1
-
-#endif /* ! __ASHMEMIOC */
-
-#endif /* _THIRD_PARTY_ASHMEM_H */
diff --git a/chromium/third_party/expat/README.chromium b/chromium/third_party/expat/README.chromium
index 7b47f5f7f1d..a0af1e2d310 100644
--- a/chromium/third_party/expat/README.chromium
+++ b/chromium/third_party/expat/README.chromium
@@ -4,7 +4,7 @@ URL: http://sourceforge.net/projects/expat/
Version: 2.1.0
License: MIT
License File: files/COPYING
-Security Critical: no
+Security Critical: yes
Description:
This is Expat XML parser - very lightweight C library for parsing XML.
@@ -38,5 +38,8 @@ Local Modifications:
lib/xmltok_impl.c (see xmltok_imp.c.original for unmodified version)
* Prevent a compiler warning when compiling with
WIN32_LEAN_AND_MEAN predefined.
+ lib/xmlparse.c (see xmlparse.c.original for unmodified version)
+ * Apply https://hg.mozilla.org/releases/mozilla-esr31/rev/2f3e78643f5c
+ to prevent an integer overflow.
Added files:
lib/expat_config.h (a generated config file)
diff --git a/chromium/third_party/expat/files/lib/xmlparse.c b/chromium/third_party/expat/files/lib/xmlparse.c
index f35aa36ba8a..ede7b5bb667 100644
--- a/chromium/third_party/expat/files/lib/xmlparse.c
+++ b/chromium/third_party/expat/files/lib/xmlparse.c
@@ -1678,6 +1678,12 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
void * XMLCALL
XML_GetBuffer(XML_Parser parser, int len)
{
+/* BEGIN MOZILLA CHANGE (sanity check len) */
+ if (len < 0) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return NULL;
+ }
+/* END MOZILLA CHANGE */
switch (ps_parsing) {
case XML_SUSPENDED:
errorCode = XML_ERROR_SUSPENDED;
@@ -1689,8 +1695,13 @@ XML_GetBuffer(XML_Parser parser, int len)
}
if (len > bufferLim - bufferEnd) {
- /* FIXME avoid integer overflow */
int neededSize = len + (int)(bufferEnd - bufferPtr);
+/* BEGIN MOZILLA CHANGE (sanity check neededSize) */
+ if (neededSize < 0) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return NULL;
+ }
+/* END MOZILLA CHANGE */
#ifdef XML_CONTEXT_BYTES
int keep = (int)(bufferPtr - buffer);
@@ -1719,7 +1730,15 @@ XML_GetBuffer(XML_Parser parser, int len)
bufferSize = INIT_BUFFER_SIZE;
do {
bufferSize *= 2;
- } while (bufferSize < neededSize);
+/* BEGIN MOZILLA CHANGE (prevent infinite loop on overflow) */
+ } while (bufferSize < neededSize && bufferSize > 0);
+/* END MOZILLA CHANGE */
+/* BEGIN MOZILLA CHANGE (sanity check bufferSize) */
+ if (bufferSize <= 0) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return NULL;
+ }
+/* END MOZILLA CHANGE */
newBuf = (char *)MALLOC(bufferSize);
if (newBuf == 0) {
errorCode = XML_ERROR_NO_MEMORY;
diff --git a/chromium/third_party/expat/files/lib/xmlparse.c.original b/chromium/third_party/expat/files/lib/xmlparse.c.original
new file mode 100644
index 00000000000..f35aa36ba8a
--- /dev/null
+++ b/chromium/third_party/expat/files/lib/xmlparse.c.original
@@ -0,0 +1,6403 @@
+/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#include <stddef.h>
+#include <string.h> /* memset(), memcpy() */
+#include <assert.h>
+#include <limits.h> /* UINT_MAX */
+#include <time.h> /* time() */
+
+#define XML_BUILDING_EXPAT 1
+
+#ifdef COMPILED_FROM_DSP
+#include "winconfig.h"
+#elif defined(MACOS_CLASSIC)
+#include "macconfig.h"
+#elif defined(__amigaos__)
+#include "amigaconfig.h"
+#elif defined(__WATCOMC__)
+#include "watcomconfig.h"
+#elif defined(HAVE_EXPAT_CONFIG_H)
+#include <expat_config.h>
+#endif /* ndef COMPILED_FROM_DSP */
+
+#include "ascii.h"
+#include "expat.h"
+
+#ifdef XML_UNICODE
+#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX
+#define XmlConvert XmlUtf16Convert
+#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding
+#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS
+#define XmlEncode XmlUtf16Encode
+/* Using pointer subtraction to convert to integer type. */
+#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))
+typedef unsigned short ICHAR;
+#else
+#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX
+#define XmlConvert XmlUtf8Convert
+#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding
+#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS
+#define XmlEncode XmlUtf8Encode
+#define MUST_CONVERT(enc, s) (!(enc)->isUtf8)
+typedef char ICHAR;
+#endif
+
+
+#ifndef XML_NS
+
+#define XmlInitEncodingNS XmlInitEncoding
+#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding
+#undef XmlGetInternalEncodingNS
+#define XmlGetInternalEncodingNS XmlGetInternalEncoding
+#define XmlParseXmlDeclNS XmlParseXmlDecl
+
+#endif
+
+#ifdef XML_UNICODE
+
+#ifdef XML_UNICODE_WCHAR_T
+#define XML_T(x) (const wchar_t)x
+#define XML_L(x) L ## x
+#else
+#define XML_T(x) (const unsigned short)x
+#define XML_L(x) x
+#endif
+
+#else
+
+#define XML_T(x) x
+#define XML_L(x) x
+
+#endif
+
+/* Round up n to be a multiple of sz, where sz is a power of 2. */
+#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
+
+/* Handle the case where memmove() doesn't exist. */
+#ifndef HAVE_MEMMOVE
+#ifdef HAVE_BCOPY
+#define memmove(d,s,l) bcopy((s),(d),(l))
+#else
+#error memmove does not exist on this platform, nor is a substitute available
+#endif /* HAVE_BCOPY */
+#endif /* HAVE_MEMMOVE */
+
+#include "internal.h"
+#include "xmltok.h"
+#include "xmlrole.h"
+
+typedef const XML_Char *KEY;
+
+typedef struct {
+ KEY name;
+} NAMED;
+
+typedef struct {
+ NAMED **v;
+ unsigned char power;
+ size_t size;
+ size_t used;
+ const XML_Memory_Handling_Suite *mem;
+} HASH_TABLE;
+
+/* Basic character hash algorithm, taken from Python's string hash:
+ h = h * 1000003 ^ character, the constant being a prime number.
+
+*/
+#ifdef XML_UNICODE
+#define CHAR_HASH(h, c) \
+ (((h) * 0xF4243) ^ (unsigned short)(c))
+#else
+#define CHAR_HASH(h, c) \
+ (((h) * 0xF4243) ^ (unsigned char)(c))
+#endif
+
+/* For probing (after a collision) we need a step size relative prime
+ to the hash table size, which is a power of 2. We use double-hashing,
+ since we can calculate a second hash value cheaply by taking those bits
+ of the first hash value that were discarded (masked out) when the table
+ index was calculated: index = hash & mask, where mask = table->size - 1.
+ We limit the maximum step size to table->size / 4 (mask >> 2) and make
+ it odd, since odd numbers are always relative prime to a power of 2.
+*/
+#define SECOND_HASH(hash, mask, power) \
+ ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2))
+#define PROBE_STEP(hash, mask, power) \
+ ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))
+
+typedef struct {
+ NAMED **p;
+ NAMED **end;
+} HASH_TABLE_ITER;
+
+#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */
+#define INIT_DATA_BUF_SIZE 1024
+#define INIT_ATTS_SIZE 16
+#define INIT_ATTS_VERSION 0xFFFFFFFF
+#define INIT_BLOCK_SIZE 1024
+#define INIT_BUFFER_SIZE 1024
+
+#define EXPAND_SPARE 24
+
+typedef struct binding {
+ struct prefix *prefix;
+ struct binding *nextTagBinding;
+ struct binding *prevPrefixBinding;
+ const struct attribute_id *attId;
+ XML_Char *uri;
+ int uriLen;
+ int uriAlloc;
+} BINDING;
+
+typedef struct prefix {
+ const XML_Char *name;
+ BINDING *binding;
+} PREFIX;
+
+typedef struct {
+ const XML_Char *str;
+ const XML_Char *localPart;
+ const XML_Char *prefix;
+ int strLen;
+ int uriLen;
+ int prefixLen;
+} TAG_NAME;
+
+/* TAG represents an open element.
+ The name of the element is stored in both the document and API
+ encodings. The memory buffer 'buf' is a separately-allocated
+ memory area which stores the name. During the XML_Parse()/
+ XMLParseBuffer() when the element is open, the memory for the 'raw'
+ version of the name (in the document encoding) is shared with the
+ document buffer. If the element is open across calls to
+ XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to
+ contain the 'raw' name as well.
+
+ A parser re-uses these structures, maintaining a list of allocated
+ TAG objects in a free list.
+*/
+typedef struct tag {
+ struct tag *parent; /* parent of this element */
+ const char *rawName; /* tagName in the original encoding */
+ int rawNameLength;
+ TAG_NAME name; /* tagName in the API encoding */
+ char *buf; /* buffer for name components */
+ char *bufEnd; /* end of the buffer */
+ BINDING *bindings;
+} TAG;
+
+typedef struct {
+ const XML_Char *name;
+ const XML_Char *textPtr;
+ int textLen; /* length in XML_Chars */
+ int processed; /* # of processed bytes - when suspended */
+ const XML_Char *systemId;
+ const XML_Char *base;
+ const XML_Char *publicId;
+ const XML_Char *notation;
+ XML_Bool open;
+ XML_Bool is_param;
+ XML_Bool is_internal; /* true if declared in internal subset outside PE */
+} ENTITY;
+
+typedef struct {
+ enum XML_Content_Type type;
+ enum XML_Content_Quant quant;
+ const XML_Char * name;
+ int firstchild;
+ int lastchild;
+ int childcnt;
+ int nextsib;
+} CONTENT_SCAFFOLD;
+
+#define INIT_SCAFFOLD_ELEMENTS 32
+
+typedef struct block {
+ struct block *next;
+ int size;
+ XML_Char s[1];
+} BLOCK;
+
+typedef struct {
+ BLOCK *blocks;
+ BLOCK *freeBlocks;
+ const XML_Char *end;
+ XML_Char *ptr;
+ XML_Char *start;
+ const XML_Memory_Handling_Suite *mem;
+} STRING_POOL;
+
+/* The XML_Char before the name is used to determine whether
+ an attribute has been specified. */
+typedef struct attribute_id {
+ XML_Char *name;
+ PREFIX *prefix;
+ XML_Bool maybeTokenized;
+ XML_Bool xmlns;
+} ATTRIBUTE_ID;
+
+typedef struct {
+ const ATTRIBUTE_ID *id;
+ XML_Bool isCdata;
+ const XML_Char *value;
+} DEFAULT_ATTRIBUTE;
+
+typedef struct {
+ unsigned long version;
+ unsigned long hash;
+ const XML_Char *uriName;
+} NS_ATT;
+
+typedef struct {
+ const XML_Char *name;
+ PREFIX *prefix;
+ const ATTRIBUTE_ID *idAtt;
+ int nDefaultAtts;
+ int allocDefaultAtts;
+ DEFAULT_ATTRIBUTE *defaultAtts;
+} ELEMENT_TYPE;
+
+typedef struct {
+ HASH_TABLE generalEntities;
+ HASH_TABLE elementTypes;
+ HASH_TABLE attributeIds;
+ HASH_TABLE prefixes;
+ STRING_POOL pool;
+ STRING_POOL entityValuePool;
+ /* false once a parameter entity reference has been skipped */
+ XML_Bool keepProcessing;
+ /* true once an internal or external PE reference has been encountered;
+ this includes the reference to an external subset */
+ XML_Bool hasParamEntityRefs;
+ XML_Bool standalone;
+#ifdef XML_DTD
+ /* indicates if external PE has been read */
+ XML_Bool paramEntityRead;
+ HASH_TABLE paramEntities;
+#endif /* XML_DTD */
+ PREFIX defaultPrefix;
+ /* === scaffolding for building content model === */
+ XML_Bool in_eldecl;
+ CONTENT_SCAFFOLD *scaffold;
+ unsigned contentStringLen;
+ unsigned scaffSize;
+ unsigned scaffCount;
+ int scaffLevel;
+ int *scaffIndex;
+} DTD;
+
+typedef struct open_internal_entity {
+ const char *internalEventPtr;
+ const char *internalEventEndPtr;
+ struct open_internal_entity *next;
+ ENTITY *entity;
+ int startTagLevel;
+ XML_Bool betweenDecl; /* WFC: PE Between Declarations */
+} OPEN_INTERNAL_ENTITY;
+
+typedef enum XML_Error PTRCALL Processor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr);
+
+static Processor prologProcessor;
+static Processor prologInitProcessor;
+static Processor contentProcessor;
+static Processor cdataSectionProcessor;
+#ifdef XML_DTD
+static Processor ignoreSectionProcessor;
+static Processor externalParEntProcessor;
+static Processor externalParEntInitProcessor;
+static Processor entityValueProcessor;
+static Processor entityValueInitProcessor;
+#endif /* XML_DTD */
+static Processor epilogProcessor;
+static Processor errorProcessor;
+static Processor externalEntityInitProcessor;
+static Processor externalEntityInitProcessor2;
+static Processor externalEntityInitProcessor3;
+static Processor externalEntityContentProcessor;
+static Processor internalEntityProcessor;
+
+static enum XML_Error
+handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName);
+static enum XML_Error
+processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
+ const char *s, const char *next);
+static enum XML_Error
+initializeEncoding(XML_Parser parser);
+static enum XML_Error
+doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
+ const char *end, int tok, const char *next, const char **nextPtr,
+ XML_Bool haveMore);
+static enum XML_Error
+processInternalEntity(XML_Parser parser, ENTITY *entity,
+ XML_Bool betweenDecl);
+static enum XML_Error
+doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+ const char *start, const char *end, const char **endPtr,
+ XML_Bool haveMore);
+static enum XML_Error
+doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr,
+ const char *end, const char **nextPtr, XML_Bool haveMore);
+#ifdef XML_DTD
+static enum XML_Error
+doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr,
+ const char *end, const char **nextPtr, XML_Bool haveMore);
+#endif /* XML_DTD */
+
+static enum XML_Error
+storeAtts(XML_Parser parser, const ENCODING *, const char *s,
+ TAG_NAME *tagNamePtr, BINDING **bindingsPtr);
+static enum XML_Error
+addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
+ const XML_Char *uri, BINDING **bindingsPtr);
+static int
+defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
+ XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser);
+static enum XML_Error
+storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
+ const char *, const char *, STRING_POOL *);
+static enum XML_Error
+appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
+ const char *, const char *, STRING_POOL *);
+static ATTRIBUTE_ID *
+getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
+ const char *end);
+static int
+setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
+static enum XML_Error
+storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start,
+ const char *end);
+static int
+reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end);
+static int
+reportComment(XML_Parser parser, const ENCODING *enc, const char *start,
+ const char *end);
+static void
+reportDefault(XML_Parser parser, const ENCODING *enc, const char *start,
+ const char *end);
+
+static const XML_Char * getContext(XML_Parser parser);
+static XML_Bool
+setContext(XML_Parser parser, const XML_Char *context);
+
+static void FASTCALL normalizePublicId(XML_Char *s);
+
+static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms);
+/* do not call if parentParser != NULL */
+static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
+static void
+dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms);
+static int
+dtdCopy(XML_Parser oldParser,
+ DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms);
+static int
+copyEntityTable(XML_Parser oldParser,
+ HASH_TABLE *, STRING_POOL *, const HASH_TABLE *);
+static NAMED *
+lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize);
+static void FASTCALL
+hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms);
+static void FASTCALL hashTableClear(HASH_TABLE *);
+static void FASTCALL hashTableDestroy(HASH_TABLE *);
+static void FASTCALL
+hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
+static NAMED * FASTCALL hashTableIterNext(HASH_TABLE_ITER *);
+
+static void FASTCALL
+poolInit(STRING_POOL *, const XML_Memory_Handling_Suite *ms);
+static void FASTCALL poolClear(STRING_POOL *);
+static void FASTCALL poolDestroy(STRING_POOL *);
+static XML_Char *
+poolAppend(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end);
+static XML_Char *
+poolStoreString(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end);
+static XML_Bool FASTCALL poolGrow(STRING_POOL *pool);
+static const XML_Char * FASTCALL
+poolCopyString(STRING_POOL *pool, const XML_Char *s);
+static const XML_Char *
+poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n);
+static const XML_Char * FASTCALL
+poolAppendString(STRING_POOL *pool, const XML_Char *s);
+
+static int FASTCALL nextScaffoldPart(XML_Parser parser);
+static XML_Content * build_model(XML_Parser parser);
+static ELEMENT_TYPE *
+getElementType(XML_Parser parser, const ENCODING *enc,
+ const char *ptr, const char *end);
+
+static unsigned long generate_hash_secret_salt(void);
+static XML_Bool startParsing(XML_Parser parser);
+
+static XML_Parser
+parserCreate(const XML_Char *encodingName,
+ const XML_Memory_Handling_Suite *memsuite,
+ const XML_Char *nameSep,
+ DTD *dtd);
+
+static void
+parserInit(XML_Parser parser, const XML_Char *encodingName);
+
+#define poolStart(pool) ((pool)->start)
+#define poolEnd(pool) ((pool)->ptr)
+#define poolLength(pool) ((pool)->ptr - (pool)->start)
+#define poolChop(pool) ((void)--(pool->ptr))
+#define poolLastChar(pool) (((pool)->ptr)[-1])
+#define poolDiscard(pool) ((pool)->ptr = (pool)->start)
+#define poolFinish(pool) ((pool)->start = (pool)->ptr)
+#define poolAppendChar(pool, c) \
+ (((pool)->ptr == (pool)->end && !poolGrow(pool)) \
+ ? 0 \
+ : ((*((pool)->ptr)++ = c), 1))
+
+struct XML_ParserStruct {
+ /* The first member must be userData so that the XML_GetUserData
+ macro works. */
+ void *m_userData;
+ void *m_handlerArg;
+ char *m_buffer;
+ const XML_Memory_Handling_Suite m_mem;
+ /* first character to be parsed */
+ const char *m_bufferPtr;
+ /* past last character to be parsed */
+ char *m_bufferEnd;
+ /* allocated end of buffer */
+ const char *m_bufferLim;
+ XML_Index m_parseEndByteIndex;
+ const char *m_parseEndPtr;
+ XML_Char *m_dataBuf;
+ XML_Char *m_dataBufEnd;
+ XML_StartElementHandler m_startElementHandler;
+ XML_EndElementHandler m_endElementHandler;
+ XML_CharacterDataHandler m_characterDataHandler;
+ XML_ProcessingInstructionHandler m_processingInstructionHandler;
+ XML_CommentHandler m_commentHandler;
+ XML_StartCdataSectionHandler m_startCdataSectionHandler;
+ XML_EndCdataSectionHandler m_endCdataSectionHandler;
+ XML_DefaultHandler m_defaultHandler;
+ XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler;
+ XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler;
+ XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler;
+ XML_NotationDeclHandler m_notationDeclHandler;
+ XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler;
+ XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler;
+ XML_NotStandaloneHandler m_notStandaloneHandler;
+ XML_ExternalEntityRefHandler m_externalEntityRefHandler;
+ XML_Parser m_externalEntityRefHandlerArg;
+ XML_SkippedEntityHandler m_skippedEntityHandler;
+ XML_UnknownEncodingHandler m_unknownEncodingHandler;
+ XML_ElementDeclHandler m_elementDeclHandler;
+ XML_AttlistDeclHandler m_attlistDeclHandler;
+ XML_EntityDeclHandler m_entityDeclHandler;
+ XML_XmlDeclHandler m_xmlDeclHandler;
+ const ENCODING *m_encoding;
+ INIT_ENCODING m_initEncoding;
+ const ENCODING *m_internalEncoding;
+ const XML_Char *m_protocolEncodingName;
+ XML_Bool m_ns;
+ XML_Bool m_ns_triplets;
+ void *m_unknownEncodingMem;
+ void *m_unknownEncodingData;
+ void *m_unknownEncodingHandlerData;
+ void (XMLCALL *m_unknownEncodingRelease)(void *);
+ PROLOG_STATE m_prologState;
+ Processor *m_processor;
+ enum XML_Error m_errorCode;
+ const char *m_eventPtr;
+ const char *m_eventEndPtr;
+ const char *m_positionPtr;
+ OPEN_INTERNAL_ENTITY *m_openInternalEntities;
+ OPEN_INTERNAL_ENTITY *m_freeInternalEntities;
+ XML_Bool m_defaultExpandInternalEntities;
+ int m_tagLevel;
+ ENTITY *m_declEntity;
+ const XML_Char *m_doctypeName;
+ const XML_Char *m_doctypeSysid;
+ const XML_Char *m_doctypePubid;
+ const XML_Char *m_declAttributeType;
+ const XML_Char *m_declNotationName;
+ const XML_Char *m_declNotationPublicId;
+ ELEMENT_TYPE *m_declElementType;
+ ATTRIBUTE_ID *m_declAttributeId;
+ XML_Bool m_declAttributeIsCdata;
+ XML_Bool m_declAttributeIsId;
+ DTD *m_dtd;
+ const XML_Char *m_curBase;
+ TAG *m_tagStack;
+ TAG *m_freeTagList;
+ BINDING *m_inheritedBindings;
+ BINDING *m_freeBindingList;
+ int m_attsSize;
+ int m_nSpecifiedAtts;
+ int m_idAttIndex;
+ ATTRIBUTE *m_atts;
+ NS_ATT *m_nsAtts;
+ unsigned long m_nsAttsVersion;
+ unsigned char m_nsAttsPower;
+#ifdef XML_ATTR_INFO
+ XML_AttrInfo *m_attInfo;
+#endif
+ POSITION m_position;
+ STRING_POOL m_tempPool;
+ STRING_POOL m_temp2Pool;
+ char *m_groupConnector;
+ unsigned int m_groupSize;
+ XML_Char m_namespaceSeparator;
+ XML_Parser m_parentParser;
+ XML_ParsingStatus m_parsingStatus;
+#ifdef XML_DTD
+ XML_Bool m_isParamEntity;
+ XML_Bool m_useForeignDTD;
+ enum XML_ParamEntityParsing m_paramEntityParsing;
+#endif
+ unsigned long m_hash_secret_salt;
+};
+
+#define MALLOC(s) (parser->m_mem.malloc_fcn((s)))
+#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s)))
+#define FREE(p) (parser->m_mem.free_fcn((p)))
+
+#define userData (parser->m_userData)
+#define handlerArg (parser->m_handlerArg)
+#define startElementHandler (parser->m_startElementHandler)
+#define endElementHandler (parser->m_endElementHandler)
+#define characterDataHandler (parser->m_characterDataHandler)
+#define processingInstructionHandler \
+ (parser->m_processingInstructionHandler)
+#define commentHandler (parser->m_commentHandler)
+#define startCdataSectionHandler \
+ (parser->m_startCdataSectionHandler)
+#define endCdataSectionHandler (parser->m_endCdataSectionHandler)
+#define defaultHandler (parser->m_defaultHandler)
+#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler)
+#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler)
+#define unparsedEntityDeclHandler \
+ (parser->m_unparsedEntityDeclHandler)
+#define notationDeclHandler (parser->m_notationDeclHandler)
+#define startNamespaceDeclHandler \
+ (parser->m_startNamespaceDeclHandler)
+#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler)
+#define notStandaloneHandler (parser->m_notStandaloneHandler)
+#define externalEntityRefHandler \
+ (parser->m_externalEntityRefHandler)
+#define externalEntityRefHandlerArg \
+ (parser->m_externalEntityRefHandlerArg)
+#define internalEntityRefHandler \
+ (parser->m_internalEntityRefHandler)
+#define skippedEntityHandler (parser->m_skippedEntityHandler)
+#define unknownEncodingHandler (parser->m_unknownEncodingHandler)
+#define elementDeclHandler (parser->m_elementDeclHandler)
+#define attlistDeclHandler (parser->m_attlistDeclHandler)
+#define entityDeclHandler (parser->m_entityDeclHandler)
+#define xmlDeclHandler (parser->m_xmlDeclHandler)
+#define encoding (parser->m_encoding)
+#define initEncoding (parser->m_initEncoding)
+#define internalEncoding (parser->m_internalEncoding)
+#define unknownEncodingMem (parser->m_unknownEncodingMem)
+#define unknownEncodingData (parser->m_unknownEncodingData)
+#define unknownEncodingHandlerData \
+ (parser->m_unknownEncodingHandlerData)
+#define unknownEncodingRelease (parser->m_unknownEncodingRelease)
+#define protocolEncodingName (parser->m_protocolEncodingName)
+#define ns (parser->m_ns)
+#define ns_triplets (parser->m_ns_triplets)
+#define prologState (parser->m_prologState)
+#define processor (parser->m_processor)
+#define errorCode (parser->m_errorCode)
+#define eventPtr (parser->m_eventPtr)
+#define eventEndPtr (parser->m_eventEndPtr)
+#define positionPtr (parser->m_positionPtr)
+#define position (parser->m_position)
+#define openInternalEntities (parser->m_openInternalEntities)
+#define freeInternalEntities (parser->m_freeInternalEntities)
+#define defaultExpandInternalEntities \
+ (parser->m_defaultExpandInternalEntities)
+#define tagLevel (parser->m_tagLevel)
+#define buffer (parser->m_buffer)
+#define bufferPtr (parser->m_bufferPtr)
+#define bufferEnd (parser->m_bufferEnd)
+#define parseEndByteIndex (parser->m_parseEndByteIndex)
+#define parseEndPtr (parser->m_parseEndPtr)
+#define bufferLim (parser->m_bufferLim)
+#define dataBuf (parser->m_dataBuf)
+#define dataBufEnd (parser->m_dataBufEnd)
+#define _dtd (parser->m_dtd)
+#define curBase (parser->m_curBase)
+#define declEntity (parser->m_declEntity)
+#define doctypeName (parser->m_doctypeName)
+#define doctypeSysid (parser->m_doctypeSysid)
+#define doctypePubid (parser->m_doctypePubid)
+#define declAttributeType (parser->m_declAttributeType)
+#define declNotationName (parser->m_declNotationName)
+#define declNotationPublicId (parser->m_declNotationPublicId)
+#define declElementType (parser->m_declElementType)
+#define declAttributeId (parser->m_declAttributeId)
+#define declAttributeIsCdata (parser->m_declAttributeIsCdata)
+#define declAttributeIsId (parser->m_declAttributeIsId)
+#define freeTagList (parser->m_freeTagList)
+#define freeBindingList (parser->m_freeBindingList)
+#define inheritedBindings (parser->m_inheritedBindings)
+#define tagStack (parser->m_tagStack)
+#define atts (parser->m_atts)
+#define attsSize (parser->m_attsSize)
+#define nSpecifiedAtts (parser->m_nSpecifiedAtts)
+#define idAttIndex (parser->m_idAttIndex)
+#define nsAtts (parser->m_nsAtts)
+#define nsAttsVersion (parser->m_nsAttsVersion)
+#define nsAttsPower (parser->m_nsAttsPower)
+#define attInfo (parser->m_attInfo)
+#define tempPool (parser->m_tempPool)
+#define temp2Pool (parser->m_temp2Pool)
+#define groupConnector (parser->m_groupConnector)
+#define groupSize (parser->m_groupSize)
+#define namespaceSeparator (parser->m_namespaceSeparator)
+#define parentParser (parser->m_parentParser)
+#define ps_parsing (parser->m_parsingStatus.parsing)
+#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer)
+#ifdef XML_DTD
+#define isParamEntity (parser->m_isParamEntity)
+#define useForeignDTD (parser->m_useForeignDTD)
+#define paramEntityParsing (parser->m_paramEntityParsing)
+#endif /* XML_DTD */
+#define hash_secret_salt (parser->m_hash_secret_salt)
+
+XML_Parser XMLCALL
+XML_ParserCreate(const XML_Char *encodingName)
+{
+ return XML_ParserCreate_MM(encodingName, NULL, NULL);
+}
+
+XML_Parser XMLCALL
+XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep)
+{
+ XML_Char tmp[2];
+ *tmp = nsSep;
+ return XML_ParserCreate_MM(encodingName, NULL, tmp);
+}
+
+static const XML_Char implicitContext[] = {
+ ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h, ASCII_t, ASCII_t, ASCII_p,
+ ASCII_COLON, ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w,
+ ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g,
+ ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, ASCII_SLASH, ASCII_1, ASCII_9,
+ ASCII_9, ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, ASCII_e,
+ ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e, '\0'
+};
+
+static unsigned long
+generate_hash_secret_salt(void)
+{
+ unsigned int seed = time(NULL) % UINT_MAX;
+ srand(seed);
+ return rand();
+}
+
+static XML_Bool /* only valid for root parser */
+startParsing(XML_Parser parser)
+{
+ /* hash functions must be initialized before setContext() is called */
+ if (hash_secret_salt == 0)
+ hash_secret_salt = generate_hash_secret_salt();
+ if (ns) {
+ /* implicit context only set for root parser, since child
+ parsers (i.e. external entity parsers) will inherit it
+ */
+ return setContext(parser, implicitContext);
+ }
+ return XML_TRUE;
+}
+
+XML_Parser XMLCALL
+XML_ParserCreate_MM(const XML_Char *encodingName,
+ const XML_Memory_Handling_Suite *memsuite,
+ const XML_Char *nameSep)
+{
+ return parserCreate(encodingName, memsuite, nameSep, NULL);
+}
+
+static XML_Parser
+parserCreate(const XML_Char *encodingName,
+ const XML_Memory_Handling_Suite *memsuite,
+ const XML_Char *nameSep,
+ DTD *dtd)
+{
+ XML_Parser parser;
+
+ if (memsuite) {
+ XML_Memory_Handling_Suite *mtemp;
+ parser = (XML_Parser)
+ memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
+ if (parser != NULL) {
+ mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
+ mtemp->malloc_fcn = memsuite->malloc_fcn;
+ mtemp->realloc_fcn = memsuite->realloc_fcn;
+ mtemp->free_fcn = memsuite->free_fcn;
+ }
+ }
+ else {
+ XML_Memory_Handling_Suite *mtemp;
+ parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct));
+ if (parser != NULL) {
+ mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
+ mtemp->malloc_fcn = malloc;
+ mtemp->realloc_fcn = realloc;
+ mtemp->free_fcn = free;
+ }
+ }
+
+ if (!parser)
+ return parser;
+
+ buffer = NULL;
+ bufferLim = NULL;
+
+ attsSize = INIT_ATTS_SIZE;
+ atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE));
+ if (atts == NULL) {
+ FREE(parser);
+ return NULL;
+ }
+#ifdef XML_ATTR_INFO
+ attInfo = (XML_AttrInfo*)MALLOC(attsSize * sizeof(XML_AttrInfo));
+ if (attInfo == NULL) {
+ FREE(atts);
+ FREE(parser);
+ return NULL;
+ }
+#endif
+ dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
+ if (dataBuf == NULL) {
+ FREE(atts);
+#ifdef XML_ATTR_INFO
+ FREE(attInfo);
+#endif
+ FREE(parser);
+ return NULL;
+ }
+ dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE;
+
+ if (dtd)
+ _dtd = dtd;
+ else {
+ _dtd = dtdCreate(&parser->m_mem);
+ if (_dtd == NULL) {
+ FREE(dataBuf);
+ FREE(atts);
+#ifdef XML_ATTR_INFO
+ FREE(attInfo);
+#endif
+ FREE(parser);
+ return NULL;
+ }
+ }
+
+ freeBindingList = NULL;
+ freeTagList = NULL;
+ freeInternalEntities = NULL;
+
+ groupSize = 0;
+ groupConnector = NULL;
+
+ unknownEncodingHandler = NULL;
+ unknownEncodingHandlerData = NULL;
+
+ namespaceSeparator = ASCII_EXCL;
+ ns = XML_FALSE;
+ ns_triplets = XML_FALSE;
+
+ nsAtts = NULL;
+ nsAttsVersion = 0;
+ nsAttsPower = 0;
+
+ poolInit(&tempPool, &(parser->m_mem));
+ poolInit(&temp2Pool, &(parser->m_mem));
+ parserInit(parser, encodingName);
+
+ if (encodingName && !protocolEncodingName) {
+ XML_ParserFree(parser);
+ return NULL;
+ }
+
+ if (nameSep) {
+ ns = XML_TRUE;
+ internalEncoding = XmlGetInternalEncodingNS();
+ namespaceSeparator = *nameSep;
+ }
+ else {
+ internalEncoding = XmlGetInternalEncoding();
+ }
+
+ return parser;
+}
+
+static void
+parserInit(XML_Parser parser, const XML_Char *encodingName)
+{
+ processor = prologInitProcessor;
+ XmlPrologStateInit(&prologState);
+ protocolEncodingName = (encodingName != NULL
+ ? poolCopyString(&tempPool, encodingName)
+ : NULL);
+ curBase = NULL;
+ XmlInitEncoding(&initEncoding, &encoding, 0);
+ userData = NULL;
+ handlerArg = NULL;
+ startElementHandler = NULL;
+ endElementHandler = NULL;
+ characterDataHandler = NULL;
+ processingInstructionHandler = NULL;
+ commentHandler = NULL;
+ startCdataSectionHandler = NULL;
+ endCdataSectionHandler = NULL;
+ defaultHandler = NULL;
+ startDoctypeDeclHandler = NULL;
+ endDoctypeDeclHandler = NULL;
+ unparsedEntityDeclHandler = NULL;
+ notationDeclHandler = NULL;
+ startNamespaceDeclHandler = NULL;
+ endNamespaceDeclHandler = NULL;
+ notStandaloneHandler = NULL;
+ externalEntityRefHandler = NULL;
+ externalEntityRefHandlerArg = parser;
+ skippedEntityHandler = NULL;
+ elementDeclHandler = NULL;
+ attlistDeclHandler = NULL;
+ entityDeclHandler = NULL;
+ xmlDeclHandler = NULL;
+ bufferPtr = buffer;
+ bufferEnd = buffer;
+ parseEndByteIndex = 0;
+ parseEndPtr = NULL;
+ declElementType = NULL;
+ declAttributeId = NULL;
+ declEntity = NULL;
+ doctypeName = NULL;
+ doctypeSysid = NULL;
+ doctypePubid = NULL;
+ declAttributeType = NULL;
+ declNotationName = NULL;
+ declNotationPublicId = NULL;
+ declAttributeIsCdata = XML_FALSE;
+ declAttributeIsId = XML_FALSE;
+ memset(&position, 0, sizeof(POSITION));
+ errorCode = XML_ERROR_NONE;
+ eventPtr = NULL;
+ eventEndPtr = NULL;
+ positionPtr = NULL;
+ openInternalEntities = NULL;
+ defaultExpandInternalEntities = XML_TRUE;
+ tagLevel = 0;
+ tagStack = NULL;
+ inheritedBindings = NULL;
+ nSpecifiedAtts = 0;
+ unknownEncodingMem = NULL;
+ unknownEncodingRelease = NULL;
+ unknownEncodingData = NULL;
+ parentParser = NULL;
+ ps_parsing = XML_INITIALIZED;
+#ifdef XML_DTD
+ isParamEntity = XML_FALSE;
+ useForeignDTD = XML_FALSE;
+ paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+#endif
+ hash_secret_salt = 0;
+}
+
+/* moves list of bindings to freeBindingList */
+static void FASTCALL
+moveToFreeBindingList(XML_Parser parser, BINDING *bindings)
+{
+ while (bindings) {
+ BINDING *b = bindings;
+ bindings = bindings->nextTagBinding;
+ b->nextTagBinding = freeBindingList;
+ freeBindingList = b;
+ }
+}
+
+XML_Bool XMLCALL
+XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
+{
+ TAG *tStk;
+ OPEN_INTERNAL_ENTITY *openEntityList;
+ if (parentParser)
+ return XML_FALSE;
+ /* move tagStack to freeTagList */
+ tStk = tagStack;
+ while (tStk) {
+ TAG *tag = tStk;
+ tStk = tStk->parent;
+ tag->parent = freeTagList;
+ moveToFreeBindingList(parser, tag->bindings);
+ tag->bindings = NULL;
+ freeTagList = tag;
+ }
+ /* move openInternalEntities to freeInternalEntities */
+ openEntityList = openInternalEntities;
+ while (openEntityList) {
+ OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
+ openEntityList = openEntity->next;
+ openEntity->next = freeInternalEntities;
+ freeInternalEntities = openEntity;
+ }
+ moveToFreeBindingList(parser, inheritedBindings);
+ FREE(unknownEncodingMem);
+ if (unknownEncodingRelease)
+ unknownEncodingRelease(unknownEncodingData);
+ poolClear(&tempPool);
+ poolClear(&temp2Pool);
+ parserInit(parser, encodingName);
+ dtdReset(_dtd, &parser->m_mem);
+ return XML_TRUE;
+}
+
+enum XML_Status XMLCALL
+XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName)
+{
+ /* Block after XML_Parse()/XML_ParseBuffer() has been called.
+ XXX There's no way for the caller to determine which of the
+ XXX possible error cases caused the XML_STATUS_ERROR return.
+ */
+ if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ return XML_STATUS_ERROR;
+ if (encodingName == NULL)
+ protocolEncodingName = NULL;
+ else {
+ protocolEncodingName = poolCopyString(&tempPool, encodingName);
+ if (!protocolEncodingName)
+ return XML_STATUS_ERROR;
+ }
+ return XML_STATUS_OK;
+}
+
+XML_Parser XMLCALL
+XML_ExternalEntityParserCreate(XML_Parser oldParser,
+ const XML_Char *context,
+ const XML_Char *encodingName)
+{
+ XML_Parser parser = oldParser;
+ DTD *newDtd = NULL;
+ DTD *oldDtd = _dtd;
+ XML_StartElementHandler oldStartElementHandler = startElementHandler;
+ XML_EndElementHandler oldEndElementHandler = endElementHandler;
+ XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler;
+ XML_ProcessingInstructionHandler oldProcessingInstructionHandler
+ = processingInstructionHandler;
+ XML_CommentHandler oldCommentHandler = commentHandler;
+ XML_StartCdataSectionHandler oldStartCdataSectionHandler
+ = startCdataSectionHandler;
+ XML_EndCdataSectionHandler oldEndCdataSectionHandler
+ = endCdataSectionHandler;
+ XML_DefaultHandler oldDefaultHandler = defaultHandler;
+ XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler
+ = unparsedEntityDeclHandler;
+ XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler;
+ XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler
+ = startNamespaceDeclHandler;
+ XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler
+ = endNamespaceDeclHandler;
+ XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler;
+ XML_ExternalEntityRefHandler oldExternalEntityRefHandler
+ = externalEntityRefHandler;
+ XML_SkippedEntityHandler oldSkippedEntityHandler = skippedEntityHandler;
+ XML_UnknownEncodingHandler oldUnknownEncodingHandler
+ = unknownEncodingHandler;
+ XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler;
+ XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler;
+ XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler;
+ XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler;
+ ELEMENT_TYPE * oldDeclElementType = declElementType;
+
+ void *oldUserData = userData;
+ void *oldHandlerArg = handlerArg;
+ XML_Bool oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
+ XML_Parser oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
+#ifdef XML_DTD
+ enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing;
+ int oldInEntityValue = prologState.inEntityValue;
+#endif
+ XML_Bool oldns_triplets = ns_triplets;
+ /* Note that the new parser shares the same hash secret as the old
+ parser, so that dtdCopy and copyEntityTable can lookup values
+ from hash tables associated with either parser without us having
+ to worry which hash secrets each table has.
+ */
+ unsigned long oldhash_secret_salt = hash_secret_salt;
+
+#ifdef XML_DTD
+ if (!context)
+ newDtd = oldDtd;
+#endif /* XML_DTD */
+
+ /* Note that the magical uses of the pre-processor to make field
+ access look more like C++ require that `parser' be overwritten
+ here. This makes this function more painful to follow than it
+ would be otherwise.
+ */
+ if (ns) {
+ XML_Char tmp[2];
+ *tmp = namespaceSeparator;
+ parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
+ }
+ else {
+ parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
+ }
+
+ if (!parser)
+ return NULL;
+
+ startElementHandler = oldStartElementHandler;
+ endElementHandler = oldEndElementHandler;
+ characterDataHandler = oldCharacterDataHandler;
+ processingInstructionHandler = oldProcessingInstructionHandler;
+ commentHandler = oldCommentHandler;
+ startCdataSectionHandler = oldStartCdataSectionHandler;
+ endCdataSectionHandler = oldEndCdataSectionHandler;
+ defaultHandler = oldDefaultHandler;
+ unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
+ notationDeclHandler = oldNotationDeclHandler;
+ startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
+ endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
+ notStandaloneHandler = oldNotStandaloneHandler;
+ externalEntityRefHandler = oldExternalEntityRefHandler;
+ skippedEntityHandler = oldSkippedEntityHandler;
+ unknownEncodingHandler = oldUnknownEncodingHandler;
+ elementDeclHandler = oldElementDeclHandler;
+ attlistDeclHandler = oldAttlistDeclHandler;
+ entityDeclHandler = oldEntityDeclHandler;
+ xmlDeclHandler = oldXmlDeclHandler;
+ declElementType = oldDeclElementType;
+ userData = oldUserData;
+ if (oldUserData == oldHandlerArg)
+ handlerArg = userData;
+ else
+ handlerArg = parser;
+ if (oldExternalEntityRefHandlerArg != oldParser)
+ externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
+ defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
+ ns_triplets = oldns_triplets;
+ hash_secret_salt = oldhash_secret_salt;
+ parentParser = oldParser;
+#ifdef XML_DTD
+ paramEntityParsing = oldParamEntityParsing;
+ prologState.inEntityValue = oldInEntityValue;
+ if (context) {
+#endif /* XML_DTD */
+ if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem)
+ || !setContext(parser, context)) {
+ XML_ParserFree(parser);
+ return NULL;
+ }
+ processor = externalEntityInitProcessor;
+#ifdef XML_DTD
+ }
+ else {
+ /* The DTD instance referenced by _dtd is shared between the document's
+ root parser and external PE parsers, therefore one does not need to
+ call setContext. In addition, one also *must* not call setContext,
+ because this would overwrite existing prefix->binding pointers in
+ _dtd with ones that get destroyed with the external PE parser.
+ This would leave those prefixes with dangling pointers.
+ */
+ isParamEntity = XML_TRUE;
+ XmlPrologStateInitExternalEntity(&prologState);
+ processor = externalParEntInitProcessor;
+ }
+#endif /* XML_DTD */
+ return parser;
+}
+
+static void FASTCALL
+destroyBindings(BINDING *bindings, XML_Parser parser)
+{
+ for (;;) {
+ BINDING *b = bindings;
+ if (!b)
+ break;
+ bindings = b->nextTagBinding;
+ FREE(b->uri);
+ FREE(b);
+ }
+}
+
+void XMLCALL
+XML_ParserFree(XML_Parser parser)
+{
+ TAG *tagList;
+ OPEN_INTERNAL_ENTITY *entityList;
+ if (parser == NULL)
+ return;
+ /* free tagStack and freeTagList */
+ tagList = tagStack;
+ for (;;) {
+ TAG *p;
+ if (tagList == NULL) {
+ if (freeTagList == NULL)
+ break;
+ tagList = freeTagList;
+ freeTagList = NULL;
+ }
+ p = tagList;
+ tagList = tagList->parent;
+ FREE(p->buf);
+ destroyBindings(p->bindings, parser);
+ FREE(p);
+ }
+ /* free openInternalEntities and freeInternalEntities */
+ entityList = openInternalEntities;
+ for (;;) {
+ OPEN_INTERNAL_ENTITY *openEntity;
+ if (entityList == NULL) {
+ if (freeInternalEntities == NULL)
+ break;
+ entityList = freeInternalEntities;
+ freeInternalEntities = NULL;
+ }
+ openEntity = entityList;
+ entityList = entityList->next;
+ FREE(openEntity);
+ }
+
+ destroyBindings(freeBindingList, parser);
+ destroyBindings(inheritedBindings, parser);
+ poolDestroy(&tempPool);
+ poolDestroy(&temp2Pool);
+#ifdef XML_DTD
+ /* external parameter entity parsers share the DTD structure
+ parser->m_dtd with the root parser, so we must not destroy it
+ */
+ if (!isParamEntity && _dtd)
+#else
+ if (_dtd)
+#endif /* XML_DTD */
+ dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem);
+ FREE((void *)atts);
+#ifdef XML_ATTR_INFO
+ FREE((void *)attInfo);
+#endif
+ FREE(groupConnector);
+ FREE(buffer);
+ FREE(dataBuf);
+ FREE(nsAtts);
+ FREE(unknownEncodingMem);
+ if (unknownEncodingRelease)
+ unknownEncodingRelease(unknownEncodingData);
+ FREE(parser);
+}
+
+void XMLCALL
+XML_UseParserAsHandlerArg(XML_Parser parser)
+{
+ handlerArg = parser;
+}
+
+enum XML_Error XMLCALL
+XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD)
+{
+#ifdef XML_DTD
+ /* block after XML_Parse()/XML_ParseBuffer() has been called */
+ if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING;
+ useForeignDTD = useDTD;
+ return XML_ERROR_NONE;
+#else
+ return XML_ERROR_FEATURE_REQUIRES_XML_DTD;
+#endif
+}
+
+void XMLCALL
+XML_SetReturnNSTriplet(XML_Parser parser, int do_nst)
+{
+ /* block after XML_Parse()/XML_ParseBuffer() has been called */
+ if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ return;
+ ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
+}
+
+void XMLCALL
+XML_SetUserData(XML_Parser parser, void *p)
+{
+ if (handlerArg == userData)
+ handlerArg = userData = p;
+ else
+ userData = p;
+}
+
+enum XML_Status XMLCALL
+XML_SetBase(XML_Parser parser, const XML_Char *p)
+{
+ if (p) {
+ p = poolCopyString(&_dtd->pool, p);
+ if (!p)
+ return XML_STATUS_ERROR;
+ curBase = p;
+ }
+ else
+ curBase = NULL;
+ return XML_STATUS_OK;
+}
+
+const XML_Char * XMLCALL
+XML_GetBase(XML_Parser parser)
+{
+ return curBase;
+}
+
+int XMLCALL
+XML_GetSpecifiedAttributeCount(XML_Parser parser)
+{
+ return nSpecifiedAtts;
+}
+
+int XMLCALL
+XML_GetIdAttributeIndex(XML_Parser parser)
+{
+ return idAttIndex;
+}
+
+#ifdef XML_ATTR_INFO
+const XML_AttrInfo * XMLCALL
+XML_GetAttributeInfo(XML_Parser parser)
+{
+ return attInfo;
+}
+#endif
+
+void XMLCALL
+XML_SetElementHandler(XML_Parser parser,
+ XML_StartElementHandler start,
+ XML_EndElementHandler end)
+{
+ startElementHandler = start;
+ endElementHandler = end;
+}
+
+void XMLCALL
+XML_SetStartElementHandler(XML_Parser parser,
+ XML_StartElementHandler start) {
+ startElementHandler = start;
+}
+
+void XMLCALL
+XML_SetEndElementHandler(XML_Parser parser,
+ XML_EndElementHandler end) {
+ endElementHandler = end;
+}
+
+void XMLCALL
+XML_SetCharacterDataHandler(XML_Parser parser,
+ XML_CharacterDataHandler handler)
+{
+ characterDataHandler = handler;
+}
+
+void XMLCALL
+XML_SetProcessingInstructionHandler(XML_Parser parser,
+ XML_ProcessingInstructionHandler handler)
+{
+ processingInstructionHandler = handler;
+}
+
+void XMLCALL
+XML_SetCommentHandler(XML_Parser parser,
+ XML_CommentHandler handler)
+{
+ commentHandler = handler;
+}
+
+void XMLCALL
+XML_SetCdataSectionHandler(XML_Parser parser,
+ XML_StartCdataSectionHandler start,
+ XML_EndCdataSectionHandler end)
+{
+ startCdataSectionHandler = start;
+ endCdataSectionHandler = end;
+}
+
+void XMLCALL
+XML_SetStartCdataSectionHandler(XML_Parser parser,
+ XML_StartCdataSectionHandler start) {
+ startCdataSectionHandler = start;
+}
+
+void XMLCALL
+XML_SetEndCdataSectionHandler(XML_Parser parser,
+ XML_EndCdataSectionHandler end) {
+ endCdataSectionHandler = end;
+}
+
+void XMLCALL
+XML_SetDefaultHandler(XML_Parser parser,
+ XML_DefaultHandler handler)
+{
+ defaultHandler = handler;
+ defaultExpandInternalEntities = XML_FALSE;
+}
+
+void XMLCALL
+XML_SetDefaultHandlerExpand(XML_Parser parser,
+ XML_DefaultHandler handler)
+{
+ defaultHandler = handler;
+ defaultExpandInternalEntities = XML_TRUE;
+}
+
+void XMLCALL
+XML_SetDoctypeDeclHandler(XML_Parser parser,
+ XML_StartDoctypeDeclHandler start,
+ XML_EndDoctypeDeclHandler end)
+{
+ startDoctypeDeclHandler = start;
+ endDoctypeDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetStartDoctypeDeclHandler(XML_Parser parser,
+ XML_StartDoctypeDeclHandler start) {
+ startDoctypeDeclHandler = start;
+}
+
+void XMLCALL
+XML_SetEndDoctypeDeclHandler(XML_Parser parser,
+ XML_EndDoctypeDeclHandler end) {
+ endDoctypeDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
+ XML_UnparsedEntityDeclHandler handler)
+{
+ unparsedEntityDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetNotationDeclHandler(XML_Parser parser,
+ XML_NotationDeclHandler handler)
+{
+ notationDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetNamespaceDeclHandler(XML_Parser parser,
+ XML_StartNamespaceDeclHandler start,
+ XML_EndNamespaceDeclHandler end)
+{
+ startNamespaceDeclHandler = start;
+ endNamespaceDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetStartNamespaceDeclHandler(XML_Parser parser,
+ XML_StartNamespaceDeclHandler start) {
+ startNamespaceDeclHandler = start;
+}
+
+void XMLCALL
+XML_SetEndNamespaceDeclHandler(XML_Parser parser,
+ XML_EndNamespaceDeclHandler end) {
+ endNamespaceDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetNotStandaloneHandler(XML_Parser parser,
+ XML_NotStandaloneHandler handler)
+{
+ notStandaloneHandler = handler;
+}
+
+void XMLCALL
+XML_SetExternalEntityRefHandler(XML_Parser parser,
+ XML_ExternalEntityRefHandler handler)
+{
+ externalEntityRefHandler = handler;
+}
+
+void XMLCALL
+XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
+{
+ if (arg)
+ externalEntityRefHandlerArg = (XML_Parser)arg;
+ else
+ externalEntityRefHandlerArg = parser;
+}
+
+void XMLCALL
+XML_SetSkippedEntityHandler(XML_Parser parser,
+ XML_SkippedEntityHandler handler)
+{
+ skippedEntityHandler = handler;
+}
+
+void XMLCALL
+XML_SetUnknownEncodingHandler(XML_Parser parser,
+ XML_UnknownEncodingHandler handler,
+ void *data)
+{
+ unknownEncodingHandler = handler;
+ unknownEncodingHandlerData = data;
+}
+
+void XMLCALL
+XML_SetElementDeclHandler(XML_Parser parser,
+ XML_ElementDeclHandler eldecl)
+{
+ elementDeclHandler = eldecl;
+}
+
+void XMLCALL
+XML_SetAttlistDeclHandler(XML_Parser parser,
+ XML_AttlistDeclHandler attdecl)
+{
+ attlistDeclHandler = attdecl;
+}
+
+void XMLCALL
+XML_SetEntityDeclHandler(XML_Parser parser,
+ XML_EntityDeclHandler handler)
+{
+ entityDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetXmlDeclHandler(XML_Parser parser,
+ XML_XmlDeclHandler handler) {
+ xmlDeclHandler = handler;
+}
+
+int XMLCALL
+XML_SetParamEntityParsing(XML_Parser parser,
+ enum XML_ParamEntityParsing peParsing)
+{
+ /* block after XML_Parse()/XML_ParseBuffer() has been called */
+ if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ return 0;
+#ifdef XML_DTD
+ paramEntityParsing = peParsing;
+ return 1;
+#else
+ return peParsing == XML_PARAM_ENTITY_PARSING_NEVER;
+#endif
+}
+
+int XMLCALL
+XML_SetHashSalt(XML_Parser parser,
+ unsigned long hash_salt)
+{
+ /* block after XML_Parse()/XML_ParseBuffer() has been called */
+ if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ return 0;
+ hash_secret_salt = hash_salt;
+ return 1;
+}
+
+enum XML_Status XMLCALL
+XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
+{
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ errorCode = XML_ERROR_SUSPENDED;
+ return XML_STATUS_ERROR;
+ case XML_FINISHED:
+ errorCode = XML_ERROR_FINISHED;
+ return XML_STATUS_ERROR;
+ case XML_INITIALIZED:
+ if (parentParser == NULL && !startParsing(parser)) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return XML_STATUS_ERROR;
+ }
+ default:
+ ps_parsing = XML_PARSING;
+ }
+
+ if (len == 0) {
+ ps_finalBuffer = (XML_Bool)isFinal;
+ if (!isFinal)
+ return XML_STATUS_OK;
+ positionPtr = bufferPtr;
+ parseEndPtr = bufferEnd;
+
+ /* If data are left over from last buffer, and we now know that these
+ data are the final chunk of input, then we have to check them again
+ to detect errors based on that fact.
+ */
+ errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+
+ if (errorCode == XML_ERROR_NONE) {
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+ positionPtr = bufferPtr;
+ return XML_STATUS_SUSPENDED;
+ case XML_INITIALIZED:
+ case XML_PARSING:
+ ps_parsing = XML_FINISHED;
+ /* fall through */
+ default:
+ return XML_STATUS_OK;
+ }
+ }
+ eventEndPtr = eventPtr;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+#ifndef XML_CONTEXT_BYTES
+ else if (bufferPtr == bufferEnd) {
+ const char *end;
+ int nLeftOver;
+ enum XML_Error result;
+ parseEndByteIndex += len;
+ positionPtr = s;
+ ps_finalBuffer = (XML_Bool)isFinal;
+
+ errorCode = processor(parser, s, parseEndPtr = s + len, &end);
+
+ if (errorCode != XML_ERROR_NONE) {
+ eventEndPtr = eventPtr;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+ else {
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ result = XML_STATUS_SUSPENDED;
+ break;
+ case XML_INITIALIZED:
+ case XML_PARSING:
+ if (isFinal) {
+ ps_parsing = XML_FINISHED;
+ return XML_STATUS_OK;
+ }
+ /* fall through */
+ default:
+ result = XML_STATUS_OK;
+ }
+ }
+
+ XmlUpdatePosition(encoding, positionPtr, end, &position);
+ nLeftOver = s + len - end;
+ if (nLeftOver) {
+ if (buffer == NULL || nLeftOver > bufferLim - buffer) {
+ /* FIXME avoid integer overflow */
+ char *temp;
+ temp = (buffer == NULL
+ ? (char *)MALLOC(len * 2)
+ : (char *)REALLOC(buffer, len * 2));
+ if (temp == NULL) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ eventPtr = eventEndPtr = NULL;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+ buffer = temp;
+ bufferLim = buffer + len * 2;
+ }
+ memcpy(buffer, end, nLeftOver);
+ }
+ bufferPtr = buffer;
+ bufferEnd = buffer + nLeftOver;
+ positionPtr = bufferPtr;
+ parseEndPtr = bufferEnd;
+ eventPtr = bufferPtr;
+ eventEndPtr = bufferPtr;
+ return result;
+ }
+#endif /* not defined XML_CONTEXT_BYTES */
+ else {
+ void *buff = XML_GetBuffer(parser, len);
+ if (buff == NULL)
+ return XML_STATUS_ERROR;
+ else {
+ memcpy(buff, s, len);
+ return XML_ParseBuffer(parser, len, isFinal);
+ }
+ }
+}
+
+enum XML_Status XMLCALL
+XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
+{
+ const char *start;
+ enum XML_Status result = XML_STATUS_OK;
+
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ errorCode = XML_ERROR_SUSPENDED;
+ return XML_STATUS_ERROR;
+ case XML_FINISHED:
+ errorCode = XML_ERROR_FINISHED;
+ return XML_STATUS_ERROR;
+ case XML_INITIALIZED:
+ if (parentParser == NULL && !startParsing(parser)) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return XML_STATUS_ERROR;
+ }
+ default:
+ ps_parsing = XML_PARSING;
+ }
+
+ start = bufferPtr;
+ positionPtr = start;
+ bufferEnd += len;
+ parseEndPtr = bufferEnd;
+ parseEndByteIndex += len;
+ ps_finalBuffer = (XML_Bool)isFinal;
+
+ errorCode = processor(parser, start, parseEndPtr, &bufferPtr);
+
+ if (errorCode != XML_ERROR_NONE) {
+ eventEndPtr = eventPtr;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+ else {
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ result = XML_STATUS_SUSPENDED;
+ break;
+ case XML_INITIALIZED:
+ case XML_PARSING:
+ if (isFinal) {
+ ps_parsing = XML_FINISHED;
+ return result;
+ }
+ default: ; /* should not happen */
+ }
+ }
+
+ XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+ positionPtr = bufferPtr;
+ return result;
+}
+
+void * XMLCALL
+XML_GetBuffer(XML_Parser parser, int len)
+{
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ errorCode = XML_ERROR_SUSPENDED;
+ return NULL;
+ case XML_FINISHED:
+ errorCode = XML_ERROR_FINISHED;
+ return NULL;
+ default: ;
+ }
+
+ if (len > bufferLim - bufferEnd) {
+ /* FIXME avoid integer overflow */
+ int neededSize = len + (int)(bufferEnd - bufferPtr);
+#ifdef XML_CONTEXT_BYTES
+ int keep = (int)(bufferPtr - buffer);
+
+ if (keep > XML_CONTEXT_BYTES)
+ keep = XML_CONTEXT_BYTES;
+ neededSize += keep;
+#endif /* defined XML_CONTEXT_BYTES */
+ if (neededSize <= bufferLim - buffer) {
+#ifdef XML_CONTEXT_BYTES
+ if (keep < bufferPtr - buffer) {
+ int offset = (int)(bufferPtr - buffer) - keep;
+ memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep);
+ bufferEnd -= offset;
+ bufferPtr -= offset;
+ }
+#else
+ memmove(buffer, bufferPtr, bufferEnd - bufferPtr);
+ bufferEnd = buffer + (bufferEnd - bufferPtr);
+ bufferPtr = buffer;
+#endif /* not defined XML_CONTEXT_BYTES */
+ }
+ else {
+ char *newBuf;
+ int bufferSize = (int)(bufferLim - bufferPtr);
+ if (bufferSize == 0)
+ bufferSize = INIT_BUFFER_SIZE;
+ do {
+ bufferSize *= 2;
+ } while (bufferSize < neededSize);
+ newBuf = (char *)MALLOC(bufferSize);
+ if (newBuf == 0) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return NULL;
+ }
+ bufferLim = newBuf + bufferSize;
+#ifdef XML_CONTEXT_BYTES
+ if (bufferPtr) {
+ int keep = (int)(bufferPtr - buffer);
+ if (keep > XML_CONTEXT_BYTES)
+ keep = XML_CONTEXT_BYTES;
+ memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep);
+ FREE(buffer);
+ buffer = newBuf;
+ bufferEnd = buffer + (bufferEnd - bufferPtr) + keep;
+ bufferPtr = buffer + keep;
+ }
+ else {
+ bufferEnd = newBuf + (bufferEnd - bufferPtr);
+ bufferPtr = buffer = newBuf;
+ }
+#else
+ if (bufferPtr) {
+ memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr);
+ FREE(buffer);
+ }
+ bufferEnd = newBuf + (bufferEnd - bufferPtr);
+ bufferPtr = buffer = newBuf;
+#endif /* not defined XML_CONTEXT_BYTES */
+ }
+ eventPtr = eventEndPtr = NULL;
+ positionPtr = NULL;
+ }
+ return bufferEnd;
+}
+
+enum XML_Status XMLCALL
+XML_StopParser(XML_Parser parser, XML_Bool resumable)
+{
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ if (resumable) {
+ errorCode = XML_ERROR_SUSPENDED;
+ return XML_STATUS_ERROR;
+ }
+ ps_parsing = XML_FINISHED;
+ break;
+ case XML_FINISHED:
+ errorCode = XML_ERROR_FINISHED;
+ return XML_STATUS_ERROR;
+ default:
+ if (resumable) {
+#ifdef XML_DTD
+ if (isParamEntity) {
+ errorCode = XML_ERROR_SUSPEND_PE;
+ return XML_STATUS_ERROR;
+ }
+#endif
+ ps_parsing = XML_SUSPENDED;
+ }
+ else
+ ps_parsing = XML_FINISHED;
+ }
+ return XML_STATUS_OK;
+}
+
+enum XML_Status XMLCALL
+XML_ResumeParser(XML_Parser parser)
+{
+ enum XML_Status result = XML_STATUS_OK;
+
+ if (ps_parsing != XML_SUSPENDED) {
+ errorCode = XML_ERROR_NOT_SUSPENDED;
+ return XML_STATUS_ERROR;
+ }
+ ps_parsing = XML_PARSING;
+
+ errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+
+ if (errorCode != XML_ERROR_NONE) {
+ eventEndPtr = eventPtr;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+ else {
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ result = XML_STATUS_SUSPENDED;
+ break;
+ case XML_INITIALIZED:
+ case XML_PARSING:
+ if (ps_finalBuffer) {
+ ps_parsing = XML_FINISHED;
+ return result;
+ }
+ default: ;
+ }
+ }
+
+ XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+ positionPtr = bufferPtr;
+ return result;
+}
+
+void XMLCALL
+XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status)
+{
+ assert(status != NULL);
+ *status = parser->m_parsingStatus;
+}
+
+enum XML_Error XMLCALL
+XML_GetErrorCode(XML_Parser parser)
+{
+ return errorCode;
+}
+
+XML_Index XMLCALL
+XML_GetCurrentByteIndex(XML_Parser parser)
+{
+ if (eventPtr)
+ return parseEndByteIndex - (parseEndPtr - eventPtr);
+ return -1;
+}
+
+int XMLCALL
+XML_GetCurrentByteCount(XML_Parser parser)
+{
+ if (eventEndPtr && eventPtr)
+ return (int)(eventEndPtr - eventPtr);
+ return 0;
+}
+
+const char * XMLCALL
+XML_GetInputContext(XML_Parser parser, int *offset, int *size)
+{
+#ifdef XML_CONTEXT_BYTES
+ if (eventPtr && buffer) {
+ *offset = (int)(eventPtr - buffer);
+ *size = (int)(bufferEnd - buffer);
+ return buffer;
+ }
+#endif /* defined XML_CONTEXT_BYTES */
+ return (char *) 0;
+}
+
+XML_Size XMLCALL
+XML_GetCurrentLineNumber(XML_Parser parser)
+{
+ if (eventPtr && eventPtr >= positionPtr) {
+ XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
+ positionPtr = eventPtr;
+ }
+ return position.lineNumber + 1;
+}
+
+XML_Size XMLCALL
+XML_GetCurrentColumnNumber(XML_Parser parser)
+{
+ if (eventPtr && eventPtr >= positionPtr) {
+ XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
+ positionPtr = eventPtr;
+ }
+ return position.columnNumber;
+}
+
+void XMLCALL
+XML_FreeContentModel(XML_Parser parser, XML_Content *model)
+{
+ FREE(model);
+}
+
+void * XMLCALL
+XML_MemMalloc(XML_Parser parser, size_t size)
+{
+ return MALLOC(size);
+}
+
+void * XMLCALL
+XML_MemRealloc(XML_Parser parser, void *ptr, size_t size)
+{
+ return REALLOC(ptr, size);
+}
+
+void XMLCALL
+XML_MemFree(XML_Parser parser, void *ptr)
+{
+ FREE(ptr);
+}
+
+void XMLCALL
+XML_DefaultCurrent(XML_Parser parser)
+{
+ if (defaultHandler) {
+ if (openInternalEntities)
+ reportDefault(parser,
+ internalEncoding,
+ openInternalEntities->internalEventPtr,
+ openInternalEntities->internalEventEndPtr);
+ else
+ reportDefault(parser, encoding, eventPtr, eventEndPtr);
+ }
+}
+
+const XML_LChar * XMLCALL
+XML_ErrorString(enum XML_Error code)
+{
+ static const XML_LChar* const message[] = {
+ 0,
+ XML_L("out of memory"),
+ XML_L("syntax error"),
+ XML_L("no element found"),
+ XML_L("not well-formed (invalid token)"),
+ XML_L("unclosed token"),
+ XML_L("partial character"),
+ XML_L("mismatched tag"),
+ XML_L("duplicate attribute"),
+ XML_L("junk after document element"),
+ XML_L("illegal parameter entity reference"),
+ XML_L("undefined entity"),
+ XML_L("recursive entity reference"),
+ XML_L("asynchronous entity"),
+ XML_L("reference to invalid character number"),
+ XML_L("reference to binary entity"),
+ XML_L("reference to external entity in attribute"),
+ XML_L("XML or text declaration not at start of entity"),
+ XML_L("unknown encoding"),
+ XML_L("encoding specified in XML declaration is incorrect"),
+ XML_L("unclosed CDATA section"),
+ XML_L("error in processing external entity reference"),
+ XML_L("document is not standalone"),
+ XML_L("unexpected parser state - please send a bug report"),
+ XML_L("entity declared in parameter entity"),
+ XML_L("requested feature requires XML_DTD support in Expat"),
+ XML_L("cannot change setting once parsing has begun"),
+ XML_L("unbound prefix"),
+ XML_L("must not undeclare prefix"),
+ XML_L("incomplete markup in parameter entity"),
+ XML_L("XML declaration not well-formed"),
+ XML_L("text declaration not well-formed"),
+ XML_L("illegal character(s) in public id"),
+ XML_L("parser suspended"),
+ XML_L("parser not suspended"),
+ XML_L("parsing aborted"),
+ XML_L("parsing finished"),
+ XML_L("cannot suspend in external parameter entity"),
+ XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"),
+ XML_L("reserved prefix (xmlns) must not be declared or undeclared"),
+ XML_L("prefix must not be bound to one of the reserved namespace names")
+ };
+ if (code > 0 && code < sizeof(message)/sizeof(message[0]))
+ return message[code];
+ return NULL;
+}
+
+const XML_LChar * XMLCALL
+XML_ExpatVersion(void) {
+
+ /* V1 is used to string-ize the version number. However, it would
+ string-ize the actual version macro *names* unless we get them
+ substituted before being passed to V1. CPP is defined to expand
+ a macro, then rescan for more expansions. Thus, we use V2 to expand
+ the version macros, then CPP will expand the resulting V1() macro
+ with the correct numerals. */
+ /* ### I'm assuming cpp is portable in this respect... */
+
+#define V1(a,b,c) XML_L(#a)XML_L(".")XML_L(#b)XML_L(".")XML_L(#c)
+#define V2(a,b,c) XML_L("expat_")V1(a,b,c)
+
+ return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION);
+
+#undef V1
+#undef V2
+}
+
+XML_Expat_Version XMLCALL
+XML_ExpatVersionInfo(void)
+{
+ XML_Expat_Version version;
+
+ version.major = XML_MAJOR_VERSION;
+ version.minor = XML_MINOR_VERSION;
+ version.micro = XML_MICRO_VERSION;
+
+ return version;
+}
+
+const XML_Feature * XMLCALL
+XML_GetFeatureList(void)
+{
+ static const XML_Feature features[] = {
+ {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
+ sizeof(XML_Char)},
+ {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
+ sizeof(XML_LChar)},
+#ifdef XML_UNICODE
+ {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
+#endif
+#ifdef XML_UNICODE_WCHAR_T
+ {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
+#endif
+#ifdef XML_DTD
+ {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
+#endif
+#ifdef XML_CONTEXT_BYTES
+ {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
+ XML_CONTEXT_BYTES},
+#endif
+#ifdef XML_MIN_SIZE
+ {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
+#endif
+#ifdef XML_NS
+ {XML_FEATURE_NS, XML_L("XML_NS"), 0},
+#endif
+#ifdef XML_LARGE_SIZE
+ {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
+#endif
+#ifdef XML_ATTR_INFO
+ {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
+#endif
+ {XML_FEATURE_END, NULL, 0}
+ };
+
+ return features;
+}
+
+/* Initially tag->rawName always points into the parse buffer;
+ for those TAG instances opened while the current parse buffer was
+ processed, and not yet closed, we need to store tag->rawName in a more
+ permanent location, since the parse buffer is about to be discarded.
+*/
+static XML_Bool
+storeRawNames(XML_Parser parser)
+{
+ TAG *tag = tagStack;
+ while (tag) {
+ int bufSize;
+ int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
+ char *rawNameBuf = tag->buf + nameLen;
+ /* Stop if already stored. Since tagStack is a stack, we can stop
+ at the first entry that has already been copied; everything
+ below it in the stack is already been accounted for in a
+ previous call to this function.
+ */
+ if (tag->rawName == rawNameBuf)
+ break;
+ /* For re-use purposes we need to ensure that the
+ size of tag->buf is a multiple of sizeof(XML_Char).
+ */
+ bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
+ if (bufSize > tag->bufEnd - tag->buf) {
+ char *temp = (char *)REALLOC(tag->buf, bufSize);
+ if (temp == NULL)
+ return XML_FALSE;
+ /* if tag->name.str points to tag->buf (only when namespace
+ processing is off) then we have to update it
+ */
+ if (tag->name.str == (XML_Char *)tag->buf)
+ tag->name.str = (XML_Char *)temp;
+ /* if tag->name.localPart is set (when namespace processing is on)
+ then update it as well, since it will always point into tag->buf
+ */
+ if (tag->name.localPart)
+ tag->name.localPart = (XML_Char *)temp + (tag->name.localPart -
+ (XML_Char *)tag->buf);
+ tag->buf = temp;
+ tag->bufEnd = temp + bufSize;
+ rawNameBuf = temp + nameLen;
+ }
+ memcpy(rawNameBuf, tag->rawName, tag->rawNameLength);
+ tag->rawName = rawNameBuf;
+ tag = tag->parent;
+ }
+ return XML_TRUE;
+}
+
+static enum XML_Error PTRCALL
+contentProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = doContent(parser, 0, encoding, start, end,
+ endPtr, (XML_Bool)!ps_finalBuffer);
+ if (result == XML_ERROR_NONE) {
+ if (!storeRawNames(parser))
+ return XML_ERROR_NO_MEMORY;
+ }
+ return result;
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = initializeEncoding(parser);
+ if (result != XML_ERROR_NONE)
+ return result;
+ processor = externalEntityInitProcessor2;
+ return externalEntityInitProcessor2(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor2(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ const char *next = start; /* XmlContentTok doesn't always set the last arg */
+ int tok = XmlContentTok(encoding, start, end, &next);
+ switch (tok) {
+ case XML_TOK_BOM:
+ /* If we are at the end of the buffer, this would cause the next stage,
+ i.e. externalEntityInitProcessor3, to pass control directly to
+ doContent (by detecting XML_TOK_NONE) without processing any xml text
+ declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent.
+ */
+ if (next == end && !ps_finalBuffer) {
+ *endPtr = next;
+ return XML_ERROR_NONE;
+ }
+ start = next;
+ break;
+ case XML_TOK_PARTIAL:
+ if (!ps_finalBuffer) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ eventPtr = start;
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (!ps_finalBuffer) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ eventPtr = start;
+ return XML_ERROR_PARTIAL_CHAR;
+ }
+ processor = externalEntityInitProcessor3;
+ return externalEntityInitProcessor3(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor3(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ int tok;
+ const char *next = start; /* XmlContentTok doesn't always set the last arg */
+ eventPtr = start;
+ tok = XmlContentTok(encoding, start, end, &next);
+ eventEndPtr = next;
+
+ switch (tok) {
+ case XML_TOK_XML_DECL:
+ {
+ enum XML_Error result;
+ result = processXmlDecl(parser, 1, start, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *endPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default:
+ start = next;
+ }
+ }
+ break;
+ case XML_TOK_PARTIAL:
+ if (!ps_finalBuffer) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (!ps_finalBuffer) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ }
+ processor = externalEntityContentProcessor;
+ tagLevel = 1;
+ return externalEntityContentProcessor(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityContentProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = doContent(parser, 1, encoding, start, end,
+ endPtr, (XML_Bool)!ps_finalBuffer);
+ if (result == XML_ERROR_NONE) {
+ if (!storeRawNames(parser))
+ return XML_ERROR_NO_MEMORY;
+ }
+ return result;
+}
+
+static enum XML_Error
+doContent(XML_Parser parser,
+ int startTagLevel,
+ const ENCODING *enc,
+ const char *s,
+ const char *end,
+ const char **nextPtr,
+ XML_Bool haveMore)
+{
+ /* save one level of indirection */
+ DTD * const dtd = _dtd;
+
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+ *eventPP = s;
+
+ for (;;) {
+ const char *next = s; /* XmlContentTok doesn't always set the last arg */
+ int tok = XmlContentTok(enc, s, end, &next);
+ *eventEndPP = next;
+ switch (tok) {
+ case XML_TOK_TRAILING_CR:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ *eventEndPP = end;
+ if (characterDataHandler) {
+ XML_Char c = 0xA;
+ characterDataHandler(handlerArg, &c, 1);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, end);
+ /* We are at the end of the final buffer, should we check for
+ XML_SUSPENDED, XML_FINISHED?
+ */
+ if (startTagLevel == 0)
+ return XML_ERROR_NO_ELEMENTS;
+ if (tagLevel != startTagLevel)
+ return XML_ERROR_ASYNC_ENTITY;
+ *nextPtr = end;
+ return XML_ERROR_NONE;
+ case XML_TOK_NONE:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ if (startTagLevel > 0) {
+ if (tagLevel != startTagLevel)
+ return XML_ERROR_ASYNC_ENTITY;
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_NO_ELEMENTS;
+ case XML_TOK_INVALID:
+ *eventPP = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_ENTITY_REF:
+ {
+ const XML_Char *name;
+ ENTITY *entity;
+ XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (ch) {
+ if (characterDataHandler)
+ characterDataHandler(handlerArg, &ch, 1);
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ name = poolStoreString(&dtd->pool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
+ poolDiscard(&dtd->pool);
+ /* First, determine if a check for an existing declaration is needed;
+ if yes, check that the entity exists, and that it is internal,
+ otherwise call the skipped entity or default handler.
+ */
+ if (!dtd->hasParamEntityRefs || dtd->standalone) {
+ if (!entity)
+ return XML_ERROR_UNDEFINED_ENTITY;
+ else if (!entity->is_internal)
+ return XML_ERROR_ENTITY_DECLARED_IN_PE;
+ }
+ else if (!entity) {
+ if (skippedEntityHandler)
+ skippedEntityHandler(handlerArg, name, 0);
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ if (entity->open)
+ return XML_ERROR_RECURSIVE_ENTITY_REF;
+ if (entity->notation)
+ return XML_ERROR_BINARY_ENTITY_REF;
+ if (entity->textPtr) {
+ enum XML_Error result;
+ if (!defaultExpandInternalEntities) {
+ if (skippedEntityHandler)
+ skippedEntityHandler(handlerArg, entity->name, 0);
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ result = processInternalEntity(parser, entity, XML_FALSE);
+ if (result != XML_ERROR_NONE)
+ return result;
+ }
+ else if (externalEntityRefHandler) {
+ const XML_Char *context;
+ entity->open = XML_TRUE;
+ context = getContext(parser);
+ entity->open = XML_FALSE;
+ if (!context)
+ return XML_ERROR_NO_MEMORY;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ context,
+ entity->base,
+ entity->systemId,
+ entity->publicId))
+ return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ poolDiscard(&tempPool);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ case XML_TOK_START_TAG_NO_ATTS:
+ /* fall through */
+ case XML_TOK_START_TAG_WITH_ATTS:
+ {
+ TAG *tag;
+ enum XML_Error result;
+ XML_Char *toPtr;
+ if (freeTagList) {
+ tag = freeTagList;
+ freeTagList = freeTagList->parent;
+ }
+ else {
+ tag = (TAG *)MALLOC(sizeof(TAG));
+ if (!tag)
+ return XML_ERROR_NO_MEMORY;
+ tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE);
+ if (!tag->buf) {
+ FREE(tag);
+ return XML_ERROR_NO_MEMORY;
+ }
+ tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
+ }
+ tag->bindings = NULL;
+ tag->parent = tagStack;
+ tagStack = tag;
+ tag->name.localPart = NULL;
+ tag->name.prefix = NULL;
+ tag->rawName = s + enc->minBytesPerChar;
+ tag->rawNameLength = XmlNameLength(enc, tag->rawName);
+ ++tagLevel;
+ {
+ const char *rawNameEnd = tag->rawName + tag->rawNameLength;
+ const char *fromPtr = tag->rawName;
+ toPtr = (XML_Char *)tag->buf;
+ for (;;) {
+ int bufSize;
+ int convLen;
+ XmlConvert(enc,
+ &fromPtr, rawNameEnd,
+ (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1);
+ convLen = (int)(toPtr - (XML_Char *)tag->buf);
+ if (fromPtr == rawNameEnd) {
+ tag->name.strLen = convLen;
+ break;
+ }
+ bufSize = (int)(tag->bufEnd - tag->buf) << 1;
+ {
+ char *temp = (char *)REALLOC(tag->buf, bufSize);
+ if (temp == NULL)
+ return XML_ERROR_NO_MEMORY;
+ tag->buf = temp;
+ tag->bufEnd = temp + bufSize;
+ toPtr = (XML_Char *)temp + convLen;
+ }
+ }
+ }
+ tag->name.str = (XML_Char *)tag->buf;
+ *toPtr = XML_T('\0');
+ result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
+ if (result)
+ return result;
+ if (startElementHandler)
+ startElementHandler(handlerArg, tag->name.str,
+ (const XML_Char **)atts);
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ poolClear(&tempPool);
+ break;
+ }
+ case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
+ /* fall through */
+ case XML_TOK_EMPTY_ELEMENT_WITH_ATTS:
+ {
+ const char *rawName = s + enc->minBytesPerChar;
+ enum XML_Error result;
+ BINDING *bindings = NULL;
+ XML_Bool noElmHandlers = XML_TRUE;
+ TAG_NAME name;
+ name.str = poolStoreString(&tempPool, enc, rawName,
+ rawName + XmlNameLength(enc, rawName));
+ if (!name.str)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ result = storeAtts(parser, enc, s, &name, &bindings);
+ if (result)
+ return result;
+ poolFinish(&tempPool);
+ if (startElementHandler) {
+ startElementHandler(handlerArg, name.str, (const XML_Char **)atts);
+ noElmHandlers = XML_FALSE;
+ }
+ if (endElementHandler) {
+ if (startElementHandler)
+ *eventPP = *eventEndPP;
+ endElementHandler(handlerArg, name.str);
+ noElmHandlers = XML_FALSE;
+ }
+ if (noElmHandlers && defaultHandler)
+ reportDefault(parser, enc, s, next);
+ poolClear(&tempPool);
+ while (bindings) {
+ BINDING *b = bindings;
+ if (endNamespaceDeclHandler)
+ endNamespaceDeclHandler(handlerArg, b->prefix->name);
+ bindings = bindings->nextTagBinding;
+ b->nextTagBinding = freeBindingList;
+ freeBindingList = b;
+ b->prefix->binding = b->prevPrefixBinding;
+ }
+ }
+ if (tagLevel == 0)
+ return epilogProcessor(parser, next, end, nextPtr);
+ break;
+ case XML_TOK_END_TAG:
+ if (tagLevel == startTagLevel)
+ return XML_ERROR_ASYNC_ENTITY;
+ else {
+ int len;
+ const char *rawName;
+ TAG *tag = tagStack;
+ tagStack = tag->parent;
+ tag->parent = freeTagList;
+ freeTagList = tag;
+ rawName = s + enc->minBytesPerChar*2;
+ len = XmlNameLength(enc, rawName);
+ if (len != tag->rawNameLength
+ || memcmp(tag->rawName, rawName, len) != 0) {
+ *eventPP = rawName;
+ return XML_ERROR_TAG_MISMATCH;
+ }
+ --tagLevel;
+ if (endElementHandler) {
+ const XML_Char *localPart;
+ const XML_Char *prefix;
+ XML_Char *uri;
+ localPart = tag->name.localPart;
+ if (ns && localPart) {
+ /* localPart and prefix may have been overwritten in
+ tag->name.str, since this points to the binding->uri
+ buffer which gets re-used; so we have to add them again
+ */
+ uri = (XML_Char *)tag->name.str + tag->name.uriLen;
+ /* don't need to check for space - already done in storeAtts() */
+ while (*localPart) *uri++ = *localPart++;
+ prefix = (XML_Char *)tag->name.prefix;
+ if (ns_triplets && prefix) {
+ *uri++ = namespaceSeparator;
+ while (*prefix) *uri++ = *prefix++;
+ }
+ *uri = XML_T('\0');
+ }
+ endElementHandler(handlerArg, tag->name.str);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ while (tag->bindings) {
+ BINDING *b = tag->bindings;
+ if (endNamespaceDeclHandler)
+ endNamespaceDeclHandler(handlerArg, b->prefix->name);
+ tag->bindings = tag->bindings->nextTagBinding;
+ b->nextTagBinding = freeBindingList;
+ freeBindingList = b;
+ b->prefix->binding = b->prevPrefixBinding;
+ }
+ if (tagLevel == 0)
+ return epilogProcessor(parser, next, end, nextPtr);
+ }
+ break;
+ case XML_TOK_CHAR_REF:
+ {
+ int n = XmlCharRefNumber(enc, s);
+ if (n < 0)
+ return XML_ERROR_BAD_CHAR_REF;
+ if (characterDataHandler) {
+ XML_Char buf[XML_ENCODE_MAX];
+ characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf));
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ }
+ break;
+ case XML_TOK_XML_DECL:
+ return XML_ERROR_MISPLACED_XML_PI;
+ case XML_TOK_DATA_NEWLINE:
+ if (characterDataHandler) {
+ XML_Char c = 0xA;
+ characterDataHandler(handlerArg, &c, 1);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ case XML_TOK_CDATA_SECT_OPEN:
+ {
+ enum XML_Error result;
+ if (startCdataSectionHandler)
+ startCdataSectionHandler(handlerArg);
+#if 0
+ /* Suppose you doing a transformation on a document that involves
+ changing only the character data. You set up a defaultHandler
+ and a characterDataHandler. The defaultHandler simply copies
+ characters through. The characterDataHandler does the
+ transformation and writes the characters out escaping them as
+ necessary. This case will fail to work if we leave out the
+ following two lines (because & and < inside CDATA sections will
+ be incorrectly escaped).
+
+ However, now we have a start/endCdataSectionHandler, so it seems
+ easier to let the user deal with this.
+ */
+ else if (characterDataHandler)
+ characterDataHandler(handlerArg, dataBuf, 0);
+#endif
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
+ if (result != XML_ERROR_NONE)
+ return result;
+ else if (!next) {
+ processor = cdataSectionProcessor;
+ return result;
+ }
+ }
+ break;
+ case XML_TOK_TRAILING_RSQB:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ if (characterDataHandler) {
+ if (MUST_CONVERT(enc, s)) {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+ characterDataHandler(handlerArg, dataBuf,
+ (int)(dataPtr - (ICHAR *)dataBuf));
+ }
+ else
+ characterDataHandler(handlerArg,
+ (XML_Char *)s,
+ (int)((XML_Char *)end - (XML_Char *)s));
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, end);
+ /* We are at the end of the final buffer, should we check for
+ XML_SUSPENDED, XML_FINISHED?
+ */
+ if (startTagLevel == 0) {
+ *eventPP = end;
+ return XML_ERROR_NO_ELEMENTS;
+ }
+ if (tagLevel != startTagLevel) {
+ *eventPP = end;
+ return XML_ERROR_ASYNC_ENTITY;
+ }
+ *nextPtr = end;
+ return XML_ERROR_NONE;
+ case XML_TOK_DATA_CHARS:
+ {
+ XML_CharacterDataHandler charDataHandler = characterDataHandler;
+ if (charDataHandler) {
+ if (MUST_CONVERT(enc, s)) {
+ for (;;) {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+ *eventEndPP = s;
+ charDataHandler(handlerArg, dataBuf,
+ (int)(dataPtr - (ICHAR *)dataBuf));
+ if (s == next)
+ break;
+ *eventPP = s;
+ }
+ }
+ else
+ charDataHandler(handlerArg,
+ (XML_Char *)s,
+ (int)((XML_Char *)next - (XML_Char *)s));
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ }
+ break;
+ case XML_TOK_PI:
+ if (!reportProcessingInstruction(parser, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_COMMENT:
+ if (!reportComment(parser, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ default:
+ if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ *eventPP = s = next;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default: ;
+ }
+ }
+ /* not reached */
+}
+
+/* Precondition: all arguments must be non-NULL;
+ Purpose:
+ - normalize attributes
+ - check attributes for well-formedness
+ - generate namespace aware attribute names (URI, prefix)
+ - build list of attributes for startElementHandler
+ - default attributes
+ - process namespace declarations (check and report them)
+ - generate namespace aware element name (URI, prefix)
+*/
+static enum XML_Error
+storeAtts(XML_Parser parser, const ENCODING *enc,
+ const char *attStr, TAG_NAME *tagNamePtr,
+ BINDING **bindingsPtr)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ ELEMENT_TYPE *elementType;
+ int nDefaultAtts;
+ const XML_Char **appAtts; /* the attribute list for the application */
+ int attIndex = 0;
+ int prefixLen;
+ int i;
+ int n;
+ XML_Char *uri;
+ int nPrefixes = 0;
+ BINDING *binding;
+ const XML_Char *localPart;
+
+ /* lookup the element type name */
+ elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0);
+ if (!elementType) {
+ const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name,
+ sizeof(ELEMENT_TYPE));
+ if (!elementType)
+ return XML_ERROR_NO_MEMORY;
+ if (ns && !setElementTypePrefix(parser, elementType))
+ return XML_ERROR_NO_MEMORY;
+ }
+ nDefaultAtts = elementType->nDefaultAtts;
+
+ /* get the attributes from the tokenizer */
+ n = XmlGetAttributes(enc, attStr, attsSize, atts);
+ if (n + nDefaultAtts > attsSize) {
+ int oldAttsSize = attsSize;
+ ATTRIBUTE *temp;
+#ifdef XML_ATTR_INFO
+ XML_AttrInfo *temp2;
+#endif
+ attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
+ temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE));
+ if (temp == NULL)
+ return XML_ERROR_NO_MEMORY;
+ atts = temp;
+#ifdef XML_ATTR_INFO
+ temp2 = (XML_AttrInfo *)REALLOC((void *)attInfo, attsSize * sizeof(XML_AttrInfo));
+ if (temp2 == NULL)
+ return XML_ERROR_NO_MEMORY;
+ attInfo = temp2;
+#endif
+ if (n > oldAttsSize)
+ XmlGetAttributes(enc, attStr, n, atts);
+ }
+
+ appAtts = (const XML_Char **)atts;
+ for (i = 0; i < n; i++) {
+ ATTRIBUTE *currAtt = &atts[i];
+#ifdef XML_ATTR_INFO
+ XML_AttrInfo *currAttInfo = &attInfo[i];
+#endif
+ /* add the name and value to the attribute list */
+ ATTRIBUTE_ID *attId = getAttributeId(parser, enc, currAtt->name,
+ currAtt->name
+ + XmlNameLength(enc, currAtt->name));
+ if (!attId)
+ return XML_ERROR_NO_MEMORY;
+#ifdef XML_ATTR_INFO
+ currAttInfo->nameStart = parseEndByteIndex - (parseEndPtr - currAtt->name);
+ currAttInfo->nameEnd = currAttInfo->nameStart +
+ XmlNameLength(enc, currAtt->name);
+ currAttInfo->valueStart = parseEndByteIndex -
+ (parseEndPtr - currAtt->valuePtr);
+ currAttInfo->valueEnd = parseEndByteIndex - (parseEndPtr - currAtt->valueEnd);
+#endif
+ /* Detect duplicate attributes by their QNames. This does not work when
+ namespace processing is turned on and different prefixes for the same
+ namespace are used. For this case we have a check further down.
+ */
+ if ((attId->name)[-1]) {
+ if (enc == encoding)
+ eventPtr = atts[i].name;
+ return XML_ERROR_DUPLICATE_ATTRIBUTE;
+ }
+ (attId->name)[-1] = 1;
+ appAtts[attIndex++] = attId->name;
+ if (!atts[i].normalized) {
+ enum XML_Error result;
+ XML_Bool isCdata = XML_TRUE;
+
+ /* figure out whether declared as other than CDATA */
+ if (attId->maybeTokenized) {
+ int j;
+ for (j = 0; j < nDefaultAtts; j++) {
+ if (attId == elementType->defaultAtts[j].id) {
+ isCdata = elementType->defaultAtts[j].isCdata;
+ break;
+ }
+ }
+ }
+
+ /* normalize the attribute value */
+ result = storeAttributeValue(parser, enc, isCdata,
+ atts[i].valuePtr, atts[i].valueEnd,
+ &tempPool);
+ if (result)
+ return result;
+ appAtts[attIndex] = poolStart(&tempPool);
+ poolFinish(&tempPool);
+ }
+ else {
+ /* the value did not need normalizing */
+ appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr,
+ atts[i].valueEnd);
+ if (appAtts[attIndex] == 0)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ }
+ /* handle prefixed attribute names */
+ if (attId->prefix) {
+ if (attId->xmlns) {
+ /* deal with namespace declarations here */
+ enum XML_Error result = addBinding(parser, attId->prefix, attId,
+ appAtts[attIndex], bindingsPtr);
+ if (result)
+ return result;
+ --attIndex;
+ }
+ else {
+ /* deal with other prefixed names later */
+ attIndex++;
+ nPrefixes++;
+ (attId->name)[-1] = 2;
+ }
+ }
+ else
+ attIndex++;
+ }
+
+ /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */
+ nSpecifiedAtts = attIndex;
+ if (elementType->idAtt && (elementType->idAtt->name)[-1]) {
+ for (i = 0; i < attIndex; i += 2)
+ if (appAtts[i] == elementType->idAtt->name) {
+ idAttIndex = i;
+ break;
+ }
+ }
+ else
+ idAttIndex = -1;
+
+ /* do attribute defaulting */
+ for (i = 0; i < nDefaultAtts; i++) {
+ const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i;
+ if (!(da->id->name)[-1] && da->value) {
+ if (da->id->prefix) {
+ if (da->id->xmlns) {
+ enum XML_Error result = addBinding(parser, da->id->prefix, da->id,
+ da->value, bindingsPtr);
+ if (result)
+ return result;
+ }
+ else {
+ (da->id->name)[-1] = 2;
+ nPrefixes++;
+ appAtts[attIndex++] = da->id->name;
+ appAtts[attIndex++] = da->value;
+ }
+ }
+ else {
+ (da->id->name)[-1] = 1;
+ appAtts[attIndex++] = da->id->name;
+ appAtts[attIndex++] = da->value;
+ }
+ }
+ }
+ appAtts[attIndex] = 0;
+
+ /* expand prefixed attribute names, check for duplicates,
+ and clear flags that say whether attributes were specified */
+ i = 0;
+ if (nPrefixes) {
+ int j; /* hash table index */
+ unsigned long version = nsAttsVersion;
+ int nsAttsSize = (int)1 << nsAttsPower;
+ /* size of hash table must be at least 2 * (# of prefixed attributes) */
+ if ((nPrefixes << 1) >> nsAttsPower) { /* true for nsAttsPower = 0 */
+ NS_ATT *temp;
+ /* hash table size must also be a power of 2 and >= 8 */
+ while (nPrefixes >> nsAttsPower++);
+ if (nsAttsPower < 3)
+ nsAttsPower = 3;
+ nsAttsSize = (int)1 << nsAttsPower;
+ temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT));
+ if (!temp)
+ return XML_ERROR_NO_MEMORY;
+ nsAtts = temp;
+ version = 0; /* force re-initialization of nsAtts hash table */
+ }
+ /* using a version flag saves us from initializing nsAtts every time */
+ if (!version) { /* initialize version flags when version wraps around */
+ version = INIT_ATTS_VERSION;
+ for (j = nsAttsSize; j != 0; )
+ nsAtts[--j].version = version;
+ }
+ nsAttsVersion = --version;
+
+ /* expand prefixed names and check for duplicates */
+ for (; i < attIndex; i += 2) {
+ const XML_Char *s = appAtts[i];
+ if (s[-1] == 2) { /* prefixed */
+ ATTRIBUTE_ID *id;
+ const BINDING *b;
+ unsigned long uriHash = hash_secret_salt;
+ ((XML_Char *)s)[-1] = 0; /* clear flag */
+ id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0);
+ b = id->prefix->binding;
+ if (!b)
+ return XML_ERROR_UNBOUND_PREFIX;
+
+ /* as we expand the name we also calculate its hash value */
+ for (j = 0; j < b->uriLen; j++) {
+ const XML_Char c = b->uri[j];
+ if (!poolAppendChar(&tempPool, c))
+ return XML_ERROR_NO_MEMORY;
+ uriHash = CHAR_HASH(uriHash, c);
+ }
+ while (*s++ != XML_T(ASCII_COLON))
+ ;
+ do { /* copies null terminator */
+ const XML_Char c = *s;
+ if (!poolAppendChar(&tempPool, *s))
+ return XML_ERROR_NO_MEMORY;
+ uriHash = CHAR_HASH(uriHash, c);
+ } while (*s++);
+
+ { /* Check hash table for duplicate of expanded name (uriName).
+ Derived from code in lookup(parser, HASH_TABLE *table, ...).
+ */
+ unsigned char step = 0;
+ unsigned long mask = nsAttsSize - 1;
+ j = uriHash & mask; /* index into hash table */
+ while (nsAtts[j].version == version) {
+ /* for speed we compare stored hash values first */
+ if (uriHash == nsAtts[j].hash) {
+ const XML_Char *s1 = poolStart(&tempPool);
+ const XML_Char *s2 = nsAtts[j].uriName;
+ /* s1 is null terminated, but not s2 */
+ for (; *s1 == *s2 && *s1 != 0; s1++, s2++);
+ if (*s1 == 0)
+ return XML_ERROR_DUPLICATE_ATTRIBUTE;
+ }
+ if (!step)
+ step = PROBE_STEP(uriHash, mask, nsAttsPower);
+ j < step ? (j += nsAttsSize - step) : (j -= step);
+ }
+ }
+
+ if (ns_triplets) { /* append namespace separator and prefix */
+ tempPool.ptr[-1] = namespaceSeparator;
+ s = b->prefix->name;
+ do {
+ if (!poolAppendChar(&tempPool, *s))
+ return XML_ERROR_NO_MEMORY;
+ } while (*s++);
+ }
+
+ /* store expanded name in attribute list */
+ s = poolStart(&tempPool);
+ poolFinish(&tempPool);
+ appAtts[i] = s;
+
+ /* fill empty slot with new version, uriName and hash value */
+ nsAtts[j].version = version;
+ nsAtts[j].hash = uriHash;
+ nsAtts[j].uriName = s;
+
+ if (!--nPrefixes) {
+ i += 2;
+ break;
+ }
+ }
+ else /* not prefixed */
+ ((XML_Char *)s)[-1] = 0; /* clear flag */
+ }
+ }
+ /* clear flags for the remaining attributes */
+ for (; i < attIndex; i += 2)
+ ((XML_Char *)(appAtts[i]))[-1] = 0;
+ for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
+ binding->attId->name[-1] = 0;
+
+ if (!ns)
+ return XML_ERROR_NONE;
+
+ /* expand the element type name */
+ if (elementType->prefix) {
+ binding = elementType->prefix->binding;
+ if (!binding)
+ return XML_ERROR_UNBOUND_PREFIX;
+ localPart = tagNamePtr->str;
+ while (*localPart++ != XML_T(ASCII_COLON))
+ ;
+ }
+ else if (dtd->defaultPrefix.binding) {
+ binding = dtd->defaultPrefix.binding;
+ localPart = tagNamePtr->str;
+ }
+ else
+ return XML_ERROR_NONE;
+ prefixLen = 0;
+ if (ns_triplets && binding->prefix->name) {
+ for (; binding->prefix->name[prefixLen++];)
+ ; /* prefixLen includes null terminator */
+ }
+ tagNamePtr->localPart = localPart;
+ tagNamePtr->uriLen = binding->uriLen;
+ tagNamePtr->prefix = binding->prefix->name;
+ tagNamePtr->prefixLen = prefixLen;
+ for (i = 0; localPart[i++];)
+ ; /* i includes null terminator */
+ n = i + binding->uriLen + prefixLen;
+ if (n > binding->uriAlloc) {
+ TAG *p;
+ uri = (XML_Char *)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char));
+ if (!uri)
+ return XML_ERROR_NO_MEMORY;
+ binding->uriAlloc = n + EXPAND_SPARE;
+ memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char));
+ for (p = tagStack; p; p = p->parent)
+ if (p->name.str == binding->uri)
+ p->name.str = uri;
+ FREE(binding->uri);
+ binding->uri = uri;
+ }
+ /* if namespaceSeparator != '\0' then uri includes it already */
+ uri = binding->uri + binding->uriLen;
+ memcpy(uri, localPart, i * sizeof(XML_Char));
+ /* we always have a namespace separator between localPart and prefix */
+ if (prefixLen) {
+ uri += i - 1;
+ *uri = namespaceSeparator; /* replace null terminator */
+ memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char));
+ }
+ tagNamePtr->str = binding->uri;
+ return XML_ERROR_NONE;
+}
+
+/* addBinding() overwrites the value of prefix->binding without checking.
+ Therefore one must keep track of the old value outside of addBinding().
+*/
+static enum XML_Error
+addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
+ const XML_Char *uri, BINDING **bindingsPtr)
+{
+ static const XML_Char xmlNamespace[] = {
+ ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH,
+ ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD,
+ ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L,
+ ASCII_SLASH, ASCII_1, ASCII_9, ASCII_9, ASCII_8, ASCII_SLASH,
+ ASCII_n, ASCII_a, ASCII_m, ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c,
+ ASCII_e, '\0'
+ };
+ static const int xmlLen =
+ (int)sizeof(xmlNamespace)/sizeof(XML_Char) - 1;
+ static const XML_Char xmlnsNamespace[] = {
+ ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH,
+ ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD,
+ ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_2, ASCII_0, ASCII_0,
+ ASCII_0, ASCII_SLASH, ASCII_x, ASCII_m, ASCII_l, ASCII_n, ASCII_s,
+ ASCII_SLASH, '\0'
+ };
+ static const int xmlnsLen =
+ (int)sizeof(xmlnsNamespace)/sizeof(XML_Char) - 1;
+
+ XML_Bool mustBeXML = XML_FALSE;
+ XML_Bool isXML = XML_TRUE;
+ XML_Bool isXMLNS = XML_TRUE;
+
+ BINDING *b;
+ int len;
+
+ /* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */
+ if (*uri == XML_T('\0') && prefix->name)
+ return XML_ERROR_UNDECLARING_PREFIX;
+
+ if (prefix->name
+ && prefix->name[0] == XML_T(ASCII_x)
+ && prefix->name[1] == XML_T(ASCII_m)
+ && prefix->name[2] == XML_T(ASCII_l)) {
+
+ /* Not allowed to bind xmlns */
+ if (prefix->name[3] == XML_T(ASCII_n)
+ && prefix->name[4] == XML_T(ASCII_s)
+ && prefix->name[5] == XML_T('\0'))
+ return XML_ERROR_RESERVED_PREFIX_XMLNS;
+
+ if (prefix->name[3] == XML_T('\0'))
+ mustBeXML = XML_TRUE;
+ }
+
+ for (len = 0; uri[len]; len++) {
+ if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len]))
+ isXML = XML_FALSE;
+
+ if (!mustBeXML && isXMLNS
+ && (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
+ isXMLNS = XML_FALSE;
+ }
+ isXML = isXML && len == xmlLen;
+ isXMLNS = isXMLNS && len == xmlnsLen;
+
+ if (mustBeXML != isXML)
+ return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML
+ : XML_ERROR_RESERVED_NAMESPACE_URI;
+
+ if (isXMLNS)
+ return XML_ERROR_RESERVED_NAMESPACE_URI;
+
+ if (namespaceSeparator)
+ len++;
+ if (freeBindingList) {
+ b = freeBindingList;
+ if (len > b->uriAlloc) {
+ XML_Char *temp = (XML_Char *)REALLOC(b->uri,
+ sizeof(XML_Char) * (len + EXPAND_SPARE));
+ if (temp == NULL)
+ return XML_ERROR_NO_MEMORY;
+ b->uri = temp;
+ b->uriAlloc = len + EXPAND_SPARE;
+ }
+ freeBindingList = b->nextTagBinding;
+ }
+ else {
+ b = (BINDING *)MALLOC(sizeof(BINDING));
+ if (!b)
+ return XML_ERROR_NO_MEMORY;
+ b->uri = (XML_Char *)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE));
+ if (!b->uri) {
+ FREE(b);
+ return XML_ERROR_NO_MEMORY;
+ }
+ b->uriAlloc = len + EXPAND_SPARE;
+ }
+ b->uriLen = len;
+ memcpy(b->uri, uri, len * sizeof(XML_Char));
+ if (namespaceSeparator)
+ b->uri[len - 1] = namespaceSeparator;
+ b->prefix = prefix;
+ b->attId = attId;
+ b->prevPrefixBinding = prefix->binding;
+ /* NULL binding when default namespace undeclared */
+ if (*uri == XML_T('\0') && prefix == &_dtd->defaultPrefix)
+ prefix->binding = NULL;
+ else
+ prefix->binding = b;
+ b->nextTagBinding = *bindingsPtr;
+ *bindingsPtr = b;
+ /* if attId == NULL then we are not starting a namespace scope */
+ if (attId && startNamespaceDeclHandler)
+ startNamespaceDeclHandler(handlerArg, prefix->name,
+ prefix->binding ? uri : 0);
+ return XML_ERROR_NONE;
+}
+
+/* The idea here is to avoid using stack for each CDATA section when
+ the whole file is parsed with one call.
+*/
+static enum XML_Error PTRCALL
+cdataSectionProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = doCdataSection(parser, encoding, &start, end,
+ endPtr, (XML_Bool)!ps_finalBuffer);
+ if (result != XML_ERROR_NONE)
+ return result;
+ if (start) {
+ if (parentParser) { /* we are parsing an external entity */
+ processor = externalEntityContentProcessor;
+ return externalEntityContentProcessor(parser, start, end, endPtr);
+ }
+ else {
+ processor = contentProcessor;
+ return contentProcessor(parser, start, end, endPtr);
+ }
+ }
+ return result;
+}
+
+/* startPtr gets set to non-null if the section is closed, and to null if
+ the section is not yet closed.
+*/
+static enum XML_Error
+doCdataSection(XML_Parser parser,
+ const ENCODING *enc,
+ const char **startPtr,
+ const char *end,
+ const char **nextPtr,
+ XML_Bool haveMore)
+{
+ const char *s = *startPtr;
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ *eventPP = s;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+ *eventPP = s;
+ *startPtr = NULL;
+
+ for (;;) {
+ const char *next;
+ int tok = XmlCdataSectionTok(enc, s, end, &next);
+ *eventEndPP = next;
+ switch (tok) {
+ case XML_TOK_CDATA_SECT_CLOSE:
+ if (endCdataSectionHandler)
+ endCdataSectionHandler(handlerArg);
+#if 0
+ /* see comment under XML_TOK_CDATA_SECT_OPEN */
+ else if (characterDataHandler)
+ characterDataHandler(handlerArg, dataBuf, 0);
+#endif
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ *startPtr = next;
+ *nextPtr = next;
+ if (ps_parsing == XML_FINISHED)
+ return XML_ERROR_ABORTED;
+ else
+ return XML_ERROR_NONE;
+ case XML_TOK_DATA_NEWLINE:
+ if (characterDataHandler) {
+ XML_Char c = 0xA;
+ characterDataHandler(handlerArg, &c, 1);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ case XML_TOK_DATA_CHARS:
+ {
+ XML_CharacterDataHandler charDataHandler = characterDataHandler;
+ if (charDataHandler) {
+ if (MUST_CONVERT(enc, s)) {
+ for (;;) {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+ *eventEndPP = next;
+ charDataHandler(handlerArg, dataBuf,
+ (int)(dataPtr - (ICHAR *)dataBuf));
+ if (s == next)
+ break;
+ *eventPP = s;
+ }
+ }
+ else
+ charDataHandler(handlerArg,
+ (XML_Char *)s,
+ (int)((XML_Char *)next - (XML_Char *)s));
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ }
+ break;
+ case XML_TOK_INVALID:
+ *eventPP = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_PARTIAL:
+ case XML_TOK_NONE:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_CDATA_SECTION;
+ default:
+ *eventPP = next;
+ return XML_ERROR_UNEXPECTED_STATE;
+ }
+
+ *eventPP = s = next;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default: ;
+ }
+ }
+ /* not reached */
+}
+
+#ifdef XML_DTD
+
+/* The idea here is to avoid using stack for each IGNORE section when
+ the whole file is parsed with one call.
+*/
+static enum XML_Error PTRCALL
+ignoreSectionProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = doIgnoreSection(parser, encoding, &start, end,
+ endPtr, (XML_Bool)!ps_finalBuffer);
+ if (result != XML_ERROR_NONE)
+ return result;
+ if (start) {
+ processor = prologProcessor;
+ return prologProcessor(parser, start, end, endPtr);
+ }
+ return result;
+}
+
+/* startPtr gets set to non-null is the section is closed, and to null
+ if the section is not yet closed.
+*/
+static enum XML_Error
+doIgnoreSection(XML_Parser parser,
+ const ENCODING *enc,
+ const char **startPtr,
+ const char *end,
+ const char **nextPtr,
+ XML_Bool haveMore)
+{
+ const char *next;
+ int tok;
+ const char *s = *startPtr;
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ *eventPP = s;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+ *eventPP = s;
+ *startPtr = NULL;
+ tok = XmlIgnoreSectionTok(enc, s, end, &next);
+ *eventEndPP = next;
+ switch (tok) {
+ case XML_TOK_IGNORE_SECT:
+ if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ *startPtr = next;
+ *nextPtr = next;
+ if (ps_parsing == XML_FINISHED)
+ return XML_ERROR_ABORTED;
+ else
+ return XML_ERROR_NONE;
+ case XML_TOK_INVALID:
+ *eventPP = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_PARTIAL:
+ case XML_TOK_NONE:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */
+ default:
+ *eventPP = next;
+ return XML_ERROR_UNEXPECTED_STATE;
+ }
+ /* not reached */
+}
+
+#endif /* XML_DTD */
+
+static enum XML_Error
+initializeEncoding(XML_Parser parser)
+{
+ const char *s;
+#ifdef XML_UNICODE
+ char encodingBuf[128];
+ if (!protocolEncodingName)
+ s = NULL;
+ else {
+ int i;
+ for (i = 0; protocolEncodingName[i]; i++) {
+ if (i == sizeof(encodingBuf) - 1
+ || (protocolEncodingName[i] & ~0x7f) != 0) {
+ encodingBuf[0] = '\0';
+ break;
+ }
+ encodingBuf[i] = (char)protocolEncodingName[i];
+ }
+ encodingBuf[i] = '\0';
+ s = encodingBuf;
+ }
+#else
+ s = protocolEncodingName;
+#endif
+ if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s))
+ return XML_ERROR_NONE;
+ return handleUnknownEncoding(parser, protocolEncodingName);
+}
+
+static enum XML_Error
+processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
+ const char *s, const char *next)
+{
+ const char *encodingName = NULL;
+ const XML_Char *storedEncName = NULL;
+ const ENCODING *newEncoding = NULL;
+ const char *version = NULL;
+ const char *versionend;
+ const XML_Char *storedversion = NULL;
+ int standalone = -1;
+ if (!(ns
+ ? XmlParseXmlDeclNS
+ : XmlParseXmlDecl)(isGeneralTextEntity,
+ encoding,
+ s,
+ next,
+ &eventPtr,
+ &version,
+ &versionend,
+ &encodingName,
+ &newEncoding,
+ &standalone)) {
+ if (isGeneralTextEntity)
+ return XML_ERROR_TEXT_DECL;
+ else
+ return XML_ERROR_XML_DECL;
+ }
+ if (!isGeneralTextEntity && standalone == 1) {
+ _dtd->standalone = XML_TRUE;
+#ifdef XML_DTD
+ if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
+ paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+#endif /* XML_DTD */
+ }
+ if (xmlDeclHandler) {
+ if (encodingName != NULL) {
+ storedEncName = poolStoreString(&temp2Pool,
+ encoding,
+ encodingName,
+ encodingName
+ + XmlNameLength(encoding, encodingName));
+ if (!storedEncName)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&temp2Pool);
+ }
+ if (version) {
+ storedversion = poolStoreString(&temp2Pool,
+ encoding,
+ version,
+ versionend - encoding->minBytesPerChar);
+ if (!storedversion)
+ return XML_ERROR_NO_MEMORY;
+ }
+ xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, encoding, s, next);
+ if (protocolEncodingName == NULL) {
+ if (newEncoding) {
+ if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) {
+ eventPtr = encodingName;
+ return XML_ERROR_INCORRECT_ENCODING;
+ }
+ encoding = newEncoding;
+ }
+ else if (encodingName) {
+ enum XML_Error result;
+ if (!storedEncName) {
+ storedEncName = poolStoreString(
+ &temp2Pool, encoding, encodingName,
+ encodingName + XmlNameLength(encoding, encodingName));
+ if (!storedEncName)
+ return XML_ERROR_NO_MEMORY;
+ }
+ result = handleUnknownEncoding(parser, storedEncName);
+ poolClear(&temp2Pool);
+ if (result == XML_ERROR_UNKNOWN_ENCODING)
+ eventPtr = encodingName;
+ return result;
+ }
+ }
+
+ if (storedEncName || storedversion)
+ poolClear(&temp2Pool);
+
+ return XML_ERROR_NONE;
+}
+
+static enum XML_Error
+handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
+{
+ if (unknownEncodingHandler) {
+ XML_Encoding info;
+ int i;
+ for (i = 0; i < 256; i++)
+ info.map[i] = -1;
+ info.convert = NULL;
+ info.data = NULL;
+ info.release = NULL;
+ if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName,
+ &info)) {
+ ENCODING *enc;
+ unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding());
+ if (!unknownEncodingMem) {
+ if (info.release)
+ info.release(info.data);
+ return XML_ERROR_NO_MEMORY;
+ }
+ enc = (ns
+ ? XmlInitUnknownEncodingNS
+ : XmlInitUnknownEncoding)(unknownEncodingMem,
+ info.map,
+ info.convert,
+ info.data);
+ if (enc) {
+ unknownEncodingData = info.data;
+ unknownEncodingRelease = info.release;
+ encoding = enc;
+ return XML_ERROR_NONE;
+ }
+ }
+ if (info.release != NULL)
+ info.release(info.data);
+ }
+ return XML_ERROR_UNKNOWN_ENCODING;
+}
+
+static enum XML_Error PTRCALL
+prologInitProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ enum XML_Error result = initializeEncoding(parser);
+ if (result != XML_ERROR_NONE)
+ return result;
+ processor = prologProcessor;
+ return prologProcessor(parser, s, end, nextPtr);
+}
+
+#ifdef XML_DTD
+
+static enum XML_Error PTRCALL
+externalParEntInitProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ enum XML_Error result = initializeEncoding(parser);
+ if (result != XML_ERROR_NONE)
+ return result;
+
+ /* we know now that XML_Parse(Buffer) has been called,
+ so we consider the external parameter entity read */
+ _dtd->paramEntityRead = XML_TRUE;
+
+ if (prologState.inEntityValue) {
+ processor = entityValueInitProcessor;
+ return entityValueInitProcessor(parser, s, end, nextPtr);
+ }
+ else {
+ processor = externalParEntProcessor;
+ return externalParEntProcessor(parser, s, end, nextPtr);
+ }
+}
+
+static enum XML_Error PTRCALL
+entityValueInitProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ int tok;
+ const char *start = s;
+ const char *next = start;
+ eventPtr = start;
+
+ for (;;) {
+ tok = XmlPrologTok(encoding, start, end, &next);
+ eventEndPtr = next;
+ if (tok <= 0) {
+ if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ switch (tok) {
+ case XML_TOK_INVALID:
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_NONE: /* start == end */
+ default:
+ break;
+ }
+ /* found end of entity value - can store it now */
+ return storeEntityValue(parser, encoding, s, end);
+ }
+ else if (tok == XML_TOK_XML_DECL) {
+ enum XML_Error result;
+ result = processXmlDecl(parser, 0, start, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default:
+ *nextPtr = next;
+ }
+ /* stop scanning for text declaration - we found one */
+ processor = entityValueProcessor;
+ return entityValueProcessor(parser, next, end, nextPtr);
+ }
+ /* If we are at the end of the buffer, this would cause XmlPrologTok to
+ return XML_TOK_NONE on the next call, which would then cause the
+ function to exit with *nextPtr set to s - that is what we want for other
+ tokens, but not for the BOM - we would rather like to skip it;
+ then, when this routine is entered the next time, XmlPrologTok will
+ return XML_TOK_INVALID, since the BOM is still in the buffer
+ */
+ else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) {
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ }
+ start = next;
+ eventPtr = start;
+ }
+}
+
+static enum XML_Error PTRCALL
+externalParEntProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ const char *next = s;
+ int tok;
+
+ tok = XmlPrologTok(encoding, s, end, &next);
+ if (tok <= 0) {
+ if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ switch (tok) {
+ case XML_TOK_INVALID:
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_NONE: /* start == end */
+ default:
+ break;
+ }
+ }
+ /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM.
+ However, when parsing an external subset, doProlog will not accept a BOM
+ as valid, and report a syntax error, so we have to skip the BOM
+ */
+ else if (tok == XML_TOK_BOM) {
+ s = next;
+ tok = XmlPrologTok(encoding, s, end, &next);
+ }
+
+ processor = prologProcessor;
+ return doProlog(parser, encoding, s, end, tok, next,
+ nextPtr, (XML_Bool)!ps_finalBuffer);
+}
+
+static enum XML_Error PTRCALL
+entityValueProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ const char *start = s;
+ const char *next = s;
+ const ENCODING *enc = encoding;
+ int tok;
+
+ for (;;) {
+ tok = XmlPrologTok(enc, start, end, &next);
+ if (tok <= 0) {
+ if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ switch (tok) {
+ case XML_TOK_INVALID:
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_NONE: /* start == end */
+ default:
+ break;
+ }
+ /* found end of entity value - can store it now */
+ return storeEntityValue(parser, enc, s, end);
+ }
+ start = next;
+ }
+}
+
+#endif /* XML_DTD */
+
+static enum XML_Error PTRCALL
+prologProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ const char *next = s;
+ int tok = XmlPrologTok(encoding, s, end, &next);
+ return doProlog(parser, encoding, s, end, tok, next,
+ nextPtr, (XML_Bool)!ps_finalBuffer);
+}
+
+static enum XML_Error
+doProlog(XML_Parser parser,
+ const ENCODING *enc,
+ const char *s,
+ const char *end,
+ int tok,
+ const char *next,
+ const char **nextPtr,
+ XML_Bool haveMore)
+{
+#ifdef XML_DTD
+ static const XML_Char externalSubsetName[] = { ASCII_HASH , '\0' };
+#endif /* XML_DTD */
+ static const XML_Char atypeCDATA[] =
+ { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+ static const XML_Char atypeID[] = { ASCII_I, ASCII_D, '\0' };
+ static const XML_Char atypeIDREF[] =
+ { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' };
+ static const XML_Char atypeIDREFS[] =
+ { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' };
+ static const XML_Char atypeENTITY[] =
+ { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' };
+ static const XML_Char atypeENTITIES[] = { ASCII_E, ASCII_N,
+ ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, '\0' };
+ static const XML_Char atypeNMTOKEN[] = {
+ ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' };
+ static const XML_Char atypeNMTOKENS[] = { ASCII_N, ASCII_M, ASCII_T,
+ ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, '\0' };
+ static const XML_Char notationPrefix[] = { ASCII_N, ASCII_O, ASCII_T,
+ ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, ASCII_LPAREN, '\0' };
+ static const XML_Char enumValueSep[] = { ASCII_PIPE, '\0' };
+ static const XML_Char enumValueStart[] = { ASCII_LPAREN, '\0' };
+
+ /* save one level of indirection */
+ DTD * const dtd = _dtd;
+
+ const char **eventPP;
+ const char **eventEndPP;
+ enum XML_Content_Quant quant;
+
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+
+ for (;;) {
+ int role;
+ XML_Bool handleDefault = XML_TRUE;
+ *eventPP = s;
+ *eventEndPP = next;
+ if (tok <= 0) {
+ if (haveMore && tok != XML_TOK_INVALID) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ switch (tok) {
+ case XML_TOK_INVALID:
+ *eventPP = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ return XML_ERROR_PARTIAL_CHAR;
+ case -XML_TOK_PROLOG_S:
+ tok = -tok;
+ break;
+ case XML_TOK_NONE:
+#ifdef XML_DTD
+ /* for internal PE NOT referenced between declarations */
+ if (enc != encoding && !openInternalEntities->betweenDecl) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ /* WFC: PE Between Declarations - must check that PE contains
+ complete markup, not only for external PEs, but also for
+ internal PEs if the reference occurs between declarations.
+ */
+ if (isParamEntity || enc != encoding) {
+ if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc)
+ == XML_ROLE_ERROR)
+ return XML_ERROR_INCOMPLETE_PE;
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+#endif /* XML_DTD */
+ return XML_ERROR_NO_ELEMENTS;
+ default:
+ tok = -tok;
+ next = end;
+ break;
+ }
+ }
+ role = XmlTokenRole(&prologState, tok, s, next, enc);
+ switch (role) {
+ case XML_ROLE_XML_DECL:
+ {
+ enum XML_Error result = processXmlDecl(parser, 0, s, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ enc = encoding;
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_DOCTYPE_NAME:
+ if (startDoctypeDeclHandler) {
+ doctypeName = poolStoreString(&tempPool, enc, s, next);
+ if (!doctypeName)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ doctypePubid = NULL;
+ handleDefault = XML_FALSE;
+ }
+ doctypeSysid = NULL; /* always initialize to NULL */
+ break;
+ case XML_ROLE_DOCTYPE_INTERNAL_SUBSET:
+ if (startDoctypeDeclHandler) {
+ startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid,
+ doctypePubid, 1);
+ doctypeName = NULL;
+ poolClear(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ break;
+#ifdef XML_DTD
+ case XML_ROLE_TEXT_DECL:
+ {
+ enum XML_Error result = processXmlDecl(parser, 1, s, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ enc = encoding;
+ handleDefault = XML_FALSE;
+ }
+ break;
+#endif /* XML_DTD */
+ case XML_ROLE_DOCTYPE_PUBLIC_ID:
+#ifdef XML_DTD
+ useForeignDTD = XML_FALSE;
+ declEntity = (ENTITY *)lookup(parser,
+ &dtd->paramEntities,
+ externalSubsetName,
+ sizeof(ENTITY));
+ if (!declEntity)
+ return XML_ERROR_NO_MEMORY;
+#endif /* XML_DTD */
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (startDoctypeDeclHandler) {
+ XML_Char *pubId;
+ if (!XmlIsPublicId(enc, s, next, eventPP))
+ return XML_ERROR_PUBLICID;
+ pubId = poolStoreString(&tempPool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!pubId)
+ return XML_ERROR_NO_MEMORY;
+ normalizePublicId(pubId);
+ poolFinish(&tempPool);
+ doctypePubid = pubId;
+ handleDefault = XML_FALSE;
+ goto alreadyChecked;
+ }
+ /* fall through */
+ case XML_ROLE_ENTITY_PUBLIC_ID:
+ if (!XmlIsPublicId(enc, s, next, eventPP))
+ return XML_ERROR_PUBLICID;
+ alreadyChecked:
+ if (dtd->keepProcessing && declEntity) {
+ XML_Char *tem = poolStoreString(&dtd->pool,
+ enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!tem)
+ return XML_ERROR_NO_MEMORY;
+ normalizePublicId(tem);
+ declEntity->publicId = tem;
+ poolFinish(&dtd->pool);
+ if (entityDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_DOCTYPE_CLOSE:
+ if (doctypeName) {
+ startDoctypeDeclHandler(handlerArg, doctypeName,
+ doctypeSysid, doctypePubid, 0);
+ poolClear(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ /* doctypeSysid will be non-NULL in the case of a previous
+ XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler
+ was not set, indicating an external subset
+ */
+#ifdef XML_DTD
+ if (doctypeSysid || useForeignDTD) {
+ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (paramEntityParsing && externalEntityRefHandler) {
+ ENTITY *entity = (ENTITY *)lookup(parser,
+ &dtd->paramEntities,
+ externalSubsetName,
+ sizeof(ENTITY));
+ if (!entity)
+ return XML_ERROR_NO_MEMORY;
+ if (useForeignDTD)
+ entity->base = curBase;
+ dtd->paramEntityRead = XML_FALSE;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ 0,
+ entity->base,
+ entity->systemId,
+ entity->publicId))
+ return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ if (dtd->paramEntityRead) {
+ if (!dtd->standalone &&
+ notStandaloneHandler &&
+ !notStandaloneHandler(handlerArg))
+ return XML_ERROR_NOT_STANDALONE;
+ }
+ /* if we didn't read the foreign DTD then this means that there
+ is no external subset and we must reset dtd->hasParamEntityRefs
+ */
+ else if (!doctypeSysid)
+ dtd->hasParamEntityRefs = hadParamEntityRefs;
+ /* end of DTD - no need to update dtd->keepProcessing */
+ }
+ useForeignDTD = XML_FALSE;
+ }
+#endif /* XML_DTD */
+ if (endDoctypeDeclHandler) {
+ endDoctypeDeclHandler(handlerArg);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_INSTANCE_START:
+#ifdef XML_DTD
+ /* if there is no DOCTYPE declaration then now is the
+ last chance to read the foreign DTD
+ */
+ if (useForeignDTD) {
+ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (paramEntityParsing && externalEntityRefHandler) {
+ ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities,
+ externalSubsetName,
+ sizeof(ENTITY));
+ if (!entity)
+ return XML_ERROR_NO_MEMORY;
+ entity->base = curBase;
+ dtd->paramEntityRead = XML_FALSE;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ 0,
+ entity->base,
+ entity->systemId,
+ entity->publicId))
+ return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ if (dtd->paramEntityRead) {
+ if (!dtd->standalone &&
+ notStandaloneHandler &&
+ !notStandaloneHandler(handlerArg))
+ return XML_ERROR_NOT_STANDALONE;
+ }
+ /* if we didn't read the foreign DTD then this means that there
+ is no external subset and we must reset dtd->hasParamEntityRefs
+ */
+ else
+ dtd->hasParamEntityRefs = hadParamEntityRefs;
+ /* end of DTD - no need to update dtd->keepProcessing */
+ }
+ }
+#endif /* XML_DTD */
+ processor = contentProcessor;
+ return contentProcessor(parser, s, end, nextPtr);
+ case XML_ROLE_ATTLIST_ELEMENT_NAME:
+ declElementType = getElementType(parser, enc, s, next);
+ if (!declElementType)
+ return XML_ERROR_NO_MEMORY;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_NAME:
+ declAttributeId = getAttributeId(parser, enc, s, next);
+ if (!declAttributeId)
+ return XML_ERROR_NO_MEMORY;
+ declAttributeIsCdata = XML_FALSE;
+ declAttributeType = NULL;
+ declAttributeIsId = XML_FALSE;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_CDATA:
+ declAttributeIsCdata = XML_TRUE;
+ declAttributeType = atypeCDATA;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_ID:
+ declAttributeIsId = XML_TRUE;
+ declAttributeType = atypeID;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_IDREF:
+ declAttributeType = atypeIDREF;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_IDREFS:
+ declAttributeType = atypeIDREFS;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_ENTITY:
+ declAttributeType = atypeENTITY;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES:
+ declAttributeType = atypeENTITIES;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN:
+ declAttributeType = atypeNMTOKEN;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS:
+ declAttributeType = atypeNMTOKENS;
+ checkAttListDeclHandler:
+ if (dtd->keepProcessing && attlistDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_ATTRIBUTE_ENUM_VALUE:
+ case XML_ROLE_ATTRIBUTE_NOTATION_VALUE:
+ if (dtd->keepProcessing && attlistDeclHandler) {
+ const XML_Char *prefix;
+ if (declAttributeType) {
+ prefix = enumValueSep;
+ }
+ else {
+ prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE
+ ? notationPrefix
+ : enumValueStart);
+ }
+ if (!poolAppendString(&tempPool, prefix))
+ return XML_ERROR_NO_MEMORY;
+ if (!poolAppend(&tempPool, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ declAttributeType = tempPool.start;
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE:
+ case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE:
+ if (dtd->keepProcessing) {
+ if (!defineAttribute(declElementType, declAttributeId,
+ declAttributeIsCdata, declAttributeIsId,
+ 0, parser))
+ return XML_ERROR_NO_MEMORY;
+ if (attlistDeclHandler && declAttributeType) {
+ if (*declAttributeType == XML_T(ASCII_LPAREN)
+ || (*declAttributeType == XML_T(ASCII_N)
+ && declAttributeType[1] == XML_T(ASCII_O))) {
+ /* Enumerated or Notation type */
+ if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
+ || !poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_ERROR_NO_MEMORY;
+ declAttributeType = tempPool.start;
+ poolFinish(&tempPool);
+ }
+ *eventEndPP = s;
+ attlistDeclHandler(handlerArg, declElementType->name,
+ declAttributeId->name, declAttributeType,
+ 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
+ poolClear(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ }
+ break;
+ case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE:
+ case XML_ROLE_FIXED_ATTRIBUTE_VALUE:
+ if (dtd->keepProcessing) {
+ const XML_Char *attVal;
+ enum XML_Error result =
+ storeAttributeValue(parser, enc, declAttributeIsCdata,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar,
+ &dtd->pool);
+ if (result)
+ return result;
+ attVal = poolStart(&dtd->pool);
+ poolFinish(&dtd->pool);
+ /* ID attributes aren't allowed to have a default */
+ if (!defineAttribute(declElementType, declAttributeId,
+ declAttributeIsCdata, XML_FALSE, attVal, parser))
+ return XML_ERROR_NO_MEMORY;
+ if (attlistDeclHandler && declAttributeType) {
+ if (*declAttributeType == XML_T(ASCII_LPAREN)
+ || (*declAttributeType == XML_T(ASCII_N)
+ && declAttributeType[1] == XML_T(ASCII_O))) {
+ /* Enumerated or Notation type */
+ if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
+ || !poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_ERROR_NO_MEMORY;
+ declAttributeType = tempPool.start;
+ poolFinish(&tempPool);
+ }
+ *eventEndPP = s;
+ attlistDeclHandler(handlerArg, declElementType->name,
+ declAttributeId->name, declAttributeType,
+ attVal,
+ role == XML_ROLE_FIXED_ATTRIBUTE_VALUE);
+ poolClear(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ }
+ break;
+ case XML_ROLE_ENTITY_VALUE:
+ if (dtd->keepProcessing) {
+ enum XML_Error result = storeEntityValue(parser, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (declEntity) {
+ declEntity->textPtr = poolStart(&dtd->entityValuePool);
+ declEntity->textLen = (int)(poolLength(&dtd->entityValuePool));
+ poolFinish(&dtd->entityValuePool);
+ if (entityDeclHandler) {
+ *eventEndPP = s;
+ entityDeclHandler(handlerArg,
+ declEntity->name,
+ declEntity->is_param,
+ declEntity->textPtr,
+ declEntity->textLen,
+ curBase, 0, 0, 0);
+ handleDefault = XML_FALSE;
+ }
+ }
+ else
+ poolDiscard(&dtd->entityValuePool);
+ if (result != XML_ERROR_NONE)
+ return result;
+ }
+ break;
+ case XML_ROLE_DOCTYPE_SYSTEM_ID:
+#ifdef XML_DTD
+ useForeignDTD = XML_FALSE;
+#endif /* XML_DTD */
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (startDoctypeDeclHandler) {
+ doctypeSysid = poolStoreString(&tempPool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (doctypeSysid == NULL)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+#ifdef XML_DTD
+ else
+ /* use externalSubsetName to make doctypeSysid non-NULL
+ for the case where no startDoctypeDeclHandler is set */
+ doctypeSysid = externalSubsetName;
+#endif /* XML_DTD */
+ if (!dtd->standalone
+#ifdef XML_DTD
+ && !paramEntityParsing
+#endif /* XML_DTD */
+ && notStandaloneHandler
+ && !notStandaloneHandler(handlerArg))
+ return XML_ERROR_NOT_STANDALONE;
+#ifndef XML_DTD
+ break;
+#else /* XML_DTD */
+ if (!declEntity) {
+ declEntity = (ENTITY *)lookup(parser,
+ &dtd->paramEntities,
+ externalSubsetName,
+ sizeof(ENTITY));
+ if (!declEntity)
+ return XML_ERROR_NO_MEMORY;
+ declEntity->publicId = NULL;
+ }
+ /* fall through */
+#endif /* XML_DTD */
+ case XML_ROLE_ENTITY_SYSTEM_ID:
+ if (dtd->keepProcessing && declEntity) {
+ declEntity->systemId = poolStoreString(&dtd->pool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!declEntity->systemId)
+ return XML_ERROR_NO_MEMORY;
+ declEntity->base = curBase;
+ poolFinish(&dtd->pool);
+ if (entityDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_ENTITY_COMPLETE:
+ if (dtd->keepProcessing && declEntity && entityDeclHandler) {
+ *eventEndPP = s;
+ entityDeclHandler(handlerArg,
+ declEntity->name,
+ declEntity->is_param,
+ 0,0,
+ declEntity->base,
+ declEntity->systemId,
+ declEntity->publicId,
+ 0);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_ENTITY_NOTATION_NAME:
+ if (dtd->keepProcessing && declEntity) {
+ declEntity->notation = poolStoreString(&dtd->pool, enc, s, next);
+ if (!declEntity->notation)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&dtd->pool);
+ if (unparsedEntityDeclHandler) {
+ *eventEndPP = s;
+ unparsedEntityDeclHandler(handlerArg,
+ declEntity->name,
+ declEntity->base,
+ declEntity->systemId,
+ declEntity->publicId,
+ declEntity->notation);
+ handleDefault = XML_FALSE;
+ }
+ else if (entityDeclHandler) {
+ *eventEndPP = s;
+ entityDeclHandler(handlerArg,
+ declEntity->name,
+ 0,0,0,
+ declEntity->base,
+ declEntity->systemId,
+ declEntity->publicId,
+ declEntity->notation);
+ handleDefault = XML_FALSE;
+ }
+ }
+ break;
+ case XML_ROLE_GENERAL_ENTITY_NAME:
+ {
+ if (XmlPredefinedEntityName(enc, s, next)) {
+ declEntity = NULL;
+ break;
+ }
+ if (dtd->keepProcessing) {
+ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name,
+ sizeof(ENTITY));
+ if (!declEntity)
+ return XML_ERROR_NO_MEMORY;
+ if (declEntity->name != name) {
+ poolDiscard(&dtd->pool);
+ declEntity = NULL;
+ }
+ else {
+ poolFinish(&dtd->pool);
+ declEntity->publicId = NULL;
+ declEntity->is_param = XML_FALSE;
+ /* if we have a parent parser or are reading an internal parameter
+ entity, then the entity declaration is not considered "internal"
+ */
+ declEntity->is_internal = !(parentParser || openInternalEntities);
+ if (entityDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ }
+ else {
+ poolDiscard(&dtd->pool);
+ declEntity = NULL;
+ }
+ }
+ break;
+ case XML_ROLE_PARAM_ENTITY_NAME:
+#ifdef XML_DTD
+ if (dtd->keepProcessing) {
+ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities,
+ name, sizeof(ENTITY));
+ if (!declEntity)
+ return XML_ERROR_NO_MEMORY;
+ if (declEntity->name != name) {
+ poolDiscard(&dtd->pool);
+ declEntity = NULL;
+ }
+ else {
+ poolFinish(&dtd->pool);
+ declEntity->publicId = NULL;
+ declEntity->is_param = XML_TRUE;
+ /* if we have a parent parser or are reading an internal parameter
+ entity, then the entity declaration is not considered "internal"
+ */
+ declEntity->is_internal = !(parentParser || openInternalEntities);
+ if (entityDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ }
+ else {
+ poolDiscard(&dtd->pool);
+ declEntity = NULL;
+ }
+#else /* not XML_DTD */
+ declEntity = NULL;
+#endif /* XML_DTD */
+ break;
+ case XML_ROLE_NOTATION_NAME:
+ declNotationPublicId = NULL;
+ declNotationName = NULL;
+ if (notationDeclHandler) {
+ declNotationName = poolStoreString(&tempPool, enc, s, next);
+ if (!declNotationName)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_NOTATION_PUBLIC_ID:
+ if (!XmlIsPublicId(enc, s, next, eventPP))
+ return XML_ERROR_PUBLICID;
+ if (declNotationName) { /* means notationDeclHandler != NULL */
+ XML_Char *tem = poolStoreString(&tempPool,
+ enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!tem)
+ return XML_ERROR_NO_MEMORY;
+ normalizePublicId(tem);
+ declNotationPublicId = tem;
+ poolFinish(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_NOTATION_SYSTEM_ID:
+ if (declNotationName && notationDeclHandler) {
+ const XML_Char *systemId
+ = poolStoreString(&tempPool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!systemId)
+ return XML_ERROR_NO_MEMORY;
+ *eventEndPP = s;
+ notationDeclHandler(handlerArg,
+ declNotationName,
+ curBase,
+ systemId,
+ declNotationPublicId);
+ handleDefault = XML_FALSE;
+ }
+ poolClear(&tempPool);
+ break;
+ case XML_ROLE_NOTATION_NO_SYSTEM_ID:
+ if (declNotationPublicId && notationDeclHandler) {
+ *eventEndPP = s;
+ notationDeclHandler(handlerArg,
+ declNotationName,
+ curBase,
+ 0,
+ declNotationPublicId);
+ handleDefault = XML_FALSE;
+ }
+ poolClear(&tempPool);
+ break;
+ case XML_ROLE_ERROR:
+ switch (tok) {
+ case XML_TOK_PARAM_ENTITY_REF:
+ /* PE references in internal subset are
+ not allowed within declarations. */
+ return XML_ERROR_PARAM_ENTITY_REF;
+ case XML_TOK_XML_DECL:
+ return XML_ERROR_MISPLACED_XML_PI;
+ default:
+ return XML_ERROR_SYNTAX;
+ }
+#ifdef XML_DTD
+ case XML_ROLE_IGNORE_SECT:
+ {
+ enum XML_Error result;
+ if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ handleDefault = XML_FALSE;
+ result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore);
+ if (result != XML_ERROR_NONE)
+ return result;
+ else if (!next) {
+ processor = ignoreSectionProcessor;
+ return result;
+ }
+ }
+ break;
+#endif /* XML_DTD */
+ case XML_ROLE_GROUP_OPEN:
+ if (prologState.level >= groupSize) {
+ if (groupSize) {
+ char *temp = (char *)REALLOC(groupConnector, groupSize *= 2);
+ if (temp == NULL)
+ return XML_ERROR_NO_MEMORY;
+ groupConnector = temp;
+ if (dtd->scaffIndex) {
+ int *temp = (int *)REALLOC(dtd->scaffIndex,
+ groupSize * sizeof(int));
+ if (temp == NULL)
+ return XML_ERROR_NO_MEMORY;
+ dtd->scaffIndex = temp;
+ }
+ }
+ else {
+ groupConnector = (char *)MALLOC(groupSize = 32);
+ if (!groupConnector)
+ return XML_ERROR_NO_MEMORY;
+ }
+ }
+ groupConnector[prologState.level] = 0;
+ if (dtd->in_eldecl) {
+ int myindex = nextScaffoldPart(parser);
+ if (myindex < 0)
+ return XML_ERROR_NO_MEMORY;
+ dtd->scaffIndex[dtd->scaffLevel] = myindex;
+ dtd->scaffLevel++;
+ dtd->scaffold[myindex].type = XML_CTYPE_SEQ;
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_GROUP_SEQUENCE:
+ if (groupConnector[prologState.level] == ASCII_PIPE)
+ return XML_ERROR_SYNTAX;
+ groupConnector[prologState.level] = ASCII_COMMA;
+ if (dtd->in_eldecl && elementDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_GROUP_CHOICE:
+ if (groupConnector[prologState.level] == ASCII_COMMA)
+ return XML_ERROR_SYNTAX;
+ if (dtd->in_eldecl
+ && !groupConnector[prologState.level]
+ && (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+ != XML_CTYPE_MIXED)
+ ) {
+ dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+ = XML_CTYPE_CHOICE;
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ groupConnector[prologState.level] = ASCII_PIPE;
+ break;
+ case XML_ROLE_PARAM_ENTITY_REF:
+#ifdef XML_DTD
+ case XML_ROLE_INNER_PARAM_ENTITY_REF:
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (!paramEntityParsing)
+ dtd->keepProcessing = dtd->standalone;
+ else {
+ const XML_Char *name;
+ ENTITY *entity;
+ name = poolStoreString(&dtd->pool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
+ poolDiscard(&dtd->pool);
+ /* first, determine if a check for an existing declaration is needed;
+ if yes, check that the entity exists, and that it is internal,
+ otherwise call the skipped entity handler
+ */
+ if (prologState.documentEntity &&
+ (dtd->standalone
+ ? !openInternalEntities
+ : !dtd->hasParamEntityRefs)) {
+ if (!entity)
+ return XML_ERROR_UNDEFINED_ENTITY;
+ else if (!entity->is_internal)
+ return XML_ERROR_ENTITY_DECLARED_IN_PE;
+ }
+ else if (!entity) {
+ dtd->keepProcessing = dtd->standalone;
+ /* cannot report skipped entities in declarations */
+ if ((role == XML_ROLE_PARAM_ENTITY_REF) && skippedEntityHandler) {
+ skippedEntityHandler(handlerArg, name, 1);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ }
+ if (entity->open)
+ return XML_ERROR_RECURSIVE_ENTITY_REF;
+ if (entity->textPtr) {
+ enum XML_Error result;
+ XML_Bool betweenDecl =
+ (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE);
+ result = processInternalEntity(parser, entity, betweenDecl);
+ if (result != XML_ERROR_NONE)
+ return result;
+ handleDefault = XML_FALSE;
+ break;
+ }
+ if (externalEntityRefHandler) {
+ dtd->paramEntityRead = XML_FALSE;
+ entity->open = XML_TRUE;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ 0,
+ entity->base,
+ entity->systemId,
+ entity->publicId)) {
+ entity->open = XML_FALSE;
+ return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ }
+ entity->open = XML_FALSE;
+ handleDefault = XML_FALSE;
+ if (!dtd->paramEntityRead) {
+ dtd->keepProcessing = dtd->standalone;
+ break;
+ }
+ }
+ else {
+ dtd->keepProcessing = dtd->standalone;
+ break;
+ }
+ }
+#endif /* XML_DTD */
+ if (!dtd->standalone &&
+ notStandaloneHandler &&
+ !notStandaloneHandler(handlerArg))
+ return XML_ERROR_NOT_STANDALONE;
+ break;
+
+ /* Element declaration stuff */
+
+ case XML_ROLE_ELEMENT_NAME:
+ if (elementDeclHandler) {
+ declElementType = getElementType(parser, enc, s, next);
+ if (!declElementType)
+ return XML_ERROR_NO_MEMORY;
+ dtd->scaffLevel = 0;
+ dtd->scaffCount = 0;
+ dtd->in_eldecl = XML_TRUE;
+ handleDefault = XML_FALSE;
+ }
+ break;
+
+ case XML_ROLE_CONTENT_ANY:
+ case XML_ROLE_CONTENT_EMPTY:
+ if (dtd->in_eldecl) {
+ if (elementDeclHandler) {
+ XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content));
+ if (!content)
+ return XML_ERROR_NO_MEMORY;
+ content->quant = XML_CQUANT_NONE;
+ content->name = NULL;
+ content->numchildren = 0;
+ content->children = NULL;
+ content->type = ((role == XML_ROLE_CONTENT_ANY) ?
+ XML_CTYPE_ANY :
+ XML_CTYPE_EMPTY);
+ *eventEndPP = s;
+ elementDeclHandler(handlerArg, declElementType->name, content);
+ handleDefault = XML_FALSE;
+ }
+ dtd->in_eldecl = XML_FALSE;
+ }
+ break;
+
+ case XML_ROLE_CONTENT_PCDATA:
+ if (dtd->in_eldecl) {
+ dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+ = XML_CTYPE_MIXED;
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+
+ case XML_ROLE_CONTENT_ELEMENT:
+ quant = XML_CQUANT_NONE;
+ goto elementContent;
+ case XML_ROLE_CONTENT_ELEMENT_OPT:
+ quant = XML_CQUANT_OPT;
+ goto elementContent;
+ case XML_ROLE_CONTENT_ELEMENT_REP:
+ quant = XML_CQUANT_REP;
+ goto elementContent;
+ case XML_ROLE_CONTENT_ELEMENT_PLUS:
+ quant = XML_CQUANT_PLUS;
+ elementContent:
+ if (dtd->in_eldecl) {
+ ELEMENT_TYPE *el;
+ const XML_Char *name;
+ int nameLen;
+ const char *nxt = (quant == XML_CQUANT_NONE
+ ? next
+ : next - enc->minBytesPerChar);
+ int myindex = nextScaffoldPart(parser);
+ if (myindex < 0)
+ return XML_ERROR_NO_MEMORY;
+ dtd->scaffold[myindex].type = XML_CTYPE_NAME;
+ dtd->scaffold[myindex].quant = quant;
+ el = getElementType(parser, enc, s, nxt);
+ if (!el)
+ return XML_ERROR_NO_MEMORY;
+ name = el->name;
+ dtd->scaffold[myindex].name = name;
+ nameLen = 0;
+ for (; name[nameLen++]; );
+ dtd->contentStringLen += nameLen;
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+
+ case XML_ROLE_GROUP_CLOSE:
+ quant = XML_CQUANT_NONE;
+ goto closeGroup;
+ case XML_ROLE_GROUP_CLOSE_OPT:
+ quant = XML_CQUANT_OPT;
+ goto closeGroup;
+ case XML_ROLE_GROUP_CLOSE_REP:
+ quant = XML_CQUANT_REP;
+ goto closeGroup;
+ case XML_ROLE_GROUP_CLOSE_PLUS:
+ quant = XML_CQUANT_PLUS;
+ closeGroup:
+ if (dtd->in_eldecl) {
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ dtd->scaffLevel--;
+ dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant;
+ if (dtd->scaffLevel == 0) {
+ if (!handleDefault) {
+ XML_Content *model = build_model(parser);
+ if (!model)
+ return XML_ERROR_NO_MEMORY;
+ *eventEndPP = s;
+ elementDeclHandler(handlerArg, declElementType->name, model);
+ }
+ dtd->in_eldecl = XML_FALSE;
+ dtd->contentStringLen = 0;
+ }
+ }
+ break;
+ /* End element declaration stuff */
+
+ case XML_ROLE_PI:
+ if (!reportProcessingInstruction(parser, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_COMMENT:
+ if (!reportComment(parser, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_NONE:
+ switch (tok) {
+ case XML_TOK_BOM:
+ handleDefault = XML_FALSE;
+ break;
+ }
+ break;
+ case XML_ROLE_DOCTYPE_NONE:
+ if (startDoctypeDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_ENTITY_NONE:
+ if (dtd->keepProcessing && entityDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_NOTATION_NONE:
+ if (notationDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_ATTLIST_NONE:
+ if (dtd->keepProcessing && attlistDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_ELEMENT_NONE:
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ } /* end of big switch */
+
+ if (handleDefault && defaultHandler)
+ reportDefault(parser, enc, s, next);
+
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default:
+ s = next;
+ tok = XmlPrologTok(enc, s, end, &next);
+ }
+ }
+ /* not reached */
+}
+
+static enum XML_Error PTRCALL
+epilogProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ processor = epilogProcessor;
+ eventPtr = s;
+ for (;;) {
+ const char *next = NULL;
+ int tok = XmlPrologTok(encoding, s, end, &next);
+ eventEndPtr = next;
+ switch (tok) {
+ /* report partial linebreak - it might be the last token */
+ case -XML_TOK_PROLOG_S:
+ if (defaultHandler) {
+ reportDefault(parser, encoding, s, next);
+ if (ps_parsing == XML_FINISHED)
+ return XML_ERROR_ABORTED;
+ }
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_TOK_NONE:
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ case XML_TOK_PROLOG_S:
+ if (defaultHandler)
+ reportDefault(parser, encoding, s, next);
+ break;
+ case XML_TOK_PI:
+ if (!reportProcessingInstruction(parser, encoding, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_COMMENT:
+ if (!reportComment(parser, encoding, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_INVALID:
+ eventPtr = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ if (!ps_finalBuffer) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (!ps_finalBuffer) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ default:
+ return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
+ }
+ eventPtr = s = next;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default: ;
+ }
+ }
+}
+
+static enum XML_Error
+processInternalEntity(XML_Parser parser, ENTITY *entity,
+ XML_Bool betweenDecl)
+{
+ const char *textStart, *textEnd;
+ const char *next;
+ enum XML_Error result;
+ OPEN_INTERNAL_ENTITY *openEntity;
+
+ if (freeInternalEntities) {
+ openEntity = freeInternalEntities;
+ freeInternalEntities = openEntity->next;
+ }
+ else {
+ openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(sizeof(OPEN_INTERNAL_ENTITY));
+ if (!openEntity)
+ return XML_ERROR_NO_MEMORY;
+ }
+ entity->open = XML_TRUE;
+ entity->processed = 0;
+ openEntity->next = openInternalEntities;
+ openInternalEntities = openEntity;
+ openEntity->entity = entity;
+ openEntity->startTagLevel = tagLevel;
+ openEntity->betweenDecl = betweenDecl;
+ openEntity->internalEventPtr = NULL;
+ openEntity->internalEventEndPtr = NULL;
+ textStart = (char *)entity->textPtr;
+ textEnd = (char *)(entity->textPtr + entity->textLen);
+
+#ifdef XML_DTD
+ if (entity->is_param) {
+ int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
+ result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
+ next, &next, XML_FALSE);
+ }
+ else
+#endif /* XML_DTD */
+ result = doContent(parser, tagLevel, internalEncoding, textStart,
+ textEnd, &next, XML_FALSE);
+
+ if (result == XML_ERROR_NONE) {
+ if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+ entity->processed = (int)(next - textStart);
+ processor = internalEntityProcessor;
+ }
+ else {
+ entity->open = XML_FALSE;
+ openInternalEntities = openEntity->next;
+ /* put openEntity back in list of free instances */
+ openEntity->next = freeInternalEntities;
+ freeInternalEntities = openEntity;
+ }
+ }
+ return result;
+}
+
+static enum XML_Error PTRCALL
+internalEntityProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ ENTITY *entity;
+ const char *textStart, *textEnd;
+ const char *next;
+ enum XML_Error result;
+ OPEN_INTERNAL_ENTITY *openEntity = openInternalEntities;
+ if (!openEntity)
+ return XML_ERROR_UNEXPECTED_STATE;
+
+ entity = openEntity->entity;
+ textStart = ((char *)entity->textPtr) + entity->processed;
+ textEnd = (char *)(entity->textPtr + entity->textLen);
+
+#ifdef XML_DTD
+ if (entity->is_param) {
+ int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
+ result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
+ next, &next, XML_FALSE);
+ }
+ else
+#endif /* XML_DTD */
+ result = doContent(parser, openEntity->startTagLevel, internalEncoding,
+ textStart, textEnd, &next, XML_FALSE);
+
+ if (result != XML_ERROR_NONE)
+ return result;
+ else if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+ entity->processed = (int)(next - (char *)entity->textPtr);
+ return result;
+ }
+ else {
+ entity->open = XML_FALSE;
+ openInternalEntities = openEntity->next;
+ /* put openEntity back in list of free instances */
+ openEntity->next = freeInternalEntities;
+ freeInternalEntities = openEntity;
+ }
+
+#ifdef XML_DTD
+ if (entity->is_param) {
+ int tok;
+ processor = prologProcessor;
+ tok = XmlPrologTok(encoding, s, end, &next);
+ return doProlog(parser, encoding, s, end, tok, next, nextPtr,
+ (XML_Bool)!ps_finalBuffer);
+ }
+ else
+#endif /* XML_DTD */
+ {
+ processor = contentProcessor;
+ /* see externalEntityContentProcessor vs contentProcessor */
+ return doContent(parser, parentParser ? 1 : 0, encoding, s, end,
+ nextPtr, (XML_Bool)!ps_finalBuffer);
+ }
+}
+
+static enum XML_Error PTRCALL
+errorProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ return errorCode;
+}
+
+static enum XML_Error
+storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+ const char *ptr, const char *end,
+ STRING_POOL *pool)
+{
+ enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr,
+ end, pool);
+ if (result)
+ return result;
+ if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
+ poolChop(pool);
+ if (!poolAppendChar(pool, XML_T('\0')))
+ return XML_ERROR_NO_MEMORY;
+ return XML_ERROR_NONE;
+}
+
+static enum XML_Error
+appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+ const char *ptr, const char *end,
+ STRING_POOL *pool)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ for (;;) {
+ const char *next;
+ int tok = XmlAttributeValueTok(enc, ptr, end, &next);
+ switch (tok) {
+ case XML_TOK_NONE:
+ return XML_ERROR_NONE;
+ case XML_TOK_INVALID:
+ if (enc == encoding)
+ eventPtr = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_CHAR_REF:
+ {
+ XML_Char buf[XML_ENCODE_MAX];
+ int i;
+ int n = XmlCharRefNumber(enc, ptr);
+ if (n < 0) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_BAD_CHAR_REF;
+ }
+ if (!isCdata
+ && n == 0x20 /* space */
+ && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
+ break;
+ n = XmlEncode(n, (ICHAR *)buf);
+ if (!n) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_BAD_CHAR_REF;
+ }
+ for (i = 0; i < n; i++) {
+ if (!poolAppendChar(pool, buf[i]))
+ return XML_ERROR_NO_MEMORY;
+ }
+ }
+ break;
+ case XML_TOK_DATA_CHARS:
+ if (!poolAppend(pool, enc, ptr, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_TRAILING_CR:
+ next = ptr + enc->minBytesPerChar;
+ /* fall through */
+ case XML_TOK_ATTRIBUTE_VALUE_S:
+ case XML_TOK_DATA_NEWLINE:
+ if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
+ break;
+ if (!poolAppendChar(pool, 0x20))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_ENTITY_REF:
+ {
+ const XML_Char *name;
+ ENTITY *entity;
+ char checkEntityDecl;
+ XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
+ ptr + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (ch) {
+ if (!poolAppendChar(pool, ch))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ }
+ name = poolStoreString(&temp2Pool, enc,
+ ptr + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
+ poolDiscard(&temp2Pool);
+ /* First, determine if a check for an existing declaration is needed;
+ if yes, check that the entity exists, and that it is internal.
+ */
+ if (pool == &dtd->pool) /* are we called from prolog? */
+ checkEntityDecl =
+#ifdef XML_DTD
+ prologState.documentEntity &&
+#endif /* XML_DTD */
+ (dtd->standalone
+ ? !openInternalEntities
+ : !dtd->hasParamEntityRefs);
+ else /* if (pool == &tempPool): we are called from content */
+ checkEntityDecl = !dtd->hasParamEntityRefs || dtd->standalone;
+ if (checkEntityDecl) {
+ if (!entity)
+ return XML_ERROR_UNDEFINED_ENTITY;
+ else if (!entity->is_internal)
+ return XML_ERROR_ENTITY_DECLARED_IN_PE;
+ }
+ else if (!entity) {
+ /* Cannot report skipped entity here - see comments on
+ skippedEntityHandler.
+ if (skippedEntityHandler)
+ skippedEntityHandler(handlerArg, name, 0);
+ */
+ /* Cannot call the default handler because this would be
+ out of sync with the call to the startElementHandler.
+ if ((pool == &tempPool) && defaultHandler)
+ reportDefault(parser, enc, ptr, next);
+ */
+ break;
+ }
+ if (entity->open) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_RECURSIVE_ENTITY_REF;
+ }
+ if (entity->notation) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_BINARY_ENTITY_REF;
+ }
+ if (!entity->textPtr) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
+ }
+ else {
+ enum XML_Error result;
+ const XML_Char *textEnd = entity->textPtr + entity->textLen;
+ entity->open = XML_TRUE;
+ result = appendAttributeValue(parser, internalEncoding, isCdata,
+ (char *)entity->textPtr,
+ (char *)textEnd, pool);
+ entity->open = XML_FALSE;
+ if (result)
+ return result;
+ }
+ }
+ break;
+ default:
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_UNEXPECTED_STATE;
+ }
+ ptr = next;
+ }
+ /* not reached */
+}
+
+static enum XML_Error
+storeEntityValue(XML_Parser parser,
+ const ENCODING *enc,
+ const char *entityTextPtr,
+ const char *entityTextEnd)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ STRING_POOL *pool = &(dtd->entityValuePool);
+ enum XML_Error result = XML_ERROR_NONE;
+#ifdef XML_DTD
+ int oldInEntityValue = prologState.inEntityValue;
+ prologState.inEntityValue = 1;
+#endif /* XML_DTD */
+ /* never return Null for the value argument in EntityDeclHandler,
+ since this would indicate an external entity; therefore we
+ have to make sure that entityValuePool.start is not null */
+ if (!pool->blocks) {
+ if (!poolGrow(pool))
+ return XML_ERROR_NO_MEMORY;
+ }
+
+ for (;;) {
+ const char *next;
+ int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
+ switch (tok) {
+ case XML_TOK_PARAM_ENTITY_REF:
+#ifdef XML_DTD
+ if (isParamEntity || enc != encoding) {
+ const XML_Char *name;
+ ENTITY *entity;
+ name = poolStoreString(&tempPool, enc,
+ entityTextPtr + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!name) {
+ result = XML_ERROR_NO_MEMORY;
+ goto endEntityValue;
+ }
+ entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
+ poolDiscard(&tempPool);
+ if (!entity) {
+ /* not a well-formedness error - see XML 1.0: WFC Entity Declared */
+ /* cannot report skipped entity here - see comments on
+ skippedEntityHandler
+ if (skippedEntityHandler)
+ skippedEntityHandler(handlerArg, name, 0);
+ */
+ dtd->keepProcessing = dtd->standalone;
+ goto endEntityValue;
+ }
+ if (entity->open) {
+ if (enc == encoding)
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_RECURSIVE_ENTITY_REF;
+ goto endEntityValue;
+ }
+ if (entity->systemId) {
+ if (externalEntityRefHandler) {
+ dtd->paramEntityRead = XML_FALSE;
+ entity->open = XML_TRUE;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ 0,
+ entity->base,
+ entity->systemId,
+ entity->publicId)) {
+ entity->open = XML_FALSE;
+ result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ goto endEntityValue;
+ }
+ entity->open = XML_FALSE;
+ if (!dtd->paramEntityRead)
+ dtd->keepProcessing = dtd->standalone;
+ }
+ else
+ dtd->keepProcessing = dtd->standalone;
+ }
+ else {
+ entity->open = XML_TRUE;
+ result = storeEntityValue(parser,
+ internalEncoding,
+ (char *)entity->textPtr,
+ (char *)(entity->textPtr
+ + entity->textLen));
+ entity->open = XML_FALSE;
+ if (result)
+ goto endEntityValue;
+ }
+ break;
+ }
+#endif /* XML_DTD */
+ /* In the internal subset, PE references are not legal
+ within markup declarations, e.g entity values in this case. */
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_PARAM_ENTITY_REF;
+ goto endEntityValue;
+ case XML_TOK_NONE:
+ result = XML_ERROR_NONE;
+ goto endEntityValue;
+ case XML_TOK_ENTITY_REF:
+ case XML_TOK_DATA_CHARS:
+ if (!poolAppend(pool, enc, entityTextPtr, next)) {
+ result = XML_ERROR_NO_MEMORY;
+ goto endEntityValue;
+ }
+ break;
+ case XML_TOK_TRAILING_CR:
+ next = entityTextPtr + enc->minBytesPerChar;
+ /* fall through */
+ case XML_TOK_DATA_NEWLINE:
+ if (pool->end == pool->ptr && !poolGrow(pool)) {
+ result = XML_ERROR_NO_MEMORY;
+ goto endEntityValue;
+ }
+ *(pool->ptr)++ = 0xA;
+ break;
+ case XML_TOK_CHAR_REF:
+ {
+ XML_Char buf[XML_ENCODE_MAX];
+ int i;
+ int n = XmlCharRefNumber(enc, entityTextPtr);
+ if (n < 0) {
+ if (enc == encoding)
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_BAD_CHAR_REF;
+ goto endEntityValue;
+ }
+ n = XmlEncode(n, (ICHAR *)buf);
+ if (!n) {
+ if (enc == encoding)
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_BAD_CHAR_REF;
+ goto endEntityValue;
+ }
+ for (i = 0; i < n; i++) {
+ if (pool->end == pool->ptr && !poolGrow(pool)) {
+ result = XML_ERROR_NO_MEMORY;
+ goto endEntityValue;
+ }
+ *(pool->ptr)++ = buf[i];
+ }
+ }
+ break;
+ case XML_TOK_PARTIAL:
+ if (enc == encoding)
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_INVALID_TOKEN;
+ goto endEntityValue;
+ case XML_TOK_INVALID:
+ if (enc == encoding)
+ eventPtr = next;
+ result = XML_ERROR_INVALID_TOKEN;
+ goto endEntityValue;
+ default:
+ if (enc == encoding)
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_UNEXPECTED_STATE;
+ goto endEntityValue;
+ }
+ entityTextPtr = next;
+ }
+endEntityValue:
+#ifdef XML_DTD
+ prologState.inEntityValue = oldInEntityValue;
+#endif /* XML_DTD */
+ return result;
+}
+
+static void FASTCALL
+normalizeLines(XML_Char *s)
+{
+ XML_Char *p;
+ for (;; s++) {
+ if (*s == XML_T('\0'))
+ return;
+ if (*s == 0xD)
+ break;
+ }
+ p = s;
+ do {
+ if (*s == 0xD) {
+ *p++ = 0xA;
+ if (*++s == 0xA)
+ s++;
+ }
+ else
+ *p++ = *s++;
+ } while (*s);
+ *p = XML_T('\0');
+}
+
+static int
+reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end)
+{
+ const XML_Char *target;
+ XML_Char *data;
+ const char *tem;
+ if (!processingInstructionHandler) {
+ if (defaultHandler)
+ reportDefault(parser, enc, start, end);
+ return 1;
+ }
+ start += enc->minBytesPerChar * 2;
+ tem = start + XmlNameLength(enc, start);
+ target = poolStoreString(&tempPool, enc, start, tem);
+ if (!target)
+ return 0;
+ poolFinish(&tempPool);
+ data = poolStoreString(&tempPool, enc,
+ XmlSkipS(enc, tem),
+ end - enc->minBytesPerChar*2);
+ if (!data)
+ return 0;
+ normalizeLines(data);
+ processingInstructionHandler(handlerArg, target, data);
+ poolClear(&tempPool);
+ return 1;
+}
+
+static int
+reportComment(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end)
+{
+ XML_Char *data;
+ if (!commentHandler) {
+ if (defaultHandler)
+ reportDefault(parser, enc, start, end);
+ return 1;
+ }
+ data = poolStoreString(&tempPool,
+ enc,
+ start + enc->minBytesPerChar * 4,
+ end - enc->minBytesPerChar * 3);
+ if (!data)
+ return 0;
+ normalizeLines(data);
+ commentHandler(handlerArg, data);
+ poolClear(&tempPool);
+ return 1;
+}
+
+static void
+reportDefault(XML_Parser parser, const ENCODING *enc,
+ const char *s, const char *end)
+{
+ if (MUST_CONVERT(enc, s)) {
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+ do {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+ *eventEndPP = s;
+ defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf));
+ *eventPP = s;
+ } while (s != end);
+ }
+ else
+ defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s));
+}
+
+
+static int
+defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
+ XML_Bool isId, const XML_Char *value, XML_Parser parser)
+{
+ DEFAULT_ATTRIBUTE *att;
+ if (value || isId) {
+ /* The handling of default attributes gets messed up if we have
+ a default which duplicates a non-default. */
+ int i;
+ for (i = 0; i < type->nDefaultAtts; i++)
+ if (attId == type->defaultAtts[i].id)
+ return 1;
+ if (isId && !type->idAtt && !attId->xmlns)
+ type->idAtt = attId;
+ }
+ if (type->nDefaultAtts == type->allocDefaultAtts) {
+ if (type->allocDefaultAtts == 0) {
+ type->allocDefaultAtts = 8;
+ type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(type->allocDefaultAtts
+ * sizeof(DEFAULT_ATTRIBUTE));
+ if (!type->defaultAtts)
+ return 0;
+ }
+ else {
+ DEFAULT_ATTRIBUTE *temp;
+ int count = type->allocDefaultAtts * 2;
+ temp = (DEFAULT_ATTRIBUTE *)
+ REALLOC(type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE)));
+ if (temp == NULL)
+ return 0;
+ type->allocDefaultAtts = count;
+ type->defaultAtts = temp;
+ }
+ }
+ att = type->defaultAtts + type->nDefaultAtts;
+ att->id = attId;
+ att->value = value;
+ att->isCdata = isCdata;
+ if (!isCdata)
+ attId->maybeTokenized = XML_TRUE;
+ type->nDefaultAtts += 1;
+ return 1;
+}
+
+static int
+setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ const XML_Char *name;
+ for (name = elementType->name; *name; name++) {
+ if (*name == XML_T(ASCII_COLON)) {
+ PREFIX *prefix;
+ const XML_Char *s;
+ for (s = elementType->name; s != name; s++) {
+ if (!poolAppendChar(&dtd->pool, *s))
+ return 0;
+ }
+ if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+ return 0;
+ prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
+ sizeof(PREFIX));
+ if (!prefix)
+ return 0;
+ if (prefix->name == poolStart(&dtd->pool))
+ poolFinish(&dtd->pool);
+ else
+ poolDiscard(&dtd->pool);
+ elementType->prefix = prefix;
+
+ }
+ }
+ return 1;
+}
+
+static ATTRIBUTE_ID *
+getAttributeId(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ ATTRIBUTE_ID *id;
+ const XML_Char *name;
+ if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+ return NULL;
+ name = poolStoreString(&dtd->pool, enc, start, end);
+ if (!name)
+ return NULL;
+ /* skip quotation mark - its storage will be re-used (like in name[-1]) */
+ ++name;
+ id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID));
+ if (!id)
+ return NULL;
+ if (id->name != name)
+ poolDiscard(&dtd->pool);
+ else {
+ poolFinish(&dtd->pool);
+ if (!ns)
+ ;
+ else if (name[0] == XML_T(ASCII_x)
+ && name[1] == XML_T(ASCII_m)
+ && name[2] == XML_T(ASCII_l)
+ && name[3] == XML_T(ASCII_n)
+ && name[4] == XML_T(ASCII_s)
+ && (name[5] == XML_T('\0') || name[5] == XML_T(ASCII_COLON))) {
+ if (name[5] == XML_T('\0'))
+ id->prefix = &dtd->defaultPrefix;
+ else
+ id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX));
+ id->xmlns = XML_TRUE;
+ }
+ else {
+ int i;
+ for (i = 0; name[i]; i++) {
+ /* attributes without prefix are *not* in the default namespace */
+ if (name[i] == XML_T(ASCII_COLON)) {
+ int j;
+ for (j = 0; j < i; j++) {
+ if (!poolAppendChar(&dtd->pool, name[j]))
+ return NULL;
+ }
+ if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+ return NULL;
+ id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
+ sizeof(PREFIX));
+ if (id->prefix->name == poolStart(&dtd->pool))
+ poolFinish(&dtd->pool);
+ else
+ poolDiscard(&dtd->pool);
+ break;
+ }
+ }
+ }
+ }
+ return id;
+}
+
+#define CONTEXT_SEP XML_T(ASCII_FF)
+
+static const XML_Char *
+getContext(XML_Parser parser)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ HASH_TABLE_ITER iter;
+ XML_Bool needSep = XML_FALSE;
+
+ if (dtd->defaultPrefix.binding) {
+ int i;
+ int len;
+ if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
+ return NULL;
+ len = dtd->defaultPrefix.binding->uriLen;
+ if (namespaceSeparator)
+ len--;
+ for (i = 0; i < len; i++)
+ if (!poolAppendChar(&tempPool, dtd->defaultPrefix.binding->uri[i]))
+ return NULL;
+ needSep = XML_TRUE;
+ }
+
+ hashTableIterInit(&iter, &(dtd->prefixes));
+ for (;;) {
+ int i;
+ int len;
+ const XML_Char *s;
+ PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter);
+ if (!prefix)
+ break;
+ if (!prefix->binding)
+ continue;
+ if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+ return NULL;
+ for (s = prefix->name; *s; s++)
+ if (!poolAppendChar(&tempPool, *s))
+ return NULL;
+ if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
+ return NULL;
+ len = prefix->binding->uriLen;
+ if (namespaceSeparator)
+ len--;
+ for (i = 0; i < len; i++)
+ if (!poolAppendChar(&tempPool, prefix->binding->uri[i]))
+ return NULL;
+ needSep = XML_TRUE;
+ }
+
+
+ hashTableIterInit(&iter, &(dtd->generalEntities));
+ for (;;) {
+ const XML_Char *s;
+ ENTITY *e = (ENTITY *)hashTableIterNext(&iter);
+ if (!e)
+ break;
+ if (!e->open)
+ continue;
+ if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+ return NULL;
+ for (s = e->name; *s; s++)
+ if (!poolAppendChar(&tempPool, *s))
+ return 0;
+ needSep = XML_TRUE;
+ }
+
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return NULL;
+ return tempPool.start;
+}
+
+static XML_Bool
+setContext(XML_Parser parser, const XML_Char *context)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ const XML_Char *s = context;
+
+ while (*context != XML_T('\0')) {
+ if (*s == CONTEXT_SEP || *s == XML_T('\0')) {
+ ENTITY *e;
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_FALSE;
+ e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0);
+ if (e)
+ e->open = XML_TRUE;
+ if (*s != XML_T('\0'))
+ s++;
+ context = s;
+ poolDiscard(&tempPool);
+ }
+ else if (*s == XML_T(ASCII_EQUALS)) {
+ PREFIX *prefix;
+ if (poolLength(&tempPool) == 0)
+ prefix = &dtd->defaultPrefix;
+ else {
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_FALSE;
+ prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool),
+ sizeof(PREFIX));
+ if (!prefix)
+ return XML_FALSE;
+ if (prefix->name == poolStart(&tempPool)) {
+ prefix->name = poolCopyString(&dtd->pool, prefix->name);
+ if (!prefix->name)
+ return XML_FALSE;
+ }
+ poolDiscard(&tempPool);
+ }
+ for (context = s + 1;
+ *context != CONTEXT_SEP && *context != XML_T('\0');
+ context++)
+ if (!poolAppendChar(&tempPool, *context))
+ return XML_FALSE;
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_FALSE;
+ if (addBinding(parser, prefix, NULL, poolStart(&tempPool),
+ &inheritedBindings) != XML_ERROR_NONE)
+ return XML_FALSE;
+ poolDiscard(&tempPool);
+ if (*context != XML_T('\0'))
+ ++context;
+ s = context;
+ }
+ else {
+ if (!poolAppendChar(&tempPool, *s))
+ return XML_FALSE;
+ s++;
+ }
+ }
+ return XML_TRUE;
+}
+
+static void FASTCALL
+normalizePublicId(XML_Char *publicId)
+{
+ XML_Char *p = publicId;
+ XML_Char *s;
+ for (s = publicId; *s; s++) {
+ switch (*s) {
+ case 0x20:
+ case 0xD:
+ case 0xA:
+ if (p != publicId && p[-1] != 0x20)
+ *p++ = 0x20;
+ break;
+ default:
+ *p++ = *s;
+ }
+ }
+ if (p != publicId && p[-1] == 0x20)
+ --p;
+ *p = XML_T('\0');
+}
+
+static DTD *
+dtdCreate(const XML_Memory_Handling_Suite *ms)
+{
+ DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD));
+ if (p == NULL)
+ return p;
+ poolInit(&(p->pool), ms);
+ poolInit(&(p->entityValuePool), ms);
+ hashTableInit(&(p->generalEntities), ms);
+ hashTableInit(&(p->elementTypes), ms);
+ hashTableInit(&(p->attributeIds), ms);
+ hashTableInit(&(p->prefixes), ms);
+#ifdef XML_DTD
+ p->paramEntityRead = XML_FALSE;
+ hashTableInit(&(p->paramEntities), ms);
+#endif /* XML_DTD */
+ p->defaultPrefix.name = NULL;
+ p->defaultPrefix.binding = NULL;
+
+ p->in_eldecl = XML_FALSE;
+ p->scaffIndex = NULL;
+ p->scaffold = NULL;
+ p->scaffLevel = 0;
+ p->scaffSize = 0;
+ p->scaffCount = 0;
+ p->contentStringLen = 0;
+
+ p->keepProcessing = XML_TRUE;
+ p->hasParamEntityRefs = XML_FALSE;
+ p->standalone = XML_FALSE;
+ return p;
+}
+
+static void
+dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms)
+{
+ HASH_TABLE_ITER iter;
+ hashTableIterInit(&iter, &(p->elementTypes));
+ for (;;) {
+ ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+ if (!e)
+ break;
+ if (e->allocDefaultAtts != 0)
+ ms->free_fcn(e->defaultAtts);
+ }
+ hashTableClear(&(p->generalEntities));
+#ifdef XML_DTD
+ p->paramEntityRead = XML_FALSE;
+ hashTableClear(&(p->paramEntities));
+#endif /* XML_DTD */
+ hashTableClear(&(p->elementTypes));
+ hashTableClear(&(p->attributeIds));
+ hashTableClear(&(p->prefixes));
+ poolClear(&(p->pool));
+ poolClear(&(p->entityValuePool));
+ p->defaultPrefix.name = NULL;
+ p->defaultPrefix.binding = NULL;
+
+ p->in_eldecl = XML_FALSE;
+
+ ms->free_fcn(p->scaffIndex);
+ p->scaffIndex = NULL;
+ ms->free_fcn(p->scaffold);
+ p->scaffold = NULL;
+
+ p->scaffLevel = 0;
+ p->scaffSize = 0;
+ p->scaffCount = 0;
+ p->contentStringLen = 0;
+
+ p->keepProcessing = XML_TRUE;
+ p->hasParamEntityRefs = XML_FALSE;
+ p->standalone = XML_FALSE;
+}
+
+static void
+dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms)
+{
+ HASH_TABLE_ITER iter;
+ hashTableIterInit(&iter, &(p->elementTypes));
+ for (;;) {
+ ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+ if (!e)
+ break;
+ if (e->allocDefaultAtts != 0)
+ ms->free_fcn(e->defaultAtts);
+ }
+ hashTableDestroy(&(p->generalEntities));
+#ifdef XML_DTD
+ hashTableDestroy(&(p->paramEntities));
+#endif /* XML_DTD */
+ hashTableDestroy(&(p->elementTypes));
+ hashTableDestroy(&(p->attributeIds));
+ hashTableDestroy(&(p->prefixes));
+ poolDestroy(&(p->pool));
+ poolDestroy(&(p->entityValuePool));
+ if (isDocEntity) {
+ ms->free_fcn(p->scaffIndex);
+ ms->free_fcn(p->scaffold);
+ }
+ ms->free_fcn(p);
+}
+
+/* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise.
+ The new DTD has already been initialized.
+*/
+static int
+dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
+{
+ HASH_TABLE_ITER iter;
+
+ /* Copy the prefix table. */
+
+ hashTableIterInit(&iter, &(oldDtd->prefixes));
+ for (;;) {
+ const XML_Char *name;
+ const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter);
+ if (!oldP)
+ break;
+ name = poolCopyString(&(newDtd->pool), oldP->name);
+ if (!name)
+ return 0;
+ if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX)))
+ return 0;
+ }
+
+ hashTableIterInit(&iter, &(oldDtd->attributeIds));
+
+ /* Copy the attribute id table. */
+
+ for (;;) {
+ ATTRIBUTE_ID *newA;
+ const XML_Char *name;
+ const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter);
+
+ if (!oldA)
+ break;
+ /* Remember to allocate the scratch byte before the name. */
+ if (!poolAppendChar(&(newDtd->pool), XML_T('\0')))
+ return 0;
+ name = poolCopyString(&(newDtd->pool), oldA->name);
+ if (!name)
+ return 0;
+ ++name;
+ newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name,
+ sizeof(ATTRIBUTE_ID));
+ if (!newA)
+ return 0;
+ newA->maybeTokenized = oldA->maybeTokenized;
+ if (oldA->prefix) {
+ newA->xmlns = oldA->xmlns;
+ if (oldA->prefix == &oldDtd->defaultPrefix)
+ newA->prefix = &newDtd->defaultPrefix;
+ else
+ newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
+ oldA->prefix->name, 0);
+ }
+ }
+
+ /* Copy the element type table. */
+
+ hashTableIterInit(&iter, &(oldDtd->elementTypes));
+
+ for (;;) {
+ int i;
+ ELEMENT_TYPE *newE;
+ const XML_Char *name;
+ const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+ if (!oldE)
+ break;
+ name = poolCopyString(&(newDtd->pool), oldE->name);
+ if (!name)
+ return 0;
+ newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name,
+ sizeof(ELEMENT_TYPE));
+ if (!newE)
+ return 0;
+ if (oldE->nDefaultAtts) {
+ newE->defaultAtts = (DEFAULT_ATTRIBUTE *)
+ ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
+ if (!newE->defaultAtts) {
+ ms->free_fcn(newE);
+ return 0;
+ }
+ }
+ if (oldE->idAtt)
+ newE->idAtt = (ATTRIBUTE_ID *)
+ lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0);
+ newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
+ if (oldE->prefix)
+ newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
+ oldE->prefix->name, 0);
+ for (i = 0; i < newE->nDefaultAtts; i++) {
+ newE->defaultAtts[i].id = (ATTRIBUTE_ID *)
+ lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
+ newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
+ if (oldE->defaultAtts[i].value) {
+ newE->defaultAtts[i].value
+ = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value);
+ if (!newE->defaultAtts[i].value)
+ return 0;
+ }
+ else
+ newE->defaultAtts[i].value = NULL;
+ }
+ }
+
+ /* Copy the entity tables. */
+ if (!copyEntityTable(oldParser,
+ &(newDtd->generalEntities),
+ &(newDtd->pool),
+ &(oldDtd->generalEntities)))
+ return 0;
+
+#ifdef XML_DTD
+ if (!copyEntityTable(oldParser,
+ &(newDtd->paramEntities),
+ &(newDtd->pool),
+ &(oldDtd->paramEntities)))
+ return 0;
+ newDtd->paramEntityRead = oldDtd->paramEntityRead;
+#endif /* XML_DTD */
+
+ newDtd->keepProcessing = oldDtd->keepProcessing;
+ newDtd->hasParamEntityRefs = oldDtd->hasParamEntityRefs;
+ newDtd->standalone = oldDtd->standalone;
+
+ /* Don't want deep copying for scaffolding */
+ newDtd->in_eldecl = oldDtd->in_eldecl;
+ newDtd->scaffold = oldDtd->scaffold;
+ newDtd->contentStringLen = oldDtd->contentStringLen;
+ newDtd->scaffSize = oldDtd->scaffSize;
+ newDtd->scaffLevel = oldDtd->scaffLevel;
+ newDtd->scaffIndex = oldDtd->scaffIndex;
+
+ return 1;
+} /* End dtdCopy */
+
+static int
+copyEntityTable(XML_Parser oldParser,
+ HASH_TABLE *newTable,
+ STRING_POOL *newPool,
+ const HASH_TABLE *oldTable)
+{
+ HASH_TABLE_ITER iter;
+ const XML_Char *cachedOldBase = NULL;
+ const XML_Char *cachedNewBase = NULL;
+
+ hashTableIterInit(&iter, oldTable);
+
+ for (;;) {
+ ENTITY *newE;
+ const XML_Char *name;
+ const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter);
+ if (!oldE)
+ break;
+ name = poolCopyString(newPool, oldE->name);
+ if (!name)
+ return 0;
+ newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY));
+ if (!newE)
+ return 0;
+ if (oldE->systemId) {
+ const XML_Char *tem = poolCopyString(newPool, oldE->systemId);
+ if (!tem)
+ return 0;
+ newE->systemId = tem;
+ if (oldE->base) {
+ if (oldE->base == cachedOldBase)
+ newE->base = cachedNewBase;
+ else {
+ cachedOldBase = oldE->base;
+ tem = poolCopyString(newPool, cachedOldBase);
+ if (!tem)
+ return 0;
+ cachedNewBase = newE->base = tem;
+ }
+ }
+ if (oldE->publicId) {
+ tem = poolCopyString(newPool, oldE->publicId);
+ if (!tem)
+ return 0;
+ newE->publicId = tem;
+ }
+ }
+ else {
+ const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr,
+ oldE->textLen);
+ if (!tem)
+ return 0;
+ newE->textPtr = tem;
+ newE->textLen = oldE->textLen;
+ }
+ if (oldE->notation) {
+ const XML_Char *tem = poolCopyString(newPool, oldE->notation);
+ if (!tem)
+ return 0;
+ newE->notation = tem;
+ }
+ newE->is_param = oldE->is_param;
+ newE->is_internal = oldE->is_internal;
+ }
+ return 1;
+}
+
+#define INIT_POWER 6
+
+static XML_Bool FASTCALL
+keyeq(KEY s1, KEY s2)
+{
+ for (; *s1 == *s2; s1++, s2++)
+ if (*s1 == 0)
+ return XML_TRUE;
+ return XML_FALSE;
+}
+
+static unsigned long FASTCALL
+hash(XML_Parser parser, KEY s)
+{
+ unsigned long h = hash_secret_salt;
+ while (*s)
+ h = CHAR_HASH(h, *s++);
+ return h;
+}
+
+static NAMED *
+lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize)
+{
+ size_t i;
+ if (table->size == 0) {
+ size_t tsize;
+ if (!createSize)
+ return NULL;
+ table->power = INIT_POWER;
+ /* table->size is a power of 2 */
+ table->size = (size_t)1 << INIT_POWER;
+ tsize = table->size * sizeof(NAMED *);
+ table->v = (NAMED **)table->mem->malloc_fcn(tsize);
+ if (!table->v) {
+ table->size = 0;
+ return NULL;
+ }
+ memset(table->v, 0, tsize);
+ i = hash(parser, name) & ((unsigned long)table->size - 1);
+ }
+ else {
+ unsigned long h = hash(parser, name);
+ unsigned long mask = (unsigned long)table->size - 1;
+ unsigned char step = 0;
+ i = h & mask;
+ while (table->v[i]) {
+ if (keyeq(name, table->v[i]->name))
+ return table->v[i];
+ if (!step)
+ step = PROBE_STEP(h, mask, table->power);
+ i < step ? (i += table->size - step) : (i -= step);
+ }
+ if (!createSize)
+ return NULL;
+
+ /* check for overflow (table is half full) */
+ if (table->used >> (table->power - 1)) {
+ unsigned char newPower = table->power + 1;
+ size_t newSize = (size_t)1 << newPower;
+ unsigned long newMask = (unsigned long)newSize - 1;
+ size_t tsize = newSize * sizeof(NAMED *);
+ NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize);
+ if (!newV)
+ return NULL;
+ memset(newV, 0, tsize);
+ for (i = 0; i < table->size; i++)
+ if (table->v[i]) {
+ unsigned long newHash = hash(parser, table->v[i]->name);
+ size_t j = newHash & newMask;
+ step = 0;
+ while (newV[j]) {
+ if (!step)
+ step = PROBE_STEP(newHash, newMask, newPower);
+ j < step ? (j += newSize - step) : (j -= step);
+ }
+ newV[j] = table->v[i];
+ }
+ table->mem->free_fcn(table->v);
+ table->v = newV;
+ table->power = newPower;
+ table->size = newSize;
+ i = h & newMask;
+ step = 0;
+ while (table->v[i]) {
+ if (!step)
+ step = PROBE_STEP(h, newMask, newPower);
+ i < step ? (i += newSize - step) : (i -= step);
+ }
+ }
+ }
+ table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize);
+ if (!table->v[i])
+ return NULL;
+ memset(table->v[i], 0, createSize);
+ table->v[i]->name = name;
+ (table->used)++;
+ return table->v[i];
+}
+
+static void FASTCALL
+hashTableClear(HASH_TABLE *table)
+{
+ size_t i;
+ for (i = 0; i < table->size; i++) {
+ table->mem->free_fcn(table->v[i]);
+ table->v[i] = NULL;
+ }
+ table->used = 0;
+}
+
+static void FASTCALL
+hashTableDestroy(HASH_TABLE *table)
+{
+ size_t i;
+ for (i = 0; i < table->size; i++)
+ table->mem->free_fcn(table->v[i]);
+ table->mem->free_fcn(table->v);
+}
+
+static void FASTCALL
+hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms)
+{
+ p->power = 0;
+ p->size = 0;
+ p->used = 0;
+ p->v = NULL;
+ p->mem = ms;
+}
+
+static void FASTCALL
+hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table)
+{
+ iter->p = table->v;
+ iter->end = iter->p + table->size;
+}
+
+static NAMED * FASTCALL
+hashTableIterNext(HASH_TABLE_ITER *iter)
+{
+ while (iter->p != iter->end) {
+ NAMED *tem = *(iter->p)++;
+ if (tem)
+ return tem;
+ }
+ return NULL;
+}
+
+static void FASTCALL
+poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms)
+{
+ pool->blocks = NULL;
+ pool->freeBlocks = NULL;
+ pool->start = NULL;
+ pool->ptr = NULL;
+ pool->end = NULL;
+ pool->mem = ms;
+}
+
+static void FASTCALL
+poolClear(STRING_POOL *pool)
+{
+ if (!pool->freeBlocks)
+ pool->freeBlocks = pool->blocks;
+ else {
+ BLOCK *p = pool->blocks;
+ while (p) {
+ BLOCK *tem = p->next;
+ p->next = pool->freeBlocks;
+ pool->freeBlocks = p;
+ p = tem;
+ }
+ }
+ pool->blocks = NULL;
+ pool->start = NULL;
+ pool->ptr = NULL;
+ pool->end = NULL;
+}
+
+static void FASTCALL
+poolDestroy(STRING_POOL *pool)
+{
+ BLOCK *p = pool->blocks;
+ while (p) {
+ BLOCK *tem = p->next;
+ pool->mem->free_fcn(p);
+ p = tem;
+ }
+ p = pool->freeBlocks;
+ while (p) {
+ BLOCK *tem = p->next;
+ pool->mem->free_fcn(p);
+ p = tem;
+ }
+}
+
+static XML_Char *
+poolAppend(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end)
+{
+ if (!pool->ptr && !poolGrow(pool))
+ return NULL;
+ for (;;) {
+ XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
+ if (ptr == end)
+ break;
+ if (!poolGrow(pool))
+ return NULL;
+ }
+ return pool->start;
+}
+
+static const XML_Char * FASTCALL
+poolCopyString(STRING_POOL *pool, const XML_Char *s)
+{
+ do {
+ if (!poolAppendChar(pool, *s))
+ return NULL;
+ } while (*s++);
+ s = pool->start;
+ poolFinish(pool);
+ return s;
+}
+
+static const XML_Char *
+poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n)
+{
+ if (!pool->ptr && !poolGrow(pool))
+ return NULL;
+ for (; n > 0; --n, s++) {
+ if (!poolAppendChar(pool, *s))
+ return NULL;
+ }
+ s = pool->start;
+ poolFinish(pool);
+ return s;
+}
+
+static const XML_Char * FASTCALL
+poolAppendString(STRING_POOL *pool, const XML_Char *s)
+{
+ while (*s) {
+ if (!poolAppendChar(pool, *s))
+ return NULL;
+ s++;
+ }
+ return pool->start;
+}
+
+static XML_Char *
+poolStoreString(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end)
+{
+ if (!poolAppend(pool, enc, ptr, end))
+ return NULL;
+ if (pool->ptr == pool->end && !poolGrow(pool))
+ return NULL;
+ *(pool->ptr)++ = 0;
+ return pool->start;
+}
+
+static XML_Bool FASTCALL
+poolGrow(STRING_POOL *pool)
+{
+ if (pool->freeBlocks) {
+ if (pool->start == 0) {
+ pool->blocks = pool->freeBlocks;
+ pool->freeBlocks = pool->freeBlocks->next;
+ pool->blocks->next = NULL;
+ pool->start = pool->blocks->s;
+ pool->end = pool->start + pool->blocks->size;
+ pool->ptr = pool->start;
+ return XML_TRUE;
+ }
+ if (pool->end - pool->start < pool->freeBlocks->size) {
+ BLOCK *tem = pool->freeBlocks->next;
+ pool->freeBlocks->next = pool->blocks;
+ pool->blocks = pool->freeBlocks;
+ pool->freeBlocks = tem;
+ memcpy(pool->blocks->s, pool->start,
+ (pool->end - pool->start) * sizeof(XML_Char));
+ pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
+ pool->start = pool->blocks->s;
+ pool->end = pool->start + pool->blocks->size;
+ return XML_TRUE;
+ }
+ }
+ if (pool->blocks && pool->start == pool->blocks->s) {
+ int blockSize = (int)(pool->end - pool->start)*2;
+ BLOCK *temp = (BLOCK *)
+ pool->mem->realloc_fcn(pool->blocks,
+ (offsetof(BLOCK, s)
+ + blockSize * sizeof(XML_Char)));
+ if (temp == NULL)
+ return XML_FALSE;
+ pool->blocks = temp;
+ pool->blocks->size = blockSize;
+ pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
+ pool->start = pool->blocks->s;
+ pool->end = pool->start + blockSize;
+ }
+ else {
+ BLOCK *tem;
+ int blockSize = (int)(pool->end - pool->start);
+ if (blockSize < INIT_BLOCK_SIZE)
+ blockSize = INIT_BLOCK_SIZE;
+ else
+ blockSize *= 2;
+ tem = (BLOCK *)pool->mem->malloc_fcn(offsetof(BLOCK, s)
+ + blockSize * sizeof(XML_Char));
+ if (!tem)
+ return XML_FALSE;
+ tem->size = blockSize;
+ tem->next = pool->blocks;
+ pool->blocks = tem;
+ if (pool->ptr != pool->start)
+ memcpy(tem->s, pool->start,
+ (pool->ptr - pool->start) * sizeof(XML_Char));
+ pool->ptr = tem->s + (pool->ptr - pool->start);
+ pool->start = tem->s;
+ pool->end = tem->s + blockSize;
+ }
+ return XML_TRUE;
+}
+
+static int FASTCALL
+nextScaffoldPart(XML_Parser parser)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ CONTENT_SCAFFOLD * me;
+ int next;
+
+ if (!dtd->scaffIndex) {
+ dtd->scaffIndex = (int *)MALLOC(groupSize * sizeof(int));
+ if (!dtd->scaffIndex)
+ return -1;
+ dtd->scaffIndex[0] = 0;
+ }
+
+ if (dtd->scaffCount >= dtd->scaffSize) {
+ CONTENT_SCAFFOLD *temp;
+ if (dtd->scaffold) {
+ temp = (CONTENT_SCAFFOLD *)
+ REALLOC(dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
+ if (temp == NULL)
+ return -1;
+ dtd->scaffSize *= 2;
+ }
+ else {
+ temp = (CONTENT_SCAFFOLD *)MALLOC(INIT_SCAFFOLD_ELEMENTS
+ * sizeof(CONTENT_SCAFFOLD));
+ if (temp == NULL)
+ return -1;
+ dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS;
+ }
+ dtd->scaffold = temp;
+ }
+ next = dtd->scaffCount++;
+ me = &dtd->scaffold[next];
+ if (dtd->scaffLevel) {
+ CONTENT_SCAFFOLD *parent = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel-1]];
+ if (parent->lastchild) {
+ dtd->scaffold[parent->lastchild].nextsib = next;
+ }
+ if (!parent->childcnt)
+ parent->firstchild = next;
+ parent->lastchild = next;
+ parent->childcnt++;
+ }
+ me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0;
+ return next;
+}
+
+static void
+build_node(XML_Parser parser,
+ int src_node,
+ XML_Content *dest,
+ XML_Content **contpos,
+ XML_Char **strpos)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ dest->type = dtd->scaffold[src_node].type;
+ dest->quant = dtd->scaffold[src_node].quant;
+ if (dest->type == XML_CTYPE_NAME) {
+ const XML_Char *src;
+ dest->name = *strpos;
+ src = dtd->scaffold[src_node].name;
+ for (;;) {
+ *(*strpos)++ = *src;
+ if (!*src)
+ break;
+ src++;
+ }
+ dest->numchildren = 0;
+ dest->children = NULL;
+ }
+ else {
+ unsigned int i;
+ int cn;
+ dest->numchildren = dtd->scaffold[src_node].childcnt;
+ dest->children = *contpos;
+ *contpos += dest->numchildren;
+ for (i = 0, cn = dtd->scaffold[src_node].firstchild;
+ i < dest->numchildren;
+ i++, cn = dtd->scaffold[cn].nextsib) {
+ build_node(parser, cn, &(dest->children[i]), contpos, strpos);
+ }
+ dest->name = NULL;
+ }
+}
+
+static XML_Content *
+build_model (XML_Parser parser)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ XML_Content *ret;
+ XML_Content *cpos;
+ XML_Char * str;
+ int allocsize = (dtd->scaffCount * sizeof(XML_Content)
+ + (dtd->contentStringLen * sizeof(XML_Char)));
+
+ ret = (XML_Content *)MALLOC(allocsize);
+ if (!ret)
+ return NULL;
+
+ str = (XML_Char *) (&ret[dtd->scaffCount]);
+ cpos = &ret[1];
+
+ build_node(parser, 0, ret, &cpos, &str);
+ return ret;
+}
+
+static ELEMENT_TYPE *
+getElementType(XML_Parser parser,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end);
+ ELEMENT_TYPE *ret;
+
+ if (!name)
+ return NULL;
+ ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE));
+ if (!ret)
+ return NULL;
+ if (ret->name != name)
+ poolDiscard(&dtd->pool);
+ else {
+ poolFinish(&dtd->pool);
+ if (!setElementTypePrefix(parser, ret))
+ return NULL;
+ }
+ return ret;
+}
diff --git a/chromium/third_party/pdfium/pdfium.gyp b/chromium/third_party/pdfium/pdfium.gyp
index d8df460c07e..7f1d908b1c7 100644
--- a/chromium/third_party/pdfium/pdfium.gyp
+++ b/chromium/third_party/pdfium/pdfium.gyp
@@ -840,6 +840,7 @@
'sources': [
'core/src/fxcodec/codec/fx_codec_jpx_unittest.cpp',
'core/src/fxcrt/fx_basic_bstring_unittest.cpp',
+ 'core/src/fxcrt/fx_basic_memmgr_unittest.cpp',
'core/src/fxcrt/fx_basic_wstring_unittest.cpp',
'testing/fx_string_testhelpers.h',
'testing/fx_string_testhelpers.cpp',
diff --git a/chromium/third_party/skia/PRESUBMIT.py b/chromium/third_party/skia/PRESUBMIT.py
index 6d429dfa1c1..5599c316c36 100644
--- a/chromium/third_party/skia/PRESUBMIT.py
+++ b/chromium/third_party/skia/PRESUBMIT.py
@@ -343,6 +343,8 @@ def PostUploadHook(cl, change, output_api):
need to be gated on the master branch's tree.
* Adds 'NOTRY=true' for non master branch changes since trybots do not yet
work on them.
+ * Adds 'NOPRESUBMIT=true' for non master branch changes since those don't
+ run the presubmit checks.
"""
results = []
@@ -405,6 +407,12 @@ def PostUploadHook(cl, change, output_api):
output_api.PresubmitNotifyResult(
'Trybots do not yet work for non-master branches. '
'Automatically added \'NOTRY=true\' to the CL\'s description'))
+ if not re.search(
+ r'^NOPRESUBMIT=true$', new_description, re.M | re.I):
+ new_description += "\nNOPRESUBMIT=true"
+ results.append(
+ output_api.PresubmitNotifyResult(
+ 'Branch changes do not run the presubmit checks.'))
# Read and process the HASHTAGS file.
hashtags_fullpath = os.path.join(change._local_root, 'HASHTAGS')
diff --git a/chromium/third_party/skia/include/core/SkMatrix.h b/chromium/third_party/skia/include/core/SkMatrix.h
index 0252bc7101c..fa7a63a4e86 100644
--- a/chromium/third_party/skia/include/core/SkMatrix.h
+++ b/chromium/third_party/skia/include/core/SkMatrix.h
@@ -719,6 +719,12 @@ private:
SkScalar fMat[9];
mutable uint32_t fTypeMask;
+ /** Are all elements of the matrix finite?
+ */
+ bool isFinite() const;
+
+ static void ComputeInv(SkScalar dst[9], const SkScalar src[9], SkScalar invDet, bool isPersp);
+
void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) {
fMat[kMScaleX] = sx;
fMat[kMSkewX] = 0;
diff --git a/chromium/third_party/skia/include/core/SkPackBits.h b/chromium/third_party/skia/include/core/SkPackBits.h
index f0614a08434..1e32ee08755 100644
--- a/chromium/third_party/skia/include/core/SkPackBits.h
+++ b/chromium/third_party/skia/include/core/SkPackBits.h
@@ -14,11 +14,6 @@
class SkPackBits {
public:
- /** Given the number of 16bit values that will be passed to Pack16,
- returns the worst-case size needed for the dst[] buffer.
- */
- static size_t ComputeMaxSize16(int count);
-
/** Given the number of 8bit values that will be passed to Pack8,
returns the worst-case size needed for the dst[] buffer.
*/
@@ -26,54 +21,26 @@ public:
/** Write the src array into a packed format. The packing process may end
up writing more bytes than it read, so dst[] must be large enough.
- @param src Input array of 16bit values
- @param count Number of entries in src[]
- @param dst Buffer (allocated by caller) to write the packed data
- into
- @return the number of bytes written to dst[]
- */
- static size_t Pack16(const uint16_t src[], int count, uint8_t dst[]);
-
- /** Write the src array into a packed format. The packing process may end
- up writing more bytes than it read, so dst[] must be large enough.
@param src Input array of 8bit values
- @param count Number of entries in src[]
+ @param srcSize Number of entries in src[]
@param dst Buffer (allocated by caller) to write the packed data
into
+ @param dstSize Number of bytes in the output buffer.
@return the number of bytes written to dst[]
*/
- static size_t Pack8(const uint8_t src[], int count, uint8_t dst[]);
-
- /** Unpack the data in src[], and expand it into dst[]. The src[] data was
- written by a previous call to Pack16.
- @param src Input data to unpack, previously created by Pack16.
- @param srcSize Number of bytes of src to unpack
- @param dst Buffer (allocated by caller) to expand the src[] into.
- @return the number of dst elements (not bytes) written into dst.
- */
- static int Unpack16(const uint8_t src[], size_t srcSize, uint16_t dst[]);
+ static size_t Pack8(const uint8_t src[], size_t srcSize, uint8_t dst[],
+ size_t dstSize);
/** Unpack the data in src[], and expand it into dst[]. The src[] data was
written by a previous call to Pack8.
@param src Input data to unpack, previously created by Pack8.
@param srcSize Number of bytes of src to unpack
@param dst Buffer (allocated by caller) to expand the src[] into.
+ @param dstSize Number of bytes in the output buffer.
@return the number of bytes written into dst.
*/
- static int Unpack8(const uint8_t src[], size_t srcSize, uint8_t dst[]);
-
- /** Unpack the data from src[], skip the first dstSkip bytes, then write
- dstWrite bytes into dst[]. The src[] data was written by a previous
- call to Pack8. Return the number of bytes actually writtten into dst[]
- @param src Input data to unpack, previously created by Pack8.
- @param dst Buffer (allocated by caller) to expand the src[] into.
- @param dstSkip Number of bytes of unpacked src to skip before writing
- into dst
- @param dstWrite Number of bytes of unpacked src to write into dst (after
- skipping dstSkip bytes)
- */
- static void Unpack8(uint8_t dst[], size_t dstSkip, size_t dstWrite,
- const uint8_t src[]);
+ static int Unpack8(const uint8_t src[], size_t srcSize, uint8_t dst[],
+ size_t dstSize);
};
#endif
diff --git a/chromium/third_party/skia/include/core/SkPicture.h b/chromium/third_party/skia/include/core/SkPicture.h
index 9a2b65b5c50..f845e942887 100644
--- a/chromium/third_party/skia/include/core/SkPicture.h
+++ b/chromium/third_party/skia/include/core/SkPicture.h
@@ -242,13 +242,14 @@ private:
// V39: Added FilterLevel option to SkPictureImageFilter
// V40: Remove UniqueID serialization from SkImageFilter.
// V41: Added serialization of SkBitmapSource's filterQuality parameter
+ // V42: Added a bool to SkPictureShader serialization to indicate did-we-serialize-a-picture?
// Note: If the picture version needs to be increased then please follow the
// steps to generate new SKPs in (only accessible to Googlers): http://goo.gl/qATVcw
// Only SKPs within the min/current picture version range (inclusive) can be read.
- static const uint32_t MIN_PICTURE_VERSION = 35; // Produced by Chrome M39.
- static const uint32_t CURRENT_PICTURE_VERSION = 41;
+ static const uint32_t MIN_PICTURE_VERSION = 35; // Produced by Chrome M39.
+ static const uint32_t CURRENT_PICTURE_VERSION = 42;
static_assert(MIN_PICTURE_VERSION <= 41,
"Remove kFontFileName and related code from SkFontDescriptor.cpp.");
diff --git a/chromium/third_party/skia/src/core/SkData.cpp b/chromium/third_party/skia/src/core/SkData.cpp
index dfbd0038497..ad79ce05350 100644
--- a/chromium/third_party/skia/src/core/SkData.cpp
+++ b/chromium/third_party/skia/src/core/SkData.cpp
@@ -63,7 +63,14 @@ SkData* SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
if (0 == length) {
return SkData::NewEmpty();
}
- char* storage = (char*)sk_malloc_throw(sizeof(SkData) + length);
+
+ const size_t actualLength = length + sizeof(SkData);
+ if (actualLength < length) {
+ // we overflowed
+ sk_throw();
+ }
+
+ char* storage = (char*)sk_malloc_throw(actualLength);
SkData* data = new (storage) SkData(length);
if (srcOrNull) {
memcpy(data->writable_data(), srcOrNull, length);
diff --git a/chromium/third_party/skia/src/core/SkMatrix.cpp b/chromium/third_party/skia/src/core/SkMatrix.cpp
index 9c9c4375f9e..068902eaace 100644
--- a/chromium/third_party/skia/src/core/SkMatrix.cpp
+++ b/chromium/third_party/skia/src/core/SkMatrix.cpp
@@ -752,6 +752,16 @@ static double sk_inv_determinant(const float mat[9], int isPerspective) {
return 1.0 / det;
}
+bool SkMatrix::isFinite() const {
+ for (int i = 0; i < 9; ++i) {
+ if (!SkScalarIsFinite(fMat[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
void SkMatrix::SetAffineIdentity(SkScalar affine[6]) {
affine[kAScaleX] = 1;
affine[kASkewY] = 0;
@@ -776,6 +786,37 @@ bool SkMatrix::asAffine(SkScalar affine[6]) const {
return true;
}
+void SkMatrix::ComputeInv(SkScalar dst[9], const SkScalar src[9], SkScalar invDet, bool isPersp) {
+ SkASSERT(src != dst);
+ SkASSERT(src && dst);
+
+ if (isPersp) {
+ dst[kMScaleX] = scross_dscale(src[kMScaleY], src[kMPersp2], src[kMTransY], src[kMPersp1], invDet);
+ dst[kMSkewX] = scross_dscale(src[kMTransX], src[kMPersp1], src[kMSkewX], src[kMPersp2], invDet);
+ dst[kMTransX] = scross_dscale(src[kMSkewX], src[kMTransY], src[kMTransX], src[kMScaleY], invDet);
+
+ dst[kMSkewY] = scross_dscale(src[kMTransY], src[kMPersp0], src[kMSkewY], src[kMPersp2], invDet);
+ dst[kMScaleY] = scross_dscale(src[kMScaleX], src[kMPersp2], src[kMTransX], src[kMPersp0], invDet);
+ dst[kMTransY] = scross_dscale(src[kMTransX], src[kMSkewY], src[kMScaleX], src[kMTransY], invDet);
+
+ dst[kMPersp0] = scross_dscale(src[kMSkewY], src[kMPersp1], src[kMScaleY], src[kMPersp0], invDet);
+ dst[kMPersp1] = scross_dscale(src[kMSkewX], src[kMPersp0], src[kMScaleX], src[kMPersp1], invDet);
+ dst[kMPersp2] = scross_dscale(src[kMScaleX], src[kMScaleY], src[kMSkewX], src[kMSkewY], invDet);
+ } else { // not perspective
+ dst[kMScaleX] = SkDoubleToScalar(src[kMScaleY] * invDet);
+ dst[kMSkewX] = SkDoubleToScalar(-src[kMSkewX] * invDet);
+ dst[kMTransX] = dcross_dscale(src[kMSkewX], src[kMTransY], src[kMScaleY], src[kMTransX], invDet);
+
+ dst[kMSkewY] = SkDoubleToScalar(-src[kMSkewY] * invDet);
+ dst[kMScaleY] = SkDoubleToScalar(src[kMScaleX] * invDet);
+ dst[kMTransY] = dcross_dscale(src[kMSkewY], src[kMTransX], src[kMScaleX], src[kMTransY], invDet);
+
+ dst[kMPersp0] = 0;
+ dst[kMPersp1] = 0;
+ dst[kMPersp2] = 1;
+ }
+}
+
bool SkMatrix::invertNonIdentity(SkMatrix* inv) const {
SkASSERT(!this->isIdentity());
@@ -819,50 +860,32 @@ bool SkMatrix::invertNonIdentity(SkMatrix* inv) const {
}
int isPersp = mask & kPerspective_Mask;
- double scale = sk_inv_determinant(fMat, isPersp);
+ double invDet = sk_inv_determinant(fMat, isPersp);
- if (scale == 0) { // underflow
+ if (invDet == 0) { // underflow
return false;
}
- if (inv) {
- SkMatrix tmp;
- if (inv == this) {
- inv = &tmp;
- }
+ bool applyingInPlace = (inv == this);
- if (isPersp) {
- inv->fMat[kMScaleX] = scross_dscale(fMat[kMScaleY], fMat[kMPersp2], fMat[kMTransY], fMat[kMPersp1], scale);
- inv->fMat[kMSkewX] = scross_dscale(fMat[kMTransX], fMat[kMPersp1], fMat[kMSkewX], fMat[kMPersp2], scale);
- inv->fMat[kMTransX] = scross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMTransX], fMat[kMScaleY], scale);
-
- inv->fMat[kMSkewY] = scross_dscale(fMat[kMTransY], fMat[kMPersp0], fMat[kMSkewY], fMat[kMPersp2], scale);
- inv->fMat[kMScaleY] = scross_dscale(fMat[kMScaleX], fMat[kMPersp2], fMat[kMTransX], fMat[kMPersp0], scale);
- inv->fMat[kMTransY] = scross_dscale(fMat[kMTransX], fMat[kMSkewY], fMat[kMScaleX], fMat[kMTransY], scale);
-
- inv->fMat[kMPersp0] = scross_dscale(fMat[kMSkewY], fMat[kMPersp1], fMat[kMScaleY], fMat[kMPersp0], scale);
- inv->fMat[kMPersp1] = scross_dscale(fMat[kMSkewX], fMat[kMPersp0], fMat[kMScaleX], fMat[kMPersp1], scale);
- inv->fMat[kMPersp2] = scross_dscale(fMat[kMScaleX], fMat[kMScaleY], fMat[kMSkewX], fMat[kMSkewY], scale);
- } else { // not perspective
- inv->fMat[kMScaleX] = SkDoubleToScalar(fMat[kMScaleY] * scale);
- inv->fMat[kMSkewX] = SkDoubleToScalar(-fMat[kMSkewX] * scale);
- inv->fMat[kMTransX] = dcross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMScaleY], fMat[kMTransX], scale);
-
- inv->fMat[kMSkewY] = SkDoubleToScalar(-fMat[kMSkewY] * scale);
- inv->fMat[kMScaleY] = SkDoubleToScalar(fMat[kMScaleX] * scale);
- inv->fMat[kMTransY] = dcross_dscale(fMat[kMSkewY], fMat[kMTransX], fMat[kMScaleX], fMat[kMTransY], scale);
-
- inv->fMat[kMPersp0] = 0;
- inv->fMat[kMPersp1] = 0;
- inv->fMat[kMPersp2] = 1;
- }
+ SkMatrix* tmp = inv;
+
+ SkMatrix storage;
+ if (applyingInPlace || NULL == tmp) {
+ tmp = &storage; // we either need to avoid trampling memory or have no memory
+ }
+
+ ComputeInv(tmp->fMat, fMat, invDet, isPersp);
+ if (!tmp->isFinite()) {
+ return false;
+ }
- inv->setTypeMask(fTypeMask);
+ tmp->setTypeMask(fTypeMask);
- if (inv == &tmp) {
- *(SkMatrix*)this = tmp;
- }
+ if (applyingInPlace) {
+ *inv = storage; // need to copy answer back
}
+
return true;
}
diff --git a/chromium/third_party/skia/src/core/SkPackBits.cpp b/chromium/third_party/skia/src/core/SkPackBits.cpp
index 3c6197b6f27..a3424e2bdcb 100644
--- a/chromium/third_party/skia/src/core/SkPackBits.cpp
+++ b/chromium/third_party/skia/src/core/SkPackBits.cpp
@@ -1,4 +1,3 @@
-
/*
* Copyright 2011 Google Inc.
*
@@ -7,182 +6,27 @@
*/
#include "SkPackBits.h"
-#define GATHER_STATSx
-
-static inline void small_memcpy(void* SK_RESTRICT dst,
- const void* SK_RESTRICT src, size_t n) {
- SkASSERT(n > 0 && n <= 15);
- uint8_t* d = (uint8_t*)dst;
- const uint8_t* s = (const uint8_t*)src;
- switch (n) {
- case 15: *d++ = *s++;
- case 14: *d++ = *s++;
- case 13: *d++ = *s++;
- case 12: *d++ = *s++;
- case 11: *d++ = *s++;
- case 10: *d++ = *s++;
- case 9: *d++ = *s++;
- case 8: *d++ = *s++;
- case 7: *d++ = *s++;
- case 6: *d++ = *s++;
- case 5: *d++ = *s++;
- case 4: *d++ = *s++;
- case 3: *d++ = *s++;
- case 2: *d++ = *s++;
- case 1: *d++ = *s++;
- case 0: break;
- }
-}
-
-static inline void small_memset(void* dst, uint8_t value, size_t n) {
- SkASSERT(n > 0 && n <= 15);
- uint8_t* d = (uint8_t*)dst;
- switch (n) {
- case 15: *d++ = value;
- case 14: *d++ = value;
- case 13: *d++ = value;
- case 12: *d++ = value;
- case 11: *d++ = value;
- case 10: *d++ = value;
- case 9: *d++ = value;
- case 8: *d++ = value;
- case 7: *d++ = value;
- case 6: *d++ = value;
- case 5: *d++ = value;
- case 4: *d++ = value;
- case 3: *d++ = value;
- case 2: *d++ = value;
- case 1: *d++ = value;
- case 0: break;
- }
-}
-
-// can we do better for small counts with our own inlined memcpy/memset?
-
-#define PB_MEMSET(addr, value, count) \
-do { \
-if ((count) > 15) { \
-memset(addr, value, count); \
-} else { \
-small_memset(addr, value, count); \
-} \
-} while (0)
-
-#define PB_MEMCPY(dst, src, count) \
-do { \
- if ((count) > 15) { \
- memcpy(dst, src, count); \
- } else { \
- small_memcpy(dst, src, count); \
- } \
-} while (0)
-
-///////////////////////////////////////////////////////////////////////////////
-
-#ifdef GATHER_STATS
- static int gMemSetBuckets[129];
- static int gMemCpyBuckets[129];
- static int gCounter;
-
-static void register_memset_count(int n) {
- SkASSERT((unsigned)n <= 128);
- gMemSetBuckets[n] += 1;
- gCounter += 1;
-
- if ((gCounter & 0xFF) == 0) {
- SkDebugf("----- packbits memset stats: ");
- for (size_t i = 0; i < SK_ARRAY_COUNT(gMemSetBuckets); i++) {
- if (gMemSetBuckets[i]) {
- SkDebugf(" %d:%d", i, gMemSetBuckets[i]);
- }
- }
- }
-}
-static void register_memcpy_count(int n) {
- SkASSERT((unsigned)n <= 128);
- gMemCpyBuckets[n] += 1;
- gCounter += 1;
-
- if ((gCounter & 0x1FF) == 0) {
- SkDebugf("----- packbits memcpy stats: ");
- for (size_t i = 0; i < SK_ARRAY_COUNT(gMemCpyBuckets); i++) {
- if (gMemCpyBuckets[i]) {
- SkDebugf(" %d:%d", i, gMemCpyBuckets[i]);
- }
- }
- }
-}
-#else
-#define register_memset_count(n)
-#define register_memcpy_count(n)
-#endif
-
-
-///////////////////////////////////////////////////////////////////////////////
-
-size_t SkPackBits::ComputeMaxSize16(int count) {
- // worst case is the number of 16bit values (times 2) +
- // 1 byte per (up to) 128 entries.
- return ((count + 127) >> 7) + (count << 1);
-}
-
size_t SkPackBits::ComputeMaxSize8(int count) {
// worst case is the number of 8bit values + 1 byte per (up to) 128 entries.
return ((count + 127) >> 7) + count;
}
-static uint8_t* flush_same16(uint8_t dst[], uint16_t value, int count) {
+static uint8_t* flush_same8(uint8_t dst[], uint8_t value, size_t count) {
while (count > 0) {
- int n = count;
- if (n > 128) {
- n = 128;
- }
+ int n = count > 128 ? 128 : count;
*dst++ = (uint8_t)(n - 1);
- *dst++ = (uint8_t)(value >> 8);
*dst++ = (uint8_t)value;
count -= n;
}
return dst;
}
-static uint8_t* flush_same8(uint8_t dst[], uint8_t value, int count) {
- while (count > 0) {
- int n = count;
- if (n > 128) {
- n = 128;
- }
- *dst++ = (uint8_t)(n - 1);
- *dst++ = (uint8_t)value;
- count -= n;
- }
- return dst;
-}
-
-static uint8_t* flush_diff16(uint8_t* SK_RESTRICT dst,
- const uint16_t* SK_RESTRICT src, int count) {
- while (count > 0) {
- int n = count;
- if (n > 128) {
- n = 128;
- }
- *dst++ = (uint8_t)(n + 127);
- PB_MEMCPY(dst, src, n * sizeof(uint16_t));
- src += n;
- dst += n * sizeof(uint16_t);
- count -= n;
- }
- return dst;
-}
-
static uint8_t* flush_diff8(uint8_t* SK_RESTRICT dst,
- const uint8_t* SK_RESTRICT src, int count) {
+ const uint8_t* SK_RESTRICT src, size_t count) {
while (count > 0) {
- int n = count;
- if (n > 128) {
- n = 128;
- }
+ int n = count > 128 ? 128 : count;
*dst++ = (uint8_t)(n + 127);
- PB_MEMCPY(dst, src, n);
+ memcpy(dst, src, n);
src += n;
dst += n;
count -= n;
@@ -190,64 +34,20 @@ static uint8_t* flush_diff8(uint8_t* SK_RESTRICT dst,
return dst;
}
-size_t SkPackBits::Pack16(const uint16_t* SK_RESTRICT src, int count,
- uint8_t* SK_RESTRICT dst) {
- uint8_t* origDst = dst;
- const uint16_t* stop = src + count;
-
- for (;;) {
- count = SkToInt(stop - src);
- SkASSERT(count >= 0);
- if (count == 0) {
- return dst - origDst;
- }
- if (1 == count) {
- *dst++ = 0;
- *dst++ = (uint8_t)(*src >> 8);
- *dst++ = (uint8_t)*src;
- return dst - origDst;
- }
-
- unsigned value = *src;
- const uint16_t* s = src + 1;
-
- if (*s == value) { // accumulate same values...
- do {
- s++;
- if (s == stop) {
- break;
- }
- } while (*s == value);
- dst = flush_same16(dst, value, SkToInt(s - src));
- } else { // accumulate diff values...
- do {
- if (++s == stop) {
- goto FLUSH_DIFF;
- }
- } while (*s != s[-1]);
- s -= 1; // back up so we don't grab one of the "same" values that follow
- FLUSH_DIFF:
- dst = flush_diff16(dst, src, SkToInt(s - src));
- }
- src = s;
+size_t SkPackBits::Pack8(const uint8_t* SK_RESTRICT src, size_t srcSize,
+ uint8_t* SK_RESTRICT dst, size_t dstSize) {
+ if (dstSize < ComputeMaxSize8(srcSize)) {
+ return 0;
}
-}
-size_t SkPackBits::Pack8(const uint8_t* SK_RESTRICT src, int count,
- uint8_t* SK_RESTRICT dst) {
- uint8_t* origDst = dst;
- const uint8_t* stop = src + count;
+ uint8_t* const origDst = dst;
+ const uint8_t* stop = src + srcSize;
- for (;;) {
- count = SkToInt(stop - src);
- SkASSERT(count >= 0);
- if (count == 0) {
- return dst - origDst;
- }
+ for (intptr_t count = stop - src; count > 0; count = stop - src) {
if (1 == count) {
*dst++ = 0;
*dst++ = *src;
- return dst - origDst;
+ break;
}
unsigned value = *src;
@@ -275,137 +75,35 @@ size_t SkPackBits::Pack8(const uint8_t* SK_RESTRICT src, int count,
}
src = s;
}
+ return dst - origDst;
}
#include "SkUtils.h"
-int SkPackBits::Unpack16(const uint8_t* SK_RESTRICT src, size_t srcSize,
- uint16_t* SK_RESTRICT dst) {
- uint16_t* origDst = dst;
- const uint8_t* stop = src + srcSize;
-
- while (src < stop) {
- unsigned n = *src++;
- if (n <= 127) { // repeat count (n + 1)
- n += 1;
- sk_memset16(dst, (src[0] << 8) | src[1], n);
- src += 2;
- } else { // same count (n - 127)
- n -= 127;
- PB_MEMCPY(dst, src, n * sizeof(uint16_t));
- src += n * sizeof(uint16_t);
- }
- dst += n;
- }
- SkASSERT(src == stop);
- return SkToInt(dst - origDst);
-}
-
int SkPackBits::Unpack8(const uint8_t* SK_RESTRICT src, size_t srcSize,
- uint8_t* SK_RESTRICT dst) {
- uint8_t* origDst = dst;
+ uint8_t* SK_RESTRICT dst, size_t dstSize) {
+ uint8_t* const origDst = dst;
+ uint8_t* const endDst = dst + dstSize;
const uint8_t* stop = src + srcSize;
while (src < stop) {
unsigned n = *src++;
if (n <= 127) { // repeat count (n + 1)
n += 1;
- PB_MEMSET(dst, *src++, n);
- } else { // same count (n - 127)
- n -= 127;
- PB_MEMCPY(dst, src, n);
- src += n;
- }
- dst += n;
- }
- SkASSERT(src == stop);
- return SkToInt(dst - origDst);
-}
-
-enum UnpackState {
- CLEAN_STATE,
- REPEAT_BYTE_STATE,
- COPY_SRC_STATE
-};
-
-void SkPackBits::Unpack8(uint8_t* SK_RESTRICT dst, size_t dstSkip,
- size_t dstWrite, const uint8_t* SK_RESTRICT src) {
- if (dstWrite == 0) {
- return;
- }
-
- UnpackState state = CLEAN_STATE;
- size_t stateCount = 0;
-
- // state 1: do the skip-loop
- while (dstSkip > 0) {
- size_t n = *src++;
- if (n <= 127) { // repeat count (n + 1)
- n += 1;
- if (n > dstSkip) {
- state = REPEAT_BYTE_STATE;
- stateCount = n - dstSkip;
- n = dstSkip;
- // we don't increment src here, since its needed in stage 2
- } else {
- src++; // skip the src byte
- }
- } else { // same count (n - 127)
- n -= 127;
- if (n > dstSkip) {
- state = COPY_SRC_STATE;
- stateCount = n - dstSkip;
- n = dstSkip;
- }
- src += n;
- }
- dstSkip -= n;
- }
-
- // stage 2: perform any catchup from the skip-stage
- if (stateCount > dstWrite) {
- stateCount = dstWrite;
- }
- switch (state) {
- case REPEAT_BYTE_STATE:
- SkASSERT(stateCount > 0);
- register_memset_count(stateCount);
- PB_MEMSET(dst, *src++, stateCount);
- break;
- case COPY_SRC_STATE:
- SkASSERT(stateCount > 0);
- register_memcpy_count(stateCount);
- PB_MEMCPY(dst, src, stateCount);
- src += stateCount;
- break;
- default:
- SkASSERT(stateCount == 0);
- break;
- }
- dst += stateCount;
- dstWrite -= stateCount;
-
- // copy at most dstWrite bytes into dst[]
- while (dstWrite > 0) {
- size_t n = *src++;
- if (n <= 127) { // repeat count (n + 1)
- n += 1;
- if (n > dstWrite) {
- n = dstWrite;
+ if (dst >(endDst - n)) {
+ return 0;
}
- register_memset_count(n);
- PB_MEMSET(dst, *src++, n);
+ memset(dst, *src++, n);
} else { // same count (n - 127)
n -= 127;
- if (n > dstWrite) {
- n = dstWrite;
+ if (dst > (endDst - n)) {
+ return 0;
}
- register_memcpy_count(n);
- PB_MEMCPY(dst, src, n);
+ memcpy(dst, src, n);
src += n;
}
dst += n;
- dstWrite -= n;
}
- SkASSERT(0 == dstWrite);
+ SkASSERT(src <= stop);
+ return SkToInt(dst - origDst);
}
diff --git a/chromium/third_party/skia/src/core/SkPictureShader.cpp b/chromium/third_party/skia/src/core/SkPictureShader.cpp
index c1c47550586..7efef21e70c 100644
--- a/chromium/third_party/skia/src/core/SkPictureShader.cpp
+++ b/chromium/third_party/skia/src/core/SkPictureShader.cpp
@@ -122,6 +122,8 @@ SkPictureShader* SkPictureShader::Create(const SkPicture* picture, TileMode tmx,
return SkNEW_ARGS(SkPictureShader, (picture, tmx, tmy, localMatrix, tile));
}
+// TODO: rename SK_DISALLOW_CROSSPROCESS_PICTUREIMAGEFILTERS to SK_DISALLOW_CROSSPROCESS_PICTURES
+
SkFlattenable* SkPictureShader::CreateProc(SkReadBuffer& buffer) {
SkMatrix lm;
buffer.readMatrix(&lm);
@@ -129,7 +131,27 @@ SkFlattenable* SkPictureShader::CreateProc(SkReadBuffer& buffer) {
TileMode my = (TileMode)buffer.read32();
SkRect tile;
buffer.readRect(&tile);
- SkAutoTUnref<SkPicture> picture(SkPicture::CreateFromBuffer(buffer));
+
+ SkAutoTUnref<SkPicture> picture;
+#ifdef SK_DISALLOW_CROSSPROCESS_PICTUREIMAGEFILTERS
+ if (buffer.isCrossProcess()) {
+ if (buffer.isVersionLT(SkReadBuffer::kPictureShaderHasPictureBool_Version)) {
+ // Older code blindly serialized pictures. We don't trust them.
+ buffer.validate(false);
+ return NULL;
+ }
+ // Newer code won't serialize pictures in disallow-cross-process-picture mode.
+ // Assert that they didn't serialize anything except a false here.
+ buffer.validate(!buffer.readBool());
+ } else
+#endif
+ {
+ // Old code always serialized the picture. New code writes a 'true' first if it did.
+ if (buffer.isVersionLT(SkReadBuffer::kPictureShaderHasPictureBool_Version) ||
+ buffer.readBool()) {
+ picture.reset(SkPicture::CreateFromBuffer(buffer));
+ }
+ }
return SkPictureShader::Create(picture, mx, my, &lm, &tile);
}
@@ -138,7 +160,18 @@ void SkPictureShader::flatten(SkWriteBuffer& buffer) const {
buffer.write32(fTmx);
buffer.write32(fTmy);
buffer.writeRect(fTile);
- fPicture->flatten(buffer);
+
+#ifdef SK_DISALLOW_CROSSPROCESS_PICTUREIMAGEFILTERS
+ // The deserialization code won't trust that our serialized picture is safe to deserialize.
+ // So write a 'false' telling it that we're not serializing a picture.
+ if (buffer.isCrossProcess()) {
+ buffer.writeBool(false);
+ } else
+#endif
+ {
+ buffer.writeBool(true);
+ fPicture->flatten(buffer);
+ }
}
SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix, const SkMatrix* localM,
diff --git a/chromium/third_party/skia/src/core/SkReadBuffer.h b/chromium/third_party/skia/src/core/SkReadBuffer.h
index 1299edaf82b..ba47835daf8 100644
--- a/chromium/third_party/skia/src/core/SkReadBuffer.h
+++ b/chromium/third_party/skia/src/core/SkReadBuffer.h
@@ -56,7 +56,8 @@ public:
kPictureImageFilterResolution_Version = 38,
kPictureImageFilterLevel_Version = 39,
kImageFilterNoUniqueID_Version = 40,
- kBitmapSourceFilterQuality_Version = 41
+ kBitmapSourceFilterQuality_Version = 41,
+ kPictureShaderHasPictureBool_Version = 42,
};
/**
diff --git a/chromium/third_party/skia/src/effects/SkTableColorFilter.cpp b/chromium/third_party/skia/src/effects/SkTableColorFilter.cpp
index 7298960a086..8e54a014779 100644
--- a/chromium/third_party/skia/src/effects/SkTableColorFilter.cpp
+++ b/chromium/third_party/skia/src/effects/SkTableColorFilter.cpp
@@ -201,8 +201,8 @@ static const uint8_t gCountNibBits[] = {
void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const {
uint8_t storage[5*256];
int count = gCountNibBits[fFlags & 0xF];
- size_t size = SkPackBits::Pack8(fStorage, count * 256, storage);
- SkASSERT(size <= sizeof(storage));
+ size_t size = SkPackBits::Pack8(fStorage, count * 256, storage,
+ sizeof(storage));
buffer.write32(fFlags);
buffer.writeByteArray(storage, size);
@@ -223,7 +223,8 @@ SkFlattenable* SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) {
}
uint8_t unpackedStorage[4*256];
- size_t unpackedSize = SkPackBits::Unpack8(packedStorage, packedSize, unpackedStorage);
+ size_t unpackedSize = SkPackBits::Unpack8(packedStorage, packedSize,
+ unpackedStorage, sizeof(unpackedStorage));
// now check that we got the size we expected
if (!buffer.validate(unpackedSize == count*256)) {
return NULL;
diff --git a/chromium/third_party/undoview/LICENSE b/chromium/third_party/undoview/LICENSE
deleted file mode 100644
index 4362b49151d..00000000000
--- a/chromium/third_party/undoview/LICENSE
+++ /dev/null
@@ -1,502 +0,0 @@
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the Lesser GPL. It also counts
- as the successor of the GNU Library Public License, version 2, hence
- the version number 2.1.]
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
- This license, the Lesser General Public License, applies to some
-specially designated software packages--typically libraries--of the
-Free Software Foundation and other authors who decide to use it. You
-can use it too, but we suggest you first think carefully about whether
-this license or the ordinary General Public License is the better
-strategy to use in any particular case, based on the explanations below.
-
- When we speak of free software, we are referring to freedom of use,
-not price. Our General Public Licenses are designed to make sure that
-you have the freedom to distribute copies of free software (and charge
-for this service if you wish); that you receive source code or can get
-it if you want it; that you can change the software and use pieces of
-it in new free programs; and that you are informed that you can do
-these things.
-
- To protect your rights, we need to make restrictions that forbid
-distributors to deny you these rights or to ask you to surrender these
-rights. These restrictions translate to certain responsibilities for
-you if you distribute copies of the library or if you modify it.
-
- For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link other code with the library, you must provide
-complete object files to the recipients, so that they can relink them
-with the library after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-
- We protect your rights with a two-step method: (1) we copyright the
-library, and (2) we offer you this license, which gives you legal
-permission to copy, distribute and/or modify the library.
-
- To protect each distributor, we want to make it very clear that
-there is no warranty for the free library. Also, if the library is
-modified by someone else and passed on, the recipients should know
-that what they have is not the original version, so that the original
-author's reputation will not be affected by problems that might be
-introduced by others.
-
- Finally, software patents pose a constant threat to the existence of
-any free program. We wish to make sure that a company cannot
-effectively restrict the users of a free program by obtaining a
-restrictive license from a patent holder. Therefore, we insist that
-any patent license obtained for a version of the library must be
-consistent with the full freedom of use specified in this license.
-
- Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License. This license, the GNU Lesser
-General Public License, applies to certain designated libraries, and
-is quite different from the ordinary General Public License. We use
-this license for certain libraries in order to permit linking those
-libraries into non-free programs.
-
- When a program is linked with a library, whether statically or using
-a shared library, the combination of the two is legally speaking a
-combined work, a derivative of the original library. The ordinary
-General Public License therefore permits such linking only if the
-entire combination fits its criteria of freedom. The Lesser General
-Public License permits more lax criteria for linking other code with
-the library.
-
- We call this license the "Lesser" General Public License because it
-does Less to protect the user's freedom than the ordinary General
-Public License. It also provides other free software developers Less
-of an advantage over competing non-free programs. These disadvantages
-are the reason we use the ordinary General Public License for many
-libraries. However, the Lesser license provides advantages in certain
-special circumstances.
-
- For example, on rare occasions, there may be a special need to
-encourage the widest possible use of a certain library, so that it becomes
-a de-facto standard. To achieve this, non-free programs must be
-allowed to use the library. A more frequent case is that a free
-library does the same job as widely used non-free libraries. In this
-case, there is little to gain by limiting the free library to free
-software only, so we use the Lesser General Public License.
-
- In other cases, permission to use a particular library in non-free
-programs enables a greater number of people to use a large body of
-free software. For example, permission to use the GNU C Library in
-non-free programs enables many more people to use the whole GNU
-operating system, as well as its variant, the GNU/Linux operating
-system.
-
- Although the Lesser General Public License is Less protective of the
-users' freedom, it does ensure that the user of a program that is
-linked with the Library has the freedom and the wherewithal to run
-that program using a modified version of the Library.
-
- The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, whereas the latter must
-be combined with the library in order to run.
-
- GNU LESSER GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License Agreement applies to any software library or other
-program which contains a notice placed by the copyright holder or
-other authorized party saying it may be distributed under the terms of
-this Lesser General Public License (also called "this License").
-Each licensee is addressed as "you".
-
- A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
- The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-
- "Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
- Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
- 1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
- You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-
- 2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) The modified work must itself be a software library.
-
- b) You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
-
- c) You must cause the whole of the work to be licensed at no
- charge to all third parties under the terms of this License.
-
- d) If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses
- the facility, other than as an argument passed when the facility
- is invoked, then you must make a good faith effort to ensure that,
- in the event an application does not supply such function or
- table, the facility still operates, and performs whatever part of
- its purpose remains meaningful.
-
- (For example, a function in a library to compute square roots has
- a purpose that is entirely well-defined independent of the
- application. Therefore, Subsection 2d requires that any
- application-supplied function or table used by this function must
- be optional: if the application does not supply it, the square
- root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library. To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License. (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.) Do not make any other change in
-these notices.
-
- Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
- This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
- 4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
- If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library". Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
- However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
- When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-
- If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
- Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-
- 6. As an exception to the Sections above, you may also combine or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
- You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
-
- a) Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that
- uses the Library", as object code and/or source code, so that the
- user can modify the Library and then relink to produce a modified
- executable containing the modified Library. (It is understood
- that the user who changes the contents of definitions files in the
- Library will not necessarily be able to recompile the application
- to use the modified definitions.)
-
- b) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (1) uses at run time a
- copy of the library already present on the user's computer system,
- rather than copying library functions into the executable, and (2)
- will operate properly with a modified version of the library, if
- the user installs one, as long as the modified version is
- interface-compatible with the version that the work was made with.
-
- c) Accompany the work with a written offer, valid for at
- least three years, to give the same user the materials
- specified in Subsection 6a, above, for a charge no more
- than the cost of performing this distribution.
-
- d) If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
-
- e) Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
-
- For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the materials to be distributed need not include anything that is
-normally distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
- It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-
- 7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
- a) Accompany the combined library with a copy of the same work
- based on the Library, uncombined with any other library
- facilities. This must be distributed under the terms of the
- Sections above.
-
- b) Give prominent notice with the combined library of the fact
- that part of it is a work based on the Library, and explaining
- where to find the accompanying uncombined form of the same work.
-
- 8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License. Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License. However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
- 9. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Library or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
- 10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties with
-this License.
-
- 11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all. For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded. In such case, this License incorporates the limitation as if
-written in the body of this License.
-
- 13. The Free Software Foundation may publish revised and/or new
-versions of the Lesser General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-
- 14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission. For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
- NO WARRANTY
-
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Libraries
-
- If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change. You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
- To apply these terms, attach the following notices to the library. It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
- <one line to give the library's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
- <signature of Ty Coon>, 1 April 1990
- Ty Coon, President of Vice
-
-That's all there is to it!
diff --git a/chromium/third_party/undoview/README.chromium b/chromium/third_party/undoview/README.chromium
deleted file mode 100644
index 032e2b33c08..00000000000
--- a/chromium/third_party/undoview/README.chromium
+++ /dev/null
@@ -1,13 +0,0 @@
-Name: undoview
-Short Name: undoview
-URL: http://projects.gnome.org/gtksourceview, http://www.gtk.org
-Version: unknown
-License: LGPL 2.1
-Security Critical: yes
-
-This directory provides a new class, GtkUndoView. It is based on GtkTextView
-from the GTK+ project, but with undo/redo support added. The code to add this
-support is borrowed from the GtkSourceView project. Since GtkSourceView has a
-lot of other stuff we don't want, we borrow only the undo/redo support and add
-it to GtkTextView to create GtkUndoView.
-
diff --git a/chromium/third_party/undoview/undo_manager.c b/chromium/third_party/undoview/undo_manager.c
deleted file mode 100644
index 6efba9c848a..00000000000
--- a/chromium/third_party/undoview/undo_manager.c
+++ /dev/null
@@ -1,1110 +0,0 @@
-/*
- * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
- * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
- * Copyright (C) 2002-2005 Paolo Maggi
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
-
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "undo_manager.h"
-
-#define DEFAULT_MAX_UNDO_LEVELS 25
-
-typedef struct _GtkSourceUndoAction GtkSourceUndoAction;
-typedef struct _GtkSourceUndoInsertAction GtkSourceUndoInsertAction;
-typedef struct _GtkSourceUndoDeleteAction GtkSourceUndoDeleteAction;
-
-typedef enum {
- GTK_SOURCE_UNDO_ACTION_INSERT,
- GTK_SOURCE_UNDO_ACTION_DELETE,
-} GtkSourceUndoActionType;
-
-/*
- * We use offsets instead of GtkTextIters because the last ones
- * require to much memory in this context without giving us any advantage.
- */
-
-struct _GtkSourceUndoInsertAction {
- gint pos;
- gchar *text;
- gint length;
- gint chars;
-};
-
-struct _GtkSourceUndoDeleteAction {
- gint start;
- gint end;
- gchar *text;
- gboolean forward;
-};
-
-struct _GtkSourceUndoAction {
- GtkSourceUndoActionType action_type;
-
- union {
- GtkSourceUndoInsertAction insert;
- GtkSourceUndoDeleteAction delete;
- } action;
-
- gint order_in_group;
-
- /* It is TRUE whether the action can be merged with the following action. */
- guint mergeable : 1;
-
- /* It is TRUE whether the action is marked as "modified".
- * An action is marked as "modified" if it changed the
- * state of the buffer from "not modified" to "modified". Only the first
- * action of a group can be marked as modified.
- * There can be a single action marked as "modified" in the actions list.
- */
- guint modified : 1;
-};
-
-/* INVALID is a pointer to an invalid action */
-#define INVALID ((void *) "IA")
-
-struct _GtkSourceUndoManagerPrivate {
- GtkTextBuffer *document;
-
- GList* actions;
- gint next_redo;
-
- gint actions_in_current_group;
-
- gint running_not_undoable_actions;
-
- gint num_of_groups;
-
- gint max_undo_levels;
-
- guint can_undo : 1;
- guint can_redo : 1;
-
- /* It is TRUE whether, while undoing an action of the current group (with order_in_group > 1),
- * the state of the buffer changed from "not modified" to "modified".
- */
- guint modified_undoing_group : 1;
-
- /* Pointer to the action (in the action list) marked as "modified".
- * It is NULL when no action is marked as "modified".
- * It is INVALID when the action marked as "modified" has been removed
- * from the action list (freeing the list or resizing it) */
- GtkSourceUndoAction *modified_action;
-};
-
-enum {
- CAN_UNDO,
- CAN_REDO,
- LAST_SIGNAL
-};
-
-#if !defined(NDEBUG)
-static void
-print_state(GtkSourceUndoManager* um)
-{
- fprintf(stderr, "\n***\n");
- GList* actions = um->priv->actions;
-
- for (; actions; actions = g_list_next(actions)) {
- GtkSourceUndoAction* act = actions->data;
- fprintf(stderr, "* type = %s\n", act->action_type == GTK_SOURCE_UNDO_ACTION_DELETE ?
- "delete" : "insert");
-
- fprintf(stderr, "\ttext = %s\n", act->action_type == GTK_SOURCE_UNDO_ACTION_DELETE
- ? act->action.delete.text : act->action.insert.text);
- fprintf(stderr, "\torder = %d\n", act->order_in_group);
- }
-
- fprintf(stderr, "* next redo: %d\n", um->priv->next_redo);
- fprintf(stderr, "* num of groups: %d\n", um->priv->num_of_groups);
- fprintf(stderr, "* actions in group: %d\n", um->priv->actions_in_current_group);
-}
-#endif
-
-static void gtk_source_undo_manager_class_init(GtkSourceUndoManagerClass *klass);
-static void gtk_source_undo_manager_init(GtkSourceUndoManager *um);
-static void gtk_source_undo_manager_finalize(GObject *object);
-
-static void gtk_source_undo_manager_insert_text_handler(GtkTextBuffer *buffer,
- GtkTextIter *pos,
- const gchar *text,
- gint length,
- GtkSourceUndoManager *um);
-static void gtk_source_undo_manager_delete_range_handler(GtkTextBuffer *buffer,
- GtkTextIter *start,
- GtkTextIter *end,
- GtkSourceUndoManager *um);
-static void gtk_source_undo_manager_begin_user_action_handler(GtkTextBuffer *buffer,
- GtkSourceUndoManager *um);
-static void gtk_source_undo_manager_modified_changed_handler(GtkTextBuffer *buffer,
- GtkSourceUndoManager *um);
-
-static void gtk_source_undo_manager_free_action_list(GtkSourceUndoManager *um);
-
-static void gtk_source_undo_manager_add_action(GtkSourceUndoManager *um,
- const GtkSourceUndoAction *undo_action);
-static void gtk_source_undo_manager_free_first_n_actions(GtkSourceUndoManager *um,
- gint n);
-static void gtk_source_undo_manager_check_list_size(GtkSourceUndoManager *um);
-
-static gboolean gtk_source_undo_manager_merge_action(GtkSourceUndoManager *um,
- const GtkSourceUndoAction *undo_action);
-
-static GObjectClass *parent_class = NULL;
-static guint undo_manager_signals [LAST_SIGNAL] = { 0 };
-
-GType
-gtk_source_undo_manager_get_type(void) {
- static GType undo_manager_type = 0;
-
- if(undo_manager_type == 0)
- {
- static const GTypeInfo our_info =
- {
- sizeof(GtkSourceUndoManagerClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) gtk_source_undo_manager_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof(GtkSourceUndoManager),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gtk_source_undo_manager_init,
- NULL /* value_table */
- };
-
- undo_manager_type = g_type_register_static(G_TYPE_OBJECT,
- "GtkSourceUndoManager",
- &our_info,
- 0);
- }
-
- return undo_manager_type;
-}
-
-static void
-gtk_source_undo_manager_class_init(GtkSourceUndoManagerClass *klass) {
- GObjectClass *object_class = G_OBJECT_CLASS(klass);
-
- parent_class = g_type_class_peek_parent(klass);
-
- object_class->finalize = gtk_source_undo_manager_finalize;
-
- klass->can_undo = NULL;
- klass->can_redo = NULL;
-
- undo_manager_signals[CAN_UNDO] =
- g_signal_new("can_undo",
- G_OBJECT_CLASS_TYPE(object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(GtkSourceUndoManagerClass, can_undo),
- NULL, NULL,
- g_cclosure_marshal_VOID__BOOLEAN,
- G_TYPE_NONE,
- 1,
- G_TYPE_BOOLEAN);
-
- undo_manager_signals[CAN_REDO] =
- g_signal_new("can_redo",
- G_OBJECT_CLASS_TYPE(object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(GtkSourceUndoManagerClass, can_redo),
- NULL, NULL,
- g_cclosure_marshal_VOID__BOOLEAN,
- G_TYPE_NONE,
- 1,
- G_TYPE_BOOLEAN);
-}
-
-static void
-gtk_source_undo_manager_init(GtkSourceUndoManager *um) {
- um->priv = g_new0(GtkSourceUndoManagerPrivate, 1);
-
- um->priv->actions = NULL;
- um->priv->next_redo = 0;
-
- um->priv->can_undo = FALSE;
- um->priv->can_redo = FALSE;
-
- um->priv->running_not_undoable_actions = 0;
-
- um->priv->num_of_groups = 0;
-
- um->priv->max_undo_levels = DEFAULT_MAX_UNDO_LEVELS;
-
- um->priv->modified_action = NULL;
-
- um->priv->modified_undoing_group = FALSE;
-}
-
-static void
-gtk_source_undo_manager_finalize(GObject *object) {
- GtkSourceUndoManager *um;
-
- g_return_if_fail(object != NULL);
- g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(object));
-
- um = GTK_SOURCE_UNDO_MANAGER(object);
-
- g_return_if_fail(um->priv != NULL);
-
- if(um->priv->actions != NULL)
- gtk_source_undo_manager_free_action_list(um);
-
- g_signal_handlers_disconnect_by_func(G_OBJECT(um->priv->document),
- G_CALLBACK(gtk_source_undo_manager_delete_range_handler),
- um);
-
- g_signal_handlers_disconnect_by_func(G_OBJECT(um->priv->document),
- G_CALLBACK(gtk_source_undo_manager_insert_text_handler),
- um);
-
- g_signal_handlers_disconnect_by_func(G_OBJECT(um->priv->document),
- G_CALLBACK(gtk_source_undo_manager_begin_user_action_handler),
- um);
-
- g_signal_handlers_disconnect_by_func(G_OBJECT(um->priv->document),
- G_CALLBACK(gtk_source_undo_manager_modified_changed_handler),
- um);
-
- g_free(um->priv);
-
- G_OBJECT_CLASS(parent_class)->finalize(object);
-}
-
-GtkSourceUndoManager*
-gtk_source_undo_manager_new(GtkTextBuffer* buffer) {
- GtkSourceUndoManager *um;
-
- um = GTK_SOURCE_UNDO_MANAGER(g_object_new(GTK_SOURCE_TYPE_UNDO_MANAGER, NULL));
-
- g_return_val_if_fail(um->priv != NULL, NULL);
- um->priv->document = buffer;
-
- g_signal_connect(G_OBJECT(buffer), "insert_text",
- G_CALLBACK(gtk_source_undo_manager_insert_text_handler),
- um);
-
- g_signal_connect(G_OBJECT(buffer), "delete_range",
- G_CALLBACK(gtk_source_undo_manager_delete_range_handler),
- um);
-
- g_signal_connect(G_OBJECT(buffer), "begin_user_action",
- G_CALLBACK(gtk_source_undo_manager_begin_user_action_handler),
- um);
-
- g_signal_connect(G_OBJECT(buffer), "modified_changed",
- G_CALLBACK(gtk_source_undo_manager_modified_changed_handler),
- um);
- return um;
-}
-
-void
-gtk_source_undo_manager_begin_not_undoable_action(GtkSourceUndoManager *um) {
- g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
- g_return_if_fail(um->priv != NULL);
-
- ++um->priv->running_not_undoable_actions;
-}
-
-static void
-gtk_source_undo_manager_end_not_undoable_action_internal(GtkSourceUndoManager *um) {
- g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
- g_return_if_fail(um->priv != NULL);
-
- g_return_if_fail(um->priv->running_not_undoable_actions > 0);
-
- --um->priv->running_not_undoable_actions;
-}
-
-void
-gtk_source_undo_manager_end_not_undoable_action(GtkSourceUndoManager *um) {
- g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
- g_return_if_fail(um->priv != NULL);
-
- gtk_source_undo_manager_end_not_undoable_action_internal(um);
-
- if(um->priv->running_not_undoable_actions == 0)
- {
- gtk_source_undo_manager_free_action_list(um);
-
- um->priv->next_redo = -1;
-
- if(um->priv->can_undo)
- {
- um->priv->can_undo = FALSE;
- g_signal_emit(G_OBJECT(um),
- undo_manager_signals [CAN_UNDO],
- 0,
- FALSE);
- }
-
- if(um->priv->can_redo)
- {
- um->priv->can_redo = FALSE;
- g_signal_emit(G_OBJECT(um),
- undo_manager_signals [CAN_REDO],
- 0,
- FALSE);
- }
- }
-}
-
-gboolean
-gtk_source_undo_manager_can_undo(const GtkSourceUndoManager *um) {
- g_return_val_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um), FALSE);
- g_return_val_if_fail(um->priv != NULL, FALSE);
-
- return um->priv->can_undo;
-}
-
-gboolean
-gtk_source_undo_manager_can_redo(const GtkSourceUndoManager *um) {
- g_return_val_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um), FALSE);
- g_return_val_if_fail(um->priv != NULL, FALSE);
-
- return um->priv->can_redo;
-}
-
-static void
-set_cursor(GtkTextBuffer *buffer, gint cursor) {
- GtkTextIter iter;
-
- /* Place the cursor at the requested position */
- gtk_text_buffer_get_iter_at_offset(buffer, &iter, cursor);
- gtk_text_buffer_place_cursor(buffer, &iter);
-}
-
-static void
-insert_text(GtkTextBuffer *buffer, gint pos, const gchar *text, gint len) {
- GtkTextIter iter;
-
- gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos);
- gtk_text_buffer_insert(buffer, &iter, text, len);
-}
-
-static void
-delete_text(GtkTextBuffer *buffer, gint start, gint end) {
- GtkTextIter start_iter;
- GtkTextIter end_iter;
-
- gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, start);
-
- if(end < 0)
- gtk_text_buffer_get_end_iter(buffer, &end_iter);
- else
- gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, end);
-
- gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
-}
-
-static gchar*
-get_chars(GtkTextBuffer *buffer, gint start, gint end) {
- GtkTextIter start_iter;
- GtkTextIter end_iter;
-
- gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, start);
-
- if(end < 0)
- gtk_text_buffer_get_end_iter(buffer, &end_iter);
- else
- gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, end);
-
- return gtk_text_buffer_get_slice(buffer, &start_iter, &end_iter, TRUE);
-}
-
-void
-gtk_source_undo_manager_undo(GtkSourceUndoManager *um) {
- GtkSourceUndoAction *undo_action;
- gboolean modified = FALSE;
-
- g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
- g_return_if_fail(um->priv != NULL);
- g_return_if_fail(um->priv->can_undo);
-
- um->priv->modified_undoing_group = FALSE;
-
- gtk_source_undo_manager_begin_not_undoable_action(um);
-
- do
- {
- undo_action = g_list_nth_data(um->priv->actions, um->priv->next_redo + 1);
- g_return_if_fail(undo_action != NULL);
-
- /* undo_action->modified can be TRUE only if undo_action->order_in_group <= 1 */
- g_return_if_fail((undo_action->order_in_group <= 1) ||
- ((undo_action->order_in_group > 1) && !undo_action->modified));
-
- if(undo_action->order_in_group <= 1)
- {
- /* Set modified to TRUE only if the buffer did not change its state from
- * "not modified" to "modified" undoing an action(with order_in_group > 1)
- * in current group. */
- modified =(undo_action->modified && !um->priv->modified_undoing_group);
- }
-
- switch(undo_action->action_type)
- {
- case GTK_SOURCE_UNDO_ACTION_DELETE:
- insert_text(
- um->priv->document,
- undo_action->action.delete.start,
- undo_action->action.delete.text,
- strlen(undo_action->action.delete.text));
-
- if(undo_action->action.delete.forward)
- set_cursor(
- um->priv->document,
- undo_action->action.delete.start);
- else
- set_cursor(
- um->priv->document,
- undo_action->action.delete.end);
-
- break;
-
- case GTK_SOURCE_UNDO_ACTION_INSERT:
- delete_text(
- um->priv->document,
- undo_action->action.insert.pos,
- undo_action->action.insert.pos +
- undo_action->action.insert.chars);
-
- set_cursor(
- um->priv->document,
- undo_action->action.insert.pos);
- break;
-
- default:
- /* Unknown action type. */
- g_return_if_reached();
- }
-
- ++um->priv->next_redo;
-
- } while(undo_action->order_in_group > 1);
-
- if(modified)
- {
- --um->priv->next_redo;
- gtk_text_buffer_set_modified(um->priv->document, FALSE);
- ++um->priv->next_redo;
- }
-
- gtk_source_undo_manager_end_not_undoable_action_internal(um);
-
- um->priv->modified_undoing_group = FALSE;
-
- if(!um->priv->can_redo)
- {
- um->priv->can_redo = TRUE;
- g_signal_emit(G_OBJECT(um),
- undo_manager_signals [CAN_REDO],
- 0,
- TRUE);
- }
-
- if(um->priv->next_redo >=(gint)(g_list_length(um->priv->actions) - 1))
- {
- um->priv->can_undo = FALSE;
- g_signal_emit(G_OBJECT(um),
- undo_manager_signals [CAN_UNDO],
- 0,
- FALSE);
- }
-}
-
-void
-gtk_source_undo_manager_redo(GtkSourceUndoManager *um) {
- GtkSourceUndoAction *undo_action;
- gboolean modified = FALSE;
-
- g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
- g_return_if_fail(um->priv != NULL);
- g_return_if_fail(um->priv->can_redo);
-
- undo_action = g_list_nth_data(um->priv->actions, um->priv->next_redo);
- g_return_if_fail(undo_action != NULL);
-
- gtk_source_undo_manager_begin_not_undoable_action(um);
-
- do
- {
- if(undo_action->modified)
- {
- g_return_if_fail(undo_action->order_in_group <= 1);
- modified = TRUE;
- }
-
- --um->priv->next_redo;
-
- switch(undo_action->action_type)
- {
- case GTK_SOURCE_UNDO_ACTION_DELETE:
- delete_text(
- um->priv->document,
- undo_action->action.delete.start,
- undo_action->action.delete.end);
-
- set_cursor(
- um->priv->document,
- undo_action->action.delete.start);
-
- break;
-
- case GTK_SOURCE_UNDO_ACTION_INSERT:
- set_cursor(
- um->priv->document,
- undo_action->action.insert.pos);
-
- insert_text(
- um->priv->document,
- undo_action->action.insert.pos,
- undo_action->action.insert.text,
- undo_action->action.insert.length);
-
- break;
-
- default:
- /* Unknown action type */
- ++um->priv->next_redo;
- g_return_if_reached();
- }
-
- if(um->priv->next_redo < 0)
- undo_action = NULL;
- else
- undo_action = g_list_nth_data(um->priv->actions, um->priv->next_redo);
-
- } while((undo_action != NULL) &&(undo_action->order_in_group > 1));
-
- if(modified)
- {
- ++um->priv->next_redo;
- gtk_text_buffer_set_modified(um->priv->document, FALSE);
- --um->priv->next_redo;
- }
-
- gtk_source_undo_manager_end_not_undoable_action_internal(um);
-
- if(um->priv->next_redo < 0)
- {
- um->priv->can_redo = FALSE;
- g_signal_emit(G_OBJECT(um), undo_manager_signals [CAN_REDO], 0, FALSE);
- }
-
- if(!um->priv->can_undo)
- {
- um->priv->can_undo = TRUE;
- g_signal_emit(G_OBJECT(um), undo_manager_signals [CAN_UNDO], 0, TRUE);
- }
-}
-
-static void
-gtk_source_undo_action_free(GtkSourceUndoAction *action) {
- if(action == NULL)
- return;
-
- if(action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
- g_free(action->action.insert.text);
- else if(action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
- g_free(action->action.delete.text);
- else
- g_return_if_reached();
-
- g_free(action);
-}
-
-static void
-gtk_source_undo_manager_free_action_list(GtkSourceUndoManager *um) {
- GList *l;
-
- l = um->priv->actions;
-
- while(l != NULL)
- {
- GtkSourceUndoAction *action = l->data;
-
- if(action->order_in_group == 1)
- --um->priv->num_of_groups;
- um->priv->actions_in_current_group = action->order_in_group - 1;
-
- if(action->modified)
- um->priv->modified_action = INVALID;
-
- gtk_source_undo_action_free(action);
-
- l = g_list_next(l);
- }
-
- g_list_free(um->priv->actions);
- um->priv->actions = NULL;
-}
-
-static void
-gtk_source_undo_manager_insert_text_handler(GtkTextBuffer *buffer,
- GtkTextIter *pos,
- const gchar *text,
- gint length,
- GtkSourceUndoManager *um) {
- GtkSourceUndoAction undo_action;
-
- if(um->priv->running_not_undoable_actions > 0)
- return;
-
- undo_action.action_type = GTK_SOURCE_UNDO_ACTION_INSERT;
-
- undo_action.action.insert.pos = gtk_text_iter_get_offset(pos);
- undo_action.action.insert.text =(gchar*) text;
- undo_action.action.insert.length = length;
- undo_action.action.insert.chars = g_utf8_strlen(text, length);
-
- if((undo_action.action.insert.chars > 1) ||(g_utf8_get_char(text) == '\n'))
-
- undo_action.mergeable = FALSE;
- else
- undo_action.mergeable = TRUE;
-
- undo_action.modified = FALSE;
-
- gtk_source_undo_manager_add_action(um, &undo_action);
-}
-
-static void
-gtk_source_undo_manager_delete_range_handler(GtkTextBuffer *buffer,
- GtkTextIter *start,
- GtkTextIter *end,
- GtkSourceUndoManager *um) {
- GtkSourceUndoAction undo_action;
- GtkTextIter insert_iter;
-
- if(um->priv->running_not_undoable_actions > 0)
- return;
-
- undo_action.action_type = GTK_SOURCE_UNDO_ACTION_DELETE;
-
- gtk_text_iter_order(start, end);
-
- undo_action.action.delete.start = gtk_text_iter_get_offset(start);
- undo_action.action.delete.end = gtk_text_iter_get_offset(end);
-
- undo_action.action.delete.text = get_chars(
- buffer,
- undo_action.action.delete.start,
- undo_action.action.delete.end);
-
- /* figure out if the user used the Delete or the Backspace key */
- gtk_text_buffer_get_iter_at_mark(buffer, &insert_iter,
- gtk_text_buffer_get_insert(buffer));
- if(gtk_text_iter_get_offset(&insert_iter) <= undo_action.action.delete.start)
- undo_action.action.delete.forward = TRUE;
- else
- undo_action.action.delete.forward = FALSE;
-
- if(((undo_action.action.delete.end - undo_action.action.delete.start) > 1) ||
- (g_utf8_get_char(undo_action.action.delete.text ) == '\n'))
- undo_action.mergeable = FALSE;
- else
- undo_action.mergeable = TRUE;
-
- undo_action.modified = FALSE;
-
- gtk_source_undo_manager_add_action(um, &undo_action);
-
- g_free(undo_action.action.delete.text);
-
-}
-
-static void
-gtk_source_undo_manager_begin_user_action_handler(GtkTextBuffer *buffer, GtkSourceUndoManager *um) {
- g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
- g_return_if_fail(um->priv != NULL);
-
- if(um->priv->running_not_undoable_actions > 0)
- return;
-
- um->priv->actions_in_current_group = 0;
-}
-
-static void
-gtk_source_undo_manager_add_action(GtkSourceUndoManager *um,
- const GtkSourceUndoAction *undo_action) {
- GtkSourceUndoAction* action;
-
- if(um->priv->next_redo >= 0)
- {
- gtk_source_undo_manager_free_first_n_actions(um, um->priv->next_redo + 1);
- }
-
- um->priv->next_redo = -1;
-
- if(!gtk_source_undo_manager_merge_action(um, undo_action))
- {
- action = g_new(GtkSourceUndoAction, 1);
- *action = *undo_action;
-
- if(action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
- action->action.insert.text = g_strndup(undo_action->action.insert.text, undo_action->action.insert.length);
- else if(action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
- action->action.delete.text = g_strdup(undo_action->action.delete.text);
- else
- {
- g_free(action);
- g_return_if_reached();
- }
-
- ++um->priv->actions_in_current_group;
- action->order_in_group = um->priv->actions_in_current_group;
-
- if(action->order_in_group == 1)
- ++um->priv->num_of_groups;
-
- um->priv->actions = g_list_prepend(um->priv->actions, action);
- }
-
- gtk_source_undo_manager_check_list_size(um);
-
- if(!um->priv->can_undo)
- {
- um->priv->can_undo = TRUE;
- g_signal_emit(G_OBJECT(um), undo_manager_signals [CAN_UNDO], 0, TRUE);
- }
-
- if(um->priv->can_redo)
- {
- um->priv->can_redo = FALSE;
- g_signal_emit(G_OBJECT(um), undo_manager_signals [CAN_REDO], 0, FALSE);
- }
-}
-
-static void
-gtk_source_undo_manager_free_first_n_actions(GtkSourceUndoManager *um,
- gint n) {
- gint i;
-
- if(um->priv->actions == NULL)
- return;
-
- for(i = 0; i < n; i++)
- {
- GtkSourceUndoAction *action = g_list_first(um->priv->actions)->data;
-
- if(action->order_in_group == 1)
- --um->priv->num_of_groups;
- um->priv->actions_in_current_group = action->order_in_group - 1;
-
- if(action->modified)
- um->priv->modified_action = INVALID;
-
- gtk_source_undo_action_free(action);
-
- um->priv->actions = g_list_delete_link(um->priv->actions,
- um->priv->actions);
-
- if(um->priv->actions == NULL)
- return;
- }
-}
-
-static void
-gtk_source_undo_manager_check_list_size(GtkSourceUndoManager *um) {
- gint undo_levels;
-
- g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
- g_return_if_fail(um->priv != NULL);
-
- undo_levels = gtk_source_undo_manager_get_max_undo_levels(um);
-
- if(undo_levels < 1)
- return;
-
- if(um->priv->num_of_groups > undo_levels)
- {
- GtkSourceUndoAction *undo_action;
- GList *last;
-
- last = g_list_last(um->priv->actions);
- undo_action =(GtkSourceUndoAction*) last->data;
-
- do
- {
- GList *tmp;
-
- if(undo_action->order_in_group == 1)
- --um->priv->num_of_groups;
- um->priv->actions_in_current_group = undo_action->order_in_group - 1;
-
- if(undo_action->modified)
- um->priv->modified_action = INVALID;
-
- gtk_source_undo_action_free(undo_action);
-
- tmp = g_list_previous(last);
- um->priv->actions = g_list_delete_link(um->priv->actions, last);
- last = tmp;
- g_return_if_fail(last != NULL);
-
- undo_action =(GtkSourceUndoAction*) last->data;
-
- } while((undo_action->order_in_group > 1) ||
- (um->priv->num_of_groups > undo_levels));
- }
-}
-
-/**
- * gtk_source_undo_manager_merge_action:
- * @um: a #GtkSourceUndoManager.
- * @undo_action: a #GtkSourceUndoAction.
- *
- * This function tries to merge the undo action at the top of
- * the stack with a new undo action. So when we undo for example
- * typing, we can undo the whole word and not each letter by itself.
- *
- * Return Value: %TRUE is merge was successful, %FALSE otherwise.
- **/
-static gboolean
-gtk_source_undo_manager_merge_action(GtkSourceUndoManager *um,
- const GtkSourceUndoAction *undo_action) {
- GtkSourceUndoAction *last_action;
-
- g_return_val_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um), FALSE);
- g_return_val_if_fail(um->priv != NULL, FALSE);
-
- if(um->priv->actions == NULL)
- return FALSE;
-
- last_action =(GtkSourceUndoAction*) g_list_nth_data(um->priv->actions, 0);
-
- if(!last_action->mergeable)
- return FALSE;
-
- if((!undo_action->mergeable) ||
- (undo_action->action_type != last_action->action_type))
- {
- last_action->mergeable = FALSE;
- return FALSE;
- }
-
- if(undo_action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
- {
- if((last_action->action.delete.forward != undo_action->action.delete.forward) ||
- ((last_action->action.delete.start != undo_action->action.delete.start) &&
- (last_action->action.delete.start != undo_action->action.delete.end)))
- {
- last_action->mergeable = FALSE;
- return FALSE;
- }
-
- if(last_action->action.delete.start == undo_action->action.delete.start)
- {
- gchar *str;
-
-#define L (last_action->action.delete.end - last_action->action.delete.start - 1)
-#define g_utf8_get_char_at(p,i) g_utf8_get_char(g_utf8_offset_to_pointer((p),(i)))
-
- /* Deleted with the delete key */
- if((g_utf8_get_char(undo_action->action.delete.text) != ' ') &&
- (g_utf8_get_char(undo_action->action.delete.text) != '\t') &&
- ((g_utf8_get_char_at(last_action->action.delete.text, L) == ' ') ||
- (g_utf8_get_char_at(last_action->action.delete.text, L) == '\t')))
- {
- last_action->mergeable = FALSE;
- return FALSE;
- }
-
- str = g_strdup_printf("%s%s", last_action->action.delete.text,
- undo_action->action.delete.text);
-
- g_free(last_action->action.delete.text);
- last_action->action.delete.end +=(undo_action->action.delete.end -
- undo_action->action.delete.start);
- last_action->action.delete.text = str;
- }
- else
- {
- gchar *str;
-
- /* Deleted with the backspace key */
- if((g_utf8_get_char(undo_action->action.delete.text) != ' ') &&
- (g_utf8_get_char(undo_action->action.delete.text) != '\t') &&
- ((g_utf8_get_char(last_action->action.delete.text) == ' ') ||
- (g_utf8_get_char(last_action->action.delete.text) == '\t')))
- {
- last_action->mergeable = FALSE;
- return FALSE;
- }
-
- str = g_strdup_printf("%s%s", undo_action->action.delete.text,
- last_action->action.delete.text);
-
- g_free(last_action->action.delete.text);
- last_action->action.delete.start = undo_action->action.delete.start;
- last_action->action.delete.text = str;
- }
- }
- else if(undo_action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
- {
- gchar* str;
-
-#define I (last_action->action.insert.chars - 1)
-
- if((undo_action->action.insert.pos !=
- (last_action->action.insert.pos + last_action->action.insert.chars)) ||
- ((g_utf8_get_char(undo_action->action.insert.text) != ' ') &&
- (g_utf8_get_char(undo_action->action.insert.text) != '\t') &&
- ((g_utf8_get_char_at(last_action->action.insert.text, I) == ' ') ||
- (g_utf8_get_char_at(last_action->action.insert.text, I) == '\t')))
- )
- {
- last_action->mergeable = FALSE;
- return FALSE;
- }
-
- str = g_strdup_printf("%s%s", last_action->action.insert.text,
- undo_action->action.insert.text);
-
- g_free(last_action->action.insert.text);
- last_action->action.insert.length += undo_action->action.insert.length;
- last_action->action.insert.text = str;
- last_action->action.insert.chars += undo_action->action.insert.chars;
-
- }
- else
- /* Unknown action inside undo merge encountered */
- g_return_val_if_reached(TRUE);
-
- return TRUE;
-}
-
-gint
-gtk_source_undo_manager_get_max_undo_levels(GtkSourceUndoManager *um) {
- g_return_val_if_fail(um != NULL, 0);
- g_return_val_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um), 0);
-
- return um->priv->max_undo_levels;
-}
-
-void
-gtk_source_undo_manager_set_max_undo_levels(GtkSourceUndoManager *um,
- gint max_undo_levels) {
- gint old_levels;
-
- g_return_if_fail(um != NULL);
- g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
-
- old_levels = um->priv->max_undo_levels;
- um->priv->max_undo_levels = max_undo_levels;
-
- if(max_undo_levels < 1)
- return;
-
- if(old_levels > max_undo_levels)
- {
- /* strip redo actions first */
- while(um->priv->next_redo >= 0 &&(um->priv->num_of_groups > max_undo_levels))
- {
- gtk_source_undo_manager_free_first_n_actions(um, 1);
- um->priv->next_redo--;
- }
-
- /* now remove undo actions if necessary */
- gtk_source_undo_manager_check_list_size(um);
-
- /* emit "can_undo" and/or "can_redo" if appropiate */
- if(um->priv->next_redo < 0 && um->priv->can_redo)
- {
- um->priv->can_redo = FALSE;
- g_signal_emit(G_OBJECT(um), undo_manager_signals [CAN_REDO], 0, FALSE);
- }
-
- if(um->priv->can_undo &&
- um->priv->next_redo >=(gint)(g_list_length(um->priv->actions) - 1))
- {
- um->priv->can_undo = FALSE;
- g_signal_emit(G_OBJECT(um), undo_manager_signals [CAN_UNDO], 0, FALSE);
- }
- }
-}
-
-static void
-gtk_source_undo_manager_modified_changed_handler(GtkTextBuffer *buffer,
- GtkSourceUndoManager *um) {
- GtkSourceUndoAction *action;
- GList *list;
-
- g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
- g_return_if_fail(um->priv != NULL);
-
- if(um->priv->actions == NULL)
- return;
-
- list = g_list_nth(um->priv->actions, um->priv->next_redo + 1);
-
- if(list != NULL)
- action =(GtkSourceUndoAction*) list->data;
- else
- action = NULL;
-
- if(gtk_text_buffer_get_modified(buffer) == FALSE)
- {
- if(action != NULL)
- action->mergeable = FALSE;
-
- if(um->priv->modified_action != NULL)
- {
- if(um->priv->modified_action != INVALID)
- um->priv->modified_action->modified = FALSE;
-
- um->priv->modified_action = NULL;
- }
-
- return;
- }
-
- if(action == NULL)
- {
- g_return_if_fail(um->priv->running_not_undoable_actions > 0);
-
- return;
- }
-
- /* gtk_text_buffer_get_modified(buffer) == TRUE */
-
- g_return_if_fail(um->priv->modified_action == NULL);
-
- if(action->order_in_group > 1)
- um->priv->modified_undoing_group = TRUE;
-
- while(action->order_in_group > 1)
- {
- list = g_list_next(list);
- g_return_if_fail(list != NULL);
-
- action =(GtkSourceUndoAction*) list->data;
- g_return_if_fail(action != NULL);
- }
-
- action->modified = TRUE;
- um->priv->modified_action = action;
-}
-
diff --git a/chromium/third_party/undoview/undo_manager.h b/chromium/third_party/undoview/undo_manager.h
deleted file mode 100644
index 5a18829eb82..00000000000
--- a/chromium/third_party/undoview/undo_manager.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
- * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
- * Copyright (C) 2002, 2003 Paolo Maggi
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
-
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef UNDOVIEW_UNDO_MANAGER_H_
-#define UNDOVIEW_UNDO_MANAGER_H_
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-#define GTK_SOURCE_TYPE_UNDO_MANAGER (gtk_source_undo_manager_get_type())
-
-#define GTK_SOURCE_UNDO_MANAGER(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_SOURCE_TYPE_UNDO_MANAGER, GtkSourceUndoManager))
-
-#define GTK_SOURCE_UNDO_MANAGER_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass), GTK_SOURCE_TYPE_UNDO_MANAGER, GtkSourceUndoManagerClass))
-
-#define GTK_SOURCE_IS_UNDO_MANAGER(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_SOURCE_TYPE_UNDO_MANAGER))
-
-#define GTK_SOURCE_IS_UNDO_MANAGER_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_SOURCE_TYPE_UNDO_MANAGER))
-
-#define GTK_SOURCE_UNDO_MANAGER_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_SOURCE_TYPE_UNDO_MANAGER, GtkSourceUndoManagerClass))
-
-typedef struct _GtkSourceUndoManager GtkSourceUndoManager;
-typedef struct _GtkSourceUndoManagerClass GtkSourceUndoManagerClass;
-
-typedef struct _GtkSourceUndoManagerPrivate GtkSourceUndoManagerPrivate;
-
-struct _GtkSourceUndoManager
-{
- GObject base;
-
- GtkSourceUndoManagerPrivate *priv;
-};
-
-struct _GtkSourceUndoManagerClass
-{
- GObjectClass parent_class;
-
- /* Signals */
- void (*can_undo)(GtkSourceUndoManager *um, gboolean can_undo);
- void (*can_redo)(GtkSourceUndoManager *um, gboolean can_redo);
-};
-
-GType gtk_source_undo_manager_get_type(void) G_GNUC_CONST;
-
-GtkSourceUndoManager* gtk_source_undo_manager_new(GtkTextBuffer *buffer);
-
-gboolean gtk_source_undo_manager_can_undo(const GtkSourceUndoManager *um);
-gboolean gtk_source_undo_manager_can_redo(const GtkSourceUndoManager *um);
-
-void gtk_source_undo_manager_undo(GtkSourceUndoManager *um);
-void gtk_source_undo_manager_redo(GtkSourceUndoManager *um);
-
-void gtk_source_undo_manager_begin_not_undoable_action(GtkSourceUndoManager *um);
-void gtk_source_undo_manager_end_not_undoable_action(GtkSourceUndoManager *um);
-
-gint gtk_source_undo_manager_get_max_undo_levels(GtkSourceUndoManager *um);
-void gtk_source_undo_manager_set_max_undo_levels(GtkSourceUndoManager *um,
- gint undo_levels);
-
-G_END_DECLS
-
-#endif // UNDOVIEW_UNDO_MANAGER_H_
-
diff --git a/chromium/third_party/undoview/undo_view.c b/chromium/third_party/undoview/undo_view.c
deleted file mode 100644
index 933f8adca0e..00000000000
--- a/chromium/third_party/undoview/undo_view.c
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Boilerplate code was generated by http://burtonini.com/cgi/gobject.py
-
-#include <gdk/gdkkeysyms.h>
-
-#include "undo_view.h"
-
-G_DEFINE_TYPE (GtkUndoView, gtk_undo_view, GTK_TYPE_TEXT_VIEW)
-
-static void
-gtk_undo_view_dispose(GObject *object) {
- GtkUndoView *uview = GTK_UNDO_VIEW(object);
-
- if(uview->undo_manager_) {
- g_object_unref(G_OBJECT(uview->undo_manager_));
- uview->undo_manager_ = NULL;
- }
- G_OBJECT_CLASS(gtk_undo_view_parent_class)->dispose(object);
-}
-
-static void
-gtk_undo_view_undo(GtkUndoView *uview) {
- if(gtk_source_undo_manager_can_undo(uview->undo_manager_))
- gtk_source_undo_manager_undo(uview->undo_manager_);
-}
-
-static void
-gtk_undo_view_redo(GtkUndoView *uview) {
- if(gtk_source_undo_manager_can_redo(uview->undo_manager_))
- gtk_source_undo_manager_redo(uview->undo_manager_);
-}
-
-static void
-gtk_undo_view_class_init(GtkUndoViewClass *klass) {
- GObjectClass *object_class = G_OBJECT_CLASS(klass);
- GtkBindingSet *binding_set;
-
- g_signal_new("undo",
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET(GtkUndoViewClass, undo),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
- g_signal_new("redo",
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET(GtkUndoViewClass, redo),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-
- klass->undo = gtk_undo_view_undo;
- klass->redo = gtk_undo_view_redo;
-
- binding_set = gtk_binding_set_by_class(klass);
- gtk_binding_entry_add_signal(binding_set, GDK_z, GDK_CONTROL_MASK, "undo", 0);
- gtk_binding_entry_add_signal(binding_set, GDK_y, GDK_CONTROL_MASK, "redo", 0);
- gtk_binding_entry_add_signal(binding_set, GDK_z, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "redo", 0);
- gtk_binding_entry_add_signal(binding_set, GDK_F14, 0, "undo", 0);
-
- object_class->dispose = gtk_undo_view_dispose;
-}
-
-static void
-gtk_undo_view_init(GtkUndoView *self) {
-}
-
-GtkWidget*
-gtk_undo_view_new(GtkTextBuffer *buffer) {
- GtkWidget *ret = g_object_new(GTK_TYPE_UNDO_VIEW, "buffer", buffer, NULL);
- GTK_UNDO_VIEW(ret)->undo_manager_ = gtk_source_undo_manager_new(GTK_TEXT_BUFFER(buffer));
-
- return ret;
-}
-
diff --git a/chromium/third_party/undoview/undo_view.h b/chromium/third_party/undoview/undo_view.h
deleted file mode 100644
index 7fccf87bd99..00000000000
--- a/chromium/third_party/undoview/undo_view.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Boilerplate code was generated by http://burtonini.com/cgi/gobject.py
-
-#ifndef UNDOVIEW_UNDO_VIEW_H_
-#define UNDOVIEW_UNDO_VIEW_H_
-
-#include <gtk/gtk.h>
-#include "undo_manager.h"
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_UNDO_VIEW gtk_undo_view_get_type()
-
-#define GTK_UNDO_VIEW(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_UNDO_VIEW, GtkUndoView))
-
-#define GTK_UNDO_VIEW_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_UNDO_VIEW, GtkUndoViewClass))
-
-#define GTK_IS_UNDO_VIEW(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_UNDO_VIEW))
-
-#define GTK_IS_UNDO_VIEW_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_UNDO_VIEW))
-
-#define GTK_UNDO_VIEW_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_UNDO_VIEW, GtkUndoViewClass))
-
-typedef struct {
- GtkTextView parent;
- GtkSourceUndoManager *undo_manager_;
-} GtkUndoView;
-
-typedef struct {
- GtkTextViewClass parent_class;
-
- void (*undo)(GtkUndoView *);
- void (*redo)(GtkUndoView *);
-} GtkUndoViewClass;
-
-GType gtk_undo_view_get_type(void);
-
-GtkWidget* gtk_undo_view_new(GtkTextBuffer *buffer);
-
-G_END_DECLS
-
-#endif // UNDOVIEW_UNDO_VIEW_H_
diff --git a/chromium/third_party/webrtc/modules/audio_processing/aec/aec_core.c b/chromium/third_party/webrtc/modules/audio_processing/aec/aec_core.c
index 4d59956dc88..85ea8bd3510 100644
--- a/chromium/third_party/webrtc/modules/audio_processing/aec/aec_core.c
+++ b/chromium/third_party/webrtc/modules/audio_processing/aec/aec_core.c
@@ -98,9 +98,13 @@ ALIGN16_BEG const float ALIGN16_END WebRtcAec_overDriveCurve[65] = {
1.9354f, 1.9437f, 1.9520f, 1.9601f, 1.9682f, 1.9763f, 1.9843f, 1.9922f,
2.0000f};
-// TODO(bjornv): These parameters will be tuned.
+// Delay Agnostic AEC parameters, still under development and may change.
static const float kDelayQualityThresholdMax = 0.07f;
+static const float kDelayQualityThresholdMin = 0.01f;
static const int kInitialShiftOffset = 5;
+#if !defined(WEBRTC_ANDROID)
+static const int kDelayCorrectionStart = 1500; // 10 ms chunks
+#endif
// Target suppression levels for nlp modes.
// log{0.001, 0.00001, 0.00000001}
@@ -853,10 +857,28 @@ static void TimeToFrequency(float time_data[PART_LEN2],
}
}
+static int MoveFarReadPtrWithoutSystemDelayUpdate(AecCore* self, int elements) {
+ WebRtc_MoveReadPtr(self->far_buf_windowed, elements);
+#ifdef WEBRTC_AEC_DEBUG_DUMP
+ WebRtc_MoveReadPtr(self->far_time_buf, elements);
+#endif
+ return WebRtc_MoveReadPtr(self->far_buf, elements);
+}
+
static int SignalBasedDelayCorrection(AecCore* self) {
int delay_correction = 0;
int last_delay = -2;
assert(self != NULL);
+#if !defined(WEBRTC_ANDROID)
+ // On desktops, turn on correction after |kDelayCorrectionStart| frames. This
+ // is to let the delay estimation get a chance to converge. Also, if the
+ // playout audio volume is low (or even muted) the delay estimation can return
+ // a very large delay, which will break the AEC if it is applied.
+ if (self->frame_count < kDelayCorrectionStart) {
+ return 0;
+ }
+#endif
+
// 1. Check for non-negative delay estimate. Note that the estimates we get
// from the delay estimation are not compensated for lookahead. Hence, a
// negative |last_delay| is an invalid one.
@@ -874,15 +896,22 @@ static int SignalBasedDelayCorrection(AecCore* self) {
(WebRtc_last_delay_quality(self->delay_estimator) >
self->delay_quality_threshold)) {
int delay = last_delay - WebRtc_lookahead(self->delay_estimator);
- // Allow for a slack in the actual delay. The adaptive echo cancellation
- // filter is currently |num_partitions| (of 64 samples) long. If the
- // delay estimate indicates a delay of at least one quarter of the filter
- // length we open up for correction.
- if (delay <= 0 || delay > (self->num_partitions / 4)) {
+ // Allow for a slack in the actual delay, defined by a |lower_bound| and an
+ // |upper_bound|. The adaptive echo cancellation filter is currently
+ // |num_partitions| (of 64 samples) long. If the delay estimate is negative
+ // or at least 3/4 of the filter length we open up for correction.
+ const int lower_bound = 0;
+ const int upper_bound = self->num_partitions * 3 / 4;
+ const int do_correction = delay <= lower_bound || delay > upper_bound;
+ if (do_correction == 1) {
int available_read = (int)WebRtc_available_read(self->far_buf);
- // Adjust w.r.t. a |shift_offset| to account for not as reliable estimates
- // in the beginning, hence we are more conservative.
- delay_correction = -(delay - self->shift_offset);
+ // With |shift_offset| we gradually rely on the delay estimates. For
+ // positive delays we reduce the correction by |shift_offset| to lower the
+ // risk of pushing the AEC into a non causal state. For negative delays
+ // we rely on the values up to a rounding error, hence compensate by 1
+ // element to make sure to push the delay into the causal region.
+ delay_correction = -delay;
+ delay_correction += delay > self->shift_offset ? self->shift_offset : 1;
self->shift_offset--;
self->shift_offset = (self->shift_offset <= 1 ? 1 : self->shift_offset);
if (delay_correction > available_read - self->mult - 1) {
@@ -1433,12 +1462,15 @@ int WebRtcAec_CreateAec(AecCore** aecInst) {
return -1;
}
#ifdef WEBRTC_ANDROID
+ aec->reported_delay_enabled = 0; // DA-AEC enabled by default.
// DA-AEC assumes the system is causal from the beginning and will self adjust
// the lookahead when shifting is required.
WebRtc_set_lookahead(aec->delay_estimator, 0);
#else
+ aec->reported_delay_enabled = 1;
WebRtc_set_lookahead(aec->delay_estimator, kLookaheadBlocks);
#endif
+ aec->extended_filter_enabled = 0;
// Assembly optimization
WebRtcAec_FilterFar = FilterFar;
@@ -1583,14 +1615,8 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
aec->previous_delay = -2; // (-2): Uninitialized.
aec->delay_correction_count = 0;
aec->shift_offset = kInitialShiftOffset;
- aec->delay_quality_threshold = 0;
+ aec->delay_quality_threshold = kDelayQualityThresholdMin;
-#ifdef WEBRTC_ANDROID
- aec->reported_delay_enabled = 0; // Disabled by default.
-#else
- aec->reported_delay_enabled = 1;
-#endif
- aec->extended_filter_enabled = 0;
aec->num_partitions = kNormalNumPartitions;
// Update the delay estimator with filter length. We use half the
@@ -1603,6 +1629,7 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
// all the time and the APIs to turn it on/off will be removed. Hence, remove
// this line then.
WebRtc_enable_robust_validation(aec->delay_estimator, 1);
+ aec->frame_count = 0;
// Default target suppression mode.
aec->nlp_mode = 1;
@@ -1707,11 +1734,7 @@ void WebRtcAec_BufferFarendPartition(AecCore* aec, const float* farend) {
}
int WebRtcAec_MoveFarReadPtr(AecCore* aec, int elements) {
- int elements_moved = WebRtc_MoveReadPtr(aec->far_buf_windowed, elements);
- WebRtc_MoveReadPtr(aec->far_buf, elements);
-#ifdef WEBRTC_AEC_DEBUG_DUMP
- WebRtc_MoveReadPtr(aec->far_time_buf, elements);
-#endif
+ int elements_moved = MoveFarReadPtrWithoutSystemDelayUpdate(aec, elements);
aec->system_delay -= elements_moved * PART_LEN;
return elements_moved;
}
@@ -1725,6 +1748,7 @@ void WebRtcAec_ProcessFrames(AecCore* aec,
int i, j;
int out_elements = 0;
+ aec->frame_count++;
// For each frame the process is as follows:
// 1) If the system_delay indicates on being too small for processing a
// frame we stuff the buffer with enough data for 10 ms.
@@ -1783,42 +1807,27 @@ void WebRtcAec_ProcessFrames(AecCore* aec,
// which should be investigated. Maybe, allow for a non-symmetric
// rounding, like -16.
int move_elements = (aec->knownDelay - knownDelay - 32) / PART_LEN;
- int moved_elements = WebRtc_MoveReadPtr(aec->far_buf, move_elements);
- WebRtc_MoveReadPtr(aec->far_buf_windowed, move_elements);
+ int moved_elements =
+ MoveFarReadPtrWithoutSystemDelayUpdate(aec, move_elements);
aec->knownDelay -= moved_elements * PART_LEN;
- #ifdef WEBRTC_AEC_DEBUG_DUMP
- WebRtc_MoveReadPtr(aec->far_time_buf, move_elements);
- #endif
} else {
// 2 b) Apply signal based delay correction.
int move_elements = SignalBasedDelayCorrection(aec);
- int moved_elements = WebRtc_MoveReadPtr(aec->far_buf, move_elements);
- WebRtc_MoveReadPtr(aec->far_buf_windowed, move_elements);
- #ifdef WEBRTC_AEC_DEBUG_DUMP
- WebRtc_MoveReadPtr(aec->far_time_buf, move_elements);
- #endif
+ int moved_elements =
+ MoveFarReadPtrWithoutSystemDelayUpdate(aec, move_elements);
+ int far_near_buffer_diff = WebRtc_available_read(aec->far_buf) -
+ WebRtc_available_read(aec->nearFrBuf) / PART_LEN;
WebRtc_SoftResetDelayEstimator(aec->delay_estimator, moved_elements);
WebRtc_SoftResetDelayEstimatorFarend(aec->delay_estimator_farend,
moved_elements);
aec->signal_delay_correction += moved_elements;
- // TODO(bjornv): Investigate if this is reasonable. I had to add this
- // guard when the signal based delay correction replaces the system based
- // one. Otherwise there was a buffer underrun in the "qa-new/01/"
- // recording when adding 44 ms extra delay. This was not seen if we kept
- // both delay correction algorithms running in parallel.
- // A first investigation showed that we have a drift in this case that
- // causes the buffer underrun. Compared to when delay correction was
- // turned off, we get buffer underrun as well which was triggered in 1)
- // above. In addition there was a shift in |knownDelay| later increasing
- // the buffer. When running in parallel, this if statement was not
- // triggered. This suggests two alternatives; (a) use both algorithms, or
- // (b) allow for smaller delay corrections when we operate close to the
- // buffer limit. At the time of testing we required a change of 6 blocks,
- // but could change it to, e.g., 2 blocks. It requires some testing
- // though.
- if ((int)WebRtc_available_read(aec->far_buf) < (aec->mult + 1)) {
- // We don't have enough data so we stuff the far-end buffers.
- WebRtcAec_MoveFarReadPtr(aec, -(aec->mult + 1));
+ // If we rely on reported system delay values only, a buffer underrun here
+ // can never occur since we've taken care of that in 1) above. Here, we
+ // apply signal based delay correction and can therefore end up with
+ // buffer underruns since the delay estimation can be wrong. We therefore
+ // stuff the buffer with enough elements if needed.
+ if (far_near_buffer_diff < 0) {
+ WebRtcAec_MoveFarReadPtr(aec, far_near_buffer_diff);
}
}
diff --git a/chromium/third_party/webrtc/modules/audio_processing/aec/aec_core_internal.h b/chromium/third_party/webrtc/modules/audio_processing/aec/aec_core_internal.h
index bdb90413a7d..2f795896f51 100644
--- a/chromium/third_party/webrtc/modules/audio_processing/aec/aec_core_internal.h
+++ b/chromium/third_party/webrtc/modules/audio_processing/aec/aec_core_internal.h
@@ -142,6 +142,7 @@ struct AecCore {
int delay_correction_count;
int shift_offset;
float delay_quality_threshold;
+ int frame_count;
// 0 = reported delay mode disabled (signal based delay correction enabled).
// otherwise enabled
diff --git a/chromium/third_party/webrtc/modules/audio_processing/aec/echo_cancellation.c b/chromium/third_party/webrtc/modules/audio_processing/aec/echo_cancellation.c
index 54ac24dcf43..733dee0db9a 100644
--- a/chromium/third_party/webrtc/modules/audio_processing/aec/echo_cancellation.c
+++ b/chromium/third_party/webrtc/modules/audio_processing/aec/echo_cancellation.c
@@ -242,7 +242,10 @@ int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) {
aecpc->checkBuffSize = 1;
aecpc->firstVal = 0;
- aecpc->startup_phase = WebRtcAec_reported_delay_enabled(aecpc->aec);
+ // We skip the startup_phase completely (setting to 0) if DA-AEC is enabled,
+ // but not extended_filter mode.
+ aecpc->startup_phase = WebRtcAec_delay_correction_enabled(aecpc->aec) ||
+ WebRtcAec_reported_delay_enabled(aecpc->aec);
aecpc->bufSizeStart = 0;
aecpc->checkBufSizeCtr = 0;
aecpc->msInSndCardBuf = 0;
@@ -725,9 +728,7 @@ static int ProcessNormal(Aec* aecpc,
}
} else {
// AEC is enabled.
- if (WebRtcAec_reported_delay_enabled(aecpc->aec)) {
- EstBufDelayNormal(aecpc);
- }
+ EstBufDelayNormal(aecpc);
// Call the AEC.
// TODO(bjornv): Re-structure such that we don't have to pass
@@ -789,12 +790,13 @@ static void ProcessExtended(Aec* self,
// measurement.
int startup_size_ms =
reported_delay_ms < kFixedDelayMs ? kFixedDelayMs : reported_delay_ms;
+#if defined(WEBRTC_ANDROID)
int target_delay = startup_size_ms * self->rate_factor * 8;
-#if !defined(WEBRTC_ANDROID)
+#else
// To avoid putting the AEC in a non-causal state we're being slightly
// conservative and scale by 2. On Android we use a fixed delay and
// therefore there is no need to scale the target_delay.
- target_delay /= 2;
+ int target_delay = startup_size_ms * self->rate_factor * 8 / 2;
#endif
int overhead_elements =
(WebRtcAec_system_delay(self->aec) - target_delay) / PART_LEN;
@@ -802,9 +804,7 @@ static void ProcessExtended(Aec* self,
self->startup_phase = 0;
}
- if (WebRtcAec_reported_delay_enabled(self->aec)) {
- EstBufDelayExtended(self);
- }
+ EstBufDelayExtended(self);
{
// |delay_diff_offset| gives us the option to manually rewind the delay on
diff --git a/chromium/third_party/webrtc/modules/audio_processing/aec/system_delay_unittest.cc b/chromium/third_party/webrtc/modules/audio_processing/aec/system_delay_unittest.cc
index da28752bcc4..259b0759c8c 100644
--- a/chromium/third_party/webrtc/modules/audio_processing/aec/system_delay_unittest.cc
+++ b/chromium/third_party/webrtc/modules/audio_processing/aec/system_delay_unittest.cc
@@ -40,7 +40,7 @@ class SystemDelayTest : public ::testing::Test {
// Maps buffer size in ms into samples, taking the unprocessed frame into
// account.
- int MapBufferSizeToSamples(int size_in_ms);
+ int MapBufferSizeToSamples(int size_in_ms, bool extended_filter);
void* handle_;
Aec* self_;
@@ -98,6 +98,7 @@ static const int kMaxConvergenceMs = 500;
void SystemDelayTest::Init(int sample_rate_hz) {
// Initialize AEC
EXPECT_EQ(0, WebRtcAec_Init(handle_, sample_rate_hz, 48000));
+ EXPECT_EQ(0, WebRtcAec_system_delay(self_->aec));
// One frame equals 10 ms of data.
samples_per_frame_ = sample_rate_hz / 100;
@@ -133,26 +134,38 @@ void SystemDelayTest::RunStableStartup() {
// up the far-end buffer with the same amount as we will report in through
// Process().
int buffer_size = BufferFillUp();
- // A stable device should be accepted and put in a regular process mode within
- // |kStableConvergenceMs|.
- int process_time_ms = 0;
- for (; process_time_ms < kStableConvergenceMs; process_time_ms += 10) {
+
+ if (WebRtcAec_reported_delay_enabled(self_->aec) == 0) {
+ // In extended_filter mode we set the buffer size after the first processed
+ // 10 ms chunk. Hence, we don't need to wait for the reported system delay
+ // values to become stable.
RenderAndCapture(kDeviceBufMs);
buffer_size += samples_per_frame_;
- if (self_->startup_phase == 0) {
- // We have left the startup phase.
- break;
+ EXPECT_EQ(0, self_->startup_phase);
+ } else {
+ // A stable device should be accepted and put in a regular process mode
+ // within |kStableConvergenceMs|.
+ int process_time_ms = 0;
+ for (; process_time_ms < kStableConvergenceMs; process_time_ms += 10) {
+ RenderAndCapture(kDeviceBufMs);
+ buffer_size += samples_per_frame_;
+ if (self_->startup_phase == 0) {
+ // We have left the startup phase.
+ break;
+ }
}
+ // Verify convergence time.
+ EXPECT_GT(kStableConvergenceMs, process_time_ms);
}
- // Verify convergence time.
- EXPECT_GT(kStableConvergenceMs, process_time_ms);
// Verify that the buffer has been flushed.
EXPECT_GE(buffer_size, WebRtcAec_system_delay(self_->aec));
}
-int SystemDelayTest::MapBufferSizeToSamples(int size_in_ms) {
- // The extra 10 ms corresponds to the unprocessed frame.
- return (size_in_ms + 10) * samples_per_frame_ / 10;
+ int SystemDelayTest::MapBufferSizeToSamples(int size_in_ms,
+ bool extended_filter) {
+ // If extended_filter is disabled we add an extra 10 ms for the unprocessed
+ // frame. That is simply how the algorithm is constructed.
+ return (size_in_ms + (extended_filter ? 0 : 10)) * samples_per_frame_ / 10;
}
// The tests should meet basic requirements and not be adjusted to what is
@@ -179,14 +192,23 @@ int SystemDelayTest::MapBufferSizeToSamples(int size_in_ms) {
TEST_F(SystemDelayTest, CorrectIncreaseWhenBufferFarend) {
// When we add data to the AEC buffer the internal system delay should be
// incremented with the same amount as the size of data.
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
-
- // Loop through a couple of calls to make sure the system delay increments
- // correctly.
- for (int j = 1; j <= 5; j++) {
- EXPECT_EQ(0, WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_));
- EXPECT_EQ(j * samples_per_frame_, WebRtcAec_system_delay(self_->aec));
+ // This process should be independent of DA-AEC and extended_filter mode.
+ for (int extended_filter = 0; extended_filter <= 1; ++extended_filter) {
+ WebRtcAec_enable_delay_correction(self_->aec, extended_filter);
+ EXPECT_EQ(extended_filter, WebRtcAec_delay_correction_enabled(self_->aec));
+ for (int da_aec = 0; da_aec <= 1; ++da_aec) {
+ WebRtcAec_enable_reported_delay(self_->aec, 1 - da_aec);
+ EXPECT_EQ(1 - da_aec, WebRtcAec_reported_delay_enabled(self_->aec));
+ for (size_t i = 0; i < kNumSampleRates; i++) {
+ Init(kSampleRateHz[i]);
+ // Loop through a couple of calls to make sure the system delay
+ // increments correctly.
+ for (int j = 1; j <= 5; j++) {
+ EXPECT_EQ(0,
+ WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_));
+ EXPECT_EQ(j * samples_per_frame_, WebRtcAec_system_delay(self_->aec));
+ }
+ }
}
}
}
@@ -197,21 +219,42 @@ TEST_F(SystemDelayTest, CorrectIncreaseWhenBufferFarend) {
TEST_F(SystemDelayTest, CorrectDelayAfterStableStartup) {
// We run the system in a stable startup. After that we verify that the system
// delay meets the requirements.
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
- RunStableStartup();
-
- // Verify system delay with respect to requirements, i.e., the
- // |system_delay| is in the interval [75%, 100%] of what's reported on the
- // average.
- int average_reported_delay = kDeviceBufMs * samples_per_frame_ / 10;
- EXPECT_GE(average_reported_delay, WebRtcAec_system_delay(self_->aec));
- EXPECT_LE(average_reported_delay * 3 / 4,
- WebRtcAec_system_delay(self_->aec));
+ // This process should be independent of DA-AEC and extended_filter mode.
+ for (int extended_filter = 0; extended_filter <= 1; ++extended_filter) {
+ WebRtcAec_enable_delay_correction(self_->aec, extended_filter);
+ EXPECT_EQ(extended_filter, WebRtcAec_delay_correction_enabled(self_->aec));
+ for (int da_aec = 0; da_aec <= 1; ++da_aec) {
+ WebRtcAec_enable_reported_delay(self_->aec, 1 - da_aec);
+ EXPECT_EQ(1 - da_aec, WebRtcAec_reported_delay_enabled(self_->aec));
+ for (size_t i = 0; i < kNumSampleRates; i++) {
+ Init(kSampleRateHz[i]);
+ RunStableStartup();
+
+ // Verify system delay with respect to requirements, i.e., the
+ // |system_delay| is in the interval [75%, 100%] of what's reported on
+ // the average.
+ // In extended_filter mode we target 50% and measure after one processed
+ // 10 ms chunk.
+ int average_reported_delay = kDeviceBufMs * samples_per_frame_ / 10;
+ EXPECT_GE(average_reported_delay, WebRtcAec_system_delay(self_->aec));
+ int lower_bound = WebRtcAec_delay_correction_enabled(self_->aec)
+ ? average_reported_delay / 2 - samples_per_frame_
+ : average_reported_delay * 3 / 4;
+ EXPECT_LE(lower_bound, WebRtcAec_system_delay(self_->aec));
+ }
+ }
}
}
TEST_F(SystemDelayTest, CorrectDelayAfterUnstableStartup) {
+ // This test does not apply in extended_filter mode, since we only use the
+ // the first 10 ms chunk to determine a reasonable buffer size. Neither does
+ // it apply if DA-AEC is on because that overrides the startup procedure.
+ WebRtcAec_enable_delay_correction(self_->aec, 0);
+ EXPECT_EQ(0, WebRtcAec_delay_correction_enabled(self_->aec));
+ WebRtcAec_enable_reported_delay(self_->aec, 1);
+ EXPECT_EQ(1, WebRtcAec_reported_delay_enabled(self_->aec));
+
// In an unstable system we would start processing after |kMaxConvergenceMs|.
// On the last frame the AEC buffer is adjusted to 60% of the last reported
// device buffer size.
@@ -252,15 +295,19 @@ TEST_F(SystemDelayTest, CorrectDelayAfterUnstableStartup) {
}
}
-TEST_F(SystemDelayTest,
- DISABLED_ON_ANDROID(CorrectDelayAfterStableBufferBuildUp)) {
+TEST_F(SystemDelayTest, CorrectDelayAfterStableBufferBuildUp) {
+ // This test does not apply in extended_filter mode, since we only use the
+ // the first 10 ms chunk to determine a reasonable buffer size. Neither does
+ // it apply if DA-AEC is on because that overrides the startup procedure.
+ WebRtcAec_enable_delay_correction(self_->aec, 0);
+ EXPECT_EQ(0, WebRtcAec_delay_correction_enabled(self_->aec));
+ WebRtcAec_enable_reported_delay(self_->aec, 1);
+ EXPECT_EQ(1, WebRtcAec_reported_delay_enabled(self_->aec));
+
// In this test we start by establishing the device buffer size during stable
// conditions, but with an empty internal far-end buffer. Once that is done we
// verify that the system delay is increased correctly until we have reach an
// internal buffer size of 75% of what's been reported.
-
- // This test assumes the reported delays are used.
- WebRtcAec_enable_reported_delay(WebRtcAec_aec_core(handle_), 1);
for (size_t i = 0; i < kNumSampleRates; i++) {
Init(kSampleRateHz[i]);
@@ -314,62 +361,73 @@ TEST_F(SystemDelayTest, CorrectDelayWhenBufferUnderrun) {
// WebRtcAec_Process() we will finally run out of data, but should
// automatically stuff the buffer. We verify this behavior by checking if the
// system delay goes negative.
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
- RunStableStartup();
-
- // The AEC has now left the Startup phase. We now have at most
- // |kStableConvergenceMs| in the buffer. Keep on calling Process() until
- // we run out of data and verify that the system delay is non-negative.
- for (int j = 0; j <= kStableConvergenceMs; j += 10) {
- EXPECT_EQ(0,
- WebRtcAec_Process(handle_,
- &near_ptr_,
- 1,
- &out_ptr_,
- samples_per_frame_,
- kDeviceBufMs,
- 0));
- EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
+ // This process should be independent of DA-AEC and extended_filter mode.
+ for (int extended_filter = 0; extended_filter <= 1; ++extended_filter) {
+ WebRtcAec_enable_delay_correction(self_->aec, extended_filter);
+ EXPECT_EQ(extended_filter, WebRtcAec_delay_correction_enabled(self_->aec));
+ for (int da_aec = 0; da_aec <= 1; ++da_aec) {
+ WebRtcAec_enable_reported_delay(self_->aec, 1 - da_aec);
+ EXPECT_EQ(1 - da_aec, WebRtcAec_reported_delay_enabled(self_->aec));
+ for (size_t i = 0; i < kNumSampleRates; i++) {
+ Init(kSampleRateHz[i]);
+ RunStableStartup();
+
+ // The AEC has now left the Startup phase. We now have at most
+ // |kStableConvergenceMs| in the buffer. Keep on calling Process() until
+ // we run out of data and verify that the system delay is non-negative.
+ for (int j = 0; j <= kStableConvergenceMs; j += 10) {
+ EXPECT_EQ(0, WebRtcAec_Process(handle_, &near_ptr_, 1, &out_ptr_,
+ samples_per_frame_, kDeviceBufMs, 0));
+ EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
+ }
+ }
}
}
}
-TEST_F(SystemDelayTest, DISABLED_ON_ANDROID(CorrectDelayDuringDrift)) {
+TEST_F(SystemDelayTest, CorrectDelayDuringDrift) {
// This drift test should verify that the system delay is never exceeding the
// device buffer. The drift is simulated by decreasing the reported device
// buffer size by 1 ms every 100 ms. If the device buffer size goes below 30
// ms we jump (add) 10 ms to give a repeated pattern.
- // This test assumes the reported delays are used.
- WebRtcAec_enable_reported_delay(WebRtcAec_aec_core(handle_), 1);
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
- RunStableStartup();
-
- // We have now left the startup phase and proceed with normal processing.
- int jump = 0;
- for (int j = 0; j < 1000; j++) {
- // Drift = -1 ms per 100 ms of data.
- int device_buf_ms = kDeviceBufMs - (j / 10) + jump;
- int device_buf = MapBufferSizeToSamples(device_buf_ms);
-
- if (device_buf_ms < 30) {
- // Add 10 ms data, taking affect next frame.
- jump += 10;
+ // This process should be independent of DA-AEC and extended_filter mode.
+ for (int extended_filter = 0; extended_filter <= 1; ++extended_filter) {
+ WebRtcAec_enable_delay_correction(self_->aec, extended_filter);
+ EXPECT_EQ(extended_filter, WebRtcAec_delay_correction_enabled(self_->aec));
+ for (int da_aec = 0; da_aec <= 1; ++da_aec) {
+ WebRtcAec_enable_reported_delay(self_->aec, 1 - da_aec);
+ EXPECT_EQ(1 - da_aec, WebRtcAec_reported_delay_enabled(self_->aec));
+ for (size_t i = 0; i < kNumSampleRates; i++) {
+ Init(kSampleRateHz[i]);
+ RunStableStartup();
+
+ // We have left the startup phase and proceed with normal processing.
+ int jump = 0;
+ for (int j = 0; j < 1000; j++) {
+ // Drift = -1 ms per 100 ms of data.
+ int device_buf_ms = kDeviceBufMs - (j / 10) + jump;
+ int device_buf = MapBufferSizeToSamples(device_buf_ms,
+ extended_filter == 1);
+
+ if (device_buf_ms < 30) {
+ // Add 10 ms data, taking affect next frame.
+ jump += 10;
+ }
+ RenderAndCapture(device_buf_ms);
+
+ // Verify that the system delay does not exceed the device buffer.
+ EXPECT_GE(device_buf, WebRtcAec_system_delay(self_->aec));
+
+ // Verify that the system delay is non-negative.
+ EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
+ }
}
- RenderAndCapture(device_buf_ms);
-
- // Verify that the system delay does not exceed the device buffer.
- EXPECT_GE(device_buf, WebRtcAec_system_delay(self_->aec));
-
- // Verify that the system delay is non-negative.
- EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
}
}
}
-TEST_F(SystemDelayTest, DISABLED_ON_ANDROID(ShouldRecoverAfterGlitch)) {
+TEST_F(SystemDelayTest, ShouldRecoverAfterGlitch) {
// This glitch test should verify that the system delay recovers if there is
// a glitch in data. The data glitch is constructed as 200 ms of buffering
// after which the stable procedure continues. The glitch is never reported by
@@ -377,79 +435,100 @@ TEST_F(SystemDelayTest, DISABLED_ON_ANDROID(ShouldRecoverAfterGlitch)) {
// The system is said to be in a non-causal state if the difference between
// the device buffer and system delay is less than a block (64 samples).
- // This test assumes the reported delays are used.
- WebRtcAec_enable_reported_delay(WebRtcAec_aec_core(handle_), 1);
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
- RunStableStartup();
- int device_buf = MapBufferSizeToSamples(kDeviceBufMs);
- // Glitch state.
- for (int j = 0; j < 20; j++) {
- EXPECT_EQ(0, WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_));
- // No need to verify system delay, since that is done in a separate test.
- }
- // Verify that we are in a non-causal state, i.e.,
- // |system_delay| > |device_buf|.
- EXPECT_LT(device_buf, WebRtcAec_system_delay(self_->aec));
-
- // Recover state. Should recover at least 4 ms of data per 10 ms, hence a
- // glitch of 200 ms will take at most 200 * 10 / 4 = 500 ms to recover from.
- bool non_causal = true; // We are currently in a non-causal state.
- for (int j = 0; j < 50; j++) {
- int system_delay_before = WebRtcAec_system_delay(self_->aec);
- RenderAndCapture(kDeviceBufMs);
- int system_delay_after = WebRtcAec_system_delay(self_->aec);
-
- // We have recovered if |device_buf| - |system_delay_after| >= 64 (one
- // block). During recovery |system_delay_after| < |system_delay_before|,
- // otherwise they are equal.
- if (non_causal) {
- EXPECT_LT(system_delay_after, system_delay_before);
- if (device_buf - system_delay_after >= 64) {
- non_causal = false;
+ // This process should be independent of DA-AEC and extended_filter mode.
+ for (int extended_filter = 0; extended_filter <= 1; ++extended_filter) {
+ WebRtcAec_enable_delay_correction(self_->aec, extended_filter);
+ EXPECT_EQ(extended_filter, WebRtcAec_delay_correction_enabled(self_->aec));
+ for (int da_aec = 0; da_aec <= 1; ++da_aec) {
+ WebRtcAec_enable_reported_delay(self_->aec, 1 - da_aec);
+ EXPECT_EQ(1 - da_aec, WebRtcAec_reported_delay_enabled(self_->aec));
+ for (size_t i = 0; i < kNumSampleRates; i++) {
+ Init(kSampleRateHz[i]);
+ RunStableStartup();
+ int device_buf = MapBufferSizeToSamples(kDeviceBufMs,
+ extended_filter == 1);
+ // Glitch state.
+ for (int j = 0; j < 20; j++) {
+ EXPECT_EQ(0,
+ WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_));
+ // No need to verify system delay, since that is done in a separate
+ // test.
}
- } else {
- EXPECT_EQ(system_delay_before, system_delay_after);
+ // Verify that we are in a non-causal state, i.e.,
+ // |system_delay| > |device_buf|.
+ EXPECT_LT(device_buf, WebRtcAec_system_delay(self_->aec));
+
+ // Recover state. Should recover at least 4 ms of data per 10 ms, hence
+ // a glitch of 200 ms will take at most 200 * 10 / 4 = 500 ms to recover
+ // from.
+ bool non_causal = true; // We are currently in a non-causal state.
+ for (int j = 0; j < 50; j++) {
+ int system_delay_before = WebRtcAec_system_delay(self_->aec);
+ RenderAndCapture(kDeviceBufMs);
+ int system_delay_after = WebRtcAec_system_delay(self_->aec);
+ // We have recovered if
+ // |device_buf| - |system_delay_after| >= PART_LEN (1 block).
+ // During recovery, |system_delay_after| < |system_delay_before|,
+ // otherwise they are equal.
+ if (non_causal) {
+ EXPECT_LT(system_delay_after, system_delay_before);
+ if (device_buf - system_delay_after >= PART_LEN) {
+ non_causal = false;
+ }
+ } else {
+ EXPECT_EQ(system_delay_before, system_delay_after);
+ }
+ // Verify that the system delay is non-negative.
+ EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
+ }
+ // Check that we have recovered.
+ EXPECT_FALSE(non_causal);
}
- // Verify that the system delay is non-negative.
- EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
}
- // Check that we have recovered.
- EXPECT_FALSE(non_causal);
}
}
TEST_F(SystemDelayTest, UnaffectedWhenSpuriousDeviceBufferValues) {
- // This spurious device buffer data test aims at verifying that the system
- // delay is unaffected by large outliers.
- // The system is said to be in a non-causal state if the difference between
- // the device buffer and system delay is less than a block (64 samples).
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
- RunStableStartup();
- int device_buf = MapBufferSizeToSamples(kDeviceBufMs);
-
- // Normal state. We are currently not in a non-causal state.
- bool non_causal = false;
-
- // Run 1 s and replace device buffer size with 500 ms every 100 ms.
- for (int j = 0; j < 100; j++) {
- int system_delay_before_calls = WebRtcAec_system_delay(self_->aec);
- int device_buf_ms = kDeviceBufMs;
- if (j % 10 == 0) {
- device_buf_ms = 500;
- }
- RenderAndCapture(device_buf_ms);
+ // This test does not apply in extended_filter mode, since we only use the
+ // the first 10 ms chunk to determine a reasonable buffer size.
+ const int extended_filter = 0;
+ WebRtcAec_enable_delay_correction(self_->aec, extended_filter);
+ EXPECT_EQ(extended_filter, WebRtcAec_delay_correction_enabled(self_->aec));
+
+ // Should be DA-AEC independent.
+ for (int da_aec = 0; da_aec <= 1; ++da_aec) {
+ WebRtcAec_enable_reported_delay(self_->aec, 1 - da_aec);
+ EXPECT_EQ(1 - da_aec, WebRtcAec_reported_delay_enabled(self_->aec));
+ // This spurious device buffer data test aims at verifying that the system
+ // delay is unaffected by large outliers.
+ // The system is said to be in a non-causal state if the difference between
+ // the device buffer and system delay is less than a block (64 samples).
+ for (size_t i = 0; i < kNumSampleRates; i++) {
+ Init(kSampleRateHz[i]);
+ RunStableStartup();
+ int device_buf = MapBufferSizeToSamples(kDeviceBufMs,
+ extended_filter == 1);
+
+ // Normal state. We are currently not in a non-causal state.
+ bool non_causal = false;
+
+ // Run 1 s and replace device buffer size with 500 ms every 100 ms.
+ for (int j = 0; j < 100; j++) {
+ int system_delay_before_calls = WebRtcAec_system_delay(self_->aec);
+ int device_buf_ms = j % 10 == 0 ? 500 : kDeviceBufMs;
+ RenderAndCapture(device_buf_ms);
+
+ // Check for non-causality.
+ if (device_buf - WebRtcAec_system_delay(self_->aec) < PART_LEN) {
+ non_causal = true;
+ }
+ EXPECT_FALSE(non_causal);
+ EXPECT_EQ(system_delay_before_calls,
+ WebRtcAec_system_delay(self_->aec));
- // Check for non-causality.
- if (device_buf - WebRtcAec_system_delay(self_->aec) < 64) {
- non_causal = true;
+ // Verify that the system delay is non-negative.
+ EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
}
- EXPECT_FALSE(non_causal);
- EXPECT_EQ(system_delay_before_calls, WebRtcAec_system_delay(self_->aec));
-
- // Verify that the system delay is non-negative.
- EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
}
}
}
@@ -460,36 +539,54 @@ TEST_F(SystemDelayTest, CorrectImpactWhenTogglingDeviceBufferValues) {
// The test is constructed such that every other device buffer value is zero
// and then 2 * |kDeviceBufMs|, hence the size is constant on the average. The
// zero values will force us into a non-causal state and thereby lowering the
- // system delay until we basically runs out of data. Once that happens the
+ // system delay until we basically run out of data. Once that happens the
// buffer will be stuffed.
// TODO(bjornv): This test will have a better impact if we verified that the
- // delay estimate goes up when the system delay goes done to meet the average
+ // delay estimate goes up when the system delay goes down to meet the average
// device buffer size.
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
- RunStableStartup();
- int device_buf = MapBufferSizeToSamples(kDeviceBufMs);
-
- // Normal state. We are currently not in a non-causal state.
- bool non_causal = false;
-
- // Loop through 100 frames (both render and capture), which equals 1 s of
- // data. Every odd frame we set the device buffer size to 2 * |kDeviceBufMs|
- // and even frames we set the device buffer size to zero.
- for (int j = 0; j < 100; j++) {
- int system_delay_before_calls = WebRtcAec_system_delay(self_->aec);
- int device_buf_ms = 2 * (j % 2) * kDeviceBufMs;
- RenderAndCapture(device_buf_ms);
- // Check for non-causality, compared with the average device buffer size.
- non_causal |= (device_buf - WebRtcAec_system_delay(self_->aec) < 64);
- EXPECT_GE(system_delay_before_calls, WebRtcAec_system_delay(self_->aec));
-
- // Verify that the system delay is non-negative.
- EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
+ // This test does not apply if DA-AEC is enabled and extended_filter mode
+ // disabled.
+ for (int extended_filter = 0; extended_filter <= 1; ++extended_filter) {
+ WebRtcAec_enable_delay_correction(self_->aec, extended_filter);
+ EXPECT_EQ(extended_filter, WebRtcAec_delay_correction_enabled(self_->aec));
+ for (int da_aec = 0; da_aec <= 1; ++da_aec) {
+ WebRtcAec_enable_reported_delay(self_->aec, 1 - da_aec);
+ EXPECT_EQ(1 - da_aec, WebRtcAec_reported_delay_enabled(self_->aec));
+ if (extended_filter == 0 && da_aec == 1) {
+ continue;
+ }
+ for (size_t i = 0; i < kNumSampleRates; i++) {
+ Init(kSampleRateHz[i]);
+ RunStableStartup();
+ const int device_buf = MapBufferSizeToSamples(kDeviceBufMs,
+ extended_filter == 1);
+
+ // Normal state. We are currently not in a non-causal state.
+ bool non_causal = false;
+
+ // Loop through 100 frames (both render and capture), which equals 1 s
+ // of data. Every odd frame we set the device buffer size to
+ // 2 * |kDeviceBufMs| and even frames we set the device buffer size to
+ // zero.
+ for (int j = 0; j < 100; j++) {
+ int system_delay_before_calls = WebRtcAec_system_delay(self_->aec);
+ int device_buf_ms = 2 * (j % 2) * kDeviceBufMs;
+ RenderAndCapture(device_buf_ms);
+
+ // Check for non-causality, compared with the average device buffer
+ // size.
+ non_causal |= (device_buf - WebRtcAec_system_delay(self_->aec) < 64);
+ EXPECT_GE(system_delay_before_calls,
+ WebRtcAec_system_delay(self_->aec));
+
+ // Verify that the system delay is non-negative.
+ EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
+ }
+ // Verify we are not in a non-causal state.
+ EXPECT_FALSE(non_causal);
+ }
}
- // Verify we are not in a non-causal state.
- EXPECT_FALSE(non_causal);
}
}
diff --git a/chromium/third_party/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.cc b/chromium/third_party/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.cc
index 9d9550b0b1b..cf46ca9c333 100644
--- a/chromium/third_party/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.cc
+++ b/chromium/third_party/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.cc
@@ -81,11 +81,16 @@ int32_t FecReceiverImpl::AddReceivedRedPacket(
uint8_t REDHeaderLength = 1;
size_t payload_data_length = packet_length - header.headerLength;
+ if (payload_data_length == 0) {
+ LOG(LS_WARNING) << "Corrupt/truncated FEC packet.";
+ return -1;
+ }
+
// Add to list without RED header, aka a virtual RTP packet
// we remove the RED header
- ForwardErrorCorrection::ReceivedPacket* received_packet =
- new ForwardErrorCorrection::ReceivedPacket;
+ rtc::scoped_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet(
+ new ForwardErrorCorrection::ReceivedPacket);
received_packet->pkt = new ForwardErrorCorrection::Packet;
// get payload type from RED header
@@ -99,16 +104,18 @@ int32_t FecReceiverImpl::AddReceivedRedPacket(
if (incoming_rtp_packet[header.headerLength] & 0x80) {
// f bit set in RED header
REDHeaderLength = 4;
+ if (payload_data_length < REDHeaderLength + 1u) {
+ LOG(LS_WARNING) << "Corrupt/truncated FEC packet.";
+ return -1;
+ }
+
uint16_t timestamp_offset =
(incoming_rtp_packet[header.headerLength + 1]) << 8;
timestamp_offset +=
incoming_rtp_packet[header.headerLength + 2];
timestamp_offset = timestamp_offset >> 2;
if (timestamp_offset != 0) {
- // |timestampOffset| should be 0. However, it's possible this is the first
- // location a corrupt payload can be caught, so don't assert.
LOG(LS_WARNING) << "Corrupt payload found.";
- delete received_packet;
return -1;
}
@@ -118,21 +125,20 @@ int32_t FecReceiverImpl::AddReceivedRedPacket(
// check next RED header
if (incoming_rtp_packet[header.headerLength + 4] & 0x80) {
- // more than 2 blocks in packet not supported
- delete received_packet;
- assert(false);
+ LOG(LS_WARNING) << "More than 2 blocks in packet not supported.";
return -1;
}
- if (blockLength > payload_data_length - REDHeaderLength) {
- // block length longer than packet
- delete received_packet;
- assert(false);
+ // Check that the packet is long enough to contain data in the following
+ // block.
+ if (blockLength > payload_data_length - (REDHeaderLength + 1)) {
+ LOG(LS_WARNING) << "Block length longer than packet.";
return -1;
}
}
++packet_counter_.num_packets;
- ForwardErrorCorrection::ReceivedPacket* second_received_packet = NULL;
+ rtc::scoped_ptr<ForwardErrorCorrection::ReceivedPacket>
+ second_received_packet;
if (blockLength > 0) {
// handle block length, split into 2 packets
REDHeaderLength = 5;
@@ -154,7 +160,7 @@ int32_t FecReceiverImpl::AddReceivedRedPacket(
received_packet->pkt->length = blockLength;
- second_received_packet = new ForwardErrorCorrection::ReceivedPacket;
+ second_received_packet.reset(new ForwardErrorCorrection::ReceivedPacket);
second_received_packet->pkt = new ForwardErrorCorrection::Packet;
second_received_packet->is_fec = true;
@@ -202,14 +208,12 @@ int32_t FecReceiverImpl::AddReceivedRedPacket(
}
if (received_packet->pkt->length == 0) {
- delete second_received_packet;
- delete received_packet;
return 0;
}
- received_packet_list_.push_back(received_packet);
+ received_packet_list_.push_back(received_packet.release());
if (second_received_packet) {
- received_packet_list_.push_back(second_received_packet);
+ received_packet_list_.push_back(second_received_packet.release());
}
return 0;
}
diff --git a/chromium/third_party/webrtc/modules/rtp_rtcp/source/fec_receiver_unittest.cc b/chromium/third_party/webrtc/modules/rtp_rtcp/source/fec_receiver_unittest.cc
index 31baf4e767a..f64b537a522 100644
--- a/chromium/third_party/webrtc/modules/rtp_rtcp/source/fec_receiver_unittest.cc
+++ b/chromium/third_party/webrtc/modules/rtp_rtcp/source/fec_receiver_unittest.cc
@@ -16,7 +16,9 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/rtp_rtcp/interface/fec_receiver.h"
+#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/fec_test_helper.h"
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
@@ -81,6 +83,11 @@ class ReceiverFecTest : public ::testing::Test {
delete red_packet;
}
+ void InjectGarbagePacketLength(size_t fec_garbage_offset);
+ static void SurvivesMaliciousPacket(const uint8_t* data,
+ size_t length,
+ uint8_t ulpfec_payload_type);
+
MockRtpData rtp_data_callback_;
rtc::scoped_ptr<ForwardErrorCorrection> fec_;
rtc::scoped_ptr<FecReceiver> receiver_fec_;
@@ -104,8 +111,7 @@ TEST_F(ReceiverFecTest, TwoMediaOneFec) {
// Recovery
std::list<RtpPacket*>::iterator it = media_rtp_packets.begin();
- std::list<RtpPacket*>::iterator media_it = media_rtp_packets.begin();
- BuildAndAddRedMediaPacket(*media_it);
+ BuildAndAddRedMediaPacket(*it);
VerifyReconstructedMediaPacket(*it, 1);
EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
// Drop one media packet.
@@ -123,6 +129,44 @@ TEST_F(ReceiverFecTest, TwoMediaOneFec) {
DeletePackets(&media_packets);
}
+void ReceiverFecTest::InjectGarbagePacketLength(size_t fec_garbage_offset) {
+ EXPECT_CALL(rtp_data_callback_, OnRecoveredPacket(_, _))
+ .WillRepeatedly(Return(true));
+
+ const unsigned int kNumFecPackets = 1u;
+ std::list<RtpPacket*> media_rtp_packets;
+ std::list<Packet*> media_packets;
+ GenerateFrame(2, 0, &media_rtp_packets, &media_packets);
+ std::list<Packet*> fec_packets;
+ GenerateFEC(&media_packets, &fec_packets, kNumFecPackets);
+ ByteWriter<uint16_t>::WriteBigEndian(
+ &fec_packets.front()->data[fec_garbage_offset], 0x4711);
+
+ // Inject first media packet, then first FEC packet, skipping the second media
+ // packet to cause a recovery from the FEC packet.
+ BuildAndAddRedMediaPacket(media_rtp_packets.front());
+ BuildAndAddRedFecPacket(fec_packets.front());
+ EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+
+ FecPacketCounter counter = receiver_fec_->GetPacketCounter();
+ EXPECT_EQ(2u, counter.num_packets);
+ EXPECT_EQ(1u, counter.num_fec_packets);
+ EXPECT_EQ(0u, counter.num_recovered_packets);
+
+ DeletePackets(&media_packets);
+}
+
+TEST_F(ReceiverFecTest, InjectGarbageFecHeaderLengthRecovery) {
+ // Byte offset 8 is the 'length recovery' field of the FEC header.
+ InjectGarbagePacketLength(8);
+}
+
+TEST_F(ReceiverFecTest, InjectGarbageFecLevelHeaderProtectionLength) {
+ // Byte offset 10 is the 'protection length' field in the first FEC level
+ // header.
+ InjectGarbagePacketLength(10);
+}
+
TEST_F(ReceiverFecTest, TwoMediaTwoFec) {
const unsigned int kNumFecPackets = 2u;
std::list<RtpPacket*> media_rtp_packets;
@@ -362,4 +406,132 @@ TEST_F(ReceiverFecTest, OldFecPacketDropped) {
DeletePackets(&media_packets);
}
+void ReceiverFecTest::SurvivesMaliciousPacket(const uint8_t* data,
+ size_t length,
+ uint8_t ulpfec_payload_type) {
+ webrtc::RTPHeader header;
+ rtc::scoped_ptr<webrtc::RtpHeaderParser> parser(
+ webrtc::RtpHeaderParser::Create());
+ ASSERT_TRUE(parser->Parse(data, length, &header));
+
+ webrtc::NullRtpData null_callback;
+ rtc::scoped_ptr<webrtc::FecReceiver> receiver_fec(
+ webrtc::FecReceiver::Create(&null_callback));
+
+ receiver_fec->AddReceivedRedPacket(header, data, length, ulpfec_payload_type);
+}
+
+TEST_F(ReceiverFecTest, TruncatedPacketWithFBitSet) {
+ const uint8_t kTruncatedPacket[] = {0x80,
+ 0x2a,
+ 0x68,
+ 0x71,
+ 0x29,
+ 0xa1,
+ 0x27,
+ 0x3a,
+ 0x29,
+ 0x12,
+ 0x2a,
+ 0x98,
+ 0xe0,
+ 0x29};
+
+ SurvivesMaliciousPacket(kTruncatedPacket, sizeof(kTruncatedPacket), 100);
+}
+
+TEST_F(ReceiverFecTest, TruncatedPacketWithFBitSetEndingAfterFirstRedHeader) {
+ const uint8_t kPacket[] = {0x89,
+ 0x27,
+ 0x3a,
+ 0x83,
+ 0x27,
+ 0x3a,
+ 0x3a,
+ 0xf3,
+ 0x67,
+ 0xbe,
+ 0x2a,
+ 0xa9,
+ 0x27,
+ 0x54,
+ 0x3a,
+ 0x3a,
+ 0x2a,
+ 0x67,
+ 0x3a,
+ 0xf3,
+ 0x67,
+ 0xbe,
+ 0x2a,
+ 0x27,
+ 0xe6,
+ 0xf6,
+ 0x03,
+ 0x3e,
+ 0x29,
+ 0x27,
+ 0x21,
+ 0x27,
+ 0x2a,
+ 0x29,
+ 0x21,
+ 0x4b,
+ 0x29,
+ 0x3a,
+ 0x28,
+ 0x29,
+ 0xbf,
+ 0x29,
+ 0x2a,
+ 0x26,
+ 0x29,
+ 0xae,
+ 0x27,
+ 0xa6,
+ 0xf6,
+ 0x00,
+ 0x03,
+ 0x3e};
+ SurvivesMaliciousPacket(kPacket, sizeof(kPacket), 100);
+}
+
+TEST_F(ReceiverFecTest, TruncatedPacketWithoutDataPastFirstBlock) {
+ const uint8_t kPacket[] = {0x82,
+ 0x38,
+ 0x92,
+ 0x38,
+ 0x92,
+ 0x38,
+ 0xde,
+ 0x2a,
+ 0x11,
+ 0xc8,
+ 0xa3,
+ 0xc4,
+ 0x82,
+ 0x38,
+ 0x2a,
+ 0x21,
+ 0x2a,
+ 0x28,
+ 0x92,
+ 0x38,
+ 0x92,
+ 0x00,
+ 0x00,
+ 0x0a,
+ 0x3a,
+ 0xc8,
+ 0xa3,
+ 0x3a,
+ 0x27,
+ 0xc4,
+ 0x2a,
+ 0x21,
+ 0x2a,
+ 0x28};
+ SurvivesMaliciousPacket(kPacket, sizeof(kPacket), 100);
+}
+
} // namespace webrtc
diff --git a/chromium/third_party/webrtc/modules/rtp_rtcp/source/forward_error_correction.cc b/chromium/third_party/webrtc/modules/rtp_rtcp/source/forward_error_correction.cc
index abef1dda302..fe62dbf25bf 100644
--- a/chromium/third_party/webrtc/modules/rtp_rtcp/source/forward_error_correction.cc
+++ b/chromium/third_party/webrtc/modules/rtp_rtcp/source/forward_error_correction.cc
@@ -634,23 +634,35 @@ void ForwardErrorCorrection::InsertPackets(
DiscardOldPackets(recovered_packet_list);
}
-void ForwardErrorCorrection::InitRecovery(const FecPacket* fec_packet,
+bool ForwardErrorCorrection::InitRecovery(const FecPacket* fec_packet,
RecoveredPacket* recovered) {
// This is the first packet which we try to recover with.
const uint16_t ulp_header_size =
fec_packet->pkt->data[0] & 0x40 ? kUlpHeaderSizeLBitSet
: kUlpHeaderSizeLBitClear; // L bit set?
+ if (fec_packet->pkt->length <
+ static_cast<size_t>(kFecHeaderSize + ulp_header_size)) {
+ LOG(LS_WARNING)
+ << "Truncated FEC packet doesn't contain room for ULP header.";
+ return false;
+ }
recovered->pkt = new Packet;
memset(recovered->pkt->data, 0, IP_PACKET_SIZE);
recovered->returned = false;
recovered->was_recovered = true;
- uint8_t protection_length[2];
- // Copy the protection length from the ULP header.
- memcpy(protection_length, &fec_packet->pkt->data[10], 2);
+ uint16_t protection_length =
+ ByteReader<uint16_t>::ReadBigEndian(&fec_packet->pkt->data[10]);
+ if (protection_length >
+ std::min(
+ sizeof(recovered->pkt->data) - kRtpHeaderSize,
+ sizeof(fec_packet->pkt->data) - kFecHeaderSize - ulp_header_size)) {
+ LOG(LS_WARNING) << "Incorrect FEC protection length, dropping.";
+ return false;
+ }
// Copy FEC payload, skipping the ULP header.
memcpy(&recovered->pkt->data[kRtpHeaderSize],
&fec_packet->pkt->data[kFecHeaderSize + ulp_header_size],
- ByteReader<uint16_t>::ReadBigEndian(protection_length));
+ protection_length);
// Copy the length recovery field.
memcpy(recovered->length_recovery, &fec_packet->pkt->data[8], 2);
// Copy the first 2 bytes of the FEC header.
@@ -660,9 +672,10 @@ void ForwardErrorCorrection::InitRecovery(const FecPacket* fec_packet,
// Set the SSRC field.
ByteWriter<uint32_t>::WriteBigEndian(&recovered->pkt->data[8],
fec_packet->ssrc);
+ return true;
}
-void ForwardErrorCorrection::FinishRecovery(RecoveredPacket* recovered) {
+bool ForwardErrorCorrection::FinishRecovery(RecoveredPacket* recovered) {
// Set the RTP version to 2.
recovered->pkt->data[0] |= 0x80; // Set the 1st bit.
recovered->pkt->data[0] &= 0xbf; // Clear the 2nd bit.
@@ -674,6 +687,10 @@ void ForwardErrorCorrection::FinishRecovery(RecoveredPacket* recovered) {
recovered->pkt->length =
ByteReader<uint16_t>::ReadBigEndian(recovered->length_recovery) +
kRtpHeaderSize;
+ if (recovered->pkt->length > sizeof(recovered->pkt->data) - kRtpHeaderSize)
+ return false;
+
+ return true;
}
void ForwardErrorCorrection::XorPackets(const Packet* src_packet,
@@ -700,9 +717,11 @@ void ForwardErrorCorrection::XorPackets(const Packet* src_packet,
}
}
-void ForwardErrorCorrection::RecoverPacket(
- const FecPacket* fec_packet, RecoveredPacket* rec_packet_to_insert) {
- InitRecovery(fec_packet, rec_packet_to_insert);
+bool ForwardErrorCorrection::RecoverPacket(
+ const FecPacket* fec_packet,
+ RecoveredPacket* rec_packet_to_insert) {
+ if (!InitRecovery(fec_packet, rec_packet_to_insert))
+ return false;
ProtectedPacketList::const_iterator protected_it =
fec_packet->protected_pkt_list.begin();
while (protected_it != fec_packet->protected_pkt_list.end()) {
@@ -714,7 +733,9 @@ void ForwardErrorCorrection::RecoverPacket(
}
++protected_it;
}
- FinishRecovery(rec_packet_to_insert);
+ if (!FinishRecovery(rec_packet_to_insert))
+ return false;
+ return true;
}
void ForwardErrorCorrection::AttemptRecover(
@@ -729,7 +750,13 @@ void ForwardErrorCorrection::AttemptRecover(
// Recovery possible.
RecoveredPacket* packet_to_insert = new RecoveredPacket;
packet_to_insert->pkt = NULL;
- RecoverPacket(*fec_packet_list_it, packet_to_insert);
+ if (!RecoverPacket(*fec_packet_list_it, packet_to_insert)) {
+ // Can't recover using this packet, drop it.
+ DiscardFECPacket(*fec_packet_list_it);
+ fec_packet_list_it = fec_packet_list_.erase(fec_packet_list_it);
+ delete packet_to_insert;
+ continue;
+ }
// Add recovered packet to the list of recovered packets and update any
// FEC packets covering this packet with a pointer to the data.
diff --git a/chromium/third_party/webrtc/modules/rtp_rtcp/source/forward_error_correction.h b/chromium/third_party/webrtc/modules/rtp_rtcp/source/forward_error_correction.h
index a3b3fa0e493..dc831708347 100644
--- a/chromium/third_party/webrtc/modules/rtp_rtcp/source/forward_error_correction.h
+++ b/chromium/third_party/webrtc/modules/rtp_rtcp/source/forward_error_correction.h
@@ -279,7 +279,7 @@ class ForwardErrorCorrection {
void AttemptRecover(RecoveredPacketList* recovered_packet_list);
// Initializes the packet recovery using the FEC packet.
- static void InitRecovery(const FecPacket* fec_packet,
+ static bool InitRecovery(const FecPacket* fec_packet,
RecoveredPacket* recovered);
// Performs XOR between |src_packet| and |dst_packet| and stores the result
@@ -287,10 +287,10 @@ class ForwardErrorCorrection {
static void XorPackets(const Packet* src_packet, RecoveredPacket* dst_packet);
// Finish up the recovery of a packet.
- static void FinishRecovery(RecoveredPacket* recovered);
+ static bool FinishRecovery(RecoveredPacket* recovered);
// Recover a missing packet.
- void RecoverPacket(const FecPacket* fec_packet,
+ bool RecoverPacket(const FecPacket* fec_packet,
RecoveredPacket* rec_packet_to_insert);
// Get the number of missing media packets which are covered by this
diff --git a/chromium/third_party/webrtc/modules/rtp_rtcp/source/h264_sps_parser.cc b/chromium/third_party/webrtc/modules/rtp_rtcp/source/h264_sps_parser.cc
index b022b21165d..034e761dcd4 100644
--- a/chromium/third_party/webrtc/modules/rtp_rtcp/source/h264_sps_parser.cc
+++ b/chromium/third_party/webrtc/modules/rtp_rtcp/source/h264_sps_parser.cc
@@ -36,8 +36,8 @@ bool H264SpsParser::Parse() {
// section 7.3.1 of the H.264 standard.
rtc::ByteBuffer rbsp_buffer;
for (size_t i = 0; i < byte_length_;) {
- if (i < byte_length_ - 3 &&
- sps_[i] == 0 && sps_[i + 1] == 0 && sps_[i + 2] == 3) {
+ if (i + 3 < byte_length_ && sps_[i] == 0 && sps_[i + 1] == 0 &&
+ sps_[i + 2] == 3) {
// Two rbsp bytes + the emulation byte.
rbsp_buffer.WriteBytes(sps_bytes + i, 2);
i += 3;
diff --git a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc
index ebd46b02e0e..c3ef75aeab1 100644
--- a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc
+++ b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc
@@ -39,7 +39,7 @@ enum NalDefs { kFBit = 0x80, kNriMask = 0x60, kTypeMask = 0x1F };
// Bit masks for FU (A and B) headers.
enum FuDefs { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 };
-void ParseSingleNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
+bool ParseSingleNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
const uint8_t* payload_data,
size_t payload_data_length) {
parsed_payload->type.Video.width = 0;
@@ -54,6 +54,9 @@ void ParseSingleNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
uint8_t nal_type = payload_data[0] & kTypeMask;
if (nal_type == kStapA) {
// Skip the StapA header (StapA nal type + length).
+ if (payload_data_length <= kStapAHeaderSize) {
+ return false;
+ }
nal_type = payload_data[kStapAHeaderSize] & kTypeMask;
nalu_start += kStapAHeaderSize;
nalu_length -= kStapAHeaderSize;
@@ -81,12 +84,16 @@ void ParseSingleNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
parsed_payload->frame_type = kVideoFrameDelta;
break;
}
+ return true;
}
-void ParseFuaNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
+bool ParseFuaNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
const uint8_t* payload_data,
size_t payload_data_length,
size_t* offset) {
+ if (payload_data_length < kFuAHeaderSize) {
+ return false;
+ }
uint8_t fnri = payload_data[0] & (kFBit | kNriMask);
uint8_t original_nal_type = payload_data[1] & kTypeMask;
bool first_fragment = (payload_data[1] & kSBit) > 0;
@@ -113,6 +120,7 @@ void ParseFuaNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
&parsed_payload->type.Video.codecHeader.H264;
h264_header->packetization_type = kH264FuA;
h264_header->nalu_type = original_nal_type;
+ return true;
}
} // namespace
@@ -316,15 +324,23 @@ bool RtpDepacketizerH264::Parse(ParsedPayload* parsed_payload,
const uint8_t* payload_data,
size_t payload_data_length) {
assert(parsed_payload != NULL);
+ if (payload_data_length == 0) {
+ return false;
+ }
+
uint8_t nal_type = payload_data[0] & kTypeMask;
size_t offset = 0;
if (nal_type == kFuA) {
// Fragmented NAL units (FU-A).
- ParseFuaNalu(parsed_payload, payload_data, payload_data_length, &offset);
+ if (!ParseFuaNalu(
+ parsed_payload, payload_data, payload_data_length, &offset)) {
+ return false;
+ }
} else {
// We handle STAP-A and single NALU's the same way here. The jitter buffer
// will depacketize the STAP-A into NAL units later.
- ParseSingleNalu(parsed_payload, payload_data, payload_data_length);
+ if (!ParseSingleNalu(parsed_payload, payload_data, payload_data_length))
+ return false;
}
parsed_payload->payload = payload_data + offset;
diff --git a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc
index 66a19ddf569..3ad5686fe9e 100644
--- a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc
+++ b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc
@@ -537,4 +537,36 @@ TEST_F(RtpDepacketizerH264Test, TestFuA) {
EXPECT_EQ(kH264FuA, payload.type.Video.codecHeader.H264.packetization_type);
EXPECT_EQ(kIdr, payload.type.Video.codecHeader.H264.nalu_type);
}
+
+TEST_F(RtpDepacketizerH264Test, TestEmptyPayload) {
+ // Using a wild pointer to crash on accesses from inside the depacketizer.
+ uint8_t* garbage_ptr = reinterpret_cast<uint8_t*>(0x4711);
+ RtpDepacketizer::ParsedPayload payload;
+ EXPECT_FALSE(depacketizer_->Parse(&payload, garbage_ptr, 0));
+}
+
+TEST_F(RtpDepacketizerH264Test, TestTruncatedFuaNalu) {
+ const uint8_t kPayload[] = {0x9c};
+ RtpDepacketizer::ParsedPayload payload;
+ EXPECT_FALSE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload)));
+}
+
+TEST_F(RtpDepacketizerH264Test, TestTruncatedSingleStapANalu) {
+ const uint8_t kPayload[] = {0xd8, 0x27};
+ RtpDepacketizer::ParsedPayload payload;
+ EXPECT_FALSE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload)));
+}
+
+TEST_F(RtpDepacketizerH264Test, TestTruncationJustAfterSingleStapANalu) {
+ const uint8_t kPayload[] = {0x38, 0x27, 0x27};
+ RtpDepacketizer::ParsedPayload payload;
+ EXPECT_FALSE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload)));
+}
+
+TEST_F(RtpDepacketizerH264Test, TestShortSpsPacket) {
+ const uint8_t kPayload[] = {0x27, 0x80, 0x00};
+ RtpDepacketizer::ParsedPayload payload;
+ EXPECT_TRUE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload)));
+}
+
} // namespace webrtc
diff --git a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc
index 1fa288acad7..5b74aafc851 100644
--- a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc
+++ b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc
@@ -90,6 +90,9 @@ bool RtpDepacketizerGeneric::Parse(ParsedPayload* parsed_payload,
const uint8_t* payload_data,
size_t payload_data_length) {
assert(parsed_payload != NULL);
+ if (payload_data_length == 0) {
+ return false;
+ }
uint8_t generic_header = *payload_data++;
--payload_data_length;
diff --git a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc
index 5202754caf4..1dc799968d0 100644
--- a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc
+++ b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc
@@ -668,6 +668,10 @@ bool RtpDepacketizerVp8::Parse(ParsedPayload* parsed_payload,
const uint8_t* payload_data,
size_t payload_data_length) {
assert(parsed_payload != NULL);
+ if (payload_data_length == 0) {
+ LOG(LS_ERROR) << "Empty payload.";
+ return false;
+ }
// Parse mandatory first byte of payload descriptor.
bool extension = (*payload_data & 0x80) ? true : false; // X bit
diff --git a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc
index 804dc090388..4283a778d00 100644
--- a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc
+++ b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc
@@ -596,4 +596,11 @@ TEST_F(RtpDepacketizerVp8Test, TestWithPacketizer) {
EXPECT_EQ(payload.type.Video.codecHeader.VP8.layerSync,
input_header.layerSync);
}
+
+TEST_F(RtpDepacketizerVp8Test, TestEmptyPayload) {
+ // Using a wild pointer to crash on accesses from inside the depacketizer.
+ uint8_t* garbage_ptr = reinterpret_cast<uint8_t*>(0x4711);
+ RtpDepacketizer::ParsedPayload payload;
+ EXPECT_FALSE(depacketizer_->Parse(&payload, garbage_ptr, 0));
+}
} // namespace webrtc
diff --git a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc
index df3067ac6f3..8e2ff1742ef 100644
--- a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc
+++ b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc
@@ -237,7 +237,8 @@ bool RTPPayloadRegistry::RestoreOriginalPacket(uint8_t** restored_packet,
size_t* packet_length,
uint32_t original_ssrc,
const RTPHeader& header) const {
- if (kRtxHeaderSize + header.headerLength > *packet_length) {
+ if (kRtxHeaderSize + header.headerLength + header.paddingLength >
+ *packet_length) {
return false;
}
const uint8_t* rtx_header = packet + header.headerLength;
diff --git a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc
index 8d8147cd638..ff64e49cafa 100644
--- a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc
+++ b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc
@@ -13,6 +13,7 @@
#include <assert.h>
#include <string.h>
+#include "webrtc/base/checks.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_cvo.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_format.h"
@@ -60,6 +61,7 @@ int32_t RTPReceiverVideo::ParseRtpPacket(WebRtcRTPHeader* rtp_header,
rtp_header->header.timestamp);
rtp_header->type.Video.codec = specific_payload.Video.videoCodecType;
+ DCHECK_GE(payload_length, rtp_header->header.paddingLength);
const size_t payload_data_length =
payload_length - rtp_header->header.paddingLength;
diff --git a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
index 566772a42a7..23300bbff60 100644
--- a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
+++ b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -770,8 +770,10 @@ TEST_F(RtpSenderTest, SendPadding) {
EXPECT_EQ(kMaxPaddingLength + rtp_header_len,
transport_.last_sent_packet_len_);
// Parse sent packet.
- ASSERT_TRUE(rtp_parser->Parse(transport_.last_sent_packet_, kPaddingBytes,
+ ASSERT_TRUE(rtp_parser->Parse(transport_.last_sent_packet_,
+ transport_.last_sent_packet_len_,
&rtp_header));
+ EXPECT_EQ(kMaxPaddingLength, rtp_header.paddingLength);
// Verify sequence number and timestamp.
EXPECT_EQ(seq_num++, rtp_header.sequenceNumber);
diff --git a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_utility.cc b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
index 3fef05355c7..0d083bd92a5 100644
--- a/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
+++ b/chromium/third_party/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
@@ -355,6 +355,8 @@ bool RtpHeaderParser::Parse(RTPHeader& header,
}
header.headerLength += XLen;
}
+ if (header.headerLength + header.paddingLength > static_cast<size_t>(length))
+ return false;
return true;
}
diff --git a/chromium/third_party/webrtc/video/rampup_tests.cc b/chromium/third_party/webrtc/video/rampup_tests.cc
index 6d6696004b2..934603229fb 100644
--- a/chromium/third_party/webrtc/video/rampup_tests.cc
+++ b/chromium/third_party/webrtc/video/rampup_tests.cc
@@ -131,7 +131,9 @@ bool StreamObserver::SendRtp(const uint8_t* packet, size_t length) {
++total_packets_sent_;
if (header.paddingLength > 0)
++padding_packets_sent_;
- if (rtx_media_ssrcs_.find(header.ssrc) != rtx_media_ssrcs_.end()) {
+ // Handle RTX retransmission, but only for non-padding-only packets.
+ if (rtx_media_ssrcs_.find(header.ssrc) != rtx_media_ssrcs_.end() &&
+ header.headerLength + header.paddingLength != length) {
rtx_media_sent_ += length - header.headerLength - header.paddingLength;
if (header.paddingLength == 0)
++rtx_media_packets_sent_;
@@ -141,9 +143,8 @@ bool StreamObserver::SendRtp(const uint8_t* packet, size_t length) {
EXPECT_TRUE(payload_registry_->RestoreOriginalPacket(
&restored_packet_ptr, packet, &restored_length,
rtx_media_ssrcs_[header.ssrc], header));
- length = restored_length;
- EXPECT_TRUE(rtp_parser_->Parse(
- restored_packet, static_cast<int>(length), &header));
+ EXPECT_TRUE(
+ rtp_parser_->Parse(restored_packet_ptr, restored_length, &header));
} else {
rtp_rtcp_->SetRemoteSSRC(header.ssrc);
}
diff --git a/chromium/tools/compile_test/compile_test.py b/chromium/tools/compile_test/compile_test.py
new file mode 100755
index 00000000000..bbda4abfe54
--- /dev/null
+++ b/chromium/tools/compile_test/compile_test.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Tries to compile given code, produces different output depending on success.
+
+This is similar to checks done by ./configure scripts.
+"""
+
+
+import optparse
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+
+
+def DoMain(argv):
+ parser = optparse.OptionParser()
+ parser.add_option('--code')
+ parser.add_option('--run-linker', action='store_true')
+ parser.add_option('--on-success', default='')
+ parser.add_option('--on-failure', default='')
+
+ options, args = parser.parse_args(argv)
+
+ if not options.code:
+ parser.error('Missing required --code switch.')
+
+ # The environment variable might expand to a string with spaces,
+ # e.g. "ccache g++". Convert it to a list suitable for argv.
+ cxx = os.environ.get('CXX', 'g++').split()
+
+ tmpdir = tempfile.mkdtemp()
+ try:
+ cxx_path = os.path.join(tmpdir, 'test.cc')
+ with open(cxx_path, 'w') as f:
+ f.write(options.code.decode('string-escape'))
+
+ o_path = os.path.join(tmpdir, 'test.o')
+
+ cxx_cmdline = cxx + [cxx_path, '-o', o_path]
+ if not options.run_linker:
+ cxx_cmdline.append('-c')
+ # Pass remaining arguments to the compiler.
+ cxx_cmdline += args
+ cxx_popen = subprocess.Popen(cxx_cmdline,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ cxx_stdout, cxx_stderr = cxx_popen.communicate()
+ if cxx_popen.returncode == 0:
+ print options.on_success
+ else:
+ print options.on_failure
+ finally:
+ shutil.rmtree(tmpdir)
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(DoMain(sys.argv[1:]))
diff --git a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_kn.xtb b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_kn.xtb
index 72ae0b82699..2e3848136df 100644
--- a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_kn.xtb
+++ b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_kn.xtb
@@ -24,7 +24,7 @@
<translation id="2471847333270902538"><ph name="SITE"/> ಗೆ ಬಣ್ಣದ ಯೋಜನೆ:</translation>
<translation id="381767806621926835">ಅದರ ದೀರ್ಘ ವಿವರಣೆಯನ್ನು ಪ್ರವೇಶಿಸಲು &quot;longdesc&quot; ಅಥವಾ &quot;aria-describedat&quot; ಗುಣಲಕ್ಷಣದೊಂದಿಗೆ ಯಾವುದರ ಮೇಲಾದರೂ ರೈಟ್-ಕ್ಲಿಕ್ ಮಾಡಿ.</translation>
<translation id="6838518108677880446">ಸೆಟಪ್:</translation>
-<translation id="5594989420907487559">ಆನಿಮೇಶನ್‌ಗಳನ್ನು ಒಮ್ಮೆ ಮಾತ್ರ ರನ್ ಮಾಡಿ ಅಥವಾ ಸಂಪೂರ್ಣವಾಗಿ ಆನಿಮೇಶನ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ.</translation>
+<translation id="5594989420907487559">ಅನಿಮೇಶನ್‌‌ಗಳನ್ನು ಒಮ್ಮೆ ಮಾತ್ರ ರನ್ ಮಾಡಿ ಅಥವಾ ಸಂಪೂರ್ಣವಾಗಿ ಆನಿಮೇಶನ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ.</translation>
<translation id="786423340267544509">aria-describedat ಅಥವಾ longdesc ಗುಣಲಕ್ಷಣಗಳ ಜೊತೆಗೆ ಅಂಶಗಳಿಗೆ ಅಂಚು ಸೇರಿಸಿ.</translation>
<translation id="690628312087070417">ದೀರ್ಘವಾದ ಅಂತರದಿಂದ ಕೆರೆಟ್ ಮುಂದಕ್ಕೆ ಸಾಗಿದಾಗ:</translation>
<translation id="1996252509865389616">ಸಕ್ರಿಯಗೊಳಿಸುವುದೇ?</translation>
diff --git a/chromium/ui/base/ime/input_method_win.cc b/chromium/ui/base/ime/input_method_win.cc
index 9bea264937c..f5859aa459d 100644
--- a/chromium/ui/base/ime/input_method_win.cc
+++ b/chromium/ui/base/ime/input_method_win.cc
@@ -35,22 +35,18 @@ InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate,
composing_window_handle_(NULL),
default_input_language_initialized_(false) {
SetDelegate(delegate);
+ // Temporarily apply "always-focused" mode for InputMethodWin due to
+ // regression crbug.com/493292 caused by cl
+ // https://codereview.chromium.org/1109333002.
+ // This is only for quick fix in M44.
+ // TODO(shuchen): remove the "always-focused" mode for M45.
+ InputMethodBase::OnFocus();
}
void InputMethodWin::OnFocus() {
- InputMethodBase::OnFocus();
- if (GetTextInputClient())
- UpdateIMEState();
}
void InputMethodWin::OnBlur() {
- ConfirmCompositionText();
- // Gets the focused text input client before calling parent's OnBlur() because
- // it will cause GetTextInputClient() returns NULL.
- ui::TextInputClient* client = GetTextInputClient();
- InputMethodBase::OnBlur();
- if (client)
- UpdateIMEState();
}
bool InputMethodWin::OnUntranslatedIMEMessage(
diff --git a/chromium/ui/views/controls/textfield/textfield.cc b/chromium/ui/views/controls/textfield/textfield.cc
index 73cccd53cae..d0410cb0536 100644
--- a/chromium/ui/views/controls/textfield/textfield.cc
+++ b/chromium/ui/views/controls/textfield/textfield.cc
@@ -288,6 +288,13 @@ Textfield::Textfield()
password_reveal_duration_ = ViewsDelegate::views_delegate->
GetDefaultTextfieldObscuredRevealDuration();
}
+
+ // These allow BrowserView to pass edit commands from the Chrome menu to us
+ // when we're focused by simply asking the FocusManager to
+ // ProcessAccelerator() with the relevant accelerators.
+ AddAccelerator(ui::Accelerator(ui::VKEY_X, ui::EF_CONTROL_DOWN));
+ AddAccelerator(ui::Accelerator(ui::VKEY_C, ui::EF_CONTROL_DOWN));
+ AddAccelerator(ui::Accelerator(ui::VKEY_V, ui::EF_CONTROL_DOWN));
}
Textfield::~Textfield() {}
@@ -817,6 +824,10 @@ bool Textfield::AcceleratorPressed(const ui::Accelerator& accelerator) {
return true;
}
+bool Textfield::CanHandleAccelerators() const {
+ return GetRenderText()->focused() && View::CanHandleAccelerators();
+}
+
void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) {
SelectAll(false);
}
diff --git a/chromium/ui/views/controls/textfield/textfield.h b/chromium/ui/views/controls/textfield/textfield.h
index 68149465e3b..9a6e68c71a0 100644
--- a/chromium/ui/views/controls/textfield/textfield.h
+++ b/chromium/ui/views/controls/textfield/textfield.h
@@ -221,6 +221,7 @@ class VIEWS_EXPORT Textfield : public View,
ui::TextInputClient* GetTextInputClient() override;
void OnGestureEvent(ui::GestureEvent* event) override;
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
+ bool CanHandleAccelerators() const override;
void AboutToRequestFocusFromTabTraversal(bool reverse) override;
bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) override;
bool GetDropFormats(
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index 69c5b2f44a8..ceffac09ddb 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -237,7 +237,17 @@ void DesktopWindowTreeHostX11::SwapNonClientEventHandler(
x11_non_client_event_filter_ = handler.Pass();
}
-void DesktopWindowTreeHostX11::CleanUpWindowList() {
+void DesktopWindowTreeHostX11::CleanUpWindowList(
+ void (*func)(aura::Window* window)) {
+ if (!open_windows_)
+ return;
+ while (!open_windows_->empty()) {
+ XID xid = open_windows_->front();
+ func(GetContentWindowForXID(xid));
+ if (!open_windows_->empty() && open_windows_->front() == xid)
+ open_windows_->erase(open_windows_->begin());
+ }
+
delete open_windows_;
open_windows_ = NULL;
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
index 94d4b1ba2f2..59591bd9bfc 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -83,8 +83,9 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
// Swaps the current handler for events in the non client view with |handler|.
void SwapNonClientEventHandler(scoped_ptr<ui::EventHandler> handler);
- // Deallocates the internal list of open windows.
- static void CleanUpWindowList();
+ // Runs the |func| callback for each content-window, and deallocates the
+ // internal list of open windows.
+ static void CleanUpWindowList(void (*func)(aura::Window* window));
protected:
// Overridden from DesktopWindowTreeHost:
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
index 17eb63a8e79..64cb2b7a937 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
@@ -456,6 +456,33 @@ TEST_F(DesktopWindowTreeHostX11Test, ToggleMinimizePropogateToContentWindow) {
EXPECT_TRUE(widget.GetNativeWindow()->IsVisible());
}
+TEST_F(DesktopWindowTreeHostX11Test, ChildWindowDestructionDuringTearDown) {
+ Widget parent_widget;
+ Widget::InitParams parent_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ parent_params.native_widget = new DesktopNativeWidgetAura(&parent_widget);
+ parent_widget.Init(parent_params);
+ parent_widget.Show();
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ Widget child_widget;
+ Widget::InitParams child_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ child_params.native_widget = new DesktopNativeWidgetAura(&child_widget);
+ child_params.parent = parent_widget.GetNativeWindow();
+ child_widget.Init(child_params);
+ child_widget.Show();
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ // Sanity check that the two widgets each have their own XID.
+ ASSERT_NE(parent_widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget(),
+ child_widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+ Widget::CloseAllSecondaryWidgets();
+ EXPECT_TRUE(DesktopWindowTreeHostX11::GetAllOpenWindows().empty());
+}
+
class MouseEventRecorder : public ui::EventHandler {
public:
MouseEventRecorder() {}
diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc
index bf113e6e119..d5bb6dfa57d 100644
--- a/chromium/ui/views/widget/native_widget_aura.cc
+++ b/chromium/ui/views/widget/native_widget_aura.cc
@@ -1060,10 +1060,7 @@ void Widget::CloseAllSecondaryWidgets() {
#endif
#if defined(USE_X11) && !defined(OS_CHROMEOS)
- std::vector<aura::Window*> open_windows =
- DesktopWindowTreeHostX11::GetAllOpenWindows();
- std::for_each(open_windows.begin(), open_windows.end(), CloseWindow);
- DesktopWindowTreeHostX11::CleanUpWindowList();
+ DesktopWindowTreeHostX11::CleanUpWindowList(CloseWindow);
#endif
}
diff --git a/chromium/v8/include/v8-version.h b/chromium/v8/include/v8-version.h
index 64eafa5d661..b50ba34aa1d 100644
--- a/chromium/v8/include/v8-version.h
+++ b/chromium/v8/include/v8-version.h
@@ -11,7 +11,7 @@
#define V8_MAJOR_VERSION 4
#define V8_MINOR_VERSION 4
#define V8_BUILD_NUMBER 63
-#define V8_PATCH_LEVEL 13
+#define V8_PATCH_LEVEL 19
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/chromium/v8/src/arm64/code-stubs-arm64.cc b/chromium/v8/src/arm64/code-stubs-arm64.cc
index 9ce5a05ce53..7f3c9952049 100644
--- a/chromium/v8/src/arm64/code-stubs-arm64.cc
+++ b/chromium/v8/src/arm64/code-stubs-arm64.cc
@@ -2286,27 +2286,16 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
Register last_match_info_elements = x21;
Register code_object = x22;
- // TODO(jbramley): Is it necessary to preserve these? I don't think ARM does.
- CPURegList used_callee_saved_registers(subject,
- regexp_data,
- last_match_info_elements,
- code_object);
- __ PushCPURegList(used_callee_saved_registers);
-
// Stack frame.
- // jssp[0] : x19
- // jssp[8] : x20
- // jssp[16]: x21
- // jssp[24]: x22
- // jssp[32]: last_match_info (JSArray)
- // jssp[40]: previous index
- // jssp[48]: subject string
- // jssp[56]: JSRegExp object
-
- const int kLastMatchInfoOffset = 4 * kPointerSize;
- const int kPreviousIndexOffset = 5 * kPointerSize;
- const int kSubjectOffset = 6 * kPointerSize;
- const int kJSRegExpOffset = 7 * kPointerSize;
+ // jssp[00]: last_match_info (JSArray)
+ // jssp[08]: previous index
+ // jssp[16]: subject string
+ // jssp[24]: JSRegExp object
+
+ const int kLastMatchInfoOffset = 0 * kPointerSize;
+ const int kPreviousIndexOffset = 1 * kPointerSize;
+ const int kSubjectOffset = 2 * kPointerSize;
+ const int kJSRegExpOffset = 3 * kPointerSize;
// Ensure that a RegExp stack is allocated.
ExternalReference address_of_regexp_stack_memory_address =
@@ -2673,7 +2662,6 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Return last match info.
__ Peek(x0, kLastMatchInfoOffset);
- __ PopCPURegList(used_callee_saved_registers);
// Drop the 4 arguments of the stub from the stack.
__ Drop(4);
__ Ret();
@@ -2696,13 +2684,11 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ Bind(&failure);
__ Mov(x0, Operand(isolate()->factory()->null_value()));
- __ PopCPURegList(used_callee_saved_registers);
// Drop the 4 arguments of the stub from the stack.
__ Drop(4);
__ Ret();
__ Bind(&runtime);
- __ PopCPURegList(used_callee_saved_registers);
__ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
// Deferred code for string handling.
diff --git a/chromium/v8/src/flag-definitions.h b/chromium/v8/src/flag-definitions.h
index 93e61df0825..2b905e31d43 100644
--- a/chromium/v8/src/flag-definitions.h
+++ b/chromium/v8/src/flag-definitions.h
@@ -199,7 +199,7 @@ DEFINE_IMPLICATION(es_staging, harmony)
#define HARMONY_STAGED(V) \
V(harmony_rest_parameters, "harmony rest parameters") \
V(harmony_spreadcalls, "harmony spread-calls") \
- V(harmony_tostring, "harmony toString") \
+ V(harmony_tostring, "harmony toString")
// Features that are shipping (turned on by default, but internal flag remains).
#define HARMONY_SHIPPING(V) \
diff --git a/chromium/v8/src/ic/ic.cc b/chromium/v8/src/ic/ic.cc
index daf7704c71d..65b2e3df9ad 100644
--- a/chromium/v8/src/ic/ic.cc
+++ b/chromium/v8/src/ic/ic.cc
@@ -1112,7 +1112,39 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
code = slow_stub();
}
} else {
- code = ComputeHandler(lookup);
+ if (lookup->state() == LookupIterator::ACCESSOR) {
+ Handle<Object> accessors = lookup->GetAccessors();
+ Handle<Map> map = receiver_map();
+ if (accessors->IsExecutableAccessorInfo()) {
+ Handle<ExecutableAccessorInfo> info =
+ Handle<ExecutableAccessorInfo>::cast(accessors);
+ if ((v8::ToCData<Address>(info->getter()) != 0) &&
+ !ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
+ map)) {
+ TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
+ code = slow_stub();
+ }
+ } else if (accessors->IsAccessorPair()) {
+ Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
+ isolate());
+ Handle<JSObject> holder = lookup->GetHolder<JSObject>();
+ Handle<Object> receiver = lookup->GetReceiver();
+ if (getter->IsJSFunction() && holder->HasFastProperties()) {
+ Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
+ if (receiver->IsJSObject() || function->IsBuiltin() ||
+ !is_sloppy(function->shared()->language_mode())) {
+ CallOptimization call_optimization(function);
+ if (call_optimization.is_simple_api_call() &&
+ !call_optimization.IsCompatibleReceiver(receiver, holder)) {
+ TRACE_GENERIC_IC(isolate(), "LoadIC",
+ "incompatible receiver type");
+ code = slow_stub();
+ }
+ }
+ }
+ }
+ }
+ if (code.is_null()) code = ComputeHandler(lookup);
}
PatchCache(lookup->name(), code);
@@ -1242,6 +1274,8 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
if (v8::ToCData<Address>(info->getter()) == 0) break;
if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
map)) {
+ // This case should be already handled in LoadIC::UpdateCaches.
+ UNREACHABLE();
break;
}
if (!holder->HasFastProperties()) break;
@@ -1262,10 +1296,14 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
}
CallOptimization call_optimization(function);
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
- if (call_optimization.is_simple_api_call() &&
- call_optimization.IsCompatibleReceiver(receiver, holder)) {
- return compiler.CompileLoadCallback(lookup->name(), call_optimization,
- lookup->GetAccessorIndex());
+ if (call_optimization.is_simple_api_call()) {
+ if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
+ return compiler.CompileLoadCallback(
+ lookup->name(), call_optimization, lookup->GetAccessorIndex());
+ } else {
+ // This case should be already handled in LoadIC::UpdateCaches.
+ UNREACHABLE();
+ }
}
int expected_arguments =
function->shared()->internal_formal_parameter_count();
diff --git a/chromium/v8/src/objects.cc b/chromium/v8/src/objects.cc
index 67a7b2bc7a1..ad1395a2597 100644
--- a/chromium/v8/src/objects.cc
+++ b/chromium/v8/src/objects.cc
@@ -3275,54 +3275,58 @@ MaybeHandle<Object> Object::SetSuperProperty(LookupIterator* it,
if (found) return result;
LookupIterator own_lookup(it->GetReceiver(), it->name(), LookupIterator::OWN);
+ for (; own_lookup.IsFound(); own_lookup.Next()) {
+ switch (own_lookup.state()) {
+ case LookupIterator::ACCESS_CHECK:
+ if (!own_lookup.HasAccess()) {
+ return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
+ SLOPPY);
+ }
+ break;
- switch (own_lookup.state()) {
- case LookupIterator::NOT_FOUND:
- return JSObject::AddDataProperty(&own_lookup, value, NONE, language_mode,
- store_mode);
-
- case LookupIterator::INTEGER_INDEXED_EXOTIC:
- return result;
+ case LookupIterator::INTEGER_INDEXED_EXOTIC:
+ return RedefineNonconfigurableProperty(it->isolate(), it->name(), value,
+ language_mode);
- case LookupIterator::DATA: {
- PropertyDetails details = own_lookup.property_details();
- if (details.IsConfigurable() || !details.IsReadOnly()) {
- return JSObject::SetOwnPropertyIgnoreAttributes(
- Handle<JSObject>::cast(it->GetReceiver()), it->name(), value,
- details.attributes());
+ case LookupIterator::DATA: {
+ PropertyDetails details = own_lookup.property_details();
+ if (details.IsConfigurable() || !details.IsReadOnly()) {
+ return JSObject::SetOwnPropertyIgnoreAttributes(
+ Handle<JSObject>::cast(it->GetReceiver()), it->name(), value,
+ details.attributes());
+ }
+ return WriteToReadOnlyProperty(&own_lookup, value, language_mode);
}
- return WriteToReadOnlyProperty(&own_lookup, value, language_mode);
- }
- case LookupIterator::ACCESSOR: {
- PropertyDetails details = own_lookup.property_details();
- if (details.IsConfigurable()) {
- return JSObject::SetOwnPropertyIgnoreAttributes(
- Handle<JSObject>::cast(it->GetReceiver()), it->name(), value,
- details.attributes());
- }
+ case LookupIterator::ACCESSOR: {
+ PropertyDetails details = own_lookup.property_details();
+ if (details.IsConfigurable()) {
+ return JSObject::SetOwnPropertyIgnoreAttributes(
+ Handle<JSObject>::cast(it->GetReceiver()), it->name(), value,
+ details.attributes());
+ }
- return RedefineNonconfigurableProperty(it->isolate(), it->name(), value,
- language_mode);
- }
+ return RedefineNonconfigurableProperty(it->isolate(), it->name(), value,
+ language_mode);
+ }
- case LookupIterator::TRANSITION:
- UNREACHABLE();
- break;
+ case LookupIterator::INTERCEPTOR:
+ case LookupIterator::JSPROXY: {
+ bool found = false;
+ MaybeHandle<Object> result = SetPropertyInternal(
+ &own_lookup, value, language_mode, store_mode, &found);
+ if (found) return result;
+ break;
+ }
- case LookupIterator::INTERCEPTOR:
- case LookupIterator::JSPROXY:
- case LookupIterator::ACCESS_CHECK: {
- bool found = false;
- MaybeHandle<Object> result = SetPropertyInternal(
- &own_lookup, value, language_mode, store_mode, &found);
- if (found) return result;
- return SetDataProperty(&own_lookup, value);
+ case LookupIterator::NOT_FOUND:
+ case LookupIterator::TRANSITION:
+ UNREACHABLE();
}
}
- UNREACHABLE();
- return MaybeHandle<Object>();
+ return JSObject::AddDataProperty(&own_lookup, value, NONE, language_mode,
+ store_mode);
}
diff --git a/chromium/v8/src/snapshot/serialize.cc b/chromium/v8/src/snapshot/serialize.cc
index dbe92a6accb..55685be2785 100644
--- a/chromium/v8/src/snapshot/serialize.cc
+++ b/chromium/v8/src/snapshot/serialize.cc
@@ -746,21 +746,10 @@ void Deserializer::ReadObject(int space_number, Object** write_back) {
HeapObject* obj;
int next_int = source_.GetInt();
- bool double_align = false;
-#ifndef V8_HOST_ARCH_64_BIT
- double_align = next_int == kDoubleAlignmentSentinel;
- if (double_align) next_int = source_.GetInt();
-#endif
-
DCHECK_NE(kDoubleAlignmentSentinel, next_int);
int size = next_int << kObjectAlignmentBits;
- int reserved_size = size + (double_align ? kPointerSize : 0);
- address = Allocate(space_number, reserved_size);
+ address = Allocate(space_number, size);
obj = HeapObject::FromAddress(address);
- if (double_align) {
- obj = isolate_->heap()->DoubleAlignForDeserialization(obj, reserved_size);
- address = obj->address();
- }
isolate_->heap()->OnAllocationEvent(obj, size);
Object** current = reinterpret_cast<Object**>(address);
@@ -1671,17 +1660,8 @@ void Serializer::ObjectSerializer::SerializePrologue(AllocationSpace space,
}
back_reference = serializer_->AllocateLargeObject(size);
} else {
- bool needs_double_align = false;
- if (object_->NeedsToEnsureDoubleAlignment()) {
- // Add wriggle room for double alignment padding.
- back_reference = serializer_->Allocate(space, size + kPointerSize);
- needs_double_align = true;
- } else {
- back_reference = serializer_->Allocate(space, size);
- }
+ back_reference = serializer_->Allocate(space, size);
sink_->Put(kNewObject + reference_representation_ + space, "NewObject");
- if (needs_double_align)
- sink_->PutInt(kDoubleAlignmentSentinel, "DoubleAlignSentinel");
int encoded_size = size >> kObjectAlignmentBits;
DCHECK_NE(kDoubleAlignmentSentinel, encoded_size);
sink_->PutInt(encoded_size, "ObjectSizeInWords");
diff --git a/chromium/v8/src/unicode-decoder.cc b/chromium/v8/src/unicode-decoder.cc
index a3bf8295226..2289e083425 100644
--- a/chromium/v8/src/unicode-decoder.cc
+++ b/chromium/v8/src/unicode-decoder.cc
@@ -15,6 +15,7 @@ void Utf8DecoderBase::Reset(uint16_t* buffer, size_t buffer_length,
// Assume everything will fit in the buffer and stream won't be needed.
last_byte_of_buffer_unused_ = false;
unbuffered_start_ = NULL;
+ unbuffered_length_ = 0;
bool writing_to_buffer = true;
// Loop until stream is read, writing to buffer as long as buffer has space.
size_t utf16_length = 0;
@@ -41,6 +42,7 @@ void Utf8DecoderBase::Reset(uint16_t* buffer, size_t buffer_length,
// Just wrote last character of buffer
writing_to_buffer = false;
unbuffered_start_ = stream;
+ unbuffered_length_ = stream_length;
}
continue;
}
@@ -50,19 +52,23 @@ void Utf8DecoderBase::Reset(uint16_t* buffer, size_t buffer_length,
writing_to_buffer = false;
last_byte_of_buffer_unused_ = true;
unbuffered_start_ = stream - cursor;
+ unbuffered_length_ = stream_length + cursor;
}
utf16_length_ = utf16_length;
}
-void Utf8DecoderBase::WriteUtf16Slow(const uint8_t* stream, uint16_t* data,
+void Utf8DecoderBase::WriteUtf16Slow(const uint8_t* stream,
+ size_t stream_length, uint16_t* data,
size_t data_length) {
while (data_length != 0) {
size_t cursor = 0;
- uint32_t character = Utf8::ValueOf(stream, Utf8::kMaxEncodedSize, &cursor);
+ uint32_t character = Utf8::ValueOf(stream, stream_length, &cursor);
// There's a total lack of bounds checking for stream
// as it was already done in Reset.
stream += cursor;
+ DCHECK(stream_length >= cursor);
+ stream_length -= cursor;
if (character > unibrow::Utf16::kMaxNonSurrogateCharCode) {
*data++ = Utf16::LeadSurrogate(character);
*data++ = Utf16::TrailSurrogate(character);
diff --git a/chromium/v8/src/unicode-decoder.h b/chromium/v8/src/unicode-decoder.h
index bfb14a38555..c0308411660 100644
--- a/chromium/v8/src/unicode-decoder.h
+++ b/chromium/v8/src/unicode-decoder.h
@@ -23,9 +23,10 @@ class Utf8DecoderBase {
// The first buffer_length utf16 chars are cached in the buffer.
void Reset(uint16_t* buffer, size_t buffer_length, const uint8_t* stream,
size_t stream_length);
- static void WriteUtf16Slow(const uint8_t* stream, uint16_t* data,
- size_t length);
+ static void WriteUtf16Slow(const uint8_t* stream, size_t stream_length,
+ uint16_t* data, size_t length);
const uint8_t* unbuffered_start_;
+ size_t unbuffered_length_;
size_t utf16_length_;
bool last_byte_of_buffer_unused_;
@@ -48,6 +49,7 @@ class Utf8Decoder : public Utf8DecoderBase {
Utf8DecoderBase::Utf8DecoderBase()
: unbuffered_start_(NULL),
+ unbuffered_length_(0),
utf16_length_(0),
last_byte_of_buffer_unused_(false) {}
@@ -84,7 +86,7 @@ size_t Utf8Decoder<kBufferSize>::WriteUtf16(uint16_t* data,
if (length <= buffer_length) return length;
DCHECK(unbuffered_start_ != NULL);
// Copy the rest the slow way.
- WriteUtf16Slow(unbuffered_start_, data + buffer_length,
+ WriteUtf16Slow(unbuffered_start_, unbuffered_length_, data + buffer_length,
length - buffer_length);
return length;
}