| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
 | 
 | 
package com.sun.jmx.snmp;  | 
 | 
 | 
 | 
 | 
 | 
/**  | 
 | 
 * The <CODE>BerEncoder</CODE> class is used for encoding data using BER.  | 
 | 
 *  | 
 | 
 * A <CODE>BerEncoder</CODE> needs to be set up with a byte buffer. The encoded  | 
 | 
 * data are stored in this byte buffer.  | 
 | 
 * <P>  | 
 | 
 * NOTE : the buffer is filled from end to start. This means the caller  | 
 | 
 * needs to encode its data in the reverse order.  | 
 | 
 *  | 
 | 
 *  | 
 | 
 * <p><b>This API is a Sun Microsystems internal API  and is subject  | 
 | 
 * to change without notice.</b></p>  | 
 | 
 *  | 
 | 
 * @since 1.5  | 
 | 
 */  | 
 | 
 | 
 | 
public class BerEncoder { | 
 | 
 | 
 | 
  /**  | 
 | 
  * Constructs a new encoder and attaches it to the specified byte string.  | 
 | 
  *  | 
 | 
  * @param b The byte string containing the encoded data.  | 
 | 
  */  | 
 | 
 | 
 | 
  public BerEncoder(byte b[]) { | 
 | 
    bytes = b ;  | 
 | 
    start = b.length ;  | 
 | 
    stackTop = 0 ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Trim the encoding data and returns the length of the encoding.  | 
 | 
  *  | 
 | 
  * The encoder does backward encoding : so the bytes buffer is  | 
 | 
  * filled from end to start. The encoded data must be shift before  | 
 | 
  * the buffer can be used. This is the purpose of the <CODE>trim</CODE> method.  | 
 | 
  *  | 
 | 
  * After a call to the <CODE>trim</CODE> method, the encoder is reinitialized and <CODE>putXXX</CODE>  | 
 | 
  * overwrite any existing encoded data.  | 
 | 
  *  | 
 | 
  * @return The length of the encoded data.  | 
 | 
  */  | 
 | 
 | 
 | 
  public int trim() { | 
 | 
    final int result = bytes.length - start ;  | 
 | 
 | 
 | 
    // for (int i = start ; i < bytes.length ; i++) { | 
 | 
    //  bytes[i-start] = bytes[i] ;  | 
 | 
      | 
 | 
    if (result > 0)  | 
 | 
        java.lang.System.arraycopy(bytes,start,bytes,0,result);  | 
 | 
 | 
 | 
    start = bytes.length ;  | 
 | 
    stackTop = 0 ;  | 
 | 
 | 
 | 
    return result ;  | 
 | 
  }  | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put an integer.  | 
 | 
  *  | 
 | 
  * @param v The integer to encode.  | 
 | 
  */  | 
 | 
 | 
 | 
  public void putInteger(int v) { | 
 | 
    putInteger(v, IntegerTag) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put an integer with the specified tag.  | 
 | 
  *  | 
 | 
  * @param v The integer to encode.  | 
 | 
  * @param tag The tag to encode.  | 
 | 
  */  | 
 | 
 | 
 | 
  public void putInteger(int v, int tag) { | 
 | 
    putIntegerValue(v) ;  | 
 | 
    putTag(tag) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put an integer expressed as a long.  | 
 | 
  *  | 
 | 
  * @param v The long to encode.  | 
 | 
  */  | 
 | 
 | 
 | 
  public void putInteger(long v) { | 
 | 
    putInteger(v, IntegerTag) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put an integer expressed as a long with the specified tag.  | 
 | 
  *  | 
 | 
  * @param v The long to encode  | 
 | 
  * @param tag The tag to encode.  | 
 | 
  */  | 
 | 
 | 
 | 
  public void putInteger(long v, int tag) { | 
 | 
    putIntegerValue(v) ;  | 
 | 
    putTag(tag) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put an octet string.  | 
 | 
  *  | 
 | 
  * @param s The bytes to encode  | 
 | 
  */  | 
 | 
 | 
 | 
  public void putOctetString(byte[] s) { | 
 | 
    putOctetString(s, OctetStringTag) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put an octet string with a specified tag.  | 
 | 
  *  | 
 | 
  * @param s The bytes to encode  | 
 | 
  * @param tag The tag to encode.  | 
 | 
  */  | 
 | 
 | 
 | 
  public void putOctetString(byte[] s, int tag) { | 
 | 
    putStringValue(s) ;  | 
 | 
    putTag(tag) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put an object identifier.  | 
 | 
  *  | 
 | 
  * @param s The oid to encode.  | 
 | 
  */  | 
 | 
 | 
 | 
  public void putOid(long[] s) { | 
 | 
    putOid(s, OidTag) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put an object identifier with a specified tag.  | 
 | 
  *  | 
 | 
  * @param s The integer to encode.  | 
 | 
  * @param tag The tag to encode.  | 
 | 
  */  | 
 | 
 | 
 | 
  public void putOid(long[] s, int tag) { | 
 | 
    putOidValue(s) ;  | 
 | 
    putTag(tag) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put a <CODE>NULL</CODE> value.  | 
 | 
  */  | 
 | 
 | 
 | 
  public void putNull() { | 
 | 
    putNull(NullTag) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put a <CODE>NULL</CODE> value with a specified tag.  | 
 | 
  *  | 
 | 
  * @param tag The tag to encode.  | 
 | 
  */  | 
 | 
 | 
 | 
  public void putNull(int tag) { | 
 | 
    putLength(0) ;  | 
 | 
    putTag(tag) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put an <CODE>ANY</CODE> value. In fact, this method does not encode anything.  | 
 | 
  * It simply copies the specified bytes into the encoding.  | 
 | 
  *  | 
 | 
  * @param s The encoding of the <CODE>ANY</CODE> value.  | 
 | 
  */  | 
 | 
 | 
 | 
  public void putAny(byte[] s) { | 
 | 
        putAny(s, s.length) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put an <CODE>ANY</CODE> value. Only the first <CODE>byteCount</CODE> are considered.  | 
 | 
  *  | 
 | 
  * @param s The encoding of the <CODE>ANY</CODE> value.  | 
 | 
  * @param byteCount The number of bytes of the encoding.  | 
 | 
  */  | 
 | 
 | 
 | 
  public void putAny(byte[] s, int byteCount) { | 
 | 
      java.lang.System.arraycopy(s,0,bytes,start-byteCount,byteCount);  | 
 | 
      start -= byteCount;  | 
 | 
      //    for (int i = byteCount - 1 ; i >= 0 ; i--) { | 
 | 
      //      bytes[--start] = s[i] ;  | 
 | 
      //    }  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Open a sequence.  | 
 | 
  * The encoder push the current position on its stack.  | 
 | 
  */  | 
 | 
 | 
 | 
  public void openSequence() { | 
 | 
    stackBuf[stackTop++] = start ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Close a sequence.  | 
 | 
  * The decode pull the stack to know the end of the current sequence.  | 
 | 
  */  | 
 | 
 | 
 | 
  public void closeSequence() { | 
 | 
    closeSequence(SequenceTag) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Close a sequence with the specified tag.  | 
 | 
  */  | 
 | 
 | 
 | 
  public void closeSequence(int tag) { | 
 | 
    final int end = stackBuf[--stackTop] ;  | 
 | 
    putLength(end - start) ;  | 
 | 
    putTag(tag) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  //  | 
 | 
  // Some standard tags  | 
 | 
    | 
 | 
  public final static int BooleanTag      = 1 ;  | 
 | 
  public final static int IntegerTag      = 2 ;  | 
 | 
  public final static int OctetStringTag  = 4 ;  | 
 | 
  public final static int NullTag          = 5 ;  | 
 | 
  public final static int OidTag          = 6 ;  | 
 | 
  public final static int SequenceTag      = 0x30 ;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
  ////////////////////////// PROTECTED ///////////////////////////////  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put a tag and move the current position backward.  | 
 | 
  *  | 
 | 
  * @param tag The tag to encode.  | 
 | 
  */  | 
 | 
 | 
 | 
  protected final void putTag(int tag) { | 
 | 
    if (tag < 256) { | 
 | 
      bytes[--start] = (byte)tag ;  | 
 | 
    }  | 
 | 
    else { | 
 | 
      while (tag != 0) { | 
 | 
        bytes[--start] = (byte)(tag & 127) ;  | 
 | 
        tag = tag << 7 ;  | 
 | 
      }  | 
 | 
    }  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put a length and move the current position backward.  | 
 | 
  *  | 
 | 
  * @param length The length to encode.  | 
 | 
  */  | 
 | 
 | 
 | 
  protected final void putLength(final int length) { | 
 | 
    if (length < 0) { | 
 | 
      throw new IllegalArgumentException() ;  | 
 | 
    }  | 
 | 
    else if (length < 128) { | 
 | 
      bytes[--start] = (byte)length ;  | 
 | 
    }  | 
 | 
    else if (length < 256) { | 
 | 
      bytes[--start] = (byte)length ;  | 
 | 
      bytes[--start] = (byte)0x81 ;  | 
 | 
    }  | 
 | 
    else if (length < 65536) { | 
 | 
      bytes[--start] = (byte)(length) ;  | 
 | 
      bytes[--start] = (byte)(length >> 8) ;  | 
 | 
      bytes[--start] = (byte)0x82 ;  | 
 | 
    }  | 
 | 
    else if (length < 16777126) { | 
 | 
      bytes[--start] = (byte)(length) ;  | 
 | 
      bytes[--start] = (byte)(length >> 8) ;  | 
 | 
      bytes[--start] = (byte)(length >> 16) ;  | 
 | 
      bytes[--start] = (byte)0x83 ;  | 
 | 
    }  | 
 | 
    else { | 
 | 
      bytes[--start] = (byte)(length) ;  | 
 | 
      bytes[--start] = (byte)(length >> 8) ;  | 
 | 
      bytes[--start] = (byte)(length >> 16) ;  | 
 | 
      bytes[--start] = (byte)(length >> 24) ;  | 
 | 
      bytes[--start] = (byte)0x84 ;  | 
 | 
    }  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put an integer value and move the current position backward.  | 
 | 
  *  | 
 | 
  * @param v The integer to encode.  | 
 | 
  */  | 
 | 
 | 
 | 
  protected final void putIntegerValue(int v) { | 
 | 
    final int end = start ;  | 
 | 
    int mask = 0x7f800000 ;  | 
 | 
    int byteNeeded = 4 ;  | 
 | 
    if (v < 0) { | 
 | 
      while (((mask & v) == mask) && (byteNeeded > 1)) { | 
 | 
        mask = mask >> 8 ;  | 
 | 
        byteNeeded-- ;  | 
 | 
      }  | 
 | 
    }  | 
 | 
    else { | 
 | 
      while (((mask & v) == 0) && (byteNeeded > 1)) { | 
 | 
        mask = mask >> 8 ;  | 
 | 
        byteNeeded-- ;  | 
 | 
      }  | 
 | 
    }  | 
 | 
    for (int i = 0 ; i < byteNeeded ; i++) { | 
 | 
      bytes[--start] = (byte)v ;  | 
 | 
      v =  v >> 8 ;  | 
 | 
    }  | 
 | 
    putLength(end - start) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put an integer value expressed as a long.  | 
 | 
  *  | 
 | 
  * @param v The integer to encode.  | 
 | 
  */  | 
 | 
 | 
 | 
  protected final void putIntegerValue(long v) { | 
 | 
    final int end = start ;  | 
 | 
    long mask = 0x7f80000000000000L ;  | 
 | 
    int byteNeeded = 8 ;  | 
 | 
    if (v < 0) { | 
 | 
      while (((mask & v) == mask) && (byteNeeded > 1)) { | 
 | 
        mask = mask >> 8 ;  | 
 | 
        byteNeeded-- ;  | 
 | 
      }  | 
 | 
    }  | 
 | 
    else { | 
 | 
      while (((mask & v) == 0) && (byteNeeded > 1)) { | 
 | 
        mask = mask >> 8 ;  | 
 | 
        byteNeeded-- ;  | 
 | 
      }  | 
 | 
    }  | 
 | 
    for (int i = 0 ; i < byteNeeded ; i++) { | 
 | 
      bytes[--start] = (byte)v ;  | 
 | 
      v =  v >> 8 ;  | 
 | 
    }  | 
 | 
    putLength(end - start) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put a byte string and move the current position backward.  | 
 | 
  *  | 
 | 
  * @param s The byte string to encode.  | 
 | 
  */  | 
 | 
 | 
 | 
  protected final void putStringValue(byte[] s) { | 
 | 
      final int datalen = s.length;  | 
 | 
      java.lang.System.arraycopy(s,0,bytes,start-datalen,datalen);  | 
 | 
      start -= datalen;  | 
 | 
      // for (int i = s.length - 1 ; i >= 0 ; i--) { | 
 | 
      //   bytes[--start] = s[i] ;  | 
 | 
        | 
 | 
      putLength(datalen) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
  /**  | 
 | 
  * Put an oid and move the current position backward.  | 
 | 
  *  | 
 | 
  * @param s The oid to encode.  | 
 | 
  */  | 
 | 
 | 
 | 
  protected final void putOidValue(final long[] s) { | 
 | 
      final int end = start ;  | 
 | 
      final int slength = s.length;  | 
 | 
 | 
 | 
        | 
 | 
      if ((slength < 2) || (s[0] > 2) || (s[1] >= 40)) { | 
 | 
          throw new IllegalArgumentException() ;  | 
 | 
      }  | 
 | 
      for (int i = slength - 1 ; i >= 2 ; i--) { | 
 | 
          long c = s[i] ;  | 
 | 
          if (c < 0) { | 
 | 
              throw new IllegalArgumentException() ;  | 
 | 
          }  | 
 | 
          else if (c < 128) { | 
 | 
              bytes[--start] = (byte)c ;  | 
 | 
          }  | 
 | 
          else { | 
 | 
              bytes[--start] = (byte)(c & 127) ;  | 
 | 
              c = c >> 7 ;  | 
 | 
              while (c != 0) { | 
 | 
                  bytes[--start] = (byte)(c | 128) ;  | 
 | 
                  c = c >> 7 ;  | 
 | 
              }  | 
 | 
          }  | 
 | 
      }  | 
 | 
      bytes[--start] = (byte)(s[0] * 40 + s[1]) ;  | 
 | 
      putLength(end - start) ;  | 
 | 
  }  | 
 | 
 | 
 | 
 | 
 | 
  //  | 
 | 
  // This is the byte array containing the encoding.  | 
 | 
    | 
 | 
  protected final byte bytes[];  | 
 | 
 | 
 | 
  //  | 
 | 
  // This is the index of the first byte of the encoding.  | 
 | 
  // It is initialized to <CODE>bytes.length</CODE> and decrease each time  | 
 | 
  // an value is put in the encoder.  | 
 | 
    | 
 | 
  protected int start = -1 ;  | 
 | 
 | 
 | 
  //  | 
 | 
  // This is the stack where end of sequences are kept.  | 
 | 
  // A value is computed and pushed in it each time the <CODE>openSequence</CODE> method  | 
 | 
  // is invoked.  | 
 | 
  // A value is pulled and checked each time the <CODE>closeSequence</CODE> method is called.  | 
 | 
    | 
 | 
  protected final int stackBuf[] = new int[200] ;  | 
 | 
  protected int stackTop = 0 ;  | 
 | 
 | 
 | 
}  |