Example #1
0
        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)
		{
			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;
		}
		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;
		}
        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 ct = context.Nodes.Peek() as XClosingTag;

            if (ct == null)
            {
                Debug.Assert(context.CurrentStateLength == 1,
                             "IncompleteNode must not be an XClosingTag when CurrentStateLength is 1");

                ct = new XClosingTag(context.LocationMinus(3));                   //3 = </ and the current char
                context.Nodes.Push(ct);
            }

            //if tag closed
            if (c == '>')
            {
                context.Nodes.Pop();

                if (ct.IsNamed)
                {
                    ct.End(context.Location);

                    // walk up tree of parents looking for matching tag
                    int  popCount = 0;
                    bool found    = false;
                    foreach (XObject node in context.Nodes)
                    {
                        popCount++;
                        XElement element = node as XElement;
                        if (element != null && element.Name == ct.Name)
                        {
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        popCount = 0;
                    }

                    //clear the stack of intermediate unclosed tags
                    while (popCount > 1)
                    {
                        XElement el = context.Nodes.Pop() as XElement;
                        if (el != null)
                        {
                            context.LogError(string.Format(
                                                 "Unclosed tag '{0}' at line {1}, column {2}.", el.Name.FullName, el.Region.BeginLine, el.Region.BeginColumn),
                                             ct.Region);
                        }
                        popCount--;
                    }

                    //close the start tag, if we found it
                    if (popCount > 0)
                    {
                        if (context.BuildTree)
                        {
                            ((XElement)context.Nodes.Pop()).Close(ct);
                        }
                        else
                        {
                            context.Nodes.Pop();
                        }
                    }
                    else
                    {
                        context.LogError(
                            "Closing tag '" + ct.Name.FullName + "' does not match any currently open tag.",
                            ct.Region
                            );
                    }
                }
                else
                {
                    context.LogError("Closing tag ended prematurely.");
                }
                return(Parent);
            }

            if (c == '<')
            {
                context.LogError("Unexpected '<' in tag.");
                rollback = string.Empty;
                return(Parent);
            }

            if (!ct.IsNamed && (char.IsLetter(c) || c == '_'))
            {
                rollback = string.Empty;
                return(NameState);
            }

            rollback = string.Empty;
            context.LogError("Unexpected character '" + c + "' in closing tag.");
            return(Parent);
        }
Example #6
0
        public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback)
        {
            XElement element = context.Nodes.Peek() as XElement;

            if (element == null || element.IsComplete)
            {
                var parent = element;
                element        = new XElement(context.LocationMinus(2));            // 2 == < + current char
                element.Parent = parent;
                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);
        }
Example #7
0
        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();
                    if (element.Attributes.Get(att.Name, false) != null)
                    {
                        context.LogError("'" + att.Name + "' is a duplicate attribute name.", att.Region);
                    }
                    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)
		{
			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;
		}
Example #9
0
        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));
            }
        }
Example #10
0
		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;
		}
		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 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);
        }
Example #13
0
        public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback)
        {
            if (c == '<')
            {
                if (context.StateTag != FREE)
                {
                    context.LogError(
                        "Incomplete tag opening; encountered unexpected '<'.",
                        TextSpan.FromBounds(
                            context.Position - LengthFromOpenBracket(context) - 1,
                            context.Position - 1
                            )
                        );
                }
                context.StateTag = BRACKET;
                return(null);
            }

            switch (context.StateTag)
            {
            case FREE:
                if (!char.IsWhiteSpace(c) && !char.IsControl(c))
                {
                    rollback = string.Empty;
                    return(TextState);
                }

                return(null);

            case BRACKET:
                switch (c)
                {
                case '?':
                    rollback = string.Empty;
                    return(ProcessingInstructionState);

                case '!':
                    context.StateTag = BRACKET_EXCLAM;
                    return(null);

                case '/':
                    return(ClosingTagState);
                }
                if (char.IsLetter(c) || c == '_' || char.IsWhiteSpace(c))
                {
                    rollback = string.Empty;
                    return(TagState);
                }
                break;

            case BRACKET_EXCLAM:
                switch (c)
                {
                case '[':
                    context.StateTag = CDATA;
                    return(null);

                case '-':
                    context.StateTag = COMMENT;
                    return(null);

                case '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 + "'.",
                             TextSpan.FromBounds(
                                 context.Position - LengthFromOpenBracket(context),
                                 context.Position));

            context.StateTag = FREE;
            return(null);
        }
Example #14
0
		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;
		}
        public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback)
        {
            var element = context.Nodes.Peek() as XElement;

            if (element == null || element.IsEnded)
            {
                var parent = element;
                element = new XElement(context.Position - 2)
                {
                    Parent = parent
                };                                                                                 // 2 == < + current char
                context.Nodes.Push(element);
                if (context.BuildTree)
                {
                    var parentContainer = (XContainer)context.Nodes.Peek(element.IsClosed ? 0 : 1);
                    parentContainer.AddChildNode(element);
                }
            }

            if (c == '<')
            {
                if (element.IsNamed)
                {
                    context.LogError("Unexpected '<' in tag '" + element.Name.FullName + "'.");
                    Close(element, context, context.Position - 1);
                }
                else
                {
                    context.LogError("Tag has no name.", element.Span.Start);
                }

                rollback = string.Empty;
                return(Parent);
            }

            Debug.Assert(!element.IsEnded);

            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 == '>')
            {
                element.HasEndBracket = true;
                if (context.StateTag == MAYBE_SELF_CLOSING)
                {
                    element.Close(element);
                }
                if (!element.IsNamed)
                {
                    context.LogError("Tag closed prematurely.");
                }
                else
                {
                    Close(element, context, context.Position);
                }
                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 = FREE;

            if (context.CurrentStateLength > 1 && XmlChar.IsFirstNameChar(c))
            {
                rollback = string.Empty;
                return(AttributeState);
            }

            if (!element.IsNamed && XmlChar.IsFirstNameChar(c))
            {
                rollback = string.Empty;
                return(NameState);
            }

            if (XmlChar.IsWhitespace(c))
            {
                return(null);
            }

            context.LogError("Unexpected character '" + c + "' in tag.", context.Position - 1);
            context.StateTag = ATTEMPT_RECOVERY;
            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;
		}
Example #17
0
        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 DomRegion(context.Location, TextLocation.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 DomRegion(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);
        }
Example #18
0
        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);
        }
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			var ct = context.Nodes.Peek () as XClosingTag;
			
			if (ct == null) {
				Debug.Assert (context.CurrentStateLength == 1,
					"IncompleteNode must not be an XClosingTag when CurrentStateLength is 1");
				
				ct = new XClosingTag (context.LocationMinus (3)); //3 = </ and the current char
				context.Nodes.Push (ct);
			}
			
			//if tag closed
			if (c == '>') {
				context.Nodes.Pop ();
				
				if (ct.IsNamed) {
					ct.End (context.Location);
					
					// walk up tree of parents looking for matching tag
					int popCount = 0;
					bool found = false;
					foreach (XObject node in context.Nodes) {
						popCount++;
						XElement element = node as XElement;
						if (element != null && element.Name == ct.Name) {
							found = true;
							break;
						}
					}
					if (!found)
						popCount = 0;
					
					//clear the stack of intermediate unclosed tags
					while (popCount > 1) {
						XElement el = context.Nodes.Pop () as XElement;
						if (el != null)
							context.LogError (string.Format (
								"Unclosed tag '{0}' at line {1}, column {2}.", el.Name.FullName, el.Region.BeginLine, el.Region.BeginColumn),
								ct.Region);
						popCount--;
					}
					
					//close the start tag, if we found it
					if (popCount > 0) {
						if (context.BuildTree)
							((XElement) context.Nodes.Pop ()).Close (ct);
						else
							context.Nodes.Pop ();
					} else {
						context.LogError (
							"Closing tag '" + ct.Name.FullName + "' does not match any currently open tag.",
							ct.Region
						);
					}
				} else {
					context.LogError ("Closing tag ended prematurely.");
				}
				return Parent;
			}
			
			if (c == '<') {
				context.LogError ("Unexpected '<' in tag.", context.LocationMinus (1));
				context.Nodes.Pop ();
				rollback = string.Empty;
				return Parent;
			}

			if (XmlChar.IsWhitespace (c)) {
				return null;
			}
			
			if (!ct.IsNamed && (char.IsLetter (c) || c == '_')) {
				rollback = string.Empty;
				return NameState;
			}
			
			rollback = string.Empty;
			context.LogError ("Unexpected character '" + c + "' in closing tag.", context.LocationMinus (1));
			context.Nodes.Pop ();
			return Parent;
		}
		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;
		}