private void ParseAttributeValueSlow(int curPos, char quoteChar, NodeData attr) { int pos = curPos; char[] chars = _ps.chars; int attributeBaseEntityId = _ps.entityId; int valueChunkStartPos = 0; LineInfo valueChunkLineInfo = new LineInfo(_ps.lineNo, _ps.LinePos); NodeData lastChunk = null; Debug.Assert(_stringBuilder.Length == 0); for (;;) { // parse the rest of the attribute value unsafe { while (_xmlCharType.IsAttributeValueChar(chars[pos])) { pos++; } } if (pos - _ps.charPos > 0) { _stringBuilder.Append(chars, _ps.charPos, pos - _ps.charPos); _ps.charPos = pos; } if (chars[pos] == quoteChar && attributeBaseEntityId == _ps.entityId) { break; } else { switch (chars[pos]) { // eol case (char)0xA: pos++; OnNewLine(pos); if (_normalize) { _stringBuilder.Append((char)0x20); // CDATA normalization of 0xA _ps.charPos++; } continue; case (char)0xD: if (chars[pos + 1] == (char)0xA) { pos += 2; if (_normalize) { _stringBuilder.Append(_ps.eolNormalized ? "\u0020\u0020" : "\u0020"); // CDATA normalization of 0xD 0xA _ps.charPos = pos; } } else if (pos + 1 < _ps.charsUsed || _ps.isEof) { pos++; if (_normalize) { _stringBuilder.Append((char)0x20); // CDATA normalization of 0xD and 0xD 0xA _ps.charPos = pos; } } else { goto ReadData; } OnNewLine(pos); continue; // tab case (char)0x9: pos++; if (_normalize) { _stringBuilder.Append((char)0x20); // CDATA normalization of 0x9 _ps.charPos++; } continue; case '"': case '\'': case '>': pos++; continue; // attribute values cannot contain '<' case '<': Throw(pos, SR.Xml_BadAttributeChar, XmlException.BuildCharExceptionArgs('<', '\0')); break; // entity referece case '&': if (pos - _ps.charPos > 0) { _stringBuilder.Append(chars, _ps.charPos, pos - _ps.charPos); } _ps.charPos = pos; int enclosingEntityId = _ps.entityId; LineInfo entityLineInfo = new LineInfo(_ps.lineNo, _ps.LinePos + 1); switch (HandleEntityReference(true, EntityExpandType.All, out pos)) { case EntityType.CharacterDec: case EntityType.CharacterHex: case EntityType.CharacterNamed: break; case EntityType.Unexpanded: if (_parsingMode == ParsingMode.Full && _ps.entityId == attributeBaseEntityId) { // construct text value chunk int valueChunkLen = _stringBuilder.Length - valueChunkStartPos; if (valueChunkLen > 0) { NodeData textChunk = new NodeData(); textChunk.lineInfo = valueChunkLineInfo; textChunk.depth = attr.depth + 1; textChunk.SetValueNode(XmlNodeType.Text, _stringBuilder.ToString(valueChunkStartPos, valueChunkLen)); AddAttributeChunkToList(attr, textChunk, ref lastChunk); } // parse entity name _ps.charPos++; string entityName = ParseEntityName(); // construct entity reference chunk NodeData entityChunk = new NodeData(); entityChunk.lineInfo = entityLineInfo; entityChunk.depth = attr.depth + 1; entityChunk.SetNamedNode(XmlNodeType.EntityReference, entityName); AddAttributeChunkToList(attr, entityChunk, ref lastChunk); // append entity ref to the attribute value _stringBuilder.Append('&'); _stringBuilder.Append(entityName); _stringBuilder.Append(';'); // update info for the next attribute value chunk valueChunkStartPos = _stringBuilder.Length; valueChunkLineInfo.Set(_ps.LineNo, _ps.LinePos); _fullAttrCleanup = true; } else { _ps.charPos++; ParseEntityName(); } pos = _ps.charPos; break; case EntityType.ExpandedInAttribute: if (_parsingMode == ParsingMode.Full && enclosingEntityId == attributeBaseEntityId) { // construct text value chunk int valueChunkLen = _stringBuilder.Length - valueChunkStartPos; if (valueChunkLen > 0) { NodeData textChunk = new NodeData(); textChunk.lineInfo = valueChunkLineInfo; textChunk.depth = attr.depth + 1; textChunk.SetValueNode(XmlNodeType.Text, _stringBuilder.ToString(valueChunkStartPos, valueChunkLen)); AddAttributeChunkToList(attr, textChunk, ref lastChunk); } // construct entity reference chunk NodeData entityChunk = new NodeData(); entityChunk.lineInfo = entityLineInfo; entityChunk.depth = attr.depth + 1; entityChunk.SetNamedNode(XmlNodeType.EntityReference, _ps.entity.Name); AddAttributeChunkToList(attr, entityChunk, ref lastChunk); _fullAttrCleanup = true; // Note: info for the next attribute value chunk will be updated once we // get out of the expanded entity } pos = _ps.charPos; break; default: pos = _ps.charPos; break; } chars = _ps.chars; continue; default: // end of buffer if (pos == _ps.charsUsed) { goto ReadData; } // surrogate chars else { char ch = chars[pos]; if (XmlCharType.IsHighSurrogate(ch)) { if (pos + 1 == _ps.charsUsed) { goto ReadData; } pos++; if (XmlCharType.IsLowSurrogate(chars[pos])) { pos++; continue; } } ThrowInvalidChar(chars, _ps.charsUsed, pos); break; } } } ReadData: // read new characters into the buffer if (ReadData() == 0) { if (_ps.charsUsed - _ps.charPos > 0) { if (_ps.chars[_ps.charPos] != (char)0xD) { Debug.Assert(false, "We should never get to this point."); Throw(SR.Xml_UnexpectedEOF1); } Debug.Assert(_ps.isEof); } else { if (!InEntity) { if (_fragmentType == XmlNodeType.Attribute) { if (attributeBaseEntityId != _ps.entityId) { Throw(SR.Xml_EntityRefNesting); } break; } Throw(SR.Xml_UnclosedQuote); } if (HandleEntityEnd(true)) { // no EndEntity reporting while parsing attributes Debug.Assert(false); Throw(SR.Xml_InternalError); } // update info for the next attribute value chunk if (attributeBaseEntityId == _ps.entityId) { valueChunkStartPos = _stringBuilder.Length; valueChunkLineInfo.Set(_ps.LineNo, _ps.LinePos); } } } pos = _ps.charPos; chars = _ps.chars; } if (attr.nextAttrValueChunk != null) { // construct last text value chunk int valueChunkLen = _stringBuilder.Length - valueChunkStartPos; if (valueChunkLen > 0) { NodeData textChunk = new NodeData(); textChunk.lineInfo = valueChunkLineInfo; textChunk.depth = attr.depth + 1; textChunk.SetValueNode(XmlNodeType.Text, _stringBuilder.ToString(valueChunkStartPos, valueChunkLen)); AddAttributeChunkToList(attr, textChunk, ref lastChunk); } } _ps.charPos = pos + 1; attr.SetValue(_stringBuilder.ToString()); _stringBuilder.Length = 0; }
private bool ParseAttributeValueChunk() { char[] chars = _ps.chars; int pos = _ps.charPos; _curNode = AddNode(_index + _attrCount + 1, _index + 2); _curNode.SetLineInfo(_ps.LineNo, _ps.LinePos); if (_emptyEntityInAttributeResolved) { _curNode.SetValueNode(XmlNodeType.Text, string.Empty); _emptyEntityInAttributeResolved = false; return true; } Debug.Assert(_stringBuilder.Length == 0); for (;;) { unsafe { while (_xmlCharType.IsAttributeValueChar(chars[pos])) pos++; } switch (chars[pos]) { // eol D case (char)0xD: Debug.Assert(_ps.eolNormalized, "Entity replacement text for attribute values should be EOL-normalized!"); pos++; continue; // eol A, tab case (char)0xA: case (char)0x9: if (_normalize) { chars[pos] = (char)0x20; // CDATA normalization of 0xA and 0x9 } pos++; continue; case '"': case '\'': case '>': pos++; continue; // attribute values cannot contain '<' case '<': Throw(pos, SR.Xml_BadAttributeChar, XmlException.BuildCharExceptionArgs('<', '\0')); break; // entity reference case '&': if (pos - _ps.charPos > 0) { _stringBuilder.Append(chars, _ps.charPos, pos - _ps.charPos); } _ps.charPos = pos; // expand char entities but not general entities switch (HandleEntityReference(true, EntityExpandType.OnlyCharacter, out pos)) { case EntityType.CharacterDec: case EntityType.CharacterHex: case EntityType.CharacterNamed: chars = _ps.chars; if (_normalize && _xmlCharType.IsWhiteSpace(chars[_ps.charPos]) && pos - _ps.charPos == 1) { chars[_ps.charPos] = (char)0x20; // CDATA normalization of character references in entities } break; case EntityType.Unexpanded: if (_stringBuilder.Length == 0) { _curNode.lineInfo.linePos++; _ps.charPos++; _curNode.SetNamedNode(XmlNodeType.EntityReference, ParseEntityName()); return true; } else { goto ReturnText; } default: Debug.Assert(false, "We should never get to this point."); break; } chars = _ps.chars; continue; default: // end of buffer if (pos == _ps.charsUsed) { goto ReadData; } // surrogate chars else { char ch = chars[pos]; if (XmlCharType.IsHighSurrogate(ch)) { if (pos + 1 == _ps.charsUsed) { goto ReadData; } pos++; if (XmlCharType.IsLowSurrogate(chars[pos])) { pos++; continue; } } ThrowInvalidChar(chars, _ps.charsUsed, pos); break; } } ReadData: if (pos - _ps.charPos > 0) { _stringBuilder.Append(chars, _ps.charPos, pos - _ps.charPos); _ps.charPos = pos; } // read new characters into the buffer if (ReadData() == 0) { if (_stringBuilder.Length > 0) { goto ReturnText; } else { if (HandleEntityEnd(false)) { SetupEndEntityNodeInAttribute(); return true; } else { Debug.Assert(false, "We should never get to this point."); } } } pos = _ps.charPos; chars = _ps.chars; } ReturnText: if (pos - _ps.charPos > 0) { _stringBuilder.Append(chars, _ps.charPos, pos - _ps.charPos); _ps.charPos = pos; } _curNode.SetValueNode(XmlNodeType.Text, _stringBuilder.ToString()); _stringBuilder.Length = 0; return true; }
// Reads next node from the input data public override bool Read() { if (_laterInitParam != null) { FinishInit(); } for (;;) { switch (_parsingFunction) { case ParsingFunction.ElementContent: return ParseElementContent(); case ParsingFunction.DocumentContent: return ParseDocumentContent(); case ParsingFunction.OpenUrl: OpenUrl(); Debug.Assert(_nextParsingFunction == ParsingFunction.DocumentContent); goto case ParsingFunction.SwitchToInteractiveXmlDecl; case ParsingFunction.SwitchToInteractive: Debug.Assert(!_ps.appendMode); _readState = ReadState.Interactive; _parsingFunction = _nextParsingFunction; continue; case ParsingFunction.SwitchToInteractiveXmlDecl: _readState = ReadState.Interactive; _parsingFunction = _nextParsingFunction; if (ParseXmlDeclaration(false)) { _reportedEncoding = _ps.encoding; return true; } _reportedEncoding = _ps.encoding; continue; case ParsingFunction.ResetAttributesRootLevel: ResetAttributes(); _curNode = _nodes[_index]; _parsingFunction = (_index == 0) ? ParsingFunction.DocumentContent : ParsingFunction.ElementContent; continue; case ParsingFunction.MoveToElementContent: ResetAttributes(); _index++; _curNode = AddNode(_index, _index); _parsingFunction = ParsingFunction.ElementContent; continue; case ParsingFunction.PopElementContext: PopElementContext(); _parsingFunction = _nextParsingFunction; Debug.Assert(_parsingFunction == ParsingFunction.ElementContent || _parsingFunction == ParsingFunction.DocumentContent); continue; case ParsingFunction.PopEmptyElementContext: _curNode = _nodes[_index]; Debug.Assert(_curNode.type == XmlNodeType.Element); _curNode.IsEmptyElement = false; ResetAttributes(); PopElementContext(); _parsingFunction = _nextParsingFunction; continue; case ParsingFunction.EntityReference: _parsingFunction = _nextParsingFunction; ParseEntityReference(); return true; case ParsingFunction.ReportEndEntity: SetupEndEntityNodeInContent(); _parsingFunction = _nextParsingFunction; return true; case ParsingFunction.AfterResolveEntityInContent: _curNode = AddNode(_index, _index); _reportedEncoding = _ps.encoding; _reportedBaseUri = _ps.baseUriStr; _parsingFunction = _nextParsingFunction; continue; case ParsingFunction.AfterResolveEmptyEntityInContent: _curNode = AddNode(_index, _index); _curNode.SetValueNode(XmlNodeType.Text, string.Empty); _curNode.SetLineInfo(_ps.lineNo, _ps.LinePos); _reportedEncoding = _ps.encoding; _reportedBaseUri = _ps.baseUriStr; _parsingFunction = _nextParsingFunction; return true; case ParsingFunction.InReadAttributeValue: FinishAttributeValueIterator(); _curNode = _nodes[_index]; continue; case ParsingFunction.InIncrementalRead: FinishIncrementalRead(); return true; case ParsingFunction.FragmentAttribute: return ParseFragmentAttribute(); case ParsingFunction.XmlDeclarationFragment: ParseXmlDeclarationFragment(); _parsingFunction = ParsingFunction.GoToEof; return true; case ParsingFunction.GoToEof: OnEof(); return false; case ParsingFunction.Error: case ParsingFunction.Eof: case ParsingFunction.ReaderClosed: return false; case ParsingFunction.NoData: ThrowWithoutLineInfo(SR.Xml_MissingRoot); return false; case ParsingFunction.PartialTextValue: SkipPartialTextValue(); continue; case ParsingFunction.InReadValueChunk: FinishReadValueChunk(); continue; case ParsingFunction.InReadContentAsBinary: FinishReadContentAsBinary(); continue; case ParsingFunction.InReadElementContentAsBinary: FinishReadElementContentAsBinary(); continue; default: Debug.Assert(false); break; } } }
// Reads next node from the input data public override bool Read() { if (laterInitParam != null) { FinishInit(); } for (;;) { switch ( parsingFunction ) { case ParsingFunction.ElementContent: return ParseElementContent(); case ParsingFunction.DocumentContent: return ParseDocumentContent(); #if !SILVERLIGHT // Needed only for XmlTextReader case ParsingFunction.OpenUrl: OpenUrl(); Debug.Assert( nextParsingFunction == ParsingFunction.DocumentContent ); goto case ParsingFunction.SwitchToInteractiveXmlDecl; #endif case ParsingFunction.SwitchToInteractive: Debug.Assert( !ps.appendMode ); readState = ReadState.Interactive; parsingFunction = nextParsingFunction; continue; case ParsingFunction.SwitchToInteractiveXmlDecl: readState = ReadState.Interactive; parsingFunction = nextParsingFunction; if ( ParseXmlDeclaration( false ) ) { reportedEncoding = ps.encoding; return true; } reportedEncoding = ps.encoding; continue; case ParsingFunction.ResetAttributesRootLevel: ResetAttributes(); curNode = nodes[index]; parsingFunction = ( index == 0 ) ? ParsingFunction.DocumentContent : ParsingFunction.ElementContent; continue; case ParsingFunction.MoveToElementContent: ResetAttributes(); index++; curNode = AddNode( index, index ); parsingFunction = ParsingFunction.ElementContent; continue; case ParsingFunction.PopElementContext: PopElementContext(); parsingFunction = nextParsingFunction; Debug.Assert( parsingFunction == ParsingFunction.ElementContent || parsingFunction == ParsingFunction.DocumentContent ); continue; case ParsingFunction.PopEmptyElementContext: curNode = nodes[index]; Debug.Assert( curNode.type == XmlNodeType.Element ); curNode.IsEmptyElement = false; ResetAttributes(); PopElementContext(); parsingFunction = nextParsingFunction; continue; #if !SILVERLIGHT // Needed only for XmlTextReader (reporting of entities) case ParsingFunction.EntityReference: parsingFunction = nextParsingFunction; ParseEntityReference(); return true; case ParsingFunction.ReportEndEntity: SetupEndEntityNodeInContent(); parsingFunction = nextParsingFunction; return true; case ParsingFunction.AfterResolveEntityInContent: curNode = AddNode( index, index ); reportedEncoding = ps.encoding; reportedBaseUri = ps.baseUriStr; parsingFunction = nextParsingFunction; continue; case ParsingFunction.AfterResolveEmptyEntityInContent: curNode = AddNode( index, index ); curNode.SetValueNode( XmlNodeType.Text, string.Empty ); curNode.SetLineInfo( ps.lineNo, ps.LinePos ); reportedEncoding = ps.encoding; reportedBaseUri = ps.baseUriStr; parsingFunction = nextParsingFunction; return true; #endif case ParsingFunction.InReadAttributeValue: FinishAttributeValueIterator(); curNode = nodes[index]; continue; #if !SILVERLIGHT // Needed only for XmlTextReader (ReadChars, ReadBase64, ReadBinHex) case ParsingFunction.InIncrementalRead: FinishIncrementalRead(); return true; case ParsingFunction.FragmentAttribute: return ParseFragmentAttribute(); case ParsingFunction.XmlDeclarationFragment: ParseXmlDeclarationFragment(); parsingFunction = ParsingFunction.GoToEof; return true; #endif case ParsingFunction.GoToEof: OnEof(); return false; case ParsingFunction.Error: case ParsingFunction.Eof: case ParsingFunction.ReaderClosed: return false; case ParsingFunction.NoData: ThrowWithoutLineInfo( Res.Xml_MissingRoot ); return false; case ParsingFunction.PartialTextValue: SkipPartialTextValue(); continue; case ParsingFunction.InReadValueChunk: FinishReadValueChunk(); continue; case ParsingFunction.InReadContentAsBinary: FinishReadContentAsBinary(); continue; case ParsingFunction.InReadElementContentAsBinary: FinishReadElementContentAsBinary(); continue; default: Debug.Assert( false ); break; } } }
private bool ParseAttributeValueChunk() { char[] chars = ps.chars; int pos = ps.charPos; curNode = AddNode(index + attrCount + 1, index + 2); curNode.SetLineInfo(ps.LineNo, ps.LinePos); Debug.Assert(stringBuilder.Length == 0); for (; ; ) { while (chars[pos] > XmlCharType.MaxAsciiChar || (xmlCharType.charProperties[chars[pos]] & XmlCharType.fAttrValue) != 0) { pos++; } switch (chars[pos]) { // eol D case (char)0xD: Debug.Assert(ps.eolNormalized, "Entity replacement text for attribute values should be EOL-normalized!"); pos++; continue; // eol A, tab case (char)0xA: case (char)0x9: if (normalize) { chars[pos] = (char)0x20; // CDATA normalization of 0xA and 0x9 } pos++; continue; case '"': case '\'': case '>': pos++; continue; // attribute values cannot contain '<' case '<': Throw(pos, Res.Xml_BadAttributeChar, XmlException.BuildCharExceptionStr('<')); break; // entity reference case '&': if (pos - ps.charPos > 0) { stringBuilder.Append(chars, ps.charPos, pos - ps.charPos); } ps.charPos = pos; // expand char entities but not general entities switch (HandleEntityReference(true, EntityExpandType.OnlyCharacter, out pos)) { case EntityType.CharacterDec: case EntityType.CharacterHex: case EntityType.CharacterNamed: chars = ps.chars; if (normalize && xmlCharType.IsWhiteSpace(chars[ps.charPos]) && pos - ps.charPos == 1) { chars[ps.charPos] = (char)0x20; // CDATA normalization of character references in entities } break; case EntityType.Unexpanded: Debug.Assert(false, "Found general entity in attribute"); throw new NotSupportedException(); default: Debug.Assert(false, "We should never get to this point."); break; } chars = ps.chars; continue; default: // end of buffer if (pos == ps.charsUsed) { goto ReadData; } // surrogate chars else { char ch = chars[pos]; if (ch >= SurHighStart && ch <= SurHighEnd) { if (pos + 1 == ps.charsUsed) { goto ReadData; } pos++; if (chars[pos] >= SurLowStart && chars[pos] <= SurLowEnd) { pos++; continue; } } ThrowInvalidChar(pos, ch); break; } } ReadData: if (pos - ps.charPos > 0) { stringBuilder.Append(chars, ps.charPos, pos - ps.charPos); ps.charPos = pos; } // read new characters into the buffer if (ReadData() == 0) { if (stringBuilder.Length > 0) { goto ReturnText; } else { Debug.Assert(false, "We should never get to this point."); } } pos = ps.charPos; chars = ps.chars; } ReturnText: if (pos - ps.charPos > 0) { stringBuilder.Append(chars, ps.charPos, pos - ps.charPos); ps.charPos = pos; } curNode.SetValueNode(XmlNodeType.Text, stringBuilder.ToString()); stringBuilder.Length = 0; return true; }
private void ParseAttributeValueSlow(int curPos, char quoteChar, NodeData attr) { int pos = curPos; char[] chars = ps.chars; int valueChunkStartPos = 0; LineInfo valueChunkLineInfo = new LineInfo(ps.lineNo, ps.LinePos); NodeData lastChunk = null; Debug.Assert(stringBuilder.Length == 0); for (; ; ) { // parse the rest of the attribute value while (chars[pos] > XmlCharType.MaxAsciiChar || (xmlCharType.charProperties[chars[pos]] & XmlCharType.fAttrValue) != 0) { pos++; } if (pos - ps.charPos > 0) { stringBuilder.Append(chars, ps.charPos, pos - ps.charPos); ps.charPos = pos; } if (chars[pos] == quoteChar) { break; } else { switch (chars[pos]) { // eol case (char)0xA: pos++; OnNewLine(pos); if (normalize) { stringBuilder.Append((char)0x20); // CDATA normalization of 0xA ps.charPos++; } continue; case (char)0xD: if (chars[pos + 1] == (char)0xA) { pos += 2; if (normalize) { stringBuilder.Append(ps.eolNormalized ? "\u0020\u0020" : "\u0020"); // CDATA normalization of 0xD 0xA ps.charPos = pos; } } else if (pos + 1 < ps.charsUsed || ps.isEof) { pos++; if (normalize) { stringBuilder.Append((char)0x20); // CDATA normalization of 0xD and 0xD 0xA ps.charPos = pos; } } else { goto ReadData; } OnNewLine(pos); continue; // tab case (char)0x9: pos++; if (normalize) { stringBuilder.Append((char)0x20); // CDATA normalization of 0x9 ps.charPos++; } continue; case '"': case '\'': case '>': pos++; continue; // attribute values cannot contain '<' case '<': Throw(pos, Res.Xml_BadAttributeChar, XmlException.BuildCharExceptionStr('<')); break; // entity referece case '&': if (pos - ps.charPos > 0) { stringBuilder.Append(chars, ps.charPos, pos - ps.charPos); } ps.charPos = pos; LineInfo entityLineInfo = new LineInfo(ps.lineNo, ps.LinePos + 1); switch (HandleEntityReference(true, EntityExpandType.All, out pos)) { case EntityType.CharacterDec: case EntityType.CharacterHex: case EntityType.CharacterNamed: break; case EntityType.Unexpanded: Debug.Assert(false, "The document contains an entity reference"); throw new NotSupportedException(); case EntityType.ExpandedInAttribute: Debug.Assert(false, "The document contains an entity reference"); throw new NotSupportedException(); default: pos = ps.charPos; break; } chars = ps.chars; continue; default: // end of buffer if (pos == ps.charsUsed) { goto ReadData; } // surrogate chars else { char ch = chars[pos]; if (ch >= SurHighStart && ch <= SurHighEnd) { if (pos + 1 == ps.charsUsed) { goto ReadData; } pos++; if (chars[pos] >= SurLowStart && chars[pos] <= SurLowEnd) { pos++; continue; } } ThrowInvalidChar(pos, ch); break; } } } ReadData: // read new characters into the buffer if (ReadData() == 0) { if (ps.charsUsed - ps.charPos > 0) { if (ps.chars[ps.charPos] != (char)0xD) { Debug.Assert(false, "We should never get to this point."); Throw(Res.Xml_UnexpectedEOF1); } Debug.Assert(ps.isEof); } else { if (fragmentType == XmlNodeType.Attribute) { break; } Throw(Res.Xml_UnclosedQuote); } } pos = ps.charPos; chars = ps.chars; } if (attr.nextAttrValueChunk != null) { // construct last text value chunk int valueChunkLen = stringBuilder.Length - valueChunkStartPos; if (valueChunkLen > 0) { NodeData textChunk = new NodeData(); textChunk.lineInfo = valueChunkLineInfo; textChunk.depth = attr.depth + 1; textChunk.SetValueNode(XmlNodeType.Text, stringBuilder.ToString(valueChunkStartPos, valueChunkLen)); AddAttributeChunkToList(attr, textChunk, ref lastChunk); } } ps.charPos = pos + 1; attr.SetValue(stringBuilder.ToString()); stringBuilder.Length = 0; }
private async Task ParseAttributeValueSlowAsync( int curPos, char quoteChar, NodeData attr ) { int pos = curPos; char[] chars = ps.chars; int attributeBaseEntityId = ps.entityId; #if !SILVERLIGHT // Needed only for XmlTextReader (reporting of entities) int valueChunkStartPos = 0; LineInfo valueChunkLineInfo = new LineInfo(ps.lineNo, ps.LinePos); NodeData lastChunk = null; #endif Debug.Assert( stringBuilder.Length == 0 ); for (;;) { // parse the rest of the attribute value #if SILVERLIGHT while (xmlCharType.IsAttributeValueChar(chars[pos])) { pos++; } #else // Optimization due to the lack of inlining when a method uses byte* unsafe { while (((xmlCharType.charProperties[chars[pos]] & XmlCharType.fAttrValue) != 0)) { pos++; } } #endif if ( pos - ps.charPos > 0 ) { stringBuilder.Append( chars, ps.charPos, pos - ps.charPos ); ps.charPos = pos; } if ( chars[pos] == quoteChar && attributeBaseEntityId == ps.entityId ) { break; } else { switch ( chars[pos] ) { // eol case (char)0xA: pos++; OnNewLine( pos ); if ( normalize ) { stringBuilder.Append( (char)0x20 ); // CDATA normalization of 0xA ps.charPos++; } continue; case (char)0xD: if ( chars[pos+1] == (char)0xA ) { pos += 2; if ( normalize ) { stringBuilder.Append( ps.eolNormalized ? "\u0020\u0020" : "\u0020" ); // CDATA normalization of 0xD 0xA ps.charPos = pos; } } else if ( pos+1 < ps.charsUsed || ps.isEof ) { pos++; if ( normalize ) { stringBuilder.Append( (char)0x20 ); // CDATA normalization of 0xD and 0xD 0xA ps.charPos = pos; } } else { goto ReadData; } OnNewLine( pos ); continue; // tab case (char)0x9: pos++; if ( normalize ) { stringBuilder.Append( (char)0x20 ); // CDATA normalization of 0x9 ps.charPos++; } continue; case '"': case '\'': case '>': pos++; continue; // attribute values cannot contain '<' case '<': Throw( pos, Res.Xml_BadAttributeChar, XmlException.BuildCharExceptionArgs( '<', '\0' ) ); break; // entity referece case '&': if ( pos - ps.charPos > 0 ) { stringBuilder.Append( chars, ps.charPos, pos - ps.charPos ); } ps.charPos = pos; #if !SILVERLIGHT // Needed only for XmlTextReader (reporting of entities) int enclosingEntityId = ps.entityId; LineInfo entityLineInfo = new LineInfo( ps.lineNo, ps.LinePos + 1 ); #endif var tuple_8 = await HandleEntityReferenceAsync( true, EntityExpandType.All).ConfigureAwait(false); pos = tuple_8.Item1; switch ( tuple_8.Item2 ) { case EntityType.CharacterDec: case EntityType.CharacterHex: case EntityType.CharacterNamed: break; #if !SILVERLIGHT // Needed only for XmlTextReader (reporting of entities) case EntityType.Unexpanded: if ( parsingMode == ParsingMode.Full && ps.entityId == attributeBaseEntityId ) { // construct text value chunk int valueChunkLen = stringBuilder.Length - valueChunkStartPos; if ( valueChunkLen > 0 ) { NodeData textChunk = new NodeData(); textChunk.lineInfo = valueChunkLineInfo; textChunk.depth = attr.depth + 1; textChunk.SetValueNode( XmlNodeType.Text, stringBuilder.ToString( valueChunkStartPos, valueChunkLen ) ); AddAttributeChunkToList( attr, textChunk, ref lastChunk ); } // parse entity name ps.charPos++; string entityName = await ParseEntityNameAsync().ConfigureAwait(false); // construct entity reference chunk NodeData entityChunk = new NodeData(); entityChunk.lineInfo = entityLineInfo; entityChunk.depth = attr.depth + 1; entityChunk.SetNamedNode( XmlNodeType.EntityReference, entityName ); AddAttributeChunkToList( attr, entityChunk, ref lastChunk ); // append entity ref to the attribute value stringBuilder.Append( '&' ); stringBuilder.Append( entityName ); stringBuilder.Append( ';' ); // update info for the next attribute value chunk valueChunkStartPos = stringBuilder.Length; valueChunkLineInfo.Set( ps.LineNo, ps.LinePos ); fullAttrCleanup = true; } else { ps.charPos++; await ParseEntityNameAsync().ConfigureAwait(false); } pos = ps.charPos; break; case EntityType.ExpandedInAttribute: if ( parsingMode == ParsingMode.Full && enclosingEntityId == attributeBaseEntityId ) { // construct text value chunk int valueChunkLen = stringBuilder.Length - valueChunkStartPos; if ( valueChunkLen > 0 ) { NodeData textChunk = new NodeData(); textChunk.lineInfo = valueChunkLineInfo; textChunk.depth = attr.depth + 1; textChunk.SetValueNode( XmlNodeType.Text, stringBuilder.ToString( valueChunkStartPos, valueChunkLen ) ); AddAttributeChunkToList( attr, textChunk, ref lastChunk ); } // construct entity reference chunk NodeData entityChunk = new NodeData(); entityChunk.lineInfo = entityLineInfo; entityChunk.depth = attr.depth + 1; entityChunk.SetNamedNode( XmlNodeType.EntityReference, ps.entity.Name ); AddAttributeChunkToList( attr, entityChunk, ref lastChunk ); fullAttrCleanup = true; // Note: info for the next attribute value chunk will be updated once we // get out of the expanded entity } pos = ps.charPos; break; #endif default: pos = ps.charPos; break; } chars = ps.chars; continue; default: // end of buffer if ( pos == ps.charsUsed ) { goto ReadData; } // surrogate chars else { char ch = chars[pos]; if ( XmlCharType.IsHighSurrogate(ch) ) { if ( pos + 1 == ps.charsUsed ) { goto ReadData; } pos++; if ( XmlCharType.IsLowSurrogate( chars[pos] ) ) { pos++; continue; } } ThrowInvalidChar( chars, ps.charsUsed, pos ); break; } } } ReadData: // read new characters into the buffer if ( await ReadDataAsync().ConfigureAwait(false) == 0 ) { if ( ps.charsUsed - ps.charPos > 0 ) { if ( ps.chars[ps.charPos] != (char)0xD ) { Debug.Assert( false, "We should never get to this point." ); Throw( Res.Xml_UnexpectedEOF1 ); } Debug.Assert( ps.isEof ); } else { if ( !InEntity ) { if ( fragmentType == XmlNodeType.Attribute ) { if ( attributeBaseEntityId != ps.entityId ) { Throw( Res.Xml_EntityRefNesting ); } break; } Throw( Res.Xml_UnclosedQuote ); } #if SILVERLIGHT // Needed only for XmlTextReader (reporting of entities) HandleEntityEnd( true ); #else if ( HandleEntityEnd( true ) ) { // no EndEntity reporting while parsing attributes Debug.Assert( false ); Throw( Res.Xml_InternalError ); } // update info for the next attribute value chunk if ( attributeBaseEntityId == ps.entityId ) { valueChunkStartPos = stringBuilder.Length; valueChunkLineInfo.Set( ps.LineNo, ps.LinePos ); } #endif } } pos = ps.charPos; chars = ps.chars; } #if !SILVERLIGHT // Needed only for XmlTextReader (reporting of entities) if ( attr.nextAttrValueChunk != null ) { // construct last text value chunk int valueChunkLen = stringBuilder.Length - valueChunkStartPos; if ( valueChunkLen > 0 ) { NodeData textChunk = new NodeData(); textChunk.lineInfo = valueChunkLineInfo; textChunk.depth = attr.depth + 1; textChunk.SetValueNode( XmlNodeType.Text, stringBuilder.ToString( valueChunkStartPos, valueChunkLen ) ); AddAttributeChunkToList( attr, textChunk, ref lastChunk ); } } #endif ps.charPos = pos + 1; attr.SetValue( stringBuilder.ToString() ); stringBuilder.Length = 0; }