The Labs \ Source Viewer \ SSCLI \ System.Security.Util \ Parser

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** CLASS:    Parser
  18. **
  19. **
  20. ** PURPOSE:  Parse "Elementary XML", that is, XML without
  21. **          attributes or DTDs, in other words, XML with
  22. **          elements only.
  23. **
  24. **
  25. ===========================================================*/
  26. namespace System.Security.Util
  27. {
  28.     using System.Text;
  29.     using System.Runtime.InteropServices;
  30.     using System;
  31.     using BinaryReader = System.IO.BinaryReader;
  32.     using ArrayList = System.Collections.ArrayList;
  33.     using Stream = System.IO.Stream;
  34.     using StreamReader = System.IO.StreamReader;
  35.     using Encoding = System.Text.Encoding;
  36.    
  37.     internal sealed class Parser
  38.     {
  39.         private SecurityDocument _doc;
  40.         private Tokenizer _t;
  41.        
  42.         internal SecurityElement GetTopElement()
  43.         {
  44.             if (!ParsedSuccessfully())
  45.                 throw new XmlSyntaxException(_t.LineNo);
  46.            
  47.             return _doc.GetRootElement();
  48.         }
  49.        
  50.         internal bool ParsedSuccessfully()
  51.         {
  52.             return true;
  53.         }
  54.        
  55.         private const short c_flag = 16384;
  56.         private const short c_elementtag = (short)(SecurityDocument.c_element << 8 | c_flag);
  57.         private const short c_attributetag = (short)(SecurityDocument.c_attribute << 8 | c_flag);
  58.         private const short c_texttag = (short)(SecurityDocument.c_text << 8 | c_flag);
  59.         private const short c_additionaltexttag = (short)(SecurityDocument.c_text << 8 | c_flag | 8192);
  60.         private const short c_childrentag = (short)(SecurityDocument.c_children << 8 | c_flag);
  61.         private const short c_wastedstringtag = (short)(4096 | c_flag);
  62.        
  63.         private void GetRequiredSizes(TokenizerStream stream, ref int index)
  64.         {
  65.             //
  66.             // Iteratively collect stuff up until the next end-tag.
  67.             // We've already seen the open-tag.
  68.             //
  69.            
  70.             bool needToBreak = false;
  71.             bool needToPop = false;
  72.             bool createdNode = false;
  73.             bool intag = false;
  74.             int stackDepth = 1;
  75.             SecurityElementType type = SecurityElementType.Regular;
  76.             string strValue = null;
  77.             bool sawEquals = false;
  78.             bool sawText = false;
  79.             int status = 0;
  80.            
  81.             short i;
  82.            
  83.             do {
  84.                 for (i = stream.GetNextToken(); i != -1; i = stream.GetNextToken()) {
  85.                     switch (i & 255) {
  86.                         case Tokenizer.cstr:
  87.                            
  88.                             {
  89.                                 if (intag) {
  90.                                     if (type == SecurityElementType.Comment) {
  91.                                         // Ignore data in comments but still get the data
  92.                                         // to keep the stream in the right place.
  93.                                         stream.ThrowAwayNextString();
  94.                                         stream.TagLastToken(c_wastedstringtag);
  95.                                     }
  96.                                     else {
  97.                                         // We're in a regular tag, so we've found an attribute/value pair.
  98.                                        
  99.                                         if (strValue == null) {
  100.                                             // Found attribute name, save it for later.
  101.                                            
  102.                                             strValue = stream.GetNextString();
  103.                                         }
  104.                                         else {
  105.                                             // Found attribute text, add the pair to the current element.
  106.                                            
  107.                                             if (!sawEquals)
  108.                                                 throw new XmlSyntaxException(_t.LineNo);
  109.                                            
  110.                                             stream.TagLastToken(c_attributetag);
  111.                                             index += SecurityDocument.EncodedStringSize(strValue) + SecurityDocument.EncodedStringSize(stream.GetNextString()) + 1;
  112.                                             strValue = null;
  113.                                             sawEquals = false;
  114.                                         }
  115.                                     }
  116.                                 }
  117.                                 else {
  118.                                     // We're not in a tag, so we've found text between tags.
  119.                                    
  120.                                     if (sawText) {
  121.                                         stream.TagLastToken(c_additionaltexttag);
  122.                                         index += SecurityDocument.EncodedStringSize(stream.GetNextString()) + SecurityDocument.EncodedStringSize(" ");
  123.                                     }
  124.                                     else {
  125.                                         stream.TagLastToken(c_texttag);
  126.                                         index += SecurityDocument.EncodedStringSize(stream.GetNextString()) + 1;
  127.                                         sawText = true;
  128.                                     }
  129.                                 }
  130.                             }
  131.                             break;
  132.                         case Tokenizer.bra:
  133.                            
  134.                             intag = true;
  135.                             sawText = false;
  136.                             i = stream.GetNextToken();
  137.                            
  138.                             if (i == Tokenizer.slash) {
  139.                                 stream.TagLastToken(c_childrentag);
  140.                                 while (true) {
  141.                                     // spin; don't care what's in here
  142.                                     i = stream.GetNextToken();
  143.                                     if (i == Tokenizer.cstr) {
  144.                                         stream.ThrowAwayNextString();
  145.                                         stream.TagLastToken(c_wastedstringtag);
  146.                                     }
  147.                                     else if (i == -1)
  148.                                         throw new XmlSyntaxException(_t.LineNo, Environment.GetResourceString("XMLSyntax_UnexpectedEndOfFile"));
  149.                                     else
  150.                                         break;
  151.                                 }
  152.                                
  153.                                 if (i != Tokenizer.ket) {
  154.                                     throw new XmlSyntaxException(_t.LineNo, Environment.GetResourceString("XMLSyntax_ExpectedCloseBracket"));
  155.                                 }
  156.                                
  157.                                 intag = false;
  158.                                
  159.                                 // Found the end of this element
  160.                                 index++;
  161.                                
  162.                                 sawText = false;
  163.                                 stackDepth--;
  164.                                
  165.                                 needToBreak = true;
  166.                             }
  167.                             else if (i == Tokenizer.cstr) {
  168.                                 // Found a child
  169.                                
  170.                                 createdNode = true;
  171.                                
  172.                                 stream.TagLastToken(c_elementtag);
  173.                                 index += SecurityDocument.EncodedStringSize(stream.GetNextString()) + 1;
  174.                                
  175.                                 if (type != SecurityElementType.Regular)
  176.                                     throw new XmlSyntaxException(_t.LineNo);
  177.                                
  178.                                 needToBreak = true;
  179.                                 stackDepth++;
  180.                             }
  181.                             else if (i == Tokenizer.bang) {
  182.                                 // Found a child that is a comment node. Next up better be a cstr.
  183.                                
  184.                                 status = 1;
  185.                                
  186.                                 do {
  187.                                     i = stream.GetNextToken();
  188.                                    
  189.                                     switch (i) {
  190.                                         case Tokenizer.bra:
  191.                                             status++;
  192.                                             break;
  193.                                         case Tokenizer.ket:
  194.                                            
  195.                                             status--;
  196.                                             break;
  197.                                         case Tokenizer.cstr:
  198.                                            
  199.                                             stream.ThrowAwayNextString();
  200.                                             stream.TagLastToken(c_wastedstringtag);
  201.                                             break;
  202.                                         default:
  203.                                            
  204.                                             break;
  205.                                     }
  206.                                 }
  207.                                 while (status > 0);
  208.                                
  209.                                 intag = false;
  210.                                 sawText = false;
  211.                                 needToBreak = true;
  212.                             }
  213.                             else if (i == Tokenizer.quest) {
  214.                                 // Found a child that is a format node. Next up better be a cstr.
  215.                                
  216.                                 i = stream.GetNextToken();
  217.                                
  218.                                 if (i != Tokenizer.cstr)
  219.                                     throw new XmlSyntaxException(_t.LineNo);
  220.                                
  221.                                 createdNode = true;
  222.                                
  223.                                 type = SecurityElementType.Format;
  224.                                
  225.                                 stream.TagLastToken(c_elementtag);
  226.                                 index += SecurityDocument.EncodedStringSize(stream.GetNextString()) + 1;
  227.                                
  228.                                 status = 1;
  229.                                 stackDepth++;
  230.                                
  231.                                 needToBreak = true;
  232.                             }
  233.                             else {
  234.                                 throw new XmlSyntaxException(_t.LineNo, Environment.GetResourceString("XMLSyntax_ExpectedSlashOrString"));
  235.                             }
  236.                             break;
  237.                         case Tokenizer.equals:
  238.                            
  239.                             sawEquals = true;
  240.                             break;
  241.                         case Tokenizer.ket:
  242.                            
  243.                             if (intag) {
  244.                                 intag = false;
  245.                                 continue;
  246.                             }
  247.                             else {
  248.                                 throw new XmlSyntaxException(_t.LineNo, Environment.GetResourceString("XMLSyntax_UnexpectedCloseBracket"));
  249.                             }
  250.                             break;
  251.                         case Tokenizer.slash:
  252.                             // not reachable
  253.                            
  254.                             i = stream.GetNextToken();
  255.                            
  256.                             if (i == Tokenizer.ket) {
  257.                                 // Found the end of this element
  258.                                 stream.TagLastToken(c_childrentag);
  259.                                 index++;
  260.                                 stackDepth--;
  261.                                 sawText = false;
  262.                                
  263.                                 needToBreak = true;
  264.                             }
  265.                             else {
  266.                                 throw new XmlSyntaxException(_t.LineNo, Environment.GetResourceString("XMLSyntax_ExpectedCloseBracket"));
  267.                             }
  268.                             break;
  269.                         case Tokenizer.quest:
  270.                            
  271.                             if (intag && type == SecurityElementType.Format && status == 1) {
  272.                                 i = stream.GetNextToken();
  273.                                
  274.                                 if (i == Tokenizer.ket) {
  275.                                     stream.TagLastToken(c_childrentag);
  276.                                     index++;
  277.                                     stackDepth--;
  278.                                     sawText = false;
  279.                                    
  280.                                     needToBreak = true;
  281.                                 }
  282.                                 else {
  283.                                     throw new XmlSyntaxException(_t.LineNo, Environment.GetResourceString("XMLSyntax_ExpectedCloseBracket"));
  284.                                 }
  285.                             }
  286.                             else {
  287.                                 throw new XmlSyntaxException(_t.LineNo);
  288.                             }
  289.                             break;
  290.                         case Tokenizer.dash:
  291.                         default:
  292.                            
  293.                             throw new XmlSyntaxException(_t.LineNo);
  294.                             break;
  295.                     }
  296.                    
  297.                     if (needToBreak) {
  298.                         needToBreak = false;
  299.                         needToPop = false;
  300.                         break;
  301.                     }
  302.                     else {
  303.                         needToPop = true;
  304.                     }
  305.                 }
  306.                
  307.                 if (needToPop) {
  308.                     index++;
  309.                     stackDepth--;
  310.                     sawText = false;
  311.                 }
  312.                 else if (i == -1 && (stackDepth != 1 || !createdNode)) {
  313.                     // This means that we still have items on the stack, but the end of our
  314.                     // stream has been reached.
  315.                    
  316.                     throw new XmlSyntaxException(_t.LineNo, Environment.GetResourceString("XMLSyntax_UnexpectedEndOfFile"));
  317.                 }
  318.             }
  319.             while (stackDepth > 1);
  320.         }
  321.        
  322.         private int DetermineFormat(TokenizerStream stream)
  323.         {
  324.             if (stream.GetNextToken() == Tokenizer.bra) {
  325.                 if (stream.GetNextToken() == Tokenizer.quest) {
  326.                     _t.GetTokens(stream, -1, true);
  327.                     stream.GoToPosition(2);
  328.                    
  329.                     bool sawEquals = false;
  330.                     bool sawEncoding = false;
  331.                    
  332.                     short i;
  333.                    
  334.                     for (i = stream.GetNextToken(); i != -1 && i != Tokenizer.ket; i = stream.GetNextToken()) {
  335.                         switch (i) {
  336.                             case Tokenizer.cstr:
  337.                                 if (sawEquals && sawEncoding) {
  338.                                     _t.ChangeFormat(System.Text.Encoding.GetEncoding(stream.GetNextString()));
  339.                                     return 0;
  340.                                 }
  341.                                 else if (!sawEquals) {
  342.                                     if (String.Compare(stream.GetNextString(), "encoding", StringComparison.Ordinal) == 0)
  343.                                         sawEncoding = true;
  344.                                 }
  345.                                 else {
  346.                                     sawEquals = false;
  347.                                     sawEncoding = false;
  348.                                     stream.ThrowAwayNextString();
  349.                                 }
  350.                                 break;
  351.                             case Tokenizer.equals:
  352.                                
  353.                                 sawEquals = true;
  354.                                 break;
  355.                             default:
  356.                                
  357.                                 throw new XmlSyntaxException(_t.LineNo, Environment.GetResourceString("XMLSyntax_UnexpectedEndOfFile"));
  358.                                 break;
  359.                         }
  360.                     }
  361.                    
  362.                     return 0;
  363.                 }
  364.             }
  365.            
  366.             return 2;
  367.         }
  368.        
  369.        
  370.         private void ParseContents()
  371.         {
  372.             short i;
  373.            
  374.             TokenizerStream stream = new TokenizerStream();
  375.            
  376.             _t.GetTokens(stream, 2, false);
  377.             stream.Reset();
  378.            
  379.             int gotoPosition = DetermineFormat(stream);
  380.            
  381.             stream.GoToPosition(gotoPosition);
  382.             _t.GetTokens(stream, -1, false);
  383.             stream.Reset();
  384.            
  385.             int neededIndex = 0;
  386.            
  387.             GetRequiredSizes(stream, ref neededIndex);
  388.            
  389.             _doc = new SecurityDocument(neededIndex);
  390.             int position = 0;
  391.            
  392.             stream.Reset();
  393.            
  394.             for (i = stream.GetNextFullToken(); i != -1; i = stream.GetNextFullToken()) {
  395.                 if ((i & c_flag) != c_flag)
  396.                     continue;
  397.                 else {
  398.                     switch ((short)(i & 65280)) {
  399.                         case c_elementtag:
  400.                             _doc.AddToken(SecurityDocument.c_element, ref position);
  401.                             _doc.AddString(stream.GetNextString(), ref position);
  402.                             break;
  403.                         case c_attributetag:
  404.                            
  405.                             _doc.AddToken(SecurityDocument.c_attribute, ref position);
  406.                             _doc.AddString(stream.GetNextString(), ref position);
  407.                             _doc.AddString(stream.GetNextString(), ref position);
  408.                             break;
  409.                         case c_texttag:
  410.                            
  411.                             _doc.AddToken(SecurityDocument.c_text, ref position);
  412.                             _doc.AddString(stream.GetNextString(), ref position);
  413.                             break;
  414.                         case c_additionaltexttag:
  415.                            
  416.                             _doc.AppendString(" ", ref position);
  417.                             _doc.AppendString(stream.GetNextString(), ref position);
  418.                             break;
  419.                         case c_childrentag:
  420.                            
  421.                             _doc.AddToken(SecurityDocument.c_children, ref position);
  422.                             break;
  423.                         case c_wastedstringtag:
  424.                            
  425.                             stream.ThrowAwayNextString();
  426.                             break;
  427.                         default:
  428.                            
  429.                             throw new XmlSyntaxException();
  430.                             break;
  431.                     }
  432.                 }
  433.             }
  434.         }
  435.        
  436.         private Parser(Tokenizer t)
  437.         {
  438.             _t = t;
  439.             _doc = null;
  440.            
  441.             try {
  442.                 ParseContents();
  443.             }
  444.             finally {
  445.                 _t.Recycle();
  446.             }
  447.         }
  448.        
  449.         internal Parser(string input) : this(new Tokenizer(input))
  450.         {
  451.         }
  452.        
  453.         internal Parser(string input, string[] searchStrings, string[] replaceStrings) : this(new Tokenizer(input, searchStrings, replaceStrings))
  454.         {
  455.         }
  456.        
  457.         internal Parser(byte[] array, Tokenizer.ByteTokenEncoding encoding) : this(new Tokenizer(array, encoding, 0))
  458.         {
  459.         }
  460.        
  461.        
  462.         internal Parser(byte[] array, Tokenizer.ByteTokenEncoding encoding, int startIndex) : this(new Tokenizer(array, encoding, startIndex))
  463.         {
  464.         }
  465.        
  466.         internal Parser(StreamReader input) : this(new Tokenizer(input))
  467.         {
  468.         }
  469.        
  470.         internal Parser(char[] array) : this(new Tokenizer(array))
  471.         {
  472.         }
  473.        
  474.     }
  475.    
  476. }

Developer Fusion