- /*
- * @(#)file BerEncoder.java
- * @(#)author Sun Microsystems, Inc.
- * @(#)version 4.16
- * @(#)date 04/09/15
- *
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- */
-
-
- 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>
- * @version 4.16 12/19/03
- * @author Sun Microsystems, Inc
- *
- * @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;
-
- // bugId 4641746: 0, 1, and 2 are legal values.
- 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 ;
-
- }
-
-