3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*============================================================
10 ** <OWNER>[....]</OWNER>
13 ** PURPOSE: Parse "Elementary XML", that is, XML without
14 ** attributes or DTDs, in other words, XML with
18 ===========================================================*/
19 namespace System.Security.Util {
21 using System.Runtime.InteropServices;
23 using BinaryReader = System.IO.BinaryReader ;
24 using ArrayList = System.Collections.ArrayList;
25 using Stream = System.IO.Stream;
26 using StreamReader = System.IO.StreamReader;
27 using Encoding = System.Text.Encoding;
29 sealed internal class Parser
31 private SecurityDocument _doc;
34 internal SecurityElement GetTopElement()
36 return _doc.GetRootElement();
39 private const short c_flag = 0x4000;
40 private const short c_elementtag = (short)(SecurityDocument.c_element << 8 | c_flag);
41 private const short c_attributetag = (short)(SecurityDocument.c_attribute << 8 | c_flag);
42 private const short c_texttag = (short)(SecurityDocument.c_text << 8 | c_flag);
43 private const short c_additionaltexttag = (short)(SecurityDocument.c_text << 8 | c_flag | 0x2000);
44 private const short c_childrentag = (short)(SecurityDocument.c_children << 8 | c_flag);
45 private const short c_wastedstringtag = (short)(0x1000 | c_flag);
47 private void GetRequiredSizes( TokenizerStream stream, ref int index )
50 // Iteratively collect stuff up until the next end-tag.
51 // We've already seen the open-tag.
54 bool needToBreak = false;
55 bool needToPop = false;
56 bool createdNode = false;
59 SecurityElementType type = SecurityElementType.Regular;
60 String strValue = null;
61 bool sawEquals = false;
69 for (i = stream.GetNextToken() ; i != -1 ; i = stream.GetNextToken())
77 if (type == SecurityElementType.Comment)
79 // Ignore data in comments but still get the data
80 // to keep the stream in the right place.
81 stream.ThrowAwayNextString();
82 stream.TagLastToken( c_wastedstringtag );
86 // We're in a regular tag, so we've found an attribute/value pair.
90 // Found attribute name, save it for later.
92 strValue = stream.GetNextString();
96 // Found attribute text, add the pair to the current element.
99 throw new XmlSyntaxException( _t.LineNo );
101 stream.TagLastToken( c_attributetag );
102 index += SecurityDocument.EncodedStringSize( strValue ) +
103 SecurityDocument.EncodedStringSize( stream.GetNextString() ) +
112 // We're not in a tag, so we've found text between tags.
116 stream.TagLastToken( c_additionaltexttag );
117 index += SecurityDocument.EncodedStringSize( stream.GetNextString() ) +
118 SecurityDocument.EncodedStringSize( " " );
122 stream.TagLastToken( c_texttag );
123 index += SecurityDocument.EncodedStringSize( stream.GetNextString() ) +
134 i = stream.GetNextToken();
136 if (i == Tokenizer.slash)
138 stream.TagLastToken( c_childrentag );
141 // spin; don't care what's in here
142 i = stream.GetNextToken();
143 if (i == Tokenizer.cstr)
145 stream.ThrowAwayNextString();
146 stream.TagLastToken( c_wastedstringtag );
149 throw new XmlSyntaxException (_t.LineNo, Environment.GetResourceString( "XMLSyntax_UnexpectedEndOfFile" ));
154 if (i != Tokenizer.ket)
156 throw new XmlSyntaxException (_t.LineNo, Environment.GetResourceString( "XMLSyntax_ExpectedCloseBracket" ));
161 // Found the end of this element
169 else if (i == Tokenizer.cstr)
175 stream.TagLastToken( c_elementtag );
176 index += SecurityDocument.EncodedStringSize( stream.GetNextString() ) +
179 if (type != SecurityElementType.Regular)
180 throw new XmlSyntaxException( _t.LineNo );
185 else if (i == Tokenizer.bang)
187 // Found a child that is a comment node. Next up better be a cstr.
193 i = stream.GetNextToken();
206 stream.ThrowAwayNextString();
207 stream.TagLastToken( c_wastedstringtag );
213 } while (status > 0);
219 else if (i == Tokenizer.quest)
221 // Found a child that is a format node. Next up better be a cstr.
223 i = stream.GetNextToken();
225 if (i != Tokenizer.cstr)
226 throw new XmlSyntaxException( _t.LineNo );
230 type = SecurityElementType.Format;
232 stream.TagLastToken( c_elementtag );
233 index += SecurityDocument.EncodedStringSize( stream.GetNextString() ) +
243 throw new XmlSyntaxException (_t.LineNo, Environment.GetResourceString( "XMLSyntax_ExpectedSlashOrString" ));
247 case Tokenizer.equals:
259 throw new XmlSyntaxException (_t.LineNo, Environment.GetResourceString( "XMLSyntax_UnexpectedCloseBracket" ));
263 case Tokenizer.slash:
264 i = stream.GetNextToken();
266 if (i == Tokenizer.ket)
268 // Found the end of this element
269 stream.TagLastToken( c_childrentag );
278 throw new XmlSyntaxException (_t.LineNo, Environment.GetResourceString( "XMLSyntax_ExpectedCloseBracket" ));
282 case Tokenizer.quest:
283 if (intag && type == SecurityElementType.Format && status == 1)
285 i = stream.GetNextToken();
287 if (i == Tokenizer.ket)
289 stream.TagLastToken( c_childrentag );
298 throw new XmlSyntaxException (_t.LineNo, Environment.GetResourceString( "XMLSyntax_ExpectedCloseBracket" ));
303 throw new XmlSyntaxException (_t.LineNo);
309 throw new XmlSyntaxException (_t.LineNo) ;
330 else if (i == -1 && (stackDepth != 1 || !createdNode))
332 // This means that we still have items on the stack, but the end of our
333 // stream has been reached.
335 throw new XmlSyntaxException( _t.LineNo, Environment.GetResourceString( "XMLSyntax_UnexpectedEndOfFile" ));
338 while (stackDepth > 1);
341 private int DetermineFormat( TokenizerStream stream )
343 if (stream.GetNextToken() == Tokenizer.bra)
345 if (stream.GetNextToken() == Tokenizer.quest)
347 _t.GetTokens( stream, -1, true );
348 stream.GoToPosition( 2 );
350 bool sawEquals = false;
351 bool sawEncoding = false;
355 for (i = stream.GetNextToken(); i != -1 && i != Tokenizer.ket; i = stream.GetNextToken())
360 if (sawEquals && sawEncoding)
362 _t.ChangeFormat( System.Text.Encoding.GetEncoding( stream.GetNextString() ) );
367 if (String.Compare( stream.GetNextString(), "encoding", StringComparison.Ordinal) == 0)
374 stream.ThrowAwayNextString();
378 case Tokenizer.equals:
383 throw new XmlSyntaxException (_t.LineNo, Environment.GetResourceString( "XMLSyntax_UnexpectedEndOfFile" ));
395 private void ParseContents()
399 TokenizerStream stream = new TokenizerStream();
401 _t.GetTokens( stream, 2, false );
404 int gotoPosition = DetermineFormat( stream );
406 stream.GoToPosition( gotoPosition );
407 _t.GetTokens( stream, -1, false );
412 GetRequiredSizes( stream, ref neededIndex );
414 _doc = new SecurityDocument( neededIndex );
419 for (i = stream.GetNextFullToken(); i != -1; i = stream.GetNextFullToken())
421 if ((i & c_flag) != c_flag)
425 switch((short)(i & 0xFF00))
428 _doc.AddToken( SecurityDocument.c_element, ref position );
429 _doc.AddString( stream.GetNextString(), ref position );
433 _doc.AddToken( SecurityDocument.c_attribute, ref position );
434 _doc.AddString( stream.GetNextString(), ref position );
435 _doc.AddString( stream.GetNextString(), ref position );
439 _doc.AddToken( SecurityDocument.c_text, ref position );
440 _doc.AddString( stream.GetNextString(), ref position );
443 case c_additionaltexttag:
444 _doc.AppendString( " ", ref position );
445 _doc.AppendString( stream.GetNextString(), ref position );
449 _doc.AddToken( SecurityDocument.c_children, ref position );
452 case c_wastedstringtag:
453 stream.ThrowAwayNextString();
457 throw new XmlSyntaxException();
463 private Parser(Tokenizer t)
478 internal Parser (String input)
479 : this (new Tokenizer (input))
483 internal Parser (String input, String[] searchStrings, String[] replaceStrings)
484 : this (new Tokenizer (input, searchStrings, replaceStrings))
488 internal Parser( byte[] array, Tokenizer.ByteTokenEncoding encoding )
489 : this (new Tokenizer( array, encoding, 0 ) )
494 internal Parser( byte[] array, Tokenizer.ByteTokenEncoding encoding, int startIndex )
495 : this (new Tokenizer( array, encoding, startIndex ) )
499 internal Parser( StreamReader input )
500 : this (new Tokenizer( input ) )
504 internal Parser( char[] array )
505 : this (new Tokenizer( array ) )