New test.
[mono.git] / mcs / class / System.XML / System.Xml / XmlTextReader.cs
index af67f4f3fbebf9d86747954e88daffe37faa034d..c43f2d594e6d0bf56bf1434a7506298356335df6 100644 (file)
@@ -129,9 +129,13 @@ namespace System.Xml
                // argument is uri, not an xml fragment.
                internal XmlTextReader (bool dummy, XmlResolver resolver, string url, XmlNodeType fragType, XmlParserContext context)
                {
-                       if (resolver == null)
+                       if (resolver == null) {
+#if MOONLIGHT
+                               resolver = new XmlXapResolver ();
+#else
                                resolver = new XmlUrlResolver ();
-
+#endif
+                       }
                        this.XmlResolver = resolver;
                        string uriString;
                        Stream stream = GetStreamFromUrl (url, out uriString);
@@ -144,6 +148,7 @@ namespace System.Xml
                        fragType,
                        context)
                {
+                       disallowReset = true;
                }
 
                internal XmlTextReader (string baseURI, TextReader xmlFragment, XmlNodeType fragType)
@@ -167,6 +172,7 @@ namespace System.Xml
                                fragType,
                                context)
                {
+                       disallowReset = true;
                }
 
                internal XmlTextReader (string url, TextReader fragment, XmlNodeType fragType, XmlParserContext context)
@@ -176,6 +182,12 @@ namespace System.Xml
 
                private Stream GetStreamFromUrl (string url, out string absoluteUriString)
                {
+#if NET_2_1
+                       if (url == null)
+                               throw new ArgumentNullException ("url");
+                       if (url.Length == 0)
+                               throw new ArgumentException ("url");
+#endif
                        Uri uri = resolver.ResolveUri (null, url);
                        absoluteUriString = uri != null ? uri.ToString () : String.Empty;
                        return resolver.GetEntity (uri, null, typeof (Stream)) as Stream;
@@ -319,7 +331,7 @@ namespace System.Xml
                }
 
                public override XmlNameTable NameTable {
-                       get { return parserContext.NameTable; }
+                       get { return nameTable; }
                }
 
                public override XmlNodeType NodeType {
@@ -335,12 +347,10 @@ namespace System.Xml
                        get { return cursorToken.Prefix; }
                }
 
-#if NET_2_0
                public bool ProhibitDtd {
                        get { return prohibitDtd; }
                        set { prohibitDtd = value; }
                }
-#endif
 
                public override char QuoteChar {
                        get { return cursorToken.QuoteChar; }
@@ -437,7 +447,7 @@ namespace System.Xml
 #if NET_2_0
                public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
                {
-                       return parserContext.NamespaceManager.GetNamespacesInScope (scope);
+                       return nsmgr.GetNamespacesInScope (scope);
                }
 
                IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
@@ -469,7 +479,7 @@ namespace System.Xml
 
                private string LookupNamespace (string prefix, bool atomizedNames)
                {
-                       string s = parserContext.NamespaceManager.LookupNamespace (
+                       string s = nsmgr.LookupNamespace (
                                prefix, atomizedNames);
                        return s == String.Empty ? null : s;
                }
@@ -482,7 +492,7 @@ namespace System.Xml
 
                public string LookupPrefix (string ns, bool atomizedName)
                {
-                       return parserContext.NamespaceManager.LookupPrefix (ns, atomizedName);
+                       return nsmgr.LookupPrefix (ns, atomizedName);
                }
 #endif
 
@@ -559,8 +569,12 @@ namespace System.Xml
 
                public override bool Read ()
                {
+                       if (readState == ReadState.Closed)
+                               return false;
                        curNodePeekIndex = peekCharsIndex;
                        preserveCurrentTag = true;
+                       nestLevel = 0;
+                       ClearValueBuffer ();
 
                        if (startNodeType == XmlNodeType.Attribute) {
                                if (currentAttribute == 0)
@@ -597,8 +611,8 @@ namespace System.Xml
                                depthUp = false;
                        }
 
-                       if (shouldSkipUntilEndTag) {
-                               shouldSkipUntilEndTag = false;
+                       if (readCharsInProgress) {
+                               readCharsInProgress = false;
                                return ReadUntilEndTag ();
                        }
 
@@ -654,11 +668,21 @@ namespace System.Xml
 
                public int ReadChars (char [] buffer, int offset, int length)
                {
-                       if (offset < 0)
-                               throw new ArgumentOutOfRangeException ("offset", offset, "Offset must be non-negative integer.");
-                       else if (length < 0)
-                               throw new ArgumentOutOfRangeException ("length", length, "Length must be non-negative integer.");
-                       else if (buffer.Length < offset + length)
+                       if (offset < 0) {
+                               throw new ArgumentOutOfRangeException (
+#if !NET_2_1
+                                       "offset", offset,
+#endif
+                                       "Offset must be non-negative integer.");
+
+                       } else if (length < 0) {
+                               throw new ArgumentOutOfRangeException (
+#if !NET_2_1
+                                       "length", length,
+#endif
+                                       "Length must be non-negative integer.");
+
+                       } else if (buffer.Length < offset + length)
                                throw new ArgumentOutOfRangeException ("buffer length is smaller than the sum of offset and length.");
 
                        if (IsEmptyElement) {
@@ -666,16 +690,21 @@ namespace System.Xml
                                return 0;
                        }
 
-                       if (NodeType != XmlNodeType.Element)
+                       if (!readCharsInProgress && NodeType != XmlNodeType.Element)
                                return 0;
 
+                       preserveCurrentTag = false;
+                       readCharsInProgress = true;
+                       useProceedingLineInfo = true;
+
                        return ReadCharsInternal (buffer, offset, length);
                }
 
                public void ResetState ()
                {
-                       throw new InvalidOperationException ("Cannot call ResetState when parsing an XML fragment.");
-                       Init ();
+                       if (disallowReset)
+                               throw new InvalidOperationException ("Cannot call ResetState when parsing an XML fragment.");
+                       Clear ();
                }
 
                public override void ResolveEntity ()
@@ -825,9 +854,9 @@ namespace System.Xml
                        internal void FillXmlns ()
                        {
                                if (Object.ReferenceEquals (Prefix, XmlNamespaceManager.PrefixXmlns))
-                                       Reader.parserContext.NamespaceManager.AddNamespace (LocalName, Value);
+                                       Reader.nsmgr.AddNamespace (LocalName, Value);
                                else if (Object.ReferenceEquals (Name, XmlNamespaceManager.PrefixXmlns))
-                                       Reader.parserContext.NamespaceManager.AddNamespace (String.Empty, Value);
+                                       Reader.nsmgr.AddNamespace (String.Empty, Value);
                        }
 
                        internal void FillNamespace ()
@@ -853,8 +882,11 @@ namespace System.Xml
                private int attributeCount;
 
                private XmlParserContext parserContext;
+               private XmlNameTable nameTable;
+               private XmlNamespaceManager nsmgr;
 
                private ReadState readState;
+               private bool disallowReset;
 
                private int depth;
                private int elementDepth;
@@ -919,13 +951,18 @@ namespace System.Xml
                private XmlNodeType currentState;
 
                // For ReadChars()/ReadBase64()/ReadBinHex()
-               private bool shouldSkipUntilEndTag;
+               private int nestLevel;
+               private bool readCharsInProgress;
                XmlReaderBinarySupport.CharGetter binaryCharGetter;
 
                // These values are never re-initialized.
                private bool namespaces = true;
                private WhitespaceHandling whitespaceHandling = WhitespaceHandling.All;
+#if MOONLIGHT
+               private XmlResolver resolver = new XmlXapResolver ();
+#else
                private XmlResolver resolver = new XmlUrlResolver ();
+#endif
                private bool normalization = false;
 
                private bool checkCharacters;
@@ -942,6 +979,39 @@ namespace System.Xml
                }
 
                private void Init ()
+               {
+                       allowMultipleRoot = false;
+                       elementNames = new TagName [10];
+                       valueBuffer = new StringBuilder ();
+                       binaryCharGetter = new XmlReaderBinarySupport.CharGetter (ReadChars);
+#if USE_NAME_BUFFER
+                       nameBuffer = new char [initialNameCapacity];
+#endif
+
+                       checkCharacters = true;
+#if NET_2_0
+                       if (Settings != null)
+                               checkCharacters = Settings.CheckCharacters;
+#endif
+                       prohibitDtd = false;
+                       closeInput = true;
+                       entityHandling = EntityHandling.ExpandCharEntities;
+
+                       peekCharsIndex = 0;
+                       if (peekChars == null)
+                               peekChars = new char [peekCharCapacity];
+                       peekCharsLength = -1;
+                       curNodePeekIndex = -1; // read from start
+
+                       line = 1;
+                       column = 1;
+
+                       currentLinkedNodeLineNumber = currentLinkedNodeLinePosition = 0;
+
+                       Clear ();
+               }
+
+               private void Clear ()
                {
                        currentToken = new XmlTokenInfo (this);
                        cursorToken = currentToken;
@@ -950,14 +1020,12 @@ namespace System.Xml
                        attributeCount = 0;
 
                        readState = ReadState.Initial;
-                       allowMultipleRoot = false;
 
                        depth = 0;
                        elementDepth = 0;
                        depthUp = false;
 
                        popScope = allowMultipleRoot = false;
-                       elementNames = new TagName [10];
                        elementNameStackPos = 0;
 
                        isStandalone = false;
@@ -965,38 +1033,14 @@ namespace System.Xml
                        entityReferenceName = String.Empty;
 
 #if USE_NAME_BUFFER
-                       nameBuffer = new char [initialNameCapacity];
                        nameLength = 0;
                        nameCapacity = initialNameCapacity;
 #endif
-
-                       valueBuffer = new StringBuilder ();
-
-                       peekCharsIndex = 0;
-                       if (peekChars == null)
-                               peekChars = new char [peekCharCapacity];
-                       peekCharsLength = -1;
-                       curNodePeekIndex = -1; // read from start
-
-                       line = 1;
-                       column = 1;
-
-                       currentLinkedNodeLineNumber = currentLinkedNodeLinePosition = 0;
                        useProceedingLineInfo = false;
 
                        currentState = XmlNodeType.None;
 
-                       shouldSkipUntilEndTag = false;
-                       binaryCharGetter = new XmlReaderBinarySupport.CharGetter (ReadChars);
-
-                       checkCharacters = true;
-#if NET_2_0
-                       if (Settings != null)
-                               checkCharacters = Settings.CheckCharacters;
-#endif
-                       prohibitDtd = false;
-                       closeInput = true;
-                       entityHandling = EntityHandling.ExpandCharEntities;
+                       readCharsInProgress = false;
                }
 
                private void InitializeContext (string url, XmlParserContext context, TextReader fragment, XmlNodeType fragType)
@@ -1010,15 +1054,27 @@ namespace System.Xml
                                        String.Empty,
                                        XmlSpace.None);
                        }
+                       nameTable = parserContext.NameTable;
+                       nameTable = nameTable != null ? nameTable : new NameTable ();
+                       nsmgr = parserContext.NamespaceManager;
+                       nsmgr = nsmgr != null ? nsmgr : new XmlNamespaceManager (nameTable);
 
                        if (url != null && url.Length > 0) {
+#if NET_2_1
+                               Uri uri = new Uri (url, UriKind.RelativeOrAbsolute);
+#else
                                Uri uri = null;
                                try {
+#if NET_2_0
+                                       uri = new Uri (url, UriKind.RelativeOrAbsolute);
+#else
                                        uri = new Uri (url);
+#endif
                                } catch (Exception) {
                                        string path = Path.GetFullPath ("./a");
                                        uri = new Uri (new Uri (path), url);
                                }
+#endif
                                parserContext.BaseURI = uri.ToString ();
                        }
 
@@ -1229,7 +1285,7 @@ namespace System.Xml
                private bool ReadContent ()
                {
                        if (popScope) {
-                               parserContext.NamespaceManager.PopScope ();
+                               nsmgr.PopScope ();
                                parserContext.PopScope ();
                                popScope = false;
                        }
@@ -1325,7 +1381,7 @@ namespace System.Xml
                                throw NotWFError ("Multiple document element was detected.");
                        currentState = XmlNodeType.Element;
 
-                       parserContext.NamespaceManager.PushScope ();
+                       nsmgr.PushScope ();
 
                        currentLinkedNodeLineNumber = line;
                        currentLinkedNodeLinePosition = column;
@@ -1390,7 +1446,7 @@ namespace System.Xml
                        if (prefix.Length > 0)
                                currentToken.NamespaceURI = LookupNamespace (prefix, true);
                        else if (namespaces)
-                               currentToken.NamespaceURI = parserContext.NamespaceManager.DefaultNamespace;
+                               currentToken.NamespaceURI = nsmgr.DefaultNamespace;
 
                        if (namespaces) {
                                if (NamespaceURI == null)
@@ -1491,7 +1547,7 @@ namespace System.Xml
                        if (expected.Prefix.Length > 0)
                                currentToken.NamespaceURI = LookupNamespace (expected.Prefix, true);
                        else if (namespaces)
-                               currentToken.NamespaceURI = parserContext.NamespaceManager.DefaultNamespace;
+                               currentToken.NamespaceURI = nsmgr.DefaultNamespace;
 
                        popScope = true;
 
@@ -1551,7 +1607,7 @@ namespace System.Xml
                                        break;
                                if (whitespacePool == null)
                                        whitespacePool = new NameTable ();
-#if NET_2_0
+#if NET_2_0 && !NET_2_1
                                valueBuffer.CopyTo (0, whitespaceCache, 0, len);
 #else
                                for (int i = 0; i < len; i++)
@@ -1591,11 +1647,12 @@ namespace System.Xml
                                                break;
                                } else if (normalization && ch == '\r') {
                                        ReadChar ();
-                                       ch = ReadChar ();
+                                       ch = PeekChar ();
                                        if (ch != '\n')
                                                // append '\n' instead of '\r'.
                                                AppendValueChar ('\n');
                                        // and in case of "\r\n", discard '\r'.
+                                       continue;
                                } else {
                                        if (CharacterChecking && XmlChar.IsInvalid (ch))
                                                throw NotWFError ("Not allowed character was found.");
@@ -1776,7 +1833,7 @@ namespace System.Xml
                {
                        IncrementAttributeToken ();
                        XmlAttributeTokenInfo ati = attributeTokens [currentAttribute];
-                       ati.Name = parserContext.NameTable.Add (name);
+                       ati.Name = NameTable.Add (name);
                        ati.Prefix = String.Empty;
                        ati.NamespaceURI = String.Empty;
                        IncrementAttributeValueToken ();
@@ -1902,7 +1959,7 @@ namespace System.Xml
 #if NET_2_0
                                                if (entityHandling == EntityHandling.ExpandEntities) {
                                                        string value = DTD.GenerateEntityAttributeText (entName);
-                                                       foreach (char c in value)
+                                                       foreach (char c in (IEnumerable<char>) value)
                                                                AppendValueChar (c);
                                                } else
 #endif
@@ -2507,8 +2564,8 @@ namespace System.Xml
                                                continueParse = false;
                                                break;
                                        case DtdInputState.InsideDoubleQuoted:
-                                               continue;
                                        case DtdInputState.InsideSingleQuoted:
+                                       case DtdInputState.Comment:
                                                continue;
                                        default:
                                                throw NotWFError ("unexpected end of file at DTD.");
@@ -2690,13 +2747,13 @@ namespace System.Xml
 
                        int start = curNodePeekIndex + startOffset;
 
-                       string name = parserContext.NameTable.Add (
+                       string name = NameTable.Add (
                                peekChars, start, length);
 
                        if (colonAt > 0) {
-                               prefix = parserContext.NameTable.Add (
+                               prefix = NameTable.Add (
                                        peekChars, start, colonAt);
-                               localName = parserContext.NameTable.Add (
+                               localName = NameTable.Add (
                                        peekChars, start + colonAt + 1, length - colonAt - 1);
                        } else {
                                prefix = String.Empty;
@@ -2741,11 +2798,11 @@ namespace System.Xml
                                }
                        }
 
-                       string name = parserContext.NameTable.Add (nameBuffer, 0, nameLength);
+                       string name = NameTable.Add (nameBuffer, 0, nameLength);
 
                        if (colonAt > 0) {
-                               prefix = parserContext.NameTable.Add (nameBuffer, 0, colonAt);
-                               localName = parserContext.NameTable.Add (nameBuffer, colonAt + 1, nameLength - colonAt - 1);
+                               prefix = NameTable.Add (nameBuffer, 0, colonAt);
+                               localName = NameTable.Add (nameBuffer, colonAt + 1, nameLength - colonAt - 1);
                        } else {
                                prefix = String.Empty;
                                localName = name;
@@ -2856,8 +2913,6 @@ namespace System.Xml
                // Returns -1 if it should throw an error.
                private int ReadCharsInternal (char [] buffer, int offset, int length)
                {
-                       shouldSkipUntilEndTag = true;
-
                        int bufIndex = offset;
                        for (int i = 0; i < length; i++) {
                                int c = PeekChar ();
@@ -2865,8 +2920,18 @@ namespace System.Xml
                                case -1:
                                        throw NotWFError ("Unexpected end of xml.");
                                case '<':
+                                       if (i + 1 == length)
+                                               // if it does not end here,
+                                               // it cannot store another
+                                               // character, so stop here.
+                                               return i;
                                        Advance (c);
                                        if (PeekChar () != '/') {
+                                               nestLevel++;
+                                               buffer [bufIndex++] = '<';
+                                               continue;
+                                       }
+                                       else if (nestLevel-- > 0) {
                                                buffer [bufIndex++] = '<';
                                                continue;
                                        }
@@ -2877,7 +2942,7 @@ namespace System.Xml
                                                depthUp = false;
                                        }
                                        ReadEndTag ();
-                                       shouldSkipUntilEndTag = false;
+                                       readCharsInProgress = false;
                                        Read (); // move to the next node
                                        return i;
                                default:
@@ -2905,7 +2970,11 @@ namespace System.Xml
                                case -1:
                                        throw NotWFError ("Unexpected end of xml.");
                                case '<':
-                                       if (PeekChar () != '/')
+                                       if (PeekChar () != '/') {
+                                               nestLevel++;
+                                               continue;
+                                       }
+                                       else if (--nestLevel > 0)
                                                continue;
                                        ReadChar ();
                                        string name = ReadName ();