public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1) { context.Nodes.Push (new XProcessingInstruction (context.LocationMinus ("<?".Length))); } if (c == '?') { if (context.StateTag == NOMATCH) { context.StateTag = QUESTION; return null; } } else if (c == '>' && context.StateTag == QUESTION) { // if the '?' is followed by a '>', the state has ended // so attach a node to the DOM and end the state var xpi = (XProcessingInstruction) context.Nodes.Pop (); if (context.BuildTree) { xpi.End (context.Location); ((XContainer) context.Nodes.Peek ()).AddChildNode (xpi); } return Parent; } else { context.StateTag = NOMATCH; } return null; }
/// <summary> /// Gets properties that was not created from schema. /// </summary> /// <param name="parserContext">Source parser context.</param> /// <param name="schema">Source schema.</param> /// <param name="recursive">Recursive search in children schemas.</param> /// <returns>Properties that was not created from schema.</returns> public static IEnumerable <IProperty> GetPropertiesNotFromSchema(this IXmlParserContext parserContext, ISchema?schema = null, bool recursive = true) { // Use root schema. schema ??= parserContext.Schema; IEnumerable <IProperty> properties = schema.GetProperties(); foreach (IProperty property in properties) { if (property.GetIsNotFromSchema()) { yield return(property); } if (recursive) { if (parserContext.GetSchema(property) is { } subSchema) { foreach (IProperty subProperty in parserContext.GetPropertiesNotFromSchema(subSchema, recursive)) { yield return(subProperty); } } } } }
public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1) { context.Nodes.Push(new XProcessingInstruction(context.LocationMinus("<?".Length))); } if (c == '?') { if (context.StateTag == NOMATCH) { context.StateTag = QUESTION; return(null); } } else if (c == '>' && context.StateTag == QUESTION) { // if the '?' is followed by a '>', the state has ended // so attach a node to the DOM and end the state var xpi = (XProcessingInstruction)context.Nodes.Pop(); if (context.BuildTree) { xpi.End(context.Location); ((XContainer)context.Nodes.Peek()).AddChildNode(xpi); } return(Parent); } else { context.StateTag = NOMATCH; } return(null); }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { //NOTE: This is (mostly) duplicated in HtmlTagState //handle inline tags implicitly closed by block-level elements if (context.CurrentStateLength == 1 && context.PreviousState is XmlNameState) { var ct = (XClosingTag) context.Nodes.Peek (); if (!ct.Name.HasPrefix && ct.Name.IsValid) { //Note: the node stack will always be at least 1 deep due to the XDocument var parent = context.Nodes.Peek (1) as XElement; //if it's not a matching closing tag if (parent != null && !string.Equals (ct.Name.Name, parent.Name.Name, StringComparison.OrdinalIgnoreCase)) { //attempt to implicitly close the parents while (parent != null && parent.ValidAndNoPrefix () && parent.IsImplicitlyClosedBy (ct)) { context.Nodes.Pop (); context.Nodes.Pop (); if (warnAutoClose) { context.LogWarning (string.Format ("Tag '{0}' implicitly closed by closing tag '{1}'.", parent.Name.Name, ct.Name.Name), parent.Region); } //parent.Region.End = element.Region.Start; //parent.Region.EndColumn = Math.Max (parent.Region.EndColumn - 1, 1); parent.Close (parent); context.Nodes.Push (ct); parent = context.Nodes.Peek (1) as XElement; } } } } return base.PushChar (c, context, ref rollback); }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { if (c == '@' && context.StateTag == FREE) { context.StateTag = TRANSITION; return null; } else if (context.StateTag == TRANSITION) { rollback = String.Empty; switch (c) { case '{': // Code block @{ return CodeBlockState; case '*': // Comment @* return ServerCommentState; case '(': // Explicit expression @( return ExpressionState; default: // If char preceding @ was a letter or a digit, don't switch to expression, e.g. [email protected] if (context.CurrentStateLength <= 2 || (!Char.IsLetterOrDigit (previousChar) && (Char.IsLetter (c) || c == '_'))) // Statement, directive or implicit expression return SpeculativeState; else context.StateTag = FREE; break; } } previousChar = c; return base.PushChar (c, context, ref rollback); }
public void ReadInvalidXml() { string testXml = @" <Person> <FirstName>z</FirstName> <Address> <City>NY</City> <Unknown>1</Unknown> </Address> </Person>"; IObjectSchema personSchema = new PersonSchema().GetObjectSchema(); var container = XDocument.Parse(testXml).ParseXmlToContainer(personSchema); IXmlParserContext xmlParserContext = container.GetMetadata <IXmlParserContext>(); var validationRules = personSchema.Properties.GetValidationRules().ToArray(); var messages = container.Validate(validationRules).ToArray(); messages.Should().HaveCount(2); messages[0].FormattedMessage.Should().Be("FirstName length should be greater then 1 but was 1"); messages[1].FormattedMessage.Should().Be("LastName is marked as required but is not exists."); IObjectSchema addressSchemaStatic = personSchema.GetProperty("Address") !.GetSchema() !.ToObjectSchema(); addressSchemaStatic.Properties.Should().HaveCount(2); IObjectSchema addressSchemaReal = xmlParserContext.GetSchema(personSchema.GetProperty("Address")).ToObjectSchema(); addressSchemaReal.Properties.Should().HaveCount(3); IProperty[] notFromSchema = addressSchemaReal.GetPropertiesNotFromSchema().ToArray(); notFromSchema.Should().HaveCount(1); notFromSchema[0].Name.Should().Be("Unknown"); notFromSchema[0].Type.Should().Be(typeof(string)); }
public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1) { context.Nodes.Push(new RazorComment(context.LocationMinus(2))); return(null); } switch (context.StateTag) { case NOMATCH: if (c == '*') { context.StateTag = STAR; } break; case STAR: if (c == '@') { StateEngineService.EndCodeFragment <RazorComment> (context); return(Parent); } else { context.StateTag = NOMATCH; } break; } return(null); }
public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback) { if (c == '%' && context.StateTag == BRACKET) { context.StateTag = BRACKET_PERCENT; return(null); } else if (context.StateTag == BRACKET_PERCENT) { switch (c) { case '@': //DIRECTIVE <%@ return(DirectiveState); case '-': // SERVER COMMENT: <%-- return(ServerCommentState); case '=': //RENDER EXPRESSION <%= case '#': //DATABINDING EXPRESSION <%# case '$': //RESOURCE EXPRESSION <%$ default: // RENDER BLOCK rollback = ""; return(ExpressionState); } } return(base.PushChar(c, context, ref rollback)); }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1) { context.Nodes.Push (new XCData (context.LocationMinus ("<![CDATA[".Length + 1))); } if (c == ']') { //make sure we know when there are two ']' chars together if (context.StateTag == NOMATCH) context.StateTag = SINGLE_BRACKET; else context.StateTag = DOUBLE_BRACKET; } else if (c == '>' && context.StateTag == DOUBLE_BRACKET) { // if the ']]' is followed by a '>', the state has ended // so attach a node to the DOM and end the state var cdata = (XCData) context.Nodes.Pop (); if (context.BuildTree) { cdata.End (context.Location); ((XContainer) context.Nodes.Peek ()).AddChildNode (cdata); } return Parent; } else { // not any part of a ']]>', so make sure matching is reset context.StateTag = NOMATCH; } return null; }
public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1) { bracketsBuilder.Clear(); var block = context.Nodes.FirstOrDefault(n => n is RazorCodeBlock); if (block == null) { var razorBlock = new RazorCodeBlock(context.LocationMinus(2)); context.Nodes.Push(razorBlock); CorrespondingBlock = razorBlock; } else { CorrespondingBlock = block as RazorCodeFragment; } } switch (c) { case '{': return(ParseOpeningBracket(c, context)); case '}': return(ParseClosingBracket <RazorCodeBlock> (c, context, Parent)); } return(base.PushChar(c, context, ref rollback)); }
internal static void AddExpressionNode(char c, IXmlParserContext context) { Debug.Assert(c != '@' && c != '-', "AspNetExpressionState should not be passed a directive or comment"); switch (c) { //DATABINDING EXPRESSION <%# case '#': context.Nodes.Push(new WebFormsBindingExpression(context.LocationMinus(3))); break; //RESOURCE EXPRESSION <%$ case '$': context.Nodes.Push(new WebFormsResourceExpression(context.LocationMinus(3))); break; //RENDER EXPRESSION <%= case '=': context.Nodes.Push(new WebFormsRenderExpression(context.LocationMinus(3))); break; //HTML ENCODED EXPRESSION <%: case ':': context.Nodes.Push(new WebFormsHtmlEncodedExpression(context.LocationMinus(3))); break; // RENDER BLOCK default: context.Nodes.Push(new WebFormsRenderBlock(context.LocationMinus(3))); break; } }
public static void EndCodeFragment <T> (IXmlParserContext context, DocumentLocation loc) where T : XNode { var top = context.Nodes.Pop(); var node = top as T; if (node == null) { if (top.IsEnded) { node = context.Nodes.Pop() as T; } if (node == null) { Debug.Fail("Unexpected node at the top of the stack"); LoggingService.LogError("Error in Razor StateEngine parser: unexpected node at the top of the stack.\n" + "Expected: {0}\n{1}", typeof(T), context.ToString()); return; } } node.End(loc); if (context.BuildTree) { var xObj = context.Nodes.Peek(); var container = xObj as XContainer; if (container != null) { container.AddChildNode(node); } } }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1) { AddExpressionNode (c, context); } else if (c == '%') { context.StateTag = PERCENT; } else if (c == '>') { if (context.StateTag == PERCENT) { XNode expr = (XNode) context.Nodes.Pop (); expr.End (context.Location); if (context.BuildTree) { XObject ob = context.Nodes.Peek (); var xc = ob as XContainer; if (xc != null) { xc.AddChildNode (expr); } //FIXME: add to other kinds of node, e.g. if used within a tag } return Parent; } else { context.StateTag = NONE; } } return null; }
internal static void AddExpressionNode (char c, IXmlParserContext context) { Debug.Assert (c != '@' && c!= '-', "AspNetExpressionState should not be passed a directive or comment"); switch (c) { //DATABINDING EXPRESSION <%# case '#': context.Nodes.Push (new WebFormsBindingExpression (context.LocationMinus (3))); break; //RESOURCE EXPRESSION <%$ case '$': context.Nodes.Push (new WebFormsResourceExpression (context.LocationMinus (3))); break; //RENDER EXPRESSION <%= case '=': context.Nodes.Push (new WebFormsRenderExpression (context.LocationMinus (3))); break; //HTML ENCODED EXPRESSION <%: case ':': context.Nodes.Push (new WebFormsHtmlEncodedExpression (context.LocationMinus (3))); break; // RENDER BLOCK default: context.Nodes.Push (new WebFormsRenderBlock (context.LocationMinus (3))); break; } }
public virtual XmlParserState ParseClosingBracket <T> (char c, IXmlParserContext context, XmlParserState stateToReturn) where T : XNode { bool isEnding = false; var rootState = RootState as RazorRootState; if (rootState.UseSimplifiedBracketTracker) { if (bracketsBuilder.Length > 0) { bracketsBuilder.Remove(0, 1); } if (bracketsBuilder.Length == 0) { isEnding = true; } } else if (!rootState.UseSimplifiedBracketTracker && CorrespondingBlock.IsEndingBracket(context.LocationMinus(1))) { isEnding = true; } if (isEnding) { StateEngineService.EndCodeFragment <T> (context); return(stateToReturn); } return(null); }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 0) context.StateTag = 0; if (c == '<') { if (context.StateTag == 0) { context.StateTag++; return null; } } if (context.StateTag > 0) { if (CLOSE[context.StateTag] == c) { context.StateTag++; if (context.StateTag == CLOSE.Length) { var el = (XElement) context.Nodes.Pop (); var closing = new XClosingTag (new XName ("script"), context.LocationMinus (CLOSE.Length)); closing.End (context.Location); el.Close (closing); rollback = string.Empty; return Parent; } } else { context.StateTag = 0; } } return null; }
public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1) { context.Nodes.Push(new WebFormsServerComment(context.LocationMinus(context.CurrentStateLength + "<%--".Length))); } switch (context.StateTag) { case NOMATCH: if (c == '-') { context.StateTag = SINGLE_DASH; } break; case SINGLE_DASH: if (c == '-') { context.StateTag = DOUBLE_DASH; } else { context.StateTag = NOMATCH; } break; case DOUBLE_DASH: if (c == '%') { context.StateTag = PERCENT; } else { context.StateTag = NOMATCH; } break; case PERCENT: if (c == '>') { var comment = (WebFormsServerComment)context.Nodes.Pop(); comment.End(context.Location); if (context.BuildTree) { XObject ob = context.Nodes.Peek(); if (ob is XContainer) { ((XContainer)ob).AddChildNode(comment); } //FIXME: add to other kinds of node, e.g. if used within a tag } return(Parent); } break; } return(null); }
public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback) { var namedObject = context.Nodes.Peek() as INamedXObject; if (namedObject == null || namedObject.Name.Prefix != null) { throw new InvalidOperationException("Invalid state"); } Debug.Assert(context.CurrentStateLength > 1 || IsValidNameStart(c), "First character pushed to a XmlTagNameState must be a letter."); Debug.Assert(context.CurrentStateLength > 1 || context.KeywordBuilder.Length == 0, "Keyword builder must be empty when state begins."); if (XmlChar.IsWhitespace(c) || c == '<' || c == '>' || c == '/' || c == '=') { rollback = string.Empty; if (context.KeywordBuilder.Length == 0) { context.LogError("Zero-length name."); namedObject.Name = XName.Empty; } else { string s = context.KeywordBuilder.ToString(); int i = s.IndexOf(':'); if (i < 0) { namedObject.Name = new XName(s); } else { namedObject.Name = new XName(s.Substring(0, i), s.Substring(i + 1)); } } return(Parent); } if (c == ':') { if (context.KeywordBuilder.ToString().IndexOf(':') > 0) { context.LogError("Unexpected ':' in name."); } context.KeywordBuilder.Append(c); return(null); } if (XmlChar.IsNameChar(c)) { context.KeywordBuilder.Append(c); return(null); } rollback = string.Empty; context.LogError("Unexpected character '" + c + "' in name"); return(Parent); }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { // allow < in values if (context.StateTag != '\0' && context.CurrentStateLength > 1 && c == '<') { context.KeywordBuilder.Append (c); return null; } return base.PushChar (c, context, ref rollback); }
public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback) { // allow < in values if (context.StateTag != '\0' && context.CurrentStateLength > 1 && c == '<') { context.KeywordBuilder.Append(c); return(null); } return(base.PushChar(c, context, ref rollback)); }
/// <summary> /// Gets schema for property. /// If property is null then returns null. /// </summary> /// <param name="context">Parser context.</param> /// <param name="property">Source property.</param> /// <returns>Optional schema attached to property.</returns> public static ISchema?GetSchema(this IXmlParserContext context, IProperty?property) { if (property == null) { return(null); } context.SchemaCache.TryGetValue(property, out var schema); return(schema); }
protected virtual void Close(XElement element, IXmlParserContext context, int endOffset) { //have already checked that element is not null, i.e. top of stack is our element if (element.IsClosed) { context.Nodes.Pop(); } element.End(endOffset); }
protected virtual void Close(XElement element, IXmlParserContext context, DocumentLocation location) { //have already checked that element is not null, i.e. top of stack is our element if (element.IsClosed) { context.Nodes.Pop(); } element.End(location); }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1) { switch (c) { case '(': context.StateTag = NONE_EXPLICIT; context.Nodes.Push (new RazorExplicitExpression (context.LocationMinus (2))); return null; default: context.StateTag = NONE_IMPLICIT; if (!(context.PreviousState is RazorSpeculativeState)) context.Nodes.Push (new RazorImplicitExpression (context.LocationMinus (2))); break; } } switch (c) { case '(': if (context.StateTag == NONE_EXPLICIT) context.StateTag = INSIDE_BRACKET_EXPLICIT; else if (context.StateTag == NONE_IMPLICIT) context.StateTag = INSIDE_BRACKET_IMPLICIT; context.KeywordBuilder.Append (c); break; case ')': if (context.StateTag == NONE_EXPLICIT) { StateEngineService.EndCodeFragment<RazorExplicitExpression> (context); return Parent; } else if (context.StateTag != NONE_IMPLICIT) { if (context.KeywordBuilder.Length > 0) context.KeywordBuilder.Remove (0, 1); if (context.KeywordBuilder.Length == 0) context.StateTag = (context.StateTag == INSIDE_BRACKET_IMPLICIT ? NONE_IMPLICIT : NONE_EXPLICIT); } break; default: // Space between function's name and open bracket not allowed in razor, e.g. @Html.Raw (foo) if (!(Char.IsLetterOrDigit (c) || allowedChars.Any (ch => ch == c)) && context.StateTag == NONE_IMPLICIT) { StateEngineService.EndCodeFragment<RazorImplicitExpression> (context, 1); rollback = String.Empty; if (Parent is RazorSpeculativeState) return Parent.Parent; return Parent; } break; } return null; }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { var directive = context.Nodes.Peek () as WebFormsDirective; if (directive == null || directive.IsComplete) { directive = new WebFormsDirective (context.LocationMinus (4)); // 4 == <%@ + current char context.Nodes.Push (directive); } if (c == '<') { context.LogError ("Unexpected '<' in directive."); rollback = string.Empty; return Parent; } Debug.Assert (!directive.IsComplete); if (context.StateTag != ENDING && c == '%') { context.StateTag = ENDING; return null; } if (context.StateTag == ENDING) { if (c == '>') { //have already checked that directive is not null, i.e. top of stack is our directive context.Nodes.Pop (); if (!directive.IsNamed) { context.LogError ("Directive closed prematurely."); } else { directive.End (context.Location); if (context.BuildTree) { var container = (XContainer)context.Nodes.Peek (); container.AddChildNode (directive); } } return Parent; } //ending but not '>'? Error; go to end. } else if (char.IsLetter (c)) { rollback = string.Empty; if (!directive.IsNamed) { return NameState; } else { return AttributeState; } } else if (char.IsWhiteSpace (c)) return null; rollback = string.Empty; context.LogError ("Unexpected character '" + c + "' in tag."); return Parent; }
/// <summary> /// Gets properties that was not created from schema for the property. /// </summary> /// <param name="parserContext">Source parser context.</param> /// <param name="property">Property to get schema..</param> /// <param name="recursive">Recursive search in children schemas.</param> /// <returns>Properties that was not created from schema.</returns> public static IEnumerable <IProperty> GetPropertiesNotFromSchema(this IXmlParserContext parserContext, IProperty property, bool recursive = true) { ISchema?schema = parserContext.GetSchema(property); if (schema == null) { return(Array.Empty <IProperty>()); } return(parserContext.GetPropertiesNotFromSchema(schema, recursive: recursive)); }
XmlParserState SwitchToStatement(IXmlParserContext context, ref string rollback) { string key = context.KeywordBuilder.ToString(); var stm = new RazorStatement(context.LocationMinus(key.Length + 2)) { Name = key.Trim() }; context.Nodes.Push(stm); rollback = String.Empty; return(EnsureSetAndAdopted <RazorStatementState> (ref statementState)); }
/// <summary> /// Gets parser from context cache or <see cref="IXmlParserSettings.ParserRules"/>. /// </summary> /// <param name="context">Parser context.</param> /// <param name="property">Source property.</param> /// <returns>Parser.</returns> public static IValueParser GetParserCached(this IXmlParserContext context, IProperty property) { if (context.ParsersCache.TryGetValue(property, out IValueParser result)) { return(result); } result = context.ParserSettings.ParserRules.GetParserRule(property, context.ParserSettings.PropertyComparer)?.Parser ?? EmptyParser.Instance; context.ParsersCache.TryAdd(property, result); return(result); }
public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1 && context.PreviousState is HtmlScriptBodyState) { return(Parent); } //NOTE: This is (mostly) duplicated in HtmlClosingTagState //handle "paragraph" tags implicitly closed by block-level elements if (context.CurrentStateLength == 1 && context.PreviousState is XmlNameState) { var element = (XElement)context.Nodes.Peek(); if (!element.Name.HasPrefix && element.Name.IsValid) { //Note: the node stack will always be at least 1 deep due to the XDocument var parent = context.Nodes.Peek(1) as XElement; while (parent != null && parent.ValidAndNoPrefix() && parent.IsImplicitlyClosedBy(element)) { context.Nodes.Pop(); context.Nodes.Pop(); //parent.Region.End = element.Region.Start; //parent.Region.EndColumn = Math.Max (parent.Region.EndColumn - 1, 1); parent.Close(parent); context.Nodes.Push(element); parent = context.Nodes.Peek(1) as XElement; } } } XmlParserState ret = base.PushChar(c, context, ref rollback); if (ret == Parent && c == '>') { var element = context.Nodes.Peek() as XElement; if (element != null && !element.Name.HasPrefix && element.Name.IsValid) { if (element.Name.Name.Equals("script", StringComparison.OrdinalIgnoreCase)) { return(scriptState); } if (ElementTypes.IsEmpty(element.Name.Name)) { element.Close(element); context.Nodes.Pop(); } } } return(ret); }
/// <summary> /// Gets validation rules for property. /// </summary> /// <param name="context">Parser context.</param> /// <param name="property">Source property.</param> /// <returns>Validation rules for property.</returns> public static IPropertyValidationRules GetValidatorsCached(this IXmlParserContext context, IProperty property) { if (context.ValidatorsCache.TryGetValue(property, out IPropertyValidationRules result)) { return(result); } IValidationRule[] validationRules = context.ParserSettings.ValidationProvider.GetValidationRules(property).ToArray(); result = new PropertyValidationRules(property, validationRules); context.ValidatorsCache.TryAdd(property, result); return(result); }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { string key; switch (context.StateTag) { case UNKNOWN: context.KeywordBuilder.Append (c); key = context.KeywordBuilder.ToString (); if (!RazorSymbols.CanBeStatementOrDirective (key)) { context.Nodes.Push (new RazorImplicitExpression (context.LocationMinus (key.Length + 1))); rollback = String.Empty; return EnsureSetAndAdopted<RazorExpressionState> (ref expressionState); } if (key == "using") context.StateTag = USING; else if (RazorSymbols.IsDirective (key)) context.StateTag = POSSIBLE_DIRECTIVE; else if (RazorSymbols.IsStatement (key)) context.StateTag = POSSIBLE_STATEMENT; break; // Using can be either statement: @using (resource) {}, or directive: @using System.IO case USING: if (c == '(' || c == '\n') return SwitchToStatement (context, ref rollback); else if (Char.IsLetterOrDigit(c)) return SwitchToDirective (context, ref rollback); context.KeywordBuilder.Append (c); break; case POSSIBLE_STATEMENT: if (Char.IsWhiteSpace (c) || c == '{' || c == '(') return SwitchToStatement(context, ref rollback); context.KeywordBuilder.Append (c); context.StateTag = UNKNOWN; break; case POSSIBLE_DIRECTIVE: if (Char.IsWhiteSpace (c) || c == '{') return SwitchToDirective (context, ref rollback); context.KeywordBuilder.Append (c); context.StateTag = UNKNOWN; break; } return null; }
public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1) { context.Nodes.Push(new XComment(context.LocationMinus("<!--".Length + 1))); } if (c == '-') { //make sure we know when there are two '-' chars together if (context.StateTag == NOMATCH) { context.StateTag = SINGLE_DASH; } else { context.StateTag = DOUBLE_DASH; } } else if (context.StateTag == DOUBLE_DASH) { if (c == '>') { // if the '--' is followed by a '>', the state has ended // so attach a node to the DOM and end the state var comment = (XComment)context.Nodes.Pop(); if (context.BuildTree) { comment.End(context.Location); ((XContainer)context.Nodes.Peek()).AddChildNode(comment); } rollback = string.Empty; return(Parent); } else { context.LogWarning("The string '--' should not appear within comments."); context.StateTag = NOMATCH; } } else { // not any part of a '-->', so make sure matching is reset context.StateTag = NOMATCH; } return(null); }
XmlParserState SwitchToDirective(IXmlParserContext context, ref string rollback) { string key = context.KeywordBuilder.ToString(); string name = key.Trim(); var dir = new RazorDirective(context.LocationMinus(key.Length + 2)) { Name = name, IsSimpleDirective = RazorSymbols.IsSimpleDirective(name) }; context.Nodes.Push(dir); rollback = String.Empty; return(EnsureSetAndAdopted <RazorDirectiveState> (ref directiveState)); }
// ParseOpeningBracket and ParseClosingBracket can use simplified method of tracking brackets. // It's fast, and works correctly when parsing char by char, but sometimes may incorrectly determine // the end of a block in nested subblocks when we click inside the block from another one, // because the parent block isn't parsed from end to end then. // The simplified version is used mostly for testing. In real environment finding matching brackets // precisely is necessary for code completion. public virtual XmlParserState ParseOpeningBracket(char c, IXmlParserContext context) { var rootState = RootState as RazorRootState; if (!rootState.UseSimplifiedBracketTracker && !CorrespondingBlock.FirstBracket.HasValue) { CorrespondingBlock.FindFirstBracket(context.Location); } else if (rootState.UseSimplifiedBracketTracker) { bracketsBuilder.Append(c); } return(null); }
protected virtual void Close(XElement element, IXmlParserContext context, DocumentLocation location) { //have already checked that element is not null, i.e. top of stack is our element if (element.IsClosed) { context.Nodes.Pop(); } element.End(location); if (context.BuildTree) { var parent = (XContainer)context.Nodes.Peek(element.IsClosed ? 0 : 1); parent.AddChildNode(element); } }
public override XmlParserState ParseClosingBracket <T> (char c, IXmlParserContext context, XmlParserState stateToReturn) { if (base.ParseClosingBracket <T> (c, context, stateToReturn) != null) { if (RazorSymbols.CanBeContinued(CorrespondingBlock.Name)) { keys = RazorSymbols.PossibleKeywordsAfter(CorrespondingBlock.Name); context.StateTag = POSSIBLE_CONTINUATION; } else { return(stateToReturn); } } return(null); }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1) { bracketsBuilder.Clear (); var directive = context.Nodes.FirstOrDefault (n => n is RazorDirective); if (directive == null) { if (context.PreviousState is XmlClosingTagState && CorrespondingDirective != null) context.Nodes.Push (CorrespondingDirective); else { Debug.Fail ("Directive should be pushed before changing the state to DirectiveState"); return Parent; } } else CorrespondingBlock = directive as RazorDirective; } if (CorrespondingDirective.IsSimpleDirective) { if (c == '<') IsInsideGenerics = true; else if (c == '\n') { StateEngineService.EndCodeFragment<RazorDirective> (context); return Parent.Parent; } // using directives can be placed in one line, e.g. @using foo @using bar else if (CorrespondingDirective.Name == "using" && !(Char.IsLetterOrDigit (c) || c == ' ' || c == '=' || c == '.')) { rollback = String.Empty; StateEngineService.EndCodeFragment<RazorDirective> (context, 1); return Parent.Parent; } return null; } else { switch (c) { case '{': if (context.StateTag != TRANSITION) return ParseOpeningBracket (c, context); break; case '}': return ParseClosingBracket<RazorDirective> (c, context, Parent.Parent); } } return base.PushChar (c, context, ref rollback); }
private static void ValidateProperty( IXmlParserContext context, IMutablePropertyContainer container, IProperty property, XElement propertyElement) { var validationRules = context.GetValidatorsCached(property); if (validationRules.Rules.Count > 0) { IEnumerable <Message> messages = container.Validate(validationRules.Rules); foreach (Message message in messages) { context.Messages.Add(message.WithText(string.Concat(message.OriginalMessage, GetXmlLineInfo(propertyElement)))); } } }
public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback) { System.Diagnostics.Debug.Assert(((XAttribute)context.Nodes.Peek()).Value == null); if (c == '<') { //the parent state should report the error rollback = string.Empty; return(Parent); } if (context.CurrentStateLength == 1) { if (c == '"') { context.StateTag = DOUBLEQUOTE; return(null); } if (c == '\'') { context.StateTag = SINGLEQUOTE; return(null); } context.StateTag = UNQUOTED; } int maskedTag = context.StateTag & TagMask; if (maskedTag == UNQUOTED) { return(BuildUnquotedValue(c, context, ref rollback)); } if ((c == '"' && maskedTag == DOUBLEQUOTE) || c == '\'' && maskedTag == SINGLEQUOTE) { //ending the value var att = (XAttribute)context.Nodes.Peek(); att.Value = context.KeywordBuilder.ToString(); return(Parent); } context.KeywordBuilder.Append(c); return(null); }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1 && context.PreviousState is HtmlScriptBodyState) return Parent; //NOTE: This is (mostly) duplicated in HtmlClosingTagState //handle "paragraph" tags implicitly closed by block-level elements if (context.CurrentStateLength == 1 && context.PreviousState is XmlNameState) { var element = (XElement) context.Nodes.Peek (); if (!element.Name.HasPrefix && element.Name.IsValid) { //Note: the node stack will always be at least 1 deep due to the XDocument var parent = context.Nodes.Peek (1) as XElement; while (parent != null && parent.ValidAndNoPrefix () && parent.IsImplicitlyClosedBy (element)) { context.Nodes.Pop (); context.Nodes.Pop (); //parent.Region.End = element.Region.Start; //parent.Region.EndColumn = Math.Max (parent.Region.EndColumn - 1, 1); parent.Close (parent); context.Nodes.Push (element); parent = context.Nodes.Peek (1) as XElement; } } } XmlParserState ret = base.PushChar (c, context, ref rollback); if (ret == Parent && c == '>') { var element = context.Nodes.Peek () as XElement; if (element != null && !element.Name.HasPrefix && element.Name.IsValid) { if (element.Name.Name.Equals ("script", StringComparison.OrdinalIgnoreCase)) { return scriptState; } if (ElementTypes.IsEmpty (element.Name.Name)) { element.Close (element); context.Nodes.Pop (); } } } return ret; }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1) { context.Nodes.Push (new WebFormsServerComment (context.LocationMinus (context.CurrentStateLength + "<%--".Length))); } switch (context.StateTag) { case NOMATCH: if (c == '-') context.StateTag = SINGLE_DASH; break; case SINGLE_DASH: if (c == '-') context.StateTag = DOUBLE_DASH; else context.StateTag = NOMATCH; break; case DOUBLE_DASH: if (c == '%') context.StateTag = PERCENT; else context.StateTag = NOMATCH; break; case PERCENT: if (c == '>') { var comment = (WebFormsServerComment) context.Nodes.Pop (); comment.End (context.Location); if (context.BuildTree) { XObject ob = context.Nodes.Peek (); if (ob is XContainer) { ((XContainer)ob).AddChildNode (comment); } //FIXME: add to other kinds of node, e.g. if used within a tag } return Parent; } break; } return null; }
XmlParserState BuildUnquotedValue (char c, IXmlParserContext context, ref string rollback) { if (char.IsLetterOrDigit (c) || c == '_' || c == '.') { context.KeywordBuilder.Append (c); return null; } if (context.KeywordBuilder.Length == 0) { string fullName = ((XAttribute)context.Nodes.Peek ()).Name.FullName; context.LogError ("The value of attribute '" + fullName + "' ended unexpectedly."); rollback = string.Empty; return Parent; } var att = (XAttribute)context.Nodes.Peek (); att.Value = context.KeywordBuilder.ToString (); rollback = string.Empty; return Parent; }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { var namedObject = context.Nodes.Peek () as INamedXObject; if (namedObject == null || namedObject.Name.Prefix != null) throw new InvalidOperationException ("Invalid state"); Debug.Assert (context.CurrentStateLength > 1 || char.IsLetter (c) || c == '_', "First character pushed to a XmlTagNameState must be a letter."); Debug.Assert (context.CurrentStateLength > 1 || context.KeywordBuilder.Length == 0, "Keyword builder must be empty when state begins."); if (XmlChar.IsWhitespace (c) || c == '<' || c == '>' || c == '/' || c == '=') { rollback = string.Empty; if (context.KeywordBuilder.Length == 0) { context.LogError ("Zero-length name."); } else { string s = context.KeywordBuilder.ToString (); int i = s.IndexOf (':'); if (i < 0) { namedObject.Name = new XName (s); } else { namedObject.Name = new XName (s.Substring (0, i), s.Substring (i + 1)); } } return Parent; } if (c == ':') { if (context.KeywordBuilder.ToString ().IndexOf (':') > 0) context.LogError ("Unexpected ':' in name."); context.KeywordBuilder.Append (c); return null; } if (XmlChar.IsNameChar (c)) { context.KeywordBuilder.Append (c); return null; } rollback = string.Empty; context.LogError ("Unexpected character '" + c +"' in name"); return Parent; }
/// <summary> /// Copies input <paramref name="context"/> with possible changes. /// </summary> /// <param name="context">Source parser context.</param> /// <param name="parserSettings">Optional parser settings.</param> /// <param name="schema">Optional schema.</param> /// <param name="messages">Optional message list.</param> /// <param name="parsersCache">Optional parsers cache.</param> /// <param name="schemaCache">Optional schemas cache.</param> /// <param name="validatorsCache">Optional validators cache.</param> /// <returns>New <see cref="IXmlParserContext"/> instance.</returns> public static IXmlParserContext With( this IXmlParserContext context, IXmlParserSettings?parserSettings = null, Schema.IMutableObjectSchema?schema = null, IMutableMessageList <Message>?messages = null, ConcurrentDictionary <IProperty, IValueParser>?parsersCache = null, ConcurrentDictionary <IProperty, ISchema>?schemaCache = null, ConcurrentDictionary <IProperty, IPropertyValidationRules>?validatorsCache = null) { context.AssertArgumentNotNull(nameof(context)); return(new XmlParserContext( parserSettings: parserSettings ?? context.ParserSettings, schema: schema ?? context.Schema, messages: messages ?? context.Messages, parsersCache: parsersCache ?? context.ParsersCache, schemaCache: schemaCache ?? context.SchemaCache, validatorsCache: validatorsCache ?? context.ValidatorsCache)); }
static int LengthFromOpenBracket(IXmlParserContext context) { switch (context.StateTag) { case BRACKET: return(1); case BRACKET_EXCLAM: return(2); case COMMENT: return(3); case CDATA: case DOCTYPE: return(3 + context.KeywordBuilder.Length); default: return(1); } }
XmlParserState SwitchToContinuationStatement(IXmlParserContext context, string key) { string name = key.Trim(); int length = key.Length; if (name == "else if") { length = key.Length - 1; } else if (name == "else") { length = key.Length + 1; } var stm = new RazorStatement(context.LocationMinus(length)) { Name = name }; context.Nodes.Push(stm); return(EnsureSetAndAdopted <RazorStatementState> (ref statementState)); }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { System.Diagnostics.Debug.Assert (((XAttribute) context.Nodes.Peek ()).Value == null); if (c == '<') { //the parent state should report the error rollback = string.Empty; return Parent; } if (context.CurrentStateLength == 1) { if (c == '"') { context.StateTag = DOUBLEQUOTE; return null; } if (c == '\'') { context.StateTag = SINGLEQUOTE; return null; } context.StateTag = UNQUOTED; } int maskedTag = context.StateTag & TagMask; if (maskedTag == UNQUOTED) { return BuildUnquotedValue (c, context, ref rollback); } if ((c == '"' && maskedTag == DOUBLEQUOTE) || c == '\'' && maskedTag == SINGLEQUOTE) { //ending the value var att = (XAttribute) context.Nodes.Peek (); att.Value = context.KeywordBuilder.ToString (); return Parent; } context.KeywordBuilder.Append (c); return null; }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1) { bracketsBuilder.Clear (); var block = context.Nodes.FirstOrDefault (n => n is RazorCodeBlock); if (block == null) { var razorBlock = new RazorCodeBlock (context.LocationMinus (2)); context.Nodes.Push (razorBlock); CorrespondingBlock = razorBlock; } else CorrespondingBlock = block as RazorCodeFragment; } switch (c) { case '{': return ParseOpeningBracket (c, context); case '}': return ParseClosingBracket<RazorCodeBlock> (c, context, Parent); } return base.PushChar (c, context, ref rollback); }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1) { context.Nodes.Push (new XComment (context.LocationMinus ("<!--".Length + 1))); } if (c == '-') { //make sure we know when there are two '-' chars together if (context.StateTag == NOMATCH) context.StateTag = SINGLE_DASH; else context.StateTag = DOUBLE_DASH; } else if (context.StateTag == DOUBLE_DASH) { if (c == '>') { // if the '--' is followed by a '>', the state has ended // so attach a node to the DOM and end the state var comment = (XComment) context.Nodes.Pop (); if (context.BuildTree) { comment.End (context.Location); ((XContainer) context.Nodes.Peek ()).AddChildNode (comment); } rollback = string.Empty; return Parent; } else { context.LogWarning ("The string '--' should not appear within comments."); context.StateTag = NOMATCH; } } else { // not any part of a '-->', so make sure matching is reset context.StateTag = NOMATCH; } return null; }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { if (context.CurrentStateLength == 1) { context.Nodes.Push (new RazorComment (context.LocationMinus (2))); return null; } switch (context.StateTag) { case NOMATCH: if (c == '*') context.StateTag = STAR; break; case STAR: if (c == '@') { StateEngineService.EndCodeFragment<RazorComment> (context); return Parent; } else context.StateTag = NOMATCH; break; } return null; }
void SetTag (IXmlParserContext context, AttState value) { context.StateTag = (context.StateTag & ~TagMask) | ((int)value << XmlAttributeValueState.TagShift); }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { var maskedTag = (AttState) ((context.StateTag & TagMask) >> XmlAttributeValueState.TagShift); switch (maskedTag) { case AttState.Incoming: if (c == '<') { SetTag (context, AttState.Bracket); return null; } return base.PushChar (c, context, ref rollback); case AttState.Bracket: if (c == '%') { SetTag (context, AttState.Percent); return null; } rollback = "<"; return Parent; case AttState.Percent: if (c == '-') { SetTag (context, AttState.PercentDash); return null; } if (c == '@') { context.LogError (GettextCatalog.GetString ("Invalid directive location")); rollback = "<%"; return Parent; } WebFormsExpressionState.AddExpressionNode (c, context); SetTag (context, AttState.Expression); return null; case AttState.PercentDash: if (c == '-') { context.Nodes.Push (new WebFormsServerComment (context.LocationMinus (4))); SetTag (context, AttState.Comment); return null; } context.LogError (GettextCatalog.GetString ("Malformed server comment")); rollback = "<%-"; return Parent; case AttState.Expression: if (c == '%') SetTag (context, AttState.EndPercent); return null; case AttState.EndPercent: if (c == '>') { //TODO: attach nodes var n = context.Nodes.Pop (); n.End (context.Location); SetTag (context, AttState.Incoming); //ensure attribute get closed if value is unquoted var baseState = (context.StateTag & XmlAttributeValueState.TagMask); if (baseState == FREE || baseState == UNQUOTED) { var att = (XAttribute)context.Nodes.Peek (); att.Value = ""; return Parent; } return null; } SetTag (context, AttState.Expression); return null; case AttState.Comment: if (c == '-') SetTag (context, AttState.EndDash); return null; case AttState.EndDash: if (c == '-') SetTag (context, AttState.EndDashDash); else SetTag (context, AttState.Comment); return null; case AttState.EndDashDash: if (c == '%') SetTag (context, AttState.EndDashDashPercent); else if (c != '-') SetTag (context, AttState.Comment); return null; case AttState.EndDashDashPercent: if (c == '>') { //TODO: attach nodes var n = context.Nodes.Pop (); n.End (context.Location); SetTag (context, AttState.Incoming); return null; } SetTag (context, AttState.Comment); return null; default: return base.PushChar (c, context, ref rollback); } }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { var att = context.Nodes.Peek () as XAttribute; //state has just been entered if (context.CurrentStateLength == 1) { if (context.PreviousState is XmlNameState) { //error parsing name if (!att.IsNamed) { context.Nodes.Pop (); rollback = string.Empty; return Parent; } context.StateTag = GETTINGEQ; } else if (context.PreviousState is XmlAttributeValueState) { //Got value, so end attribute context.Nodes.Pop (); att.End (context.LocationMinus (1)); IAttributedXObject element = (IAttributedXObject) context.Nodes.Peek (); element.Attributes.AddAttribute (att); rollback = string.Empty; return Parent; } else { //starting a new attribute Debug.Assert (att == null); Debug.Assert (context.StateTag == NAMING); att = new XAttribute (context.LocationMinus (1)); context.Nodes.Push (att); rollback = string.Empty; return XmlNameState; } } if (context.StateTag == GETTINGEQ) { if (char.IsWhiteSpace (c)) { return null; } if (c == '=') { context.StateTag = GETTINGVAL; return null; } context.LogError ("Expecting = in attribute, got '" + c + "'."); } else if (context.StateTag == GETTINGVAL) { if (char.IsWhiteSpace (c)) { return null; } rollback = string.Empty; return AttributeValueState; } else if (c != '<') { //parent handles message for '<' context.LogError ("Unexpected character '" + c + "' in attribute."); } if (att != null) context.Nodes.Pop (); rollback = string.Empty; return Parent; }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { if (c == '<') { if (context.StateTag != FREE) context.LogError ("Incomplete tag opening; encountered unexpected '<'.", new DomRegion ( context.LocationMinus (LengthFromOpenBracket (context) + 1), context.LocationMinus (1))); context.StateTag = BRACKET; return null; } switch (context.StateTag) { case FREE: //FIXME: handle entities? return null; case BRACKET: if (c == '?') { rollback = string.Empty; return this.ProcessingInstructionState; } else if (c == '!') { context.StateTag = BRACKET_EXCLAM; return null; } else if (c == '/') { return this.ClosingTagState; } else if (char.IsLetter (c) || c == '_') { rollback = string.Empty; return TagState; } break; case BRACKET_EXCLAM: if (c == '[') { context.StateTag = CDATA; return null; } else if (c == '-') { context.StateTag = COMMENT; return null; } else if (c == 'D') { context.StateTag = DOCTYPE; return null; } break; case COMMENT: if (c == '-') return CommentState; break; case CDATA: string cdataStr = "CDATA["; if (c == cdataStr [context.KeywordBuilder.Length]) { context.KeywordBuilder.Append (c); if (context.KeywordBuilder.Length < cdataStr.Length) return null; return CDataState; } context.KeywordBuilder.Length = 0; break; case DOCTYPE: string docTypeStr = "OCTYPE"; if (c == docTypeStr [context.KeywordBuilder.Length]) { context.KeywordBuilder.Append (c); if (context.KeywordBuilder.Length < docTypeStr.Length) return null; return DocTypeState; } else { context.KeywordBuilder.Length = 0; } break; } context.LogError ("Incomplete tag opening; encountered unexpected character '" + c + "'.", new DomRegion ( context.LocationMinus (LengthFromOpenBracket (context)), context.Location)); context.StateTag = FREE; return null; }
static int LengthFromOpenBracket (IXmlParserContext context) { switch (context.StateTag) { case BRACKET: return 1; case BRACKET_EXCLAM: return 2; case COMMENT: return 3; case CDATA: case DOCTYPE: return 3 + context.KeywordBuilder.Length; default: return 1; } }
/// <summary> /// When the <see cref="Parser"/> advances by one character, it calls this method /// on the currently active <see cref="XmlParserState"/> to determine the next state. /// </summary> /// <param name="c">The current character.</param> /// <param name = "context">The parser context.</param> /// <param name="rollback"> If set non-null, the parser will be rolled back that number /// of characters (empty string means replay current char to the next state. /// Note that this will not change the DOM state.</param> /// <returns> /// The next state. A new or parent <see cref="XmlParserState"/> will change the parser state; /// the current state or null will not. /// </returns> public abstract XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback);
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { if (c == '%' && context.StateTag == BRACKET) { context.StateTag = BRACKET_PERCENT; return null; } else if (context.StateTag == BRACKET_PERCENT) { switch (c) { case '@': //DIRECTIVE <%@ return DirectiveState; case '-': // SERVER COMMENT: <%-- return ServerCommentState; case '=': //RENDER EXPRESSION <%= case '#': //DATABINDING EXPRESSION <%# case '$': //RESOURCE EXPRESSION <%$ default: // RENDER BLOCK rollback = ""; return ExpressionState; } } return base.PushChar (c, context, ref rollback); }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { XElement element = context.Nodes.Peek () as XElement; if (element == null || element.IsComplete) { element = new XElement (context.LocationMinus (2)); // 2 == < + current char context.Nodes.Push (element); } if (c == '<') { if (element.IsNamed) { context.LogError ("Unexpected '<' in tag '" + element.Name.FullName + "'."); Close (element, context, context.LocationMinus (1)); } else { context.LogError ("Unexpected '<' in unnamed tag."); } rollback = string.Empty; return Parent; } Debug.Assert (!element.IsComplete); if (element.IsClosed && c != '>') { if (char.IsWhiteSpace (c)) { context.LogWarning ("Unexpected whitespace after '/' in self-closing tag."); return null; } context.LogError ("Unexpected character '" + c + "' after '/' in self-closing tag."); context.Nodes.Pop (); return Parent; } //if tag closed if (c == '>') { if (context.StateTag == MAYBE_SELF_CLOSING) { element.Close (element); } if (!element.IsNamed) { context.LogError ("Tag closed prematurely."); } else { Close (element, context, context.Location); } return Parent; } if (c == '/') { context.StateTag = MAYBE_SELF_CLOSING; return null; } if (context.StateTag == ATTEMPT_RECOVERY) { if (XmlChar.IsWhitespace (c)) { context.StateTag = RECOVERY_FOUND_WHITESPACE; } return null; } if (context.StateTag == RECOVERY_FOUND_WHITESPACE) { if (!XmlChar.IsFirstNameChar (c)) return null; } context.StateTag = OK; if (!element.IsNamed && XmlChar.IsFirstNameChar (c)) { rollback = string.Empty; return NameState; } if (context.CurrentStateLength > 1 && XmlChar.IsFirstNameChar (c)) { rollback = string.Empty; return AttributeState; } if (XmlChar.IsWhitespace (c)) return null; context.LogError ("Unexpected character '" + c + "' in tag.", context.LocationMinus (1)); context.StateTag = ATTEMPT_RECOVERY; return null; }
protected virtual void Close (XElement element, IXmlParserContext context, TextLocation location) { //have already checked that element is not null, i.e. top of stack is our element if (element.IsClosed) context.Nodes.Pop (); element.End (location); if (context.BuildTree) { XContainer container = element.IsClosed? (XContainer) context.Nodes.Peek () : (XContainer) context.Nodes.Peek (1); container.AddChildNode (element); } }
public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback) { var doc = context.Nodes.Peek () as XDocType; if (doc == null) { doc = new XDocType (context.LocationMinus ("<!DOCTYPE".Length + 1)); context.Nodes.Push (doc); } if (!doc.RootElement.IsValid) { if (XmlChar.IsWhitespace (c)) return null; else if (XmlChar.IsFirstNameChar (c)) { rollback = ""; return nameState; } } else if (doc.PublicFpi == null) { if (context.StateTag == 0) { if (c == 's' || c == 'S') { context.StateTag = 1; return null; } else if (c == 'p' || c == 'P') { context.StateTag = -1; return null; } if (XmlChar.IsWhitespace (c)) { return null; } } else if (Math.Abs (context.StateTag) < 6) { if (context.StateTag > 0) { if ("YSTEM"[context.StateTag - 1] == c || "ystem"[context.StateTag - 1] == c) { context.StateTag++; if (context.StateTag == 6) { context.StateTag = 0; doc.PublicFpi = ""; } return null; } } else { int absState = Math.Abs (context.StateTag) - 1; if ("UBLIC"[absState] == c || "ublic"[absState] == c) { context.StateTag--; return null; } } } else { if (context.KeywordBuilder.Length == 0) { if (XmlChar.IsWhitespace (c)) return null; else if (c == '"') { context.KeywordBuilder.Append (c); return null; } } else { if (c == '"') { context.KeywordBuilder.Remove (0,1); doc.PublicFpi = context.KeywordBuilder.ToString (); context.KeywordBuilder.Length = 0; context.StateTag = 0; } else { context.KeywordBuilder.Append (c); } return null; } } } else if (doc.Uri == null) { if (context.KeywordBuilder.Length == 0) { if (XmlChar.IsWhitespace (c)) return null; else if (c == '"') { context.KeywordBuilder.Append (c); return null; } } else { if (c == '"') { context.KeywordBuilder.Remove (0,1); doc.Uri = context.KeywordBuilder.ToString (); context.KeywordBuilder.Length = 0; } else { context.KeywordBuilder.Append (c); } return null; } } else if (doc.InternalDeclarationRegion.EndLine <= 0) { if (XmlChar.IsWhitespace (c)) return null; switch (context.StateTag) { case 0: if (c == '[') { doc.InternalDeclarationRegion = new DocumentRegion (context.Location, DocumentLocation.Empty); context.StateTag = 1; return null; } break; case 1: if (c == '<') { context.StateTag = 2; return null; } else if (c == ']') { context.StateTag = 0; doc.InternalDeclarationRegion = new DocumentRegion (doc.InternalDeclarationRegion.Begin, context.Location); return null; } break; case 2: if (c == '>') { context.StateTag = 1; } return null; default: throw new InvalidOperationException (); } } doc = (XDocType)context.Nodes.Pop (); if (c == '<') { rollback = string.Empty; context.LogError ("Doctype ended prematurely."); } else if (c != '>') { context.LogError ("Unexpected character '" + c +"' in doctype."); } if (context.BuildTree) { doc.End (context.Location); ((XContainer) context.Nodes.Peek ()).AddChildNode (doc); } return Parent; }