home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 39 / IOPROG_39.ISO / SOFT / sdkjava40.exe / data1.cab / fg_Samples / Samples / JDirect / CToJParser / Parser.java < prev   
Encoding:
Java Source  |  2000-05-04  |  192.6 KB  |  5,858 lines

  1. /** 
  2.  * Parser for Win32 API header files
  3.  *
  4.  * (C) Copyright 1995 - 1999 Microsoft Corporation.  All rights reserved.
  5.  *
  6.  * This tool was used to generate a significant portion of the Win32 API classes. 
  7.  * It is being included for you to use and modify to fit your specific needs. Remember 
  8.  * that C header files were not designed to be language-independent descriptions, and 
  9.  * that there is more than one correct way to represent some data types in Java. Thus,
  10.  * some functions will require hand-translation. For information on how to do this, 
  11.  * see the J/Direct documentation.
  12.  *
  13.  *
  14.  */
  15.  
  16. import java.io.*;
  17. import java.util.*;
  18.  
  19. import com.ms.util.Comparison;  // For Sorting.
  20.  
  21.  
  22. class UnrecognizedCodeException extends Throwable
  23. {
  24.     public String BadFragment;
  25.     public String Description;
  26.  
  27.     /**
  28.      * Used to signal unparsible code segments.
  29.      */
  30.     UnrecognizedCodeException()
  31.     {
  32.         super();
  33.         BadFragment = "Unspecified UnrecognizedCodeException - programmer messed up.";
  34.     }
  35.  
  36.     /**
  37.      * Used to signal unparsible code segments and give a rough idea what the
  38.      * problem was.
  39.      * @param bad_code The reason for failure and the code that couldn't be parsed.
  40.      */
  41.     UnrecognizedCodeException(String bad_code)
  42.     {
  43.         super();
  44.         BadFragment = new String(bad_code);
  45.     }
  46.  
  47.     /**
  48.      * Used to signal unparsible code segments and give a rough idea what the
  49.      * problem was.
  50.      * @param reason Reason why this code failed.
  51.      * @param bad_code The reason for failure and the code that couldn't be parsed.
  52.      */
  53.     UnrecognizedCodeException(String reason, String bad_code)
  54.     {
  55.         super();
  56.         BadFragment = bad_code;
  57.         Description = reason;
  58.     }
  59. }
  60.  
  61. class ExprSyntaxError extends UnrecognizedCodeException
  62. {
  63.     public ExprSyntaxError(String reason, String bad_code)
  64.     {
  65.         super(reason, bad_code);
  66.     }
  67.  
  68.     public String toString()
  69.     {
  70.         return "Expression syntax error: "+Description+"  bad code: "+BadFragment;
  71.     }
  72. }
  73.  
  74. class NumExprSyntaxError extends ExprSyntaxError
  75. {
  76.     public NumExprSyntaxError(String reason, String bad_code)
  77.     {
  78.         super(reason, bad_code);
  79.     }
  80.  
  81.     public NumExprSyntaxError(String reason, char bad_code)
  82.     {
  83.         super(reason, ""+bad_code);
  84.     }
  85.  
  86.     public String toString()
  87.     {
  88.         return "NumExpression syntax error: "+Description+"  bad code: "+BadFragment;
  89.     }
  90. }
  91.  
  92. /**
  93.  * Used only to move control around.
  94.  */
  95. class DoneException extends Throwable
  96. {
  97. }
  98.  
  99. /**
  100.  * Punt exceptions are used to give up on certain data types.
  101.  */
  102. class PuntException extends Throwable
  103. {
  104.     public String Reason;
  105.     public String Name;
  106.  
  107.     /**
  108.      * Build a PuntException with a reason and the name of the punted item.
  109.      * @param reason Why we punted
  110.      * @param name What we punted
  111.      */
  112.     public PuntException(String reason, String name)
  113.     {
  114.         Reason = reason;
  115.         Name = name;
  116.     }
  117. }
  118.  
  119. /**
  120.  * Used to signal a corrupt or missing input file.
  121.  */
  122. class BadInputFileException extends Throwable
  123. {
  124.     public String BadFile;
  125.  
  126.     BadInputFileException()
  127.     {
  128.         super();
  129.         BadFile = "<Unknown File>";
  130.     }
  131.  
  132.     BadInputFileException(String bad_file)
  133.     {
  134.         super();
  135.         BadFile = new String(bad_file);
  136.     }
  137. }
  138.  
  139.  
  140. /**
  141.  * Used to signal an error in the input to a function.  A number was out of range,
  142.  * a parameter was null, or a file didn't exist.
  143.  */
  144. class InvalidParameterException extends Throwable
  145. {
  146.     public String Description;
  147.  
  148.     InvalidParameterException()
  149.     {
  150.         Description = "<Unknown failure>";
  151.     }
  152.  
  153.     InvalidParameterException(String problem)
  154.     {
  155.         Description = problem;
  156.     }
  157. }
  158.  
  159. /**
  160.  * Used to signal a bad operation, such as an operator that doesn't have a corresponding
  161.  * Operator class.  An example might be the sizeof() operator, which I don't represent.
  162.  */
  163. class BadOperationException extends InvalidParameterException
  164. {
  165.     BadOperationException()
  166.     {
  167.         super("<Unknown bad operation>");
  168.     }
  169.  
  170.     BadOperationException(String problem)
  171.     {
  172.         super(problem);
  173.     }
  174. }
  175.  
  176.  
  177. /**
  178.  * Need an Operator class for precedence lookup.  Maintains data to identify how this
  179.  * operator is used.  Is it a prefix operator vs. postfix or infix?  Is it a unary
  180.  * or binary operator?  What is its precedence?
  181.  * @see Parser.html#SetupPrecedenceTable
  182.  */
  183. class Operator 
  184. {
  185.     protected String op;
  186.     protected boolean unary;
  187.     protected boolean prefix;
  188.     protected int precedence;
  189.  
  190.     /**
  191.      * Build an Operator object.
  192.      * @param newop String containing operator
  193.      * @param isUnaryOperator true if it's a unary operator (ie x++), false if it's a binary operator (ie x + y)
  194.      * @param isPrefixOperator true if operator precedes its operand (++x), false if it follows operand (x++)
  195.      * @param precedent int describing order of operations.  Higher numbers go first.
  196.      */
  197.     Operator(String newop, boolean isUnaryOperator, boolean isPrefixOperator, int precedent)
  198.     {
  199.         op = newop;
  200.         unary = isUnaryOperator;
  201.         prefix = isPrefixOperator;
  202.         precedence = precedent;
  203.     }
  204.  
  205.     /**
  206.      * Clean up fields.
  207.      */
  208.     public void finalizer()
  209.     {
  210.         op = null;
  211.     }
  212.  
  213.     /**
  214.      * Get operator.
  215.      * @return String containing operator
  216.      */
  217.     String getOp()
  218.     {
  219.         return op;
  220.     }
  221.  
  222.     /**
  223.      * Is this a unary operator?
  224.      * @return true if its unary (ie x++), false if its binary (ie x+y)
  225.      */
  226.     boolean isUnaryOperator()
  227.     {
  228.         return unary;
  229.     }
  230.  
  231.     /**
  232.      * Is this a prefix operator instead of an infix (in the case of binary operators) or
  233.      * postfix (in the case of unary operators) operator?
  234.      * @return true if its prefix (ie ++x), false if its infix or postfix (ie x+y and x++)
  235.      */
  236.     boolean isPrefixOperator()
  237.     {
  238.         return prefix;
  239.     }
  240.  
  241.     /**
  242.      * Get integer describing operator's precedence.  Higher numbers go first in order of
  243.      * operations.
  244.      * @return precedence
  245.      */
  246.     int getPrecedent()
  247.     {
  248.         return precedence;
  249.     }
  250.  
  251.     /**
  252.      * Convert to string for output.  It's the caller's responsibility to worry about
  253.      * context and multiple versions of an operator.
  254.      * @return Operator in C.
  255.      */
  256.     public String toString()
  257.     {
  258.         return op;
  259.     }
  260. }
  261.  
  262.  
  263. /**
  264.  * A real expression class, for handling expressions.
  265.  */
  266. class Expression {
  267.     public String name;
  268.     public String text;
  269.  
  270.     public Expression(String expr_name)
  271.     {
  272.         name = expr_name;
  273.     }
  274.  
  275.     public Expression(String expr_name, String expr_text)
  276.     {
  277.         name = expr_name;
  278.         text = expr_text;
  279.     }
  280.  
  281.     public void finalizer()
  282.     {
  283.         name = null;
  284.         text = null;
  285.     }
  286.  
  287.     public String toString()
  288.     {
  289.         return text;
  290.     }
  291. }
  292.  
  293.  
  294. abstract class NumExpression extends Expression {
  295.     int bits;    // number of bits in this number.
  296.     NumExpression a, b;
  297.     String op;
  298.     boolean prefix;
  299.     boolean unary;
  300.  
  301.     public NumExpression()
  302.     {
  303.         super("num expression");
  304.         bits = 32;
  305.     }
  306.  
  307.     public NumExpression(String expr_text)
  308.     {
  309.         super("num expression", expr_text);
  310.         bits = 32;
  311.     }
  312.  
  313.     /**
  314.      * Build an integer expression out of a prefix unary operator applied to an 
  315.      * integer expression.
  316.      * @param operation String containing operator
  317.      * @param expr NumExpression to apply operator to.
  318.      */
  319.     public NumExpression(String operation, NumExpression expr)
  320.     {
  321.         super("num expression", operation+expr.toString());
  322.         prefix = true;
  323.         unary = true;
  324.         op = operation;
  325.         a = expr;
  326.         b = null;
  327.         bits = expr.getLength();
  328.     }
  329.  
  330.     /**
  331.      * Build an integer expression out of a postfix unary operator applied to an 
  332.      * integer expression.
  333.      * @param operation String containing operator
  334.      * @param expr NumExpression to apply operator to.
  335.      */
  336.     public NumExpression(NumExpression expr, String operation)
  337.     {
  338.         super("num expression", expr.toString()+operation);
  339.         prefix = false;
  340.         unary = true;
  341.         op = operation;
  342.         a = expr;
  343.         b = null;
  344.         bits = expr.getLength();
  345.     }
  346.  
  347.     /**
  348.      * Evaluate a NumExpression and return its results as a 64-bit quantity.
  349.      * @return Value of the exception
  350.      * @exception BadOperationException if we couldn't parse an operator
  351.      */
  352.     abstract long eval() throws BadOperationException;
  353.  
  354.     /**
  355.      * Used to get the length of an integer expression representation in bits.
  356.      * @return Number of bits.
  357.      */
  358.     public int getLength()
  359.     {
  360.         return bits;
  361.     }
  362.  
  363.     /**
  364.      * Return a string representation of this NumExpression.  Should add parentheses as
  365.      * needed for order of operations.
  366.      * @return String containing NumExpression.
  367.      */
  368.     abstract public String toString();
  369. }
  370.  
  371. class IntExpression extends NumExpression {
  372.     long intval;
  373.     boolean evaluated;
  374.     boolean complex;
  375.  
  376.     /**
  377.      * Build an integer expression out of two other integer expressions and an
  378.      * operation to be applied to them.  Mathematically, this wraps:<p>
  379.      * (Integer_Expression Op Integer_Expression)<p>
  380.      * Example: IntExpression(5, "+", 4)  =>  (5+4)<p>
  381.      * We try to preserve the bitdepth in the first expression, just as C would.
  382.      * @param first First integer expression
  383.      * @param operation String containing operator
  384.      * @param second Second integer expression
  385.      */
  386.     public IntExpression(NumExpression first, String operation, NumExpression second)
  387.     {
  388.         a = first;
  389.         op = operation;
  390.         b = second;
  391.         bits = first.getLength();
  392.         complex = true;
  393.         evaluated = false;
  394.         unary = false;
  395.     }
  396.  
  397.     /**
  398.      * Build an integer expression out of a prefix unary operator applied to an 
  399.      * integer expression.
  400.      * @param operation String containing operator
  401.      * @param expr IntExpression to apply operator to.
  402.      */
  403.     public IntExpression(String operation, NumExpression expr)
  404.     {
  405.         super(operation, expr);
  406.     }
  407.  
  408.     /**
  409.      * Build an integer expression out of a postfix unary operator applied to an 
  410.      * integer expression.
  411.      * @param operation String containing operator
  412.      * @param expr IntExpression to apply operator to.
  413.      */
  414.     public IntExpression(NumExpression expr, String operation)
  415.     {
  416.         super(expr, operation);
  417.     }
  418.  
  419.     /**
  420.      * Build an integer expression out of a short int number.
  421.      * @param value short int to represent
  422.      */
  423.     public IntExpression(short value)
  424.     {
  425.         intval = value;
  426.         bits = 16;
  427.         complex = false;
  428.         a = null;
  429.         b = null;
  430.         op = null;
  431.         evaluated = true;
  432.         unary = false;
  433.     }
  434.     
  435.     /**
  436.      * Build an integer expression out of an integer.
  437.      * @param value int to represent
  438.      */
  439.     public IntExpression(int value)
  440.     {
  441.         intval = value;
  442.         bits = 32;
  443.         complex = false;
  444.         a = null;
  445.         b = null;
  446.         op = null;
  447.         evaluated = true;
  448.         unary = false;
  449.     }
  450.  
  451.     /**
  452.      * Build an integer expression out of a long integer.
  453.      * @param value long int to represent
  454.      */
  455.     public IntExpression(long value)
  456.     {
  457.         intval = value;
  458.         bits = 64;
  459.         complex = false;
  460.         a = null;
  461.         b = null;
  462.         op = null;
  463.         evaluated = true;
  464.         unary = false;
  465.     }
  466.  
  467.     /**
  468.      * Evaluates an IntExpression.  If this was assigned an integer 
  469.      * value, return that integer.  If it was an operation performed
  470.      * on one or two IntExpressions, evaluate those then perform the
  471.      * operation.  Store result for lazy evaluation.
  472.      * @return int containing value of expression after evaluation
  473.      * @exception BadOperationException thrown if eval doesn't understand the operation.
  474.      */
  475.     public long eval() throws BadOperationException
  476.     {
  477.         if(evaluated)
  478.             return intval;
  479.  
  480.         if(unary) {
  481.             if(a==null) {
  482.                 System.out.println("Ack!  In IntExpression::eval of a unary operator, a was null!");
  483.                 System.exit(1);
  484.             }
  485.             long val = (long) a.eval();
  486.             if(op.equals("-"))
  487.                 intval = -val;
  488.             else if(op.equals("~"))
  489.                 intval = ~val;
  490.             else if(op.equals("++"))
  491.                 intval = val + 1;
  492.             else if(op.equals("--"))
  493.                 intval = val - 1;
  494.             else if(op.equals("+"))
  495.                 intval = val;
  496.             else if(op.equals("!"))
  497.                 intval = (val==0 ? 1 : 0);
  498.             else
  499.                 throw new BadOperationException("Unknown unary operation \""+op+"\" in NumExpression::eval()!");
  500.         }
  501.         else if(a != null) {
  502.             long aval = a.eval();
  503.             if(b==null) {
  504.                 System.out.println("Ack!  In IntExpression::eval of a binary operator, b was null!");
  505.                 System.exit(1);
  506.             }
  507.             long bval = b.eval();
  508.             if(op.equals("+"))      // Arrange by perceived frequency
  509.                 intval = aval + bval;
  510.             else if(op.equals("<<"))
  511.                 intval = aval << bval;
  512.             else if(op.equals("|"))
  513.                 intval = aval | bval;
  514.             else if(op.equals("&"))
  515.                 intval = aval & bval;
  516.             else if(op.equals(">>"))
  517.                 intval = aval >> bval;
  518.             else if(op.equals("-"))
  519.                 intval = aval - bval;
  520.             else if(op.equals("*"))
  521.                 intval = aval * bval;
  522.             else if(op.equals("/"))
  523.                 intval = aval / bval;
  524.             else if(op.equals("%"))
  525.                 intval = aval % bval;
  526.             else if(op.equals("<"))
  527.                 intval = (aval < bval ? 1 : 0);
  528.             else if(op.equals(">"))
  529.                 intval = (aval > bval ? 1 : 0);
  530.             else if(op.equals("<="))
  531.                 intval = (aval <= bval ? 1 : 0);
  532.             else if(op.equals(">="))
  533.                 intval = (aval >= bval ? 1 : 0);
  534.             else if(op.equals("=="))
  535.                 intval = (aval == bval ? 1 : 0);
  536.             else if(op.equals("!="))
  537.                 intval = (aval != bval ? 1 : 0);
  538.             else if(op.equals("^"))
  539.                 intval = aval ^ bval;
  540.             else
  541.                 throw new BadOperationException("Unknown binary operation \""+op+"\" in NumExpression::eval()!");
  542.         }
  543.  
  544.         // Apply appropriate bitmask to ensure range.
  545.         long bitmask = 0xFFFFFFFFFFFFFFFFL;
  546.         intval = intval & (bitmask >> (64-bits));
  547.  
  548.         evaluated = true;
  549.         return intval;
  550.     }
  551.  
  552.     /**
  553.      * Return a string representation of this IntExpression.  Should add parentheses as
  554.      * needed for order of operations.
  555.      * @return String containing IntExpression.
  556.      */
  557.     public String toString()
  558.     {
  559.         if(prefix)
  560.             return op+intval;
  561.         if(unary)
  562.             return "("+a.toString()+op+")";
  563.         if(!complex)
  564.             return ""+intval;
  565.         else
  566.             return " ( "+a.toString()+op+b.toString()+" ) ";
  567.     }
  568. }
  569.  
  570.  
  571. /**
  572.  * Need an object to store packsize (alignment) info in.
  573.  */
  574. class PackContainer
  575. {
  576.     protected Integer packsize;
  577.     protected String label;
  578.  
  579.     /**
  580.      * Make a PackContainer knowing only the size.
  581.      * @param ps Alignment in bytes.  Can be 1, 2, 4, or 8.
  582.      * @exception InvalidParameterException if ps isn't a valid alignment
  583.      */
  584.     PackContainer(int ps) throws InvalidParameterException
  585.     {
  586.         if(ps != 1 && ps != 2 && ps != 4 && ps != 8)
  587.             throw new InvalidParameterException("Ack!  PackContainer refuses to take alignment values other than 1, 2, 4, and 8!  ps: "+ps);
  588.         packsize = new Integer(ps);
  589.         label = null;
  590.     }
  591.  
  592.     /**
  593.      * Make a PackContainer knowing the size and a unique label.  For lines like this: 
  594.      * <code>#pragma pack(push, wininet, 4)</code>
  595.      * @param ps Alignment in bytes.  Can be 1, 2, 4, or 8.
  596.      * @param Label Text associated with this pack size.
  597.      * @exception InvalidParameterException if ps isn't a valid alignment
  598.      */
  599.     PackContainer(int ps, String Label) throws InvalidParameterException
  600.     {
  601.         if(ps != 1 && ps != 2 && ps != 4 && ps != 8)
  602.             throw new InvalidParameterException("Ack!  PackContainer refuses to take alignment values other than 1, 2, 4, and 8!  ps: "+ps+"  label: "+Label);
  603.         packsize = new Integer(ps);
  604.         label = Label;
  605.     }
  606.  
  607.     /**
  608.      * Return pack size.
  609.      * @return int containing pack size.
  610.      */
  611.     int getPackSize()
  612.     {
  613.         return packsize.intValue();
  614.     }
  615.  
  616.     /**
  617.      * Return label for this pack size.
  618.      * @return label
  619.      */
  620.     String getLabel()
  621.     {
  622.         return label;
  623.     }
  624.  
  625.     /**
  626.      * Return whether this container has a label
  627.      * @return true if a label is present, else false;
  628.      */
  629.     boolean hasLabel()
  630.     {
  631.         return label==null;
  632.     }
  633. }
  634.  
  635.  
  636. /** 
  637.  * Variable is a class to store the name and type of an argument to 
  638.  * a function, as well as any modifiers that might apply.  This is strictly for storage.
  639.  * I added support for some interesting keywords, but not support in the
  640.  * output for all of them.
  641.  * The idea is maybe users can add special rules for any special types they have
  642.  * in toJavaString().
  643.  */
  644. class Variable
  645. {
  646.     public String Type;
  647.     public String Name;
  648.    protected Function ptrFunc;
  649.     protected multiFieldDataStructure ptrData;
  650.     protected Array ptrArray;
  651.     protected static Hashtable TypeLUT;
  652.     protected static Hashtable StructureLUT;
  653.     protected static Hashtable StringTypes;
  654.     protected NumExpression InitialValue;
  655.     protected boolean is_var_arg;
  656.  
  657.     protected boolean is_Const;
  658.     protected boolean is_Volatile;
  659.     protected boolean is_Pointer;
  660.     protected boolean is_Handle;
  661.     protected boolean is_Reference;
  662.  
  663.     /**
  664.      * Construct a variable with a certain type and name.  Use for something like:
  665.      * <code>int x;</code>
  666.      * @param Type String containing the C type
  667.      * @param Name Name of this variable, if known.
  668.      */
  669.     public Variable(String Type, String Name)
  670.     {
  671.         this.Type = Type;
  672.         this.Name = Name;
  673.         ptrFunc = null;
  674.         ptrData = null;
  675.         ptrArray = null;
  676.         InitialValue = null;
  677.         is_var_arg = false;
  678.         if(Type == null) {
  679.             System.out.println("Ack! Variable(Type,Name) doesn't want a null type!");
  680.         }
  681.         if(Type.startsWith("va_list") || Type.startsWith("Old-style vararg list")) {
  682.             System.out.println("Found vararg type.");
  683.             is_var_arg = true;
  684.         }
  685.         is_Const = false;
  686.         is_Volatile = false;
  687.         is_Pointer = false;
  688.         is_Handle = false;
  689.         is_Reference = false;
  690.     }
  691.  
  692.     /**
  693.      * Make a Variable that wraps a pointer to a function.  Useful for members of a struct
  694.      * and function arguments.
  695.      * @param pfunc Function object.
  696.      */
  697.     public Variable(Function pfunc)
  698.     {
  699.         StringBuffer type = new StringBuffer(pfunc.getReturnType() + " (" + pfunc.getName() + ") (");
  700.         type.append(pfunc.argsToString());
  701.         type.append(")");
  702.         this.Type = type.toString();
  703.         this.Name = "ptrToFunc";
  704.         type = null;
  705.         ptrFunc = pfunc;
  706.         ptrData = null;
  707.         ptrArray = null;
  708.         InitialValue = null;
  709.         is_var_arg = false;
  710.         is_Const = false;
  711.         is_Volatile = false;
  712.         is_Pointer = true;        // A safe assumption here.
  713.         is_Handle = false;
  714.         is_Reference = false;
  715.     }
  716.  
  717.     /**
  718.      * Make a Variable storing a multiFieldDataStructure.  Use this to represent structs
  719.      * and unions as members of structs or unions.
  720.      * @param s multiFieldDataStructure to use as source.
  721.      * @param name Name of the field or variable
  722.      */
  723.     public Variable(multiFieldDataStructure s, String name)
  724.     {
  725.         Type = s.toString();
  726.         Name = name;
  727.         ptrFunc = null;
  728.         ptrData = s;
  729.         ptrArray = null;
  730.         InitialValue = null;
  731.         is_var_arg = false;
  732.         is_Const = false;
  733.         is_Volatile = false;
  734.         is_Pointer = false;   // Could be a by-ref struct passed in...
  735.         is_Handle = false;
  736.         is_Reference = false;
  737.     }
  738.  
  739.     /**
  740.      * Make a Variable storing an Array.  Use this to represent arrays as 
  741.      * members of structs or unions.
  742.      * @param a Array to use as source.
  743.      */
  744.     public Variable(Array a)
  745.     {
  746.         Type = a.toString();
  747.         this.Name = a.getName();
  748.         ptrFunc = null;
  749.         ptrData = null;
  750.         ptrArray = a;
  751.         InitialValue = null;
  752.         is_var_arg = false;
  753.         is_Const = false;
  754.         is_Volatile = false;
  755.         is_Pointer = true;    // Guess?
  756.         is_Handle = false;
  757.         is_Reference = false;
  758.     }
  759.  
  760.     /**
  761.      * Clean up fields.
  762.      * @return No return value.
  763.      */
  764.     public void finalizer()
  765.     {
  766.         Name = null;
  767.         Type = null;
  768.         ptrFunc = null;
  769.         ptrData = null;
  770.         ptrArray = null;
  771.         InitialValue = null;
  772.     }
  773.  
  774.     /**
  775.      * Is this Variable a wrapper for a Function?
  776.      * @return true if this wraps a Function; else false.
  777.      */
  778.     public boolean isFunction()
  779.     {
  780.         return ptrFunc != null;
  781.     }
  782.  
  783.     /**
  784.      * Is this Variable a wrapper for a multiFieldDataStructure?
  785.      * @return true if this wraps a multiFieldDataStructure; else false.
  786.      */
  787.     public boolean ismultiFieldDataStructure()
  788.     {
  789.         return ptrData != null;
  790.     }
  791.  
  792.     /**
  793.      * Is this Variable a wrapper for an Array?
  794.      * @return true if this wraps an Array; else false.
  795.      */
  796.     public boolean isArray()
  797.     {
  798.         return ptrArray != null;
  799.     }
  800.  
  801.     /**
  802.      * Is this Variable a wrapper for an Array?
  803.      * @return true if this wraps an Array; else false.
  804.      */
  805.     public boolean isCharArray() throws InvalidParameterException
  806.     {
  807.         if(ptrArray != null) {
  808.             if(!ptrArray.isString())
  809.                 return false;
  810.             CharArray a = (CharArray) ptrArray;
  811.             if(a==null)
  812.                 return false;
  813.             else
  814.                 return true;
  815.         }
  816.         else
  817.             return false;
  818.     }
  819.  
  820.     /**
  821.      * Is this Variable a variable arguments list?  Should support both the "..." syntax
  822.      * as well as the va_list.
  823.      * @return true if this is a vararg parameter; else false
  824.      */
  825.     public boolean isVarArg()
  826.     {
  827.         return is_var_arg;
  828.     }
  829.  
  830.     /**
  831.      * Is this a const parameter or field?
  832.      * @return true if this variable is constant; else false.
  833.      */
  834.     public boolean isConst()
  835.     {
  836.         return is_Const;
  837.     }
  838.  
  839.     /**
  840.      * Is this a volatile variable or field?
  841.      * @return true if this Variable is volatile; else false.
  842.      */
  843.     public boolean isVolatile()
  844.     {
  845.         return is_Volatile;
  846.     }
  847.  
  848.     /**
  849.      * Is this a pointer parameter or field?
  850.      * @return true if this variable is a pointer; else false.
  851.      */
  852.     public boolean isPointer()
  853.     {
  854.         return is_Pointer;
  855.     }
  856.  
  857.     /**
  858.      * Is this a handle parameter or field?
  859.      * @return true if this variable is a handle; else false.
  860.      */
  861.     public boolean isHandle()
  862.     {
  863.         return is_Handle;
  864.     }
  865.  
  866.     /**
  867.      * Is this parameter passed by reference?  Or is this structure embedded into another structure?
  868.      * <p>Examples:  Both <code>void func(int & x_byref);</code> and <code>struct { POINT pt; };</code> 
  869.      * should have this flag set to true.
  870.      * @return true if this variable is passed by reference or if this structure is embedded in another; else false.
  871.      */
  872.     public boolean isReference()
  873.     {
  874.         return is_Reference;
  875.     }
  876.  
  877.     /**
  878.      * Set const flag to a value.
  879.      * @param v What to set the const flag to.
  880.      * @return No return value.
  881.      * @exception InvalidParameterException if variable is set as both const and volatile
  882.      */
  883.     public void setConst(boolean v) throws InvalidParameterException
  884.     {
  885.         if(is_Volatile && v)
  886.             throw new InvalidParameterException("Variables can't be both const and volatile!");
  887.         is_Const = v;
  888.     }
  889.  
  890.     /**
  891.      * Set volatile flag to a value.
  892.      * @param v What to set the volatile flag to.
  893.      * @return No return value.
  894.      * @exception InvalidParameterException if variable is set as both const and volatile
  895.      */
  896.     public void setVolatile(boolean v) throws InvalidParameterException
  897.     {
  898.         if(is_Const && v)
  899.             throw new InvalidParameterException("Variables can't be both const and volatile!");
  900.         is_Volatile = v;
  901.     }
  902.  
  903.     /**
  904.      * Set pointer flag to a value.
  905.      * @param v What to set the pointer flag to.
  906.      * @return No return value.
  907.      */
  908.     public void setPointer(boolean v)
  909.     {
  910.         is_Pointer = v;
  911.     }
  912.  
  913.     /**
  914.      * Set handle flag to a value.
  915.      * @param v What to set the handle flag to.
  916.      * @return No return value.
  917.      */
  918.     public void setHandle(boolean v)
  919.     {
  920.         is_Handle = v;
  921.     }
  922.     
  923.     /**
  924.      * Set reference flag to a value.
  925.      * @param v What to set the reference flag to.
  926.      * @return No return value.
  927.      */
  928.     public void setReference(boolean v)
  929.     {
  930.         is_Reference = v;
  931.     }
  932.  
  933.     /**
  934.      * Set the Initial value of this variable.  Useful for default arguments or member 
  935.      * initialization within a struct or class.
  936.      * @param expr NumExpression to set initial value to.
  937.      * @return No return value.
  938.      */
  939.     public void setInitialValue(NumExpression expr)
  940.     {
  941.         InitialValue = expr;
  942.     }
  943.  
  944.     /**
  945.      * Get the Function this Variable wraps.
  946.      * @return This Variable's Function.
  947.      * @exception InvalidParameterException if it wasn't a function wrapper.
  948.      */
  949.     public Function getFunction() throws InvalidParameterException
  950.     {
  951.         if(ptrFunc == null)
  952.             throw new InvalidParameterException("Variable wasn't a function wrapper!");
  953.         return ptrFunc;
  954.     }
  955.  
  956.     /**
  957.      * Get the data structure this Variable wraps.
  958.      * @return This Variable's multiFieldDataStructure.
  959.      * @exception InvalidParameterException if it wasn't a data structure wrapper.
  960.      */
  961.     public multiFieldDataStructure getmultiFieldDataStructure() throws InvalidParameterException
  962.     {
  963.         if(ptrData == null)
  964.             throw new InvalidParameterException("Variable wasn't a multiFieldDataStructure wrapper!");
  965.         return ptrData;
  966.     }
  967.  
  968.     /**
  969.      * Get the Array this Variable wraps.
  970.      * @return This Variable's Array.
  971.      */
  972.     public Array getArray()
  973.     {
  974.         return ptrArray;
  975.     }
  976.  
  977.     /**
  978.      * Convert this Variable into a String containing a C representation.
  979.      * @return String containing C representation of this parameter.
  980.      */
  981.     public String toString()
  982.     {
  983.         if(ptrFunc != null)
  984.             return ptrFunc.toString();
  985.         if(ptrData != null)
  986.             return ptrData.toString();
  987.         if(ptrArray != null)
  988.             return ptrArray.toString();
  989.         return Type + " " + Name;
  990.     }
  991.  
  992.     /**
  993.      * Convert this Variable to Java and return it as a String.  This one is for converting
  994.      * types in function prototypes into Java.  See the Field.toJavaString() for members
  995.      * of structures.
  996.      * @return String containing Java representation.
  997.      * @see Field#toJavaString()
  998.      */
  999.     public String toJavaString() throws InvalidParameterException
  1000.     {
  1001.         if(TypeLUT == null)
  1002.             throw new InvalidParameterException("TypeLUT was null in toJavaString!");
  1003.         if(StructureLUT == null)
  1004.             throw new InvalidParameterException("StructureLUT was null in toJavaString!");
  1005.  
  1006.         if(ptrFunc != null) {
  1007.             System.out.println("Ack! Functions won't convert to Java strings automatically!");
  1008.             return ptrFunc.toString();
  1009.         }
  1010.         if(ptrData != null) {
  1011.             // This code needs to be fixed up for function-only usage...
  1012.             String out;
  1013.             String dataname = ptrData.getName();
  1014.             String mods = ptrData.getModifiers()!=null ? " /* " + ptrData.getModifiers() + " */" : "";
  1015.             if(dataname.equals(ptrData.anonymous)) {
  1016.                 out = "// anonymous " + (ptrData.isStruct() ? "struct" : "union") + " {\r\n";
  1017.                 for(int i=0; i<ptrData.numFields(); i++)
  1018.                     out = out + "\t\t// " + ptrData.getField(i).toJavaString() + ";\r\n";
  1019.                 out = out + "\t//} " + Name;
  1020.             } else
  1021.                 out = "public " + dataname + mods + "\t" + Name;
  1022.             return out;
  1023.         }
  1024.         if(ptrArray != null)
  1025.             return ptrArray.toJavaString(false);
  1026.  
  1027.         String jType = (String) TypeLUT.get(Type);
  1028.         if(jType == null) {
  1029.             multiFieldDataStructure data = (multiFieldDataStructure) StructureLUT.get(Type);
  1030.             if(data!=null)
  1031.                 jType = data.toJavaString(false);
  1032.         }
  1033.         // Sometimes spaces appear in type names...
  1034.         if(jType == null) {
  1035.             StringTokenizer st = new StringTokenizer(Type);
  1036.             String word = st.nextToken();
  1037.             jType = (String) TypeLUT.get(word);
  1038.             if(st.hasMoreElements()) {
  1039.                 word = st.nextToken();
  1040.                 if(word.equals("*")) {
  1041.                     is_Pointer = true;
  1042.                     System.out.println("Ack!  Special Variable.toJavaString array hack!");
  1043.                 }
  1044.             }
  1045.             if(is_Pointer)
  1046.                 jType = jType + "[]";
  1047.         }
  1048.  
  1049.         if(jType == null) {
  1050.             System.out.println("Unparsible C type: " + Type + " \tTypeLUT size was "+TypeLUT.size());
  1051.             System.out.println("TypeLUT.get("+Type+") = "+(String) TypeLUT.get(Type));
  1052.             jType = Type;
  1053.         }
  1054.         String header = "public ";
  1055.         if(isVarArg())
  1056.             header = "// "+header;
  1057.  
  1058.         return header + jType + "\t" + Name;
  1059.     }
  1060.  
  1061.     /**
  1062.      * Set static Type Lookup Table parameter.  Necessary to convert from C to Java.
  1063.      * Also sets TypeLUT for Arrays and multiFieldDataStructures.
  1064.      * @param TypeTable Primitive Hashtable.
  1065.      * @see Parser.html#PopulateTypeLUT
  1066.      */
  1067.     public static void setPrimitiveTable(Hashtable TypeTable)
  1068.     {
  1069.         TypeLUT = TypeTable;
  1070.         Array.setPrimitiveTable(TypeTable);
  1071.         multiFieldDataStructure.setPrimitiveTable(TypeTable);
  1072.     }
  1073.  
  1074.     /**
  1075.      * Set static Structure Lookup Table parameter.  Necessary to convert from C to Java.
  1076.      * Also sets StructureLUT for Arrays and multiFieldDataStructures.
  1077.      * @param StructureTable Structure Lookup Table from Parser.
  1078.      */
  1079.     public static void setStructureTable(Hashtable StructureTable)
  1080.     {
  1081.         StructureLUT = StructureTable;
  1082.         Array.setStructureTable(StructureTable);
  1083.         multiFieldDataStructure.setStructureTable(StructureTable);
  1084.     }
  1085.  
  1086.     /**
  1087.      * Set static String Lookup Table parameter.  Necessary to convert from C to Java.
  1088.      * Also sets StringTypes for Arrays.
  1089.      * @param StringTable String types Hashtable.
  1090.      * @see Parser.html#SetStringTypes
  1091.      */
  1092.     public static void setStringTable(Hashtable StringTable)
  1093.     {
  1094.         StringTypes = StringTable;
  1095.         Array.setStringTable(StringTable);
  1096.     }
  1097. }
  1098.  
  1099.  
  1100. /**
  1101.  * This class is used to wrap fields of structs, classes, and unions.  There need to be a few extra
  1102.  * settings for protection and obscure C++ keywords.
  1103.  */
  1104. class Field extends Variable
  1105. {
  1106.     protected int protection;
  1107.     protected boolean is_Static;
  1108.     protected boolean is_Virtual;
  1109.     protected boolean is_Mutable;
  1110.  
  1111.     public static final int PUBLIC = 1;
  1112.     public static final int PROTECTED = 2;
  1113.     public static final int PRIVATE = 3;
  1114.  
  1115.     /**
  1116.      * Construct a Field with a certain type and name within a structure.  Use for something like:
  1117.      * <code>struct { int x; }</code>
  1118.      * @param Type String containing the C type
  1119.      * @param Name Name of this variable, if known.
  1120.      */
  1121.     public Field(String fieldtype, String fieldname)
  1122.     {
  1123.         super(fieldtype, fieldname);
  1124.         is_Static = false;
  1125.         is_Virtual = false;
  1126.         is_Mutable = false;
  1127.     }
  1128.  
  1129.     /**
  1130.      * Make a Field that wraps a pointer to a function.  Useful for members of a struct
  1131.      * and function arguments.
  1132.      * @param pfunc Function object.
  1133.      */
  1134.     public Field(Function pfunc)
  1135.     {
  1136.         super(pfunc);
  1137.         is_Static = false;
  1138.         is_Virtual = false;
  1139.         is_Mutable = false;
  1140.     }
  1141.  
  1142.     /**
  1143.      * Make a Field storing an Array.  Use this to represent arrays inside structs or unions.
  1144.      * @param a Array to use as source.
  1145.      */
  1146.     public Field(Array a)
  1147.     {
  1148.         super(a);
  1149.         is_Static = false;
  1150.         is_Virtual = false;
  1151.         is_Mutable = false;
  1152.     }
  1153.     
  1154.     /**
  1155.      * Make a Field storing a multiFieldDataStructure.  Use this to represent structs
  1156.      * and unions as members of structs or unions.
  1157.      * @param s multiFieldDataStructure to use as source.
  1158.      * @param name Name of this field.
  1159.      */
  1160.     public Field(multiFieldDataStructure s, String name)
  1161.     {
  1162.         super(s, name);
  1163.         is_Static = false;
  1164.         is_Virtual = false;
  1165.         is_Mutable = false;
  1166.     }
  1167.  
  1168.     /**
  1169.      * Is this a static member?
  1170.      * @return true if this member is static; else false
  1171.      */
  1172.     public boolean isStatic()
  1173.     {
  1174.         return is_Static;
  1175.     }
  1176.  
  1177.     /**
  1178.      * Is this a virtual member function?
  1179.      * @return true if this is a virtual function; else false
  1180.      */
  1181.     public boolean isVirtual()
  1182.     {
  1183.         return is_Virtual;
  1184.     }
  1185.  
  1186.     /**
  1187.      * Is this a mutable member?
  1188.      * @return true if this member is mutable; else false
  1189.      */
  1190.     public boolean isMutable()
  1191.     {
  1192.         return is_Mutable;
  1193.     }
  1194.  
  1195.     /**
  1196.      * Set static flag to a value.
  1197.      * @param v What to set the static flag to.
  1198.      * @return No return value.
  1199.      */
  1200.     public void setStatic(boolean v)
  1201.     {
  1202.         is_Static = v;
  1203.     }
  1204.  
  1205.     /**
  1206.      * Set virtual flag to a value.  Only works for virtual functions!
  1207.      * @param v What to set the static flag to.
  1208.      * @return No return value.
  1209.      * @exception InvalidParameterException if this isn't a member function, since virtual only applies to functions.
  1210.      */
  1211.     public void setVirtual(boolean v) throws InvalidParameterException
  1212.     {
  1213.         if(v==true && !ismultiFieldDataStructure())
  1214.             throw new InvalidParameterException("Only functions can be virtual!");
  1215.         is_Virtual = v;
  1216.     }
  1217.  
  1218.     /**
  1219.      * Set mutable flag to a value.
  1220.      * @param v What to set the mutable flag to.
  1221.      * @return No return value.
  1222.      */
  1223.     public void setMutable(boolean v)
  1224.     {
  1225.         is_Mutable = v;
  1226.     }
  1227.  
  1228.     /**
  1229.      * Set the protection of this Field.
  1230.      * @param newprot What to set the protection to.
  1231.      * @return No return value.
  1232.      * @exception InvalidParameterException if newprot isn't PUBLIC, PRIVATE, or PROTECTED.
  1233.      */
  1234.     public void setProtection(int newprot) throws InvalidParameterException
  1235.     {
  1236.         if(newprot != PUBLIC && newprot != PRIVATE && newprot != PROTECTED)
  1237.             throw new InvalidParameterException("Invalid protection sent to Field.setProtection("+newprot+")!");
  1238.         protection = newprot;
  1239.     }
  1240.  
  1241.     /**
  1242.      * Returns Java protection string for corresponding C protection.
  1243.      * @param CAccess C protection (ie, Variable.PUBLIC)
  1244.      * @return string containing Java access permissions
  1245.      * @exception InvalidParameterException if CAccess isn't PUBLIC, PRIVATE, or PROTECTED
  1246.      */
  1247.     public static final String getJavaAccess(int CAccess) throws InvalidParameterException
  1248.     {
  1249.         if(CAccess == PUBLIC)
  1250.             return "public ";
  1251.         else if(CAccess == PROTECTED)
  1252.             return "protected ";
  1253.         else if(CAccess == PRIVATE)
  1254.             return "private ";
  1255.         else
  1256.             throw new InvalidParameterException("Unknown access permissions in Variable.getJavaAccess("+CAccess+")");
  1257.     }
  1258.  
  1259.     /**
  1260.      * Convert this Field to Java and returns it as a String.  Will apply special 
  1261.      * J/Direct rules for what can and can't be inside a struct or union.  Used for
  1262.      * members of structures - Variable.toJavaString() handles function prototypes.
  1263.      * @return String containing Java representation.
  1264.      * @see Variable#toJavaString()
  1265.      */
  1266.     public String toJavaString() throws InvalidParameterException
  1267.     {
  1268.         if(TypeLUT == null)
  1269.             throw new InvalidParameterException("TypeLUT was null in toJavaString!");
  1270.         if(StructureLUT == null)
  1271.             throw new InvalidParameterException("StructureLUT was null in toJavaString!");
  1272.  
  1273.         if(ptrFunc != null) {
  1274.             System.out.println("Ack! Functions won't convert to Java strings automatically!  Call ConvertFunction!");
  1275.             return ptrFunc.toString();
  1276.         }
  1277.         if(ptrData != null) {
  1278.             // Need to print a one-line summary here.
  1279.             String out;
  1280.             String dataname = ptrData.getName();
  1281.             String mods = ptrData.getModifiers()!=null ? " /* " + ptrData.getModifiers() + " */" : "";
  1282.             if(dataname.equals(ptrData.anonymous)) {
  1283.                 out = "// anonymous " + (ptrData.isStruct() ? "struct" : "union") + " {\r\n";
  1284.                 for(int i=0; i<ptrData.numFields(); i++)
  1285.                     out = out + "\t\t// " + ptrData.getField(i).toJavaString() + ";\r\n";
  1286.                 out = out + "\t//} " + Name;
  1287.             } 
  1288.             else if(is_Pointer)
  1289.                 out = getJavaAccess(protection) + dataname + mods + "\t" + Name;
  1290.             else
  1291.                 out = "// BUGBUG: by-val structure!  "+getJavaAccess(protection) + dataname + mods + "\t" + Name;
  1292.             return out;
  1293.         }
  1294.         if(ptrArray != null)
  1295.             return ptrArray.toJavaString(true);
  1296.  
  1297.         // Kludge for bitfields.  Don't print them.
  1298.         if(Name==null) {
  1299.             return "// "+Type+" bitfield. BUGBUG";
  1300.         }
  1301.  
  1302.         String jType = (String) TypeLUT.get(Type);
  1303.         if(jType == null) {
  1304.             multiFieldDataStructure data = (multiFieldDataStructure) StructureLUT.get(Type);
  1305.             if(data!=null)
  1306.                 jType = data.toJavaString(true);
  1307.         }
  1308.         // Sometimes spaces appear in type names...
  1309.         if(jType == null) {
  1310.             StringTokenizer st = new StringTokenizer(Type);
  1311.             String word = st.nextToken();
  1312.             jType = (String) TypeLUT.get(word);
  1313.             if(st.hasMoreElements()) {
  1314.                 word = st.nextToken();
  1315.                 if(word.equals("*")) {
  1316.                     is_Pointer = true;
  1317.                     System.out.println("Ack!  Special Field.toJavaString array hack!");
  1318.                 }
  1319.             }
  1320.             if(is_Pointer)
  1321.                 jType = jType + "[]";
  1322.         }
  1323.  
  1324.         if(jType == null) {
  1325.             System.out.println("Unparsible C type: " + Type + " \tTypeLUT size was "+TypeLUT.size());
  1326.             System.out.println("TypeLUT.get("+Type+") = "+(String) TypeLUT.get(Type));
  1327.             jType = Type;
  1328.         }
  1329.         String header = getJavaAccess(protection);
  1330.         if(isVarArg())
  1331.             header = "// "+header;
  1332.         // Handle field modifiers
  1333.         if(is_Static)
  1334.             header = header+"static ";
  1335.         if(is_Const)
  1336.             header = header+"final ";
  1337.         if(is_Volatile)
  1338.             header = header+"volatile ";
  1339.  
  1340.         // Three rules for being inside structures, then a special case.
  1341.         // Convert callbacks to ints.  We tell users to do this, so we should do it.
  1342.         // StringBuffers must be converted to Strings.
  1343.         // Strings should be converted to ints for now, but put C type in comments.
  1344.         // LPBYTE -> int.  No non-embedded byte[]   We don't know what they represent - 
  1345.         //      usually structs or a variant type.
  1346.         if(jType.equals(Parser.CallbackString))
  1347.             jType = "int /* BUGBUG: Callback */";
  1348.         else if(jType.equals("StringBuffer"))
  1349.             jType = "String";
  1350.         else if(Parser.Comment_Variant_Types && Type.equals("LPBYTE"))
  1351.             jType = "int /* BUGBUG: LPBYTE */";
  1352.  
  1353.         if(jType.equals("String"))
  1354.             jType = "int /* "+Type+" */";
  1355.  
  1356.         // Handle an initial value (or default argument)
  1357.         String trailer = "";
  1358.         if(InitialValue != null)
  1359.             trailer = " = "+InitialValue.eval();
  1360.  
  1361.         return header + jType + "\t" + Name + trailer;
  1362.     }
  1363. }
  1364.  
  1365.  
  1366. /**
  1367.  * Represents an Array of some type, with any length.  A CharArray is a special case 
  1368.  * (a subclass) of this Array class because of the special String handling rules.
  1369.  * @see CharArray
  1370.  */
  1371. class Array
  1372. {
  1373.     protected boolean lengthknown;
  1374.     protected int length;
  1375.     protected String Type;
  1376.     protected String name;
  1377.     protected Array ptrArray;
  1378.     protected static Hashtable TypeLUT;
  1379.     protected static Hashtable StructureLUT;
  1380.     protected static Hashtable StringTypes;
  1381.  
  1382.     /**
  1383.      * Makes an array of unknown length
  1384.      * @param name Name of the Array
  1385.      */
  1386.     public Array(String name)
  1387.     {
  1388.         this.name = name;
  1389.         lengthknown = false;
  1390.         Type = null;
  1391.         length = 0;
  1392.         ptrArray = null;
  1393.     }
  1394.  
  1395.     /**
  1396.      * Makes an array of fixed length.
  1397.      * @param name Name of the Array
  1398.      * @param numElements Number of elements in the array.
  1399.      */
  1400.     public Array(String name, int numElements)
  1401.     {
  1402.         this.name = name;
  1403.         lengthknown = true;
  1404.         Type = null;
  1405.         length = numElements;
  1406.         ptrArray = null;
  1407.     }
  1408.  
  1409.     /**
  1410.      * Makes an array of arrays
  1411.      * @param nestedArray array to make an array of.
  1412.      */
  1413.     public Array(Array nestedArray)
  1414.     {
  1415.         this.name = "<wrapping array "+nestedArray.getName()+">";
  1416.         lengthknown = false;
  1417.         Type = nestedArray.getType()+"[]";
  1418.         length = 0;
  1419.         ptrArray = nestedArray;
  1420.     }
  1421.  
  1422.     /**
  1423.      * Makes an array of arrays, knowing this dimension.
  1424.      * @param nestedArray array to make an array of.
  1425.      * @param len number of elements in this array.
  1426.      */
  1427.     public Array(Array nestedArray, int len)
  1428.     {
  1429.         this.name = "<wrapping array "+nestedArray.getName()+">";
  1430.         lengthknown = false;
  1431.         Type = nestedArray.getType()+"[]";
  1432.         length = len;
  1433.         ptrArray = nestedArray;
  1434.     }
  1435.  
  1436.     /**
  1437.      * Clean up fields.
  1438.      * @return No return value.
  1439.      */
  1440.     public void finalizer()
  1441.     {
  1442.         Type = null;
  1443.         name = null;
  1444.         ptrArray = null;
  1445.     }
  1446.  
  1447.     /**
  1448.      * Get the Array's name.
  1449.      * @return String containing name of this Array.
  1450.      */
  1451.     public String getName()
  1452.     {
  1453.         return name;
  1454.     }
  1455.  
  1456.     /**
  1457.      * Sets the name of a Array.
  1458.      * @param newName new name for this Array.
  1459.      * @return No return value.
  1460.      */
  1461.     public void setName(String newName)
  1462.     {
  1463.         name = new String(newName);
  1464.     }
  1465.  
  1466.     /**
  1467.      * Get this Array's type.
  1468.      * @return String containing Type.
  1469.      */
  1470.     public String getType()
  1471.     {
  1472.         return Type;
  1473.     }
  1474.  
  1475.     /**
  1476.      * Set this Array's type.
  1477.      * @param newType new type of this Array.
  1478.      * @return No return value.
  1479.      * @exception InvalidParameterException if StringTypes isn't set yet and you call CharArray.setType
  1480.      */
  1481.     public void setType(String newType) throws InvalidParameterException
  1482.     {
  1483.         Type = newType;
  1484.     }
  1485.  
  1486.     /**
  1487.      * Get the number of elements in this array.
  1488.      * @return length as number of elements.
  1489.      */
  1490.     public int getLength()
  1491.     {
  1492.         if(!lengthknown)
  1493.             return -1;
  1494.         else
  1495.             return length;
  1496.     }
  1497.  
  1498.     /**
  1499.      * Is this Array a String array, or one dealing with Strings?
  1500.      * @return true if its type involves strings at all.
  1501.      */
  1502.     public boolean isString() throws InvalidParameterException
  1503.     {
  1504.         if(StringTypes == null)
  1505.             throw new InvalidParameterException("You must set Array::StringTypes before calling isString()!");
  1506.         if(Type == null)
  1507.             throw new InvalidParameterException("You must set Array::Type before calling Array::isString()!");
  1508.  
  1509.         if(ptrArray != null)
  1510.             return ptrArray.isString();
  1511.         else
  1512.             return StringTypes.containsKey(Type);
  1513.     }
  1514.  
  1515.     public String toString()
  1516.     {
  1517.         return Type + "\t" + name + "[" + length + "];";
  1518.     }
  1519.  
  1520.     public String toJavaString(boolean isInsideStruct) throws InvalidParameterException
  1521.     {
  1522.         boolean printBrackets = true;
  1523.         String jType = (String) TypeLUT.get(Type);
  1524.  
  1525.         if(ptrArray != null) {
  1526.             jType = ptrArray.toJavaString(isInsideStruct);
  1527.         }
  1528.  
  1529.         if(jType == null) {
  1530.             multiFieldDataStructure data = (multiFieldDataStructure) StructureLUT.get(Type);
  1531.             if(data!=null)
  1532.                 jType = data.toJavaString(true);
  1533.         }
  1534.         if(jType == null) {
  1535.             System.out.println("Unparsible C type: " + Type);
  1536.             jType = Type;
  1537.         }
  1538.  
  1539.         // Last-ditch convert from char[] to String...
  1540.         if(jType.equals("char")) {
  1541.             jType = "StringBuffer";
  1542.             printBrackets = false;
  1543.         }
  1544.  
  1545.         // In Java, the length of the array isn't part of the array type.  We always
  1546.         // store references.  But if this is an embedded array of size greater than
  1547.         // one, we want to use @dll.structmap().  
  1548.         String out = "";
  1549.         if(isInsideStruct) {
  1550.             if(jType.equals("StringBuffer"))
  1551.                 jType = "String";
  1552.             if(lengthknown) {
  1553.                 if(jType.equals("String"))
  1554.                     out = "/** @dll.structmap([type=TCHAR["+length+"]]) */\r\n\t";
  1555.                 else
  1556.                     out = "/** @dll.structmap([type=FIXEDARRAY, size="+length+"]) */\r\n\t";
  1557.             }
  1558.         }
  1559.  
  1560.         // One last thing... Don't print out int[][].  Doesn't work in Java.  (void** in C)
  1561.         if(jType.equals("int[][]"))
  1562.             jType = "int";
  1563.  
  1564.         // Should probably be changed to handle access permissions sometime...
  1565.         out = out + "public "+jType + "\t" + name;
  1566.         if(printBrackets)
  1567.             out = out + "[]";
  1568.         return out;
  1569.     }
  1570.  
  1571.     /**
  1572.      * Set static Type Lookup Table parameter.  Necessary to convert from C to Java.
  1573.      * @param TypeTable Primitive Hashtable.
  1574.      * @see Parser.html#PopulateTypeLUT
  1575.      */
  1576.     public static void setPrimitiveTable(Hashtable t)
  1577.     {
  1578.         TypeLUT = t;
  1579.     }
  1580.  
  1581.     /**
  1582.      * Set static Structure Lookup Table parameter.  Necessary to convert from C to Java.
  1583.      * @param StructureTable Structure Lookup Table from Parser.
  1584.      */
  1585.     public static void setStructureTable(Hashtable s)
  1586.     {
  1587.         StructureLUT = s;
  1588.     }
  1589.  
  1590.     /**
  1591.      * Set static String Lookup Table parameter.  Necessary to convert from C to Java.
  1592.      * @param StringTable String types Hashtable.
  1593.      * @see Parser.html#SetStringTypes
  1594.      */
  1595.     public static void setStringTable(Hashtable s)
  1596.     {
  1597.         StringTypes = s;
  1598.     }
  1599. }
  1600.  
  1601.  
  1602. /**
  1603.  * Used to represent Strings, which are always difficult because they can be Unicode or
  1604.  * ASCII strings.  There are additional rules for outputting them when their length is
  1605.  * known and they're embedded in a struct, etc.
  1606.  */
  1607. class CharArray extends Array {
  1608.     protected boolean is_Unicode_String;
  1609.  
  1610.     /**
  1611.      * Build a character array of fixed length.
  1612.      * @param name Name of this char array.
  1613.      * @param length number of characters in array.
  1614.      */
  1615.     public CharArray (String name, int length)
  1616.     {
  1617.         super(name, length);
  1618.         is_Unicode_String = true;
  1619.     }
  1620.  
  1621.     /**
  1622.      * Build a character array of unknown length.
  1623.      * @param name Name of this char array.
  1624.      */
  1625.     public CharArray (String name)
  1626.     {
  1627.         super(name);
  1628.         is_Unicode_String = true;
  1629.     }
  1630.  
  1631.     /**
  1632.      * Is this an array of characters?
  1633.      * @return true if this is a C string, else false.
  1634.      */
  1635.     public boolean isString() throws InvalidParameterException
  1636.     {
  1637.         return true;
  1638.     }
  1639.  
  1640.     /**
  1641.      * Set the type of this string and determine character width.
  1642.      * @param newType new type for this Char array.
  1643.      * @return No return value.
  1644.      * @exception InvalidParameterException if StringTypes isn't set yet.
  1645.      */
  1646.     public void setType(String newType) throws InvalidParameterException
  1647.     {
  1648.         Type = newType;
  1649.         if(StringTypes==null)
  1650.             throw new InvalidParameterException("Cannot modify Char array type without setting Array.StringTypes first!");
  1651.         String width = (String) StringTypes.get(Type);
  1652.         if(width.equals("unicode"))
  1653.             is_Unicode_String = true;
  1654.         else if(width.equals("ansi"))
  1655.             is_Unicode_String = false;
  1656.     }
  1657.  
  1658.     /**
  1659.      * Is this string a Unicode String (char width is 2 bytes)
  1660.      * @return true if type is a Unicode type; else false
  1661.      */
  1662.     public boolean isUnicode()
  1663.     {
  1664.         return is_Unicode_String;
  1665.     }
  1666.  
  1667.     /**
  1668.      * Is this string an ASCII String (char width is 1 byte)
  1669.      * @return true if type is an ASCII type; else false
  1670.      */
  1671.     public boolean isASCII()
  1672.     {
  1673.         return !is_Unicode_String;
  1674.     }
  1675.  
  1676.     /**
  1677.      * Convert CharArray to Java.
  1678.      * @param isInsideStruct is this a member of a structure?
  1679.      * @return String containing Java representation of this array.
  1680.      * @exception InvalidParameterException if CharArray isn't set up properly.
  1681.      */
  1682.     public String toJavaString(boolean isInsideStruct) throws InvalidParameterException {
  1683.         if(Type == null)
  1684.             throw new InvalidParameterException("Must set a CharArray's type before converting to a Java string!");
  1685.  
  1686.         String jType = (String) TypeLUT.get(Type);
  1687.         if(jType==null)
  1688.             jType = ptrArray.toJavaString(isInsideStruct);
  1689.  
  1690. //        StringTypes.get(Type);
  1691.  
  1692.         // Should probably be changed to handle access permissions sometime...
  1693.         String header="\tpublic ";
  1694.  
  1695.         // We can only have Strings inside a struct, no StringBuffers. 
  1696.         // Strings have a special @dll.structmap syntax.
  1697.         if(isInsideStruct) {
  1698.             jType = "String";
  1699.             if(lengthknown)
  1700.                 header = "/** @dll.structmap([type=TCHAR["+length+"]]) */\r\n"+header;
  1701.         }
  1702.  
  1703.         return header + jType + "\t" + name;
  1704.     }
  1705. }
  1706.  
  1707.  
  1708. /**
  1709.  * base class for Struct and Union
  1710.  */
  1711. abstract class multiFieldDataStructure
  1712. {
  1713.     protected String name;         // struct's primary typedef'ed name
  1714.     protected Vector otherNames;   // typedef'ed names.
  1715.     protected Vector fields;       // holds Variables.
  1716.     protected int packsize;        // Alignment setting.  { 1, 2, 4, 8 }
  1717.     protected boolean hasUnion;    // whether there's a union in this data structure
  1718.     protected boolean hasStruct;   // whether there's an embedded struct in this data structure
  1719.     protected boolean hasArray;    // whether there's an array in this data structure.
  1720.     protected boolean merged;         // whether this has been merged with its ASCII or Unicode equivalent.
  1721.     protected boolean used;        // whether a function actually uses this structure.
  1722.     protected boolean notComplete; // Need to add to StructureLUT while incomplete to handle recursive structs.
  1723.     protected String modifiers;    // modifiers like volatile
  1724.     public static String anonymous = "anonymous_data_structure";
  1725.     protected static Hashtable TypeLUT;
  1726.     protected static Hashtable StructureLUT;
  1727.     protected static final int JavaDefaultPackSize = 8;
  1728.     protected static final int CDefaultPackSize = 8;       // VC++ defaults to 8
  1729.     
  1730.     /** 
  1731.      * Make a new multiFieldDataStructure object, giving it a name.
  1732.      * @param name Primary name of the struct or null if not named.
  1733.      * @return a new Struct.
  1734.      */
  1735.     public multiFieldDataStructure(String name)
  1736.     {
  1737.         if(name == null)
  1738.             this.name = anonymous;
  1739.         else
  1740.             this.name = name;
  1741.         otherNames = null;
  1742.         fields = new Vector(4, 4);
  1743.         packsize = CDefaultPackSize;
  1744.         hasUnion = false;
  1745.         hasStruct = false;
  1746.         hasArray = false;
  1747.         merged = false;
  1748.         notComplete = false;
  1749.         modifiers = null;
  1750.         used = false;
  1751.     }
  1752.  
  1753.     public void finalizer()
  1754.     {
  1755.         fields = null;
  1756.         otherNames = null;
  1757.         name = null;
  1758.         modifiers = null;
  1759.     }
  1760.  
  1761.     /**
  1762.      * Tells whether this is a union or not.
  1763.      * @return true if this multiFieldDataStructure is a union; else false
  1764.      */
  1765.     abstract public boolean isUnion();
  1766.  
  1767.     /**
  1768.      * Tells whether this is a struct or not.
  1769.      * @return true if this multiFieldDataStructure is a struct; else false
  1770.      */
  1771.     abstract public boolean isStruct();
  1772.  
  1773.     /**
  1774.      * Converts this to its string representation in C syntax.  Must be overridden.
  1775.      * @return String containing the C representation of this data structure.
  1776.      */
  1777.     abstract public String toString();
  1778.  
  1779.     /**
  1780.      * Converts this to its string representation in Java syntax.  Must be overridden.
  1781.      * @param isInsideStruct if this is inside a struct or a union
  1782.      * @return String containing the Java representation of this data structure.
  1783.      * @throws InvalidParameterException if TypeLUT or StructureLUT haven't been set.
  1784.      */
  1785.     abstract public String toJavaString(boolean isInsideStruct) throws InvalidParameterException;
  1786.  
  1787.     /**
  1788.      * Get the multiFieldDataStructure's name.
  1789.      * @return String containing name of this multiFieldDataStructure.
  1790.      */
  1791.     public final String getName()
  1792.     {
  1793.         return name;
  1794.     }
  1795.  
  1796.     /**
  1797.      * Sets the name of a multiFieldDataStructure.
  1798.      * @param newName new name for this multiFieldDataStructure.
  1799.      * @return No return value.
  1800.      */
  1801.     public final void setName(String newName)
  1802.     {
  1803.         name = newName;
  1804.     }
  1805.  
  1806.     /**
  1807.      * Set whether this structure has been merged with its ASCII or Unicode counterpart.
  1808.      * Will stick "auto" in the @dll.struct line.
  1809.      * @param val true if this is the structure that survived the merge
  1810.      * @return No return value.
  1811.      */
  1812.     public void setMerged(boolean val)
  1813.     {
  1814.         merged = val;
  1815.     }
  1816.  
  1817.     /**
  1818.      * whether this structure is used anywhere.
  1819.      * @return true if its used, false if not.
  1820.      */
  1821.     public boolean isUsed()
  1822.     {
  1823.         return used;
  1824.     }
  1825.  
  1826.     /**
  1827.      * Tell this structure its being used.
  1828.      * @return No return value.
  1829.      */
  1830.     public void Use()
  1831.     {
  1832.         if(!used) {
  1833.             used = true;
  1834.             for(int i=0; i<fields.size(); i++) {
  1835.                 Variable v = (Variable) fields.elementAt(i);
  1836.                 if(v!=null && v.ismultiFieldDataStructure()) {
  1837.                     try {
  1838.                         multiFieldDataStructure data = (multiFieldDataStructure) v.getmultiFieldDataStructure();
  1839.                         data.Use();
  1840.                     }
  1841.                     catch (InvalidParameterException e) {}
  1842.                 }
  1843.             }
  1844.         }
  1845.     }
  1846.  
  1847.     /**
  1848.      * Gets the modifiers for this data structure
  1849.      * @return String of modifiers for this structure.
  1850.      */
  1851.     public String getModifiers()
  1852.     {
  1853.         return modifiers;
  1854.     }
  1855.  
  1856.     /**
  1857.      * Sets the modifiers for this data structure
  1858.      * @param mod new string of modifiers.
  1859.      * @return No return value.
  1860.      */
  1861.     public void setModifiers(String newMods)
  1862.     {
  1863.         modifiers = newMods;
  1864.     }
  1865.  
  1866.     /**
  1867.      * Adds the modifier to the other modifiers already set for this data structure
  1868.      * @param mod new modifier.
  1869.      * @return No return value.
  1870.      */
  1871.     public void addModifier(String newMod)
  1872.     {
  1873.         if(modifiers == null)
  1874.             modifiers = newMod;
  1875.         else
  1876.             modifiers = modifiers + " " + newMod;
  1877.     }
  1878.  
  1879.     /**
  1880.      * Get the multiFieldDataStructure's pack size.
  1881.      * @return Pack size of this multiFieldDataStructure.
  1882.      */
  1883.     public int getPackSize()
  1884.     {
  1885.         return packsize;
  1886.     }
  1887.  
  1888.     /**
  1889.      * Sets the packing size of a multiFieldDataStructure.  Says that the alignment 
  1890.      * should be 1, 2, 4 or 8 bytes.
  1891.      * @param newPackSize new alignment for this multiFieldDataStructure.
  1892.      * @return No return value.
  1893.      * @exception InvalidParameterException if newPackSize isn't 1, 2, 4, or 8 bytes.
  1894.      */
  1895.     public void setPackSize(int newPackSize) throws InvalidParameterException
  1896.     {
  1897.         if(newPackSize != 1 && newPackSize != 2 && newPackSize != 4 && newPackSize != 8)
  1898.             throw new InvalidParameterException("setPackSize accepts only 1, 2, 4, or 8 bytes, not " + newPackSize);
  1899.         packsize = newPackSize;
  1900.     }
  1901.  
  1902.     /**
  1903.      * Tell whether we have the complete definition of the structure or if we only have 
  1904.      * a reference to the structure existing.  Specifically, an incomplete struct would
  1905.      * look like this:
  1906.      * <code struct An_Incomplete_Struct;</code>
  1907.      * @return No return value.
  1908.      */
  1909.     public boolean isComplete()
  1910.     {
  1911.         return !notComplete;
  1912.     }
  1913.  
  1914.     /**
  1915.      * Set the flag telling whether this structure is completely defined or not.
  1916.      * For structs that only have prototypes but no actual definition, it should
  1917.      * not be complete.  Code I'm thinking of specifically:
  1918.      * <code>struct An_Incomplete_Struct;</code>
  1919.      * @param val true if this is a complete struct, else false.
  1920.      * @return No return value.
  1921.      */
  1922.     public void setComplete(boolean val)
  1923.     {
  1924.         notComplete = !val;
  1925.     }
  1926.  
  1927.     /**
  1928.      * Returns whether the multiFieldDataStructure has a union in it, being 
  1929.      * harder to convert.
  1930.      * @return true if a union field exists; else false
  1931.      */
  1932.     public boolean containsUnion()
  1933.     {
  1934.         return hasUnion;
  1935.     }
  1936.  
  1937.     /**
  1938.      * Returns whether the multiFieldDataStructure has an embedded struct in it, 
  1939.      * being harder to convert.
  1940.      * @return true if at least one field is a struct; else false
  1941.      */
  1942.     public boolean containsStruct()
  1943.     {
  1944.         return hasStruct;
  1945.     }
  1946.  
  1947.     /**
  1948.      * Returns whether the multiFieldDataStructure has a union in it, being 
  1949.      * harder to convert.
  1950.      * @return true if at least one field is an array; else false
  1951.      */
  1952.     public boolean containsArray()
  1953.     {
  1954.         return hasArray;
  1955.     }
  1956.  
  1957.     /**
  1958.      * Determine if there's a unicode string in this multiFieldDataStructure.
  1959.      * @return true if there is a Unicode string, else false.
  1960.      */
  1961.     public boolean containsUnicodeString()
  1962.     {
  1963.         boolean val = false;
  1964.         for(int i=0; i<fields.size() && !val; i++) {
  1965.             try {
  1966.             Variable v = (Variable) fields.elementAt(i);
  1967.             if(v.isCharArray()) {
  1968.                 CharArray a = (CharArray) v.getArray();
  1969.                 if(a.isUnicode())
  1970.                     val = true;
  1971.             }
  1972.             }
  1973.             catch (InvalidParameterException ipe) {
  1974.                 System.out.println("Caught InvalidParameterException: "+ipe);
  1975.                 ipe.printStackTrace();
  1976.             }
  1977.         }
  1978.         return val;
  1979.     }
  1980.  
  1981.     /**
  1982.      * Adds another name for the data structure.  Simulates typedef's.  Creates otherNames
  1983.      * vector if it doesn't already exist.
  1984.      * @param altName An alternate name for this multiFieldDataStructure.
  1985.      * @return No return value.
  1986.      */
  1987.     public void addAltName(String altName)
  1988.     {
  1989.         if(otherNames == null)
  1990.             otherNames = new Vector(2, 2);
  1991.         otherNames.addElement(altName);
  1992.     }
  1993.  
  1994.     /**
  1995.      * Returns the number of alternate names for this data structure.
  1996.      * @return Number of alternate names for this multiFieldDataStructure.
  1997.      */
  1998.     public int numAltNames()
  1999.     {
  2000.         if(otherNames == null)
  2001.             return 0;
  2002.         return otherNames.size();
  2003.     }
  2004.     
  2005.     /**
  2006.      * Returns the alternate name you ask for.
  2007.      * @param which Which alternate name you want.
  2008.      * @return The which'th alternate name.
  2009.      */
  2010.     public String getAltName(int which)
  2011.     {
  2012.         return (String) otherNames.elementAt(which);
  2013.     }
  2014.  
  2015.     /**
  2016.      * Adds a Field to the multiFieldDataStructure.  Call in order fields appear in 
  2017.      * the C data type.
  2018.      * @param field Field holding the type and name of a new field.
  2019.      * @return No return value.
  2020.      * @exception InvalidParameterException if field is null.
  2021.      */
  2022.     public void addField(Field field) throws InvalidParameterException
  2023.     {
  2024.         if(field==null)
  2025.             throw new InvalidParameterException("addField(Variable) won't accept null Variables!");
  2026.         if(field.ismultiFieldDataStructure()) {
  2027.             multiFieldDataStructure data = field.getmultiFieldDataStructure();
  2028.             if(data == null)
  2029.                 throw new InvalidParameterException("addField(Variable) was passed an invalid data structure wrapper!");
  2030.             hasUnion = hasUnion | data.isUnion() | data.containsUnion();
  2031.             hasStruct = hasStruct | data.isStruct() | data.containsStruct();
  2032.             hasArray = hasArray | data.containsArray();
  2033.         }
  2034.         if(field.isArray()) {
  2035.             Array a = field.getArray();
  2036.             if(a == null)
  2037.                 throw new InvalidParameterException("addField(Variable) was passed an invalid array wrapper!");
  2038.             hasArray = true;
  2039.         }
  2040.         fields.addElement(field);
  2041.     }
  2042.  
  2043.     /**
  2044.      * Adds a complex field to the multiFieldDataStructure.  Call in order fields appear in 
  2045.      * the C data type.
  2046.      * @param field multiFieldDataStructure to be added into data structure.
  2047.      * @return No return value.
  2048.      * @exception InvalidParameterException if field is null
  2049.      */
  2050.     public void addField(multiFieldDataStructure field, String fname) throws InvalidParameterException
  2051.     {
  2052.         if(field == null)
  2053.             throw new InvalidParameterException("addField(multiFieldDataStructure) won't accept a null field!");
  2054.         hasUnion = hasUnion | field.isUnion() | field.containsUnion();
  2055.         hasStruct = hasStruct | field.isStruct() | field.containsStruct();
  2056.         hasArray = hasArray | field.containsArray();
  2057.         fields.addElement(new Field(field, fname));
  2058.     }
  2059.  
  2060.     /**
  2061.      * Returns the number of fields in this multiFieldDataStructure.
  2062.      * @return Number of fields in this multiFieldDataStructure.
  2063.      */
  2064.     public int numFields()
  2065.     {
  2066.         return fields.size();
  2067.     }
  2068.  
  2069.     /**
  2070.      * Returns a Field holding the nth field of this multiFieldDataStructure
  2071.      * @param n Number of field to return.
  2072.      * @return Field containing nth field of the multiFieldDataStructure.
  2073.      * @exception InvalidParameterException if n is larger than the number of fields.
  2074.      */
  2075.     public Field getField(int n) throws InvalidParameterException
  2076.     {
  2077.         if(n > fields.size())
  2078.             throw new InvalidParameterException("getField called with out of range index!  There aren't that many fields!");
  2079.         Field f = (Field) fields.elementAt(n);
  2080.         return f;
  2081.     }
  2082.  
  2083.     /**
  2084.      * Set static Type Lookup Table parameter.  Necessary to convert from C to Java.
  2085.      * @param TypeTable Primitive Hashtable.
  2086.      * @see Parser.html#PopulateTypeLUT
  2087.      */
  2088.     public static void setPrimitiveTable(Hashtable t)
  2089.     {
  2090.         TypeLUT = t;
  2091.     }
  2092.  
  2093.     /**
  2094.      * Set static Structure Lookup Table parameter.  Necessary to convert from C to Java.
  2095.      * @param StructureTable Structure Lookup Table from Parser.
  2096.      */
  2097.     public static void setStructureTable(Hashtable s)
  2098.     {
  2099.         StructureLUT = s;
  2100.     }
  2101. }
  2102.  
  2103.  
  2104. class multiFieldDataStructureCompare implements Comparison
  2105. {
  2106.     /**
  2107.      * Compares two objects that hopefully are multiFieldDataStructures.  Compares based on
  2108.      * name of the struct, then by some collection of other rules if there are two structs
  2109.      * with the same name.
  2110.      * @param a A multiFieldDataStructure to compare
  2111.      * @param b A multiFieldDataStructure to compare
  2112.      * @return 0 if they're exactly equal, a negative value if a < b, and a positive value if a > b
  2113.      */
  2114.     public int compare(Object a, Object b)
  2115.     {
  2116.         multiFieldDataStructure ma = (multiFieldDataStructure) a;
  2117.         multiFieldDataStructure mb = (multiFieldDataStructure) b;
  2118.         int res = ma.getName().compareTo(mb.getName());
  2119.         if(res == 0) { // give preference to struct over union if they have same name.
  2120.             if(ma.isStruct() && mb.isStruct())
  2121.                 return res;
  2122.             else if(ma.isStruct())
  2123.                 return -1;
  2124.             else if(mb.isStruct())
  2125.                 return +1;
  2126.         }
  2127.         return res;
  2128.     }
  2129. }
  2130.  
  2131.  
  2132. class Struct extends multiFieldDataStructure
  2133. {
  2134.     /** 
  2135.      * Make a new Struct object, giving it a name.
  2136.      * @param name Primary name of the struct
  2137.      * @return a new Struct.
  2138.      */
  2139.     public Struct(String name)
  2140.     {
  2141.         super(name);
  2142.     }
  2143.  
  2144.     /**
  2145.      * Tells whether this is a union or not.
  2146.      * @return true if this multiFieldDataStructure is a union; else false
  2147.      */
  2148.     public boolean isUnion()
  2149.     {
  2150.         return false;
  2151.     }
  2152.  
  2153.     /**
  2154.      * Tells whether this is a struct or not.
  2155.      * @return true if this multiFieldDataStructure is a struct; else false
  2156.      */
  2157.     public final boolean isStruct()
  2158.     {
  2159.         return true;
  2160.     }
  2161.  
  2162.     /**
  2163.      * Converts Struct to its string representation in C syntax.  Must be overridden.
  2164.      * @return String containing the C representation of this data structure.
  2165.      */
  2166.     public String toString()
  2167.     {
  2168.         String str = "struct " + name + (modifiers!=null ? " "+modifiers : "") + " {\r\n";
  2169.         for(int i=0; i<fields.size(); i++) {
  2170.             Variable var = (Variable) fields.elementAt(i);
  2171.             str = str + "\t" + var.Type + "\t" + var.Name + ";\r\n";
  2172.         }
  2173.         return str;
  2174.     }
  2175.  
  2176.     /**
  2177.      * Converts Struct to its string representation in Java syntax.  Must be overridden.
  2178.      * @param isInsideStruct if this is inside a struct or a union
  2179.      * @return String containing the Java representation of this data structure.
  2180.      */
  2181.     public String toJavaString(boolean isInsideStruct) throws InvalidParameterException
  2182.     {
  2183.         if(TypeLUT == null)
  2184.             throw new InvalidParameterException("TypeLUT was null in toJavaString!");
  2185.         if(StructureLUT == null)
  2186.             throw new InvalidParameterException("StructureLUT was null in toJavaString!");
  2187.  
  2188.         String mods = "";
  2189.         if(modifiers!=null)
  2190.             mods = " /* "+modifiers+" */";
  2191.         String args = "";
  2192.         if(packsize != JavaDefaultPackSize)
  2193.             args = "pack="+packsize;
  2194.  
  2195.         // If we've merged this structure with an ASCII one, use the auto keyword.
  2196.         // If not, check for using embedded unicode strings and use unicode keyword.
  2197.         if(merged) {  // if merged, you must append this.
  2198.             if(args.equals(""))
  2199.                 args = "auto";
  2200.             else
  2201.                 args = args + ", auto";
  2202.         }
  2203.         else if(containsUnicodeString()) {
  2204.             if(args.equals(""))
  2205.                 args = "unicode";
  2206.             else
  2207.                 args = args + ", unicode";
  2208.         }
  2209.  
  2210.         String str = "/** @dll.struct("+args+") */\r\npublic class " + name + mods + " {\r\n";
  2211.         try {
  2212.             for(int i=0; i<fields.size(); i++) {
  2213.                 Variable var = (Variable) fields.elementAt(i);
  2214.                 if(var == null)
  2215.                     System.out.println("Ack! Invalid null field in struct "+name);
  2216.                 String javaType = null;
  2217.                 boolean append_semicolon = true;
  2218.                 // For embedded structs, do something meaningful.  Expand them and add on the
  2219.                 // field name of the struct to the fields.  So a struct containing a POINT named pt
  2220.                 // now has two extra fields - int pt_x; and int pt_y;
  2221.                 if(var.ismultiFieldDataStructure()) {
  2222.                     append_semicolon = false;
  2223.                     multiFieldDataStructure data = var.getmultiFieldDataStructure();
  2224.                     javaType = "// "+var.Name+" was a by-value "+data.getName()+" structure\r\n";
  2225.                     for(int j=0; j<data.numFields(); j++) {
  2226.                         Field f = (Field) data.getField(j);
  2227.                         // Insert name_ before name of the field...
  2228.                         StringTokenizer st = new StringTokenizer(f.toJavaString(), " \t", true);
  2229.                         String mungedfield="\t";
  2230.                         String append = null;
  2231.                         do {
  2232.                             String token = st.nextToken();
  2233.                             if(token.equals("\t")) {
  2234.                                 append = "\t"+var.Name+"_";
  2235.                                 //mungedfield = mungedfield+"\t"+var.Name+"_";
  2236.                             }
  2237.                             else {
  2238.                                 if(append != null && !(token.equals("public") || token.equals("private") || token.equals("protected")))
  2239.                                     mungedfield = mungedfield + append + token;
  2240.                                 else {
  2241.                                     if(append != null)
  2242.                                         mungedfield = mungedfield + "\t" + token;
  2243.                                     else
  2244.                                         mungedfield = mungedfield + token;
  2245.                                 }
  2246.                                 append = null;
  2247.                             }
  2248.                         } while(st.hasMoreTokens());
  2249.                         if(javaType==null)
  2250.                             javaType = mungedfield;
  2251.                         else
  2252.                             javaType = javaType + mungedfield+";\r\n";
  2253.                     }
  2254.                 }
  2255.                 else
  2256.                     javaType = var.toJavaString();
  2257.                 // StringBuffers never exist inside structs.
  2258.                 if(javaType.equals("StringBuffer"))
  2259.                     javaType = "String";
  2260.                 str = str + "\t" + javaType + (append_semicolon ? ";\r\n" : "");
  2261.                 //str = str + "\t" + var.Type + "\t" + var.Name + ";\r\n";
  2262.             }
  2263.         }
  2264.         catch (InvalidParameterException e) {
  2265.             System.out.println("Ack!  InvalidParameterException went through Struct::toJavaString for " + name);
  2266.             throw e;
  2267.         }
  2268.         str = str + "}\r\n";
  2269.         return str;
  2270.     }
  2271. }
  2272.  
  2273. /** This class is for structures that aren't ever defined in a header file explicitly,
  2274.  * but pointers to it are used frequently.  Examples are GLUtesselator and CommCtrl's
  2275.  * _IMAGELIST.  
  2276.  * 
  2277.  * I'm still debating how, or whether, to use this.
  2278.  */
  2279. class OpaqueStruct extends Struct
  2280. {
  2281.     /**
  2282.      * Make an opaque structure, a struct that is never explicitly defined in a header file.
  2283.      * @param my_name Name of the struct
  2284.      */
  2285.     public OpaqueStruct(String my_name) {
  2286.         super(my_name);
  2287.     }
  2288.  
  2289.     /**
  2290.      * Converts Struct to its string representation in C syntax.  Must be overridden.
  2291.      * @return String containing the C representation of this data structure.
  2292.      */
  2293.     public String toString()
  2294.     {
  2295.         return "struct "+name+";";
  2296.     }
  2297.  
  2298.     /**
  2299.      * Converts Struct to its string representation in Java syntax.  Must be overridden.
  2300.      * @param isInsideStruct if this is inside a struct or a union
  2301.      * @return String containing the Java representation of this data structure.
  2302.      */
  2303.     public String toJavaString(boolean isInsideStruct) throws InvalidParameterException
  2304.     {
  2305.         if(TypeLUT == null)
  2306.             throw new InvalidParameterException("TypeLUT was null in toJavaString!");
  2307.         if(StructureLUT == null)
  2308.             throw new InvalidParameterException("StructureLUT was null in toJavaString!");
  2309.  
  2310.         String mods = "";
  2311.         if(modifiers!=null)
  2312.             mods = " /* "+modifiers+" */";
  2313.         String args = "";
  2314.         if(packsize != JavaDefaultPackSize)
  2315.             args = "pack="+packsize;
  2316.  
  2317.         // If we've merged this structure with an ASCII one, use the auto keyword.
  2318.         // If not, check for using embedded unicode strings and use unicode keyword.
  2319.         if(merged) {  // if merged, you must append this.
  2320.             if(args.equals(""))
  2321.                 args = "auto";
  2322.             else
  2323.                 args = args + ", auto";
  2324.         }
  2325.         else if(containsUnicodeString()) {
  2326.             if(args.equals(""))
  2327.                 args = "unicode";
  2328.             else
  2329.                 args = args + ", unicode";
  2330.         }
  2331.  
  2332.         String str = "/** @dll.struct("+args+") */\r\npublic class " + name + mods + " {\r\n";
  2333.         str = str + "}\r\n";
  2334.         return str;
  2335.     }
  2336. }
  2337.  
  2338.  
  2339. class Union extends multiFieldDataStructure
  2340. {
  2341.     /** 
  2342.      * Make a new Union object, giving it a name.
  2343.      * @param name Primary name of the union
  2344.      * @return a new Union.
  2345.      */
  2346.     public Union(String name)
  2347.     {
  2348.         super(name);
  2349.     }
  2350.  
  2351.     /**
  2352.      * Tells whether this is a union or not.
  2353.      * @return true if this multiFieldDataStructure is a union; else false
  2354.      */
  2355.     public final boolean isUnion()
  2356.     {
  2357.         return true;
  2358.     }
  2359.  
  2360.     /**
  2361.      * Tells whether this is a struct or not.
  2362.      * @return true if this multiFieldDataStructure is a struct; else false
  2363.      */
  2364.     public boolean isStruct()
  2365.     {
  2366.         return false;
  2367.     }
  2368.  
  2369.     /**
  2370.      * Converts union to its string representation in C syntax.  Must be overridden.
  2371.      * @return String containing the C representation of this data structure.
  2372.      */
  2373.     public String toString()
  2374.     {
  2375.         String str = "union " + name + (modifiers!=null ? " "+modifiers : "") + " {\r\n";
  2376.         for(int i=0; i<fields.size(); i++) {
  2377.             Variable var = (Variable) fields.elementAt(i);
  2378.             str = str + "\t" + var.Type + "\t" + var.Name + ";\r\n";
  2379.         }
  2380.         return str;
  2381.     }
  2382.  
  2383.     /**
  2384.      * Converts Union to java representation.  This really needs work.
  2385.      * @param isInsideStruct if this is inside a struct or a union
  2386.      * @return String containing Java representation of union.
  2387.      */
  2388.     public String toJavaString(boolean isInsideStruct) throws InvalidParameterException
  2389.     {
  2390.         if(TypeLUT == null)
  2391.             throw new InvalidParameterException("TypeLUT was null in toJavaString!");
  2392.         if(StructureLUT == null)
  2393.             throw new InvalidParameterException("StructureLUT was null in toJavaString!");
  2394.  
  2395.         String args = "";
  2396.         if(packsize != JavaDefaultPackSize)
  2397.             args = "pack="+packsize;
  2398.         if(merged) {
  2399.             if(args.equals(""))
  2400.                 args = "auto";
  2401.             else
  2402.                 args = args + ", auto";
  2403.         }
  2404.  
  2405.         String header = "/** @dll.struct("+args+") */\r\n";
  2406.         String str = "";
  2407.         str = "// stub for compilability.  Must be replaced.\r\n"+header+"public class "+name+" {}\r\n\r\n";
  2408.         str = str + "// UNION\r\n"+header+"/*\r\npublic class " + name + " {\r\n";
  2409.         // This isn't right.
  2410.         for(int i=0; i<fields.size(); i++) {
  2411.             Variable var = (Variable) fields.elementAt(i);
  2412.             str = str + "\t" + var.toJavaString() + ";\r\n";
  2413.         }
  2414.         str = str + "}\r\n*/\r\n";
  2415.         return str;
  2416.     }
  2417. }
  2418.  
  2419.  
  2420. class Function
  2421. {
  2422.     protected String return_type;
  2423.     protected Vector arguments;
  2424.     protected String name;
  2425.     protected int stringformat;        // Conversion mode for strings
  2426.     protected String library;            // What library this function occurs in
  2427.     protected boolean is_Inline;
  2428.     protected boolean is_Abstract;
  2429.  
  2430.     protected static final String DefaultLib = Parser.UnknownLibraryString;
  2431.  
  2432.     public static final int StrFmt_Unknown = 0;
  2433.     public static final int StrFmt_ANSI = 1;
  2434.     public static final int StrFmt_Unicode = 2;
  2435.     public static final int StrFmt_Auto = 3;
  2436.  
  2437.     public Function()
  2438.     {
  2439.         name = "<Unnamed Function>";
  2440.         return_type = new String("<Unknown return type>");
  2441.         arguments = new Vector();
  2442.         stringformat = StrFmt_Unknown;
  2443.         library = DefaultLib;
  2444.         is_Inline = false;
  2445.         is_Abstract = false;
  2446.     }
  2447.  
  2448.     public Function(String name)
  2449.     {
  2450.         this.name = name;
  2451.         return_type = new String("<Unknown return type>");
  2452.         arguments = new Vector();
  2453.         stringformat = StrFmt_Unknown;
  2454.         library = DefaultLib;
  2455.         is_Inline = false;
  2456.         is_Abstract = false;
  2457.     }
  2458.  
  2459.     public void finalize()
  2460.     {
  2461.         name = null;
  2462.         return_type = null;
  2463.         arguments = null;
  2464.     }
  2465.  
  2466.     /**
  2467.      * Compares two function names, returning true if they're identical.  Works on
  2468.      * the assumption that there's no polymorphism in the Win32 API (which was written 
  2469.      * in C).
  2470.      * @param f An Object to compare this one to.
  2471.      * @return true if Object is a function and names are identical; otherwise false.
  2472.      */
  2473.     public boolean equals(Object obj)
  2474.     {
  2475.         if(!(obj instanceof Function))
  2476.             return false;
  2477.         return name.equals(((Function) obj).getName());
  2478.     }
  2479.  
  2480.     /**
  2481.      * Get the Function's name.
  2482.      * @return String containing name of this Function.
  2483.      */
  2484.     public String getName()
  2485.     {
  2486.         return name;
  2487.     }
  2488.  
  2489.     /**
  2490.      * Sets the name of a Function.
  2491.      * @param newName new name for this Function.
  2492.      * @return No return value.
  2493.      */
  2494.     public void setName(String newName)
  2495.     {
  2496.         name = new String(newName);
  2497.     }
  2498.  
  2499.     /**
  2500.      * Get a function's return type in C
  2501.      * @return String containing C return type.
  2502.      */
  2503.     public String getReturnType()
  2504.     {
  2505.         return return_type;
  2506.     }
  2507.  
  2508.     /**
  2509.      * Set the return type of this function.
  2510.      * @param r New return type in C
  2511.      * @return No return value.
  2512.      */
  2513.     public void setReturnType(String r)
  2514.     {
  2515.         return_type = r;
  2516.     }
  2517.  
  2518.     /**
  2519.      * Returns current format of any string parameters to this function, 
  2520.      * ie Unknown, ANSI, Unicode, or Auto.  Exact return
  2521.      * value is Function.StrFmt_x, where x is one of the 4 modes just mentioned.
  2522.      * @return Format of string parameters to this function.
  2523.      */
  2524.     public int getStringFormat()
  2525.     {
  2526.         return stringformat;
  2527.     }
  2528.  
  2529.     /**
  2530.      * Sets the current string format to one passed in.
  2531.      * @param fmt New format for all string parameters to this function.
  2532.      * @return No return value.
  2533.      */
  2534.     public void setStringFormat(int fmt)
  2535.     {
  2536.         /*
  2537.         if(fmt < StrFmt_Unknown || fmt > StrFmt_Auto)
  2538.             throw new InvalidParameterException("New string format out of valid range.");
  2539.         */
  2540.         stringformat = fmt;
  2541.     }
  2542.  
  2543.     /**
  2544.      * Returns a string saying what library this function occurs in.  If uninitialized,
  2545.      * then returns the value of Function.DefaultLib, USER32.
  2546.      * @return Library this function occurs in, or value of DefaultLib.
  2547.      */
  2548.     public String getLibrary()
  2549.     {
  2550.         return library;
  2551.     }
  2552.  
  2553.     /** 
  2554.      * Used to set the library this function occurs in.  Defaults to 
  2555.      * Function.DefaultLib, or USER32 if not set.
  2556.      * @param LibName Library name this function occurs in, ie USER32.
  2557.      * @return No return value.
  2558.      * @exception InvalidParameterException if LibName is null.
  2559.      */
  2560.     public void setLibrary(String LibName) throws InvalidParameterException
  2561.     {
  2562.         if(LibName==null)
  2563.             throw new InvalidParameterException("Function::setLibrary won't take a null library name!");
  2564.         library = LibName;
  2565.     }
  2566.  
  2567.     /**
  2568.      * Is this Function inline?  Not quite sure how useful this is, but its supported.
  2569.      * @return true if this is an inline function; else false
  2570.      */
  2571.     public boolean isInline()
  2572.     {
  2573.         return is_Inline;
  2574.     }
  2575.  
  2576.     /**
  2577.      * Is this an abstract Function?  Not quite sure how useful this is, but its supported.
  2578.      * @return true if this is an abstract function; else false
  2579.      */
  2580.     public boolean isAbstract()
  2581.     {
  2582.         return is_Inline;
  2583.     }
  2584.  
  2585.     /**
  2586.      * Sets inline flag to a value.
  2587.      * @param v Value to set inline flag to.
  2588.      * @return No return value.
  2589.      */
  2590.     public void setInline(boolean v)
  2591.     {
  2592.         is_Inline = v;
  2593.     }
  2594.  
  2595.     /**
  2596.      * Sets abstract flag to a value.
  2597.      * @param v Value to set abstract flag to.
  2598.      * @return No return value.
  2599.      */
  2600.     public void setAbstract(boolean v)
  2601.     {
  2602.         is_Abstract = v;
  2603.     }
  2604.  
  2605.     /**
  2606.      * Adds a parameter name and the type of that parameter to a function's representation.
  2607.      * Add arguments in the order addArgument is called.
  2608.      * @param Type The type of the argument.
  2609.      * @param Param The parameter name.
  2610.      * @return No return value.
  2611.      */
  2612.     public void addArgument(String Type, String Name)
  2613.     {
  2614.         if(Type.toLowerCase().equals("void"))
  2615.             return;
  2616.         Variable var = new Variable(Type, Name);
  2617.         arguments.addElement(var);
  2618.     }
  2619.  
  2620.     /**
  2621.      * Adds a Function parameter to a function's representation.
  2622.      * Add arguments in the order addArgument is called.
  2623.      * @param pfunc A Function object to add as an argument to a function.
  2624.      * @return No return value.
  2625.      */
  2626.     public void addArgument(Function pfunc)
  2627.     {
  2628.         Variable var = new Variable(pfunc);
  2629.         arguments.addElement(var);
  2630.     }
  2631.  
  2632.     /**
  2633.      * Adds a preprocessed Variable to a function's representation.
  2634.      * Add arguments in the order addArgument is called.
  2635.      * @param var A Variable containing an element to use as a parameter.
  2636.      * @return No return value.
  2637.      */
  2638.     public void addArgument(Variable var)
  2639.     {
  2640.         arguments.addElement(var);
  2641.     }
  2642.  
  2643.     /**
  2644.      * Use this to return argument i of a function.  Numbering starts at 0.
  2645.      * @param numArg number of argument to return, starting at 0.
  2646.      * @return The specified Variable object.
  2647.      * @exception ArrayIndexOutOfBoundsException if numArg is greater than the number of function arguments.
  2648.      */
  2649.     public Variable getArgument(int numArg)
  2650.     {
  2651.         return (Variable) arguments.elementAt(numArg);
  2652.     }
  2653.  
  2654.     /**
  2655.      * Returns the number of Variables added to this Function.
  2656.     * @return The number of arguments to this function.
  2657.      */
  2658.     public int getNumArgs()
  2659.     {
  2660.         return arguments.size();
  2661.     }
  2662.  
  2663.     /**
  2664.      * Print out this function in the special format for documenting functions.
  2665.      * Useful only for our internal testing tools, which may no longer exist.
  2666.      * @deprecated This function itself isn't deprecated, but its behavior is.
  2667.      * @return String representing this function.
  2668.      */
  2669.     public String toString()
  2670.     {
  2671.         String output = name + "\t" + return_type + "\r\n";
  2672.         for(int i=0; i<arguments.size(); i++) {
  2673.             Variable var = (Variable) arguments.elementAt(i);
  2674.             output = output + name + "\t" + var.Type + "\t" + var.Name + "\r\n";
  2675.         }
  2676.         return output;
  2677.     }
  2678.  
  2679.     /**
  2680.      * Converts each of the arguments into a string representation, producing a comma
  2681.      * separated list like a function prototype.
  2682.      * @return String holding all of the function's arguments and types.
  2683.      */
  2684.     protected String argsToString()
  2685.     {
  2686.         StringBuffer output = new StringBuffer("");
  2687.         for(int i=0; i<arguments.size(); i++) {
  2688.             Variable var = (Variable) arguments.elementAt(i);
  2689.             output.append(var.Type + "  " + var.Name);
  2690.             if(arguments.size()-1 != i)
  2691.                 output.append(", ");
  2692.         }
  2693.         return output.toString();
  2694.     }
  2695. }
  2696.  
  2697.  
  2698. /** 
  2699.  * Used to compare two Function objects for sorting.
  2700.  * @see com.ms.util.Comparison
  2701.  */
  2702. class FunctionCompare implements Comparison
  2703. {
  2704.     // I only need to override compare(Object, Object), but I thought I'd do this too.
  2705.     public int compare(Function a, Function b)
  2706.     {
  2707.         return a.getName().compareTo(b.getName());
  2708.     }
  2709.  
  2710.     /**
  2711.      * Compares two Function objects by calling String::compareTo on the function names.
  2712.      * @param a first Function
  2713.      * @param b second Function
  2714.      * @return a positive number if a > b, 0 if a == b, and a negative number if a < b.
  2715.      */
  2716.     public int compare(Object a, Object b)
  2717.     {
  2718.         if(!(a instanceof Function))
  2719.             return -1;
  2720.         if(!(b instanceof Function))
  2721.             return +1;
  2722.         return ((Function) a).getName().compareTo(((Function) b).getName());
  2723.     }
  2724. }
  2725.  
  2726.  
  2727. /** 
  2728.  * <p>Parser for Win32 API header files</p>
  2729.  *
  2730.  * <p>This tool was used to generate a significant portion of the Win32 API classes. 
  2731.  * It is being included for you to use and modify to fit your specific needs. Remember 
  2732.  * that C header files were not designed to be language-independent descriptions, and 
  2733.  * that there is more than one correct way to represent some data types in Java. Thus,
  2734.  * some functions will require hand-translation. For information on how to do this, 
  2735.  * see the J/Direct documentation.</p>
  2736.  *
  2737.  * <p>Notes:</p>
  2738.  * <ul>
  2739.  * <li>Currently we prefer the Unicode version of functions if possible.  This avoids the
  2740.  * overhead on NT of converting the Java string to ASCII then the ASCII wrapper 
  2741.  * converting the string back to Unicode internally.  But most of the time we will
  2742.  * output the auto keyword on structs and functions.</li>
  2743.  *
  2744.  * <li>We can't process COM libraries.  COM uses an entirely different object and 
  2745.  * function handling method.</li>
  2746.  *
  2747.  * <li>Classes and many class-like features of structs were added as an afterthought.</li>
  2748.  *
  2749.  * <li>Another thing: functions that take structs by value (not pointers to structs) will
  2750.  * be a problem.  I will have to write wrappers for them manually.  Plus I don't have a
  2751.  * good representation for them - currently, I output them incorrectly.</li>
  2752.  *
  2753.  * <li>Inside structs, we never output StringBuffers, only strings.  (required by J/Direct)</li>
  2754.  * </ul>
  2755.  *
  2756.  * @version    0.963
  2757.  */
  2758. public class Parser
  2759. {
  2760.     // EDIT THIS LINE - put your package name here.
  2761.     protected static final String PackageName = "com.ms.win32";
  2762.  
  2763.     private static final String version = "0.963";
  2764.     protected PrintWriter PuntOutput;  // Record of what we punted on.
  2765.     protected Vector Functions;          // Functions read from the header files.
  2766.     protected Vector Symbols;              // Symbols read from the DLLs.
  2767.     protected Hashtable TypeLUT;          // Translation table from C types to Java types.
  2768.     protected Hashtable StringTypes;   // String types and their conversion format.
  2769.     protected Hashtable OutputClasses; // Based on input library, determine output package.
  2770.     protected Hashtable StructureLUT;  // user-defined datatype conversion table
  2771.     protected Hashtable Precedence;    // table of C++ operator precedence.
  2772.     protected Vector IncludeHeaders;   // Do parse these files if found.
  2773.     protected Vector ExcludeHeaders;   // Do not parse these files.
  2774.     protected Vector ExcludeFunctions; // Exclude these functions from parsing.
  2775.  
  2776.     // These control a few options, like #define's might in C.
  2777.     // Look for functions in symbol files but not header files and vice versa.
  2778.     protected static final boolean ReadSymbols = true;
  2779.  
  2780.     // When true, symbols in unknown libraries aren't printed to any Java file.
  2781.     // If we don't read in the symbol files & this is true, expect empty output files.
  2782.     // If you don't read in symbols (or don't have a symbol file), this should be false.
  2783.     protected static final boolean Suppress_UnknownLib_Functions = (ReadSymbols ? true : false);
  2784.  
  2785.     // When true, output unused structures to the com.ms.win32.dead directory.
  2786.     // (An unused structure is one that never is passed to or returned by a function)
  2787.     protected static final boolean Suppress_Unused_Structures = true;
  2788.  
  2789.     // When converting odd types like void* to int, put a greppable tag in file.
  2790.     protected static final boolean Comment_Variant_Types = true;
  2791.  
  2792.     // Debug level - to prune some of the output
  2793.     protected static final int DEBUG = 2;
  2794.  
  2795.     // Use this for all anonymous function parameters, like:
  2796.     // void foo(int);   Defined in one place for customizability.
  2797.     protected static final String AnonymousString = "<anonymous>";
  2798.  
  2799.     // Use this when we don't know what file portion of the preprocessed file we're
  2800.     // currently in.
  2801.     protected static final String UnknownFileString = "<Unknown file>";
  2802.     protected static final String UnknownLibraryString = "<unknown_library>";
  2803.     protected static final String ExcludeFunctionFile = "exclude.txt";
  2804.     public static final String CallbackString = "com.ms.dll.Callback";
  2805.     protected static String CopyrightNotice = "// (C) Copyright 1995 - 1999 Microsoft Corporation.  All rights reserved.\r\n"+
  2806. "//\r\n"+
  2807. "// This software is a preview release of the Windows API Access\r\n"+
  2808. "// classes for Java. These classes provide direct, low-overhead access\r\n"+
  2809. "// to commonly used Windows API functions. These classes use the new J/Direct\r\n"+
  2810. "// feature and therefore require either Internet Explorer 4.0 or later, or the\r\n"+
  2811. "// Microsoft SDK for Java 2.0 or later.\r\n"+
  2812. "//\r\n"+
  2813. "// WARNING: These classes are still in development and are incomplete. \r\n"+
  2814. "// This preview release is being provided as-is in order to solicit feedback\r\n"+
  2815. "// and to assist developers in the use of J/Direct by providing a library\r\n"+
  2816. "// of prewritten declarations for the most common Win32 API functions. As with\r\n"+
  2817. "// all prerelease software, it is subject to significant change without notice\r\n"+
  2818. "// before shipping. \r\n"+
  2819. "//\r\n"+
  2820. "// Information on how to use J/Direct to write your own declarations\r\n"+
  2821. "// can be found in the Microsoft SDK for Java 2.0 or later.";
  2822.  
  2823.     public Parser()
  2824.     {
  2825.         PopulateTypeLUT();
  2826.         SetupFileFilters();
  2827.         SetStringTypes();
  2828.         SetupOutputClasses();
  2829.         SetupPrecedenceTable();
  2830.         StructureLUT = new Hashtable();  // empty - filled by program.
  2831.         Variable.setStructureTable(StructureLUT);
  2832.         ExcludeFunctions = new Vector();
  2833.         ReadExcludeFunctions();
  2834.     }
  2835.  
  2836.     public void finalizer()
  2837.     {
  2838.         Functions = null;
  2839.         Symbols = null;
  2840.         TypeLUT = null;
  2841.         StructureLUT = null;
  2842.         Precedence = null;
  2843.         StringTypes = null;
  2844.         ExcludeHeaders = null;
  2845.         IncludeHeaders = null;
  2846.         ExcludeFunctions = null;
  2847.  
  2848.         // Write out closing '}' to all files in output classes.
  2849.         Enumeration enum = OutputClasses.elements();
  2850.         while(enum.hasMoreElements()) {
  2851.             PrintWriter s = (PrintWriter) enum.nextElement();
  2852.             s.print("\r\n}\r\n\r\n");
  2853.             s.close();
  2854.         }
  2855.         OutputClasses = null;
  2856.         PuntOutput.close();
  2857.         PuntOutput = null;
  2858.     }
  2859.  
  2860.     /**
  2861.      * Reads through list of functions to exclude, in the file described by 
  2862.      * ExcludeFunctionFile.
  2863.      * @return No return value.
  2864.      */
  2865.     protected void ReadExcludeFunctions()
  2866.     {
  2867.         try { 
  2868.             PuntOutput = new PrintWriter(new FileOutputStream("punt.txt")); 
  2869.             StreamTokenizer st = new StreamTokenizer(new InputStreamReader(new FileInputStream(ExcludeFunctionFile)));
  2870.             st.eolIsSignificant(false);
  2871.             st.wordChars('_', '_');
  2872.             while(st.nextToken() != st.TT_EOF) {
  2873.                 if(st.ttype == st.TT_WORD)
  2874.                     ExcludeFunctions.addElement(st.sval);
  2875.             }
  2876.             st = null;
  2877.         }
  2878.         catch (FileNotFoundException e)
  2879.         {
  2880.             System.out.println("Can't find exclude functions file "+ExcludeFunctionFile);
  2881.             System.out.println(e);
  2882.         }
  2883.         catch (IOException e)
  2884.         {
  2885.             System.out.println(e);
  2886.             e.printStackTrace();
  2887.         }
  2888.     }
  2889.  
  2890.  
  2891.     /**
  2892.      * Prints the command line syntax to stdout.
  2893.      * @return No return value.
  2894.      */
  2895.     public static final void usage()
  2896.     {
  2897.         System.out.println("This program takes a preprocessed Win32 API header file and creates");
  2898.         System.out.println("another file storing the functions and all of their argument");
  2899.         System.out.println("types and variable names.  It also converts the structs into Java");
  2900.         System.out.println("classes, for moderately complex types.  It would be very useful if");
  2901.         System.out.println("you ran dumpbin /exports on your DLL and listed the name of that");
  2902.         System.out.println("symbol file in symbolfiles.txt in this directory.");
  2903.         System.out.println("Output files include the original plus a .parse extention and many");
  2904.         System.out.println("files in .\\com\\ms\\win32, as well as a few .txt files in this dir.");
  2905.         System.out.println("");
  2906.         System.out.println("Usage:");
  2907.         System.out.println("Parser <file1> [<file2> .. <fileN>]\r\n");
  2908.     }
  2909.  
  2910.  
  2911.     /** 
  2912.      * Inserts C type names and their corresponding Java types into TypeLUT, this class's
  2913.      * internal hashtable.  Edit this function if you want to handle another type name
  2914.      * in a different way.
  2915.      * <p>
  2916.      * Tricky types are handled by leaving their type names as they were.  Then you
  2917.      * are forced to deal with them yourself when you try to compile the resulting file.
  2918.      * <p>
  2919.      * Took out most pointer to function types, hoping to recognize those at runtime.  
  2920.      * They need some special case handling anyway that I don't think we can do easily.
  2921.      * @return No return value.
  2922.      */
  2923.     protected void PopulateTypeLUT()
  2924.     {
  2925.         TypeLUT = new Hashtable();
  2926.         Variable.setPrimitiveTable(TypeLUT);
  2927.         TypeLUT.put("ATOM", "short");
  2928.         TypeLUT.put("ALG_ID", "int");
  2929.         TypeLUT.put("BOOL", "boolean");      // 32-bit - This is a Java boolean
  2930.         TypeLUT.put("BOOLEAN", "byte");         // 8-bit    This should be a byte.
  2931.         TypeLUT.put("BYTE", "byte");
  2932.         TypeLUT.put("Callback", CallbackString);   // to handle some bugs?
  2933.         TypeLUT.put(CallbackString, CallbackString);   // to handle some bugs?
  2934.         TypeLUT.put("CALID", "int");
  2935.         TypeLUT.put("CALTYPE", "int");
  2936.         TypeLUT.put("CCHAR", "byte");
  2937.         TypeLUT.put("CHAR", "byte");
  2938.         TypeLUT.put("COLORREF", "int");
  2939.         TypeLUT.put("CTRYID", "short");
  2940.         TypeLUT.put("DWORD", "int");
  2941.         TypeLUT.put("DWORDLONG", "long");
  2942.         TypeLUT.put("FLOAT", "float");
  2943.         TypeLUT.put("FOURCC", "int");
  2944.  
  2945.         // OpenGL headers have prototypes for these few structs, but never actually 
  2946.         // use the structs themselves, always passing pointers.  Declare as ints?
  2947.         TypeLUT.put("GLUnurbs", "int");
  2948.         TypeLUT.put("GLUquadric", "int");
  2949.         TypeLUT.put("GLUtesselator", "int");
  2950.         TypeLUT.put("GLUtriangulatorObj", "int");
  2951.         TypeLUT.put("GLUnurbs * ", "int");
  2952.         TypeLUT.put("GLUquadric * ", "int");
  2953.         TypeLUT.put("GLUtesselator * ", "int");
  2954.         TypeLUT.put("GLUtriangulatorObj * ", "int");
  2955.  
  2956.         TypeLUT.put("GLbitfield", "int");
  2957.         TypeLUT.put("GLbyte", "byte");
  2958.         TypeLUT.put("GLboolean", "byte");
  2959.         TypeLUT.put("GLclampd", "double");
  2960.         TypeLUT.put("GLclampf", "float");
  2961.         TypeLUT.put("GLdouble", "double");
  2962.         TypeLUT.put("GLfloat", "float");
  2963.         TypeLUT.put("GLint", "int");
  2964.         TypeLUT.put("GLsizei", "int");
  2965.         TypeLUT.put("GLshort", "short");
  2966.         TypeLUT.put("GLubyte", "byte");
  2967.         TypeLUT.put("GLuint", "int");
  2968.         TypeLUT.put("GLushort", "short");
  2969.         TypeLUT.put("GLint", "int");
  2970.         TypeLUT.put("GLvoid", "void");
  2971. //        TypeLUT.put("GOBJENUMPROC", CallbackString);
  2972. //        TypeLUT.put("GRAYSTRINGPROC", CallbackString);
  2973.         TypeLUT.put("GUID", "com.ms.com._Guid");    // Special case.
  2974.         TypeLUT.put("HACCEL", "int");
  2975.         TypeLUT.put("HANDLE", "int");
  2976.         TypeLUT.put("HBITMAP", "int");
  2977.         TypeLUT.put("HBRUSH", "int");
  2978.         TypeLUT.put("HCOLORSPACE", "int");
  2979.         TypeLUT.put("HCONV", "int");
  2980.         TypeLUT.put("HCONVLIST", "int");
  2981.         TypeLUT.put("HCURSOR", "int");
  2982.         TypeLUT.put("HDC", "int");
  2983.         TypeLUT.put("HDDEDATA", "int");
  2984.         TypeLUT.put("HDESK", "int");
  2985.         TypeLUT.put("HDRVR", "int");
  2986.         TypeLUT.put("HDWP", "int");
  2987.         TypeLUT.put("HENHMETAFILE", "int");
  2988.         TypeLUT.put("HFILE", "int");
  2989.         TypeLUT.put("HFONT", "int");
  2990.         TypeLUT.put("HGDIOBJ", "int");
  2991.         TypeLUT.put("HGLOBAL", "int");
  2992.         TypeLUT.put("HGLRC", "int");
  2993.         TypeLUT.put("HHOOK", "int");
  2994.         TypeLUT.put("HICON", "int");
  2995.         TypeLUT.put("HINSTANCE", "int");
  2996.         TypeLUT.put("HKEY", "int");
  2997.         TypeLUT.put("HKL", "int");
  2998.         TypeLUT.put("HLOCAL", "int");
  2999.         TypeLUT.put("HMENU", "int");
  3000.         TypeLUT.put("HMETAFILE", "int");
  3001.         TypeLUT.put("HMIDIIN", "int");
  3002.         TypeLUT.put("HMIDIOUT", "int");
  3003.         TypeLUT.put("HMMIO", "int");
  3004.         TypeLUT.put("HMODULE", "int");
  3005.         TypeLUT.put("HOOKPROC", "int");
  3006.         TypeLUT.put("HPALETTE", "int");
  3007.         TypeLUT.put("HPEN", "int");
  3008.         TypeLUT.put("HPSTR", "StringBuffer");
  3009.         TypeLUT.put("HRESULT", "int");          // an errorcode defined as a C long.
  3010.         TypeLUT.put("HRGN", "int");
  3011.         TypeLUT.put("HRSRC", "int");
  3012.         TypeLUT.put("HSZ", "int");
  3013.         TypeLUT.put("HTASK", "int");
  3014.         TypeLUT.put("HWAVEIN", "int");
  3015.         TypeLUT.put("HWAVEOUT", "int");
  3016.         TypeLUT.put("HWINSTA", "int");
  3017.         TypeLUT.put("HWND", "int");
  3018.         TypeLUT.put("INT", "int");
  3019.         TypeLUT.put("LANGID", "short");
  3020.         TypeLUT.put("LARGE_INTEGER", "long");
  3021.         TypeLUT.put("LCID", "int");
  3022.         TypeLUT.put("LCTYPE", "int");
  3023.         TypeLUT.put("LINEDDAPROC", "LINEDDAPROC");
  3024.         TypeLUT.put("LONG", "int");
  3025.         TypeLUT.put("LONGLONG", "long");
  3026.         TypeLUT.put("LP", "StringBuffer");
  3027.         TypeLUT.put("LPARAM", "int");
  3028.         TypeLUT.put("LPBOOL", "boolean[]");
  3029.         TypeLUT.put("LPBOOLEAN", "int[]");
  3030.         TypeLUT.put("LPBYTE", "byte[] /* BUGBUG: LPBYTE */");
  3031.         TypeLUT.put("LPCBOOL", "boolean[]");
  3032.         TypeLUT.put("LPCBOOLEAN", "byte[]");
  3033.         TypeLUT.put("LPCCH", "String");
  3034. //        TypeLUT.put("LPCCHOOKPROC", CallbackString);
  3035. //        TypeLUT.put("LPCFHOOKPROC", CallbackString);
  3036.         TypeLUT.put("LPCH", "StringBuffer");
  3037.         TypeLUT.put("LPCOLESTR", "String");
  3038.         TypeLUT.put("LPCOLORREF", "int[]");
  3039.         TypeLUT.put("LPCSTR", "String");
  3040.         TypeLUT.put("LPCTSTR", "String");
  3041.         TypeLUT.put("LPCVOID", "int");
  3042.         TypeLUT.put("LPCWCH", "String");
  3043.         TypeLUT.put("LPCWSTR", "String");
  3044.         TypeLUT.put("LPDWORD", "int[]");
  3045.         TypeLUT.put("LPHANDLE", "int[]");
  3046.         TypeLUT.put("LPHWAVEIN", "int[]");
  3047.         TypeLUT.put("LPHWAVEOUT", "int[]");
  3048.         TypeLUT.put("LPINT", "int[]");
  3049.         TypeLUT.put("LPLONG", "int[]");
  3050.         TypeLUT.put("LPOLESTR", "StringBuffer");
  3051.         TypeLUT.put("LPSTR", "StringBuffer");
  3052.         TypeLUT.put("LPTCH", "StringBuffer");
  3053.         TypeLUT.put("LPTSTR", "StringBuffer");
  3054.         TypeLUT.put("LPUINT", "int[]");
  3055.         TypeLUT.put("LPVOID", "int");
  3056.         TypeLUT.put("LPWCH", "StringBuffer");
  3057.         TypeLUT.put("LPWORD", "short[]");
  3058.         TypeLUT.put("LPWSTR", "StringBuffer");
  3059.         TypeLUT.put("LRESULT", "int");
  3060.         TypeLUT.put("LUID", "long");
  3061.         TypeLUT.put("MCIDEVICEID", "int");
  3062.         TypeLUT.put("MCIERROR", "int");
  3063.         TypeLUT.put("MMRESULT", "int");
  3064.         TypeLUT.put("NPSTR", "StringBuffer");
  3065.         TypeLUT.put("NWPSTR", "StringBuffer");
  3066.         TypeLUT.put("OLECHAR", "char");
  3067.         TypeLUT.put("PBOOL", "boolean[]");
  3068.         TypeLUT.put("PBOOLEAN", "byte[]");
  3069.         TypeLUT.put("PBYTE", "byte[] /* BUGBUG: PBYTE */");
  3070.         TypeLUT.put("PCCH", "String");
  3071.         TypeLUT.put("PCH", "StringBuffer");
  3072.         TypeLUT.put("PCHAR", "StringBuffer");
  3073.         TypeLUT.put("PCSTR", "String");
  3074.         TypeLUT.put("PCWCH", "String");
  3075.         TypeLUT.put("PCWSTR", "String");
  3076.         TypeLUT.put("PDWORD", "int[]");
  3077.         TypeLUT.put("PFLOAT", "float[]");
  3078.         TypeLUT.put("PHANDLE", "int[]");
  3079.         TypeLUT.put("PHKEY", "int[]");
  3080.         TypeLUT.put("PINT", "int[]");
  3081.         TypeLUT.put("PLARGE_INTEGER", "long[]");
  3082.         TypeLUT.put("PLONG", "int[]");
  3083.         TypeLUT.put("PLUID", "long[]");
  3084.         TypeLUT.put("PSECURITY_DESCRIPTOR_CONTROL", "short[]");
  3085.         TypeLUT.put("PSECURITY_INFORMATION", "int[]");
  3086.         TypeLUT.put("PSHORT", "short[]");
  3087. //        TypeLUT.put("PSID", "int");
  3088.         TypeLUT.put("PSID_NAME_USE", "int[]");
  3089.         TypeLUT.put("PSTR", "StringBuffer");
  3090.         TypeLUT.put("PSZ", "StringBuffer");
  3091.         TypeLUT.put("PTCH", "StringBuffer");
  3092.         TypeLUT.put("PTCHAR", "StringBuffer");
  3093.         TypeLUT.put("PTSTR", "StringBuffer");
  3094.         TypeLUT.put("PUCHAR", "StringBuffer");
  3095.         TypeLUT.put("PUINT", "int[]");
  3096.         TypeLUT.put("PULARGE_INTEGER", "long[]");
  3097.         TypeLUT.put("PULONG", "int[]");
  3098.         TypeLUT.put("PUSHORT", "short[]");
  3099.         TypeLUT.put("PVOID", "int");
  3100.         TypeLUT.put("PWCH", "StringBuffer");
  3101.         TypeLUT.put("PWCHAR", "StringBuffer");
  3102.         TypeLUT.put("PWORD", "short[]");
  3103.         TypeLUT.put("PWSTR", "StringBuffer");
  3104.         TypeLUT.put("REGSAM", "int");
  3105.         TypeLUT.put("SC_HANDLE", "int");
  3106.         TypeLUT.put("SECURITY_DESCRIPTOR_CONTROL", "short");
  3107.         TypeLUT.put("SERVICE_STATUS_HANDLE", "int");
  3108.         TypeLUT.put("SHORT", "short");
  3109.         TypeLUT.put("SPHANDLE", "int");
  3110.         TypeLUT.put("TCHAR", "char");
  3111.         TypeLUT.put("UCHAR", "char");
  3112.         TypeLUT.put("UINT", "int");
  3113.         TypeLUT.put("ULARGE_INTEGER", "long");
  3114.         TypeLUT.put("ULONG", "int");
  3115.         TypeLUT.put("USHORT", "short");
  3116.         TypeLUT.put("VOID", "void");
  3117.         TypeLUT.put("WCHAR", "char");
  3118.         TypeLUT.put("WORD", "short");
  3119.         TypeLUT.put("WPARAM", "int");
  3120.         // Real primitives
  3121.         TypeLUT.put("int", "int");
  3122.         TypeLUT.put("short", "short");
  3123.         TypeLUT.put("long", "int");
  3124.         TypeLUT.put("bool *", "boolean[]");
  3125.         TypeLUT.put("boolean *", "byte[]");
  3126.         TypeLUT.put("char", "char");
  3127.         TypeLUT.put("char *", "StringBuffer");
  3128.         TypeLUT.put("char * ", "StringBuffer");
  3129.         TypeLUT.put("size_t", "int");
  3130.         TypeLUT.put("void", "void");
  3131.         TypeLUT.put("void *", "int");
  3132.         TypeLUT.put("wchar_t", "char");
  3133.         TypeLUT.put("wctype_t", "char");
  3134.         TypeLUT.put("wint_t", "char");  // defined as wchar_t
  3135.         TypeLUT.put("float", "float");
  3136.         TypeLUT.put("double", "double");
  3137.         TypeLUT.put("__int8", "byte");  // VC++ supports these.
  3138.         TypeLUT.put("__int16", "short");
  3139.         TypeLUT.put("__int32", "int");
  3140.         TypeLUT.put("__int64", "long");
  3141.  
  3142.         // Nasty hacks for opaque structs
  3143.         TypeLUT.put("_PSP", "int");
  3144.         TypeLUT.put("HPROPSHEETPAGE", "int");
  3145.         TypeLUT.put("_PROPSHEETPAGEA", "int");
  3146.         TypeLUT.put("_PROPSHEETPAGEW", "int");
  3147.         TypeLUT.put("_IMAGELIST", "int");
  3148.         TypeLUT.put("HIMAGELIST", "int");
  3149.         TypeLUT.put("HTREEITEM", "int");
  3150.  
  3151.         if(DEBUG>4)
  3152.             System.out.println("After filling, Type lookup table size = " + TypeLUT.size());
  3153.     }
  3154.  
  3155.     /**
  3156.      * Fills the StringTypes Hashtable with all String types and how to convert them from
  3157.      * Unicode to whatever format is needed.  Punts on TCHAR and derivatives, setting 
  3158.      * them to auto.
  3159.      * @return No return value.
  3160.      */
  3161.     protected void SetStringTypes()
  3162.     {
  3163.         StringTypes = new Hashtable();
  3164.  
  3165.         Array.setStringTable(StringTypes);
  3166.  
  3167.         StringTypes.put("char", "ansi");
  3168.         StringTypes.put("char *", "ansi");
  3169.         StringTypes.put("char * ", "ansi");
  3170.         StringTypes.put("CCHAR", "ansi");
  3171.         StringTypes.put("CHAR", "ansi");
  3172.         StringTypes.put("LP", "unicode");
  3173.         StringTypes.put("LPCCH", "ansi");
  3174.         StringTypes.put("LPCH", "ansi");
  3175.         StringTypes.put("LPCSTR", "ansi");
  3176.         StringTypes.put("LPCWCH", "unicode");
  3177.         StringTypes.put("LPCWSTR", "unicode");
  3178.         StringTypes.put("LPTSTR", "auto");  // may not need to be converted...
  3179.         StringTypes.put("LPSTR", "ansi");
  3180.         StringTypes.put("LPTCH", "auto");   // may not need to be converted.
  3181.         StringTypes.put("LPTSTR", "auto");  // may not need to be converted.
  3182.         StringTypes.put("LPWCH", "unicode");
  3183.         StringTypes.put("LPWSTR", "unicode");
  3184.         StringTypes.put("NPSTR", "ansi");
  3185.         StringTypes.put("NWPSTR", "unicode");
  3186.         StringTypes.put("PCCH", "ansi");
  3187.         StringTypes.put("PCH", "ansi");
  3188.         StringTypes.put("PCHAR", "ansi");
  3189.         StringTypes.put("PCSTR", "ansi");
  3190.         StringTypes.put("PCWCH", "unicode");
  3191.         StringTypes.put("PCWSTR", "unicode");
  3192.         StringTypes.put("PSTR", "ansi");
  3193.         StringTypes.put("PSZ", "ansi");
  3194.         StringTypes.put("PTCH", "auto");    // may not need to be converted.
  3195.         StringTypes.put("PTCHAR", "auto");  // may not need to be converted.
  3196.         StringTypes.put("PTSTR", "auto");   // may not need to be converted.
  3197.         StringTypes.put("PWCH", "unicode");
  3198.         StringTypes.put("PWCHAR", "unicode");
  3199.         StringTypes.put("PWSTR", "unicode");
  3200.         StringTypes.put("TCHAR", "auto");   // may not need to be converted.
  3201.         StringTypes.put("UCHAR", "ansi");
  3202.         StringTypes.put("WCHAR", "unicode");
  3203.         StringTypes.put("wchar_t", "unicode");
  3204.         StringTypes.put("wctype_t", "unicode");
  3205.         StringTypes.put("wint_t", "unicode");
  3206.     }
  3207.  
  3208.  
  3209.     /**
  3210.      * Converts all functions and structures from C to Java.
  3211.      * @return No return value.
  3212.      */
  3213.     public void Convert() throws InvalidParameterException
  3214.     {
  3215.         try {
  3216.             for(int i=0; i<Functions.size(); i++) {
  3217.                 Function func = (Function) Functions.elementAt(i);
  3218.                 OutputToClassFile(func);
  3219.             }
  3220.  
  3221.             Enumeration e = StructureLUT.elements();
  3222.             Vector Structures = new Vector();
  3223.             while(e.hasMoreElements()) {
  3224.                 multiFieldDataStructure data = (multiFieldDataStructure) e.nextElement();
  3225.                 if(!Structures.contains(data))
  3226.                     Structures.addElement(data);
  3227.             }
  3228.             System.out.print("Sorting data structures... ");
  3229.             com.ms.util.VectorSort.sort(Structures, new multiFieldDataStructureCompare());
  3230.             System.out.print("outputting... ");
  3231.             for(int i=0; i<Structures.size(); i++) {
  3232.                 //String javaclass = ConvertStruct((Struct)Structures.elementAt(i));
  3233.                 multiFieldDataStructure data = (multiFieldDataStructure) Structures.elementAt(i);
  3234.                 if(data.isUnion()) { // Punting on all unions.
  3235.                     PuntOutput.println("Punting on union: "+data.getName());
  3236.                     continue;
  3237.                 }
  3238.                 if(data.containsUnion()) { // Punt on structures containing unions.
  3239.                     PuntOutput.println("Punting on structure containing a union: "+data.getName());
  3240.                     continue;
  3241.                 }
  3242.  
  3243.                 PrintWriter out;
  3244.                 if(Suppress_Unused_Structures && !data.isUsed())
  3245.                     out = new PrintWriter(new FileOutputStream("com\\ms\\win32\\dead\\"+data.getName()+".java"));
  3246.                 else
  3247.                     out = new PrintWriter(new FileOutputStream("com\\ms\\win32\\"+data.getName()+".java"));
  3248.                 out.print(CopyrightNotice+"\r\n\r\npackage "+PackageName+";\r\n\r\n");
  3249.                 String javaclass = data.toJavaString(false);
  3250.                 out.print(javaclass + "\r\n");
  3251.                 out.close();
  3252.             }
  3253.             System.out.println("Done.");
  3254.         }
  3255.         catch (IOException e) {
  3256.             System.out.println("Convert hit a snag: " + e);
  3257.         }
  3258.     }
  3259.     
  3260.  
  3261.     /**
  3262.      * Writes out a Function to the correct class file for that function.
  3263.      * @param func Function to write to a class.
  3264.      * @return No return value.
  3265.      * @exception InvalidParameterException if func is null.
  3266.      */
  3267.     protected void OutputToClassFile(Function func) throws InvalidParameterException
  3268.     {
  3269.         if(func==null)
  3270.             throw new InvalidParameterException("OutputToClassFile won't take a null function!");
  3271.         String lib = func.getLibrary();
  3272.         PrintWriter file = (PrintWriter) OutputClasses.get(lib);
  3273.         if(file == null) {
  3274.             System.out.println("Ack!  No file for functions in DLL " + lib);
  3275.             return;
  3276.         }
  3277.  
  3278.         String javaFunc = ConvertFunction(func);
  3279.         if(javaFunc != null)
  3280.             file.print(javaFunc + "\r\n\r\n");
  3281.     }
  3282.  
  3283.  
  3284.     /**
  3285.      * Converts a C function prototype to a Java wrapper.
  3286.      * @param func A Function object to convert.
  3287.      * @return String of converted Java wrapper or "" if conversion failed.
  3288.      * @exception InvalidParameterException if func is null or messed up.
  3289.      */
  3290.     public String ConvertFunction(Function func) throws InvalidParameterException
  3291.     {
  3292.         if(func==null)
  3293.             throw new InvalidParameterException("ConvertFunction refuses to take a null parameter!");
  3294.         String javaFunc = "public native static ";
  3295.         if(func.isAbstract())
  3296.             javaFunc = "public abstract static ";
  3297.         String trailer = "";
  3298.         if(func.getReturnType() == null) {
  3299.             System.out.println("Ack! Return type was null!");
  3300.             System.out.println("Function was "+func.getName());
  3301.         }
  3302.         String javaReturn = (String) TypeLUT.get(func.getReturnType());
  3303.         if(javaReturn == null) {
  3304.             multiFieldDataStructure data = (multiFieldDataStructure) StructureLUT.get(func.getReturnType());
  3305.             if(data != null)
  3306.                 javaReturn = data.getName();
  3307.             if(javaReturn == null) {
  3308.                 javaReturn = "int /* BUGBUG: unknown type: " + func.getReturnType()+" */";
  3309.                 System.out.println("Unknown return type: "+func.getReturnType());
  3310.             }
  3311.         }
  3312. //System.out.print("ConvertFunction: "+func.getName()+"  ");
  3313.  
  3314.         // Can't return a StringBuffer
  3315.         if(javaReturn.equals("StringBuffer"))
  3316.             javaReturn = "String";
  3317.         // Now it looks like returning Strings isn't supported.  Convert to int.
  3318.         if(javaReturn.equals("String"))
  3319.             javaReturn = "int";
  3320.         // Never return a callback object, but a pointer to one as an int.
  3321.         if(javaReturn.equals(CallbackString))
  3322.             javaReturn = "int";
  3323.  
  3324.         javaFunc = javaFunc + javaReturn + " " + func.getName() + " (";
  3325.  
  3326.         // Check to see if this function should be excluded.
  3327.         if(ExcludeFunctions.contains(func.getName())) {
  3328.             System.out.println("Excluding function "+func.getName());
  3329.             javaFunc = "/* BUGBUG - explicitly excluded */ /* "+ javaFunc;
  3330.             trailer = " */";
  3331.         }
  3332.  
  3333.         // We considered outputting JavaDoc comments for every function, but there were a few
  3334.         // problems with the idea.  Any anonymous parameters would still need to be edited,
  3335.         // text descriptions should be added to all variables, and they double the size of our
  3336.         // code for no particularly good reason (they're kinda useless right now).  But
  3337.         // if you want to add a standard version of a JavaDoc comment, uncomment some of the
  3338.         // lines below here.
  3339.         String header = "";//"\t/** Calls the Win32 function "+func.getName() +"\r\n";
  3340.  
  3341.         try {
  3342.             for(int i=0; i<func.getNumArgs(); i++) {
  3343.                 Variable var = func.getArgument(i);
  3344.                 if(var==null)
  3345.                     throw new InvalidParameterException("Function "+func.getName()+"'s argument "+i+" was null!");
  3346.                 if(var.Type==null)
  3347.                     throw new InvalidParameterException("Function "+func.getName()+"'s argument "+i+"'s Type was null!");
  3348.  
  3349.                 if(var.isVarArg())  // comment out vararg functions.
  3350.                     javaFunc = "// BUGBUG: Variable Arguments "+javaFunc;
  3351.  
  3352.                 // All of the next lines dealing with data are for 2 purposes.
  3353.                 // They skip functions that have Union parameters or structs containing unions
  3354.                 // and they mark structures as "in use".  If a structure isn't used by
  3355.                 // a function I'm processing, let's skip it.
  3356.                 multiFieldDataStructure data = null;
  3357.                 if(var.ismultiFieldDataStructure())
  3358.                     data = (multiFieldDataStructure) var.getmultiFieldDataStructure();
  3359.                 else
  3360.                     data = (multiFieldDataStructure) StructureLUT.get(var.Type);
  3361.                 if(data==null) {
  3362.                     StringTokenizer st = new StringTokenizer(var.Type);
  3363.                     do {
  3364.                         String token = st.nextToken();
  3365.                         if(token.equals("const"))
  3366.                             continue;
  3367.                         data = (multiFieldDataStructure) StructureLUT.get(token);
  3368.                     } while (data==null && st.hasMoreTokens());
  3369.                 }
  3370.  
  3371.                 if(data != null) {
  3372.                     if(data.isUnion() || data.containsUnion()) {
  3373.                         PuntOutput.println("Punting on a function that takes a union or a struct containing a union: "+func.getName());
  3374.                         return "// "+func.getName()+" took a parameter that either was or contained a union.";
  3375.                     }
  3376.                     if(Suppress_Unused_Structures)
  3377.                         data.Use();  // Mark that a function uses this data structure.
  3378.                 }
  3379.  
  3380.                 String jArg = ConvertArgumentType(var, func);
  3381.                 // For now, assume if we can't convert the type, the function is unusable.
  3382.                 if(jArg == null)
  3383.                     return "";
  3384.  
  3385.                 String ParamName = (AnonymousString.equals(var.Name) ? "anon"+i : var.Name);
  3386.                 if(ParamName.equals(multiFieldDataStructure.anonymous)) {
  3387.                     ParamName = "anonymous_struct"+i;
  3388.                 }
  3389.                 // Add a line into the comments describing the parameter.
  3390.                 //header = header + "\t * @param "+ParamName+" Empty\r\n";
  3391.                 javaFunc = javaFunc + jArg + " " + ParamName;
  3392.                 if(i+1<func.getNumArgs())
  3393.                     javaFunc = javaFunc + ", ";        
  3394.             }
  3395.         }
  3396.         catch (UnrecognizedCodeException e) {
  3397.             System.out.println("Caught Unrecognized Code: " +e+"\r\n"+ e.BadFragment);
  3398.             System.out.println("Function was " + func.toString());
  3399.             return "";
  3400.         }
  3401.         javaFunc = javaFunc + ");";
  3402.  
  3403.         // Add return type to comments...
  3404.         /*
  3405.         header = header + "\t * @return ";
  3406.         if(javaReturn.equals("void"))
  3407.             header = header + "No return value.\r\n";
  3408.         else
  3409.             header = header + javaReturn +"\r\n";
  3410.         */
  3411.  
  3412.         // Tack in @dll.import line...
  3413.         String libname = func.getLibrary();
  3414.         if(Suppress_UnknownLib_Functions && libname.equals(UnknownLibraryString)) {
  3415.             PuntOutput.println("Punting on "+func.getName()+" because we can't find out what DLL it was in!");
  3416.             return null;
  3417.         }
  3418.  
  3419.         //header = header +"\t * @dll.import(\"" + libname + "\"";
  3420.         header = "\t/** @dll.import(\"" + libname + "\"";
  3421.         switch(func.getStringFormat()) {
  3422.         case Function.StrFmt_Unknown: break;
  3423.         case Function.StrFmt_ANSI: header = header + ", ansi"; break;
  3424.         case Function.StrFmt_Unicode: header = header + ", unicode"; break;
  3425.         case Function.StrFmt_Auto: header = header + ", auto"; break;
  3426.         default: 
  3427.             System.out.println("Ack!  Fell through switch statement in ConvertFunction!");
  3428.         }
  3429.         //header = header + ")\r\n\t */\r\n\t";
  3430.         header = header + ") */\r\n\t";
  3431.         javaFunc = header + javaFunc + trailer;
  3432. //System.out.println("Done w/ "+func.getName());
  3433.         return javaFunc;
  3434.     }
  3435.  
  3436.     
  3437.     /**
  3438.      * Converts a C function argument's type into the equivalent Java type.  Also 
  3439.      * determines how to do any string conversion (Ansi vs. Unicode) by setting
  3440.      * function's stringformat.
  3441.      * @param var Variable object to convert
  3442.      * @param func Function containing this Variable
  3443.      * @return String holding Java type name.
  3444.      * @exception UnrecognizedCodeException if cannot convert argument's C type to Java.
  3445.      */
  3446.     public String ConvertArgumentType(Variable var, Function func) throws UnrecognizedCodeException, InvalidParameterException
  3447.     {
  3448.         if(var == null)
  3449.             throw new InvalidParameterException("Got passed NULL Variable!");
  3450.         if(func == null)
  3451.             throw new InvalidParameterException("Got passed NULL Function!");
  3452.  
  3453.         String CType = var.Type;
  3454.         String JType = "";
  3455.         JType = (String) TypeLUT.get(CType);
  3456.  
  3457.         String format = (String) StringTypes.get(CType);
  3458.         if(format != null) {
  3459.             //System.out.println("Found a " + format + " parameter in " + func.getName());
  3460.             if(format.equals("ansi"))
  3461.                 func.setStringFormat(Function.StrFmt_ANSI);
  3462.             else if(format.equals("unicode"))  // Unicode functions aren't implemented in Win95.
  3463.                 func.setStringFormat(Function.StrFmt_Auto);
  3464.             else if(format.equals("auto"))
  3465.                 func.setStringFormat(Function.StrFmt_Auto);
  3466.             else
  3467.                 System.out.println("Ack!  What kind of String format is this???  " + format);
  3468.         }
  3469.  
  3470.         // When converting some of the types with more exotic uses, such as LPBYTE, print
  3471.         // out a message.  Or at least make this message disable-able.
  3472.         if(Comment_Variant_Types) {
  3473.             if("LPBYTE".equals(CType) || "PBYTE".equals(CType) || CType.startsWith("BYTE *")) {
  3474.                 JType = "byte[] /* BUGBUG: "+CType+" */";
  3475.             }
  3476.         }
  3477.  
  3478.  
  3479.         if(JType != null)
  3480.             return JType;
  3481.  
  3482.         // Handle case of pointers to functions here.
  3483.         if(var.isFunction()) {
  3484.             return CallbackString;
  3485.         }
  3486.  
  3487.         // Handle trickier cases, parsing * and modifiers like const.
  3488.         StringTokenizer st = new StringTokenizer(CType);
  3489.         /* Rules:
  3490.          * If it's a char *, convert to StringBuffer, unless const is in effect.
  3491.          * 
  3492.          * If it's a pointer, convert it to an integer.
  3493.          * Otherwise, write out the type as-is and print a warning.
  3494.          */
  3495.         JType = null;
  3496.         boolean isConst = false;
  3497.         boolean isChar = false;   // strictly if this is a character type.
  3498.         boolean isString = false; // if this is a pointer to a character or char[].
  3499.         boolean isPtr = false;    // if this a pointer?
  3500.         boolean isReference = false;
  3501.         boolean isStruct = false;
  3502.         while(st.hasMoreTokens()) {
  3503.             String token = st.nextToken();
  3504.             //System.out.print("token \""+token+"\"");
  3505.             if(token.equals("const")) {
  3506.                 isConst = true;
  3507.                 continue;
  3508.             }
  3509.             if(token.equals("&")) {
  3510.                 isReference = true;
  3511.             }
  3512.             // If its a pointer...
  3513.             if(token.equals("*")) {
  3514.                 isPtr = true;
  3515.                 //System.out.print(" Found pointer. JType=\""+JType+"\" ");
  3516.                 if(isChar) {
  3517.                     JType = (isConst ? "String" : "StringBuffer");
  3518.                     isString = true;
  3519.                     isChar = false;
  3520.                     isPtr = false;
  3521.                     continue;
  3522.                 }
  3523.                 if(isString) {
  3524.                     //System.out.println("Fixup: Found a pointer to a "+JType+"! Changing to int. CType was: "+CType);
  3525.                     JType = "int /* BUGBUG: "+CType+" */";
  3526.                     continue;
  3527.                 }
  3528.                 //System.out.println("Before *, JType was " + JType);
  3529.                 if(JType != null && !isStruct)
  3530.                     JType = JType + "[]";
  3531.                 /*
  3532.                 else
  3533.                     throw new UnrecognizedCodeException("Ack! Null JType or * in wrong place!");
  3534.                 */
  3535.                 continue;
  3536.             }
  3537.             if(token.equals("char")) {
  3538.                 isChar = true;
  3539.                 continue;
  3540.             }
  3541.             // if its a struct keyword, look up structure.
  3542.             if(token.equals("struct")) {
  3543.                 //System.out.println("Found struct keyword in type...");
  3544.                 token = st.nextToken();
  3545.                 isStruct = true;
  3546.             }
  3547.             // Special case: GUID
  3548.             if(token.equals("GUID")) {
  3549.                 JType = (String) TypeLUT.get("GUID");
  3550.                 break;
  3551.             }
  3552.             // New normal Primitive lookup.
  3553.             if(JType == null) {
  3554.                 JType = (String) TypeLUT.get(token);
  3555.                 //System.out.println("primitive lookup on "+token+" returned "+JType);
  3556.                 if(JType != null) {
  3557.                     isChar = isChar || JType.equals("char");
  3558.                     isString = isString || JType.startsWith("String");
  3559.                     continue;
  3560.                 }
  3561.             }
  3562.             // Look up in StructureLUT.
  3563.             if(true) {
  3564.                 String name = token;
  3565.                 multiFieldDataStructure data = (multiFieldDataStructure) StructureLUT.get(name);
  3566.                 if(data!=null) {
  3567.                     //System.out.print("Found a structure in StructureLUT named "+data.getName());
  3568.                     JType = data.getName();
  3569.                     isStruct = true;
  3570.                 }
  3571.                 else
  3572.                     if(isStruct)
  3573.                         JType = "structure_" + name;
  3574.                 continue;
  3575.             }
  3576.             // Try to save something.  Fortunately this never gets used, as far as I can tell.
  3577.             if(JType == null) {
  3578.                 JType = (String) TypeLUT.get(token);
  3579.                 //System.out.println("special late Type lookup on \""+token+"\" returned \""+JType+"\"");
  3580.                 if(JType == null) { // special lookup rules
  3581.                     if(token.startsWith("H"))  // Handle
  3582.                         JType = "int /* BUGBUG: guessing for "+token+" */";
  3583.                     else if(token.startsWith("LPC")) { // constant pointer
  3584.                         isConst = true;
  3585.                         JType = "int /* BUGBUG: guessing for "+token+" */";
  3586.                     }
  3587.                     else if(token.startsWith("LP"))  // pointer
  3588.                         JType = "int /* BUGBUG: guessing for "+token+" */";
  3589.                 } // end special lookup rules
  3590.                 if(JType == null)  // Just can't deal with it.
  3591.                     throw new UnrecognizedCodeException("Can't handle type " + CType);
  3592.             }
  3593.             else
  3594.                 System.out.println("Hit bottom of convertargumenttype's while loop. JType="+JType);
  3595.         }  // end while
  3596.  
  3597.         if(CType.equals("")) {
  3598.             System.out.println("Ack!  CType was \"\"!!!!");
  3599.             throw new UnrecognizedCodeException("function argument of unknowable type");
  3600.         }
  3601.  
  3602.         // last-minute fix-up for strings and void[]'s.
  3603.         if(JType != null) {
  3604.             if(JType.equals("char[]"))
  3605.                 JType = "StringBuffer";
  3606.             
  3607.             if(JType.equals("void[][]"))
  3608.                 JType = "int /* BUGBUG: "+CType+" */";
  3609.  
  3610.             if(JType.equals("void[]"))
  3611.                 JType = "int[] /* BUGBUG: "+CType+" */";
  3612.  
  3613.             // Shouldn't happen often, but we'll leave this in here...
  3614.             if(JType.equals("null[]") || JType.equals("null[][]"))
  3615.                 throw new UnrecognizedCodeException("null array! CType was \""+CType+"\"  JType was " + JType);
  3616.         }
  3617.         else {
  3618.             System.out.println("Unrecognized C type \""+CType+"\".  Giving up.");
  3619.             //JType = "<"+CType+">";
  3620.             return null;
  3621.         }
  3622.         //System.out.println("Returning java type " + JType);
  3623.         return JType;
  3624.     } // end ConvertArgumentType(String)
  3625.  
  3626.  
  3627.     /** 
  3628.      * Parsefile(String) reads in the filename you pass it, stores the functions and
  3629.      * structures from that file in a vector of functions or a hash table of structures.  
  3630.      * This is the main input processing function.
  3631.      * @param FileIn Filename to parse.
  3632.      * @return No return value.
  3633.      * @exception UnrecognizedCodeException if there was a parsing problem.
  3634.      * @exception InvalidParameterException if there's a problem with a function called by this one.
  3635.      */
  3636.     public void ParseFile(String FileIn) throws UnrecognizedCodeException, InvalidParameterException
  3637.     {
  3638.         // CurrentFile is the file within FileIn we're reading through.  Here we assume
  3639.         // FileIn is the output of the C preprocessor.  We'll ignore some files and examine
  3640.         // others.
  3641.         String CurrentFile = UnknownFileString;
  3642.         Stack packsize = new Stack();
  3643.         packsize.push(new PackContainer(8, "VC++ Default Pack size"));  // VC defaults to 8-byte alignment
  3644.         InputStreamReader isr = null;
  3645.         try {
  3646.             Functions = new Vector();
  3647.             isr = new InputStreamReader((InputStream) new FileInputStream(FileIn));
  3648.  
  3649.             StreamTokenizer st = new StreamTokenizer(isr);
  3650.             st.eolIsSignificant(false);
  3651.             st.ordinaryChar('/');
  3652.             st.slashStarComments(true);
  3653.             st.slashSlashComments(true);
  3654.             // Add all the modifying characters such as *
  3655.             st.ordinaryChar('*');
  3656.             st.ordinaryChar('(');
  3657.             st.ordinaryChar(')');
  3658.             st.ordinaryChar('#');
  3659.             st.wordChars('_', '_');
  3660.             st.ordinaryChar('.');
  3661.  
  3662.             String lastString = "<unknown last string>";
  3663.  
  3664.             while (st.nextToken() != StreamTokenizer.TT_EOF) {
  3665.                 if(st.ttype == StreamTokenizer.TT_WORD) {
  3666. //                    if(st.sval.equals("WINAPI") || st.sval.equals("APIENTRY")
  3667. //                        || st.sval.equals("WINAPIV")) {
  3668.                     if(st.sval.equals("__stdcall") || st.sval.equals("__cdecl")) {
  3669.                         // Found a function
  3670.                         String keyword = st.sval;
  3671.                         st.nextToken();
  3672.                         if(st.ttype == StreamTokenizer.TT_WORD) {
  3673.                             Function func = new Function(st.sval);
  3674.                             func.setReturnType(lastString);
  3675.  
  3676.                             // Now read in parenthesis and function parameters
  3677.                             st.nextToken();
  3678.                             if(st.ttype != '(') {
  3679.                                 if(st.ttype == StreamTokenizer.TT_WORD)
  3680.                                     throw new UnrecognizedCodeException(func.getName() + ": " + st.sval);
  3681.                                 else
  3682.                                     throw new UnrecognizedCodeException(func.getName() + " had a problem.");
  3683.                             }
  3684.  
  3685.                             MungeVariables(func, st);
  3686.  
  3687.                             if(ReadSymbols)
  3688.                                 FindLibrary(func);
  3689.  
  3690.                             // If it's already in the Functions list, don't add a second copy.
  3691.                             if(findFunction(func.getName()) != null || ExcludeFunctions.contains(func.getName()))
  3692.                                 continue;
  3693.                             Functions.addElement(func);
  3694.                             //System.out.println("Added " + func.getName());
  3695.  
  3696.                         } else {
  3697.                             // Handle WINAPI in weird places, such as a typedef?
  3698.                             // These are bad states, or at least ones I didn't write code to handle.
  3699.                             if(st.ttype == ')') {
  3700.                                 throw new UnrecognizedCodeException(keyword + " trailed by ')'");
  3701.                             }
  3702.                             if(st.ttype == '*') {
  3703.                                 // Whenever we see a COM library, they invariably have a Vtbl struct
  3704.                                 // that contains pointers to functions.  I don't parse them in this format.
  3705.                                 // I see this in mapidefs.h, around IMAPIAdviseSinkVtbl
  3706.                                 throw new UnrecognizedCodeException(keyword + " trailed by '*' - maybe a COM library? (Can't parse COM)");
  3707.                             }
  3708.                             if(st.ttype == StreamTokenizer.TT_EOL) {
  3709.                                 throw new UnrecognizedCodeException(keyword + " trailed by number, num = " + st.nval);
  3710.                             }
  3711.                             throw new UnrecognizedCodeException("Unknown token following " + keyword + "\r\nType: " + ((char)st.ttype));
  3712.                         }
  3713.                     } // end WINAPI
  3714.  
  3715.                     else if(st.sval.equals("typedef")) {
  3716.                         // Note that sometimes WINAPI occurs in pointer to function typedefs.
  3717.                         st.nextToken();
  3718.                         if(st.ttype == st.TT_WORD) {
  3719.                             // Check for defining a primitive as another type name.
  3720.                             // Two possibilities - could be a pointer to a function or something
  3721.                             // like typedef int DWORD;
  3722.                             if(st.sval.equals("const") || st.sval.equals("unsigned"))
  3723.                                 st.nextToken();
  3724.                             if(TypeLUT.contains(st.sval) || TypeLUT.containsKey(st.sval)) {
  3725.                                 String old_name = st.sval;
  3726.                                 String primitive = (String) TypeLUT.get(old_name);
  3727.                                 st.nextToken();
  3728.                                 if(st.ttype == st.TT_WORD && st.sval.equals("const"))
  3729.                                     st.nextToken();
  3730.                                 if(st.ttype == '*')
  3731.                                     while(st.nextToken() == '*');
  3732.                                 if(st.ttype == '(') {// this is a pointer to a function
  3733.                                     while(st.nextToken() != '*');
  3734.                                     st.nextToken();
  3735.                                     if(st.ttype == st.TT_WORD && !TypeLUT.contains(st.sval)) {
  3736.                                         System.out.println("Adding pointer to function "+st.sval);
  3737.                                         TypeLUT.put(st.sval, CallbackString);
  3738.                                     }
  3739.                                     while(st.nextToken()!=';');
  3740.                                     continue;
  3741.                                 }
  3742.                                 if(st.ttype != st.TT_WORD)
  3743.                                     throw new UnrecognizedCodeException("typedef primitive new_primitive_name encountered something that wasn't a string! original word: "+old_name);
  3744.                                 String new_primitive = st.sval;
  3745.                                 if(!TypeLUT.containsKey(new_primitive)) {
  3746.                                     System.out.println("Adding new primitive "+new_primitive+" as "+primitive);
  3747.                                     TypeLUT.put(new_primitive, primitive);
  3748.                                 }
  3749.                                 st.nextToken();
  3750.                             }
  3751.                             // Check for being a struct or a union
  3752.                             else if(st.sval.equals("struct") || st.sval.equals("union")) {
  3753.                                 multiFieldDataStructure s = ReadStructure(st, false);
  3754.                                 if(s == null)  // a few special cases like GUID.
  3755.                                     continue;
  3756.                                 if(!packsize.isEmpty()) {  //foobie
  3757.                                     int ps = ((PackContainer) packsize.peek()).getPackSize();
  3758.                                     s.setPackSize(ps);
  3759.                                 }
  3760.  
  3761.                                 // Throw all typedef'ed names in there too!!!
  3762.                                 StructureLUT.put(s.getName(), s);
  3763.                                 for(int i=0; i<s.numAltNames(); i++)
  3764.                                     StructureLUT.put(s.getAltName(i), s);
  3765.  
  3766.                                 System.out.println("Added "+ (s.isStruct() ? "struct " : "union ") +s.getName()+"\r\n");
  3767.                             }  // end typedef struct
  3768.                             else if(StructureLUT.containsKey(st.sval)) {
  3769.                                 // This is the typedef struct_name [*] alt_name; code.
  3770.                                 multiFieldDataStructure s = (multiFieldDataStructure) StructureLUT.get(st.sval);
  3771.                                 String name = null;
  3772.                                 st.nextToken();
  3773.                                 do {
  3774.                                     if(st.ttype == '*')
  3775.                                         st.nextToken();
  3776.                                     String append = st.sval;
  3777.                                     if(st.ttype==st.TT_WORD && st.sval.equals("const"))
  3778.                                         continue;
  3779.                                     if(name==null)
  3780.                                         name = append;
  3781.                                     else
  3782.                                         name = name + append;
  3783.                                     // may not be correct - especially in the case where there are multiple typedef'ed names.
  3784.                                 } while(st.nextToken() != ';');
  3785.                                 s.addAltName(name);
  3786.                                 StructureLUT.put(name, s);
  3787.                                 System.out.println("Added alias " + name + " for " + s.getName());
  3788.                             } // typedef <struct_name> alias;
  3789.                             else if(TypeLUT.containsKey(st.sval)) {
  3790.                                 //System.out.print("Ptr to function detected, maybe.  typedef " + st.sval);
  3791.                                 st.nextToken();
  3792.                                 //System.out.println((char)st.ttype);
  3793.                                 if(st.ttype == '*')  // could return, say, void*
  3794.                                     st.nextToken();
  3795.                                 if(st.ttype == '(') {
  3796.                                     System.out.println("Found pointer to function!");
  3797.                                     while(st.nextToken() != ';');
  3798.                                 }
  3799.                             } // end typedef <type> ( <ptr-to-Function> ) ( [args] );
  3800.                             // Handle enumerated types...  This section is weak.
  3801.                             else if(st.sval.equals("enum")) {
  3802.                                 st.nextToken();
  3803.                                 if(st.ttype == st.TT_WORD) {
  3804.                                     System.out.println("Throwing in enumerated type " + st.sval);
  3805.                                     TypeLUT.put(st.sval, "int");
  3806.                                     st.nextToken();
  3807.                                 }
  3808.                                 if(st.ttype == '{') {
  3809.                                     while(st.nextToken() != '}');
  3810.                                     st.nextToken();
  3811.                                 }
  3812.                                 while(st.ttype != ';') {
  3813.                                     String alias = null;
  3814.                                     while(st.ttype != ',' && st.ttype != ';') {
  3815.                                         if(st.ttype=='*')
  3816.                                             st.nextToken();
  3817.                                         if(alias==null)
  3818.                                             alias=st.sval;
  3819.                                         else
  3820.                                             alias = alias+" "+st.sval;
  3821.                                         st.nextToken();
  3822.                                     }
  3823.                                     if(st.ttype==',')
  3824.                                         st.nextToken();
  3825.                                     System.out.println("Adding alias for enumerated type "+alias);
  3826.                                     TypeLUT.put(alias, "int");
  3827.                                 }
  3828.                             }
  3829.                             //else
  3830.                             //    System.out.println("Didn't recognize token sequence typedef "+st.sval);
  3831.                         } // end typedef <word>
  3832.                         else
  3833.                             throw new UnrecognizedCodeException("typedef what?  token was " + (char)st.ttype);
  3834.                     } // end typedef
  3835.                     else if(st.sval.equals("struct")) {
  3836.                         // Handle forward definitions of structures as ints.
  3837.                         // For cases like:  struct blah;  typedef struct blah * blahptr;
  3838.                         // And then they never define blah.  However, if a function returns a struct,
  3839.                         // it could go through this code path.  Same if they define then don't
  3840.                         // immediately typedef the struct...
  3841.                         st.nextToken();
  3842.                         if(st.ttype != st.TT_WORD)
  3843.                             throw new UnrecognizedCodeException("Thought I would read an opaque structure, but didn't!  Found non-word!");
  3844.                         String structname = st.sval;
  3845.                         st.nextToken();
  3846.                         if(st.ttype != ';') {
  3847.                             st.pushBack();
  3848.                             continue;
  3849.                             //throw new UnrecognizedCodeException("Thought I was reading an opaque struct, "+structname+", but didn't find ';' after it!");
  3850.                         }
  3851.                         //TypeLUT.put(structname, "int");
  3852.                         if(!TypeLUT.containsKey(structname)) {
  3853.                             StructureLUT.put(structname, new OpaqueStruct(structname));
  3854.                             System.out.println("Added opaque struct "+structname);
  3855.                         }
  3856.                     }
  3857.                     else if(st.sval.equals("class")) {
  3858.                         // What about forward definitions of classes????
  3859.                         multiFieldDataStructure data = ReadStructure(st, false);
  3860.                         if(data!=null) {
  3861.                             System.out.println("Adding class "+data.getName());
  3862.                             StructureLUT.put(data.getName(), data);
  3863.                         }
  3864.                     }
  3865.                     else 
  3866.                         lastString = st.sval;  // Track lastString so we know return type.
  3867.  
  3868.                 } // end is word
  3869.  
  3870.                 else if(st.ttype == '#') {
  3871.                     //System.out.println("Found a #.");
  3872.                     // Look for #line x "Current File Name"
  3873.                     // Look for #if(WINVER >= 0x0400) .. [#else ..] #endif
  3874.                     // Look for #pragma pack([push,x | pop])
  3875.                     st.nextToken();
  3876.                     if(st.ttype == StreamTokenizer.TT_WORD) {
  3877.                         if(st.sval.equals("line")) {
  3878.                             st.nextToken();
  3879.                             st.nextToken();
  3880.                             String NextFile;
  3881.                             if(st.sval.startsWith(".\\"))
  3882.                                 NextFile = st.sval.substring(2);
  3883.                             else
  3884.                                 NextFile = st.sval;
  3885.                             if(CurrentFile.equals(NextFile))
  3886.                                 continue;
  3887.                             CurrentFile = NextFile;
  3888.                             //System.out.println("Hit file marker... In " + CurrentFile);
  3889.  
  3890.                             // Aggressively skip to the next file we can parse.
  3891.                             while (!CheckFile(CurrentFile)) {
  3892.                                 //System.out.println("#line handler skipping to next file...");
  3893.                                 boolean changedFile = false;
  3894.                                 do {
  3895.                                     int ntoken;
  3896.                                     do {
  3897.                                         ntoken = st.nextToken();
  3898.                                     } while(ntoken != '#' && ntoken != StreamTokenizer.TT_EOF);
  3899.                                     if(ntoken == StreamTokenizer.TT_EOF)
  3900.                                         throw new DoneException();
  3901.                                     st.nextToken();
  3902.                                     if(st.sval != null && st.sval.equals("line")) {
  3903.                                         st.nextToken();
  3904.                                         st.nextToken();
  3905.                                         if(st.sval.startsWith(".\\"))
  3906.                                             NextFile = st.sval.substring(2);
  3907.                                         else
  3908.                                             NextFile = st.sval;
  3909.                                         if(!NextFile.equals(CurrentFile)) {
  3910.                                             CurrentFile = NextFile;
  3911.                                             //System.out.println("Changed file to " + CurrentFile);
  3912.                                             changedFile = true;
  3913.                                         }
  3914.                                     }
  3915.                                     else if(st.sval.equals("pragma")) {
  3916.                                         // Must handle pack size changes even in these files.
  3917.                                         st.nextToken();
  3918.                                         if(st.ttype == st.TT_WORD && st.sval.equals("pack"))
  3919.                                             PackHandler(st, packsize);
  3920.                                     }
  3921.                                 } while (!changedFile);
  3922.                             } // end while(!CheckFile(CurrentFile))
  3923.                         }  // end #line
  3924.                         if(st.sval.equals("pragma")) 
  3925.                         {
  3926.                             st.nextToken();
  3927.                             if(st.sval.equals("pack")) {
  3928.                                 PackHandler(st, packsize);
  3929.                             } // end #pragma pack
  3930.                             //else
  3931.                             //    System.out.println("Unrecognized pragma \"" + st.sval + "\"");
  3932.                         } // end #pragma handlers.
  3933.                     } // end # <word>
  3934.                 } // end #
  3935.  
  3936.             }  // end while
  3937.         }
  3938.         catch(DoneException e) {}
  3939.         catch(InvalidParameterException e) {
  3940.             System.out.println("Ack!  Invalid parameter exception caught in ParseFile!");
  3941.             System.out.println(e.Description);
  3942.             e.printStackTrace();
  3943.         }
  3944.         catch(IOException e) {
  3945.             System.out.println("IO Error!  CurrentFile: "+CurrentFile);
  3946.             System.out.println(e);
  3947.         }
  3948.         catch(UnrecognizedCodeException e) {
  3949.             System.out.println("Didn't recognize a code fragment in "+CurrentFile+".  Stopping parsing.");
  3950.             //System.out.println(e);
  3951.             //System.out.println(e.Description + "  " + e.BadFragment);
  3952.             //e.printStackTrace();
  3953.             throw e;
  3954.         }
  3955.         catch(NullPointerException npe) {
  3956.             System.out.println("Ack!  Caught "+npe+"!  CurrentFile: "+CurrentFile);
  3957.             npe.printStackTrace();
  3958.             throw npe;
  3959.         }
  3960.         catch(Exception e) {
  3961.             System.out.println("Uncaught exception at bottom of ParseFile(String)  CurrentFile: "+CurrentFile);
  3962.             e.printStackTrace();
  3963.             //throw e;
  3964.         }
  3965.         catch(Throwable t) {
  3966.             System.out.println("Uncaught throwable object at bottom of Parsefile!  CurrentFile: "+CurrentFile);
  3967.             System.out.println(t);
  3968.             t.printStackTrace();
  3969.         }
  3970.         finally {
  3971.             try { isr.close(); }
  3972.             catch (IOException ioe) {}
  3973.             isr = null;
  3974.             packsize = null;
  3975.             CurrentFile = null;
  3976.         }
  3977.     } // end ParseFile(String in);
  3978.  
  3979.       
  3980.     /** 
  3981.      * MungeVariables takes the current function name and a
  3982.      * StreamTokenizer positioned right after the first parenthesis.
  3983.      * It prints the function name, a tab, the type of a parameter, then
  3984.      * the parameter name on a line for every parameter.
  3985.      * <p>Example:  void WINAPI foo(int, char ch);
  3986.      * <p>Translates into:
  3987.      * <br>foo\t void
  3988.      * <br>foo\t int\t <anonymous>
  3989.      * <br>foo\t char\t ch
  3990.      * @param func Function object whose arguments are being munged.
  3991.      * @param st StreamTokenizer positioned right after beginning '(' of function arguments.
  3992.      * @return No return value.
  3993.      * @exception IOException if StreamTokenizer has a problem
  3994.      * @exception UnrecognizedCodeException if it can't parse a variable (unlikely, but possible)
  3995.      */
  3996.     protected void MungeVariables(Function func, StreamTokenizer st) throws IOException, UnrecognizedCodeException
  3997.     {
  3998.         int ntoken = st.nextToken();
  3999.         do {
  4000.             boolean addTypeandParam = true;
  4001.             String Type = new String("");
  4002.             String Name = AnonymousString;
  4003.             boolean firsttime = true;  // Used to check for anonymous args where the type has only one token.
  4004.             while(ntoken != ',' && ntoken != ')') {
  4005.                 // Invariant: Either addTypeandParam is false (pointer to function case) OR
  4006.                 //            (Type hold what we've parsed of the type so far and
  4007.                 //             Name holds data that may or may not be part of the type).
  4008.                 if(st.ttype == StreamTokenizer.TT_WORD) {
  4009.                     if(firsttime) {
  4010.                         firsttime = false;
  4011.                         Type = st.sval;
  4012.                     }
  4013.                     else {
  4014.                         if(!Name.equals(AnonymousString))
  4015.                             Type = Type+' '+Name;
  4016.                         Name = st.sval;
  4017.                     }
  4018.                 }
  4019.                 // Handle one of two variable argument syntaxes
  4020.                 if(st.ttype == '.') {
  4021.                     // Leave it in this order - remember && is short-circuited.
  4022.                     if(st.nextToken() == '.' && st.nextToken() == '.') {
  4023.                         Type = "Old-style vararg list";
  4024.                         Name = "...";
  4025.                         System.out.println("Note: Function " + func.getName() + " has a '...' argument.");
  4026.                     }
  4027.                     else {
  4028.                         System.out.println("Vararg ... test failed.  st.sval: " + st.sval + "  st.nval = " + ((char) st.nval) + "  st.ttype = " + ((char) st.ttype));
  4029.                         throw new UnrecognizedCodeException("While processing function " + func.getName() + ", found period in\r\nargument name or type and it wasn't part of a '...'");
  4030.                     }
  4031.                 }  // End var arg section.
  4032.                 if(st.ttype == '*' || st.ttype == '&') {
  4033.                     //if(st.ttype == '&')
  4034.                     //    System.out.println("Found a & in the type of one of function " + func.getName() + "'s arguments.");
  4035.                     if(!Name.equals(AnonymousString))
  4036.                         Type = Type+" "+Name;
  4037.                     // This expression was just sitting here without the assignment, which is all wrong.
  4038.                     // I think this is correct, Type=... And this probably was a major 
  4039.                     // source of bugs in my code.
  4040.                     Type = Type+' '+(char)st.ttype;
  4041.                     Name = "";
  4042.                 }
  4043.                 if(st.ttype == '(')  {  // Got a pointer to a function argument
  4044.                     Function pfunc = new Function();
  4045.                     addTypeandParam = false;
  4046.                     pfunc.setReturnType(Type);
  4047.                     pfunc.setName("Pointer-to-function-type");
  4048.                     ntoken = st.nextToken();
  4049.                     System.out.println("Found pointer to function in function " + func.getName());
  4050.                     while(st.nextToken() != ')') {
  4051.                         // throw away for now...  Lazy.
  4052.                         
  4053.                     }
  4054.                     while(st.nextToken() != '(');
  4055.                     MungeVariables(pfunc, st);
  4056.                     System.out.println("Got arguments to pointer to function...");
  4057.                     func.addArgument(pfunc);
  4058.                 }
  4059.                 ntoken = st.nextToken();
  4060.             }
  4061.             
  4062.             // If this isn't a pointer to a function...
  4063.             if(addTypeandParam && !Type.equals("")) {
  4064.                 if(Name.equals("")) {
  4065.                     //System.out.println("In function " + func.getName() + ", Name was \"\" at the end.");
  4066.                     Name = AnonymousString;
  4067.                 }
  4068.  
  4069.                 func.addArgument(Type, Name);
  4070.             }
  4071.             
  4072.             if(ntoken != ')')
  4073.                 ntoken = st.nextToken();
  4074.         } while(ntoken != ')');
  4075.  
  4076.     } // end MungeVariables
  4077.  
  4078.  
  4079.     /**
  4080.      * Parses a multiFieldDataStructure, reading in its fields, etc.  Returns the Struct
  4081.      * or Union object.
  4082.      * @param st StreamTokenizer positioned at the struct or union keyword.
  4083.      * @param insideStructure true if ReadStructure is nested in a struct or union.
  4084.      * @return a new multiFieldDataStructure object.
  4085.      * @exception UnrecognizedCodeException if struct was unparsible.
  4086.      * @exception InvalidParameterException if StreamTokenizer wasn't positioned on struct.
  4087.      * @exception IOException if StreamTokenizer can't read stream.
  4088.      */
  4089.     protected multiFieldDataStructure ReadStructure(StreamTokenizer st, boolean insideStructure) throws UnrecognizedCodeException, InvalidParameterException, IOException
  4090.     {
  4091.         if(st.sval == null || !(st.sval.equals("struct") || st.sval.equals("union") || st.sval.equals("class")))
  4092.             throw new InvalidParameterException("stream tokenizer not positioned exactly on struct!");
  4093.         String objType = st.sval;  // For debugging purposes, either class, struct, or union
  4094.         boolean use_struct = st.sval.equals("struct") || st.sval.equals("class");
  4095.         // Set default protection for fields of this structure, if applicable.
  4096.         int prot = (st.sval.equals("class") ? Field.PRIVATE : Field.PUBLIC);
  4097.         st.nextToken();
  4098.         multiFieldDataStructure str = null;
  4099.         String structure_name = null;
  4100.         boolean putInStructureLUT = false;   // Sometimes we put a half-built structure
  4101.         // in StructureLUT so that readField can deal with recursive struct definitions.
  4102.         // We also need to take it out afterwards...
  4103.  
  4104.         // Read in the name of the struct.  Change this to be an alternate name later, if
  4105.         // one is present (assuming typedef struct ...  alt_struct_name;).  Use
  4106.         // the first typedef'ed name as the real name of the struct.  Move to '{'.
  4107.         if(st.ttype != '{') {
  4108.             structure_name = st.sval;
  4109.             st.nextToken();
  4110.         }
  4111.         if(st.ttype == ':') {
  4112.             // Inheritance
  4113.             System.out.println("Ignoring inheritance list"+(structure_name!=null ? " for "+structure_name : "."));
  4114.             while(st.nextToken() != '{' && st.ttype != ';' && st.ttype != st.TT_EOF);
  4115.         }
  4116.         if(use_struct)
  4117.             str = new Struct(structure_name);
  4118.         else
  4119.             str = new Union(structure_name);
  4120.  
  4121. //        System.out.print("\r\nProcessing "+(structure_name!=null ? structure_name : "an anonymous "+
  4122. //            (str.isStruct() ? "struct" : "union"))+"... ");
  4123.  
  4124.         // Special case: skip GUID.  We have our own version.
  4125.         if(structure_name!=null && "_GUID".equals(structure_name)) {
  4126.             System.out.println("Skipping GUID - we treat it as a special primitive.");
  4127.             while(st.nextToken() != '}');
  4128.             return null;
  4129.         }
  4130.  
  4131.         // _RTL_CRITICAL_SECTION and _RTL_CRITICAL_SECTION_DEBUG each have a pointer to the other.
  4132.         // Consequently I can't deal with those structs normally.
  4133.         /*
  4134.         if(structure_name != null && structure_name.startsWith("_RTL_CRITICAL_SECTION")) {
  4135.             System.out.println("Skipping "+structure_name+" because of circular dependancies...");
  4136.             while(st.nextToken() != '}');
  4137.             while(st.nextToken() != ';');
  4138.             return null;
  4139.         }
  4140. */
  4141.         // Now we've seen struct|union [structure_name]
  4142.         try {
  4143.             // typedef struct_name [*] pfoo is handled in ParseFile's typedef section.
  4144.             // Deal with something like  struct foobie * pfoobie_field; 
  4145.             // Could be either a typedef struct blah alt_blah or field name in embedded struct
  4146.             if(st.ttype == '*')
  4147.                 st.nextToken();
  4148.             if(st.ttype == st.TT_WORD) {
  4149.                 // We've seen struct|union [structure_name] [*] <word>
  4150.                 // Could be an alias, like typedef struct foo * fooptr;
  4151.                 // Or most probably we're inside a structure or union and hit an embedded one.
  4152.                 // And that word there is the field name, or possibly a C modifier like volatile.
  4153.                 // Use insideStructure to decide which is which.
  4154.  
  4155.                 // check for any C modifiers that might be in effect...   const, volatile
  4156.                 // Don't know what to do with them now though.  They're a field-based thing,
  4157.                 // usually not for an entire structure.  So... ignore for now?
  4158.                 if(st.sval.equals("volatile") || st.sval.equals("const") ||
  4159.                     st.sval.equals("FAR") || st.sval.equals("NEAR")) {
  4160.                     //System.out.println("Adding modifier " + st.sval);
  4161.                     //str.addModifier(st.sval);  // this line is quite likely wrong.
  4162.                     st.nextToken();
  4163.                     // Do another pointer check now.
  4164.                     if(st.ttype == '*')
  4165.                         st.nextToken();
  4166.                     if(st.ttype != st.TT_WORD)
  4167.                         throw new UnrecognizedCodeException("ReadStructure messed up the stream while trying to handle a const or volatile structure modifier.");
  4168.                 }
  4169.  
  4170. //                System.out.println("In "+objType+" name [*] fieldname now...\r\nstruct "+structure_name+" [*] "+st.sval);
  4171.                 multiFieldDataStructure data = (multiFieldDataStructure) StructureLUT.get(structure_name);
  4172.                 if(data != null) {
  4173.                     System.out.println("Found "+objType+" " + data.getName()+" in StructureLUT");
  4174.                     if(insideStructure) {
  4175.                         // Now st is at the field name, with up to one modifier stripped out.
  4176.                         // must quit now and let readfield deal with the rest.
  4177.                         return data;
  4178.                     }
  4179.                     else {
  4180.                         // Adding aliased name for this structure.
  4181.                         if(st.ttype != st.TT_WORD)
  4182.                             throw new UnrecognizedCodeException("Readstructure was going to add alias to a structure, but no name was found! "+structure_name);
  4183.                         if(!st.sval.equals(structure_name)) {  // If its the same, redefine the structure.
  4184.                             data.addAltName(st.sval);
  4185.                             return data;
  4186.                         }
  4187.                     }
  4188.                 }
  4189.                 else {
  4190.                     // This could have been an opaque struct, where we have a forward definition
  4191.                     // then a typedef of a pointer to that struct.  Allow those, as ints.
  4192.                     // maybe.
  4193.                     System.out.println("Couldn't find struct or union named "+structure_name+" in StructureLUT.");
  4194.                     st.nextToken();
  4195.                     throw new PuntException("Found struct <undefined struct> somewhere... Maybe you punted on: ", structure_name);
  4196.                 }
  4197.             }
  4198.             else if(st.ttype == '{') {
  4199.                 st.nextToken();
  4200.  
  4201.                 // Add half-built struct into hashtable so we can use it for recursive structs.
  4202.                 boolean wasPresent = StructureLUT.containsKey(str.getName());
  4203.                 if(!wasPresent) {
  4204.                     //System.out.println("Adding half-built structure named " + str.getName()+" to StructureLUT.");
  4205.                     StructureLUT.put(str.getName(), str);
  4206.                     str.setComplete(false);
  4207.                     putInStructureLUT = true;
  4208.                 }
  4209.  
  4210.                 while(st.ttype != '}') {
  4211.                     // Check for #line's in the middle of the structure...
  4212.                     if(st.ttype == '#') {
  4213.                         st.nextToken(); // line
  4214.                         st.nextToken(); // x
  4215.                         st.nextToken(); // "word"?????
  4216.                         st.nextToken();
  4217.                         //System.out.println("Read my #line..  Token should be LONGLONG.  "+st.sval);
  4218.                         continue;
  4219.                     }
  4220.  
  4221.                     // Protection check - change protection, read to end of line, then continue.
  4222.                     if(st.ttype==st.TT_WORD) {
  4223.                         boolean change = false;
  4224.                         if(st.sval.equals("public")) {
  4225.                             prot = Field.PUBLIC;
  4226.                             change = true;
  4227.                         }
  4228.                         else if(st.sval.equals("protected")) {
  4229.                             prot = Field.PROTECTED;
  4230.                             change = true;
  4231.                         }
  4232.                         else if(st.sval.equals("private")) {
  4233.                             prot = Field.PRIVATE;
  4234.                             change = true;
  4235.                         }
  4236.                         if(change) {
  4237.                             st.nextToken();
  4238.                             st.nextToken();
  4239.                             continue;
  4240.                         }
  4241.                     }
  4242.  
  4243.                     Field var=null;
  4244.                     try {
  4245.                         var = (Field) readField(st, ';', '}', true, true);
  4246.                         var.setProtection(prot);
  4247.                     }
  4248.                     catch (UnrecognizedCodeException e) {
  4249.                         System.out.print("\r\nUnrecognizedCodeException filtered through ReadStructure while reading ");
  4250.                         System.out.println((str.isStruct() ? "struct" : "union") + " named " + structure_name);
  4251.                         throw e;
  4252.                     }
  4253.                     
  4254.                     if(var == null)
  4255.                         System.out.println("Ack! var == null");
  4256.                     str.addField(var);
  4257.                     st.nextToken();
  4258.                 } // parsing struct fields.
  4259.                 // Now pull out str, since we only added it to handle embedded structures.
  4260.                 // suspicious.
  4261.                 if(!wasPresent) {
  4262.                     StructureLUT.remove(str.getName());
  4263.                     str.setComplete(true);
  4264.                     putInStructureLUT = false;
  4265.                 }
  4266.             } // end typedef struct [name] {  ( [fields] }
  4267.  
  4268.             // Status check for debugging.
  4269.             if(st.ttype != '}')
  4270.                 throw new UnrecognizedCodeException("ReadStructure got lost after reading a structure and before reading its alias list/fieldname.");
  4271.  
  4272.             // Now we hit the list of aliases for this struct or union, assuming there was a typedef.
  4273.             // However, for embedded structs, these might really be fieldnames!!!!
  4274.             // We've seen struct|union [structure_name] [*] [{ [fields] }] 
  4275.             // Now we expect to see either a semicolon or a list of words and *'s, followed by a ';'
  4276.             if(!insideStructure) {
  4277.                 st.nextToken();
  4278.                 boolean firsttime = true;
  4279.                 while(st.ttype != ';') {
  4280.                     if(st.ttype != st.TT_WORD && st.ttype != '*')
  4281.                         throw new UnrecognizedCodeException("Ack!  Freaking out in a typedef alias list!  token="+(char)st.ttype);
  4282.                     
  4283.                     // Parse the type once again, looking for pointers, etc.
  4284.                     String type = null;
  4285.                     do {
  4286.                         String append = null;
  4287.                         if(st.ttype == '*')
  4288.                             append = null;  // could use "*" here...
  4289.                         else if(st.ttype == st.TT_WORD) {
  4290.                             if(!st.sval.toUpperCase().equals("FAR") && !st.sval.toUpperCase().equals("NEAR"))
  4291.                                 append = st.sval;
  4292.                         }
  4293.                         else
  4294.                             throw new UnrecognizedCodeException("Ack!  Bailing while parsing alias list for " +
  4295.                             (str.isStruct() ? "struct " : "union ") + str.getName() +"! (unexpected token \""+(char)st.ttype+"\" sval: "+st.sval);
  4296.                         if(type == null)
  4297.                             type = append;
  4298.                         else
  4299.                             type = type + " " + append;
  4300.                         st.nextToken();
  4301.                     } while(st.ttype != ',' && st.ttype != ';');
  4302.                     if(firsttime) {
  4303.                         str.addAltName(str.getName());
  4304.                         str.setName(type);
  4305.                         firsttime = false;
  4306.                     }
  4307.                     else
  4308.                         str.addAltName(type);
  4309.                     if(DEBUG>5)
  4310.                         System.out.println("Adding alt name " + type);
  4311.                     
  4312.                     if(st.ttype == ',')
  4313.                         st.nextToken();
  4314.                 } // end while to read alias names,
  4315.             } // end if !insideStructure
  4316.  
  4317.         } // end try
  4318.         catch(PuntException p) {
  4319.             System.out.println("Punted in " + p.Name +" because " + p.Reason);
  4320.             PuntOutput.println(p.Reason + "  Punted in: " + p.Name+"  ReadStructure in: "+structure_name);
  4321.             //    (str!=null ? "  ReadStructure in: "+str.getName() : ""));
  4322.             if(putInStructureLUT)
  4323.                 StructureLUT.remove(str.getName());
  4324.             str = null;
  4325.         }
  4326.         return str;
  4327.     }
  4328.  
  4329.     /**
  4330.      * Given a StreamTokenizer, it will read a variable type and name, including the
  4331.      * more complex user-defined data types like unions and structs.  Assumes it is being
  4332.      * called on text within a structure or a union, although it should work with functions
  4333.      * too.  Recursively calls ReadStructure if it hits an embedded structure.
  4334.      * Reads a field until the ending separator or terminator, leaving st there.
  4335.      * within this one.  Also tries to handle some slightly different conversion rules
  4336.      * while reading fields from structures.
  4337.      * @param st StreamTokenizer positioned at beginning of a field.
  4338.      * @param separator character used to separate multiple fields
  4339.      * @param terminator character used to end a list of fields
  4340.      * @param isInsideStruct whether we're reading a data structure
  4341.      * @param allowAnonymous whether we can have anonymous data types declared in place.
  4342.      * @return a Variable object (or if isInsideStruct is true, a Field) representing 
  4343.      *         the field read in.
  4344.      * @exception UnrecognizedCodeException if the function gets lost.
  4345.      * @exception InvalidParameterException if separator or terminator equal StreamTokenizer.TT_WORD, or if st is null.
  4346.      * @exception IOException if StreamTokenizer has an IO problem.
  4347.      * @exception PuntException if the parser doesn't understand this field or is told to ignore it, based on name and/or type.
  4348.      */
  4349.     protected Variable readField(StreamTokenizer st, char separator, char terminator, boolean isInsideStruct, boolean allowAnonymous) 
  4350.         throws UnrecognizedCodeException, InvalidParameterException, IOException, PuntException
  4351.     {
  4352.         /* New assumptions:
  4353.          * 1) All fields have a type and/or a field name.  At least one is present.
  4354.          * 2) All fields start with a one-word type (modulo *), which is either a primitive,
  4355.          *    a user-defined data type, or the name of the current user-defined data type.
  4356.          * 3) All user-defined data types will be in the StructureLUT, even in the recursive
  4357.          *    struct field case.
  4358.          * 4) user-defined data types don't have to have a type name associated with them.
  4359.          * 5) Fields can be bitfields.  Punt on those.
  4360.          * Sometimes embedded structs can be declared anonymously in place:  
  4361.          * union example { struct { int a, int b }; };  Example is the pathological LARGE_INTEGER.
  4362.          */
  4363.         if(st==null)
  4364.             throw new InvalidParameterException("readField won't accept a null StreamTokenizer parameter!");
  4365.         String Type = null;
  4366.         String Name = null;
  4367.         Variable var = null;
  4368.         boolean isConst = false;
  4369.         boolean isStatic = false;
  4370.         boolean isVolatile = false;
  4371.         boolean isVirtual = false;
  4372.         boolean isMutable = false;
  4373.         if(separator == st.TT_WORD || terminator == st.TT_WORD)
  4374.             throw new InvalidParameterException("separator and terminator can't be \""
  4375.                    +st.TT_WORD+"\" or readField will fail.  Design flaw.  That's the cost of using the StreamTokenizer.");
  4376.  
  4377.         if(st.ttype == separator || st.ttype == terminator)
  4378.             return null;
  4379.         //System.out.print("Reading field... ");
  4380.  
  4381.         if(st.ttype != st.TT_WORD)
  4382.             throw new UnrecognizedCodeException("Unknown type part of a field! Token: "+st.ttype);
  4383.  
  4384.         if(st.sval.equals("unsigned") || st.sval.equals("signed")) {
  4385.             if(DEBUG > 2)
  4386.                 System.out.println("Readfield moving past "+st.sval+"... ");
  4387.             st.nextToken();
  4388.         }
  4389.  
  4390.         // Check for modifiers
  4391.         if(st.sval.equals("virtual")) {
  4392.             isVirtual = true;
  4393.             st.nextToken();
  4394.         }
  4395.         if(st.sval.equals("const")) {
  4396.             isConst = true;
  4397.             st.nextToken();
  4398.         } else if(st.sval.equals("volatile")) {
  4399.             isVolatile = true;
  4400.             st.nextToken();
  4401.         }
  4402.         if(st.sval.equals("static")) {
  4403.             isStatic = true;
  4404.             st.nextToken();
  4405.         }
  4406.         if(st.sval.equals("mutable")) {
  4407.             isMutable = true;
  4408.             st.nextToken();
  4409.         }
  4410.         // Check again for const-ness, in case of "static const" or something.
  4411.         if(st.sval.equals("const")) {
  4412.             isConst = true;
  4413.             st.nextToken();
  4414.         } else if(st.sval.equals("volatile")) {
  4415.             isVolatile = true;
  4416.             st.nextToken();
  4417.         }
  4418.  
  4419.         // If primitive...
  4420.         if(TypeLUT.containsKey(st.sval)) {
  4421. //            System.out.println("Found a primitive field.");
  4422.             Type = st.sval;
  4423.             IntExpression assign_expr = null;
  4424.             st.nextToken();
  4425.             if(st.ttype == '(') {  // pointer to function inside structure
  4426.                 st.nextToken();
  4427.                 if(st.sval.equals("__stdcall")) {
  4428.                     st.nextToken();
  4429.                     Name = st.sval;
  4430.                     Type = "int /* BUGBUG: pointer to function */";
  4431.                     while(st.nextToken() != separator && st.ttype != terminator);
  4432.                     if(isInsideStruct)
  4433.                         var = new Field(Type, Name);
  4434.                     else
  4435.                         var = new Variable(Type, Name);
  4436.                     return var;
  4437.                 }
  4438.             }
  4439.             if(st.ttype == '*') {
  4440.                 Type = Type + " *";
  4441.                 // Ignore all pointers to things inside structures, except of course embedded char arrays.
  4442.                 //throw new PuntException("Not going to deal with pointers inside data structures.", Type);
  4443.                 // Unfortunately, this is NOT done very well at all.
  4444.                 Type = "int";
  4445.                 do {
  4446.                     if(st.ttype == st.TT_WORD)
  4447.                         Name = st.sval;
  4448.                 } while(st.nextToken() != separator && st.ttype != terminator);
  4449.                 if(isInsideStruct) {
  4450.                     var = new Field(Type, Name);
  4451.                     ((Field)var).setStatic(isStatic);
  4452.                     ((Field)var).setMutable(isMutable);
  4453.                 }
  4454.                 else
  4455.                     var = new Variable(Type, Name);
  4456.                 var.setConst(isConst);
  4457.                 var.setVolatile(isVolatile);
  4458.                 var.setPointer(true);
  4459.                 return var;
  4460.             }
  4461.             else if(st.ttype != st.TT_WORD)
  4462.                 throw new UnrecognizedCodeException("While handling primitive type, found hideous symbol (or anonymous field). token="+(char)st.ttype);
  4463.             do {
  4464.                 if(st.ttype == '[') {  // if we have an array...
  4465.                     Array a;
  4466.                     boolean isString = false;
  4467.                     st.nextToken();
  4468.                     // Some embedded arrays are of variable length.  If their size is 1, then
  4469.                     // somehow they can change size, or at least be declared to have some odd
  4470.                     // size at runtime.  And the size of the struct they are in varies too.
  4471.                     // Consequently, punt on any arrays of size 1.  (detected a few lines down)
  4472.                     // There's a string like [ANYSIZE ARRAY] that the preprocessor changes to 1
  4473.                     if(StringTypes.containsKey(Type)) {
  4474.                         //System.out.println("Found a String or StringBuffer type.");
  4475.                         isString = true;
  4476.                     }
  4477.                     int length = -1;
  4478.  
  4479.                     //if(st.ttype==st.TT_NUMBER || st.ttype=='(' || st.ttype=='-') {
  4480.                         //symbol sym = parseNumExp(st, ']');
  4481.                         //length = sym.value;
  4482.                         IntExpression len_expr = (IntExpression) parseNumExp(st, ']');
  4483.                         if(len_expr == null) {
  4484.                             System.out.println("Ack!  For array "+Name+", length parsing returned NULL!");
  4485.                             System.exit(1);
  4486.                         }
  4487.                         if(DEBUG >= 2)
  4488.                             System.out.println("For array "+Name+", length was: "+len_expr.toString()+"  evals to: "+len_expr.eval());
  4489.                         length = (int) len_expr.eval();
  4490.                     //}
  4491.  
  4492.                     if(length != -1) {
  4493.                         if(isString)
  4494.                             a = new CharArray(Name, length);
  4495.                         else
  4496.                             a = new Array(Name, length);
  4497.                     }
  4498.                     else {
  4499.                         if(isString)
  4500.                             a = new CharArray(Name);
  4501.                         else
  4502.                             a = new Array(Name);
  4503.                     }
  4504.                     if(a.getLength() == 1)
  4505.                         throw new PuntException("Found an array of size one in a struct: ", a.getName());
  4506.                     a.setType(Type);
  4507.                     if(isInsideStruct)
  4508.                         var = new Field(a);
  4509.                     else
  4510.                         var = new Variable(a);
  4511.                     //st.nextToken();
  4512.                     if(st.ttype != ']')
  4513.                         throw new UnrecognizedCodeException("While processing a primitive array named " 
  4514.                            +Name+", got lost while looking for ']'! token="+(char)st.ttype);
  4515.                     //System.out.print("Made array. ");
  4516.                 }
  4517.                 else if(st.ttype == ':') {
  4518.                     // We have a bitfield.
  4519.                     if(DEBUG>0)
  4520.                         System.out.println("Found a bitfield... ");
  4521.                     //while(st.nextToken() != '}');
  4522.                     //while(st.nextToken() != ';');
  4523.                     //throw new PuntException("Not going to deal with bitfields", "<>");
  4524. //                    while(st.nextToken() != ';');
  4525. //                    return null;
  4526.                 }
  4527.                 else if(st.ttype == '=') {  // Assignment
  4528.                     System.out.println("Found an initializer for variable "+Name);
  4529.                     st.nextToken();
  4530.                     if(st.ttype==st.TT_NUMBER || st.ttype=='(') {
  4531.                         assign_expr = (IntExpression) parseNumExp(st, ';');
  4532.                         st.pushBack();
  4533.                     }
  4534.                 }
  4535.                 else {
  4536.                     if(Name!=null)
  4537.                         Type = Type + " " + Name;
  4538.                     Name = st.sval;
  4539.                 }
  4540.                 st.nextToken();
  4541.             } while (st.ttype != separator && st.ttype != terminator);
  4542.             if(var == null) {
  4543.                 if(isInsideStruct) {
  4544.                     var = new Field(Type, Name);
  4545.                     ((Field)var).setStatic(isStatic);
  4546.                     ((Field)var).setMutable(isMutable);
  4547.                 }
  4548.                 else
  4549.                     var = new Variable(Type, Name);
  4550.             }
  4551.             var.setConst(isConst);
  4552.             var.setVolatile(isVolatile);
  4553.             if(assign_expr != null) {
  4554.                 var.setInitialValue(assign_expr);
  4555.                 System.out.println("Adding initializer to "+var.Name+" that evals to "+assign_expr.eval());
  4556.             }
  4557.             return var;
  4558.         }  // end Primitive
  4559.  
  4560.         // if user-defined data structure in StructureLUT...
  4561.         multiFieldDataStructure data = (multiFieldDataStructure) StructureLUT.get(st.sval);
  4562.         if(data != null) {
  4563. //            System.out.println("Found a data structure we've seen before.");
  4564.             boolean ptrToStruct = false;
  4565.             st.nextToken();
  4566.             if(st.ttype==st.TT_WORD && (st.sval.equals("FAR") || st.sval.equals("NEAR")))
  4567.                 st.nextToken();
  4568.             if(st.ttype == '*') { // change pointers to structs to ints.
  4569.                 st.nextToken();
  4570.                 ptrToStruct = true;
  4571.             }
  4572.             String fieldname = st.sval;
  4573.             st.nextToken();
  4574.             if(st.ttype == '[') { // Ignoring arrays of structures for now.
  4575.                 System.out.println("Ignoring an array of structures, "+data.getName()+"[]");
  4576.                 while(st.nextToken() != separator && st.ttype != terminator);
  4577.                 throw new PuntException("ignoring an array of "+(data.isStruct() ? "structs " : "unions ")+data.getName(), fieldname);
  4578.             }
  4579.             if(st.ttype != separator && st.ttype != terminator)
  4580.                 throw new UnrecognizedCodeException("Found an odd mark after a structure! token="+(char)st.ttype);
  4581. //            System.out.println("read in Data structure of type "+data.getName()+", named "+fieldname+" here.");
  4582.             if(isInsideStruct)
  4583.                 var = new Field(data, fieldname);
  4584.             else
  4585.                 var = new Variable(data, fieldname);
  4586.             var.setPointer(ptrToStruct);
  4587.             return var;
  4588.         }  // end in StructureLUT
  4589.  
  4590.         // if "struct" or "union" or "class"...
  4591.         if(st.sval.equals("struct") || st.sval.equals("union") || st.sval.equals("class")) {
  4592.             multiFieldDataStructure newData = (multiFieldDataStructure) ReadStructure(st, true);
  4593.             if(newData == null)
  4594.                 throw new PuntException("Punting because we got a null structure while reading one in.", "");
  4595.             // st could be at one of two places:  on the terminating } in the structure if 
  4596.             // this was an embedded structure, or on the fieldname if this was something like:
  4597.             // struct struct_name * fieldname;   <--- used in linked list-like structures.
  4598.             // Read in the field name, the only string following this.  may not exist though.
  4599.             // However, we should deal with words like volatile in here.
  4600.             if(st.ttype == '}')
  4601.                 st.nextToken();
  4602.             if(st.ttype == ';') {
  4603.                 if(isInsideStruct)
  4604.                     var = new Field(newData, "anonymous_field");
  4605.                 else
  4606.                     var = new Variable(newData, "anonymous_field");
  4607.             }
  4608.             else {
  4609.                 if(st.ttype != st.TT_WORD)
  4610.                     throw new UnrecognizedCodeException("maybe there was a pointer in a structure's field name?");
  4611.                 String fieldname = st.sval;
  4612.                 if(newData.isComplete()) {
  4613.                     if(isInsideStruct)
  4614.                         var = new Field(newData, fieldname);
  4615.                     else
  4616.                         var = new Variable(newData, fieldname);
  4617.                 }
  4618.                 else {
  4619.                     if(isInsideStruct)
  4620.                         var = new Field("int", fieldname);
  4621.                     else
  4622.                         var = new Variable("int", fieldname);
  4623.                 }
  4624.                 st.nextToken();
  4625.                 if(st.ttype != ';')
  4626.                     throw new UnrecognizedCodeException("Ack!  readField expected a ';' but found a "+
  4627.                         (char)st.ttype+(st.ttype==st.TT_WORD ? " sval="+st.sval : ""));
  4628.             }
  4629.             return var;
  4630.         }  // end struct or union.
  4631.  
  4632.         // Handle callback functions with a good guess...
  4633.         if(st.sval.toLowerCase().endsWith("callback") || st.sval.toLowerCase().endsWith("proc")
  4634.             || st.sval.toLowerCase().endsWith("routine")) {
  4635.             String ptrFuncType = st.sval;
  4636.             if(!TypeLUT.containsKey(ptrFuncType))
  4637.                 TypeLUT.put(ptrFuncType, CallbackString);
  4638.             while(st.nextToken()=='*');
  4639. //            System.out.println("Adding pointer to function field "+st.sval);
  4640.             if(isInsideStruct) {
  4641.                 var = new Field(CallbackString, st.sval);
  4642.                 ((Field)var).setStatic(isStatic);
  4643.                 ((Field)var).setMutable(isMutable);
  4644.                 ((Field)var).setVirtual(isVirtual);
  4645.             }
  4646.             else
  4647.                 var = new Variable(CallbackString, st.sval);
  4648.             var.setConst(isConst);
  4649.             var.setVolatile(isVolatile);
  4650.  
  4651.             st.nextToken(); // read the ';'
  4652.             return var;
  4653.         }
  4654.  
  4655.         // For now, if we hit here, deal with it as a type we punted on.  So punt on this
  4656.         // type too.  If we take this line out, make sure to uncomment the lost exception below.
  4657.         throw new PuntException("type not recognized in readField.  You probably punted on: ", st.sval);
  4658.  
  4659.         // if we reach here, we're lost.  (You should have called return by now)
  4660.         //throw new UnrecognizedCodeException("Lost in readField! word is "+st.sval);
  4661.  
  4662.         //System.out.println("Done w/ readField.");
  4663.         //return var;
  4664.     }
  4665.  
  4666.     /**
  4667.      * Starting to build a real Expression parser now, finally.
  4668.      * Returns a numerical expression parsed from st.
  4669.      * If we hit a '(' or a series of operations, then cascade
  4670.      * forward and recurse, building a tree of NumExpressions.<p><pre>
  4671.      * Grammar: UnaryOperator NumExpression
  4672.      *                NumExpression UnaryOperator
  4673.      *                NumExpression BinaryOperator NumExpression
  4674.      *                NumExpression BinaryOperator NumExpression BinaryOperator NumExpression
  4675.      * </pre>
  4676.      * @return NumExpression of parsed number, or null if none exist.
  4677.      * @exception NumExprSyntaxError if syntax was messed up.
  4678.      * @exception IOException if StreamTokenizer doesn't work.
  4679.      * @exception InvalidParameterException if parseCNum is passed invalid data.
  4680.      */
  4681.     NumExpression parseNumExp(StreamTokenizer st, char terminator) throws NumExprSyntaxError, IOException, BadOperationException, InvalidParameterException
  4682.     {
  4683.         if(st.ttype == terminator)
  4684.             return null;
  4685.         st.ordinaryChar('-');
  4686. //        st.ordinaryChar('/');
  4687.         NumExpression first = null;
  4688.         Operator preOperator = null;
  4689.         Operator operator = null;
  4690.         boolean paren = false;  // use for order of operations fixup.
  4691.         boolean unary = false;
  4692.  
  4693.         // check for unary prefix operators
  4694.         if(isCOperator((char)st.ttype))
  4695.             preOperator = readOperator(st, true);
  4696.         if(preOperator != null)
  4697.             unary = preOperator.isUnaryOperator();
  4698.  
  4699.         // Read first token.
  4700.         if(st.ttype == st.TT_NUMBER) {
  4701.             first = parseCNum(st);
  4702.             st.nextToken();
  4703.         }
  4704.         else if(st.ttype == '(') {
  4705.             st.nextToken();
  4706.             paren = true;
  4707.             first = parseNumExp(st, ')');
  4708.             if(first==null)
  4709.                 throw new NumExprSyntaxError("Empty parenthesized expression!", "()");
  4710. //            System.out.println("Paren eval - First was: "+first+"  evals to: "+first.eval());
  4711.             st.nextToken();
  4712.         }
  4713.         else if(st.ttype==st.TT_WORD) {
  4714.             // Try looking up in known constants tables.
  4715.             throw new NumExprSyntaxError("Found word in numerical expression!", st.sval);
  4716.         }
  4717.  
  4718.         // Read in one symbol  Check for terminator.  Happens commonly, like in ++x;
  4719.         // or in (-1);  Most common case though:  1;
  4720.         if(st.ttype == terminator) {
  4721.             if(preOperator != null && unary)
  4722.                 return new IntExpression(preOperator.getOp(), first);
  4723.             else
  4724.                 return first;
  4725.         }
  4726.  
  4727.         // What about x-++y+1;  Correct parsing: [(x) - (++y)] + (1)
  4728.         // I think the ++y would have been handled already.
  4729.         // How do I parse operand Operator Operator operand, like x-++y;?
  4730.         if(isCOperator((char)st.ttype))
  4731.             operator = readOperator(st, false);
  4732.             
  4733.         //st.nextToken();
  4734.         if(unary) {
  4735.             if(st.ttype != terminator)
  4736.                 throw new NumExprSyntaxError("Read in unary operator \""+operator+"\" but didn't find terminator!", "token: "+(char)st.ttype+" sval: "+st.sval);
  4737.             return new IntExpression(first, operator.getOp());
  4738.         }
  4739.  
  4740.         // Have read in one symbol plus operator.
  4741.         if(st.ttype == terminator)
  4742.             throw new NumExprSyntaxError("Read in binary operator \""+operator+"\" but didn't find another operand!", "token: "+(char)st.ttype+" sval: "+st.sval);
  4743.  
  4744.  
  4745.         // Read second token.
  4746.         NumExpression second = null;
  4747.         if(st.ttype == st.TT_NUMBER) {
  4748.             second = parseCNum(st);
  4749.             st.nextToken();
  4750.         }
  4751.         else if(st.ttype == '(') {
  4752.             st.nextToken();
  4753.             paren = true;
  4754.             second = parseNumExp(st, ')');
  4755.             if(first==null)
  4756.                 throw new NumExprSyntaxError("Empty parenthesized expression!", "()");
  4757.             st.nextToken();
  4758.         }
  4759.         else if(st.ttype==st.TT_WORD) {
  4760.             // Try looking up in known constants tables.
  4761.             throw new NumExprSyntaxError("Found word in numerical expression!", st.sval);
  4762.         }
  4763.         else if(isCOperator((char)st.ttype)) {
  4764.             return new IntExpression(first, operator.getOp());
  4765.         }
  4766.  
  4767.         if(st.ttype == terminator)
  4768.             return new IntExpression(first, operator.getOp(), second);
  4769. //        else
  4770. //            System.out.println("Need to deal with compound expressions and add recursion.");
  4771.  
  4772.         Operator secondOp = readOperator(st, false);
  4773.  
  4774.         if(secondOp==null)
  4775.             throw new NumExprSyntaxError("Read in "+first+" "+operator+" "+second+" then expected an operand.", ""+(char)st.ttype);
  4776.  
  4777.         // Deal with long strings of operations, like (5 + 6 * 10) and make sure order of
  4778.         // operations is done correctly, if neither of the operands is parenthesized (!paren)
  4779.         // What about this: (1+2*3) * (1*2+3) + 1*5 -1
  4780. //        if(!paren) {
  4781.             //System.out.println("Checking order of operations for "+operator+" and "+secondOp);
  4782.             // Worry about precedent.
  4783.             if(operator.getPrecedent() >= secondOp.getPrecedent()) {
  4784.                 IntExpression left = new IntExpression(first, operator.getOp(), second);
  4785.                 NumExpression right = parseNumExp(st, terminator);
  4786.                 return new IntExpression(left, secondOp.getOp(), right);
  4787.             } 
  4788.             else {
  4789.                 NumExpression left = first;
  4790.                 NumExpression tail = parseNumExp(st, terminator);
  4791.                 NumExpression right = new IntExpression(second, secondOp.getOp(), tail);
  4792.                 return new IntExpression(left, operator.getOp(), right);
  4793.             }
  4794. //        }
  4795. /*
  4796.         System.out.println("Default return case, unparenthesized dual expressions.  Didn't check precedence.");
  4797.         NumExpression tail = parseNumExp(st, terminator);
  4798.         return new IntExpression(first, operator.getOp(), new IntExpression(second, secondOp.getOp(), tail));
  4799. */
  4800.     }
  4801.  
  4802.  
  4803.     /**
  4804.      * Is this character an operator or a valid first token in an operator in C?
  4805.      * @param c char to test
  4806.      * @return true if c is a C operator or the first character in a C operator, else false
  4807.      */
  4808.     public boolean isCOperator(char c)
  4809.     {
  4810.         if(c == '&' || c == '|' || c == '+' || c == '-' || c == '*' || c == '/' ||
  4811.             c == '%' || c == '~' || c == '<' || c == '>' || c == '|' || c == '=' || 
  4812.             c == '^')
  4813.             return true;
  4814.         return false;
  4815.     }
  4816.  
  4817.     /**
  4818.      * Reads in a C++ operator, given a set of constraints on what this operator could be.
  4819.      * @param st StreamTokenizer positioned at start of operator.
  4820.      * @return Operator instance of token we just read.
  4821.      * @exception IOException if StreamTokenizer has problems.
  4822.      */
  4823.     public Operator readOperator(StreamTokenizer st, boolean couldBePrefix) throws IOException
  4824.     {
  4825.         Operator op = null;
  4826.         String opname = null;
  4827.         boolean unary = false;
  4828.         char firstchar;
  4829.  
  4830.         if(isCOperator((char)st.ttype)) {
  4831.             opname = ""+(char)st.ttype;
  4832.             firstchar = (char)st.ttype;
  4833.         }
  4834.         else {
  4835.             st.pushBack();
  4836.             return null;
  4837.         }
  4838.         st.nextToken();
  4839.  
  4840.         // Unary two-token operators
  4841.         if(firstchar==st.ttype && (st.ttype=='+' || st.ttype == '-')) {
  4842.             unary = true;
  4843.             opname = opname+(char)st.ttype;
  4844.             st.nextToken();
  4845.         }
  4846.         // binary two-token operators
  4847.         else if(st.ttype == '=' || st.ttype == '&' ||
  4848.             st.ttype == '|' || st.ttype == '<' || st.ttype == '>') {
  4849.             opname = opname+(char)st.ttype;
  4850.             couldBePrefix = false;
  4851.             st.nextToken();
  4852.         }
  4853.  
  4854.         try {
  4855.             op = getOperator(opname, unary, couldBePrefix);
  4856.         }
  4857.         catch (BadOperationException e) {
  4858.             System.out.println("Ack! readOperator caught "+e+" from getOperator!");
  4859.             System.out.println(e.Description);
  4860.             System.exit(1);
  4861.         }
  4862.  
  4863.         return op;
  4864.     }
  4865.  
  4866.  
  4867.     /**
  4868.      * Parse a C integer or a float, in decimal or hex, into an appropriate NumExpression
  4869.      * and return it.
  4870.      * @param st StreamTokenizer positioned where we should start reading a number.
  4871.      * @return NumExpression containing the parsed number.
  4872.      * @exception IOException if StreamTokenizer doesn't work.
  4873.      * @exception InvalidParameterException if st isn't positioned at a number or a '-'.
  4874.      */
  4875.     NumExpression parseCNum(StreamTokenizer st) throws IOException, InvalidParameterException
  4876.     {
  4877.         if(st.ttype != st.TT_NUMBER && st.ttype != '-') {
  4878.             System.out.println("Invalid StreamTokenizer in parseNum!");
  4879.             throw new InvalidParameterException("StreamTokenizer mispositioned in parseCNum!");
  4880.         }
  4881.         NumExpression num = null;
  4882.         String text = "";
  4883.         boolean negative = false;
  4884.         boolean doULcheck = true;
  4885.         boolean isLong = false;
  4886.         boolean isDouble = false;
  4887.         if(st.ttype=='-') {
  4888.             st.nextToken();
  4889.             negative = true;
  4890.         }
  4891.  
  4892.         Double d = new Double(st.nval);
  4893.         text = text+d.intValue();
  4894.         if(st.nval==0.0) { // check for hex.
  4895.             st.nextToken();
  4896.             if(st.ttype == st.TT_WORD && st.sval.toLowerCase().startsWith("x")) {
  4897.                 String append = "";
  4898.                 if(st.sval.toUpperCase().endsWith("UL"))
  4899.                     append="0"+st.sval.substring(0, st.sval.length()-2);
  4900.                 else if(st.sval.toUpperCase().endsWith("L") || st.sval.toUpperCase().endsWith("U"))
  4901.                     append="0"+st.sval.substring(0, st.sval.length()-1);
  4902.                 else
  4903.                     append = "0"+st.sval;
  4904.                 if(append.length()>10) {
  4905.                     isLong = true;
  4906.                     append = append+"L";
  4907.                 }
  4908.                 text = append;
  4909.                 doULcheck = false;
  4910.             }
  4911.             else {
  4912.                 st.pushBack();
  4913.                 doULcheck = true;
  4914.             }
  4915.         }
  4916.  
  4917.         if(doULcheck) { // Do U & L check, plus E
  4918.             // U - unsigned   L - long   E - 10^x
  4919.             st.nextToken();
  4920.             if(st.ttype == st.TT_WORD) {
  4921.                 if(st.sval.toUpperCase().equals("L") || st.sval.toUpperCase().equals("U")
  4922.                     || st.sval.toUpperCase().equals("UL")) {
  4923.                     //System.out.println("Found a long...");
  4924.                     //sym.isLong = true;
  4925.                     //text = text+"L";
  4926.                 }
  4927.                 else if(st.sval.toUpperCase().startsWith("E")) {
  4928.                     isDouble = true;
  4929.                     text = text+st.sval.toUpperCase();
  4930.                 }
  4931.                 else  // Should never be called?
  4932.                     st.pushBack();
  4933.             }
  4934.             else
  4935.                 st.pushBack();
  4936.         }
  4937.  
  4938.         if(negative)
  4939.             text = "-"+text;
  4940.         if(isDouble)
  4941.             System.out.println("Ack! Can't parse doubles yet!");  // more to the point, can't return doubles yet.
  4942.         else if(isLong)
  4943.             num = new IntExpression((new Long(text)).longValue());
  4944.         else  // isInt
  4945.             num = new IntExpression((new Integer(text)).intValue());
  4946.  
  4947.         return num;
  4948.     }  // end parseCNum
  4949.  
  4950.  
  4951.     /**
  4952.      * Handles #pragma pack lines.  Adjusts packsize stack as needed.
  4953.      * @param st StreamTokenizer positioned on a #pragma pack (specifically on "pack").
  4954.      * @param packsize Stack of PackContainer's representing current alignment.
  4955.      * @return No return value.
  4956.      * @exception InvalidParameterException if st isn't positioned on the word "pack"
  4957.      * @exception IOException if st encounters an I/O error.
  4958.      * @exception UnrecognizedCodeException if PackHandler encounters some strange syntax.
  4959.      * @see PackContainer.html
  4960.      */
  4961.     protected void PackHandler(StreamTokenizer st, Stack packsize) throws InvalidParameterException, IOException, UnrecognizedCodeException
  4962.     {
  4963.         if(st.ttype != st.TT_WORD || !st.sval.equals("pack"))
  4964.             throw new InvalidParameterException("PackHandler passed stream tokenizer that wasn't on \"pack\" keyword.");
  4965.  
  4966.         if(DEBUG>3)
  4967.             System.out.println("Found a pack command... ");
  4968.         st.nextToken();
  4969.         st.nextToken();
  4970.         if(st.ttype == ')') {   // #pragma pack()  As far as I can tell, this is a pop.
  4971.             packsize.pop();
  4972.         }
  4973.         else if(st.ttype == st.TT_NUMBER) {
  4974.             int n = (new Double(st.nval)).intValue();
  4975.             // Add this to the stack, don't destroy what's there.
  4976.             packsize.push(new PackContainer(n));
  4977.             //System.out.println("Changed pack size to " + (int)st.nval);
  4978.         } 
  4979.         else if(st.ttype==st.TT_WORD && st.sval.equals("push")) {
  4980.             st.nextToken();
  4981.             if(st.ttype == ')')
  4982.                 return;
  4983.             st.nextToken();
  4984.             String label = null;
  4985.             if(st.ttype==st.TT_WORD) {  // in wininet.h:  #pragma pack(push, wininet, 4)
  4986.                 label = st.sval;
  4987.                 st.nextToken();
  4988.                 st.nextToken();
  4989.             }
  4990.             int n = 0;  // Default invalid number, to find bugs.
  4991.             if(st.ttype == st.TT_NUMBER)
  4992.                 n = (new Double(st.nval)).intValue();
  4993.             if(label == null)
  4994.                 packsize.push(new PackContainer(n));
  4995.             else
  4996.                 packsize.push(new PackContainer(n, label));
  4997.             st.nextToken();
  4998.             //System.out.println("Pushed pack size of "+(int)st.nval+(label==null?"":", label was "+label));
  4999.         } // end #pragma pack(push, n)
  5000.         else if(st.ttype==st.TT_WORD && st.sval.equals("pop")) {
  5001.             String label = null;
  5002.             st.nextToken();
  5003.             if(st.ttype==',') { // Found a label to search for.
  5004.                 // BUGBUG: doesn't support #pragma pack(pop, n);  n = [1, 2, 4, 8]
  5005.                 PackContainer p;
  5006.                 st.nextToken();
  5007.                 if(st.ttype != st.TT_WORD)
  5008.                     throw new UnrecognizedCodeException("Ack!  PackHandler on \"pack(pop, \" looking for a string and found "+(char)st.ttype+" instead.");
  5009.                 label = st.sval;
  5010.                 do {
  5011.                     p = (PackContainer) packsize.pop();
  5012.                 } while (p!=null && !p.hasLabel() && !p.getLabel().equals(label));
  5013.                 if(p==null)
  5014.                     throw new UnrecognizedCodeException("Ack!  PackHandler was searching for label "+label+" during a pop, but the stack is empty!!!");
  5015.             }
  5016.             else
  5017.                 packsize.pop();
  5018.             st.nextToken();
  5019.             //System.out.println("pack size pop"+(label==null?"":", label was "+label));
  5020.         } // end #pragma pack(pop)
  5021.         else
  5022.             System.out.println("Ack!  unknown pack syntax \"" + st.sval+"\"");
  5023.         st.nextToken();
  5024.         //System.out.println("Done w/ pack.");
  5025.     } // end PackHandler (#pragma pack)
  5026.     
  5027.  
  5028.     /**
  5029.      * Reads in a symbol file, adding all symbols to the Symbol table, noting which file
  5030.      * each symbol came from for use later when putting functions in files.<p>
  5031.      * 
  5032.      * Symbol files can be generated by calling dumpbin on a library, like this:<p>
  5033.      * <pre>dumpbin /exports c:\windows\system\kernel32.dll > kernel32.sym</pre><p>
  5034.      *
  5035.      * Do not edit symbol files, except to get rid of function names with question marks
  5036.      * or other really odd names in them.  You can leave the Microsoft dumpbin
  5037.      * header + trailer info, or you can remove them if you need to.  (Its not used by 
  5038.      * this program, but there is a keyword used to stop skipping over the header).
  5039.      * Symbol files should contain info like this:<p>
  5040.      * <pre>
  5041.      *                   1    0   AddAtomA  (000079FE)
  5042.      *                   2    1   AddAtomW  (00004478)
  5043.      * </pre>
  5044.      * @param File Symbol file name.
  5045.      * @return No return value.
  5046.      * @exception BadInputFileException if file is not strictly the output of dumpbin /exports
  5047.      * @exception InvalidParameterException if one of the functions called here failed.
  5048.      */
  5049.     protected void ParseSymbolFile(String File) throws BadInputFileException, InvalidParameterException
  5050.     {
  5051.         if(File==null || File.equals(""))
  5052.             throw new BadInputFileException("ParseSymbolFile won't accept a null or blank file name!");
  5053.  
  5054.         if(Symbols == null)
  5055.             Symbols = new Vector();
  5056.  
  5057.         // Extract library name to store in function.
  5058.         String libname = null;
  5059.         StringTokenizer parse = new StringTokenizer(File, "\\");
  5060.         while(parse.hasMoreTokens()) {
  5061.             libname = parse.nextToken();
  5062.         }
  5063.         if(libname == null)
  5064.             throw new BadInputFileException("I couldn't parse the name of the file!");
  5065.         if(libname.endsWith(".sym")) {
  5066.             libname = libname.toUpperCase().substring(0, libname.length()-4);
  5067. //            System.out.println("Mangled lib name: "+libname);
  5068.         }
  5069.  
  5070.         try {
  5071.             InputStreamReader isr = new InputStreamReader((InputStream) (new FileInputStream(File)));
  5072.             StreamTokenizer st = new StreamTokenizer(isr);
  5073.             st.eolIsSignificant(true);
  5074.             st.wordChars('_', '_');
  5075.             //st.wordChars('0', '9');  // to handle hex numbers in file
  5076.  
  5077.             st.nextToken();  // Do this to read in MS dumpbin output without needing to edit files.
  5078.             if(st.ttype==st.TT_WORD && st.sval.equals("Microsoft")) {
  5079.                 // Read through to beginning of symbols in symbol file.
  5080.                 while(st.nextToken() != st.TT_EOF) {
  5081.                     if(st.ttype==st.TT_WORD && st.sval.equals("name")) {
  5082.                         st.nextToken();
  5083.                         st.nextToken();
  5084.                         break;
  5085.                     }
  5086.                 }
  5087.             }
  5088.             else
  5089.                 st.pushBack();
  5090.  
  5091.             while(st.nextToken() != StreamTokenizer.TT_EOF) {
  5092.                 if(st.ttype == st.TT_EOL)
  5093.                     continue;
  5094.                 else if(st.ttype == st.TT_WORD && st.sval.equals("Summary"))
  5095.                     break;
  5096.                 st.nextToken();
  5097.                 st.nextToken();
  5098.                 if(st.ttype == StreamTokenizer.TT_NUMBER) {
  5099.                     System.out.println("Ack!  st.ttype was a number!  " + st.nval);
  5100.                 }
  5101.                 if(st.ttype != StreamTokenizer.TT_WORD) {
  5102.                     throw new BadInputFileException("Expected a string, found junk in file " + File + "\r\nst.ttype was "+((char)st.ttype) + "\tst.nval was " + st.nval);
  5103.                 }
  5104.  
  5105.                 if(st.sval.length() <= 2)  // hex digit
  5106.                     st.nextToken();
  5107.  
  5108.                 Function func = new Function(st.sval);
  5109.                 func.setLibrary(libname);
  5110.                 //System.out.println("Adding Symbol " + func.getName());
  5111.                 Symbols.addElement(func);
  5112.  
  5113.                 st.nextToken();
  5114.                 // Read until end of line.
  5115.                 while(st.nextToken() != StreamTokenizer.TT_EOL && st.ttype != StreamTokenizer.TT_EOF);
  5116.             }
  5117.  
  5118.             isr.close();
  5119.             isr = null;
  5120.         }
  5121.         catch (IOException e) 
  5122.         {
  5123.             System.out.println("\r\nIO Exception caught while trying to parse symbol file "+ File+": "+ e);
  5124.             e.printStackTrace();
  5125.         }
  5126.     }
  5127.  
  5128.  
  5129.     /** 
  5130.      * Compares parsed functions with symbols from a DLL.  Assumes a file has been 
  5131.      * parsed and a symbols file has been read in.
  5132.      * @return No return value.
  5133.      */
  5134.     protected void CompareFunctionWithSymbols()
  5135.     {
  5136.         Function f;
  5137.         Function s;
  5138.         int i=0;
  5139.         int j=0;
  5140.         try {
  5141.             PrintWriter notdll = new PrintWriter(new FileOutputStream("notindll.txt"));
  5142.             PrintWriter indll = new PrintWriter(new FileOutputStream("indll.txt"));
  5143.             
  5144.             while(i<Functions.size() && j<Symbols.size())
  5145.             {
  5146.                 f = (Function) Functions.elementAt(i);
  5147.                 s = (Function) Symbols.elementAt(j);
  5148.                 if(f.getName().equals(s.getName())) {
  5149.                     i++;
  5150.                     j++;
  5151.                 } 
  5152.                 else if(f.getName().compareTo(s.getName()) < 0)  {
  5153.                     i++;
  5154.                     // output f - it wasn't in the DLL symbols.
  5155.                     notdll.println(f.getName());
  5156.                     System.out.println("Not in DLL: " + f.toString());
  5157.                 }
  5158.                 else {
  5159.                     j++;
  5160.                     // output s - it wasn't in my parsed function.
  5161.                     indll.println(s.getName());
  5162.                     System.out.println("MISSED THIS FUNCTION: " + s.toString());
  5163.                 }
  5164.             }
  5165.  
  5166.             notdll.close();
  5167.             indll.close();
  5168.         }
  5169.         catch (IOException e)
  5170.         {
  5171.             System.out.println("IOException in CompareFunctionWithSymbols.\r\n" + e);
  5172.         }
  5173.     }
  5174.  
  5175.  
  5176.     /**
  5177.      * Scans through read in functions, looking for the ASCII and Unicode versions of
  5178.      * any such functions.  If it finds them both, it will strip off the last 
  5179.      * character, merging them into one function call.  Deals with the 4 special
  5180.      * cases I found in the Win32 API.
  5181.      * @return No return value.
  5182.      */
  5183.     public void UnifyFunctions()
  5184.     {
  5185.         Function f;
  5186.         String search;
  5187.         //System.out.print("Unifying ASCII and Unicode versions of functions... ");
  5188.         for(int i=0; i<Functions.size(); i++) {
  5189.             search = null;
  5190.             Function Unicode_f = null;  // Remember which was the unicode version.
  5191.             String rootname = null;
  5192.             f = (Function) Functions.elementAt(i);
  5193.             // Check whether last character is an 'A' or a 'W'
  5194.             // Special cases:            Other version:          Expose as:
  5195.             // CommandLineToArgvW    --> X                       CommandLineToArgvW
  5196.             // GetEnviromentStringsW --> GetEnvironmentStrings   GetEnvironmentStrings
  5197.             // LHashValOfNameSysA    --> LHashValOfNameSys       LHashValOfNameSys
  5198.             // ReadDirectoryChangesW --> X                       ReadDirectoryChangesW
  5199.             // wglGetProcAddress     --> X (only ASCII version)  wglGetProcAddress
  5200.             // CharPrevExA           --> X                       CharPrevExA
  5201.             // CharNextExA           --> X                       CharNextExA
  5202.             // RegisterMediaTypesW   --> RegisterMediaTypes      RegisterMediaTypes
  5203.             // LineDDA is NOT a string function.  It just ends with a 'A'.
  5204.             if(f.getName().endsWith("A") && !f.getName().equals("LineDDA")) {
  5205.                 rootname = f.getName().substring(0, f.getName().length()-1);
  5206. //                System.out.println("Searching for function root " + rootname);
  5207.                 // Handle special cases.  Append 'W' in normal case.
  5208.                 if(!rootname.equals("LHashValOfNameSys"))
  5209.                     search = rootname + "W";
  5210.             }
  5211.             else if(f.getName().endsWith("W")) {
  5212.                 rootname = f.getName().substring(0, f.getName().length()-1);
  5213. //                System.out.println("Searching for function root " + rootname);
  5214.                 // Handle special cases.  Append 'A' in normal case.
  5215.                 if(!rootname.equals("CommandLineToArgv") && !rootname.equals("ReadDirectoryChanges")) {
  5216.                     if(rootname.equals("GetEnvironmentStrings") || rootname.equals("RegisterMediaTypes"))
  5217.                         search = rootname;
  5218.                     else
  5219.                         search = rootname + "A";  // Normal case.
  5220.                 }
  5221.                 Unicode_f = f;
  5222.             }
  5223.             // look up search in Functions list. If found, remove one and rename Unicode one.
  5224.             if(search!=null) {
  5225.                 Function search_func = findFunction(search);
  5226.                 if(search_func != null) {
  5227. //                    System.out.println("Removing " + f.getName() + " and " + search + ", replacing with " + rootname);
  5228. //                    System.out.print(".");
  5229.                     // Leave the Unicode one in our Function array - types are closer to Java.
  5230.                     if(Unicode_f == null) {
  5231.                         Functions.removeElement(f);
  5232.                         Unicode_f = search_func;
  5233.                     } else
  5234.                         Functions.removeElement(search_func);
  5235.                     Unicode_f.setName(rootname);
  5236.                 }
  5237.                 else
  5238.                     System.out.println("\r\nFound one version of a function ("+f.getName()+"), but not the other!");
  5239.             }
  5240.         }
  5241.         //System.out.println("Done.");
  5242.     }
  5243.  
  5244.     /**
  5245.      * Scans through read in functions, looking for the ASCII and Unicode versions of
  5246.      * any such functions.  If it finds them both, it will strip off the last 
  5247.      * character, merging them into one function call.  Deals with the 4 special
  5248.      * cases I found in the Win32 API.
  5249.      * @return No return value.
  5250.      */
  5251.     public void UnifyStructures()
  5252.     {
  5253.         multiFieldDataStructure data;
  5254.         multiFieldDataStructure ASCIIdata;
  5255.         multiFieldDataStructure Unicodedata;
  5256.         String rootname = null;
  5257.         System.out.print("Unifying ASCII and Unicode versions of data structures... ");
  5258.         // Must use enumeration interface
  5259.         Enumeration e = StructureLUT.elements();
  5260.         while(e.hasMoreElements()) {
  5261.             ASCIIdata = null;
  5262.             Unicodedata = null;
  5263.             data = (multiFieldDataStructure) e.nextElement();
  5264.  
  5265.           if(data.getName().endsWith("A")) {
  5266.                 ASCIIdata = data;
  5267.                 rootname = data.getName().substring(0, data.getName().length()-1);
  5268.                 Unicodedata = (multiFieldDataStructure) StructureLUT.get(rootname+"W");
  5269.             }
  5270.             else if(data.getName().endsWith("W")) {
  5271.                 Unicodedata = data;
  5272.                 rootname = data.getName().substring(0, data.getName().length()-1);
  5273.                 ASCIIdata = (multiFieldDataStructure) StructureLUT.get(rootname+"A");
  5274.             }
  5275.             if(Unicodedata != null && ASCIIdata != null) {
  5276.                 if(Unicodedata == ASCIIdata) {
  5277.                     System.out.println("For "+data.getName()+", two structures were equal!");
  5278.                     continue;
  5279.                 }
  5280. //                System.out.print("Unifying structs to "+rootname+"... ");
  5281.                 Unicodedata.setMerged(true);
  5282.                 Unicodedata.addAltName(Unicodedata.getName());
  5283.                 Unicodedata.setName(rootname);
  5284.                 Unicodedata.addAltName(rootname+"A");
  5285.                 // Get all of ascii version's alias names and put them into unicode's aliases?
  5286.                 //ASCIIdata.setName(rootname);
  5287.                 StructureLUT.remove(ASCIIdata.getName());
  5288.                 //System.out.print("removing "+ASCIIdata.numAltNames()+" altnames... ");
  5289.                 for(int i=0; i<ASCIIdata.numAltNames(); i++) {
  5290.                     String altname = ASCIIdata.getAltName(i);
  5291.                     Unicodedata.addAltName(altname);
  5292.                     StructureLUT.remove(altname);  // give it key to remove...
  5293.                     StructureLUT.put(altname, Unicodedata);
  5294.                 }
  5295.                 //System.out.print("copied names... ");
  5296.                 e = StructureLUT.elements();
  5297. //                System.out.println("Done.");
  5298.                 continue;
  5299.             }
  5300.         }
  5301.         System.out.println("Done with data structure unification.");
  5302.     }  // end UnifyStructures
  5303.  
  5304.     /**
  5305.      * Builds file Include and Exclude lists.  Here is where we set IncludeHeaders
  5306.      * and ExcludeHeaders to their original values.  This should be edited when you add
  5307.      * a new set of libraries, although the default rules should let your own header files
  5308.      * be parsed with a warning.  Remember, this program can't parse COM.
  5309.      * @return No return value.
  5310.      */
  5311.     protected void SetupFileFilters()
  5312.     {
  5313.         ExcludeHeaders = new Vector();
  5314.         IncludeHeaders = new Vector();
  5315.  
  5316.         // Standard headers
  5317.         ExcludeHeaders.addElement("stdlib.h");
  5318.         ExcludeHeaders.addElement("stdarg.h");
  5319.         ExcludeHeaders.addElement("stdio.h");
  5320.         ExcludeHeaders.addElement("string.h");
  5321.         ExcludeHeaders.addElement("strings.h");
  5322.         ExcludeHeaders.addElement("varargs.h");
  5323.         ExcludeHeaders.addElement("math.h");
  5324.         // Can't process any COM libraries.
  5325.         ExcludeHeaders.addElement("ole.h");
  5326.         ExcludeHeaders.addElement("ole2.h");
  5327.         ExcludeHeaders.addElement("ole2ver.h");
  5328.         ExcludeHeaders.addElement("oleauto.h");
  5329.         ExcludeHeaders.addElement("olectl.h");
  5330.         ExcludeHeaders.addElement("olectlid.h");
  5331.         ExcludeHeaders.addElement("oledlg.h");
  5332.         ExcludeHeaders.addElement("oleidl.h");
  5333.         ExcludeHeaders.addElement("olenls.h");
  5334.  
  5335.         ExcludeHeaders.addElement("imm.h");
  5336.         ExcludeHeaders.addElement("excpt.h");
  5337.         ExcludeHeaders.addElement("winsvc.h");
  5338.         ExcludeHeaders.addElement("mcx.h");     // modem control
  5339. //        ExcludeHeaders.addElement("winnls.h");  // natural language services
  5340.         ExcludeHeaders.addElement("winnetwk.h");
  5341.         ExcludeHeaders.addElement("winsock.h");
  5342.         ExcludeHeaders.addElement("winsock2.h");
  5343.         ExcludeHeaders.addElement("dde.h");     // dynamic data exchange
  5344.         ExcludeHeaders.addElement("ddeml.h");   // Sobesky says DDE is implemented badly with many 95/NT differences
  5345.         ExcludeHeaders.addElement("winreg.h");  // registry
  5346.         ExcludeHeaders.addElement("nb30.h");    // netbios
  5347.         ExcludeHeaders.addElement("winperf.h"); // performance monitor
  5348.         ExcludeHeaders.addElement("unknwn.h");  // RPC stubs
  5349.         ExcludeHeaders.addElement("wtypes.h");  // more RPC types?  Really gross file.
  5350.         ExcludeHeaders.addElement("cguid.h");   // odd constants?
  5351.         ExcludeHeaders.addElement("mswsock.h"); // MS socket Extensions, NT only????
  5352.         ExcludeHeaders.addElement("objbase.h"); // COM/OLE stuff
  5353.         ExcludeHeaders.addElement("aclapi.h");  // some ACL stuff (rest is in winbase.h)
  5354.         ExcludeHeaders.addElement("wintrust.h");
  5355.         ExcludeHeaders.addElement("ctype.h");   // ischar() type macros.
  5356.         ExcludeHeaders.addElement("urlmon.h");  // URL accessing functions (Uses COM)
  5357.         ExcludeHeaders.addElement("vfw.h");     // Video for Windows (Uses COM)
  5358.  
  5359.         // At this point, concentrate on these:
  5360.         // Kernel, User, GDI, Shell, commctrl, commdlg
  5361.         IncludeHeaders.addElement("gen.h");     // My wrapper for generating mega.prep.
  5362.         IncludeHeaders.addElement("windows.h"); // Doesn't declare any functions
  5363.         IncludeHeaders.addElement("winuser.h");
  5364.         IncludeHeaders.addElement("wingdi.h");
  5365.         IncludeHeaders.addElement("winbase.h");
  5366.         IncludeHeaders.addElement("winnt.h");
  5367.         IncludeHeaders.addElement("windef.h");
  5368.         IncludeHeaders.addElement("shellapi.h");
  5369.         IncludeHeaders.addElement("winerror.h");// no functions, but probably worth including.
  5370.         IncludeHeaders.addElement("winver.h");  // version of windows files
  5371.         IncludeHeaders.addElement("cderr.h");   // No functions here, but we need it.
  5372.         IncludeHeaders.addElement("commdlg.h");
  5373.         IncludeHeaders.addElement("dlgs.h");    // no functions, but...
  5374.         IncludeHeaders.addElement("prsht.h");   // CommCtrl.h & windows.h include this
  5375.  
  5376.         // Not included by windows.h, but important.
  5377.         IncludeHeaders.addElement("commctrl.h");// CommCtrl
  5378.  
  5379.         // OpenGL
  5380.         IncludeHeaders.addElement("gl.h");
  5381.         IncludeHeaders.addElement("glu.h");
  5382.         IncludeHeaders.addElement("glaux.h");
  5383.         IncludeHeaders.addElement("GL/gl.h");
  5384.         IncludeHeaders.addElement("GL/glu.h");
  5385.         IncludeHeaders.addElement("GL/glaux.h");
  5386.  
  5387.         // Added for the Java Office group (they call these functions)
  5388.         IncludeHeaders.addElement("winnls.h");  // language services?
  5389.         IncludeHeaders.addElement("winspool.h");// printer
  5390.  
  5391.         // Added because people thought it was cool
  5392.         IncludeHeaders.addElement("mmsystem.h");// MCI (multimedia control interface)
  5393.         IncludeHeaders.addElement("mciavi.h");  // Movie player
  5394.  
  5395.         // Added for no good reason
  5396.         IncludeHeaders.addElement("wincon.h");  // NT Console
  5397.         IncludeHeaders.addElement("wincrypt.h");
  5398.         IncludeHeaders.addElement("lzexpand.h");// LZ
  5399.         IncludeHeaders.addElement("wininet.h"); // Windows internet wrappers (FTP, etc)
  5400.  
  5401.         // Need to process these to get the alignment of the C structures.
  5402.         IncludeHeaders.addElement("pshpack1.h");
  5403.         IncludeHeaders.addElement("pshpack2.h");
  5404.         IncludeHeaders.addElement("pshpack4.h");
  5405.         IncludeHeaders.addElement("pshpack8.h");
  5406.         IncludeHeaders.addElement("poppack.h");
  5407.     }
  5408.  
  5409.  
  5410.     /**
  5411.      * Initializes hash table containing package files for each of the DLL's.  To add
  5412.      * a new output class, create a PrintWriter for it, output the header info and class
  5413.      * name to it, and add it to the hash table, using the symbol file name as the key.
  5414.      * This function totally controls how various functions are routed into their own
  5415.      * Java classes.
  5416.      * @return No return value.
  5417.      */
  5418.     protected void SetupOutputClasses()
  5419.     {
  5420.         OutputClasses = new Hashtable();
  5421.         String path = "com\\ms\\win32\\";
  5422.         
  5423.         try {
  5424.             // Create a PrintWriter associated with the output file.
  5425.             PrintWriter kernel = new PrintWriter(new FileOutputStream(path+"Kernel32.java"));
  5426.             PrintWriter user = new PrintWriter(new FileOutputStream(path+"User32.java"));
  5427.             PrintWriter shell = new PrintWriter(new FileOutputStream(path+"Shell32.java"));
  5428.             PrintWriter gdi = new PrintWriter(new FileOutputStream(path+"Gdi32.java"));
  5429.             PrintWriter spool = new PrintWriter(new FileOutputStream(path+"Spoolss.java"));
  5430.             PrintWriter advapi = new PrintWriter(new FileOutputStream(path+"Advapi32.java"));
  5431.             PrintWriter comdlg = new PrintWriter(new FileOutputStream(path+"Comdlg32.java"));
  5432.             PrintWriter commctrl = new PrintWriter(new FileOutputStream(path+"Comctl32.java"));
  5433.             PrintWriter winmm = new PrintWriter(new FileOutputStream(path+"Winmm.java"));
  5434.             PrintWriter misc = new PrintWriter(new FileOutputStream(path+"Misc.java"));
  5435.             PrintWriter opengl = new PrintWriter(new FileOutputStream(path+"OpenGL.java"));
  5436.             PrintWriter lz = new PrintWriter(new FileOutputStream(path+"Lz32.java"));
  5437.             PrintWriter mapi = new PrintWriter(new FileOutputStream(path+"Mapi32.java"));
  5438.             PrintWriter wininet = new PrintWriter(new FileOutputStream(path+"Wininet.java"));
  5439.  
  5440.             String Header = CopyrightNotice 
  5441.                 +"\r\n\r\npackage "+PackageName+";\r\n\r\npublic class ";
  5442.             // Output the package name and other necessary tokens
  5443.             kernel.println(Header+"Kernel32 {");
  5444.             user.println(Header+"User32 {");
  5445.             shell.println(Header+"Shell32 {");
  5446.             gdi.println(Header+"Gdi32 {");
  5447.             spool.println(Header+"Spoolss {");
  5448.             advapi.println(Header+"Advapi32 {");
  5449.             comdlg.println(Header+"Comdlg32 {");
  5450.             commctrl.println(Header+"Comctl32 {");
  5451.             winmm.println(Header+"Winmm {");
  5452.             misc.println(Header+"Misc {");
  5453.             opengl.println(Header+"OpenGL {");
  5454.             lz.println(Header+"Lz32 {");
  5455.             mapi.println(Header+"Mapi32 {");
  5456.             wininet.println(Header+"Wininet {");
  5457.  
  5458.             // Here you set up the mapping between the DLL the function occurs in and 
  5459.             // the output class.  Use all upper case and this must match the name of the
  5460.             // symbol file (without the .sym) generated by dumpbin.
  5461.             OutputClasses.put("KERNEL32", kernel);
  5462.             OutputClasses.put("USER32", user);
  5463.             OutputClasses.put("SHELL32", shell);
  5464.             OutputClasses.put("GDI32", gdi);
  5465.             OutputClasses.put("SPOOLSS", spool);
  5466.             OutputClasses.put("ADVAPI32", advapi);
  5467.             OutputClasses.put("COMDLG32", comdlg);
  5468.             OutputClasses.put("COMCTL32", commctrl);
  5469.             OutputClasses.put("WINMM", winmm);
  5470.             OutputClasses.put("GLU32", opengl);
  5471.             OutputClasses.put("OPENGL32", opengl);
  5472.             OutputClasses.put("LZ32", lz);
  5473.             OutputClasses.put("MAPI32", mapi);
  5474.             OutputClasses.put("WININET", wininet);
  5475.             OutputClasses.put("WINTRUST", misc);
  5476.             OutputClasses.put("VERSION", misc);
  5477.             // Default case - if a function isn't listed in any symbol file.
  5478.             OutputClasses.put(UnknownLibraryString, misc);
  5479.         }
  5480.         catch (IOException e) {
  5481.             System.out.println("problem in SetupOutputClasses(): "+e);
  5482.             System.exit(2);
  5483.         }    
  5484.     }
  5485.  
  5486.     /**
  5487.      * Set up a table of C operator precedence.  Taken from the VC++ 5 online help.
  5488.      * Keys are String's containing operator and values are ints describing precedence,
  5489.      * with 0 being the lowest.  Duplicate entries are handled by appending odd 
  5490.      * characters that convey some sense of the meaning with them.  I spaced out the
  5491.      * precedence numbers to add new operators, in case the table was incomplete or if
  5492.      * the ISO committee goes change-happy.
  5493.      * @return No return value.
  5494.      */
  5495.     protected void SetupPrecedenceTable()
  5496.     {
  5497.         Precedence = new Hashtable();
  5498.         // Anyone remember line numbers in BASIC?
  5499.         Precedence.put(",", new Operator(",", false, false, 10));
  5500.         Precedence.put("*=", new Operator("*=", false, false, 20));
  5501.         Precedence.put("/=", new Operator("/=", false, false, 20));
  5502.         Precedence.put("%=", new Operator("%=", false, false, 20));
  5503.         Precedence.put("+=", new Operator("+=", false, false, 20));
  5504.         Precedence.put("-=", new Operator("-=", false, false, 20));
  5505.         Precedence.put("<<=", new Operator("<<=", false, false, 20));
  5506.         Precedence.put(">>=", new Operator(">>=", false, false, 20));
  5507.         Precedence.put("&=", new Operator("&=", false, false, 20));
  5508.         Precedence.put("^=", new Operator("^=", false, false, 20));
  5509.         Precedence.put("|=", new Operator("|=", false, false, 20));
  5510.         Precedence.put("=", new Operator("=", false, false, 30));
  5511.         Precedence.put("?:", new Operator("?:", false, false, 40));
  5512.         Precedence.put("||", new Operator("||", false, false, 50));
  5513.         Precedence.put("&&", new Operator("&&", false, false, 60));
  5514.         Precedence.put("|", new Operator("|", false, false, 70));
  5515.         Precedence.put("^", new Operator("^", false, false, 80));
  5516.         Precedence.put("&", new Operator("&", false, false, 90));  // bitwise and, not address
  5517.         Precedence.put("!=", new Operator("!=", false, false, 100));
  5518.         Precedence.put("==", new Operator("==", false, false, 110));
  5519.         Precedence.put(">=", new Operator(">=", false, false, 120));
  5520.         Precedence.put(">", new Operator(">", false, false, 130));
  5521.         Precedence.put("<=", new Operator("<=", false, false, 140));
  5522.         Precedence.put("<", new Operator("<", false, false, 150));
  5523.         Precedence.put(">>", new Operator(">>", false, false, 160));
  5524.         Precedence.put("<<", new Operator("<<", false, false, 170));
  5525.         Precedence.put("-", new Operator("-", false, false, 180));  // subtraction
  5526.         Precedence.put("+", new Operator("+", false, false, 190));
  5527.         Precedence.put("%", new Operator("%", false, false, 200));
  5528.         Precedence.put("/", new Operator("/", false, false, 210));
  5529.         Precedence.put("*", new Operator("*", false, false, 220));  // multiplication, not dereference
  5530.         // Here the help gets a little weird.  I'm not sure how to interpret
  5531.         // ->*  and .*_  They're described as pointers to members, for pointers vs. objects
  5532.         Precedence.put("->*", new Operator("->*", false, false, 230));
  5533.         Precedence.put(".*_", new Operator(".*_", false, false, 240));
  5534.         Precedence.put("(cast)", new Operator("(cast)", true, true, 250));
  5535.         Precedence.put("delete", new Operator("delete", true, true, 260));
  5536.         Precedence.put("new", new Operator("new", true, true, 270));
  5537.         Precedence.put("sizeof", new Operator("sizeof", true, true, 280));
  5538.         Precedence.put("*u", new Operator("*", true, true, 290));    // dereference, not multiplication
  5539.         Precedence.put("&u", new Operator("&", true, true, 300));    // address, not bitwise and
  5540.         Precedence.put("+u", new Operator("+", true, true, 310));    // unary plus
  5541.         Precedence.put("-u", new Operator("-", true, true, 320));    // unary minus
  5542.         Precedence.put("~", new Operator("~", true, true, 330));
  5543.         Precedence.put("!", new Operator("/", true, true, 340));
  5544.         Precedence.put("--p", new Operator("--", true, true, 350));   // pre-decrement
  5545.         Precedence.put("++p", new Operator("++", true, true, 360));   // pre-increment
  5546.         Precedence.put(".", new Operator("%", false, false, 370));   // struct or union member
  5547.         Precedence.put("->", new Operator("->", false, false, 380));
  5548.         Precedence.put("[]", new Operator("[]", true, false, 390));
  5549.         Precedence.put("()", new Operator("()", false, false, 400)); // function call
  5550.         Precedence.put("--", new Operator("--", true, false, 410)); // post-decrement
  5551.         Precedence.put("++", new Operator("++", true, false, 420)); // post-increment
  5552.     }
  5553.  
  5554.     /**
  5555.      * Returns the Operator corresponding to the operator string.  Contains precedent
  5556.      * information, etc.
  5557.      * @param operator String with the name of the operator
  5558.      * @param unary is this a unary operator vs. binary
  5559.      * @param prefix is this a prefix operator vs. postfix or infix
  5560.      * @return Operator with same name as operator in appropriate contexts.
  5561.      * @exception BadOperationException if operator isn't found
  5562.      */
  5563.     Operator getOperator(String operator, boolean unary, boolean prefix) throws BadOperationException
  5564.     {
  5565.         Operator op = (Operator) Precedence.get(operator);
  5566.         if(op == null)
  5567.             throw new BadOperationException("getPrecedence called with illegal operator \""+operator+"\"");
  5568.  
  5569.         // Check op to make sure it's the correct operator.
  5570.         if(unary ^ op.isUnaryOperator() || prefix ^ op.isPrefixOperator()) {
  5571.             // Got wrong operator.
  5572.             if(unary)
  5573.                 op = (Operator) Precedence.get(operator+"u");
  5574.             if(op==null)
  5575.                 op = (Operator) Precedence.get(operator+"p");
  5576.         }
  5577.  
  5578.         if(op!=null && unary == op.isUnaryOperator() && prefix == op.isPrefixOperator())
  5579.             return op;
  5580.         else {
  5581.             if(op==null)
  5582.                 throw new BadOperationException("getPrecedence called with unknown operator \""+operator+"\", with constraints unary: "+unary+"  prefix: "+prefix);
  5583.             else
  5584.                 throw new BadOperationException("getPrecedence called with unknown operator \""+operator+"\", with constraints unary: "+unary+"  prefix: "+prefix+"\r\nOperator - isUnary: "+op.isUnaryOperator()+"  isPrefix: "+op.isPrefixOperator());
  5585.         }
  5586.     }
  5587.  
  5588.     
  5589.     /**
  5590.      * Decides if we should examine the current file or not.  Checks IncludeHeaders, 
  5591.      * ExcludeHeaders, whether its an IDL file, and whether it starts with "mm".
  5592.      * @param File Header file we may want to parse.
  5593.      * @return true if we should parse it, else false.
  5594.      */
  5595.     protected boolean CheckFile(String File)
  5596.     {
  5597.         String header;
  5598.         if(File.equals(UnknownFileString))
  5599.             return true;
  5600.         for(int i=0; i<IncludeHeaders.size(); i++)
  5601.             if(File.equals((String) IncludeHeaders.elementAt(i)))
  5602.                 return true;
  5603.         for(int i=0; i<ExcludeHeaders.size(); i++)
  5604.             if(File.equals((String) ExcludeHeaders.elementAt(i)))
  5605.                 return false;
  5606.  
  5607.         // Ignore IDL files.
  5608.         if(File.endsWith("idl.h"))
  5609.             return false;
  5610.         // Ignore RPC files
  5611.         if(File.startsWith("rpc"))
  5612.             return false;
  5613.  
  5614.         System.out.println("Don't know about parsing " + File + "...  Will parse anyway.");
  5615.         return true;
  5616.     }  // end CheckFile(String)
  5617.  
  5618.  
  5619.     /**
  5620.      * Finds a Function with the given name in the Functions vector, returning the 
  5621.      * Function object.
  5622.      * @param Name Name of the Function to look for.
  5623.      * @return reference to the Function or null if a function with that name didn't exist.
  5624.      */
  5625.     protected Function findFunction(String Name)
  5626.     {
  5627.         for(int i=0; i<Functions.size(); i++) {
  5628.             Function f = (Function) Functions.elementAt(i);
  5629.             if(Name.equals(f.getName()))
  5630.                 return f;
  5631.         }
  5632.         return null;
  5633.     }
  5634.  
  5635.     /**
  5636.      * Finds which library function occurs in based on loaded symbol files.  Assumes the
  5637.      * symbol tables have been set up to be effective.  Changes Function's library field.
  5638.      * @param func Function to search for in symbol tables.
  5639.      * @return No return value.
  5640.      */
  5641.     protected void FindLibrary(Function func) throws InvalidParameterException
  5642.     {
  5643.         if(func == null || func.getName() == null)
  5644.             throw new InvalidParameterException("FindLibrary passed an invalid Function object.");
  5645.         if(Symbols == null)
  5646.             return;
  5647.         Function sym = null;
  5648.         for(int i=0; i<Symbols.size(); i++) {
  5649.             Function f = (Function) Symbols.elementAt(i);
  5650.             if(func.getName().equals(f.getName())) {
  5651.                 sym = f;
  5652.                 break;
  5653.             }
  5654.         }
  5655.         if(sym == null)
  5656.             func.setLibrary(UnknownLibraryString);
  5657.         else
  5658.             func.setLibrary(sym.getLibrary());
  5659.     }
  5660.  
  5661.  
  5662.     /**
  5663.      * Given a file name for a list of function names, it will print out the
  5664.      * ones not in the parser's internal storage.  Writes out the missing
  5665.      * function names to the screen and to a file.
  5666.      * @param OfficeFileName File containing a list of function names, separated by whitespace
  5667.      * @param MissingFileName File to output all missing function names to
  5668.      * @return No return value.
  5669.      */
  5670.     public void OfficeFunctions(String OfficeFileName, String MissingFileName)
  5671.     {
  5672.         try {
  5673.             System.out.println("Looking for missing functions... ");
  5674.             FileInputStream off = new FileInputStream(OfficeFileName);
  5675.             StreamTokenizer st = new StreamTokenizer(new InputStreamReader(off));
  5676.             PrintWriter missing = new PrintWriter(new FileOutputStream(MissingFileName));
  5677.             int numMissing = 0;
  5678.             st.eolIsSignificant(false);
  5679.  
  5680.             while(st.nextToken() != StreamTokenizer.TT_EOF) {
  5681.                 if(st.ttype == StreamTokenizer.TT_WORD) {
  5682.                     Function f = findFunction(st.sval);
  5683.                     if(f == null) {
  5684.                         System.out.println("Missing: " + st.sval);
  5685.                         missing.println(st.sval);
  5686.                         numMissing++;
  5687.                     }
  5688.                 } // end word
  5689.             }  // end while
  5690.  
  5691.             System.out.println("Missing " + numMissing + " Office functions.");
  5692.             missing.close();
  5693.             missing = null;
  5694.         }
  5695.         catch (IOException e) {
  5696.             System.out.println("IOException in OfficeFunctions: " + e);
  5697.             e.printStackTrace();
  5698.         }
  5699.     }
  5700.  
  5701.     /**
  5702.      * Prints the functions out to the PrintWriter.  Uses the format specified in
  5703.      * Function::toString().
  5704.      * @param pw PrintWriter to send output to.
  5705.      * @return No return value.
  5706.      */
  5707.     public void WriteOutFunctions(PrintWriter pw)
  5708.     {
  5709.         System.out.print("Writing out to file... ");
  5710.         for(int i=0; i<Functions.size(); i++)
  5711.             pw.print(((Function)Functions.elementAt(i)).toString());
  5712.         System.out.println("Done.");
  5713.     } // end WriteOutFunctions(PrintWriter p)
  5714.  
  5715.     /**
  5716.      * Reads in a file containing filenames of symbol files, then subsequently parses each 
  5717.      * symbol file.  Filenames should be separated by newlines.  Comment char is '#'.
  5718.      * @param list name of file containing paths to symbol files.
  5719.      * @return No return value.
  5720.      * @exception InvalidParameterException if list file isn't in the correct format.
  5721.      */
  5722.     public void ReadListofSymbolFiles(String list) throws InvalidParameterException
  5723.     {
  5724.         boolean have_symbols = false;
  5725.         try {
  5726.             InputStreamReader isr = new InputStreamReader((InputStream) new FileInputStream(list));
  5727.             StreamTokenizer st = new StreamTokenizer(isr);
  5728.             st.eolIsSignificant(false);
  5729.             st.slashSlashComments(true);
  5730.             st.slashStarComments(true);
  5731.             st.commentChar('#');
  5732.             st.wordChars('\\', '\\');
  5733.             st.wordChars('.', '.');
  5734.             st.wordChars(':', ':');
  5735.             System.out.println("Reading DLL symbol files... ");
  5736.             while(st.nextToken() != st.TT_EOF) {
  5737.                 if(st.ttype != st.TT_WORD) {
  5738.                     System.out.println("Ack!  list of symbol files \""+list+"\" contained a non-word character!");
  5739.                     System.out.println("Expected list of symbol files, like:\r\nc:\\symbols\\r\nt\\shell32.sym\r\nc:\\symbols\\r\nt\\kernel32.sym\r\n");
  5740.                     throw new InvalidParameterException("list of symbol files \""+list+"\" was bad!");
  5741.                 }
  5742.                 try {
  5743.                     ParseSymbolFile(st.sval);
  5744.                     have_symbols = true;
  5745.                 }
  5746.                 catch(BadInputFileException e) {
  5747.                     System.out.println("Skipping a bad symbol file! "+st.sval+"\r\n"+e.BadFile);
  5748.                 }
  5749.             }
  5750.             st = null;
  5751.             isr.close();
  5752.             isr = null;
  5753.  
  5754.             com.ms.util.VectorSort.sort(Symbols, new FunctionCompare());
  5755.             System.out.println("Done reading symbols.");
  5756.         }
  5757.         catch(FileNotFoundException fnfe) {
  5758.             System.out.println("Couldn't find file \""+list+"\"");
  5759.         }
  5760.         catch(IOException e) {
  5761.             System.out.println("Error while reading file \""+list+"\"");
  5762.             System.out.println(e);
  5763.         }
  5764.         finally {
  5765.             if(!have_symbols) {
  5766.                 System.out.print("No symbols were read in.  ");
  5767.                 if(Suppress_UnknownLib_Functions)
  5768.                     System.out.println("All functions will be suppressed.");
  5769.                 else
  5770.                     System.out.println("Functions will be output to Misc.java.");
  5771.             }
  5772.         }
  5773.     }
  5774.  
  5775.     /**
  5776.      * Main.  Runs the application.
  5777.      * @param args[] Array of Strings containing command line parameters.
  5778.      * @return No return value.
  5779.      */
  5780.     public static final void main(String args[])
  5781.     {
  5782.         System.out.println("Win32 API header file parser, v"+version);
  5783.         if(args.length == 0) {
  5784.             usage();
  5785.             System.exit(1);
  5786.         }
  5787.  
  5788.         Parser parse = new Parser();
  5789.  
  5790.         try {
  5791.             if(ReadSymbols) {
  5792.                 parse.ReadListofSymbolFiles("symbolfiles.txt");
  5793.             }
  5794.  
  5795.             for(int i=0; i<args.length; i++) {
  5796.                 System.out.println("Processing \"" + args[i] + "\"...");
  5797.                 parse.ParseFile(args[i]);
  5798.  
  5799.                 System.gc();  // ParseFile generates a hideous amount of garbage.
  5800.  
  5801.                 //if(i+1 < args.length)
  5802.                 //    parse.ParseSymbolFile(args[i+1]);
  5803.  
  5804.                 // Sort Vector of Functions.
  5805.                 System.out.print("Sorting... ");
  5806.                 com.ms.util.VectorSort.sort(parse.Functions, new FunctionCompare());
  5807.                 //com.ms.util.VectorSort.sort(parse.Symbols, new FunctionCompare());
  5808.                 System.out.println("Done.");
  5809.  
  5810.                 // Do something interesting
  5811.                 //if(ReadSymbols)
  5812.                 //    parse.CompareFunctionWithSymbols();
  5813.  
  5814. //                parse.OfficeFunctions("office.txt", "missing.txt");
  5815.  
  5816.                 parse.UnifyFunctions();
  5817.                 parse.UnifyStructures();
  5818.  
  5819.                 // Converts C prototypes to Java
  5820.                 parse.Convert();
  5821.  
  5822.                 PrintWriter out = new PrintWriter(new FileOutputStream(args[i] + ".parse"));
  5823.                 parse.WriteOutFunctions(out);
  5824.                 out.close();
  5825.             }
  5826.             System.out.println("Parsing and translation complete.");
  5827.         }
  5828.         catch (IOException e)
  5829.         {
  5830.             System.out.println("Ack!  IO Exception during output!");
  5831.             System.out.println(e);
  5832.             e.printStackTrace();
  5833.         }
  5834.         catch(UnrecognizedCodeException e) {
  5835.             System.out.println(e);
  5836.             System.out.println(e.BadFragment);
  5837.             e.printStackTrace();
  5838.         }
  5839.         catch(InvalidParameterException e) {
  5840.             System.out.println(e);
  5841.             System.out.println(e.Description);
  5842.             e.printStackTrace();
  5843.         }
  5844.         catch (Exception e)
  5845.         {
  5846.             System.out.println("Uncaught exception in main.  " + e);
  5847.             e.printStackTrace();
  5848.         }
  5849.         finally {
  5850.             // Force finalizer to run and close files.
  5851.             parse.finalizer();
  5852.             parse = null;
  5853.             //System.runFinalization();
  5854.             System.gc();
  5855.         }
  5856.     } // end main
  5857. }
  5858.