diff options
author | Daniel Grunwald <daniel@danielgrunwald.de> | 2012-02-22 22:37:39 +0400 |
---|---|---|
committer | Daniel Grunwald <daniel@danielgrunwald.de> | 2012-02-23 18:39:42 +0400 |
commit | def994306351ce70f5e15dc04ca73cc8d6f6ecad (patch) | |
tree | 6dbed5faf981be1c11177235c79842f48dcc643a /ICSharpCode.NRefactory.Xml | |
parent | 2c7c1c7ee7f0e4bbde8ee319f189538489014955 (diff) |
Add AXmlObject.CreateReader() method.
Diffstat (limited to 'ICSharpCode.NRefactory.Xml')
-rw-r--r-- | ICSharpCode.NRefactory.Xml/AXmlDocument.cs | 13 | ||||
-rw-r--r-- | ICSharpCode.NRefactory.Xml/AXmlElement.cs | 8 | ||||
-rw-r--r-- | ICSharpCode.NRefactory.Xml/AXmlObject.cs | 38 | ||||
-rw-r--r-- | ICSharpCode.NRefactory.Xml/AXmlReader.cs | 339 | ||||
-rw-r--r-- | ICSharpCode.NRefactory.Xml/ICSharpCode.NRefactory.Xml.csproj | 1 | ||||
-rw-r--r-- | ICSharpCode.NRefactory.Xml/InternalDocument.cs | 18 | ||||
-rw-r--r-- | ICSharpCode.NRefactory.Xml/ObjectIterator.cs | 26 | ||||
-rw-r--r-- | ICSharpCode.NRefactory.Xml/TagMatchingHeuristics.cs | 2 | ||||
-rw-r--r-- | ICSharpCode.NRefactory.Xml/TagReader.cs | 162 |
9 files changed, 494 insertions, 113 deletions
diff --git a/ICSharpCode.NRefactory.Xml/AXmlDocument.cs b/ICSharpCode.NRefactory.Xml/AXmlDocument.cs index 90b54714..64ec7b04 100644 --- a/ICSharpCode.NRefactory.Xml/AXmlDocument.cs +++ b/ICSharpCode.NRefactory.Xml/AXmlDocument.cs @@ -18,6 +18,7 @@ using System; using System.Globalization; +using System.Xml; namespace ICSharpCode.NRefactory.Xml { @@ -32,6 +33,18 @@ namespace ICSharpCode.NRefactory.Xml } /// <inheritdoc/> + public override XmlReader CreateReader() + { + return new AXmlReader(internalObject.NestedObjects); + } + + /// <inheritdoc/> + public override XmlReader CreateReader(Func<int, TextLocation> offsetToTextLocation) + { + return new AXmlReader(internalObject.NestedObjects, startOffset, offsetToTextLocation); + } + + /// <inheritdoc/> public override void AcceptVisitor(IAXmlVisitor visitor) { visitor.VisitDocument(this); diff --git a/ICSharpCode.NRefactory.Xml/AXmlElement.cs b/ICSharpCode.NRefactory.Xml/AXmlElement.cs index 9a8dfb19..44954225 100644 --- a/ICSharpCode.NRefactory.Xml/AXmlElement.cs +++ b/ICSharpCode.NRefactory.Xml/AXmlElement.cs @@ -90,17 +90,13 @@ namespace ICSharpCode.NRefactory.Xml /// <summary> The part of name before ":" </summary> /// <returns> Empty string if not found </returns> public string Prefix { - get { - return GetNamespacePrefix(this.Name); - } + get { return ((InternalElement)internalObject).Prefix; } } /// <summary> The part of name after ":" </summary> /// <returns> Empty string if not found </returns> public string LocalName { - get { - return GetLocalName(this.Name); - } + get { return ((InternalElement)internalObject).LocalName; } } /// <summary> Resolved namespace of the name </summary> diff --git a/ICSharpCode.NRefactory.Xml/AXmlObject.cs b/ICSharpCode.NRefactory.Xml/AXmlObject.cs index 49e99273..94cc605e 100644 --- a/ICSharpCode.NRefactory.Xml/AXmlObject.cs +++ b/ICSharpCode.NRefactory.Xml/AXmlObject.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Xml; using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.Utils; @@ -51,6 +52,22 @@ namespace ICSharpCode.NRefactory.Xml } /// <summary> + /// Creates an XML reader that reads from this document. + /// </summary> + public virtual XmlReader CreateReader() + { + return new AXmlReader(new[] { internalObject }); + } + + /// <summary> + /// Creates an XML reader that reads from this document. + /// </summary> + public virtual XmlReader CreateReader(Func<int, TextLocation> offsetToTextLocation) + { + return new AXmlReader(new[] { internalObject }, startOffset, offsetToTextLocation); + } + + /// <summary> /// Gets the parent node. /// </summary> public AXmlObject Parent { @@ -82,6 +99,23 @@ namespace ICSharpCode.NRefactory.Xml } /// <summary> + /// Gets a child fully containg the given offset. + /// Goes recursively down the tree. + /// Specail case if at the end of attribute or text + /// </summary> + public AXmlObject GetChildAtOffset(int offset) + { + foreach(AXmlObject child in this.Children) { + if (offset == child.EndOffset && (child is AXmlAttribute || child is AXmlText)) + return child; + if (child.StartOffset < offset && offset < child.EndOffset) { + return child.GetChildAtOffset(offset); + } + } + return this; // No childs at offset + } + + /// <summary> /// The error that occured in the context of this node (excluding nested nodes) /// </summary> public IEnumerable<SyntaxError> MySyntaxErrors { @@ -119,7 +153,7 @@ namespace ICSharpCode.NRefactory.Xml /// <summary> The part of name before ":" </summary> /// <returns> Empty string if not found </returns> - protected static string GetNamespacePrefix(string name) + internal static string GetNamespacePrefix(string name) { if (string.IsNullOrEmpty(name)) return string.Empty; int colonIndex = name.IndexOf(':'); @@ -132,7 +166,7 @@ namespace ICSharpCode.NRefactory.Xml /// <summary> The part of name after ":" </summary> /// <returns> Whole name if ":" not found </returns> - protected static string GetLocalName(string name) + internal static string GetLocalName(string name) { if (string.IsNullOrEmpty(name)) return string.Empty; int colonIndex = name.IndexOf(':'); diff --git a/ICSharpCode.NRefactory.Xml/AXmlReader.cs b/ICSharpCode.NRefactory.Xml/AXmlReader.cs new file mode 100644 index 00000000..af4bf406 --- /dev/null +++ b/ICSharpCode.NRefactory.Xml/AXmlReader.cs @@ -0,0 +1,339 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml; + +namespace ICSharpCode.NRefactory.Xml +{ + /// <summary> + /// XmlReader implementation that reads from an <see cref="AXmlDocument"/>. + /// </summary> + sealed class AXmlReader : XmlReader, IXmlLineInfo + { + readonly ObjectIterator objectIterator; + readonly Func<int, TextLocation> offsetToTextLocation; + readonly XmlNameTable nameTable = new NameTable(); + ReadState readState = ReadState.Initial; + XmlNodeType elementNodeType = XmlNodeType.None; + IList<InternalAttribute> attributes; + int attributeIndex = -1; + bool inAttributeValue; + + internal AXmlReader(InternalObject[] objects, int startPosition = 0, Func<int, TextLocation> offsetToTextLocation = null) + { + this.offsetToTextLocation = offsetToTextLocation; + objectIterator = new ObjectIterator(objects, startPosition); + objectIterator.StopAtElementEnd = true; + } + + public override void ResolveEntity() + { + throw new NotSupportedException(); + } + + public override ReadState ReadState { + get { return readState; } + } + + public override bool ReadAttributeValue() + { + if (attributeIndex >= 0 && !inAttributeValue) { + inAttributeValue = true; + return true; + } + return false; + } + + public override bool Read() + { + switch (readState) { + case ReadState.Initial: + readState = ReadState.Interactive; + return ReadCurrentPosition(); + case ReadState.Interactive: + objectIterator.MoveInto(); + return ReadCurrentPosition(); + default: + return false; + } + } + + bool ReadCurrentPosition() + { + attributes = null; + attributeIndex = -1; + inAttributeValue = false; + while (true) { + var obj = objectIterator.CurrentObject; + if (obj == null) { + readState = ReadState.EndOfFile; + elementNodeType = XmlNodeType.None; + return false; + } else if (objectIterator.IsAtElementEnd) { + elementNodeType = XmlNodeType.EndElement; + return true; + } else if (obj is InternalElement) { + // element start + elementNodeType = XmlNodeType.Element; + InternalTag startTag = ((InternalTag)obj.NestedObjects[0]); + if (startTag.NestedObjects != null) + attributes = startTag.NestedObjects.OfType<InternalAttribute>().ToList(); + return true; + } else if (obj is InternalText) { + InternalText text = (InternalText)obj; + if (text.ContainsOnlyWhitespace) { + elementNodeType = XmlNodeType.Whitespace; + } else { + elementNodeType = XmlNodeType.Text; + } + return true; + } else if (obj is InternalTag) { + // start/end tags can be skipped as the parent InternalElement already handles them, + // TODO all other tags (xml decl, comments, ...) + } else { + throw new NotSupportedException(); + } + objectIterator.MoveInto(); + } + } + + public override void Skip() + { + if (readState == ReadState.Interactive) { + MoveToElement(); + objectIterator.MoveNext(); + ReadCurrentPosition(); + } + } + + public override string Prefix { + get { + if (readState != ReadState.Interactive) + return string.Empty; + if (attributeIndex >= 0) { + if (inAttributeValue) + return string.Empty; + return nameTable.Add(AXmlObject.GetNamespacePrefix(attributes[attributeIndex].Name)); + } + InternalElement element = objectIterator.CurrentObject as InternalElement; + return element != null ? nameTable.Add(element.Prefix) : string.Empty; + } + } + + public override string NamespaceURI { + get { + if (readState != ReadState.Interactive) + return string.Empty; + return LookupNamespace(this.Prefix); + } + } + + public override string LocalName { + get { + if (readState != ReadState.Interactive) + return string.Empty; + if (attributeIndex >= 0) { + if (inAttributeValue) + return string.Empty; + return nameTable.Add(AXmlObject.GetLocalName(attributes[attributeIndex].Name)); + } + InternalElement element = objectIterator.CurrentObject as InternalElement; + return element != null ? nameTable.Add(element.LocalName) : string.Empty; + } + } + + public override bool IsEmptyElement { + get { + if (readState != ReadState.Interactive) + return false; + InternalElement element = objectIterator.CurrentObject as InternalElement; + return element != null && element.NestedObjects.Length == 1; + } + } + + public override string Value { + get { + if (readState != ReadState.Interactive) + return string.Empty; + if (attributeIndex >= 0) + return attributes[attributeIndex].Value; + InternalText text = objectIterator.CurrentObject as InternalText; + return text != null ? text.Value : string.Empty; + } + } + + public override XmlNodeType NodeType { + get { + if (attributeIndex >= 0) + return inAttributeValue ? XmlNodeType.Text : XmlNodeType.Attribute; + else + return elementNodeType; + } + } + + public override XmlNameTable NameTable { + get { return nameTable; } + } + + public override bool MoveToFirstAttribute() + { + return DoMoveToAttribute(0); + } + + public override bool MoveToNextAttribute() + { + return DoMoveToAttribute(attributeIndex + 1); + } + + public override void MoveToAttribute(int i) + { + if (!DoMoveToAttribute(i)) + throw new ArgumentOutOfRangeException("i"); + } + + bool DoMoveToAttribute(int i) + { + if (i >= 0 && i < this.AttributeCount) { + attributeIndex = i; + inAttributeValue = false; + return true; + } + return false; + } + + public override bool MoveToElement() + { + if (attributeIndex >= 0) { + attributeIndex = -1; + inAttributeValue = false; + return true; + } + return false; + } + + int GetAttributeIndex(string name) + { + if (attributes == null) + return -1; + for (int i = 0; i < attributes.Count; i++) { + if (attributes[i].Name == name) + return i; + } + return -1; + } + + int GetAttributeIndex(string name, string ns) + { + if (attributes == null) + return -1; + for (int i = 0; i < attributes.Count; i++) { + if (AXmlObject.GetLocalName(attributes[i].Name) == name && LookupNamespace(AXmlObject.GetNamespacePrefix(attributes[i].Name)) == ns) + return i; + } + return -1; + } + + public override bool MoveToAttribute(string name, string ns) + { + return DoMoveToAttribute(GetAttributeIndex(name, ns)); + } + + public override bool MoveToAttribute(string name) + { + return DoMoveToAttribute(GetAttributeIndex(name)); + } + + public override string LookupNamespace(string prefix) + { + return string.Empty; // TODO implement namespace lookup + } + + public override string GetAttribute(int i) + { + if (attributes == null || i < 0 || i >= attributes.Count) + return null; + return attributes[i].Value; + } + + public override string GetAttribute(string name, string namespaceURI) + { + return GetAttribute(GetAttributeIndex(name, namespaceURI)); + } + + public override string GetAttribute(string name) + { + return GetAttribute(GetAttributeIndex(name)); + } + + public override bool EOF { + get { return readState == ReadState.EndOfFile; } + } + + public override int Depth { + get { return objectIterator.Depth; } + } + + public override void Close() + { + readState = ReadState.Closed; + } + + public override string BaseURI { + get { return string.Empty; } + } + + public override int AttributeCount { + get { return attributes != null ? attributes.Count : 0; } + } + + int CurrentPosition { + get { + if (attributeIndex < 0) + return objectIterator.CurrentPosition; + else + return objectIterator.CurrentPosition + attributes[attributeIndex].StartRelativeToParent; + } + } + + public int LineNumber { + get { + if (offsetToTextLocation != null) + return offsetToTextLocation(CurrentPosition).Line; + else + return 0; + } + } + + public int LinePosition { + get { + if (offsetToTextLocation != null) + return offsetToTextLocation(CurrentPosition).Column - 1; + else + return 0; + } + } + + bool IXmlLineInfo.HasLineInfo() + { + return offsetToTextLocation != null; + } + } +} diff --git a/ICSharpCode.NRefactory.Xml/ICSharpCode.NRefactory.Xml.csproj b/ICSharpCode.NRefactory.Xml/ICSharpCode.NRefactory.Xml.csproj index aa8be493..acd79c7d 100644 --- a/ICSharpCode.NRefactory.Xml/ICSharpCode.NRefactory.Xml.csproj +++ b/ICSharpCode.NRefactory.Xml/ICSharpCode.NRefactory.Xml.csproj @@ -57,6 +57,7 @@ <Compile Include="AXmlDocument.cs" />
<Compile Include="AXmlElement.cs" />
<Compile Include="AXmlObject.cs" />
+ <Compile Include="AXmlReader.cs" />
<Compile Include="AXmlTag.cs" />
<Compile Include="AXmlText.cs" />
<Compile Include="IAXmlVisitor.cs" />
diff --git a/ICSharpCode.NRefactory.Xml/InternalDocument.cs b/ICSharpCode.NRefactory.Xml/InternalDocument.cs index 6ff535c4..adfd9cb6 100644 --- a/ICSharpCode.NRefactory.Xml/InternalDocument.cs +++ b/ICSharpCode.NRefactory.Xml/InternalDocument.cs @@ -126,7 +126,7 @@ namespace ICSharpCode.NRefactory.Xml } } - class InternalAttribute : InternalObject + sealed class InternalAttribute : InternalObject { public string Name; public int EqualsSignLength; // length of equals sign including the surrounding whitespace @@ -143,10 +143,24 @@ namespace ICSharpCode.NRefactory.Xml } } - class InternalElement : InternalObject + sealed class InternalElement : InternalObject { public bool HasEndTag; public bool IsPropertyNested; + public readonly string Name; + + public InternalElement(InternalTag tag) + { + this.Name = tag.Name; + } + + public string Prefix { + get { return AXmlObject.GetNamespacePrefix(Name); } + } + + public string LocalName { + get { return AXmlObject.GetLocalName(Name); } + } public override AXmlObject CreatePublicObject(AXmlObject parent, int parentStartOffset) { diff --git a/ICSharpCode.NRefactory.Xml/ObjectIterator.cs b/ICSharpCode.NRefactory.Xml/ObjectIterator.cs index 1d83f3e2..ad4ad841 100644 --- a/ICSharpCode.NRefactory.Xml/ObjectIterator.cs +++ b/ICSharpCode.NRefactory.Xml/ObjectIterator.cs @@ -24,7 +24,7 @@ namespace ICSharpCode.NRefactory.Xml /// <summary> /// Iterates through an internal object tree. /// </summary> - class ObjectIterator + sealed class ObjectIterator { Stack<InternalObject[]> listStack = new Stack<InternalObject[]>(); Stack<int> indexStack = new Stack<int>(); @@ -33,9 +33,12 @@ namespace ICSharpCode.NRefactory.Xml int currentIndex; InternalObject currentObject; int currentPosition; + internal bool StopAtElementEnd; + bool isAtElementEnd; - public ObjectIterator(InternalObject[] objects) + public ObjectIterator(InternalObject[] objects, int startPosition = 0) { + this.currentPosition = startPosition; this.objects = objects; if (objects.Length > 0) this.currentObject = objects[0]; @@ -49,22 +52,37 @@ namespace ICSharpCode.NRefactory.Xml get { return currentPosition; } } + public bool IsAtElementEnd { + get { return isAtElementEnd; } + } + + public int Depth { + get { return listStack.Count; } + } + public void MoveNext() { if (currentObject == null) return; currentIndex++; currentPosition += currentObject.Length; + isAtElementEnd = false; while (currentIndex >= objects.Length && listStack.Count > 0) { objects = listStack.Pop(); - currentIndex = indexStack.Pop() + 1; + currentIndex = indexStack.Pop(); + if (this.StopAtElementEnd) { + isAtElementEnd = true; + break; + } else { + currentIndex++; + } } currentObject = (currentIndex < objects.Length ? objects[currentIndex] : null); } public void MoveInto() { - if (!(currentObject is InternalElement)) { + if (isAtElementEnd || !(currentObject is InternalElement)) { MoveNext(); } else { listStack.Push(objects); diff --git a/ICSharpCode.NRefactory.Xml/TagMatchingHeuristics.cs b/ICSharpCode.NRefactory.Xml/TagMatchingHeuristics.cs index e5896eaf..2772f44b 100644 --- a/ICSharpCode.NRefactory.Xml/TagMatchingHeuristics.cs +++ b/ICSharpCode.NRefactory.Xml/TagMatchingHeuristics.cs @@ -324,7 +324,7 @@ namespace ICSharpCode.NRefactory.Xml childElements.Add(tag); } } - InternalElement e = new InternalElement(); + InternalElement e = new InternalElement(startTag); e.HasEndTag = (tag != EndTagPlaceholder); e.NestedObjects = new InternalObject[childElements.Count]; int pos = 0; diff --git a/ICSharpCode.NRefactory.Xml/TagReader.cs b/ICSharpCode.NRefactory.Xml/TagReader.cs index 60527dea..e6178de3 100644 --- a/ICSharpCode.NRefactory.Xml/TagReader.cs +++ b/ICSharpCode.NRefactory.Xml/TagReader.cs @@ -97,7 +97,7 @@ namespace ICSharpCode.NRefactory.Xml return; if (tag.IsEmptyTag) { // the tag is its own element - objects[objects.Count - 1] = new InternalElement() { + objects[objects.Count - 1] = new InternalElement(tag) { Length = tag.Length, LengthTouched = tag.LengthTouched, IsPropertyNested = true, @@ -138,7 +138,7 @@ namespace ICSharpCode.NRefactory.Xml } objects.RemoveRange(startIndex, nestedObjects.Length); objects.Add( - new InternalElement { + new InternalElement((InternalTag)nestedObjects[0]) { HasEndTag = true, IsPropertyNested = true, Length = pos, @@ -601,108 +601,79 @@ namespace ICSharpCode.NRefactory.Xml #region Text /// <summary> - /// Reads text and optionaly separates it into fragments. - /// It can also return empty set for no appropriate text input. - /// Make sure you enumerate it only once + /// Reads text. /// </summary> void ReadText(TextType type) { - const int maxTextFragmentSize = 128; - bool finished; - do { - var text = new InternalText(); - var frame = BeginInternalObject(text); - text.Type = type; - - // Limit the reading to just a few characters - // (the first character not to be read) - int fragmentEnd = Math.Min(this.CurrentLocation + maxTextFragmentSize, this.InputLength); - - int start = this.CurrentLocation; - - // Whitespace would be skipped anyway by any operation + var text = new InternalText(); + var frame = BeginInternalObject(text); + text.Type = type; + + int start = this.CurrentLocation; + int fragmentEnd = inputLength; + + // Whitespace would be skipped anyway by any operation + TryMoveToNonWhiteSpace(fragmentEnd); + int wsEnd = this.CurrentLocation; + + // Try move to the terminator given by the context + if (type == TextType.WhiteSpace) { TryMoveToNonWhiteSpace(fragmentEnd); - int wsEnd = this.CurrentLocation; - - // Try move to the terminator given by the context - if (type == TextType.WhiteSpace) { - TryMoveToNonWhiteSpace(fragmentEnd); - } else if (type == TextType.CharacterData) { - while(true) { - if (!TryMoveToAnyOf(new char[] {'<', ']'}, fragmentEnd)) break; // End of fragment - if (TryPeek('<')) break; - if (TryPeek(']')) { - if (TryPeek("]]>")) { - OnSyntaxError(this.CurrentLocation, this.CurrentLocation + 3, "']]>' is not allowed in text"); - } - TryMoveNext(); - continue; - } - throw new InternalException("Infinite loop"); - } - } else if (type == TextType.Comment) { - // Do not report too many errors - bool errorReported = false; - while(true) { - if (!TryMoveTo('-', fragmentEnd)) break; // End of fragment - if (TryPeek("-->")) break; - if (TryPeek("--") && !errorReported) { - OnSyntaxError(this.CurrentLocation, this.CurrentLocation + 2, "'--' is not allowed in comment"); - errorReported = true; + } else if (type == TextType.CharacterData) { + while(true) { + if (!TryMoveToAnyOf(new char[] {'<', ']'}, fragmentEnd)) break; // End of fragment + if (TryPeek('<')) break; + if (TryPeek(']')) { + if (TryPeek("]]>")) { + OnSyntaxError(this.CurrentLocation, this.CurrentLocation + 3, "']]>' is not allowed in text"); } TryMoveNext(); + continue; } - } else if (type == TextType.CData) { - while(true) { - // We can not use use TryMoveTo("]]>", fragmentEnd) because it may incorectly accept "]" at the end of fragment - if (!TryMoveTo(']', fragmentEnd)) break; // End of fragment - if (TryPeek("]]>")) break; - TryMoveNext(); - } - } else if (type == TextType.ProcessingInstruction) { - while(true) { - if (!TryMoveTo('?', fragmentEnd)) break; // End of fragment - if (TryPeek("?>")) break; - TryMoveNext(); - } - } else if (type == TextType.UnknownBang) { - TryMoveToAnyOf(new char[] {'<', '>'}, fragmentEnd); - } else { - throw new InternalException("Uknown type " + type); + throw new InternalException("Infinite loop"); } - - text.ContainsOnlyWhitespace = (wsEnd == this.CurrentLocation); - - // Terminal found or real end was reached; - finished = this.CurrentLocation < fragmentEnd || IsEndOfFile(); - - if (!finished) { - // We have to continue reading more text fragments - - // If there is entity reference, make sure the next segment starts with it to prevent framentation - int entitySearchStart = Math.Max(start + 1 /* data for us */, this.CurrentLocation - maxEntityLength); - int entitySearchLength = this.CurrentLocation - entitySearchStart; - if (entitySearchLength > 0) { - // Note that LastIndexOf works backward - int entityIndex = input.LastIndexOf('&', this.CurrentLocation - entitySearchLength, entitySearchLength); - if (entityIndex != -1) { - GoBack(entityIndex); - } + } else if (type == TextType.Comment) { + // Do not report too many errors + bool errorReported = false; + while(true) { + if (!TryMoveTo('-', fragmentEnd)) break; // End of fragment + if (TryPeek("-->")) break; + if (TryPeek("--") && !errorReported) { + OnSyntaxError(this.CurrentLocation, this.CurrentLocation + 2, "'--' is not allowed in comment"); + errorReported = true; } + TryMoveNext(); } - - string escapedValue = GetText(start, this.CurrentLocation); - if (type == TextType.CharacterData) { - // Normalize end of line first - text.Value = Dereference(NormalizeEndOfLine(escapedValue), start); - } else { - text.Value = escapedValue; + } else if (type == TextType.CData) { + while(true) { + // We can not use use TryMoveTo("]]>", fragmentEnd) because it may incorectly accept "]" at the end of fragment + if (!TryMoveTo(']', fragmentEnd)) break; // End of fragment + if (TryPeek("]]>")) break; + TryMoveNext(); } - text.Value = GetCachedString(text.Value); - - EndInternalObject(frame, storeNewObject: this.CurrentLocation > start); - - } while (!finished); + } else if (type == TextType.ProcessingInstruction) { + while(true) { + if (!TryMoveTo('?', fragmentEnd)) break; // End of fragment + if (TryPeek("?>")) break; + TryMoveNext(); + } + } else if (type == TextType.UnknownBang) { + TryMoveToAnyOf(new char[] {'<', '>'}, fragmentEnd); + } else { + throw new InternalException("Unknown type " + type); + } + + text.ContainsOnlyWhitespace = (wsEnd == this.CurrentLocation); + + string escapedValue = GetText(start, this.CurrentLocation); + if (type == TextType.CharacterData) { + text.Value = Dereference(escapedValue, start); + } else { + text.Value = escapedValue; + } + text.Value = GetCachedString(text.Value); + + EndInternalObject(frame, storeNewObject: this.CurrentLocation > start); } #endregion @@ -856,11 +827,6 @@ namespace ICSharpCode.NRefactory.Xml return false; } } - - static string NormalizeEndOfLine(string text) - { - return text.Replace("\r\n", "\n").Replace('\r', '\n'); - } #endregion } } |