summaryrefslogtreecommitdiff
path: root/chromium/third_party
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party')
-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
65 files changed, 7286 insertions, 2937 deletions
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);
}