Browse Source

Add AXmlObject.CreateReader() method.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
def9943063
  1. 1
      ICSharpCode.NRefactory.ConsistencyCheck/ICSharpCode.NRefactory.ConsistencyCheck.csproj
  2. 4
      ICSharpCode.NRefactory.ConsistencyCheck/Program.cs
  3. 90
      ICSharpCode.NRefactory.ConsistencyCheck/Xml/XmlReaderTest.cs
  4. 13
      ICSharpCode.NRefactory.Xml/AXmlDocument.cs
  5. 8
      ICSharpCode.NRefactory.Xml/AXmlElement.cs
  6. 38
      ICSharpCode.NRefactory.Xml/AXmlObject.cs
  7. 339
      ICSharpCode.NRefactory.Xml/AXmlReader.cs
  8. 1
      ICSharpCode.NRefactory.Xml/ICSharpCode.NRefactory.Xml.csproj
  9. 18
      ICSharpCode.NRefactory.Xml/InternalDocument.cs
  10. 26
      ICSharpCode.NRefactory.Xml/ObjectIterator.cs
  11. 2
      ICSharpCode.NRefactory.Xml/TagMatchingHeuristics.cs
  12. 162
      ICSharpCode.NRefactory.Xml/TagReader.cs

1
ICSharpCode.NRefactory.ConsistencyCheck/ICSharpCode.NRefactory.ConsistencyCheck.csproj

@ -69,6 +69,7 @@ @@ -69,6 +69,7 @@
<Compile Include="Xml\IncrementalXmlParserTests.cs" />
<Compile Include="Xml\TestTextSource.cs" />
<Compile Include="Xml\TestTextSourceVersion.cs" />
<Compile Include="Xml\XmlReaderTest.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />

4
ICSharpCode.NRefactory.ConsistencyCheck/Program.cs

@ -21,6 +21,7 @@ using System.Collections.Concurrent; @@ -21,6 +21,7 @@ using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Linq;
using ICSharpCode.NRefactory.ConsistencyCheck.Xml;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Utils;
@ -46,9 +47,6 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck @@ -46,9 +47,6 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
public static void Main(string[] args)
{
//IncrementalXmlParserTests.Run("c:\\temp\\closedxml.xml");
IncrementalXmlParserTests.Run("ICSharpCode.NRefactory.xml");
using (new Timer("Loading solution... ")) {
solution = new Solution(SolutionFile);
}

90
ICSharpCode.NRefactory.ConsistencyCheck/Xml/XmlReaderTest.cs

@ -0,0 +1,90 @@ @@ -0,0 +1,90 @@
// 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.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
using System.Xml.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.Xml;
namespace ICSharpCode.NRefactory.ConsistencyCheck.Xml
{
public static class XmlReaderTest
{
public static void Run(string fileName)
{
var textSource = new StringTextSource(File.ReadAllText(fileName));
using (var textReader = textSource.CreateReader()) {
using (var xmlReader = new XmlTextReader(textReader)) {
Run(xmlReader);
}
}
var doc = new AXmlParser().Parse(textSource);
using (var xmlReader = doc.CreateReader()) {
Run(xmlReader);
}
var xmlDocument = new XmlDocument();
xmlDocument.Load(doc.CreateReader());
xmlDocument.Save(Path.Combine(Program.TempPath, "savedXmlDocument.xml"));
var xDocument = XDocument.Load(doc.CreateReader());
xDocument.Save(Path.Combine(Program.TempPath, "savedXDocument.xml"));
}
static string CSV(IEnumerable<string> input)
{
return string.Join(",", input.Select(i => "\"" + i.Replace("\"", "\"\"") + "\""));
}
static readonly string[] ignoredProperties = {
"NameTable", "CanResolveEntity", "CanReadBinaryContent", "CanReadValueChunk", "EOF", "ValueType",
"SchemaInfo", "IsDefault", "BaseURI", "Settings"
};
public static void Run(XmlReader reader)
{
using (StreamWriter output = File.CreateText(Path.Combine(Program.TempPath, reader.GetType().Name + "-output.csv"))) {
var properties = typeof(XmlReader).GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.GetIndexParameters().Length == 0 && !ignoredProperties.Contains(p.Name))
.ToArray();
output.WriteLine(CSV(properties.Select(p => p.Name)));
do {
output.WriteLine(CSV(properties.Select(p => ToString(p.GetValue(reader, null)))));
} while (reader.Read());
output.WriteLine(CSV(properties.Select(p => ToString(p.GetValue(reader, null)))));
}
}
static string ToString(object val)
{
if (val == null)
return "null";
else if (val is string)
return "\"" + CSharpOutputVisitor.ConvertString((string)val) + "\"";
else if (val is char)
return "'" + CSharpOutputVisitor.ConvertChar((char)val) + "'";
else
return val.ToString();
}
}
}

13
ICSharpCode.NRefactory.Xml/AXmlDocument.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Globalization;
using System.Xml;
namespace ICSharpCode.NRefactory.Xml
{
@ -31,6 +32,18 @@ namespace ICSharpCode.NRefactory.Xml @@ -31,6 +32,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)
{

8
ICSharpCode.NRefactory.Xml/AXmlElement.cs

@ -90,17 +90,13 @@ namespace ICSharpCode.NRefactory.Xml @@ -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>

38
ICSharpCode.NRefactory.Xml/AXmlObject.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.Utils;
@ -50,6 +51,22 @@ namespace ICSharpCode.NRefactory.Xml @@ -50,6 +51,22 @@ namespace ICSharpCode.NRefactory.Xml
this.internalObject = internalObject;
}
/// <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>
@ -81,6 +98,23 @@ namespace ICSharpCode.NRefactory.Xml @@ -81,6 +98,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>
@ -119,7 +153,7 @@ namespace ICSharpCode.NRefactory.Xml @@ -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 @@ -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(':');

339
ICSharpCode.NRefactory.Xml/AXmlReader.cs

@ -0,0 +1,339 @@ @@ -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;
}
}
}

1
ICSharpCode.NRefactory.Xml/ICSharpCode.NRefactory.Xml.csproj

@ -57,6 +57,7 @@ @@ -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" />

18
ICSharpCode.NRefactory.Xml/InternalDocument.cs

@ -126,7 +126,7 @@ namespace ICSharpCode.NRefactory.Xml @@ -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 @@ -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)
{

26
ICSharpCode.NRefactory.Xml/ObjectIterator.cs

@ -24,7 +24,7 @@ namespace ICSharpCode.NRefactory.Xml @@ -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 @@ -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 @@ -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);

2
ICSharpCode.NRefactory.Xml/TagMatchingHeuristics.cs

@ -324,7 +324,7 @@ namespace ICSharpCode.NRefactory.Xml @@ -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;

162
ICSharpCode.NRefactory.Xml/TagReader.cs

@ -97,7 +97,7 @@ namespace ICSharpCode.NRefactory.Xml @@ -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 @@ -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 @@ -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 @@ -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
}
}

Loading…
Cancel
Save