//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.Runtime.Serialization.Json { using System.Globalization; using System.IO; #if !MONO using System.ServiceModel; #endif using System.Text; using System.Runtime.Serialization; using System.Collections.Generic; using System.Xml; class XmlJsonReader : XmlBaseReader, IXmlJsonReaderInitializer { const int MaxTextChunk = 2048; static byte[] charType = new byte[256] { CharType.None, // 0 (.) CharType.None, // 1 (.) CharType.None, // 2 (.) CharType.None, // 3 (.) CharType.None, // 4 (.) CharType.None, // 5 (.) CharType.None, // 6 (.) CharType.None, // 7 (.) CharType.None, // 8 (.) CharType.None, // 9 (.) CharType.None, // A (.) CharType.None, // B (.) CharType.None, // C (.) CharType.None, // D (.) CharType.None, // E (.) CharType.None, // F (.) CharType.None, // 10 (.) CharType.None, // 11 (.) CharType.None, // 12 (.) CharType.None, // 13 (.) CharType.None, // 14 (.) CharType.None, // 15 (.) CharType.None, // 16 (.) CharType.None, // 17 (.) CharType.None, // 18 (.) CharType.None, // 19 (.) CharType.None, // 1A (.) CharType.None, // 1B (.) CharType.None, // 1C (.) CharType.None, // 1D (.) CharType.None, // 1E (.) CharType.None, // 1F (.) CharType.None, // 20 ( ) CharType.None, // 21 (!) CharType.None, // 22 (") CharType.None, // 23 (#) CharType.None, // 24 ($) CharType.None, // 25 (%) CharType.None, // 26 (&) CharType.None, // 27 (') CharType.None, // 28 (() CharType.None, // 29 ()) CharType.None, // 2A (*) CharType.None, // 2B (+) CharType.None, // 2C (,) CharType.None | CharType.Name, // 2D (-) CharType.None | CharType.Name, // 2E (.) CharType.None, // 2F (/) CharType.None | CharType.Name, // 30 (0) CharType.None | CharType.Name, // 31 (1) CharType.None | CharType.Name, // 32 (2) CharType.None | CharType.Name, // 33 (3) CharType.None | CharType.Name, // 34 (4) CharType.None | CharType.Name, // 35 (5) CharType.None | CharType.Name, // 36 (6) CharType.None | CharType.Name, // 37 (7) CharType.None | CharType.Name, // 38 (8) CharType.None | CharType.Name, // 39 (9) CharType.None, // 3A (:) CharType.None, // 3B (;) CharType.None, // 3C (<) CharType.None, // 3D (=) CharType.None, // 3E (>) CharType.None, // 3F (?) CharType.None, // 40 (@) CharType.None | CharType.FirstName | CharType.Name, // 41 (A) CharType.None | CharType.FirstName | CharType.Name, // 42 (B) CharType.None | CharType.FirstName | CharType.Name, // 43 (C) CharType.None | CharType.FirstName | CharType.Name, // 44 (D) CharType.None | CharType.FirstName | CharType.Name, // 45 (E) CharType.None | CharType.FirstName | CharType.Name, // 46 (F) CharType.None | CharType.FirstName | CharType.Name, // 47 (G) CharType.None | CharType.FirstName | CharType.Name, // 48 (H) CharType.None | CharType.FirstName | CharType.Name, // 49 (I) CharType.None | CharType.FirstName | CharType.Name, // 4A (J) CharType.None | CharType.FirstName | CharType.Name, // 4B (K) CharType.None | CharType.FirstName | CharType.Name, // 4C (L) CharType.None | CharType.FirstName | CharType.Name, // 4D (M) CharType.None | CharType.FirstName | CharType.Name, // 4E (N) CharType.None | CharType.FirstName | CharType.Name, // 4F (O) CharType.None | CharType.FirstName | CharType.Name, // 50 (P) CharType.None | CharType.FirstName | CharType.Name, // 51 (Q) CharType.None | CharType.FirstName | CharType.Name, // 52 (R) CharType.None | CharType.FirstName | CharType.Name, // 53 (S) CharType.None | CharType.FirstName | CharType.Name, // 54 (T) CharType.None | CharType.FirstName | CharType.Name, // 55 (U) CharType.None | CharType.FirstName | CharType.Name, // 56 (V) CharType.None | CharType.FirstName | CharType.Name, // 57 (W) CharType.None | CharType.FirstName | CharType.Name, // 58 (X) CharType.None | CharType.FirstName | CharType.Name, // 59 (Y) CharType.None | CharType.FirstName | CharType.Name, // 5A (Z) CharType.None, // 5B ([) CharType.None, // 5C (\) CharType.None, // 5D (]) CharType.None, // 5E (^) CharType.None | CharType.FirstName | CharType.Name, // 5F (_) CharType.None, // 60 (`) CharType.None | CharType.FirstName | CharType.Name, // 61 (a) CharType.None | CharType.FirstName | CharType.Name, // 62 (b) CharType.None | CharType.FirstName | CharType.Name, // 63 (c) CharType.None | CharType.FirstName | CharType.Name, // 64 (d) CharType.None | CharType.FirstName | CharType.Name, // 65 (e) CharType.None | CharType.FirstName | CharType.Name, // 66 (f) CharType.None | CharType.FirstName | CharType.Name, // 67 (g) CharType.None | CharType.FirstName | CharType.Name, // 68 (h) CharType.None | CharType.FirstName | CharType.Name, // 69 (i) CharType.None | CharType.FirstName | CharType.Name, // 6A (j) CharType.None | CharType.FirstName | CharType.Name, // 6B (k) CharType.None | CharType.FirstName | CharType.Name, // 6C (l) CharType.None | CharType.FirstName | CharType.Name, // 6D (m) CharType.None | CharType.FirstName | CharType.Name, // 6E (n) CharType.None | CharType.FirstName | CharType.Name, // 6F (o) CharType.None | CharType.FirstName | CharType.Name, // 70 (p) CharType.None | CharType.FirstName | CharType.Name, // 71 (q) CharType.None | CharType.FirstName | CharType.Name, // 72 (r) CharType.None | CharType.FirstName | CharType.Name, // 73 (s) CharType.None | CharType.FirstName | CharType.Name, // 74 (t) CharType.None | CharType.FirstName | CharType.Name, // 75 (u) CharType.None | CharType.FirstName | CharType.Name, // 76 (v) CharType.None | CharType.FirstName | CharType.Name, // 77 (w) CharType.None | CharType.FirstName | CharType.Name, // 78 (x) CharType.None | CharType.FirstName | CharType.Name, // 79 (y) CharType.None | CharType.FirstName | CharType.Name, // 7A (z) CharType.None, // 7B ({) CharType.None, // 7C (|) CharType.None, // 7D (}) CharType.None, // 7E (~) CharType.None, // 7F (.) CharType.None | CharType.FirstName | CharType.Name, // 80 (.) CharType.None | CharType.FirstName | CharType.Name, // 81 (.) CharType.None | CharType.FirstName | CharType.Name, // 82 (.) CharType.None | CharType.FirstName | CharType.Name, // 83 (.) CharType.None | CharType.FirstName | CharType.Name, // 84 (.) CharType.None | CharType.FirstName | CharType.Name, // 85 (.) CharType.None | CharType.FirstName | CharType.Name, // 86 (.) CharType.None | CharType.FirstName | CharType.Name, // 87 (.) CharType.None | CharType.FirstName | CharType.Name, // 88 (.) CharType.None | CharType.FirstName | CharType.Name, // 89 (.) CharType.None | CharType.FirstName | CharType.Name, // 8A (.) CharType.None | CharType.FirstName | CharType.Name, // 8B (.) CharType.None | CharType.FirstName | CharType.Name, // 8C (.) CharType.None | CharType.FirstName | CharType.Name, // 8D (.) CharType.None | CharType.FirstName | CharType.Name, // 8E (.) CharType.None | CharType.FirstName | CharType.Name, // 8F (.) CharType.None | CharType.FirstName | CharType.Name, // 90 (.) CharType.None | CharType.FirstName | CharType.Name, // 91 (.) CharType.None | CharType.FirstName | CharType.Name, // 92 (.) CharType.None | CharType.FirstName | CharType.Name, // 93 (.) CharType.None | CharType.FirstName | CharType.Name, // 94 (.) CharType.None | CharType.FirstName | CharType.Name, // 95 (.) CharType.None | CharType.FirstName | CharType.Name, // 96 (.) CharType.None | CharType.FirstName | CharType.Name, // 97 (.) CharType.None | CharType.FirstName | CharType.Name, // 98 (.) CharType.None | CharType.FirstName | CharType.Name, // 99 (.) CharType.None | CharType.FirstName | CharType.Name, // 9A (.) CharType.None | CharType.FirstName | CharType.Name, // 9B (.) CharType.None | CharType.FirstName | CharType.Name, // 9C (.) CharType.None | CharType.FirstName | CharType.Name, // 9D (.) CharType.None | CharType.FirstName | CharType.Name, // 9E (.) CharType.None | CharType.FirstName | CharType.Name, // 9F (.) CharType.None | CharType.FirstName | CharType.Name, // A0 (�) CharType.None | CharType.FirstName | CharType.Name, // A1 (�) CharType.None | CharType.FirstName | CharType.Name, // A2 (�) CharType.None | CharType.FirstName | CharType.Name, // A3 (�) CharType.None | CharType.FirstName | CharType.Name, // A4 () CharType.None | CharType.FirstName | CharType.Name, // A5 (�) CharType.None | CharType.FirstName | CharType.Name, // A6 (�) CharType.None | CharType.FirstName | CharType.Name, // A7 () CharType.None | CharType.FirstName | CharType.Name, // A8 (") CharType.None | CharType.FirstName | CharType.Name, // A9 (c) CharType.None | CharType.FirstName | CharType.Name, // AA (�) CharType.None | CharType.FirstName | CharType.Name, // AB (�) CharType.None | CharType.FirstName | CharType.Name, // AC (�) CharType.None | CharType.FirstName | CharType.Name, // AD (-) CharType.None | CharType.FirstName | CharType.Name, // AE (r) CharType.None | CharType.FirstName | CharType.Name, // AF (_) CharType.None | CharType.FirstName | CharType.Name, // B0 (�) CharType.None | CharType.FirstName | CharType.Name, // B1 (�) CharType.None | CharType.FirstName | CharType.Name, // B2 (�) CharType.None | CharType.FirstName | CharType.Name, // B3 (3) CharType.None | CharType.FirstName | CharType.Name, // B4 (') CharType.None | CharType.FirstName | CharType.Name, // B5 (�) CharType.None | CharType.FirstName | CharType.Name, // B6 () CharType.None | CharType.FirstName | CharType.Name, // B7 (�) CharType.None | CharType.FirstName | CharType.Name, // B8 (,) CharType.None | CharType.FirstName | CharType.Name, // B9 (1) CharType.None | CharType.FirstName | CharType.Name, // BA (�) CharType.None | CharType.FirstName | CharType.Name, // BB (�) CharType.None | CharType.FirstName | CharType.Name, // BC (�) CharType.None | CharType.FirstName | CharType.Name, // BD (�) CharType.None | CharType.FirstName | CharType.Name, // BE (_) CharType.None | CharType.FirstName | CharType.Name, // BF (�) CharType.None | CharType.FirstName | CharType.Name, // C0 (A) CharType.None | CharType.FirstName | CharType.Name, // C1 (A) CharType.None | CharType.FirstName | CharType.Name, // C2 (A) CharType.None | CharType.FirstName | CharType.Name, // C3 (A) CharType.None | CharType.FirstName | CharType.Name, // C4 (�) CharType.None | CharType.FirstName | CharType.Name, // C5 (�) CharType.None | CharType.FirstName | CharType.Name, // C6 (�) CharType.None | CharType.FirstName | CharType.Name, // C7 (�) CharType.None | CharType.FirstName | CharType.Name, // C8 (E) CharType.None | CharType.FirstName | CharType.Name, // C9 (�) CharType.None | CharType.FirstName | CharType.Name, // CA (E) CharType.None | CharType.FirstName | CharType.Name, // CB (E) CharType.None | CharType.FirstName | CharType.Name, // CC (I) CharType.None | CharType.FirstName | CharType.Name, // CD (I) CharType.None | CharType.FirstName | CharType.Name, // CE (I) CharType.None | CharType.FirstName | CharType.Name, // CF (I) CharType.None | CharType.FirstName | CharType.Name, // D0 (D) CharType.None | CharType.FirstName | CharType.Name, // D1 (�) CharType.None | CharType.FirstName | CharType.Name, // D2 (O) CharType.None | CharType.FirstName | CharType.Name, // D3 (O) CharType.None | CharType.FirstName | CharType.Name, // D4 (O) CharType.None | CharType.FirstName | CharType.Name, // D5 (O) CharType.None | CharType.FirstName | CharType.Name, // D6 (�) CharType.None | CharType.FirstName | CharType.Name, // D7 (x) CharType.None | CharType.FirstName | CharType.Name, // D8 (O) CharType.None | CharType.FirstName | CharType.Name, // D9 (U) CharType.None | CharType.FirstName | CharType.Name, // DA (U) CharType.None | CharType.FirstName | CharType.Name, // DB (U) CharType.None | CharType.FirstName | CharType.Name, // DC (�) CharType.None | CharType.FirstName | CharType.Name, // DD (Y) CharType.None | CharType.FirstName | CharType.Name, // DE (_) CharType.None | CharType.FirstName | CharType.Name, // DF (�) CharType.None | CharType.FirstName | CharType.Name, // E0 (�) CharType.None | CharType.FirstName | CharType.Name, // E1 (�) CharType.None | CharType.FirstName | CharType.Name, // E2 (�) CharType.None | CharType.FirstName | CharType.Name, // E3 (a) CharType.None | CharType.FirstName | CharType.Name, // E4 (�) CharType.None | CharType.FirstName | CharType.Name, // E5 (�) CharType.None | CharType.FirstName | CharType.Name, // E6 (�) CharType.None | CharType.FirstName | CharType.Name, // E7 (�) CharType.None | CharType.FirstName | CharType.Name, // E8 (�) CharType.None | CharType.FirstName | CharType.Name, // E9 (�) CharType.None | CharType.FirstName | CharType.Name, // EA (�) CharType.None | CharType.FirstName | CharType.Name, // EB (�) CharType.None | CharType.FirstName | CharType.Name, // EC (�) CharType.None | CharType.FirstName | CharType.Name, // ED (�) CharType.None | CharType.FirstName | CharType.Name, // EE (�) CharType.None | CharType.FirstName | CharType.Name, // EF (�) CharType.None | CharType.FirstName | CharType.Name, // F0 (d) CharType.None | CharType.FirstName | CharType.Name, // F1 (�) CharType.None | CharType.FirstName | CharType.Name, // F2 (�) CharType.None | CharType.FirstName | CharType.Name, // F3 (�) CharType.None | CharType.FirstName | CharType.Name, // F4 (�) CharType.None | CharType.FirstName | CharType.Name, // F5 (o) CharType.None | CharType.FirstName | CharType.Name, // F6 (�) CharType.None | CharType.FirstName | CharType.Name, // F7 (�) CharType.None | CharType.FirstName | CharType.Name, // F8 (o) CharType.None | CharType.FirstName | CharType.Name, // F9 (�) CharType.None | CharType.FirstName | CharType.Name, // FA (�) CharType.None | CharType.FirstName | CharType.Name, // FB (�) CharType.None | CharType.FirstName | CharType.Name, // FC (�) CharType.None | CharType.FirstName | CharType.Name, // FD (y) CharType.None | CharType.FirstName | CharType.Name, // FE (_) CharType.None | CharType.FirstName | CharType.Name, // FF (�) }; bool buffered; byte[] charactersToSkipOnNextRead; JsonComplexTextMode complexTextMode = JsonComplexTextMode.None; bool expectingFirstElementInNonPrimitiveChild; int maxBytesPerRead; OnXmlDictionaryReaderClose onReaderClose; bool readServerTypeElement = false; int scopeDepth = 0; JsonNodeType[] scopes; enum JsonComplexTextMode { QuotedText, NumericalText, None }; public override bool CanCanonicalize { get { return false; } } public override string Value { get { if (IsAttributeValue && !this.IsLocalName(JsonGlobals.typeString)) { return UnescapeJsonString(base.Value); } return base.Value; } } bool IsAttributeValue { get { return (this.Node.NodeType == XmlNodeType.Attribute || this.Node is XmlAttributeTextNode); } } bool IsReadingCollection { get { return ((scopeDepth > 0) && (scopes[scopeDepth] == JsonNodeType.Collection)); } } bool IsReadingComplexText { get { return ((!this.Node.IsAtomicValue) && (this.Node.NodeType == XmlNodeType.Text)); } } public override void Close() { base.Close(); OnXmlDictionaryReaderClose onClose = this.onReaderClose; this.onReaderClose = null; ResetState(); if (onClose != null) { try { onClose(this); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); } } } public override void EndCanonicalization() { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } public override string GetAttribute(int index) { return UnescapeJsonString(base.GetAttribute(index)); } public override string GetAttribute(string localName, string namespaceUri) { if (localName != JsonGlobals.typeString) { return UnescapeJsonString(base.GetAttribute(localName, namespaceUri)); } return base.GetAttribute(localName, namespaceUri); } public override string GetAttribute(string name) { if (name != JsonGlobals.typeString) { return UnescapeJsonString(base.GetAttribute(name)); } return base.GetAttribute(name); } public override string GetAttribute(XmlDictionaryString localName, XmlDictionaryString namespaceUri) { if (XmlDictionaryString.GetString(localName) != JsonGlobals.typeString) { return UnescapeJsonString(base.GetAttribute(localName, namespaceUri)); } return base.GetAttribute(localName, namespaceUri); } public override bool Read() { if (this.Node.CanMoveToElement) { // If we're positioned on an attribute or attribute text on an empty element, we need to move back // to the element in order to get the correct setting of ExitScope MoveToElement(); } if (this.Node.ReadState == ReadState.Closed) { return false; } if (this.Node.ExitScope) { ExitScope(); } if (!buffered) { BufferReader.SetWindow(ElementNode.BufferOffset, this.maxBytesPerRead); } byte ch; // Skip whitespace before checking EOF // Complex text check necessary because whitespace could be part of really long // quoted text that's read using multiple Read() calls. // This also ensures that we deal with the whitespace-only input case properly by not // floating a root element at all. if (!IsReadingComplexText) { SkipWhitespaceInBufferReader(); if (TryGetByte(out ch)) { if (charactersToSkipOnNextRead[0] == ch || charactersToSkipOnNextRead[1] == ch) { BufferReader.SkipByte(); charactersToSkipOnNextRead[0] = 0; charactersToSkipOnNextRead[1] = 0; } } SkipWhitespaceInBufferReader(); if (TryGetByte(out ch)) { if (ch == JsonGlobals.EndCollectionByte && IsReadingCollection) { BufferReader.SkipByte(); SkipWhitespaceInBufferReader(); ExitJsonScope(); } } if (BufferReader.EndOfFile) { if (scopeDepth > 0) { MoveToEndElement(); return true; } else { MoveToEndOfFile(); return false; } } } ch = BufferReader.GetByte(); if (scopeDepth == 0) { ReadNonExistentElementName(StringHandleConstStringType.Root); } else if (IsReadingComplexText) { switch (complexTextMode) { case JsonComplexTextMode.NumericalText: ReadNumericalText(); break; case JsonComplexTextMode.QuotedText: if (ch == (byte)'\\') { ReadEscapedCharacter(true); // moveToText } else { ReadQuotedText(true); // moveToText } break; case JsonComplexTextMode.None: XmlExceptionHelper.ThrowXmlException(this, new XmlException(SR.GetString(SR.JsonEncounteredUnexpectedCharacter, (char)ch))); break; } } else if (IsReadingCollection) { ReadNonExistentElementName(StringHandleConstStringType.Item); } else if (ch == JsonGlobals.EndCollectionByte) { BufferReader.SkipByte(); MoveToEndElement(); ExitJsonScope(); } else if (ch == JsonGlobals.ObjectByte) { BufferReader.SkipByte(); SkipWhitespaceInBufferReader(); ch = (byte)BufferReader.GetByte(); if (ch == JsonGlobals.EndObjectByte) { BufferReader.SkipByte(); SkipWhitespaceInBufferReader(); if (TryGetByte(out ch)) { if (ch == JsonGlobals.MemberSeparatorByte) { BufferReader.SkipByte(); } } else { charactersToSkipOnNextRead[0] = JsonGlobals.MemberSeparatorByte; } MoveToEndElement(); } else { EnterJsonScope(JsonNodeType.Object); ParseStartElement(); } } else if (ch == JsonGlobals.EndObjectByte) { BufferReader.SkipByte(); if (expectingFirstElementInNonPrimitiveChild) { SkipWhitespaceInBufferReader(); ch = BufferReader.GetByte(); if ((ch == JsonGlobals.MemberSeparatorByte) || (ch == JsonGlobals.EndObjectByte)) { BufferReader.SkipByte(); } else { XmlExceptionHelper.ThrowXmlException(this, new XmlException(SR.GetString(SR.JsonEncounteredUnexpectedCharacter, (char)ch))); } expectingFirstElementInNonPrimitiveChild = false; } MoveToEndElement(); } else if (ch == JsonGlobals.MemberSeparatorByte) { BufferReader.SkipByte(); MoveToEndElement(); } else if (ch == JsonGlobals.QuoteByte) { if (readServerTypeElement) { readServerTypeElement = false; EnterJsonScope(JsonNodeType.Object); ParseStartElement(); } else if (this.Node.NodeType == XmlNodeType.Element) { if (expectingFirstElementInNonPrimitiveChild) { EnterJsonScope(JsonNodeType.Object); ParseStartElement(); } else { BufferReader.SkipByte(); ReadQuotedText(true); // moveToText } } else if (this.Node.NodeType == XmlNodeType.EndElement) { EnterJsonScope(JsonNodeType.Element); ParseStartElement(); } else { XmlExceptionHelper.ThrowXmlException(this, new XmlException(SR.GetString(SR.JsonEncounteredUnexpectedCharacter, JsonGlobals.QuoteChar))); } } else if (ch == (byte)'f') { int offset; byte[] buffer = BufferReader.GetBuffer(5, out offset); if (buffer[offset + 1] != (byte)'a' || buffer[offset + 2] != (byte)'l' || buffer[offset + 3] != (byte)'s' || buffer[offset + 4] != (byte)'e') { XmlExceptionHelper.ThrowTokenExpected(this, "false", Encoding.UTF8.GetString(buffer, offset, 5)); } BufferReader.Advance(5); if (TryGetByte(out ch)) { if (!IsWhitespace(ch) && ch != JsonGlobals.MemberSeparatorByte && ch != JsonGlobals.EndObjectChar && ch != JsonGlobals.EndCollectionByte) { XmlExceptionHelper.ThrowTokenExpected(this, "false", Encoding.UTF8.GetString(buffer, offset, 4) + (char)ch); } } MoveToAtomicText().Value.SetValue(ValueHandleType.UTF8, offset, 5); } else if (ch == (byte)'t') { int offset; byte[] buffer = BufferReader.GetBuffer(4, out offset); if (buffer[offset + 1] != (byte)'r' || buffer[offset + 2] != (byte)'u' || buffer[offset + 3] != (byte)'e') { XmlExceptionHelper.ThrowTokenExpected(this, "true", Encoding.UTF8.GetString(buffer, offset, 4)); } BufferReader.Advance(4); if (TryGetByte(out ch)) { if (!IsWhitespace(ch) && ch != JsonGlobals.MemberSeparatorByte && ch != JsonGlobals.EndObjectChar && ch != JsonGlobals.EndCollectionByte) { XmlExceptionHelper.ThrowTokenExpected(this, "true", Encoding.UTF8.GetString(buffer, offset, 4) + (char)ch); } } MoveToAtomicText().Value.SetValue(ValueHandleType.UTF8, offset, 4); } else if (ch == (byte)'n') { int offset; byte[] buffer = BufferReader.GetBuffer(4, out offset); if (buffer[offset + 1] != (byte)'u' || buffer[offset + 2] != (byte)'l' || buffer[offset + 3] != (byte)'l') { XmlExceptionHelper.ThrowTokenExpected(this, "null", Encoding.UTF8.GetString(buffer, offset, 4)); } BufferReader.Advance(4); SkipWhitespaceInBufferReader(); if (TryGetByte(out ch)) { if (ch == JsonGlobals.MemberSeparatorByte || ch == JsonGlobals.EndObjectChar) { BufferReader.SkipByte(); } else if (ch != JsonGlobals.EndCollectionByte) { XmlExceptionHelper.ThrowTokenExpected(this, "null", Encoding.UTF8.GetString(buffer, offset, 4) + (char)ch); } } else { charactersToSkipOnNextRead[0] = JsonGlobals.MemberSeparatorByte; charactersToSkipOnNextRead[1] = JsonGlobals.EndObjectByte; } MoveToEndElement(); } else if ((ch == (byte)'-') || (((byte)'0' <= ch) && (ch <= (byte)'9')) || (ch == (byte)'I') || (ch == (byte)'N')) { ReadNumericalText(); } else { XmlExceptionHelper.ThrowXmlException(this, new XmlException(SR.GetString(SR.JsonEncounteredUnexpectedCharacter, (char)ch))); } return true; } public override decimal ReadContentAsDecimal() { string value = ReadContentAsString(); try { return decimal.Parse(value, NumberStyles.Float, NumberFormatInfo.InvariantInfo); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception)); } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception)); } catch (OverflowException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception)); } } public override int ReadContentAsInt() { return ParseInt(ReadContentAsString(), NumberStyles.Float); } public override long ReadContentAsLong() { string value = ReadContentAsString(); try { return long.Parse(value, NumberStyles.Float, NumberFormatInfo.InvariantInfo); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception)); } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception)); } catch (OverflowException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception)); } } public override int ReadValueAsBase64(byte[] buffer, int offset, int count) { if (IsAttributeValue) { if (buffer == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("buffer")); } if (offset < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString(System.Runtime.Serialization.SR.ValueMustBeNonNegative))); } if (offset > buffer.Length) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString(System.Runtime.Serialization.SR.OffsetExceedsBufferSize, buffer.Length))); } if (count < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", System.Runtime.Serialization.SR.GetString(System.Runtime.Serialization.SR.ValueMustBeNonNegative))); } if (count > buffer.Length - offset) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", System.Runtime.Serialization.SR.GetString(System.Runtime.Serialization.SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset))); } return 0; } return base.ReadValueAsBase64(buffer, offset, count); } public override int ReadValueChunk(char[] chars, int offset, int count) { if (IsAttributeValue) { if (chars == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("chars")); } if (offset < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString(System.Runtime.Serialization.SR.ValueMustBeNonNegative))); } if (offset > chars.Length) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString(System.Runtime.Serialization.SR.OffsetExceedsBufferSize, chars.Length))); } if (count < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", System.Runtime.Serialization.SR.GetString(System.Runtime.Serialization.SR.ValueMustBeNonNegative))); } if (count > chars.Length - offset) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", System.Runtime.Serialization.SR.GetString(System.Runtime.Serialization.SR.SizeExceedsRemainingBufferSpace, chars.Length - offset))); } int actual; string value = UnescapeJsonString(this.Node.ValueAsString); actual = Math.Min(count, value.Length); if (actual > 0) { value.CopyTo(0, chars, offset, actual); if (this.Node.QNameType == QNameType.Xmlns) { this.Node.Namespace.Uri.SetValue(0, 0); } else { this.Node.Value.SetValue(ValueHandleType.UTF8, 0, 0); } } return actual; } return base.ReadValueChunk(chars, offset, count); } public void SetInput(byte[] buffer, int offset, int count, Encoding encoding, XmlDictionaryReaderQuotas quotas, OnXmlDictionaryReaderClose onClose) { if (buffer == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("buffer"); } if (offset < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative))); } if (offset > buffer.Length) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ArgumentOutOfRangeException("offset", SR.GetString(SR.JsonOffsetExceedsBufferSize, buffer.Length))); } if (count < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative))); } if (count > buffer.Length - offset) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ArgumentOutOfRangeException("count", SR.GetString(SR.JsonSizeExceedsRemainingBufferSpace, buffer.Length - offset))); } MoveToInitial(quotas, onClose); ArraySegment seg = JsonEncodingStreamWrapper.ProcessBuffer(buffer, offset, count, encoding); BufferReader.SetBuffer(seg.Array, seg.Offset, seg.Count, null, null); this.buffered = true; ResetState(); } public void SetInput(Stream stream, Encoding encoding, XmlDictionaryReaderQuotas quotas, OnXmlDictionaryReaderClose onClose) { if (stream == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("stream"); } MoveToInitial(quotas, onClose); stream = new JsonEncodingStreamWrapper(stream, encoding, true); BufferReader.SetBuffer(stream, null, null); this.buffered = false; ResetState(); } public override void StartCanonicalization(Stream stream, bool includeComments, string[] inclusivePrefixes) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } internal static void CheckArray(Array array, int offset, int count) { if (array == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("array")); } if (offset < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative))); } if (offset > array.Length) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.OffsetExceedsBufferSize, array.Length))); } if (count < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative))); } if (count > array.Length - offset) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, array.Length - offset))); } } protected override XmlSigningNodeWriter CreateSigningNodeWriter() { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.JsonMethodNotSupported, "CreateSigningNodeWriter"))); } static int BreakText(byte[] buffer, int offset, int length) { // See if we might be breaking a utf8 sequence if (length > 0 && (buffer[offset + length - 1] & 0x80) == 0x80) { // Find the lead char of the utf8 sequence (0x11xxxxxx) int originalLength = length; do { length--; } while (length > 0 && (buffer[offset + length] & 0xC0) != 0xC0); // Couldn't find the lead char if (length == 0) { return originalLength; // Invalid utf8 sequence - can't break } // Count how many bytes follow the lead char byte b = (byte)(buffer[offset + length] << 2); int byteCount = 2; while ((b & 0x80) == 0x80) { b = (byte)(b << 1); byteCount++; // There shouldn't be more than 3 bytes following the lead char if (byteCount > 4) { return originalLength; // Invalid utf8 sequence - can't break } } if (length + byteCount == originalLength) { return originalLength; // sequence fits exactly } if (length == 0) { return originalLength; // Quota too small to read a char } } return length; } static int ComputeNumericalTextLength(byte[] buffer, int offset, int offsetMax) { int beginOffset = offset; while (offset < offsetMax) { byte ch = buffer[offset]; if (ch == JsonGlobals.MemberSeparatorByte || ch == JsonGlobals.EndObjectByte || ch == JsonGlobals.EndCollectionByte || IsWhitespace(ch)) { break; } offset++; } return offset - beginOffset; } static int ComputeQuotedTextLengthUntilEndQuote(byte[] buffer, int offset, int offsetMax, out bool escaped) { // Assumes that for quoted text "someText", the first " has been consumed. // For original text "someText", buffer passed in is someText". // This method returns return 8 for someText" (s, o, m, e, T, e, x, t). int beginOffset = offset; escaped = false; while (offset < offsetMax) { byte ch = buffer[offset]; if (ch < 0x20) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.InvalidCharacterEncountered, (char)ch))); } else if (ch == (byte)'\\' || ch == 0xEF) { escaped = true; break; } else if (ch == JsonGlobals.QuoteByte) { break; } offset++; } return offset - beginOffset; } // From JSON spec: // ws = *( // %x20 / ; Space // %x09 / ; Horizontal tab // %x0A / ; Line feed or New line // %x0D ; Carriage return // ) static bool IsWhitespace(byte ch) { return ((ch == 0x20) || (ch == 0x09) || (ch == 0x0A) || (ch == 0x0D)); } static char ParseChar(string value, NumberStyles style) { int intValue = ParseInt(value, style); try { return Convert.ToChar(intValue); } catch (OverflowException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "char", exception)); } } static int ParseInt(string value, NumberStyles style) { try { return int.Parse(value, style, NumberFormatInfo.InvariantInfo); } catch (ArgumentException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception)); } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception)); } catch (OverflowException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception)); } } void BufferElement() { int elementOffset = BufferReader.Offset; const int byteCount = 128; bool done = false; byte quoteChar = 0; while (!done) { int offset; int offsetMax; byte[] buffer = BufferReader.GetBuffer(byteCount, out offset, out offsetMax); if (offset + byteCount != offsetMax) { break; } for (int i = offset; i < offsetMax && !done; i++) { byte b = buffer[i]; if (b == '\\') { i++; if (i >= offsetMax) { break; } } else if (quoteChar == 0) { if (b == (byte)'\'' || b == JsonGlobals.QuoteByte) { quoteChar = b; } if (b == JsonGlobals.NameValueSeparatorByte) { done = true; } } else { if (b == quoteChar) { quoteChar = 0; } } } BufferReader.Advance(byteCount); } BufferReader.Offset = elementOffset; } void EnterJsonScope(JsonNodeType currentNodeType) { scopeDepth++; if (scopes == null) { scopes = new JsonNodeType[4]; } else if (scopes.Length == scopeDepth) { JsonNodeType[] newScopes = new JsonNodeType[scopeDepth * 2]; Array.Copy(scopes, newScopes, scopeDepth); scopes = newScopes; } scopes[scopeDepth] = currentNodeType; } JsonNodeType ExitJsonScope() { JsonNodeType nodeTypeToReturn = scopes[scopeDepth]; scopes[scopeDepth] = JsonNodeType.None; scopeDepth--; return nodeTypeToReturn; } new void MoveToEndElement() { ExitJsonScope(); base.MoveToEndElement(); } void MoveToInitial(XmlDictionaryReaderQuotas quotas, OnXmlDictionaryReaderClose onClose) { MoveToInitial(quotas); this.maxBytesPerRead = quotas.MaxBytesPerRead; this.onReaderClose = onClose; } void ParseAndSetLocalName() { XmlElementNode elementNode = EnterScope(); elementNode.NameOffset = BufferReader.Offset; do { if (BufferReader.GetByte() == '\\') { ReadEscapedCharacter(false); // moveToText } else { ReadQuotedText(false); // moveToText } } while (complexTextMode == JsonComplexTextMode.QuotedText); int actualOffset = BufferReader.Offset - 1; // -1 to ignore " at end of local name elementNode.LocalName.SetValue(elementNode.NameOffset, actualOffset - elementNode.NameOffset); elementNode.NameLength = actualOffset - elementNode.NameOffset; elementNode.Namespace.Uri.SetValue(elementNode.NameOffset, 0); elementNode.Prefix.SetValue(PrefixHandleType.Empty); elementNode.IsEmptyElement = false; elementNode.ExitScope = false; elementNode.BufferOffset = actualOffset; int currentCharacter = (int)BufferReader.GetByte(elementNode.NameOffset); if ((charType[currentCharacter] & CharType.FirstName) == 0) { SetJsonNameWithMapping(elementNode); } else { for (int i = 0, offset = elementNode.NameOffset; i < elementNode.NameLength; i++, offset++) { currentCharacter = (int)BufferReader.GetByte(offset); if ((charType[currentCharacter] & CharType.Name) == 0 || currentCharacter >= 0x80) { SetJsonNameWithMapping(elementNode); break; } } } } void ParseStartElement() { if (!buffered) { BufferElement(); } expectingFirstElementInNonPrimitiveChild = false; byte ch = BufferReader.GetByte(); if (ch == JsonGlobals.QuoteByte) { BufferReader.SkipByte(); ParseAndSetLocalName(); SkipWhitespaceInBufferReader(); SkipExpectedByteInBufferReader(JsonGlobals.NameValueSeparatorByte); SkipWhitespaceInBufferReader(); if (BufferReader.GetByte() == JsonGlobals.ObjectByte) { BufferReader.SkipByte(); expectingFirstElementInNonPrimitiveChild = true; } ReadAttributes(); } else { // " and } are the only two valid characters that may follow a { XmlExceptionHelper.ThrowTokenExpected(this, "\"", (char)ch); } } void ReadAttributes() { XmlAttributeNode attribute = AddAttribute(); attribute.LocalName.SetConstantValue(StringHandleConstStringType.Type); attribute.Namespace.Uri.SetValue(0, 0); attribute.Prefix.SetValue(PrefixHandleType.Empty); SkipWhitespaceInBufferReader(); byte nextByte = BufferReader.GetByte(); switch (nextByte) { case JsonGlobals.QuoteByte: if (!expectingFirstElementInNonPrimitiveChild) { attribute.Value.SetConstantValue(ValueHandleConstStringType.String); } else { attribute.Value.SetConstantValue(ValueHandleConstStringType.Object); ReadServerTypeAttribute(true); } break; case (byte)'n': attribute.Value.SetConstantValue(ValueHandleConstStringType.Null); break; case (byte)'t': case (byte)'f': attribute.Value.SetConstantValue(ValueHandleConstStringType.Boolean); break; case JsonGlobals.ObjectByte: attribute.Value.SetConstantValue(ValueHandleConstStringType.Object); ReadServerTypeAttribute(false); break; case JsonGlobals.EndObjectByte: if (expectingFirstElementInNonPrimitiveChild) { attribute.Value.SetConstantValue(ValueHandleConstStringType.Object); } else { XmlExceptionHelper.ThrowXmlException(this, new XmlException(SR.GetString(SR.JsonEncounteredUnexpectedCharacter, (char)nextByte))); } break; case JsonGlobals.CollectionByte: attribute.Value.SetConstantValue(ValueHandleConstStringType.Array); BufferReader.SkipByte(); EnterJsonScope(JsonNodeType.Collection); break; default: if (nextByte == '-' || (nextByte <= '9' && nextByte >= '0') || nextByte == 'N' || nextByte == 'I') { attribute.Value.SetConstantValue(ValueHandleConstStringType.Number); } else { XmlExceptionHelper.ThrowXmlException(this, new XmlException(SR.GetString(SR.JsonEncounteredUnexpectedCharacter, (char)nextByte))); } break; } } void ReadEscapedCharacter(bool moveToText) { BufferReader.SkipByte(); char ch = (char)BufferReader.GetByte(); if (ch == 'u') { BufferReader.SkipByte(); int offset; byte[] buffer = BufferReader.GetBuffer(5, out offset); string bufferAsString = Encoding.UTF8.GetString(buffer, offset, 4); BufferReader.Advance(4); int charValue = ParseChar(bufferAsString, NumberStyles.HexNumber); if (Char.IsHighSurrogate((char)charValue)) { byte nextByte = BufferReader.GetByte(); if (nextByte == (byte)'\\') { BufferReader.SkipByte(); SkipExpectedByteInBufferReader((byte)'u'); buffer = BufferReader.GetBuffer(5, out offset); bufferAsString = Encoding.UTF8.GetString(buffer, offset, 4); BufferReader.Advance(4); char lowChar = ParseChar(bufferAsString, NumberStyles.HexNumber); if (!Char.IsLowSurrogate(lowChar)) { XmlExceptionHelper.ThrowXmlException(this, new XmlException(System.Runtime.Serialization.SR.GetString(System.Runtime.Serialization.SR.XmlInvalidLowSurrogate, bufferAsString))); } charValue = new SurrogateChar(lowChar, (char)charValue).Char; } } if (buffer[offset + 4] == JsonGlobals.QuoteByte) { BufferReader.SkipByte(); if (moveToText) { MoveToAtomicText().Value.SetCharValue(charValue); } complexTextMode = JsonComplexTextMode.None; } else { if (moveToText) { MoveToComplexText().Value.SetCharValue(charValue); } complexTextMode = JsonComplexTextMode.QuotedText; } } else { switch (ch) { case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case '\"': case '\\': case '/': // Do nothing. These are the actual unescaped values. break; default: XmlExceptionHelper.ThrowXmlException(this, new XmlException(SR.GetString(SR.JsonEncounteredUnexpectedCharacter, (char)ch))); break; } BufferReader.SkipByte(); if (BufferReader.GetByte() == JsonGlobals.QuoteByte) { BufferReader.SkipByte(); if (moveToText) { MoveToAtomicText().Value.SetCharValue(ch); } complexTextMode = JsonComplexTextMode.None; } else { if (moveToText) { MoveToComplexText().Value.SetCharValue(ch); } complexTextMode = JsonComplexTextMode.QuotedText; } } } void ReadNonExistentElementName(StringHandleConstStringType elementName) { EnterJsonScope(JsonNodeType.Object); XmlElementNode elementNode = EnterScope(); elementNode.LocalName.SetConstantValue(elementName); elementNode.Namespace.Uri.SetValue(elementNode.NameOffset, 0); elementNode.Prefix.SetValue(PrefixHandleType.Empty); elementNode.BufferOffset = BufferReader.Offset; elementNode.IsEmptyElement = false; elementNode.ExitScope = false; ReadAttributes(); } int ReadNonFFFE() { int off; byte[] buff = BufferReader.GetBuffer(3, out off); if (buff[off + 1] == 0xBF && (buff[off + 2] == 0xBE || buff[off + 2] == 0xBF)) { XmlExceptionHelper.ThrowXmlException(this, new XmlException(SR.GetString(SR.JsonInvalidFFFE))); } return 3; } void ReadNumericalText() { byte[] buffer; int offset; int offsetMax; int length; if (buffered) { buffer = BufferReader.GetBuffer(out offset, out offsetMax); length = ComputeNumericalTextLength(buffer, offset, offsetMax); } else { buffer = BufferReader.GetBuffer(MaxTextChunk, out offset, out offsetMax); length = ComputeNumericalTextLength(buffer, offset, offsetMax); length = BreakText(buffer, offset, length); } BufferReader.Advance(length); if (offset <= offsetMax - length) { MoveToAtomicText().Value.SetValue(ValueHandleType.UTF8, offset, length); complexTextMode = JsonComplexTextMode.None; } else { MoveToComplexText().Value.SetValue(ValueHandleType.UTF8, offset, length); complexTextMode = JsonComplexTextMode.NumericalText; } } void ReadQuotedText(bool moveToText) { byte[] buffer; int offset; int offsetMax; int length; bool escaped; bool endReached; if (buffered) { buffer = BufferReader.GetBuffer(out offset, out offsetMax); length = ComputeQuotedTextLengthUntilEndQuote(buffer, offset, offsetMax, out escaped); endReached = offset < offsetMax - length; } else { buffer = BufferReader.GetBuffer(MaxTextChunk, out offset, out offsetMax); length = ComputeQuotedTextLengthUntilEndQuote(buffer, offset, offsetMax, out escaped); endReached = offset < offsetMax - length; length = BreakText(buffer, offset, length); } if (escaped && BufferReader.GetByte() == 0xEF) { offset = BufferReader.Offset; length = ReadNonFFFE(); } BufferReader.Advance(length); if (!escaped && endReached) { if (moveToText) { MoveToAtomicText().Value.SetValue(ValueHandleType.UTF8, offset, length); } SkipExpectedByteInBufferReader(JsonGlobals.QuoteByte); complexTextMode = JsonComplexTextMode.None; } else { if ((length == 0) && escaped) { ReadEscapedCharacter(moveToText); } else { if (moveToText) { MoveToComplexText().Value.SetValue(ValueHandleType.UTF8, offset, length); } complexTextMode = JsonComplexTextMode.QuotedText; } } } void ReadServerTypeAttribute(bool consumedObjectChar) { if (!consumedObjectChar) { SkipExpectedByteInBufferReader(JsonGlobals.ObjectByte); SkipWhitespaceInBufferReader(); // we only allow " or } after { byte ch = BufferReader.GetByte(); if (ch != JsonGlobals.QuoteByte && ch != JsonGlobals.EndObjectByte) { XmlExceptionHelper.ThrowTokenExpected(this, "\"", (char)ch); } } else { SkipWhitespaceInBufferReader(); } int offset; int offsetMax; byte[] buffer = BufferReader.GetBuffer(8, out offset, out offsetMax); if (offset + 8 <= offsetMax) { if (buffer[offset + 0] == (byte)'\"' && buffer[offset + 1] == (byte)'_' && buffer[offset + 2] == (byte)'_' && buffer[offset + 3] == (byte)'t' && buffer[offset + 4] == (byte)'y' && buffer[offset + 5] == (byte)'p' && buffer[offset + 6] == (byte)'e' && buffer[offset + 7] == (byte)'\"') { XmlAttributeNode attribute = AddAttribute(); attribute.LocalName.SetValue(offset + 1, 6); attribute.Namespace.Uri.SetValue(0, 0); attribute.Prefix.SetValue(PrefixHandleType.Empty); BufferReader.Advance(8); if (!buffered) { BufferElement(); } SkipWhitespaceInBufferReader(); SkipExpectedByteInBufferReader(JsonGlobals.NameValueSeparatorByte); SkipWhitespaceInBufferReader(); SkipExpectedByteInBufferReader(JsonGlobals.QuoteByte); buffer = BufferReader.GetBuffer(out offset, out offsetMax); do { if (BufferReader.GetByte() == '\\') { ReadEscapedCharacter(false); // moveToText } else { ReadQuotedText(false); // moveToText } } while (complexTextMode == JsonComplexTextMode.QuotedText); attribute.Value.SetValue(ValueHandleType.UTF8, offset, BufferReader.Offset - 1 - offset); SkipWhitespaceInBufferReader(); if (BufferReader.GetByte() == JsonGlobals.MemberSeparatorByte) { BufferReader.SkipByte(); readServerTypeElement = true; } } } if (BufferReader.GetByte() == JsonGlobals.EndObjectByte) { BufferReader.SkipByte(); readServerTypeElement = false; expectingFirstElementInNonPrimitiveChild = false; } else { readServerTypeElement = true; } } void ResetState() { complexTextMode = JsonComplexTextMode.None; expectingFirstElementInNonPrimitiveChild = false; charactersToSkipOnNextRead = new byte[2]; scopeDepth = 0; if ((scopes != null) && (scopes.Length > JsonGlobals.maxScopeSize)) { scopes = null; } } void SetJsonNameWithMapping(XmlElementNode elementNode) { Namespace ns = AddNamespace(); ns.Prefix.SetValue(PrefixHandleType.A); ns.Uri.SetConstantValue(StringHandleConstStringType.Item); AddXmlnsAttribute(ns); XmlAttributeNode attribute = AddAttribute(); attribute.LocalName.SetConstantValue(StringHandleConstStringType.Item); attribute.Namespace.Uri.SetValue(0, 0); attribute.Prefix.SetValue(PrefixHandleType.Empty); attribute.Value.SetValue(ValueHandleType.UTF8, elementNode.NameOffset, elementNode.NameLength); elementNode.NameLength = 0; elementNode.Prefix.SetValue(PrefixHandleType.A); elementNode.LocalName.SetConstantValue(StringHandleConstStringType.Item); elementNode.Namespace = ns; } void SkipExpectedByteInBufferReader(byte characterToSkip) { if (BufferReader.GetByte() != characterToSkip) { XmlExceptionHelper.ThrowTokenExpected(this, ((char)characterToSkip).ToString(), (char)BufferReader.GetByte()); } BufferReader.SkipByte(); } void SkipWhitespaceInBufferReader() { byte ch; while (TryGetByte(out ch) && IsWhitespace(ch)) { BufferReader.SkipByte(); } } bool TryGetByte(out byte ch) { int offset, offsetMax; byte[] buffer = BufferReader.GetBuffer(1, out offset, out offsetMax); if (offset < offsetMax) { ch = buffer[offset]; return true; } else { ch = (byte)'\0'; return false; } } string UnescapeJsonString(string val) { if (val == null) { return null; } StringBuilder sb = null; int startIndex = 0, count = 0; for (int i = 0; i < val.Length; i++) { if (val[i] == '\\') { i++; if (sb == null) { sb = new StringBuilder(); } sb.Append(val, startIndex, count); Fx.Assert(i < val.Length, "Found that an '\' was the last character in a string. ReadServerTypeAttriute validates that the escape sequence is valid when it calls ReadQuotedText and ReadEscapedCharacter"); if (i >= val.Length) { XmlExceptionHelper.ThrowXmlException(this, new XmlException(SR.GetString(SR.JsonEncounteredUnexpectedCharacter, val[i]))); } switch (val[i]) { case '"': case '\'': case '/': case '\\': sb.Append(val[i]); break; case 'b': sb.Append('\b'); break; case 'f': sb.Append('\f'); break; case 'n': sb.Append('\n'); break; case 'r': sb.Append('\r'); break; case 't': sb.Append('\t'); break; case 'u': if ((i + 3) >= val.Length) { XmlExceptionHelper.ThrowXmlException(this, new XmlException(SR.GetString(SR.JsonEncounteredUnexpectedCharacter, val[i]))); } sb.Append(ParseChar(val.Substring(i + 1, 4), NumberStyles.HexNumber)); i += 4; break; } startIndex = i + 1; count = 0; } else { count++; } } if (sb == null) { return val; } if (count > 0) { sb.Append(val, startIndex, count); } return sb.ToString(); } static class CharType { public const byte FirstName = 0x01; public const byte Name = 0x02; public const byte None = 0x00; } } }