/// <summary> /// Moves the reader to the bookmarked position. /// </summary> /// <param name="bookmark">The bookmark object to move to.</param> internal void MoveToBookmark(object bookmark) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(this.isBuffering, "Bookmarks can only be used when in buffering mode."); Debug.Assert(bookmark != null, "bookmark != null"); BufferedNode bookmarkNode = bookmark as BufferedNode; Debug.Assert(bookmarkNode != null, "Invalid bookmark."); #if DEBUG BufferedNode node = this.bufferedNodesHead; bool foundBookmark = false; do { if (node == bookmarkNode) { foundBookmark = true; break; } node = node.Next; }while (node != this.bufferedNodesHead); Debug.Assert(foundBookmark, "Tried to move to a bookmark which is already out of scope, bookmarks are only valid inside a single buffering session."); #endif this.currentBufferedNode = bookmarkNode; }
/// <summary> /// Constructor. /// </summary> /// <param name="propertyNode">The property node to create the record for.</param> internal PropertyDeduplicationRecord(BufferedNode propertyNode) { Debug.Assert(propertyNode != null, "propertyNode != null"); Debug.Assert(propertyNode.NodeType == JsonNodeType.Property, "Only property node can be stored as the property node of the deduplication record."); this.propertyNode = propertyNode; }
internal BufferingJsonReader(TextReader reader, bool removeDuplicateProperties, int maxInnerErrorDepth) : base(reader) { this.removeDuplicateProperties = removeDuplicateProperties; this.maxInnerErrorDepth = maxInnerErrorDepth; this.bufferedNodesHead = null; this.currentBufferedNode = null; }
/// <summary> /// Puts the reader into the state where it buffers read nodes. /// </summary> internal void StartBuffering() { Debug.Assert(!this.isBuffering, "Buffering is already turned on. Must not call StartBuffering again."); if (this.bufferedNodesHead == null) { // capture the current state of the reader as the first item in the buffer (if there are none) this.bufferedNodesHead = new BufferedNode(base.NodeType, base.Value); } else { this.removeOnNextRead = false; } Debug.Assert(this.bufferedNodesHead != null, "Expected at least the current node in the buffer when starting buffering."); // Set the currentBufferedNode to the first node in the list; this means every time we start buffering we reset the // position of the current buffered node since in general we don't know how far ahead we have read before and thus don't // want to blindly continuing to read. The model is that with every call to StartBuffering you reset the position of the // current node in the list and start reading through the buffer again. if (this.currentBufferedNode == null) { this.currentBufferedNode = this.bufferedNodesHead; } this.isBuffering = true; }
private string GetAttributeWithAtomizedName(string name, string namespaceURI) { if (this.bufferedNodes.Count > 0) { for (LinkedListNode <BufferedNode> node = this.GetCurrentElementNode().AttributeNodes.First; node != null; node = node.Next) { BufferedNode node2 = node.Value; if (object.ReferenceEquals(namespaceURI, node2.NamespaceUri) && object.ReferenceEquals(name, node2.LocalName)) { return(node.Value.Value); } } return(null); } string str = null; while (this.reader.MoveToNextAttribute()) { if (object.ReferenceEquals(name, this.reader.LocalName) && object.ReferenceEquals(namespaceURI, this.reader.NamespaceURI)) { str = this.reader.Value; break; } } this.reader.MoveToElement(); return(str); }
/// <summary> /// Reorders the buffered properties to conform to the required payload order. /// </summary> /// <remarks> /// The required order is: odata.context comes first, odata.removed comes next (for deleted resources), /// then comes odata.type, then all odata.* property annotations /// and finally, we preserve the relative order of custom annotations and data properties.</remarks> internal void Reorder() { BufferedNode currentNode = this.ObjectStart; // Sort the property names preserving the relative order of the properties except for the OData instance annotations. IEnumerable <string> sortedPropertyNames = this.SortPropertyNames(); foreach (string propertyName in sortedPropertyNames) { Debug.Assert(this.propertyCache.ContainsKey(propertyName), "Property must be in the cache for its name to be in the list of property names."); object storedValue = this.propertyCache[propertyName]; BufferedProperty storedProperty = storedValue as BufferedProperty; if (storedProperty != null) { storedProperty.InsertAfter(currentNode); currentNode = storedProperty.EndOfPropertyValueNode; } else { IEnumerable <BufferedProperty> sortedProperties = SortBufferedProperties((IList <BufferedProperty>)storedValue); foreach (BufferedProperty sortedProperty in sortedProperties) { sortedProperty.InsertAfter(currentNode); currentNode = sortedProperty.EndOfPropertyValueNode; } } } }
/// <summary> /// Reads the next node from the JSON reader and if a start-object node is detected starts reading ahead and /// tries to parse an in-stream error. /// </summary> /// <returns>true if a new node was found, or false if end of input was reached.</returns> private bool ReadNextAndCheckForInStreamError() { Debug.Assert(!this.parsingInStreamError, "!this.parsingInStreamError"); this.parsingInStreamError = true; try { // read the next node in the current reader mode (buffering or non-buffering) bool result = this.ReadInternal(); if (base.NodeType == JsonNodeType.StartObject) { // If we find a StartObject node we have to read ahead and check whether this // JSON object represents an in-stream error. If we are currently in buffering // mode remember the current position in the buffer; otherwise start buffering. bool wasBuffering = this.isBuffering; BufferedNode storedPosition = null; if (this.isBuffering) { storedPosition = this.currentBufferedNode; } else { this.StartBuffering(); } // If the duplicate properties should be removed, do it here. if (this.removeDuplicateProperties) { // The method will look for in-stream errors and throw on them as it performs the deduplication. this.RemoveDuplicateProperties(); } else { // read ahead and check for in-stream error this.TryReadErrorAndThrow(); } // Reset the reader state to non-buffering or to the previously // backed up position in the buffer. if (wasBuffering) { this.currentBufferedNode = storedPosition; } else { this.StopBuffering(); } } return(result); } finally { this.parsingInStreamError = false; } }
/// <summary> /// Constructor. /// </summary> /// <param name="reader">The text reader to read input characters from.</param> /// <param name="inStreamErrorPropertyName">The name of the property that denotes an in-stream error.</param> /// <param name="maxInnerErrorDepth">The maximum number of recursive internalexception objects to allow when reading in-stream errors.</param> /// <param name="jsonFormat">The specific JSON-based format expected by the reader.</param> /// <param name="isIeee754Compatible">If it is IEEE754 Compatible</param> internal BufferingJsonReader(TextReader reader, string inStreamErrorPropertyName, int maxInnerErrorDepth, ODataFormat jsonFormat, bool isIeee754Compatible) : base(reader, jsonFormat, isIeee754Compatible) { Debug.Assert(reader != null, "reader != null"); this.inStreamErrorPropertyName = inStreamErrorPropertyName; this.maxInnerErrorDepth = maxInnerErrorDepth; this.bufferedNodesHead = null; this.currentBufferedNode = null; }
/// <summary> /// Constructor. /// </summary> /// <param name="reader">The text reader to read input characters from.</param> /// <param name="inStreamErrorPropertyName">The name of the property that denotes an in-stream error.</param> /// <param name="maxInnerErrorDepth">The maximum number of recursive internalexception objects to allow when reading in-stream errors.</param> /// <param name="jsonFormat">The specific JSON-based format expected by the reader.</param> /// <param name="isIeee754Compatible">If it is IEEE754 Compatible</param> internal BufferingJsonReader(TextReader reader, string inStreamErrorPropertyName, int maxInnerErrorDepth, ODataFormat jsonFormat, bool isIeee754Compatible) : base(reader, jsonFormat, isIeee754Compatible) { Debug.Assert(reader != null, "reader != null"); this.inStreamErrorPropertyName = inStreamErrorPropertyName; this.maxInnerErrorDepth = maxInnerErrorDepth; this.bufferedNodesHead = null; this.currentBufferedNode = null; }
/// <summary> /// Constructor. /// </summary> /// <param name="innerReader">The inner JSON reader.</param> /// <param name="inStreamErrorPropertyName">The name of the property that denotes an in-stream error.</param> /// <param name="maxInnerErrorDepth">The maximum number of recursive internalexception objects to allow when reading in-stream errors.</param> internal BufferingJsonReader(IJsonReader innerReader, string inStreamErrorPropertyName, int maxInnerErrorDepth) { Debug.Assert(innerReader != null, "innerReader != null"); this.innerReader = innerReader; this.inStreamErrorPropertyName = inStreamErrorPropertyName; this.maxInnerErrorDepth = maxInnerErrorDepth; this.bufferedNodesHead = null; this.currentBufferedNode = null; }
/// <summary> /// Constructor. /// </summary> /// <param name="reader">The text reader to read input characters from.</param> /// <param name="inStreamErrorPropertyName">The name of the property that denotes an in-stream error.</param> /// <param name="maxInnerErrorDepth">The maximum number of recursive internalexception objects to allow when reading in-stream errors.</param> /// <param name="jsonFormat">The specific JSON-based format expected by the reader.</param> internal BufferingJsonReader(TextReader reader, string inStreamErrorPropertyName, int maxInnerErrorDepth, ODataFormat jsonFormat) : base(reader, jsonFormat) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(reader != null, "reader != null"); this.inStreamErrorPropertyName = inStreamErrorPropertyName; this.maxInnerErrorDepth = maxInnerErrorDepth; this.bufferedNodesHead = null; this.currentBufferedNode = null; }
/// <summary> /// Constructor. /// </summary> /// <param name="reader">The text reader to read input characters from.</param> /// <param name="removeDuplicateProperties">true if the reader should remove duplicate properties and simulate the WCF DS Server behavior.</param> /// <param name="maxInnerErrorDepth">The maximumum number of recursive internalexception objects to allow when reading in-stream errors.</param> internal BufferingJsonReader(TextReader reader, bool removeDuplicateProperties, int maxInnerErrorDepth) : base(reader) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(reader != null, "reader != null"); this.removeDuplicateProperties = removeDuplicateProperties; this.maxInnerErrorDepth = maxInnerErrorDepth; this.bufferedNodesHead = null; this.currentBufferedNode = null; }
/// <summary> /// Moves the reader to the bookmarked position. /// </summary> /// <param name="bookmark">The bookmark object to move to.</param> internal void MoveToBookmark(object bookmark) { Debug.Assert(this.isBuffering, "Bookmarks can only be used when in buffering mode."); Debug.Assert(bookmark != null, "bookmark != null"); BufferedNode bookmarkNode = bookmark as BufferedNode; Debug.Assert(bookmarkNode != null, "Invalid bookmark."); #if DEBUG Debug.Assert(this.NodeExistsInCurrentBuffer(bookmarkNode), "Tried to move to a bookmark which is already out of scope, bookmarks are only valid inside a single buffering session."); #endif this.currentBufferedNode = bookmarkNode; }
/// <summary> /// Removes the head node from the buffer. /// </summary> private void RemoveFirstNodeInBuffer() { if (this.bufferedNodesHead.Next == this.bufferedNodesHead) { Debug.Assert(this.bufferedNodesHead.Previous == this.bufferedNodesHead, "The linked list is corrupted."); this.bufferedNodesHead = null; } else { this.bufferedNodesHead.Previous.Next = this.bufferedNodesHead.Next; this.bufferedNodesHead.Next.Previous = this.bufferedNodesHead.Previous; this.bufferedNodesHead = this.bufferedNodesHead.Next; } }
/// <summary> /// Reads the next node from the JSON reader and if a start-object node is detected starts reading ahead and /// tries to parse an in-stream error. /// </summary> /// <returns>true if a new node was found, or false if end of input was reached.</returns> private bool ReadNextAndCheckForInStreamError() { Debug.Assert(!this.parsingInStreamError, "!this.parsingInStreamError"); this.parsingInStreamError = true; try { // read the next node in the current reader mode (buffering or non-buffering) bool result = this.ReadInternal(); if (base.NodeType == JsonNodeType.StartObject) { // If we find a StartObject node we have to read ahead and check whether this // JSON object represents an in-stream error. If we are currently in buffering // mode remember the current position in the buffer; otherwise start buffering. bool wasBuffering = this.isBuffering; BufferedNode storedPosition = null; if (this.isBuffering) { storedPosition = this.currentBufferedNode; } else { this.StartBuffering(); } this.ProcessObjectValue(); // Reset the reader state to non-buffering or to the previously // backed up position in the buffer. if (wasBuffering) { this.currentBufferedNode = storedPosition; } else { this.StopBuffering(); } } return(result); } finally { this.parsingInStreamError = false; } }
private bool ReadInternal() { bool flag; if (this.removeOnNextRead) { if (this.bufferedNodesHead.Next == this.bufferedNodesHead) { this.bufferedNodesHead = null; } else { this.bufferedNodesHead.Previous.Next = this.bufferedNodesHead.Next; this.bufferedNodesHead.Next.Previous = this.bufferedNodesHead.Previous; this.bufferedNodesHead = this.bufferedNodesHead.Next; } this.removeOnNextRead = false; } if (this.isBuffering) { if (this.currentBufferedNode.Next != this.bufferedNodesHead) { this.currentBufferedNode = this.currentBufferedNode.Next; return(true); } if (this.parsingInStreamError) { flag = base.Read(); BufferedNode node = new BufferedNode(base.NodeType, base.Value) { Previous = this.bufferedNodesHead.Previous, Next = this.bufferedNodesHead }; this.bufferedNodesHead.Previous.Next = node; this.bufferedNodesHead.Previous = node; this.currentBufferedNode = node; return(flag); } return(this.ReadNextAndCheckForInStreamError()); } if (this.bufferedNodesHead == null) { return(this.parsingInStreamError ? base.Read() : this.ReadNextAndCheckForInStreamError()); } flag = this.bufferedNodesHead.NodeType != JsonNodeType.EndOfInput; this.removeOnNextRead = true; return(flag); }
internal void StartBuffering() { if (this.bufferedNodesHead == null) { this.bufferedNodesHead = new BufferedNode(base.NodeType, base.Value); } else { this.removeOnNextRead = false; } if (this.currentBufferedNode == null) { this.currentBufferedNode = this.bufferedNodesHead; } this.isBuffering = true; }
/// <summary> /// Determines whether the given node exists in the current buffer. /// </summary> /// <param name="nodeToCheck">The node to test.</param> /// <returns>true if the given node was found in the buffer; false otherwise.</returns> private bool NodeExistsInCurrentBuffer(BufferedNode nodeToCheck) { BufferedNode currentNode = this.bufferedNodesHead; do { if (currentNode == nodeToCheck) { return(true); } currentNode = currentNode.Next; }while (currentNode != this.bufferedNodesHead); return(false); }
/// <summary> /// Puts the reader into the state where no buffering happen on read. /// Either buffered nodes are consumed or new nodes are read (and not buffered). /// </summary> internal void StopBuffering() { Debug.Assert(this.isBuffering, "Buffering is not turned on. Must not call StopBuffering in this state."); // NOTE: by turning off buffering the reader is set to the first node in the buffer (if any) and will continue // to read from there. removeOnNextRead is set to true since we captured the original state of the reader // (before starting to buffer) as the first node in the buffer and that node has to be removed on the next read. this.isBuffering = false; this.removeOnNextRead = true; // We set the currentBufferedNode to null here to indicate that we want to reset the position of the current // buffered node when we turn on buffering the next time. So far this (i.e., resetting the position of the buffered // node) is the only mode the BufferingJsonReader supports. We can make resetting the current node position more explicit // if needed. this.currentBufferedNode = null; }
public override bool MoveToFirstAttribute() { if (this.bufferedNodes.Count <= 0) { return(this.reader.MoveToFirstAttribute()); } BufferedNode currentElementNode = this.GetCurrentElementNode(); if ((currentElementNode.NodeType == XmlNodeType.Element) && (currentElementNode.AttributeNodes.Count > 0)) { this.currentAttributeNode = null; this.currentBufferedNodeToReport = currentElementNode.AttributeNodes.First; return(true); } return(false); }
private LinkedListNode <BufferedNode> FindAttributeBufferedNode(string localName, string namespaceUri) { BufferedNode currentElementNode = this.GetCurrentElementNode(); if ((currentElementNode.NodeType == XmlNodeType.Element) && (currentElementNode.AttributeNodes.Count > 0)) { for (LinkedListNode <BufferedNode> node2 = currentElementNode.AttributeNodes.First; node2 != null; node2 = node2.Next) { BufferedNode node3 = node2.Value; if ((string.CompareOrdinal(node3.NamespaceUri, namespaceUri) == 0) && (string.CompareOrdinal(node3.LocalName, localName) == 0)) { return(node2); } } } return(null); }
private BufferedNode BufferCurrentReaderNode() { if (this.reader.EOF) { return this.endOfInputBufferedNode; } BufferedNode node = new BufferedNode(this.reader); if (this.reader.NodeType == XmlNodeType.Element) { while (this.reader.MoveToNextAttribute()) { node.AttributeNodes.AddLast(new BufferedNode(this.reader)); } this.reader.MoveToElement(); } return node; }
private bool ReadNextAndCheckForInStreamError() { bool flag3; this.parsingInStreamError = true; try { bool flag = this.ReadInternal(); if (base.NodeType == JsonNodeType.StartObject) { bool isBuffering = this.isBuffering; BufferedNode currentBufferedNode = null; if (this.isBuffering) { currentBufferedNode = this.currentBufferedNode; } else { this.StartBuffering(); } if (this.removeDuplicateProperties) { this.RemoveDuplicateProperties(); } else { this.TryReadErrorAndThrow(); } if (isBuffering) { this.currentBufferedNode = currentBufferedNode; } else { this.StopBuffering(); } } flag3 = flag; } finally { this.parsingInStreamError = false; } return(flag3); }
private BufferedNode BufferCurrentReaderNode() { if (this.reader.EOF) { return(this.endOfInputBufferedNode); } BufferedNode node = new BufferedNode(this.reader); if (this.reader.NodeType == XmlNodeType.Element) { while (this.reader.MoveToNextAttribute()) { node.AttributeNodes.AddLast(new BufferedNode(this.reader)); } this.reader.MoveToElement(); } return(node); }
private LinkedListNode <BufferedNode> FindAttributeBufferedNode(int index) { BufferedNode currentElementNode = this.GetCurrentElementNode(); if ((currentElementNode.NodeType == XmlNodeType.Element) && (currentElementNode.AttributeNodes.Count > 0)) { LinkedListNode <BufferedNode> first = currentElementNode.AttributeNodes.First; int num = 0; while (first != null) { if (num == index) { return(first); } num++; first = first.Next; } } return(null); }
public override bool ReadAttributeValue() { if (this.bufferedNodes.Count <= 0) { return(this.reader.ReadAttributeValue()); } if (this.currentBufferedNodeToReport.Value.NodeType != XmlNodeType.Attribute) { return(false); } if (this.currentAttributeNode != null) { return(false); } BufferedNode node = new BufferedNode(this.currentBufferedNodeToReport.Value.Value, this.currentBufferedNodeToReport.Value.Depth, this.NameTable); LinkedListNode <BufferedNode> node2 = new LinkedListNode <BufferedNode>(node); this.currentAttributeNode = this.currentBufferedNodeToReport; this.currentBufferedNodeToReport = node2; return(true); }
private bool ReadInternal(bool ignoreInStreamErrors) { bool flag; if (this.removeOnNextRead) { this.currentBufferedNodeToReport = this.currentBufferedNodeToReport.Next; this.bufferedNodes.RemoveFirst(); this.removeOnNextRead = false; } if (this.isBuffering) { this.MoveFromAttributeValueNode(); if (this.currentBufferedNode.Next != null) { this.currentBufferedNode = this.currentBufferedNode.Next; this.currentBufferedNodeToReport = this.currentBufferedNode; return(true); } if (ignoreInStreamErrors) { flag = this.reader.Read(); this.bufferedNodes.AddLast(this.BufferCurrentReaderNode()); this.currentBufferedNode = this.bufferedNodes.Last; this.currentBufferedNodeToReport = this.currentBufferedNode; return(flag); } return(this.ReadNextAndCheckForInStreamError()); } if (this.bufferedNodes.Count == 0) { return(ignoreInStreamErrors ? this.reader.Read() : this.ReadNextAndCheckForInStreamError()); } this.currentBufferedNodeToReport = this.bufferedNodes.First; BufferedNode node = this.currentBufferedNodeToReport.Value; flag = !this.IsEndOfInputNode(node); this.removeOnNextRead = true; return(flag); }
internal BufferingXmlReader(XmlReader reader, Uri parentXmlBaseUri, Uri documentBaseUri, bool disableXmlBase, int maxInnerErrorDepth, string odataNamespace) { this.reader = reader; this.documentBaseUri = documentBaseUri; this.disableXmlBase = disableXmlBase; this.maxInnerErrorDepth = maxInnerErrorDepth; XmlNameTable nameTable = this.reader.NameTable; this.XmlNamespace = nameTable.Add("http://www.w3.org/XML/1998/namespace"); this.XmlBaseAttributeName = nameTable.Add("base"); this.XmlLangAttributeName = nameTable.Add("lang"); this.ODataMetadataNamespace = nameTable.Add("http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"); this.ODataNamespace = nameTable.Add(odataNamespace); this.ODataErrorElementName = nameTable.Add("error"); this.bufferedNodes = new LinkedList<BufferedNode>(); this.currentBufferedNode = null; this.endOfInputBufferedNode = BufferedNode.CreateEndOfInput(this.reader.NameTable); this.xmlBaseStack = new Stack<XmlBaseDefinition>(); if (parentXmlBaseUri != null) { this.xmlBaseStack.Push(new XmlBaseDefinition(parentXmlBaseUri, 0)); } }
private LinkedListNode <BufferedNode> FindAttributeBufferedNode(string qualifiedName) { BufferedNode currentElementNode = this.GetCurrentElementNode(); if ((currentElementNode.NodeType == XmlNodeType.Element) && (currentElementNode.AttributeNodes.Count > 0)) { for (LinkedListNode <BufferedNode> node2 = currentElementNode.AttributeNodes.First; node2 != null; node2 = node2.Next) { BufferedNode node3 = node2.Value; bool flag = !string.IsNullOrEmpty(node3.Prefix); if (!flag && (string.CompareOrdinal(node3.LocalName, qualifiedName) == 0)) { return(node2); } if (flag && (string.CompareOrdinal(node3.Prefix + ":" + node3.LocalName, qualifiedName) == 0)) { return(node2); } } } return(null); }
/// <summary> /// Reorders the buffered property to be positioned after the <paramref name="node"/> node. /// </summary> /// <param name="node">The node after which to insert this buffered property.</param> internal void InsertAfter(BufferedNode node) { Debug.Assert(node != null, "node != null"); // First take out the nodes representing the property from the linked list BufferedNode predecessor = this.PropertyNameNode.Previous; Debug.Assert(predecessor != null, "There must always be a predecessor for a property node."); BufferedNode successor = this.EndOfPropertyValueNode.Next; Debug.Assert(successor != null, "There should always be at least the end-object node after the property value."); predecessor.Next = successor; successor.Previous = predecessor; // Then insert the nodes representing the property after the 'insertAfter' node successor = node.Next; node.Next = this.PropertyNameNode; this.PropertyNameNode.Previous = node; this.EndOfPropertyValueNode.Next = successor; if (successor != null) { successor.Previous = this.EndOfPropertyValueNode; } }
internal BufferingXmlReader(XmlReader reader, Uri parentXmlBaseUri, Uri documentBaseUri, bool disableXmlBase, int maxInnerErrorDepth, string odataNamespace) { this.reader = reader; this.documentBaseUri = documentBaseUri; this.disableXmlBase = disableXmlBase; this.maxInnerErrorDepth = maxInnerErrorDepth; XmlNameTable nameTable = this.reader.NameTable; this.XmlNamespace = nameTable.Add("http://www.w3.org/XML/1998/namespace"); this.XmlBaseAttributeName = nameTable.Add("base"); this.XmlLangAttributeName = nameTable.Add("lang"); this.ODataMetadataNamespace = nameTable.Add("http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"); this.ODataNamespace = nameTable.Add(odataNamespace); this.ODataErrorElementName = nameTable.Add("error"); this.bufferedNodes = new LinkedList <BufferedNode>(); this.currentBufferedNode = null; this.endOfInputBufferedNode = BufferedNode.CreateEndOfInput(this.reader.NameTable); this.xmlBaseStack = new Stack <XmlBaseDefinition>(); if (parentXmlBaseUri != null) { this.xmlBaseStack.Push(new XmlBaseDefinition(parentXmlBaseUri, 0)); } }
/// <summary> /// Removes the head node from the buffer. /// </summary> private void RemoveFirstNodeInBuffer() { if (this.bufferedNodesHead.Next == this.bufferedNodesHead) { Debug.Assert(this.bufferedNodesHead.Previous == this.bufferedNodesHead, "The linked list is corrupted."); this.bufferedNodesHead = null; } else { this.bufferedNodesHead.Previous.Next = this.bufferedNodesHead.Next; this.bufferedNodesHead.Next.Previous = this.bufferedNodesHead.Previous; this.bufferedNodesHead = this.bufferedNodesHead.Next; } }
/// <summary> /// Puts the reader into the state where it buffers read nodes. /// </summary> internal void StartBuffering() { Debug.Assert(!this.isBuffering, "Buffering is already turned on. Must not call StartBuffering again."); if (this.bufferedNodesHead == null) { // capture the current state of the reader as the first item in the buffer (if there are none) this.bufferedNodesHead = new BufferedNode(base.NodeType, base.Value); } else { this.removeOnNextRead = false; } Debug.Assert(this.bufferedNodesHead != null, "Expected at least the current node in the buffer when starting buffering."); // Set the currentBufferedNode to the first node in the list; this means every time we start buffering we reset the // position of the current buffered node since in general we don't know how far ahead we have read before and thus don't // want to blindly continuing to read. The model is that with every call to StartBuffering you reset the position of the // current node in the list and start reading through the buffer again. if (this.currentBufferedNode == null) { this.currentBufferedNode = this.bufferedNodesHead; } this.isBuffering = true; }
/// <summary> /// Reads the next node from the input. If we have still nodes in the buffer, takes the node /// from there. Otherwise reads a new node from the underlying reader and buffers it (depending on the current mode). /// </summary> /// <returns>true if a new node was found, or false if end of input was reached.</returns> /// <remarks> /// If the parsingInStreamError field is false, the method will read ahead for every StartObject node read from the input to check whether the JSON object /// represents an in-stream error. If so, it throws an <see cref="ODataErrorException"/>. If false, this check will not happen. /// This parsingInStremError field is set to true when trying to parse an in-stream error; in normal operation it is false. /// </remarks> protected bool ReadInternal() { if (this.removeOnNextRead) { Debug.Assert(this.bufferedNodesHead != null, "If removeOnNextRead is true we must have at least one node in the buffer."); this.RemoveFirstNodeInBuffer(); this.removeOnNextRead = false; } bool result; if (this.isBuffering) { Debug.Assert(this.currentBufferedNode != null, "this.currentBufferedNode != null"); if (this.currentBufferedNode.Next != this.bufferedNodesHead) { this.currentBufferedNode = this.currentBufferedNode.Next; result = true; } else { if (this.parsingInStreamError) { // read more from the input stream and buffer it result = base.Read(); // Add the new node to the end BufferedNode newNode = new BufferedNode(base.NodeType, base.Value); newNode.Previous = this.bufferedNodesHead.Previous; newNode.Next = this.bufferedNodesHead; this.bufferedNodesHead.Previous.Next = newNode; this.bufferedNodesHead.Previous = newNode; this.currentBufferedNode = newNode; } else { // read the next node from the input stream and check // whether it is an in-stream error result = this.ReadNextAndCheckForInStreamError(); } } } else { if (this.bufferedNodesHead == null) { // if parsingInStreamError nothing in the buffer; read from the base, // else read the next node from the input stream and check // whether it is an in-stream error result = this.parsingInStreamError ? base.Read() : this.ReadNextAndCheckForInStreamError(); } else { Debug.Assert(!this.parsingInStreamError, "!this.parsingInStreamError"); // non-buffering read from the buffer result = this.bufferedNodesHead.NodeType != JsonNodeType.EndOfInput; this.removeOnNextRead = true; } } return(result); }
/// <summary> /// Moves the reader to the bookmarked position. /// </summary> /// <param name="bookmark">The bookmark object to move to.</param> internal void MoveToBookmark(object bookmark) { Debug.Assert(this.isBuffering, "Bookmarks can only be used when in buffering mode."); Debug.Assert(bookmark != null, "bookmark != null"); BufferedNode bookmarkNode = bookmark as BufferedNode; Debug.Assert(bookmarkNode != null, "Invalid bookmark."); #if DEBUG Debug.Assert(this.NodeExistsInCurrentBuffer(bookmarkNode), "Tried to move to a bookmark which is already out of scope, bookmarks are only valid inside a single buffering session."); #endif this.currentBufferedNode = bookmarkNode; }
/// <summary> /// Puts the reader into the state where no buffering happen on read. /// Either buffered nodes are consumed or new nodes are read (and not buffered). /// </summary> internal void StopBuffering() { Debug.Assert(this.isBuffering, "Buffering is not turned on. Must not call StopBuffering in this state."); // NOTE: by turning off buffering the reader is set to the first node in the buffer (if any) and will continue // to read from there. removeOnNextRead is set to true since we captured the original state of the reader // (before starting to buffer) as the first node in the buffer and that node has to be removed on the next read. this.isBuffering = false; this.removeOnNextRead = true; // We set the currentBufferedNode to null here to indicate that we want to reset the position of the current // buffered node when we turn on buffering the next time. So far this (i.e., resetting the position of the buffered // node) is the only mode the BufferingJsonReader supports. We can make resetting the current node position more explicit // if needed. this.currentBufferedNode = null; }
public override bool ReadAttributeValue() { if (this.bufferedNodes.Count <= 0) { return this.reader.ReadAttributeValue(); } if (this.currentBufferedNodeToReport.Value.NodeType != XmlNodeType.Attribute) { return false; } if (this.currentAttributeNode != null) { return false; } BufferedNode node = new BufferedNode(this.currentBufferedNodeToReport.Value.Value, this.currentBufferedNodeToReport.Value.Depth, this.NameTable); LinkedListNode<BufferedNode> node2 = new LinkedListNode<BufferedNode>(node); this.currentAttributeNode = this.currentBufferedNodeToReport; this.currentBufferedNodeToReport = node2; return true; }
/// <summary>Constructor</summary> /// <param name="reader">The reader to wrap.</param> /// <param name="parentXmlBaseUri">If this reader is wrapping an inner reader of some kind, this parameter should pass the xml:base effective value of the parent.</param> /// <param name="documentBaseUri">The base URI for the document.</param> /// <param name="disableXmlBase">Flag to control if the xml:base attributes should be processed when reading.</param> /// <param name="maxInnerErrorDepth">The maximum number of recursive internalexception elements to allow when reading in-stream errors.</param> /// <param name="odataNamespace">XML namespace for data services.</param> internal BufferingXmlReader(XmlReader reader, Uri parentXmlBaseUri, Uri documentBaseUri, bool disableXmlBase, int maxInnerErrorDepth, string odataNamespace) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(reader != null, "reader != null"); Debug.Assert(documentBaseUri == null || documentBaseUri.IsAbsoluteUri, "The document Base URI must be absolute if it's specified."); this.reader = reader; this.documentBaseUri = documentBaseUri; this.disableXmlBase = disableXmlBase; this.maxInnerErrorDepth = maxInnerErrorDepth; XmlNameTable nameTable = this.reader.NameTable; this.XmlNamespace = nameTable.Add(AtomConstants.XmlNamespace); this.XmlBaseAttributeName = nameTable.Add(AtomConstants.XmlBaseAttributeName); this.XmlLangAttributeName = nameTable.Add(AtomConstants.XmlLangAttributeName); this.ODataMetadataNamespace = nameTable.Add(AtomConstants.ODataMetadataNamespace); this.ODataNamespace = nameTable.Add(odataNamespace); this.ODataErrorElementName = nameTable.Add(AtomConstants.ODataErrorElementName); this.bufferedNodes = new LinkedList<BufferedNode>(); this.currentBufferedNode = null; this.endOfInputBufferedNode = BufferedNode.CreateEndOfInput(this.reader.NameTable); this.xmlBaseStack = new Stack<XmlBaseDefinition>(); // If there's a parent xml:base we need to push it onto our stack so that it's correctly propagated // Note that it's not the same as using it as documentBaseUri, since that one is only used to resolve relative xml:base values // not to report if there's no xml:base. if (parentXmlBaseUri != null) { this.xmlBaseStack.Push(new XmlBaseDefinition(parentXmlBaseUri, 0)); } }
/// <summary> /// Determines if the specified node is the end of input node. /// </summary> /// <param name="node">The buffered node to test.</param> /// <returns>true if the node is the special end of input node, false otherwise.</returns> private bool IsEndOfInputNode(BufferedNode node) { return object.ReferenceEquals(node, this.endOfInputBufferedNode); }
/// <summary> /// Removes duplicate properties in the current object record. /// </summary> /// <remarks> /// This method assumes that we are buffering and that the current buffered node is a StartObject. /// It then goes, buffers the entire object record (and all its children) and removes duplicate properties (using the WCF DS Server algorithm). /// It will remove duplicate properties on any objects in the subtree of the top-level object as well (behaves recursively). /// The method also checks for in-stream errors and throws if it finds one. /// </remarks> private void RemoveDuplicateProperties() { Debug.Assert(this.removeDuplicateProperties, "The RemoveDuplicateProperties method should only be called if the removal of duplicate properties is turned on."); Debug.Assert(this.currentBufferedNode.NodeType == JsonNodeType.StartObject, "this.currentBufferedNode.NodeType == JsonNodeType.StartObject"); Debug.Assert(this.parsingInStreamError, "this.parsingInStreamError"); this.AssertBuffering(); // Read ahead the entire object and create a map of properties. // This will buffer the object record we are on and all its children (the entire subtree). // We store a stack, which holds an item for each object record we find. // Each item on this stack is a dictionary // - key is the name of the property of a property in the object record // - value is a List<PropertyDeduplicationRecord>, in this list we store a new record // every time we find a property of a given name for the objet record. // This stores pointer to the property node and pointer to the node after the property value. Stack <ObjectRecordPropertyDeduplicationRecord> objectRecordStack = new Stack <ObjectRecordPropertyDeduplicationRecord>(); do { if (this.currentBufferedNode.NodeType == JsonNodeType.StartObject) { // New object record - add the node to our stack objectRecordStack.Push(new ObjectRecordPropertyDeduplicationRecord()); // See if it's an in-stream error BufferedNode startObjectPosition = this.currentBufferedNode; this.TryReadErrorAndThrow(); this.currentBufferedNode = startObjectPosition; } else if (this.currentBufferedNode.NodeType == JsonNodeType.EndObject) { // End of object record // Pop the node from our stack ObjectRecordPropertyDeduplicationRecord currentObjectRecord = objectRecordStack.Pop(); // If there is a current property, mark its last value node. if (currentObjectRecord.CurrentPropertyRecord != null) { currentObjectRecord.CurrentPropertyRecord.LastPropertyValueNode = this.currentBufferedNode.Previous; } // Now walk the list of properties for the object record and deduplicate them foreach (List <PropertyDeduplicationRecord> propertyDeduplicationRecords in currentObjectRecord.Values) { // If there's just one property of this name - there's nothing to do. if (propertyDeduplicationRecords.Count <= 1) { continue; } // Walk all the properties and each time remove the property we find from its current place and move it // inplace of the first property. Note that since the property names are the same we can replace the property node itself // without losing any information. // Once we walk the entire list the outcome will be that we will have just one property of a given name, // it will be in the position of the first property, but it will be the last property value. // We could completely remove the property occurences which are not first or last, but it's easier to move them // to the first one by one as it keeps the algorithm simple (and the performence difference is small enough). PropertyDeduplicationRecord firstProperty = propertyDeduplicationRecords[0]; for (int propertyIndex = 1; propertyIndex < propertyDeduplicationRecords.Count; propertyIndex++) { PropertyDeduplicationRecord currentProperty = propertyDeduplicationRecords[propertyIndex]; Debug.Assert((string)firstProperty.PropertyNode.Value == (string)currentProperty.PropertyNode.Value, "The property names must be the same."); // Note that property nodes must be preceded at least by the start object node and followed by the end object node // so we don't have to check for end of list here. // Remove the current property from the list currentProperty.PropertyNode.Previous.Next = currentProperty.LastPropertyValueNode.Next; currentProperty.LastPropertyValueNode.Next.Previous = currentProperty.PropertyNode.Previous; // Now replace the first property with the current property firstProperty.PropertyNode.Previous.Next = currentProperty.PropertyNode; currentProperty.PropertyNode.Previous = firstProperty.PropertyNode.Previous; firstProperty.LastPropertyValueNode.Next.Previous = currentProperty.LastPropertyValueNode; currentProperty.LastPropertyValueNode.Next = firstProperty.LastPropertyValueNode.Next; firstProperty = currentProperty; } } if (objectRecordStack.Count == 0) { break; } } else if (this.currentBufferedNode.NodeType == JsonNodeType.Property) { ObjectRecordPropertyDeduplicationRecord currentObjectRecord = objectRecordStack.Peek(); // If there is a previous property record, mark its last value node. if (currentObjectRecord.CurrentPropertyRecord != null) { currentObjectRecord.CurrentPropertyRecord.LastPropertyValueNode = this.currentBufferedNode.Previous; } // Create a new property record for this property node and add it to the object record. currentObjectRecord.CurrentPropertyRecord = new PropertyDeduplicationRecord(this.currentBufferedNode); string propertyName = (string)this.currentBufferedNode.Value; List <PropertyDeduplicationRecord> propertyDeduplicationRecords; if (!currentObjectRecord.TryGetValue(propertyName, out propertyDeduplicationRecords)) { propertyDeduplicationRecords = new List <PropertyDeduplicationRecord>(); currentObjectRecord.Add(propertyName, propertyDeduplicationRecords); } propertyDeduplicationRecords.Add(currentObjectRecord.CurrentPropertyRecord); } }while (this.ReadInternal()); }
/// <summary> /// Reads the next node from the input. If we have still nodes in the buffer, takes the node /// from there. Otherwise reads a new node from the underlying reader and buffers it (depending on the current mode). /// </summary> /// <returns>true if a new node was found, or false if end of input was reached.</returns> /// <remarks> /// If the parsingInStreamError field is false, the method will read ahead for every StartObject node read from the input to check whether the JSON object /// represents an in-stream error. If so, it throws an <see cref="ODataErrorException"/>. If false, this check will not happen. /// This parsingInStremError field is set to true when trying to parse an in-stream error; in normal operation it is false. /// </remarks> protected bool ReadInternal() { if (this.removeOnNextRead) { Debug.Assert(this.bufferedNodesHead != null, "If removeOnNextRead is true we must have at least one node in the buffer."); this.RemoveFirstNodeInBuffer(); this.removeOnNextRead = false; } bool result; if (this.isBuffering) { Debug.Assert(this.currentBufferedNode != null, "this.currentBufferedNode != null"); if (this.currentBufferedNode.Next != this.bufferedNodesHead) { this.currentBufferedNode = this.currentBufferedNode.Next; result = true; } else { if (this.parsingInStreamError) { // read more from the input stream and buffer it result = base.Read(); // Add the new node to the end BufferedNode newNode = new BufferedNode(base.NodeType, base.Value); newNode.Previous = this.bufferedNodesHead.Previous; newNode.Next = this.bufferedNodesHead; this.bufferedNodesHead.Previous.Next = newNode; this.bufferedNodesHead.Previous = newNode; this.currentBufferedNode = newNode; } else { // read the next node from the input stream and check // whether it is an in-stream error result = this.ReadNextAndCheckForInStreamError(); } } } else { if (this.bufferedNodesHead == null) { // if parsingInStreamError nothing in the buffer; read from the base, // else read the next node from the input stream and check // whether it is an in-stream error result = this.parsingInStreamError ? base.Read() : this.ReadNextAndCheckForInStreamError(); } else { Debug.Assert(!this.parsingInStreamError, "!this.parsingInStreamError"); // non-buffering read from the buffer result = this.bufferedNodesHead.NodeType != JsonNodeType.EndOfInput; this.removeOnNextRead = true; } } return result; }
/// <summary> /// Determines whether the given node exists in the current buffer. /// </summary> /// <param name="nodeToCheck">The node to test.</param> /// <returns>true if the given node was found in the buffer; false otherwise.</returns> private bool NodeExistsInCurrentBuffer(BufferedNode nodeToCheck) { BufferedNode currentNode = this.bufferedNodesHead; do { if (currentNode == nodeToCheck) { return true; } currentNode = currentNode.Next; } while (currentNode != this.bufferedNodesHead); return false; }
/// <summary> /// Reads the next node from the value of an attribute. /// </summary> /// <returns>true if next node was available; false if end of the attribute value was reached.</returns> public override bool ReadAttributeValue() { this.ValidateInternalState(); if (this.bufferedNodes.Count > 0) { if (this.currentBufferedNodeToReport.Value.NodeType != XmlNodeType.Attribute) { return false; } // If we're already on an attribute value node, return false, since we always report the entire attribute value as one node. if (this.currentAttributeNode != null) { return false; } // Otherwise create the new "fake" node for the attribute value BufferedNode attributeValueBufferedNode = new BufferedNode(this.currentBufferedNodeToReport.Value.Value, this.currentBufferedNodeToReport.Value.Depth, this.NameTable); LinkedListNode<BufferedNode> attributeValueNode = new LinkedListNode<BufferedNode>(attributeValueBufferedNode); this.currentAttributeNode = this.currentBufferedNodeToReport; this.currentBufferedNodeToReport = attributeValueNode; this.ValidateInternalState(); return true; } return this.reader.ReadAttributeValue(); }
/// <summary> /// Reads the next node from the JSON reader and if a start-object node is detected starts reading ahead and /// tries to parse an in-stream error. /// </summary> /// <returns>true if a new node was found, or false if end of input was reached.</returns> private bool ReadNextAndCheckForInStreamError() { Debug.Assert(!this.parsingInStreamError, "!this.parsingInStreamError"); this.parsingInStreamError = true; try { // read the next node in the current reader mode (buffering or non-buffering) bool result = this.ReadInternal(); if (base.NodeType == JsonNodeType.StartObject) { // If we find a StartObject node we have to read ahead and check whether this // JSON object represents an in-stream error. If we are currently in buffering // mode remember the current position in the buffer; otherwise start buffering. bool wasBuffering = this.isBuffering; BufferedNode storedPosition = null; if (this.isBuffering) { storedPosition = this.currentBufferedNode; } else { this.StartBuffering(); } this.ProcessObjectValue(); // Reset the reader state to non-buffering or to the previously // backed up position in the buffer. if (wasBuffering) { this.currentBufferedNode = storedPosition; } else { this.StopBuffering(); } } return result; } finally { this.parsingInStreamError = false; } }
/// <summary> /// Buffers the current reader state into a node. /// </summary> /// <returns>The newly created buffered node.</returns> private BufferedNode BufferCurrentReaderNode() { if (this.reader.EOF) { return this.endOfInputBufferedNode; } BufferedNode resultNode = new BufferedNode(this.reader); // If the new node is an element, read all its attributes and buffer those as well if (this.reader.NodeType == XmlNodeType.Element) { while (this.reader.MoveToNextAttribute()) { resultNode.AttributeNodes.AddLast(new BufferedNode(this.reader)); } this.reader.MoveToElement(); } return resultNode; }
/// <summary> /// Reorders the buffered property to be positioned after the <paramref name="node"/> node. /// </summary> /// <param name="node">The node after which to insert this buffered property.</param> internal void InsertAfter(BufferedNode node) { Debug.Assert(node != null, "node != null"); // First take out the nodes representing the property from the linked list BufferedNode predecessor = this.PropertyNameNode.Previous; Debug.Assert(predecessor != null, "There must always be a predecessor for a property node."); BufferedNode successor = this.EndOfPropertyValueNode.Next; Debug.Assert(successor != null, "There should always be at least the end-object node after the property value."); predecessor.Next = successor; successor.Previous = predecessor; // Then insert the nodes representing the property after the 'insertAfter' node successor = node.Next; node.Next = this.PropertyNameNode; this.PropertyNameNode.Previous = node; this.EndOfPropertyValueNode.Next = successor; if (successor != null) { successor.Previous = this.EndOfPropertyValueNode; } }