private void SetupReadContentAsBinaryState(ParsingFunction inReadBinaryFunction) { if (_parsingFunction == ParsingFunction.PartialTextValue) { _incReadState = IncrementalReadState.ReadContentAsBinary_OnPartialValue; } else { _incReadState = IncrementalReadState.ReadContentAsBinary_OnCachedValue; _nextNextParsingFunction = _nextParsingFunction; _nextParsingFunction = _parsingFunction; } _readValueOffset = 0; _parsingFunction = inReadBinaryFunction; }
private int ReadContentAsBinary(byte[] buffer, int index, int count) { Debug.Assert(_incReadDecoder != null); if (_incReadState == IncrementalReadState.ReadContentAsBinary_End) { return 0; } _incReadDecoder.SetNextOutputBuffer(buffer, index, count); for (; ;) { // read what is already cached in curNode int charsRead = 0; try { charsRead = _curNode.CopyToBinary(_incReadDecoder, _readValueOffset); } // add line info to the exception catch (XmlException e) { _curNode.AdjustLineInfo(_readValueOffset, _ps.eolNormalized, ref _incReadLineInfo); ReThrow(e, _incReadLineInfo.lineNo, _incReadLineInfo.linePos); } _readValueOffset += charsRead; if (_incReadDecoder.IsFull) { return _incReadDecoder.DecodedCount; } // if on partial value, read the rest of it if (_incReadState == IncrementalReadState.ReadContentAsBinary_OnPartialValue) { _curNode.SetValue(string.Empty); // read next chunk of text bool endOfValue = false; int startPos = 0; int endPos = 0; while (!_incReadDecoder.IsFull && !endOfValue) { int orChars = 0; // store current line info and parse more text _incReadLineInfo.Set(_ps.LineNo, _ps.LinePos); endOfValue = ParseText(out startPos, out endPos, ref orChars); try { charsRead = _incReadDecoder.Decode(_ps.chars, startPos, endPos - startPos); } // add line info to the exception catch (XmlException e) { ReThrow(e, _incReadLineInfo.lineNo, _incReadLineInfo.linePos); } startPos += charsRead; } _incReadState = endOfValue ? IncrementalReadState.ReadContentAsBinary_OnCachedValue : IncrementalReadState.ReadContentAsBinary_OnPartialValue; _readValueOffset = 0; if (_incReadDecoder.IsFull) { _curNode.SetValue(_ps.chars, startPos, endPos - startPos); // adjust line info for the chunk that has been already decoded AdjustLineInfo(_ps.chars, startPos - charsRead, startPos, _ps.eolNormalized, ref _incReadLineInfo); _curNode.SetLineInfo(_incReadLineInfo.lineNo, _incReadLineInfo.linePos); return _incReadDecoder.DecodedCount; } } // reset to normal state so we can call Read() to move forward ParsingFunction tmp = _parsingFunction; _parsingFunction = _nextParsingFunction; _nextParsingFunction = _nextNextParsingFunction; // move to next textual node in the element content; throw on sub elements if (!MoveToNextContentNode(true)) { SetupReadContentAsBinaryState(tmp); _incReadState = IncrementalReadState.ReadContentAsBinary_End; return _incReadDecoder.DecodedCount; } SetupReadContentAsBinaryState(tmp); _incReadLineInfo.Set(_curNode.LineNo, _curNode.LinePos); } }
private void InitIncrementalRead(IncrementalReadDecoder decoder) { ResetAttributes(); decoder.Reset(); _incReadDecoder = decoder; _incReadState = IncrementalReadState.Text; _incReadDepth = 1; _incReadLeftStartPos = _ps.charPos; _incReadLeftEndPos = _ps.charPos; _incReadLineInfo.Set(_ps.LineNo, _ps.LinePos); _parsingFunction = ParsingFunction.InIncrementalRead; }
private int IncrementalRead() { int charsDecoded = 0; OuterContinue: int charsLeft = _incReadLeftEndPos - _incReadLeftStartPos; if (charsLeft > 0) { int count; try { count = _incReadDecoder.Decode(_ps.chars, _incReadLeftStartPos, charsLeft); } catch (XmlException e) { ReThrow(e, (int)_incReadLineInfo.lineNo, (int)_incReadLineInfo.linePos); return 0; } if (count < charsLeft) { _incReadLeftStartPos += count; _incReadLineInfo.linePos += count; // we have never more then 1 line cached return count; } else { _incReadLeftStartPos = 0; _incReadLeftEndPos = 0; _incReadLineInfo.linePos += count; if (_incReadDecoder.IsFull) { return count; } } } int startPos = 0; int pos = 0; for (;;) { switch (_incReadState) { case IncrementalReadState.Text: case IncrementalReadState.Attributes: case IncrementalReadState.AttributeValue: break; case IncrementalReadState.PI: if (ParsePIValue(out startPos, out pos)) { Debug.Assert(XmlConvert.StrEqual(_ps.chars, _ps.charPos - 2, 2, "?>")); _ps.charPos -= 2; _incReadState = IncrementalReadState.Text; } goto Append; case IncrementalReadState.Comment: if (ParseCDataOrComment(XmlNodeType.Comment, out startPos, out pos)) { Debug.Assert(XmlConvert.StrEqual(_ps.chars, _ps.charPos - 3, 3, "-->")); _ps.charPos -= 3; _incReadState = IncrementalReadState.Text; } goto Append; case IncrementalReadState.CDATA: if (ParseCDataOrComment(XmlNodeType.CDATA, out startPos, out pos)) { Debug.Assert(XmlConvert.StrEqual(_ps.chars, _ps.charPos - 3, 3, "]]>")); _ps.charPos -= 3; _incReadState = IncrementalReadState.Text; } goto Append; case IncrementalReadState.EndElement: _parsingFunction = ParsingFunction.PopElementContext; _nextParsingFunction = (_index > 0 || _fragmentType != XmlNodeType.Document) ? ParsingFunction.ElementContent : ParsingFunction.DocumentContent; _outerReader.Read(); _incReadState = IncrementalReadState.End; goto case IncrementalReadState.End; case IncrementalReadState.End: return charsDecoded; case IncrementalReadState.ReadData: if (ReadData() == 0) { ThrowUnclosedElements(); } _incReadState = IncrementalReadState.Text; startPos = _ps.charPos; pos = startPos; break; default: Debug.Assert(false); break; } Debug.Assert(_incReadState == IncrementalReadState.Text || _incReadState == IncrementalReadState.Attributes || _incReadState == IncrementalReadState.AttributeValue); char[] chars = _ps.chars; startPos = _ps.charPos; pos = startPos; for (;;) { _incReadLineInfo.Set(_ps.LineNo, _ps.LinePos); char c; unsafe { if (_incReadState == IncrementalReadState.Attributes) { while (_xmlCharType.IsAttributeValueChar(c = chars[pos]) && c != '/') { pos++; } } else { while (_xmlCharType.IsAttributeValueChar(c = chars[pos])) { pos++; } } } if (chars[pos] == '&' || chars[pos] == (char)0x9) { pos++; continue; } if (pos - startPos > 0) { goto AppendAndUpdateCharPos; } switch (chars[pos]) { // eol case (char)0xA: pos++; OnNewLine(pos); continue; case (char)0xD: if (chars[pos + 1] == (char)0xA) { pos += 2; } else if (pos + 1 < _ps.charsUsed) { pos++; } else { goto ReadData; } OnNewLine(pos); continue; // some tag case '<': if (_incReadState != IncrementalReadState.Text) { pos++; continue; } if (_ps.charsUsed - pos < 2) { goto ReadData; } switch (chars[pos + 1]) { // pi case '?': pos += 2; _incReadState = IncrementalReadState.PI; goto AppendAndUpdateCharPos; // comment case '!': if (_ps.charsUsed - pos < 4) { goto ReadData; } if (chars[pos + 2] == '-' && chars[pos + 3] == '-') { pos += 4; _incReadState = IncrementalReadState.Comment; goto AppendAndUpdateCharPos; } if (_ps.charsUsed - pos < 9) { goto ReadData; } if (XmlConvert.StrEqual(chars, pos + 2, 7, "[CDATA[")) { pos += 9; _incReadState = IncrementalReadState.CDATA; goto AppendAndUpdateCharPos; } else { ;//Throw( ); } break; // end tag case '/': { Debug.Assert(_ps.charPos - pos == 0); Debug.Assert(_ps.charPos - startPos == 0); int colonPos; // ParseQName can flush the buffer, so we need to update the startPos, pos and chars after calling it int endPos = ParseQName(true, 2, out colonPos); if (XmlConvert.StrEqual(chars, _ps.charPos + 2, endPos - _ps.charPos - 2, _curNode.GetNameWPrefix(_nameTable)) && (_ps.chars[endPos] == '>' || _xmlCharType.IsWhiteSpace(_ps.chars[endPos]))) { if (--_incReadDepth > 0) { pos = endPos + 1; continue; } _ps.charPos = endPos; if (_xmlCharType.IsWhiteSpace(_ps.chars[endPos])) { EatWhitespaces(null); } if (_ps.chars[_ps.charPos] != '>') { ThrowUnexpectedToken(">"); } _ps.charPos++; _incReadState = IncrementalReadState.EndElement; goto OuterContinue; } else { pos = endPos; startPos = _ps.charPos; chars = _ps.chars; continue; } } // start tag default: { Debug.Assert(_ps.charPos - pos == 0); Debug.Assert(_ps.charPos - startPos == 0); int colonPos; // ParseQName can flush the buffer, so we need to update the startPos, pos and chars after calling it int endPos = ParseQName(true, 1, out colonPos); if (XmlConvert.StrEqual(_ps.chars, _ps.charPos + 1, endPos - _ps.charPos - 1, _curNode.localName) && (_ps.chars[endPos] == '>' || _ps.chars[endPos] == '/' || _xmlCharType.IsWhiteSpace(_ps.chars[endPos]))) { _incReadDepth++; _incReadState = IncrementalReadState.Attributes; pos = endPos; goto AppendAndUpdateCharPos; } pos = endPos; startPos = _ps.charPos; chars = _ps.chars; continue; } } break; // end of start tag case '/': if (_incReadState == IncrementalReadState.Attributes) { if (_ps.charsUsed - pos < 2) { goto ReadData; } if (chars[pos + 1] == '>') { _incReadState = IncrementalReadState.Text; _incReadDepth--; } } pos++; continue; // end of start tag case '>': if (_incReadState == IncrementalReadState.Attributes) { _incReadState = IncrementalReadState.Text; } pos++; continue; case '"': case '\'': switch (_incReadState) { case IncrementalReadState.AttributeValue: if (chars[pos] == _curNode.quoteChar) { _incReadState = IncrementalReadState.Attributes; } break; case IncrementalReadState.Attributes: _curNode.quoteChar = chars[pos]; _incReadState = IncrementalReadState.AttributeValue; break; } pos++; continue; default: // end of buffer if (pos == _ps.charsUsed) { goto ReadData; } // surrogate chars or invalid chars are ignored else { pos++; continue; } } } ReadData: _incReadState = IncrementalReadState.ReadData; AppendAndUpdateCharPos: _ps.charPos = pos; Append: // decode characters int charsParsed = pos - startPos; if (charsParsed > 0) { int count; try { count = _incReadDecoder.Decode(_ps.chars, startPos, charsParsed); } catch (XmlException e) { ReThrow(e, (int)_incReadLineInfo.lineNo, (int)_incReadLineInfo.linePos); return 0; } Debug.Assert(count == charsParsed || _incReadDecoder.IsFull, "Check if decoded consumed all characters unless it's full."); charsDecoded += count; if (_incReadDecoder.IsFull) { _incReadLeftStartPos = startPos + count; _incReadLeftEndPos = pos; _incReadLineInfo.linePos += count; // we have never more than 1 line cached return charsDecoded; } } } }
// Iterates over Value property and copies it into the provided buffer public override int ReadValueChunk(char[] buffer, int index, int count) { // throw on elements if (!XmlReader.HasValueInternal(_curNode.type)) { throw new InvalidOperationException(SR.Format(SR.Xml_InvalidReadValueChunk, _curNode.type)); } // check arguments if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count)); } if (index < 0) { throw new ArgumentOutOfRangeException(nameof(index)); } if (buffer.Length - index < count) { throw new ArgumentOutOfRangeException(nameof(count)); } // first call of ReadValueChunk -> initialize incremental read state if (_parsingFunction != ParsingFunction.InReadValueChunk) { if (_readState != ReadState.Interactive) { return 0; } if (_parsingFunction == ParsingFunction.PartialTextValue) { _incReadState = IncrementalReadState.ReadValueChunk_OnPartialValue; } else { _incReadState = IncrementalReadState.ReadValueChunk_OnCachedValue; _nextNextParsingFunction = _nextParsingFunction; _nextParsingFunction = _parsingFunction; } _parsingFunction = ParsingFunction.InReadValueChunk; _readValueOffset = 0; } if (count == 0) { return 0; } // read what is already cached in curNode int readCount = 0; int read = _curNode.CopyTo(_readValueOffset, buffer, index + readCount, count - readCount); readCount += read; _readValueOffset += read; if (readCount == count) { // take care of surrogate pairs spanning between buffers char ch = buffer[index + count - 1]; if (XmlCharType.IsHighSurrogate(ch)) { readCount--; _readValueOffset--; if (readCount == 0) { Throw(SR.Xml_NotEnoughSpaceForSurrogatePair); } } return readCount; } // if on partial value, read the rest of it if (_incReadState == IncrementalReadState.ReadValueChunk_OnPartialValue) { _curNode.SetValue(string.Empty); // read next chunk of text bool endOfValue = false; int startPos = 0; int endPos = 0; while (readCount < count && !endOfValue) { int orChars = 0; endOfValue = ParseText(out startPos, out endPos, ref orChars); int copyCount = count - readCount; if (copyCount > endPos - startPos) { copyCount = endPos - startPos; } BlockCopyChars(_ps.chars, startPos, buffer, (index + readCount), copyCount); readCount += copyCount; startPos += copyCount; } _incReadState = endOfValue ? IncrementalReadState.ReadValueChunk_OnCachedValue : IncrementalReadState.ReadValueChunk_OnPartialValue; if (readCount == count) { char ch = buffer[index + count - 1]; if (XmlCharType.IsHighSurrogate(ch)) { readCount--; startPos--; if (readCount == 0) { Throw(SR.Xml_NotEnoughSpaceForSurrogatePair); } } } _readValueOffset = 0; _curNode.SetValue(_ps.chars, startPos, endPos - startPos); } return readCount; }
private void FinishOtherValueIterator() { switch (_parsingFunction) { case ParsingFunction.InReadAttributeValue: // do nothing, correct value is already in curNode break; case ParsingFunction.InReadValueChunk: if (_incReadState == IncrementalReadState.ReadValueChunk_OnPartialValue) { FinishPartialValue(); _incReadState = IncrementalReadState.ReadValueChunk_OnCachedValue; } else { if (_readValueOffset > 0) { _curNode.SetValue(_curNode.StringValue.Substring(_readValueOffset)); _readValueOffset = 0; } } break; case ParsingFunction.InReadContentAsBinary: case ParsingFunction.InReadElementContentAsBinary: switch (_incReadState) { case IncrementalReadState.ReadContentAsBinary_OnPartialValue: FinishPartialValue(); _incReadState = IncrementalReadState.ReadContentAsBinary_OnCachedValue; break; case IncrementalReadState.ReadContentAsBinary_OnCachedValue: if (_readValueOffset > 0) { _curNode.SetValue(_curNode.StringValue.Substring(_readValueOffset)); _readValueOffset = 0; } break; case IncrementalReadState.ReadContentAsBinary_End: _curNode.SetValue(string.Empty); break; } break; } }
private void ParseDtdFromParserContext() { Debug.Assert( dtdInfo == null && fragmentParserContext != null && fragmentParserContext.HasDtdInfo ); IDtdParser dtdParser = DtdParser.Create(); // Parse DTD dtdInfo = dtdParser.ParseFreeFloatingDtd(fragmentParserContext.BaseURI, fragmentParserContext.DocTypeName, fragmentParserContext.PublicId, fragmentParserContext.SystemId, fragmentParserContext.InternalSubset, new DtdParserProxy( this ) ); #if SILVERLIGHT // Needed only for XmlTextReader or XmlValidatingReader if (dtdInfo.HasDefaultAttributes || dtdInfo.HasNonCDataAttributes) { #else if ( ( validatingReaderCompatFlag || !v1Compat ) && ( dtdInfo.HasDefaultAttributes || dtdInfo.HasNonCDataAttributes ) ) { #endif addDefaultAttributesAndNormalize = true; } } bool InitReadContentAsBinary() { Debug.Assert( parsingFunction != ParsingFunction.InReadContentAsBinary ); if ( parsingFunction == ParsingFunction.InReadValueChunk ) { throw new InvalidOperationException( Res.GetString( Res.Xml_MixingReadValueChunkWithBinary ) ); } if ( parsingFunction == ParsingFunction.InIncrementalRead ) { throw new InvalidOperationException( Res.GetString( Res.Xml_MixingV1StreamingWithV2Binary ) ); } if ( !XmlReader.IsTextualNode( curNode.type ) ) { if ( !MoveToNextContentNode( false ) ) { return false; } } SetupReadContentAsBinaryState( ParsingFunction.InReadContentAsBinary ); incReadLineInfo.Set( curNode.LineNo, curNode.LinePos ); return true; } bool InitReadElementContentAsBinary() { Debug.Assert( parsingFunction != ParsingFunction.InReadElementContentAsBinary ); Debug.Assert( curNode.type == XmlNodeType.Element ); bool isEmpty = curNode.IsEmptyElement; // move to content or off the empty element outerReader.Read(); if ( isEmpty ) { return false; } // make sure we are on a content node if ( !MoveToNextContentNode( false ) ) { if ( curNode.type != XmlNodeType.EndElement ) { Throw( Res.Xml_InvalidNodeType, curNode.type.ToString() ); } // move off end element outerReader.Read(); return false; } SetupReadContentAsBinaryState( ParsingFunction.InReadElementContentAsBinary ); incReadLineInfo.Set( curNode.LineNo, curNode.LinePos ); return true; } bool MoveToNextContentNode( bool moveIfOnContentNode ) { do { switch ( curNode.type ) { case XmlNodeType.Attribute: return !moveIfOnContentNode; case XmlNodeType.Text: case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: case XmlNodeType.CDATA: if ( !moveIfOnContentNode ) { return true; } break; case XmlNodeType.ProcessingInstruction: case XmlNodeType.Comment: case XmlNodeType.EndEntity: // skip comments, pis and end entity nodes break; case XmlNodeType.EntityReference: outerReader.ResolveEntity(); break; default: return false; } moveIfOnContentNode = false; } while ( outerReader.Read() ); return false; } void SetupReadContentAsBinaryState( ParsingFunction inReadBinaryFunction ) { if ( parsingFunction == ParsingFunction.PartialTextValue ) { incReadState = IncrementalReadState.ReadContentAsBinary_OnPartialValue; } else { incReadState = IncrementalReadState.ReadContentAsBinary_OnCachedValue; nextNextParsingFunction = nextParsingFunction; nextParsingFunction = parsingFunction; } readValueOffset = 0; parsingFunction = inReadBinaryFunction; } void SetupFromParserContext( XmlParserContext context, XmlReaderSettings settings ) { Debug.Assert( context != null ); // setup nameTable XmlNameTable nt = settings.NameTable; nameTableFromSettings = ( nt != null ); // get name table from namespace manager in XmlParserContext, if available; if ( context.NamespaceManager != null ) { // must be the same as XmlReaderSettings.NameTable, or null if ( nt != null && nt != context.NamespaceManager.NameTable ) { throw new XmlException( Res.Xml_NametableMismatch ); } // get the namespace manager from context namespaceManager = context.NamespaceManager; xmlContext.defaultNamespace = namespaceManager.LookupNamespace( string.Empty ); // get the nametable from ns manager nt = namespaceManager.NameTable; Debug.Assert( nt != null ); Debug.Assert( context.NameTable == null || context.NameTable == nt, "This check should have been done in XmlParserContext constructor." ); } // get name table directly from XmlParserContext else if ( context.NameTable != null ) { // must be the same as XmlReaderSettings.NameTable, or null if ( nt != null && nt != context.NameTable ) { throw new XmlException( Res.Xml_NametableMismatch, string.Empty ); } nt = context.NameTable; } // no nametable provided -> create a new one else if ( nt == null ) { nt = new NameTable(); Debug.Assert( nameTableFromSettings == false ); } nameTable = nt; // make sure we have namespace manager if ( namespaceManager == null ) { namespaceManager = new XmlNamespaceManager( nt ); } // copy xml:space and xml:lang xmlContext.xmlSpace = context.XmlSpace; xmlContext.xmlLang = context.XmlLang; }
void SetupReadContentAsBinaryState( ParsingFunction inReadBinaryFunction ) { if ( parsingFunction == ParsingFunction.PartialTextValue ) { incReadState = IncrementalReadState.ReadContentAsBinary_OnPartialValue; } else { incReadState = IncrementalReadState.ReadContentAsBinary_OnCachedValue; nextNextParsingFunction = nextParsingFunction; nextParsingFunction = parsingFunction; } readValueOffset = 0; parsingFunction = inReadBinaryFunction; }
// Iterates over Value property and copies it into the provided buffer public override int ReadValueChunk( char[] buffer, int index, int count ) { // throw on elements if ( !XmlReader.HasValueInternal( curNode.type ) ) { throw new InvalidOperationException( Res.GetString( Res.Xml_InvalidReadValueChunk, curNode.type ) ) ; } // check arguments if ( buffer == null ) { throw new ArgumentNullException( "buffer" ); } if ( count < 0 ) { throw new ArgumentOutOfRangeException( "count" ); } if ( index < 0 ) { throw new ArgumentOutOfRangeException( "index" ); } if ( buffer.Length - index < count ) { throw new ArgumentOutOfRangeException( "count" ); } // first call of ReadValueChunk -> initialize incremental read state if ( parsingFunction != ParsingFunction.InReadValueChunk ) { if ( readState != ReadState.Interactive ) { return 0; } if ( parsingFunction == ParsingFunction.PartialTextValue ) { incReadState = IncrementalReadState.ReadValueChunk_OnPartialValue; } else { incReadState = IncrementalReadState.ReadValueChunk_OnCachedValue; nextNextParsingFunction = nextParsingFunction; nextParsingFunction = parsingFunction; } parsingFunction = ParsingFunction.InReadValueChunk; readValueOffset = 0; } if ( count == 0 ) { return 0; } // read what is already cached in curNode int readCount = 0; int read = curNode.CopyTo( readValueOffset, buffer, index + readCount, count - readCount ); readCount += read; readValueOffset += read; if ( readCount == count ) { // take care of suppogate pairs spanning between buffers char ch = buffer[index + count - 1]; if ( ch >= SurHighStart && ch <= SurHighEnd ) { readCount--; readValueOffset--; if ( readCount == 0 ) { Throw( Res.Xml_NotEnoughSpaceForSurrogatePair ); } } return readCount; } // if on partial value, read the rest of it if ( incReadState == IncrementalReadState.ReadValueChunk_OnPartialValue ) { curNode.SetValue( string.Empty ); // read next chunk of text bool endOfValue = false; int startPos = 0; int endPos = 0; while ( readCount < count && !endOfValue ) { int orChars = 0; endOfValue = ParseText( out startPos, out endPos, ref orChars ); int copyCount = count - readCount; if ( copyCount > endPos - startPos ) { copyCount = endPos - startPos; } Buffer.BlockCopy( ps.chars, startPos * 2, buffer, ( index + readCount ) * 2, copyCount * 2 ); readCount += copyCount; startPos += copyCount; } incReadState = endOfValue ? IncrementalReadState.ReadValueChunk_OnCachedValue : IncrementalReadState.ReadValueChunk_OnPartialValue; if ( readCount == count ) { char ch = buffer[index + count - 1]; if ( ch >= SurHighStart && ch <= SurHighEnd ) { readCount--; startPos--; if ( readCount == 0 ) { Throw( Res.Xml_NotEnoughSpaceForSurrogatePair ); } } } readValueOffset = 0; curNode.SetValue( ps.chars, startPos, endPos - startPos ); } return readCount; }
// Iterates over Value property and copies it into the provided buffer public override int ReadValueChunk(char[] buffer, int index, int count) { // throw on elements if (!XmlReader.HasValueInternal(curNode.type)) { throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidReadValueChunk, curNode.type)); } // check arguments if (buffer == null) { throw new ArgumentNullException("buffer"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if (index < 0) { throw new ArgumentOutOfRangeException("index"); } if (buffer.Length - index < count) { throw new ArgumentOutOfRangeException("count"); } // first call of ReadValueChunk -> initialize incremental read state if (parsingFunction != ParsingFunction.InReadValueChunk) { if (readState != ReadState.Interactive) { return 0; } if (parsingFunction == ParsingFunction.PartialTextValue) { incReadState = IncrementalReadState.ReadValueChunk_OnPartialValue; } else { incReadState = IncrementalReadState.ReadValueChunk_OnCachedValue; nextNextParsingFunction = nextParsingFunction; nextParsingFunction = parsingFunction; } parsingFunction = ParsingFunction.InReadValueChunk; readValueOffset = 0; } // read what is already cached in curNode int readCount = 0; int read = curNode.CopyTo(readValueOffset, buffer, index + readCount, count - readCount); readCount += read; readValueOffset += read; if (readCount == count) { return readCount; } // if on partial value, read the rest of it if (incReadState == IncrementalReadState.ReadValueChunk_OnPartialValue) { curNode.SetValue(""); // read next chunk of text bool endOfValue = false; int startPos = 0; int endPos = 0; while (readCount < count && !endOfValue) { int orChars = 0; endOfValue = ParseText(out startPos, out endPos, ref orChars); int copyCount = count - readCount; if (copyCount > endPos - startPos) { copyCount = endPos - startPos; } Array.Copy(ps.chars, startPos, buffer, (index + readCount), copyCount); readCount += copyCount; startPos += copyCount; } incReadState = endOfValue ? IncrementalReadState.ReadValueChunk_OnCachedValue : IncrementalReadState.ReadValueChunk_OnPartialValue; readValueOffset = 0; curNode.SetValue(ps.chars, startPos, endPos - startPos); } return readCount; }
void FinishOtherValueIterator() { switch (parsingFunction) { case ParsingFunction.InReadAttributeValue: // do nothing, correct value is already in curNode break; case ParsingFunction.InReadValueChunk: if (incReadState == IncrementalReadState.ReadValueChunk_OnPartialValue) { FinishPartialValue(); incReadState = IncrementalReadState.ReadValueChunk_OnCachedValue; } else { if (readValueOffset > 0) { curNode.SetValue(curNode.StringValue.Substring(readValueOffset)); readValueOffset = 0; } } break; } }