private bool PrepareToWrite(string value) { FormatterState state = PeekState(); switch (state) { case FormatterState.StartElement: if (value == " xmlns") { PushState(FormatterState.StartAttribute); return(PrepareToWrite(value)); } else { SetColour(m_colourMaroon); } break; case FormatterState.EndElement: SetColour(value == " /" ? m_colourBlue : m_colourMaroon); break; case FormatterState.ElementBody: if (value == " xmlns") { PushState(FormatterState.StartAttribute); return(PrepareToWrite(value)); } else { SetColour(m_colourBlack); } break; case FormatterState.StartAttribute: // We don't know at this stage whether this is the attribute prefix or the attribute // name, so don't write it yet, just buffer it. Debug.Assert(m_attributeBuffer == null, "m_attributeBuffer == null"); m_attributeBuffer = value; return(false); case FormatterState.AttributeName: SetColour(m_colourRed); break; case FormatterState.AttributeBody: SetColour(m_colourBlue); break; case FormatterState.EndAttribute: SetColour(m_colourBlue); break; case FormatterState.Text: SetColour(m_colourBlack); break; case FormatterState.StartCDATA: Debug.Assert(value == "<![CDATA[", "Unexpected text in StartCDATA state: '" + value + "'"); SetColour(m_colourPink); PushState(FormatterState.CDATABody); break; case FormatterState.CDATABody: SetColour(value == "]]>" ? m_colourPink : m_colourBlack); break; case FormatterState.Comment: SetColour(value == "<!--" || value == "-->" ? m_colourBlue : m_colourGreen); break; case FormatterState.StartInstruction: if (value == "<?") { SetColour(m_colourBlue); } else if (value == "xml") { SetColour(m_colourMaroon); PushState(FormatterState.InstructionName); } break; case FormatterState.InstructionName: if (value == "?>") { SetColour(m_colourBlue); } else { WriteXmlInstructions(value); return(false); } break; case FormatterState.InstructionBody: // This may actually be the end of the processing instruction, but the colour is blue // either way. SetColour(m_colourBlue); break; case FormatterState.StartDocType: SetColour(m_colourBlue); PushState(FormatterState.DocTypeName); break; case FormatterState.DocTypeName: SetColour(m_colourRed); break; case FormatterState.DocTypeBody: SetColour(m_colourPink); break; case FormatterState.DocTypeReference: SetColour(m_colourBlue); break; case FormatterState.QualifiedName: // Nothing to do for a qualified name - it should be part of an attribute or // element value and will have the same formatting as any other value. break; default: Debug.Fail("Unexpected formatter state: " + state.ToString()); break; } return(true); }
// This is where the real work is done - work out what colour to use based on the current state // and the string value being written. XmlTextWriter has an AutoComplete() function, so often // we may be writing a value that SHOULD have been written in the previous state. This makes it // necessary to check for "xmlns" for the previous element when writing the start of the next one, // for example. // There is one method for a char value and one for a string value. This improves performance // as it avoids unnecessary conversion from char to string. private void PrepareToWrite(char value) { FormatterState state = PeekState(); switch (state) { case FormatterState.StartElement: SetColour(value == '<' || value == '>' ? m_colourBlue : m_colourMaroon); break; case FormatterState.EndElement: SetColour(value == '<' || value == '>' || value == '/' ? m_colourBlue : m_colourMaroon); break; case FormatterState.ElementBody: SetColour(value == '>' ? m_colourBlue : m_colourBlack); break; case FormatterState.StartAttribute: if (value == ':') { Debug.Assert(m_attributeBuffer != null, "m_attributeBuffer != null"); // The buffer was a prefix - write it now. SetColour(m_colourMaroon); WriteEncoded(m_attributeBuffer); m_attributeBuffer = null; SetColour(m_colourPink); // The attribute name should follow. PopState(); PushState(FormatterState.AttributeName); } else if (value == '=') { // The buffer was a name - write it now. SetColour(m_colourRed); WriteEncoded(m_attributeBuffer); m_attributeBuffer = null; // The body should follow. SetColour(m_colourBlue); PopState(); PushState(FormatterState.AttributeBody); } else { Debug.Assert(value == ' ', "Unexpected character value in StartAttribute state: '" + value.ToString() + "'"); } break; case FormatterState.AttributeName: if (value == '=') { SetColour(m_colourBlue); PopState(); PushState(FormatterState.AttributeBody); } else { SetColour(m_colourRed); } break; case FormatterState.AttributeBody: SetColour(m_colourBlue); if (value == '>') { PopState(); } break; case FormatterState.EndAttribute: SetColour(m_colourBlue); break; case FormatterState.Text: SetColour(m_colourBlack); break; case FormatterState.StartCDATA: if (value == '>') { SetColour(m_colourBlue); // The > ending the start of the element } else { Debug.Fail("Unexpected text in StartCDATA state: '" + value.ToString() + "'"); } break; case FormatterState.CDATABody: SetColour(m_colourBlack); break; case FormatterState.Comment: SetColour(m_colourGreen); break; case FormatterState.StartInstruction: // No character values for this state. break; case FormatterState.InstructionName: if (value == '=') { SetColour(m_colourBlue); PushState(FormatterState.InstructionBody); } else { SetColour(m_colourRed); } break; case FormatterState.InstructionBody: if (value == ' ') { PopState(); } else { // This may actually be the end of the processing instruction, but the colour is blue // either way. SetColour(m_colourBlue); } break; case FormatterState.StartDocType: SetColour(m_colourBlue); PushState(FormatterState.DocTypeName); break; case FormatterState.DocTypeName: if (value == '>') { SetColour(m_colourBlue); } else if (value == '[') { SetColour(m_colourBlue); PushState(FormatterState.DocTypeBody); } else if (value == '\"') { SetColour(m_colourBlue); PushState(FormatterState.DocTypeReference); } else { SetColour(m_colourRed); } break; case FormatterState.DocTypeBody: SetColour(value == ']' || value == '>' ? m_colourBlue : m_colourPink); break; case FormatterState.DocTypeReference: SetColour(m_colourBlue); break; case FormatterState.QualifiedName: // Nothing to do for a qualified name - it should be part of an attribute or // element value and will have the same formatting as any other value. break; case FormatterState.None: // This case occurs when the XML ends abruptly (ie. it's invalid), but we still // to auto-complete the last element. SetColour(value == '>' ? m_colourBlue : m_colourBlack); break; default: Debug.Fail("Unexpected formatter state: " + state.ToString()); break; } }