5
// Michael Hutchinson <mhutchinson@novell.com>
7
// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
9
// Permission is hereby granted, free of charge, to any person obtaining
10
// a copy of this software and associated documentation files (the
11
// "Software"), to deal in the Software without restriction, including
12
// without limitation the rights to use, copy, modify, merge, publish,
13
// distribute, sublicense, and/or sell copies of the Software, and to
14
// permit persons to whom the Software is furnished to do so, subject to
15
// the following conditions:
17
// The above copyright notice and this permission notice shall be
18
// included in all copies or substantial portions of the Software.
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
using System.Diagnostics;
32
namespace MonoDevelop.Xml.StateEngine
36
public class XmlParser : Parser2
38
public XmlParser () : base (false) {}
39
public XmlParser (bool buildTree) : base (buildTree) {}
41
protected XState CurrentXState {
43
Debug.Assert (CurrentState < StateOffset && CurrentState > -1);
44
return (XState) CurrentState;
48
protected virtual int StateOffset {
49
get { return (int) XState.ProcessingInstructionClosing + 1; }
52
protected override int Dispatch (char c)
54
switch (CurrentXState) {
57
case '<': return (int)XState.OpeningBracket;
58
// case '&': return (int) XState.Entity;
59
default: return (int)XState.Free;
62
case XState.Malformed:
63
if (StateLength == 0) {
69
case '>': return (int)XState.Free;
70
case '<': return (int)XState.OpeningBracket;
71
default: return (int)XState.Malformed;
74
case XState.OpeningBracket:
75
if (StateLength == 0) {
77
case '!': return (int)XState.OpeningBracket;
79
Nodes.Push (new XProcessingInstruction (this.Position - 2));
80
return (int)XState.ProcessingInstruction;
83
Nodes.Push (new XClosingTag (this.Position - 2));
84
return (int)XState.ClosingTagName;
86
if (char.IsLetter (c) || c == '_') {
87
Nodes.Push (new XElement (this.Position - 2));
88
KeywordBuilder.Append (c);
89
return (int) XState.TagName;
93
} else if (StateLength == 1) {
96
return (int)XState.CommentOpening;
98
return (int)XState.CDataOpening;
101
LogError ("Malformed tag start.");
102
if (c == '>') return (int)XState.Free;
103
else if (c == '<') return (int)XState.OpeningBracket;
104
else return (int)XState.Malformed;
107
return (int)XState.TagName;
109
if (char.IsLetterOrDigit (c) || c == '_') {
110
KeywordBuilder.Append (c);
111
return (int)XState.TagName;
115
XElement el = Nodes.Peek () as INamedXObject;
116
if (namedObject.Name.Name != null || KeywordBuilder.Length == 0) {
117
LogError ("Unexpected ':' in name.");
118
return GetStateForCurrentObject ();
120
namedObject.Name = new XName (context.KeywordBuilder.ToString ());
121
context.KeywordBuilder.Length = 0;
125
else if (char.IsWhiteSpace (c)) return (int)XState.Tag;
126
else if (c == '>') return (int)XState.Free;
127
else if (c == '/') return (int)XState.SelfClosing;
131
if (char.IsWhiteSpace (c)) return (int)XState.Tag;
132
else if (char.IsLetter (c)) return PushCurrent (XState.AttributeName);
133
else if (c == '>') return (int)XState.Free;
134
else if (c == '/') return (int)XState.SelfClosing;
137
case XState.SelfClosing:
138
if (c == '>') return (int)XState.Free;
141
case XState.AttributeName:
142
if (char.IsWhiteSpace (c))
143
return (int)XState.AttributeNamed;
144
else if (char.IsLetterOrDigit (c) | c == ':')
145
return (int)XState.AttributeName;
147
return (int)XState.AttributeValue;
148
else return (int)XState.Malformed;
150
case XState.AttributeNamed:
151
if (c == '=') return (int)XState.AttributeValue;
152
else if (char.IsWhiteSpace (c)) return (int)XState.AttributeNamed;
153
else return (int)XState.Malformed;
155
case XState.AttributeValue:
156
if (c == '\'') return (int)XState.AttributeQuotes;
157
else if (c == '"') return (int)XState.AttributeDoubleQuotes;
158
else if (c == '<') break;
159
else if (char.IsWhiteSpace (c)) return (int)XState.AttributeValue;
160
else if (char.IsLetterOrDigit (c)) {
161
LogWarning ("Unquoted attribute value.");
162
return (int)XState.AttributeUnquoted;
164
LogWarning ("Incomplete attribute.");
168
case XState.AttributeQuotes:
170
case '\'': return PopState ();
171
case '<': return UnexpectedOpeningTag;
172
case '&': return PushCurrent (XState.Entity);
173
default: return (int)XState.AttributeQuotes;
176
case XState.AttributeDoubleQuotes:
178
case '"': return PopState ();
179
case '<': return UnexpectedOpeningTag;
180
case '&': return PushCurrent (XState.Entity);
181
default: return (int)XState.AttributeDoubleQuotes;
184
case XState.AttributeUnquoted:
186
case '<': return UnexpectedOpeningTag;
187
case '&': return PushCurrent (XState.Entity);
188
case '.': case '_': case ':': case ';': return CurrentState;
189
case '>': return (int)XState.Free;
191
if (char.IsLetterOrDigit (c)) return CurrentState;
192
else if (char.IsWhiteSpace (c)) return PopState ();
196
return (int)((c == ']')? XState.CDataClosing: XState.CData);
198
case XState.CDataOpening:
199
if (StateLength < "CDATA[".Length) {
200
if ("CDATA["[StateLength] == c) return (int)XState.CDataOpening;
203
Nodes.Push (new XCData (Position - "<![CDATA[".Length));
204
return (int)XState.CData;
207
case XState.CDataClosing:
208
if ("]>"[StateLength] == c) {
209
if (StateLength == 1) {
210
XCData n = (XCData) Nodes.Pop ();
212
((XContainer)Nodes.Peek ()).AddChildNode (n);
213
return (int) XState.Free;
215
return (int)XState.CDataClosing;
217
} else return (int)XState.CData;
220
if ((StateLength == 0 && c == '#') || char.IsLetterOrDigit (c))
221
return (int)XState.Entity;
222
else if (c == ';') return PopState ();
223
else LogWarning ("Malformed entity");
226
case XState.ProcessingInstruction:
229
case '?': return (int)XState.ProcessingInstructionClosing;
230
default: return (int)XState.ProcessingInstruction;
234
case XState.ProcessingInstructionClosing:
237
case '?': return (int)XState.ProcessingInstructionClosing;
239
XProcessingInstruction n = (XProcessingInstruction) Nodes.Pop ();
242
((XContainer)Nodes.Peek ()).AddChildNode (n);
243
return (int) XState.Free; }
244
default: return (int)XState.ProcessingInstruction;
248
case XState.CommentOpening:
250
Nodes.Push (new XComment (Position - "<!--".Length));
251
return (int)XState.Comment;
256
if (c == '-') return (int)XState.CommentClosing;
257
else return (int)XState.Comment;
259
case XState.CommentClosing:
260
if (StateLength == 0) {
261
if (c == '-') return (int)XState.CommentClosing;
262
else return (int)XState.Comment;
263
} else if (StateLength > 0) {
265
XComment n = (XComment) Nodes.Pop ();
268
((XContainer)Nodes.Peek ()).AddChildNode (n);
270
else LogWarning ("The string '--' should not appear in comments.");
271
if (c == '-') return (int)XState.CommentClosing;
272
else return (int)XState.Comment;
278
return UnexpectedOpeningTag;
279
return (int)XState.Malformed;
282
protected override object CreateNew ()
284
return new XmlParser ();
287
protected virtual int UnexpectedOpeningTag {
289
LogError ("Unexpected opening tag");
290
return (int)XState.OpeningBracket;
294
protected override XDocument CreateDocument ()
296
return new XDocument ();