/// <summary> /// Reads an attribute value and returns it. /// </summary> private string _readAttributeValue() { char quote = m_str[m_pos]; if (quote != '"' && quote != '\'') { throw _error(ErrorCode.XML_PARSER_ELEMENT_MALFORMED); } m_pos++; ReadOnlySpan <char> span = m_str.AsSpan(m_pos); int charsLeft = m_str.Length - m_pos; char newline = s_newLineChar; ReadOnlySpan <char> searchChars = stackalloc char[] { quote, '&', '<', newline }; bool mayHaveEntities = false; while (true) { int index = span.IndexOfAny(searchChars); if (index == -1) { throw _error(ErrorCode.XML_PARSER_UNTERMINATED_ATTR); } char charAtIndex = span[index]; if (charAtIndex == quote) { span = span.Slice(index); break; } else if (charAtIndex == '&') { span = span.Slice(index); mayHaveEntities = true; break; } else if (charAtIndex == newline) { m_curLine++; span = span.Slice(index + 1); } else { // Attributes cannot contain '<'. throw _error(ErrorCode.XML_PARSER_ELEMENT_MALFORMED); } } int charsRead = charsLeft - span.Length; if (!mayHaveEntities) { int startPos = m_pos; m_pos += charsRead + 1; // +1 for the closing quote return(m_str.Substring(startPos, charsRead)); } char[] textBuffer = m_buffer; if (textBuffer.Length < charsRead) { DataStructureUtil.resizeArray(ref textBuffer, textBuffer.Length, charsRead); } m_str.CopyTo(m_pos, textBuffer, 0, charsRead); m_pos += charsRead; int textBufPos = charsRead; while (true) { char ch = m_str[m_pos]; if (ch == '&') { int entityCode = _readEntity(); _writeCodePoint(ref textBuffer, ref textBufPos, entityCode); } else if (ch == quote) { break; } else if (ch == '<') { throw _error(ErrorCode.XML_PARSER_ELEMENT_MALFORMED); } else if (ch == newline) { m_curLine++; m_pos++; } span = m_str.AsSpan(m_pos); int nextIndex = span.IndexOfAny(searchChars); if (nextIndex == -1) { throw _error(ErrorCode.XML_PARSER_UNTERMINATED_ATTR); } if (textBuffer.Length - textBufPos < nextIndex) { DataStructureUtil.resizeArray(ref textBuffer, textBufPos, textBufPos + nextIndex); } span.Slice(0, nextIndex).CopyTo(textBuffer.AsSpan(textBufPos)); textBufPos += nextIndex; m_pos += nextIndex; } m_pos++; // For closing quote m_buffer = textBuffer; return((textBufPos == 0) ? "" : new string(textBuffer, 0, textBufPos)); }
/// <summary> /// Reads a text node and adds it as a child to the element currently being processed. /// </summary> private void _readText() { ReadOnlySpan <char> span = m_str.AsSpan(m_pos); int charsLeft = m_str.Length - m_pos; char newline = s_newLineChar; ReadOnlySpan <char> searchChars = stackalloc char[3] { '<', '&', newline }; bool mayHaveEntities = false; while (!span.IsEmpty) { int index = span.IndexOfAny(searchChars); char charAtIndex = (index == -1) ? '\0' : span[index]; if (charAtIndex == '<') { span = span.Slice(index); break; } else if (charAtIndex == '&') { span = span.Slice(index); mayHaveEntities = true; break; } else if (charAtIndex == newline) { m_curLine++; span = span.Slice(index + 1); } else { span = default; } } int charsRead = charsLeft - span.Length; string text; if (!mayHaveEntities) { text = ((m_parserFlags & FLAG_IGNORE_SPACE) != 0) ? XMLHelper.stripWhitespace(m_str, m_pos, charsRead) : m_str.Substring(m_pos, charsRead); if (text.Length != 0) { m_nodeStack.add(ASXML.createTextNode(text)); } m_pos += charsRead; return; } char[] textBuffer = m_buffer; if (charsRead > textBuffer.Length) { DataStructureUtil.resizeArray(ref textBuffer, textBuffer.Length, charsRead); } m_str.CopyTo(m_pos, textBuffer, 0, charsRead); int textBufPos = charsRead; m_pos += charsRead; while (true) { char ch = m_str[m_pos]; if (ch == '&') { int entityCode = _readEntity(); _writeCodePoint(ref textBuffer, ref textBufPos, entityCode); } else if (ch == '<') { break; } else if (ch == newline) { m_curLine++; m_pos++; } span = m_str.AsSpan(m_pos); int nextIndex = span.IndexOfAny(searchChars); int charsToCopy = (nextIndex == -1) ? span.Length : nextIndex; if (textBuffer.Length - textBufPos < charsToCopy) { DataStructureUtil.resizeArray(ref textBuffer, textBufPos, textBufPos + charsToCopy); } span.Slice(0, charsToCopy).CopyTo(textBuffer.AsSpan(textBufPos)); textBufPos += charsToCopy; m_pos += charsToCopy; if (nextIndex == -1) { break; } } m_buffer = textBuffer; if (textBufPos == 0) { return; } text = ((m_parserFlags & FLAG_IGNORE_SPACE) != 0) ? XMLHelper.stripWhitespace(textBuffer, 0, textBufPos) : new string(textBuffer, 0, textBufPos); if (text.Length != 0) { m_nodeStack.add(ASXML.createTextNode(text)); } }