src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Utility.java
changeset 55496 8e0ae3830fca
parent 48409 5ab69533994b
equal deleted inserted replaced
55495:badfa812b82a 55496:8e0ae3830fca
     1 /*
     1 /*
     2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
     3  */
     3  */
     4 /*
     4 /*
     5  * Licensed to the Apache Software Foundation (ASF) under one or more
     5  * Licensed to the Apache Software Foundation (ASF) under one or more
     6  * contributor license agreements.  See the NOTICE file distributed with
     6  * contributor license agreements.  See the NOTICE file distributed with
     7  * this work for additional information regarding copyright ownership.
     7  * this work for additional information regarding copyright ownership.
    40 import com.sun.org.apache.bcel.internal.util.ByteSequence;
    40 import com.sun.org.apache.bcel.internal.util.ByteSequence;
    41 
    41 
    42 /**
    42 /**
    43  * Utility functions that do not really belong to any class in particular.
    43  * Utility functions that do not really belong to any class in particular.
    44  *
    44  *
    45  * @version $Id: Utility.java 1751107 2016-07-03 02:41:18Z dbrosius $
    45  * @version $Id$
    46  * @LastModified: Oct 2017
    46  * @LastModified: Jun 2019
    47  */
    47  */
    48 // @since 6.0 methods are no longer final
    48 // @since 6.0 methods are no longer final
    49 public abstract class Utility {
    49 public abstract class Utility {
    50 
    50 
    51     private static int unwrap(final ThreadLocal<Integer> tl) {
    51     private static int unwrap( final ThreadLocal<Integer> tl ) {
    52         return tl.get().intValue();
    52         return tl.get();
    53     }
    53     }
    54 
    54 
    55     private static void wrap(final ThreadLocal<Integer> tl, final int value) {
    55 
    56         tl.set(Integer.valueOf(value));
    56     private static void wrap( final ThreadLocal<Integer> tl, final int value ) {
       
    57         tl.set(value);
    57     }
    58     }
    58 
    59 
    59     private static ThreadLocal<Integer> consumed_chars = new ThreadLocal<Integer>() {
    60     private static ThreadLocal<Integer> consumed_chars = new ThreadLocal<Integer>() {
    60 
    61 
    61         @Override
    62         @Override
    62         protected Integer initialValue() {
    63         protected Integer initialValue() {
    63             return Integer.valueOf(0);
    64             return 0;
    64         }
    65         }
    65     };/* How many chars have been consumed
    66     };/* How many chars have been consumed
    66      * during parsing in signatureToString().
    67      * during parsing in signatureToString().
    67      * Read by methodSignatureToString().
    68      * Read by methodSignatureToString().
    68      * Set by side effect,but only internally.
    69      * Set by side effect,but only internally.
    69      */
    70      */
    70 
       
    71     private static boolean wide = false; /* The `WIDE' instruction is used in the
    71     private static boolean wide = false; /* The `WIDE' instruction is used in the
    72      * byte code to allow 16-bit wide indices
    72      * byte code to allow 16-bit wide indices
    73      * for local variables. This opcode
    73      * for local variables. This opcode
    74      * precedes an `ILOAD', e.g.. The opcode
    74      * precedes an `ILOAD', e.g.. The opcode
    75      * immediately following takes an extra
    75      * immediately following takes an extra
    80 
    80 
    81 
    81 
    82     /**
    82     /**
    83      * Convert bit field of flags into string such as `static final'.
    83      * Convert bit field of flags into string such as `static final'.
    84      *
    84      *
    85      * @param access_flags Access flags
    85      * @param  access_flags Access flags
    86      * @return String representation of flags
    86      * @return String representation of flags
    87      */
    87      */
    88     public static String accessToString(final int access_flags) {
    88     public static String accessToString( final int access_flags ) {
    89         return accessToString(access_flags, false);
    89         return accessToString(access_flags, false);
    90     }
    90     }
    91 
    91 
       
    92 
    92     /**
    93     /**
    93      * Convert bit field of flags into string such as `static final'.
    94      * Convert bit field of flags into string such as `static final'.
    94      *
    95      *
    95      * Special case: Classes compiled with new compilers and with the
    96      * Special case: Classes compiled with new compilers and with the
    96      * `ACC_SUPER' flag would be said to be "synchronized". This is because SUN
    97      * `ACC_SUPER' flag would be said to be "synchronized". This is
    97      * used the same value for the flags `ACC_SUPER' and `ACC_SYNCHRONIZED'.
    98      * because SUN used the same value for the flags `ACC_SUPER' and
    98      *
    99      * `ACC_SYNCHRONIZED'.
    99      * @param access_flags Access flags
   100      *
   100      * @param for_class access flags are for class qualifiers ?
   101      * @param  access_flags Access flags
       
   102      * @param  for_class access flags are for class qualifiers ?
   101      * @return String representation of flags
   103      * @return String representation of flags
   102      */
   104      */
   103     public static String accessToString(final int access_flags, final boolean for_class) {
   105     public static String accessToString( final int access_flags, final boolean for_class ) {
   104         final StringBuilder buf = new StringBuilder();
   106         final StringBuilder buf = new StringBuilder();
   105         int p = 0;
   107         int p = 0;
   106         for (int i = 0; p < Const.MAX_ACC_FLAG; i++) { // Loop through known flags
   108         for (int i = 0; p < Const.MAX_ACC_FLAG; i++) { // Loop through known flags
   107             p = pow2(i);
   109             p = pow2(i);
   108             if ((access_flags & p) != 0) {
   110             if ((access_flags & p) != 0) {
   118             }
   120             }
   119         }
   121         }
   120         return buf.toString().trim();
   122         return buf.toString().trim();
   121     }
   123     }
   122 
   124 
       
   125 
   123     /**
   126     /**
   124      * @param access_flags the class flags
   127      * @param access_flags the class flags
   125      *
   128      *
   126      * @return "class" or "interface", depending on the ACC_INTERFACE flag
   129      * @return "class" or "interface", depending on the ACC_INTERFACE flag
   127      */
   130      */
   128     public static String classOrInterface(final int access_flags) {
   131     public static String classOrInterface( final int access_flags ) {
   129         return ((access_flags & Const.ACC_INTERFACE) != 0) ? "interface" : "class";
   132         return ((access_flags & Const.ACC_INTERFACE) != 0) ? "interface" : "class";
   130     }
   133     }
       
   134 
   131 
   135 
   132     /**
   136     /**
   133      * Disassemble a byte array of JVM byte codes starting from code line
   137      * Disassemble a byte array of JVM byte codes starting from code line
   134      * `index' and return the disassembled string representation. Decode only
   138      * `index' and return the disassembled string representation. Decode only
   135      * `num' opcodes (including their operands), use -1 if you want to decompile
   139      * `num' opcodes (including their operands), use -1 if you want to
   136      * everything.
   140      * decompile everything.
   137      *
   141      *
   138      * @param code byte code array
   142      * @param  code byte code array
   139      * @param constant_pool Array of constants
   143      * @param  constant_pool Array of constants
   140      * @param index offset in `code' array
   144      * @param  index offset in `code' array
   141      * <EM>(number of opcodes, not bytes!)</EM>
   145      * <EM>(number of opcodes, not bytes!)</EM>
   142      * @param length number of opcodes to decompile, -1 for all
   146      * @param  length number of opcodes to decompile, -1 for all
   143      * @param verbose be verbose, e.g. print constant pool index
   147      * @param  verbose be verbose, e.g. print constant pool index
   144      * @return String representation of byte codes
   148      * @return String representation of byte codes
   145      */
   149      */
   146     public static String codeToString(final byte[] code, final ConstantPool constant_pool,
   150     public static String codeToString( final byte[] code, final ConstantPool constant_pool, final int index,
   147             final int index, final int length, final boolean verbose) {
   151             final int length, final boolean verbose ) {
   148         // Should be sufficient // CHECKSTYLE IGNORE MagicNumber
   152         final StringBuilder buf = new StringBuilder(code.length * 20); // Should be sufficient // CHECKSTYLE IGNORE MagicNumber
   149         final StringBuilder buf = new StringBuilder(code.length * 20);
       
   150         try (ByteSequence stream = new ByteSequence(code)) {
   153         try (ByteSequence stream = new ByteSequence(code)) {
   151             for (int i = 0; i < index; i++) {
   154             for (int i = 0; i < index; i++) {
   152                 codeToString(stream, constant_pool, verbose);
   155                 codeToString(stream, constant_pool, verbose);
   153             }
   156             }
   154             for (int i = 0; stream.available() > 0; i++) {
   157             for (int i = 0; stream.available() > 0; i++) {
   155                 if ((length < 0) || (i < length)) {
   158                 if ((length < 0) || (i < length)) {
   156                     final String indices = fillup(stream.getIndex() + ":", 6, true, ' ');
   159                     final String indices = fillup(stream.getIndex() + ":", 6, true, ' ');
   157                     buf.append(indices)
   160                     buf.append(indices).append(codeToString(stream, constant_pool, verbose)).append('\n');
   158                             .append(codeToString(stream, constant_pool, verbose))
       
   159                             .append('\n');
       
   160                 }
   161                 }
   161             }
   162             }
   162         } catch (final IOException e) {
   163         } catch (final IOException e) {
   163             throw new ClassFormatException("Byte code error: " + buf.toString(), e);
   164             throw new ClassFormatException("Byte code error: " + buf.toString(), e);
   164         }
   165         }
   165         return buf.toString();
   166         return buf.toString();
   166     }
   167     }
   167 
   168 
   168     public static String codeToString(final byte[] code, final ConstantPool constant_pool,
   169 
   169             final int index, final int length) {
   170     public static String codeToString( final byte[] code, final ConstantPool constant_pool, final int index, final int length ) {
   170         return codeToString(code, constant_pool, index, length, true);
   171         return codeToString(code, constant_pool, index, length, true);
   171     }
   172     }
   172 
   173 
   173     /**
   174 
   174      * Disassemble a stream of byte codes and return the string representation.
   175     /**
   175      *
   176      * Disassemble a stream of byte codes and return the
   176      * @param bytes stream of bytes
   177      * string representation.
   177      * @param constant_pool Array of constants
   178      *
   178      * @param verbose be verbose, e.g. print constant pool index
   179      * @param  bytes stream of bytes
       
   180      * @param  constant_pool Array of constants
       
   181      * @param  verbose be verbose, e.g. print constant pool index
   179      * @return String representation of byte code
   182      * @return String representation of byte code
   180      *
   183      *
   181      * @throws IOException if a failure from reading from the bytes argument
   184      * @throws IOException if a failure from reading from the bytes argument occurs
   182      * occurs
       
   183      */
   185      */
   184     @SuppressWarnings("fallthrough") // by design for case Const.INSTANCEOF
   186     @SuppressWarnings("fallthrough") // by design for case Const.INSTANCEOF
   185     public static String codeToString(final ByteSequence bytes, final ConstantPool constant_pool,
   187     public static String codeToString(final ByteSequence bytes, final ConstantPool constant_pool,
   186             final boolean verbose) throws IOException {
   188             final boolean verbose) throws IOException {
   187         final short opcode = (short) bytes.readUnsignedByte();
   189         final short opcode = (short) bytes.readUnsignedByte();
   251                         buf.append(", ");
   253                         buf.append(", ");
   252                     }
   254                     }
   253                 }
   255                 }
   254                 buf.append(")");
   256                 buf.append(")");
   255             }
   257             }
   256             break;
   258                 break;
   257             /* Two address bytes + offset from start of byte stream form the
   259             /* Two address bytes + offset from start of byte stream form the
   258              * jump target
   260              * jump target
   259              */
   261              */
   260             case Const.GOTO:
   262             case Const.GOTO:
   261             case Const.IFEQ:
   263             case Const.IFEQ:
   325             case Const.PUTFIELD:
   327             case Const.PUTFIELD:
   326             case Const.PUTSTATIC:
   328             case Const.PUTSTATIC:
   327                 index = bytes.readUnsignedShort();
   329                 index = bytes.readUnsignedShort();
   328                 buf.append("\t\t").append(
   330                 buf.append("\t\t").append(
   329                         constant_pool.constantToString(index, Const.CONSTANT_Fieldref)).append(
   331                         constant_pool.constantToString(index, Const.CONSTANT_Fieldref)).append(
   330                                 verbose ? " (" + index + ")" : "");
   332                         verbose ? " (" + index + ")" : "");
   331                 break;
   333                 break;
   332             /* Operands are references to classes in constant pool
   334             /* Operands are references to classes in constant pool
   333              */
   335              */
   334             case Const.NEW:
   336             case Const.NEW:
   335             case Const.CHECKCAST:
   337             case Const.CHECKCAST:
   336                 buf.append("\t");
   338                 buf.append("\t");
   337             //$FALL-THROUGH$
   339                 //$FALL-THROUGH$
   338             case Const.INSTANCEOF:
   340             case Const.INSTANCEOF:
   339                 index = bytes.readUnsignedShort();
   341                 index = bytes.readUnsignedShort();
   340                 buf.append("\t<").append(
   342                 buf.append("\t<").append(
   341                         constant_pool.constantToString(index, Const.CONSTANT_Class))
   343                         constant_pool.constantToString(index, Const.CONSTANT_Class))
   342                         .append(">").append(verbose ? " (" + index + ")" : "");
   344                         .append(">").append(verbose ? " (" + index + ")" : "");
   362             case Const.INVOKEINTERFACE:
   364             case Const.INVOKEINTERFACE:
   363                 index = bytes.readUnsignedShort();
   365                 index = bytes.readUnsignedShort();
   364                 final int nargs = bytes.readUnsignedByte(); // historical, redundant
   366                 final int nargs = bytes.readUnsignedByte(); // historical, redundant
   365                 buf.append("\t").append(
   367                 buf.append("\t").append(
   366                         constant_pool
   368                         constant_pool
   367                         .constantToString(index, Const.CONSTANT_InterfaceMethodref))
   369                                 .constantToString(index, Const.CONSTANT_InterfaceMethodref))
   368                         .append(verbose ? " (" + index + ")\t" : "").append(nargs).append("\t")
   370                         .append(verbose ? " (" + index + ")\t" : "").append(nargs).append("\t")
   369                         .append(bytes.readUnsignedByte()); // Last byte is a reserved space
   371                         .append(bytes.readUnsignedByte()); // Last byte is a reserved space
   370                 break;
   372                 break;
   371             case Const.INVOKEDYNAMIC:
   373             case Const.INVOKEDYNAMIC:
   372                 index = bytes.readUnsignedShort();
   374                 index = bytes.readUnsignedShort();
   373                 buf.append("\t").append(
   375                 buf.append("\t").append(
   374                         constant_pool
   376                         constant_pool
   375                         .constantToString(index, Const.CONSTANT_InvokeDynamic))
   377                                 .constantToString(index, Const.CONSTANT_InvokeDynamic))
   376                         .append(verbose ? " (" + index + ")\t" : "")
   378                         .append(verbose ? " (" + index + ")\t" : "")
   377                         .append(bytes.readUnsignedByte()) // Thrid byte is a reserved space
   379                         .append(bytes.readUnsignedByte())  // Thrid byte is a reserved space
   378                         .append(bytes.readUnsignedByte()); // Last byte is a reserved space
   380                         .append(bytes.readUnsignedByte()); // Last byte is a reserved space
   379                 break;
   381                 break;
   380             /* Operands are references to items in constant pool
   382             /* Operands are references to items in constant pool
   381              */
   383              */
   382             case Const.LDC_W:
   384             case Const.LDC_W:
   396              */
   398              */
   397             case Const.ANEWARRAY:
   399             case Const.ANEWARRAY:
   398                 index = bytes.readUnsignedShort();
   400                 index = bytes.readUnsignedShort();
   399                 buf.append("\t\t<").append(
   401                 buf.append("\t\t<").append(
   400                         compactClassName(constant_pool.getConstantString(index,
   402                         compactClassName(constant_pool.getConstantString(index,
   401                                         Const.CONSTANT_Class), false)).append(">").append(
   403                                 Const.CONSTANT_Class), false)).append(">").append(
   402                                 verbose ? " (" + index + ")" : "");
   404                         verbose ? " (" + index + ")" : "");
   403                 break;
   405                 break;
   404             /* Multidimensional array of references.
   406             /* Multidimensional array of references.
   405              */
   407              */
   406             case Const.MULTIANEWARRAY: {
   408             case Const.MULTIANEWARRAY: {
   407                 index = bytes.readUnsignedShort();
   409                 index = bytes.readUnsignedShort();
   408                 final int dimensions = bytes.readUnsignedByte();
   410                 final int dimensions = bytes.readUnsignedByte();
   409                 buf.append("\t<").append(
   411                 buf.append("\t<").append(
   410                         compactClassName(constant_pool.getConstantString(index,
   412                         compactClassName(constant_pool.getConstantString(index,
   411                                         Const.CONSTANT_Class), false)).append(">\t").append(dimensions)
   413                                 Const.CONSTANT_Class), false)).append(">\t").append(dimensions)
   412                         .append(verbose ? " (" + index + ")" : "");
   414                         .append(verbose ? " (" + index + ")" : "");
   413             }
   415             }
   414             break;
   416                 break;
   415             /* Increment local variable.
   417             /* Increment local variable.
   416              */
   418              */
   417             case Const.IINC:
   419             case Const.IINC:
   418                 if (wide) {
   420                 if (wide) {
   419                     vindex = bytes.readUnsignedShort();
   421                     vindex = bytes.readUnsignedShort();
   446                 }
   448                 }
   447         }
   449         }
   448         return buf.toString();
   450         return buf.toString();
   449     }
   451     }
   450 
   452 
   451     public static String codeToString(final ByteSequence bytes, final ConstantPool constant_pool)
   453 
       
   454     public static String codeToString( final ByteSequence bytes, final ConstantPool constant_pool )
   452             throws IOException {
   455             throws IOException {
   453         return codeToString(bytes, constant_pool, true);
   456         return codeToString(bytes, constant_pool, true);
   454     }
   457     }
   455 
   458 
       
   459 
   456     /**
   460     /**
   457      * Shorten long class names, <em>java/lang/String</em> becomes
   461      * Shorten long class names, <em>java/lang/String</em> becomes
   458      * <em>String</em>.
   462      * <em>String</em>.
   459      *
   463      *
   460      * @param str The long class name
   464      * @param str The long class name
   461      * @return Compacted class name
   465      * @return Compacted class name
   462      */
   466      */
   463     public static String compactClassName(final String str) {
   467     public static String compactClassName( final String str ) {
   464         return compactClassName(str, true);
   468         return compactClassName(str, true);
   465     }
   469     }
   466 
   470 
       
   471 
   467     /**
   472     /**
   468      * Shorten long class name <em>str</em>, i.e., chop off the <em>prefix</em>,
   473      * Shorten long class name <em>str</em>, i.e., chop off the <em>prefix</em>,
   469      * if the class name starts with this string and the flag <em>chopit</em> is
   474      * if the
   470      * true. Slashes <em>/</em> are converted to dots <em>.</em>.
   475      * class name starts with this string and the flag <em>chopit</em> is true.
       
   476      * Slashes <em>/</em> are converted to dots <em>.</em>.
   471      *
   477      *
   472      * @param str The long class name
   478      * @param str The long class name
   473      * @param prefix The prefix the get rid off
   479      * @param prefix The prefix the get rid off
   474      * @param chopit Flag that determines whether chopping is executed or not
   480      * @param chopit Flag that determines whether chopping is executed or not
   475      * @return Compacted class name
   481      * @return Compacted class name
   476      */
   482      */
   477     public static String compactClassName(String str, final String prefix, final boolean chopit) {
   483     public static String compactClassName( String str, final String prefix, final boolean chopit ) {
   478         final int len = prefix.length();
   484         final int len = prefix.length();
   479         str = str.replace('/', '.'); // Is `/' on all systems, even DOS
   485         str = str.replace('/', '.'); // Is `/' on all systems, even DOS
   480         if (chopit) {
   486         if (chopit) {
   481             // If string starts with `prefix' and contains no further dots
   487             // If string starts with `prefix' and contains no further dots
   482             if (str.startsWith(prefix) && (str.substring(len).indexOf('.') == -1)) {
   488             if (str.startsWith(prefix) && (str.substring(len).indexOf('.') == -1)) {
   484             }
   490             }
   485         }
   491         }
   486         return str;
   492         return str;
   487     }
   493     }
   488 
   494 
       
   495 
   489     /**
   496     /**
   490      * Shorten long class names, <em>java/lang/String</em> becomes
   497      * Shorten long class names, <em>java/lang/String</em> becomes
   491      * <em>java.lang.String</em>, e.g.. If <em>chopit</em> is <em>true</em> the
   498      * <em>java.lang.String</em>,
   492      * prefix <em>java.lang</em>
   499      * e.g.. If <em>chopit</em> is <em>true</em> the prefix <em>java.lang</em>
   493      * is also removed.
   500      * is also removed.
   494      *
   501      *
   495      * @param str The long class name
   502      * @param str The long class name
   496      * @param chopit Flag that determines whether chopping is executed or not
   503      * @param chopit Flag that determines whether chopping is executed or not
   497      * @return Compacted class name
   504      * @return Compacted class name
   498      */
   505      */
   499     public static String compactClassName(final String str, final boolean chopit) {
   506     public static String compactClassName( final String str, final boolean chopit ) {
   500         return compactClassName(str, "java.lang.", chopit);
   507         return compactClassName(str, "java.lang.", chopit);
   501     }
   508     }
   502 
   509 
       
   510 
   503     /**
   511     /**
   504      * @return `flag' with bit `i' set to 1
   512      * @return `flag' with bit `i' set to 1
   505      */
   513      */
   506     public static int setBit(final int flag, final int i) {
   514     public static int setBit( final int flag, final int i ) {
   507         return flag | pow2(i);
   515         return flag | pow2(i);
   508     }
   516     }
   509 
   517 
       
   518 
   510     /**
   519     /**
   511      * @return `flag' with bit `i' set to 0
   520      * @return `flag' with bit `i' set to 0
   512      */
   521      */
   513     public static int clearBit(final int flag, final int i) {
   522     public static int clearBit( final int flag, final int i ) {
   514         final int bit = pow2(i);
   523         final int bit = pow2(i);
   515         return (flag & bit) == 0 ? flag : flag ^ bit;
   524         return (flag & bit) == 0 ? flag : flag ^ bit;
   516     }
   525     }
   517 
   526 
       
   527 
   518     /**
   528     /**
   519      * @return true, if bit `i' in `flag' is set
   529      * @return true, if bit `i' in `flag' is set
   520      */
   530      */
   521     public static boolean isSet(final int flag, final int i) {
   531     public static boolean isSet( final int flag, final int i ) {
   522         return (flag & pow2(i)) != 0;
   532         return (flag & pow2(i)) != 0;
   523     }
   533     }
   524 
   534 
   525     /**
   535 
   526      * Converts string containing the method return and argument types to a byte
   536     /**
   527      * code method signature.
   537      * Converts string containing the method return and argument types
   528      *
   538      * to a byte code method signature.
   529      * @param ret Return type of method
   539      *
   530      * @param argv Types of method arguments
   540      * @param  ret Return type of method
       
   541      * @param  argv Types of method arguments
   531      * @return Byte code representation of method signature
   542      * @return Byte code representation of method signature
   532      *
   543      *
   533      * @throws ClassFormatException if the signature is for Void
   544      * @throws ClassFormatException if the signature is for Void
   534      */
   545      */
   535     public static String methodTypeToSignature(final String ret, final String[] argv)
   546     public static String methodTypeToSignature( final String ret, final String[] argv )
   536             throws ClassFormatException {
   547             throws ClassFormatException {
   537         final StringBuilder buf = new StringBuilder("(");
   548         final StringBuilder buf = new StringBuilder("(");
   538         String str;
   549         String str;
   539         if (argv != null) {
   550         if (argv != null) {
   540             for (final String element : argv) {
   551             for (final String element : argv) {
   548         str = getSignature(ret);
   559         str = getSignature(ret);
   549         buf.append(")").append(str);
   560         buf.append(")").append(str);
   550         return buf.toString();
   561         return buf.toString();
   551     }
   562     }
   552 
   563 
   553     /**
   564 
   554      * @param signature Method signature
   565     /**
       
   566      * @param  signature    Method signature
   555      * @return Array of argument types
   567      * @return Array of argument types
   556      * @throws ClassFormatException
   568      * @throws  ClassFormatException
   557      */
   569      */
   558     public static String[] methodSignatureArgumentTypes(final String signature)
   570     public static String[] methodSignatureArgumentTypes( final String signature )
   559             throws ClassFormatException {
   571             throws ClassFormatException {
   560         return methodSignatureArgumentTypes(signature, true);
   572         return methodSignatureArgumentTypes(signature, true);
   561     }
   573     }
   562 
   574 
   563     /**
   575 
   564      * @param signature Method signature
   576     /**
       
   577      * @param  signature    Method signature
   565      * @param chopit Shorten class names ?
   578      * @param chopit Shorten class names ?
   566      * @return Array of argument types
   579      * @return Array of argument types
   567      * @throws ClassFormatException
   580      * @throws  ClassFormatException
   568      */
   581      */
   569     public static String[] methodSignatureArgumentTypes(final String signature, final boolean chopit)
   582     public static String[] methodSignatureArgumentTypes( final String signature, final boolean chopit )
   570             throws ClassFormatException {
   583             throws ClassFormatException {
   571         final List<String> vec = new ArrayList<>();
   584         final List<String> vec = new ArrayList<>();
   572         int index;
   585         int index;
   573         try { // Read all declarations between for `(' and `)'
   586         try { // Read all declarations between for `(' and `)'
   574             if (signature.charAt(0) != '(') {
   587             if (signature.charAt(0) != '(') {
   584             throw new ClassFormatException("Invalid method signature: " + signature, e);
   597             throw new ClassFormatException("Invalid method signature: " + signature, e);
   585         }
   598         }
   586         return vec.toArray(new String[vec.size()]);
   599         return vec.toArray(new String[vec.size()]);
   587     }
   600     }
   588 
   601 
   589     /**
   602 
   590      * @param signature Method signature
   603     /**
       
   604      * @param  signature    Method signature
   591      * @return return type of method
   605      * @return return type of method
   592      * @throws ClassFormatException
   606      * @throws  ClassFormatException
   593      */
   607      */
   594     public static String methodSignatureReturnType(final String signature)
   608     public static String methodSignatureReturnType( final String signature ) throws ClassFormatException {
   595             throws ClassFormatException {
       
   596         return methodSignatureReturnType(signature, true);
   609         return methodSignatureReturnType(signature, true);
   597     }
   610     }
   598 
   611 
   599     /**
   612 
   600      * @param signature Method signature
   613     /**
       
   614      * @param  signature    Method signature
   601      * @param chopit Shorten class names ?
   615      * @param chopit Shorten class names ?
   602      * @return return type of method
   616      * @return return type of method
   603      * @throws ClassFormatException
   617      * @throws  ClassFormatException
   604      */
   618      */
   605     public static String methodSignatureReturnType(final String signature,
   619     public static String methodSignatureReturnType( final String signature, final boolean chopit ) throws ClassFormatException {
   606             final boolean chopit) throws ClassFormatException {
       
   607         int index;
   620         int index;
   608         String type;
   621         String type;
   609         try {
   622         try {
   610             // Read return type after `)'
   623             // Read return type after `)'
   611             index = signature.lastIndexOf(')') + 1;
   624             index = signature.lastIndexOf(')') + 1;
   614             throw new ClassFormatException("Invalid method signature: " + signature, e);
   627             throw new ClassFormatException("Invalid method signature: " + signature, e);
   615         }
   628         }
   616         return type;
   629         return type;
   617     }
   630     }
   618 
   631 
       
   632 
   619     /**
   633     /**
   620      * Converts method signature to string with all class names compacted.
   634      * Converts method signature to string with all class names compacted.
   621      *
   635      *
   622      * @param signature to convert
   636      * @param signature to convert
   623      * @param name of method
   637      * @param name of method
   624      * @param access flags of method
   638      * @param access flags of method
   625      * @return Human readable signature
   639      * @return Human readable signature
   626      */
   640      */
   627     public static String methodSignatureToString(final String signature,
   641     public static String methodSignatureToString( final String signature, final String name, final String access ) {
   628             final String name, final String access) {
       
   629         return methodSignatureToString(signature, name, access, true);
   642         return methodSignatureToString(signature, name, access, true);
   630     }
   643     }
   631 
   644 
   632     public static String methodSignatureToString(final String signature,
   645 
   633             final String name, final String access, final boolean chopit) {
   646     public static String methodSignatureToString( final String signature, final String name, final String access, final boolean chopit ) {
   634         return methodSignatureToString(signature, name, access, chopit, null);
   647         return methodSignatureToString(signature, name, access, chopit, null);
   635     }
   648     }
   636 
   649 
   637     /**
   650 
   638      * A returntype signature represents the return value from a method. It is a
   651     /**
   639      * series of bytes in the following grammar:
   652      * A returntype signature represents the return value from a method.
       
   653      * It is a series of bytes in the following grammar:
   640      *
   654      *
   641      * <pre>
   655      * <pre>
   642      * &lt;return_signature&gt; ::= &lt;field_type&gt; | V
   656      * &lt;return_signature&gt; ::= &lt;field_type&gt; | V
   643      * </pre>
   657      * </pre>
   644      *
   658      *
   645      * The character V indicates that the method returns no value. Otherwise,
   659      * The character V indicates that the method returns no value. Otherwise, the
   646      * the signature indicates the type of the return value. An argument
   660      * signature indicates the type of the return value.
   647      * signature represents an argument passed to a method:
   661      * An argument signature represents an argument passed to a method:
   648      *
   662      *
   649      * <pre>
   663      * <pre>
   650      * &lt;argument_signature&gt; ::= &lt;field_type&gt;
   664      * &lt;argument_signature&gt; ::= &lt;field_type&gt;
   651      * </pre>
   665      * </pre>
   652      *
   666      *
   659      *
   673      *
   660      * This method converts such a string into a Java type declaration like
   674      * This method converts such a string into a Java type declaration like
   661      * `void main(String[])' and throws a `ClassFormatException' when the parsed
   675      * `void main(String[])' and throws a `ClassFormatException' when the parsed
   662      * type is invalid.
   676      * type is invalid.
   663      *
   677      *
   664      * @param signature Method signature
   678      * @param  signature    Method signature
   665      * @param name Method name
   679      * @param  name         Method name
   666      * @param access Method access rights
   680      * @param  access       Method access rights
   667      * @param chopit
   681      * @param chopit
   668      * @param vars
   682      * @param vars
   669      * @return Java type declaration
   683      * @return Java type declaration
   670      * @throws ClassFormatException
   684      * @throws  ClassFormatException
   671      */
   685      */
   672     public static String methodSignatureToString(final String signature, final String name,
   686     public static String methodSignatureToString( final String signature, final String name,
   673             final String access, final boolean chopit, final LocalVariableTable vars)
   687             final String access, final boolean chopit, final LocalVariableTable vars ) throws ClassFormatException {
   674             throws ClassFormatException {
       
   675         final StringBuilder buf = new StringBuilder("(");
   688         final StringBuilder buf = new StringBuilder("(");
   676         String type;
   689         String type;
   677         int index;
   690         int index;
   678         int var_index = access.contains("static") ? 0 : 1;
   691         int var_index = access.contains("static") ? 0 : 1;
   679         try { // Read all declarations between for `(' and `)'
   692         try { // Read all declarations between for `(' and `)'
   713         buf.append(")");
   726         buf.append(")");
   714         return access + ((access.length() > 0) ? " " : "") + // May be an empty string
   727         return access + ((access.length() > 0) ? " " : "") + // May be an empty string
   715                 type + " " + name + buf.toString();
   728                 type + " " + name + buf.toString();
   716     }
   729     }
   717 
   730 
       
   731 
   718     // Guess what this does
   732     // Guess what this does
   719     private static int pow2(final int n) {
   733     private static int pow2( final int n ) {
   720         return 1 << n;
   734         return 1 << n;
   721     }
   735     }
   722 
   736 
   723     /**
   737 
   724      * Replace all occurrences of <em>old</em> in <em>str</em> with
   738     /**
   725      * <em>new</em>.
   739      * Replace all occurrences of <em>old</em> in <em>str</em> with <em>new</em>.
   726      *
   740      *
   727      * @param str String to permute
   741      * @param str String to permute
   728      * @param old String to be replaced
   742      * @param old String to be replaced
   729      * @param new_ Replacement string
   743      * @param new_ Replacement string
   730      * @return new String object
   744      * @return new String object
   731      */
   745      */
   732     public static String replace(String str, final String old, final String new_) {
   746     public static String replace( String str, final String old, final String new_ ) {
   733         int index;
   747         int index;
   734         int old_index;
   748         int old_index;
   735         try {
   749         try {
   736             if (str.contains(old)) { // `old' found in str
   750             if (str.contains(old)) { // `old' found in str
   737                 final StringBuilder buf = new StringBuilder();
   751                 final StringBuilder buf = new StringBuilder();
   749             System.err.println(e);
   763             System.err.println(e);
   750         }
   764         }
   751         return str;
   765         return str;
   752     }
   766     }
   753 
   767 
       
   768 
   754     /**
   769     /**
   755      * Converts signature to string with all class names compacted.
   770      * Converts signature to string with all class names compacted.
   756      *
   771      *
   757      * @param signature to convert
   772      * @param signature to convert
   758      * @return Human readable signature
   773      * @return Human readable signature
   759      */
   774      */
   760     public static String signatureToString(final String signature) {
   775     public static String signatureToString( final String signature ) {
   761         return signatureToString(signature, true);
   776         return signatureToString(signature, true);
   762     }
   777     }
       
   778 
   763 
   779 
   764     /**
   780     /**
   765      * The field signature represents the value of an argument to a function or
   781      * The field signature represents the value of an argument to a function or
   766      * the value of a variable. It is a series of bytes generated by the
   782      * the value of a variable. It is a series of bytes generated by the
   767      * following grammar:
   783      * following grammar:
   788      *
   804      *
   789      * This method converts this string into a Java type declaration such as
   805      * This method converts this string into a Java type declaration such as
   790      * `String[]' and throws a `ClassFormatException' when the parsed type is
   806      * `String[]' and throws a `ClassFormatException' when the parsed type is
   791      * invalid.
   807      * invalid.
   792      *
   808      *
   793      * @param signature Class signature
   809      * @param  signature  Class signature
   794      * @param chopit Flag that determines whether chopping is executed or not
   810      * @param chopit Flag that determines whether chopping is executed or not
   795      * @return Java type declaration
   811      * @return Java type declaration
   796      * @throws ClassFormatException
   812      * @throws ClassFormatException
   797      */
   813      */
   798     public static String signatureToString(final String signature, final boolean chopit) {
   814     public static String signatureToString( final String signature, final boolean chopit ) {
   799         //corrected concurrent private static field acess
   815         //corrected concurrent private static field acess
   800         wrap(consumed_chars, 1); // This is the default, read just one char like `B'
   816         wrap(consumed_chars, 1); // This is the default, read just one char like `B'
   801         try {
   817         try {
   802             switch (signature.charAt(0)) {
   818             switch (signature.charAt(0)) {
   803                 case 'B':
   819                 case 'B':
   835                     }
   851                     }
   836                     final int index = signature.indexOf(';', fromIndex); // Look for closing `;'
   852                     final int index = signature.indexOf(';', fromIndex); // Look for closing `;'
   837                     if (index < 0) {
   853                     if (index < 0) {
   838                         throw new ClassFormatException("Invalid signature: " + signature);
   854                         throw new ClassFormatException("Invalid signature: " + signature);
   839                     }
   855                     }
       
   856 
   840                     // check to see if there are any TypeArguments
   857                     // check to see if there are any TypeArguments
   841                     final int bracketIndex = signature.substring(0, index).indexOf('<');
   858                     final int bracketIndex = signature.substring(0, index).indexOf('<');
   842                     if (bracketIndex < 0) {
   859                     if (bracketIndex < 0) {
   843                         // just a class identifier
   860                         // just a class identifier
   844                         wrap(consumed_chars, index + 1); // "Lblabla;" `L' and `;' are removed
   861                         wrap(consumed_chars, index + 1); // "Lblabla;" `L' and `;' are removed
   845                         return compactClassName(signature.substring(1, index), chopit);
   862                         return compactClassName(signature.substring(1, index), chopit);
   846                     }
   863                     }
       
   864                     // but make sure we are not looking past the end of the current item
       
   865                     fromIndex = signature.indexOf(';');
       
   866                     if (fromIndex < 0) {
       
   867                         throw new ClassFormatException("Invalid signature: " + signature);
       
   868                     }
       
   869                     if (fromIndex < bracketIndex) {
       
   870                         // just a class identifier
       
   871                         wrap(consumed_chars, fromIndex + 1); // "Lblabla;" `L' and `;' are removed
       
   872                         return compactClassName(signature.substring(1, fromIndex), chopit);
       
   873                     }
   847 
   874 
   848                     // we have TypeArguments; build up partial result
   875                     // we have TypeArguments; build up partial result
   849                     // as we recurse for each TypeArgument
   876                     // as we recurse for each TypeArgument
   850                     final StringBuilder type = new StringBuilder(
   877                     final StringBuilder type = new StringBuilder(compactClassName(signature.substring(1, bracketIndex), chopit)).append("<");
   851                             compactClassName(signature.substring(1, bracketIndex), chopit))
       
   852                             .append("<");
       
   853                     int consumed_chars = bracketIndex + 1; // Shadows global var
   878                     int consumed_chars = bracketIndex + 1; // Shadows global var
   854 
   879 
   855                     // check for wildcards
   880                     // check for wildcards
   856                     if (signature.charAt(consumed_chars) == '+') {
   881                     if (signature.charAt(consumed_chars) == '+') {
   857                         type.append("? extends ");
   882                         type.append("? extends ");
   858                         consumed_chars++;
   883                         consumed_chars++;
   859                     } else if (signature.charAt(consumed_chars) == '-') {
   884                     } else if (signature.charAt(consumed_chars) == '-') {
   860                         type.append("? super ");
   885                         type.append("? super ");
   861                         consumed_chars++;
   886                         consumed_chars++;
   862                     } else if (signature.charAt(consumed_chars) == '*') {
       
   863                         // must be at end of signature
       
   864                         if (signature.charAt(consumed_chars + 1) != '>') {
       
   865                             throw new ClassFormatException("Invalid signature: " + signature);
       
   866                         }
       
   867                         if (signature.charAt(consumed_chars + 2) != ';') {
       
   868                             throw new ClassFormatException("Invalid signature: " + signature);
       
   869                         }
       
   870                         wrap(Utility.consumed_chars, consumed_chars + 3); // remove final "*>;"
       
   871                         return type + "?>...";
       
   872                     }
   887                     }
   873 
   888 
   874                     // get the first TypeArgument
   889                     // get the first TypeArgument
   875                     type.append(signatureToString(signature.substring(consumed_chars), chopit));
   890                     if (signature.charAt(consumed_chars) == '*') {
   876                     // update our consumed count by the number of characters the for type argument
   891                         type.append("?");
   877                     consumed_chars = unwrap(Utility.consumed_chars) + consumed_chars;
   892                         consumed_chars++;
   878                     wrap(Utility.consumed_chars, consumed_chars);
   893                     } else {
   879 
   894                         type.append(signatureToString(signature.substring(consumed_chars), chopit));
   880                     // are there more TypeArguments?
       
   881                     while (signature.charAt(consumed_chars) != '>') {
       
   882                         type.append(", ").append(signatureToString(signature.substring(consumed_chars), chopit));
       
   883                         // update our consumed count by the number of characters the for type argument
   895                         // update our consumed count by the number of characters the for type argument
   884                         consumed_chars = unwrap(Utility.consumed_chars) + consumed_chars;
   896                         consumed_chars = unwrap(Utility.consumed_chars) + consumed_chars;
   885                         wrap(Utility.consumed_chars, consumed_chars);
   897                         wrap(Utility.consumed_chars, consumed_chars);
   886                     }
   898                     }
   887 
   899 
   888                     if (signature.charAt(consumed_chars + 1) != ';') {
   900                     // are there more TypeArguments?
       
   901                     while (signature.charAt(consumed_chars) != '>') {
       
   902                         type.append(", ");
       
   903                         // check for wildcards
       
   904                         if (signature.charAt(consumed_chars) == '+') {
       
   905                             type.append("? extends ");
       
   906                             consumed_chars++;
       
   907                         } else if (signature.charAt(consumed_chars) == '-') {
       
   908                             type.append("? super ");
       
   909                             consumed_chars++;
       
   910                         }
       
   911                         if (signature.charAt(consumed_chars) == '*') {
       
   912                             type.append("?");
       
   913                             consumed_chars++;
       
   914                         } else {
       
   915                             type.append(signatureToString(signature.substring(consumed_chars), chopit));
       
   916                             // update our consumed count by the number of characters the for type argument
       
   917                             consumed_chars = unwrap(Utility.consumed_chars) + consumed_chars;
       
   918                             wrap(Utility.consumed_chars, consumed_chars);
       
   919                         }
       
   920                     }
       
   921 
       
   922                     // process the closing ">"
       
   923                     consumed_chars++;
       
   924                     type.append(">");
       
   925 
       
   926                     if (signature.charAt(consumed_chars) == '.') {
       
   927                         // we have a ClassTypeSignatureSuffix
       
   928                         type.append(".");
       
   929                         // convert SimpleClassTypeSignature to fake ClassTypeSignature
       
   930                         // and then recurse to parse it
       
   931                         type.append(signatureToString("L" + signature.substring(consumed_chars+1), chopit));
       
   932                         // update our consumed count by the number of characters the for type argument
       
   933                         // note that this count includes the "L" we added, but that is ok
       
   934                         // as it accounts for the "." we didn't consume
       
   935                         consumed_chars = unwrap(Utility.consumed_chars) + consumed_chars;
       
   936                         wrap(Utility.consumed_chars, consumed_chars);
       
   937                         return type.toString();
       
   938                     }
       
   939                     if (signature.charAt(consumed_chars) != ';') {
   889                         throw new ClassFormatException("Invalid signature: " + signature);
   940                         throw new ClassFormatException("Invalid signature: " + signature);
   890                     }
   941                     }
   891                     wrap(Utility.consumed_chars, consumed_chars + 2); // remove final ">;"
   942                     wrap(Utility.consumed_chars, consumed_chars + 1); // remove final ";"
   892                     return type.append(">").toString();
   943                     return type.toString();
   893                 }
   944                 }
   894                 case 'S':
   945                 case 'S':
   895                     return "short";
   946                     return "short";
   896                 case 'Z':
   947                 case 'Z':
   897                     return "boolean";
   948                     return "boolean";
   922         } catch (final StringIndexOutOfBoundsException e) { // Should never occur
   973         } catch (final StringIndexOutOfBoundsException e) { // Should never occur
   923             throw new ClassFormatException("Invalid signature: " + signature, e);
   974             throw new ClassFormatException("Invalid signature: " + signature, e);
   924         }
   975         }
   925     }
   976     }
   926 
   977 
   927     /**
   978 
   928      * Parse Java type such as "char", or "java.lang.String[]" and return the
   979     /** Parse Java type such as "char", or "java.lang.String[]" and return the
   929      * signature in byte code format, e.g. "C" or "[Ljava/lang/String;"
   980      * signature in byte code format, e.g. "C" or "[Ljava/lang/String;" respectively.
   930      * respectively.
   981      *
   931      *
   982      * @param  type Java type
   932      * @param type Java type
       
   933      * @return byte code signature
   983      * @return byte code signature
   934      */
   984      */
   935     public static String getSignature(String type) {
   985     public static String getSignature( String type ) {
   936         final StringBuilder buf = new StringBuilder();
   986         final StringBuilder buf = new StringBuilder();
   937         final char[] chars = type.toCharArray();
   987         final char[] chars = type.toCharArray();
   938         boolean char_found = false;
   988         boolean char_found = false;
   939         boolean delim = false;
   989         boolean delim = false;
   940         int index = -1;
   990         int index = -1;
   941         loop:
   991         loop: for (int i = 0; i < chars.length; i++) {
   942         for (int i = 0; i < chars.length; i++) {
       
   943             switch (chars[i]) {
   992             switch (chars[i]) {
   944                 case ' ':
   993                 case ' ':
   945                 case '\t':
   994                 case '\t':
   946                 case '\n':
   995                 case '\n':
   947                 case '\r':
   996                 case '\r':
   983             buf.append('L').append(type.replace('.', '/')).append(';');
  1032             buf.append('L').append(type.replace('.', '/')).append(';');
   984         }
  1033         }
   985         return buf.toString();
  1034         return buf.toString();
   986     }
  1035     }
   987 
  1036 
   988     private static int countBrackets(final String brackets) {
  1037 
       
  1038     private static int countBrackets( final String brackets ) {
   989         final char[] chars = brackets.toCharArray();
  1039         final char[] chars = brackets.toCharArray();
   990         int count = 0;
  1040         int count = 0;
   991         boolean open = false;
  1041         boolean open = false;
   992         for (final char c : chars) {
  1042         for (final char c : chars) {
   993             switch (c) {
  1043             switch (c) {
  1013             throw new RuntimeException("Illegally nested brackets:" + brackets);
  1063             throw new RuntimeException("Illegally nested brackets:" + brackets);
  1014         }
  1064         }
  1015         return count;
  1065         return count;
  1016     }
  1066     }
  1017 
  1067 
  1018     /**
  1068 
  1019      * Return type of method signature as a byte value as defined in
  1069     /**
  1020      * <em>Constants</em>
  1070      * Return type of method signature as a byte value as defined in <em>Constants</em>
  1021      *
  1071      *
  1022      * @param signature in format described above
  1072      * @param  signature in format described above
  1023      * @return type of method signature
  1073      * @return type of method signature
  1024      * @see Const
  1074      * @see    Const
  1025      *
  1075      *
  1026      * @throws ClassFormatException if signature is not a method signature
  1076      * @throws ClassFormatException if signature is not a method signature
  1027      */
  1077      */
  1028     public static byte typeOfMethodSignature(final String signature) throws ClassFormatException {
  1078     public static byte typeOfMethodSignature( final String signature ) throws ClassFormatException {
  1029         int index;
  1079         int index;
  1030         try {
  1080         try {
  1031             if (signature.charAt(0) != '(') {
  1081             if (signature.charAt(0) != '(') {
  1032                 throw new ClassFormatException("Invalid method signature: " + signature);
  1082                 throw new ClassFormatException("Invalid method signature: " + signature);
  1033             }
  1083             }
  1036         } catch (final StringIndexOutOfBoundsException e) {
  1086         } catch (final StringIndexOutOfBoundsException e) {
  1037             throw new ClassFormatException("Invalid method signature: " + signature, e);
  1087             throw new ClassFormatException("Invalid method signature: " + signature, e);
  1038         }
  1088         }
  1039     }
  1089     }
  1040 
  1090 
       
  1091 
  1041     /**
  1092     /**
  1042      * Return type of signature as a byte value as defined in <em>Constants</em>
  1093      * Return type of signature as a byte value as defined in <em>Constants</em>
  1043      *
  1094      *
  1044      * @param signature in format described above
  1095      * @param  signature in format described above
  1045      * @return type of signature
  1096      * @return type of signature
  1046      * @see Const
  1097      * @see    Const
  1047      *
  1098      *
  1048      * @throws ClassFormatException if signature isn't a known type
  1099      * @throws ClassFormatException if signature isn't a known type
  1049      */
  1100      */
  1050     public static byte typeOfSignature(final String signature) throws ClassFormatException {
  1101     public static byte typeOfSignature( final String signature ) throws ClassFormatException {
  1051         try {
  1102         try {
  1052             switch (signature.charAt(0)) {
  1103             switch (signature.charAt(0)) {
  1053                 case 'B':
  1104                 case 'B':
  1054                     return Const.T_BYTE;
  1105                     return Const.T_BYTE;
  1055                 case 'C':
  1106                 case 'C':
  1083         } catch (final StringIndexOutOfBoundsException e) {
  1134         } catch (final StringIndexOutOfBoundsException e) {
  1084             throw new ClassFormatException("Invalid method signature: " + signature, e);
  1135             throw new ClassFormatException("Invalid method signature: " + signature, e);
  1085         }
  1136         }
  1086     }
  1137     }
  1087 
  1138 
  1088     /**
  1139 
  1089      * Map opcode names to opcode numbers. E.g., return Constants.ALOAD for
  1140     /** Map opcode names to opcode numbers. E.g., return Constants.ALOAD for "aload"
  1090      * "aload"
  1141      */
  1091      */
  1142     public static short searchOpcode( String name ) {
  1092     public static short searchOpcode(String name) {
       
  1093         name = name.toLowerCase(Locale.ENGLISH);
  1143         name = name.toLowerCase(Locale.ENGLISH);
  1094         for (short i = 0; i < Const.OPCODE_NAMES_LENGTH; i++) {
  1144         for (short i = 0; i < Const.OPCODE_NAMES_LENGTH; i++) {
  1095             if (Const.getOpcodeName(i).equals(name)) {
  1145             if (Const.getOpcodeName(i).equals(name)) {
  1096                 return i;
  1146                 return i;
  1097             }
  1147             }
  1098         }
  1148         }
  1099         return -1;
  1149         return -1;
  1100     }
  1150     }
  1101 
  1151 
       
  1152 
  1102     /**
  1153     /**
  1103      * Convert (signed) byte to (unsigned) short value, i.e., all negative
  1154      * Convert (signed) byte to (unsigned) short value, i.e., all negative
  1104      * values become positive.
  1155      * values become positive.
  1105      */
  1156      */
  1106     private static short byteToShort(final byte b) {
  1157     private static short byteToShort( final byte b ) {
  1107         return (b < 0) ? (short) (256 + b) : (short) b;
  1158         return (b < 0) ? (short) (256 + b) : (short) b;
  1108     }
  1159     }
  1109 
  1160 
  1110     /**
  1161 
  1111      * Convert bytes into hexadecimal string
  1162     /** Convert bytes into hexadecimal string
  1112      *
  1163      *
  1113      * @param bytes an array of bytes to convert to hexadecimal
  1164      * @param bytes an array of bytes to convert to hexadecimal
  1114      *
  1165      *
  1115      * @return bytes as hexadecimal string, e.g. 00 fa 12 ...
  1166      * @return bytes as hexadecimal string, e.g. 00 fa 12 ...
  1116      */
  1167      */
  1117     public static String toHexString(final byte[] bytes) {
  1168     public static String toHexString( final byte[] bytes ) {
  1118         final StringBuilder buf = new StringBuilder();
  1169         final StringBuilder buf = new StringBuilder();
  1119         for (int i = 0; i < bytes.length; i++) {
  1170         for (int i = 0; i < bytes.length; i++) {
  1120             final short b = byteToShort(bytes[i]);
  1171             final short b = byteToShort(bytes[i]);
  1121             final String hex = Integer.toHexString(b);
  1172             final String hex = Integer.toHexString(b);
  1122             if (b < 0x10) {
  1173             if (b < 0x10) {
  1128             }
  1179             }
  1129         }
  1180         }
  1130         return buf.toString();
  1181         return buf.toString();
  1131     }
  1182     }
  1132 
  1183 
       
  1184 
  1133     /**
  1185     /**
  1134      * Return a string for an integer justified left or right and filled up with
  1186      * Return a string for an integer justified left or right and filled up with
  1135      * `fill' characters if necessary.
  1187      * `fill' characters if necessary.
  1136      *
  1188      *
  1137      * @param i integer to format
  1189      * @param i integer to format
  1138      * @param length length of desired string
  1190      * @param length length of desired string
  1139      * @param left_justify format left or right
  1191      * @param left_justify format left or right
  1140      * @param fill fill character
  1192      * @param fill fill character
  1141      * @return formatted int
  1193      * @return formatted int
  1142      */
  1194      */
  1143     public static String format(final int i, final int length,
  1195     public static String format( final int i, final int length, final boolean left_justify, final char fill ) {
  1144             final boolean left_justify, final char fill) {
       
  1145         return fillup(Integer.toString(i), length, left_justify, fill);
  1196         return fillup(Integer.toString(i), length, left_justify, fill);
  1146     }
  1197     }
  1147 
  1198 
  1148     /**
  1199 
  1149      * Fillup char with up to length characters with char `fill' and justify it
  1200     /**
  1150      * left or right.
  1201      * Fillup char with up to length characters with char `fill' and justify it left or right.
  1151      *
  1202      *
  1152      * @param str string to format
  1203      * @param str string to format
  1153      * @param length length of desired string
  1204      * @param length length of desired string
  1154      * @param left_justify format left or right
  1205      * @param left_justify format left or right
  1155      * @param fill fill character
  1206      * @param fill fill character
  1156      * @return formatted string
  1207      * @return formatted string
  1157      */
  1208      */
  1158     public static String fillup(final String str, final int length,
  1209     public static String fillup( final String str, final int length, final boolean left_justify, final char fill ) {
  1159             final boolean left_justify, final char fill) {
       
  1160         final int len = length - str.length();
  1210         final int len = length - str.length();
  1161         final char[] buf = new char[(len < 0) ? 0 : len];
  1211         final char[] buf = new char[(len < 0) ? 0 : len];
  1162         for (int j = 0; j < buf.length; j++) {
  1212         for (int j = 0; j < buf.length; j++) {
  1163             buf[j] = fill;
  1213             buf[j] = fill;
  1164         }
  1214         }
  1166             return str + new String(buf);
  1216             return str + new String(buf);
  1167         }
  1217         }
  1168         return new String(buf) + str;
  1218         return new String(buf) + str;
  1169     }
  1219     }
  1170 
  1220 
  1171     static boolean equals(final byte[] a, final byte[] b) {
  1221 
       
  1222     static boolean equals( final byte[] a, final byte[] b ) {
  1172         int size;
  1223         int size;
  1173         if ((size = a.length) != b.length) {
  1224         if ((size = a.length) != b.length) {
  1174             return false;
  1225             return false;
  1175         }
  1226         }
  1176         for (int i = 0; i < size; i++) {
  1227         for (int i = 0; i < size; i++) {
  1179             }
  1230             }
  1180         }
  1231         }
  1181         return true;
  1232         return true;
  1182     }
  1233     }
  1183 
  1234 
  1184     public static void printArray(final PrintStream out, final Object[] obj) {
  1235 
       
  1236     public static void printArray( final PrintStream out, final Object[] obj ) {
  1185         out.println(printArray(obj, true));
  1237         out.println(printArray(obj, true));
  1186     }
  1238     }
  1187 
  1239 
  1188     public static void printArray(final PrintWriter out, final Object[] obj) {
  1240 
       
  1241     public static void printArray( final PrintWriter out, final Object[] obj ) {
  1189         out.println(printArray(obj, true));
  1242         out.println(printArray(obj, true));
  1190     }
  1243     }
  1191 
  1244 
  1192     public static String printArray(final Object[] obj) {
  1245 
       
  1246     public static String printArray( final Object[] obj ) {
  1193         return printArray(obj, true);
  1247         return printArray(obj, true);
  1194     }
  1248     }
  1195 
  1249 
  1196     public static String printArray(final Object[] obj, final boolean braces) {
  1250 
       
  1251     public static String printArray( final Object[] obj, final boolean braces ) {
  1197         return printArray(obj, braces, false);
  1252         return printArray(obj, braces, false);
  1198     }
  1253     }
  1199 
  1254 
  1200     public static String printArray(final Object[] obj, final boolean braces, final boolean quote) {
  1255 
       
  1256     public static String printArray( final Object[] obj, final boolean braces, final boolean quote ) {
  1201         if (obj == null) {
  1257         if (obj == null) {
  1202             return null;
  1258             return null;
  1203         }
  1259         }
  1204         final StringBuilder buf = new StringBuilder();
  1260         final StringBuilder buf = new StringBuilder();
  1205         if (braces) {
  1261         if (braces) {
  1219             buf.append('}');
  1275             buf.append('}');
  1220         }
  1276         }
  1221         return buf.toString();
  1277         return buf.toString();
  1222     }
  1278     }
  1223 
  1279 
       
  1280 
  1224     /**
  1281     /**
  1225      * @param ch the character to test if it's part of an identifier
  1282      * @param ch the character to test if it's part of an identifier
  1226      *
  1283      *
  1227      * @return true, if character is one of (a, ... z, A, ... Z, 0, ... 9, _)
  1284      * @return true, if character is one of (a, ... z, A, ... Z, 0, ... 9, _)
  1228      */
  1285      */
  1229     public static boolean isJavaIdentifierPart(final char ch) {
  1286     public static boolean isJavaIdentifierPart( final char ch ) {
  1230         return ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'))
  1287         return ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'))
  1231                 || ((ch >= '0') && (ch <= '9')) || (ch == '_');
  1288                 || ((ch >= '0') && (ch <= '9')) || (ch == '_');
  1232     }
  1289     }
  1233 
  1290 
  1234     /**
  1291 
  1235      * Encode byte array it into Java identifier string, i.e., a string that
  1292     /**
  1236      * only contains the following characters: (a, ... z, A, ... Z, 0, ... 9, _,
  1293      * Encode byte array it into Java identifier string, i.e., a string
  1237      * $). The encoding algorithm itself is not too clever: if the current
  1294      * that only contains the following characters: (a, ... z, A, ... Z,
  1238      * byte's ASCII value already is a valid Java identifier part, leave it as
  1295      * 0, ... 9, _, $).  The encoding algorithm itself is not too
  1239      * it is. Otherwise it writes the escape character($) followed by:
  1296      * clever: if the current byte's ASCII value already is a valid Java
       
  1297      * identifier part, leave it as it is. Otherwise it writes the
       
  1298      * escape character($) followed by:
  1240      *
  1299      *
  1241      * <ul>
  1300      * <ul>
  1242      * <li> the ASCII value as a hexadecimal string, if the value is not in the
  1301      *   <li> the ASCII value as a hexadecimal string, if the value is not in the range 200..247</li>
  1243      * range 200..247</li>
  1302      *   <li>a Java identifier char not used in a lowercase hexadecimal string, if the value is in the range 200..247</li>
  1244      * <li>a Java identifier char not used in a lowercase hexadecimal string, if
       
  1245      * the value is in the range 200..247</li>
       
  1246      * </ul>
  1303      * </ul>
  1247      *
  1304      *
  1248      * <p>
  1305      * <p>This operation inflates the original byte array by roughly 40-50%</p>
  1249      * This operation inflates the original byte array by roughly 40-50%</p>
       
  1250      *
  1306      *
  1251      * @param bytes the byte array to convert
  1307      * @param bytes the byte array to convert
  1252      * @param compress use gzip to minimize string
  1308      * @param compress use gzip to minimize string
  1253      *
  1309      *
  1254      * @throws IOException if there's a gzip exception
  1310      * @throws IOException if there's a gzip exception
  1268                 jw.write(in);
  1324                 jw.write(in);
  1269             }
  1325             }
  1270         }
  1326         }
  1271         return caw.toString();
  1327         return caw.toString();
  1272     }
  1328     }
       
  1329 
  1273 
  1330 
  1274     /**
  1331     /**
  1275      * Decode a string back to a byte array.
  1332      * Decode a string back to a byte array.
  1276      *
  1333      *
  1277      * @param s the string to convert
  1334      * @param s the string to convert
  1306     // A-Z, g-z, _, $
  1363     // A-Z, g-z, _, $
  1307     private static final int FREE_CHARS = 48;
  1364     private static final int FREE_CHARS = 48;
  1308     private static int[] CHAR_MAP = new int[FREE_CHARS];
  1365     private static int[] CHAR_MAP = new int[FREE_CHARS];
  1309     private static int[] MAP_CHAR = new int[256]; // Reverse map
  1366     private static int[] MAP_CHAR = new int[256]; // Reverse map
  1310     private static final char ESCAPE_CHAR = '$';
  1367     private static final char ESCAPE_CHAR = '$';
  1311 
       
  1312     static {
  1368     static {
  1313         int j = 0;
  1369         int j = 0;
  1314         for (int i = 'A'; i <= 'Z'; i++) {
  1370         for (int i = 'A'; i <= 'Z'; i++) {
  1315             CHAR_MAP[j] = i;
  1371             CHAR_MAP[j] = i;
  1316             MAP_CHAR[i] = j;
  1372             MAP_CHAR[i] = j;
  1327         CHAR_MAP[j] = '_';
  1383         CHAR_MAP[j] = '_';
  1328         MAP_CHAR['_'] = j;
  1384         MAP_CHAR['_'] = j;
  1329     }
  1385     }
  1330 
  1386 
  1331     /**
  1387     /**
  1332      * Decode characters into bytes. Used by <a
  1388      * Decode characters into bytes.
  1333      * href="Utility.html#decode(java.lang.String, boolean)">decode()</a>
  1389      * Used by <a href="Utility.html#decode(java.lang.String, boolean)">decode()</a>
  1334      */
  1390      */
  1335     private static class JavaReader extends FilterReader {
  1391     private static class JavaReader extends FilterReader {
  1336 
  1392 
  1337         public JavaReader(final Reader in) {
  1393         public JavaReader(final Reader in) {
  1338             super(in);
  1394             super(in);
  1339         }
  1395         }
       
  1396 
  1340 
  1397 
  1341         @Override
  1398         @Override
  1342         public int read() throws IOException {
  1399         public int read() throws IOException {
  1343             final int b = in.read();
  1400             final int b = in.read();
  1344             if (b != ESCAPE_CHAR) {
  1401             if (b != ESCAPE_CHAR) {
  1352                 final int j = in.read();
  1409                 final int j = in.read();
  1353                 if (j < 0) {
  1410                 if (j < 0) {
  1354                     return -1;
  1411                     return -1;
  1355                 }
  1412                 }
  1356                 final char[] tmp = {
  1413                 final char[] tmp = {
  1357                     (char) i, (char) j
  1414                         (char) i, (char) j
  1358                 };
  1415                 };
  1359                 final int s = Integer.parseInt(new String(tmp), 16);
  1416                 final int s = Integer.parseInt(new String(tmp), 16);
  1360                 return s;
  1417                 return s;
  1361             }
  1418             }
  1362             return MAP_CHAR[i];
  1419             return MAP_CHAR[i];
  1363         }
  1420         }
  1364 
  1421 
       
  1422 
  1365         @Override
  1423         @Override
  1366         public int read(final char[] cbuf, final int off, final int len) throws IOException {
  1424         public int read( final char[] cbuf, final int off, final int len ) throws IOException {
  1367             for (int i = 0; i < len; i++) {
  1425             for (int i = 0; i < len; i++) {
  1368                 cbuf[off + i] = (char) read();
  1426                 cbuf[off + i] = (char) read();
  1369             }
  1427             }
  1370             return len;
  1428             return len;
  1371         }
  1429         }
  1372     }
  1430     }
  1373 
  1431 
  1374     /**
  1432     /**
  1375      * Encode bytes into valid java identifier characters. Used by <a
  1433      * Encode bytes into valid java identifier characters.
  1376      * href="Utility.html#encode(byte[], boolean)">encode()</a>
  1434      * Used by <a href="Utility.html#encode(byte[], boolean)">encode()</a>
  1377      */
  1435      */
  1378     private static class JavaWriter extends FilterWriter {
  1436     private static class JavaWriter extends FilterWriter {
  1379 
  1437 
  1380         public JavaWriter(final Writer out) {
  1438         public JavaWriter(final Writer out) {
  1381             super(out);
  1439             super(out);
  1382         }
  1440         }
  1383 
  1441 
       
  1442 
  1384         @Override
  1443         @Override
  1385         public void write(final int b) throws IOException {
  1444         public void write( final int b ) throws IOException {
  1386             if (isJavaIdentifierPart((char) b) && (b != ESCAPE_CHAR)) {
  1445             if (isJavaIdentifierPart((char) b) && (b != ESCAPE_CHAR)) {
  1387                 out.write(b);
  1446                 out.write(b);
  1388             } else {
  1447             } else {
  1389                 out.write(ESCAPE_CHAR); // Escape character
  1448                 out.write(ESCAPE_CHAR); // Escape character
  1390                 // Special escape
  1449                 // Special escape
  1401                     }
  1460                     }
  1402                 }
  1461                 }
  1403             }
  1462             }
  1404         }
  1463         }
  1405 
  1464 
       
  1465 
  1406         @Override
  1466         @Override
  1407         public void write(final char[] cbuf, final int off, final int len) throws IOException {
  1467         public void write( final char[] cbuf, final int off, final int len ) throws IOException {
  1408             for (int i = 0; i < len; i++) {
  1468             for (int i = 0; i < len; i++) {
  1409                 write(cbuf[off + i]);
  1469                 write(cbuf[off + i]);
  1410             }
  1470             }
  1411         }
  1471         }
  1412 
  1472 
       
  1473 
  1413         @Override
  1474         @Override
  1414         public void write(final String str, final int off, final int len) throws IOException {
  1475         public void write( final String str, final int off, final int len ) throws IOException {
  1415             write(str.toCharArray(), off, len);
  1476             write(str.toCharArray(), off, len);
  1416         }
  1477         }
  1417     }
  1478     }
  1418 
  1479 
       
  1480 
  1419     /**
  1481     /**
  1420      * Escape all occurences of newline chars '\n', quotes \", etc.
  1482      * Escape all occurences of newline chars '\n', quotes \", etc.
  1421      */
  1483      */
  1422     public static String convertString(final String label) {
  1484     public static String convertString( final String label ) {
  1423         final char[] ch = label.toCharArray();
  1485         final char[] ch = label.toCharArray();
  1424         final StringBuilder buf = new StringBuilder();
  1486         final StringBuilder buf = new StringBuilder();
  1425         for (final char element : ch) {
  1487         for (final char element : ch) {
  1426             switch (element) {
  1488             switch (element) {
  1427                 case '\n':
  1489                 case '\n':
  1444                     break;
  1506                     break;
  1445             }
  1507             }
  1446         }
  1508         }
  1447         return buf.toString();
  1509         return buf.toString();
  1448     }
  1510     }
       
  1511 
  1449 }
  1512 }