0N/A/*
2362N/A * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A
0N/Apackage com.sun.jmx.snmp;
0N/A
0N/A
0N/A/**
0N/A * The <CODE>BerEncoder</CODE> class is used for encoding data using BER.
0N/A *
0N/A * A <CODE>BerEncoder</CODE> needs to be set up with a byte buffer. The encoded
0N/A * data are stored in this byte buffer.
0N/A * <P>
0N/A * NOTE : the buffer is filled from end to start. This means the caller
0N/A * needs to encode its data in the reverse order.
0N/A *
0N/A *
0N/A * <p><b>This API is a Sun Microsystems internal API and is subject
0N/A * to change without notice.</b></p>
0N/A *
0N/A * @since 1.5
0N/A */
0N/A
0N/Apublic class BerEncoder {
0N/A
0N/A /**
0N/A * Constructs a new encoder and attaches it to the specified byte string.
0N/A *
0N/A * @param b The byte string containing the encoded data.
0N/A */
0N/A
0N/A public BerEncoder(byte b[]) {
0N/A bytes = b ;
0N/A start = b.length ;
0N/A stackTop = 0 ;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Trim the encoding data and returns the length of the encoding.
0N/A *
0N/A * The encoder does backward encoding : so the bytes buffer is
0N/A * filled from end to start. The encoded data must be shift before
0N/A * the buffer can be used. This is the purpose of the <CODE>trim</CODE> method.
0N/A *
0N/A * After a call to the <CODE>trim</CODE> method, the encoder is reinitialized and <CODE>putXXX</CODE>
0N/A * overwrite any existing encoded data.
0N/A *
0N/A * @return The length of the encoded data.
0N/A */
0N/A
0N/A public int trim() {
0N/A final int result = bytes.length - start ;
0N/A
0N/A // for (int i = start ; i < bytes.length ; i++) {
0N/A // bytes[i-start] = bytes[i] ;
0N/A // }
0N/A if (result > 0)
0N/A java.lang.System.arraycopy(bytes,start,bytes,0,result);
0N/A
0N/A start = bytes.length ;
0N/A stackTop = 0 ;
0N/A
0N/A return result ;
0N/A }
0N/A
0N/A /**
0N/A * Put an integer.
0N/A *
0N/A * @param v The integer to encode.
0N/A */
0N/A
0N/A public void putInteger(int v) {
0N/A putInteger(v, IntegerTag) ;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Put an integer with the specified tag.
0N/A *
0N/A * @param v The integer to encode.
0N/A * @param tag The tag to encode.
0N/A */
0N/A
0N/A public void putInteger(int v, int tag) {
0N/A putIntegerValue(v) ;
0N/A putTag(tag) ;
0N/A }
0N/A
0N/A
0N/A
0N/A /**
0N/A * Put an integer expressed as a long.
0N/A *
0N/A * @param v The long to encode.
0N/A */
0N/A
0N/A public void putInteger(long v) {
0N/A putInteger(v, IntegerTag) ;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Put an integer expressed as a long with the specified tag.
0N/A *
0N/A * @param v The long to encode
0N/A * @param tag The tag to encode.
0N/A */
0N/A
0N/A public void putInteger(long v, int tag) {
0N/A putIntegerValue(v) ;
0N/A putTag(tag) ;
0N/A }
0N/A
0N/A
0N/A
0N/A /**
0N/A * Put an octet string.
0N/A *
0N/A * @param s The bytes to encode
0N/A */
0N/A
0N/A public void putOctetString(byte[] s) {
0N/A putOctetString(s, OctetStringTag) ;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Put an octet string with a specified tag.
0N/A *
0N/A * @param s The bytes to encode
0N/A * @param tag The tag to encode.
0N/A */
0N/A
0N/A public void putOctetString(byte[] s, int tag) {
0N/A putStringValue(s) ;
0N/A putTag(tag) ;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Put an object identifier.
0N/A *
0N/A * @param s The oid to encode.
0N/A */
0N/A
0N/A public void putOid(long[] s) {
0N/A putOid(s, OidTag) ;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Put an object identifier with a specified tag.
0N/A *
0N/A * @param s The integer to encode.
0N/A * @param tag The tag to encode.
0N/A */
0N/A
0N/A public void putOid(long[] s, int tag) {
0N/A putOidValue(s) ;
0N/A putTag(tag) ;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Put a <CODE>NULL</CODE> value.
0N/A */
0N/A
0N/A public void putNull() {
0N/A putNull(NullTag) ;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Put a <CODE>NULL</CODE> value with a specified tag.
0N/A *
0N/A * @param tag The tag to encode.
0N/A */
0N/A
0N/A public void putNull(int tag) {
0N/A putLength(0) ;
0N/A putTag(tag) ;
0N/A }
0N/A
0N/A
0N/A
0N/A /**
0N/A * Put an <CODE>ANY</CODE> value. In fact, this method does not encode anything.
0N/A * It simply copies the specified bytes into the encoding.
0N/A *
0N/A * @param s The encoding of the <CODE>ANY</CODE> value.
0N/A */
0N/A
0N/A public void putAny(byte[] s) {
0N/A putAny(s, s.length) ;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Put an <CODE>ANY</CODE> value. Only the first <CODE>byteCount</CODE> are considered.
0N/A *
0N/A * @param s The encoding of the <CODE>ANY</CODE> value.
0N/A * @param byteCount The number of bytes of the encoding.
0N/A */
0N/A
0N/A public void putAny(byte[] s, int byteCount) {
0N/A java.lang.System.arraycopy(s,0,bytes,start-byteCount,byteCount);
0N/A start -= byteCount;
0N/A // for (int i = byteCount - 1 ; i >= 0 ; i--) {
0N/A // bytes[--start] = s[i] ;
0N/A // }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Open a sequence.
0N/A * The encoder push the current position on its stack.
0N/A */
0N/A
0N/A public void openSequence() {
0N/A stackBuf[stackTop++] = start ;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Close a sequence.
0N/A * The decode pull the stack to know the end of the current sequence.
0N/A */
0N/A
0N/A public void closeSequence() {
0N/A closeSequence(SequenceTag) ;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Close a sequence with the specified tag.
0N/A */
0N/A
0N/A public void closeSequence(int tag) {
0N/A final int end = stackBuf[--stackTop] ;
0N/A putLength(end - start) ;
0N/A putTag(tag) ;
0N/A }
0N/A
0N/A
0N/A //
0N/A // Some standard tags
0N/A //
0N/A public final static int BooleanTag = 1 ;
0N/A public final static int IntegerTag = 2 ;
0N/A public final static int OctetStringTag = 4 ;
0N/A public final static int NullTag = 5 ;
0N/A public final static int OidTag = 6 ;
0N/A public final static int SequenceTag = 0x30 ;
0N/A
0N/A
0N/A
0N/A
0N/A ////////////////////////// PROTECTED ///////////////////////////////
0N/A
0N/A
0N/A
0N/A /**
0N/A * Put a tag and move the current position backward.
0N/A *
0N/A * @param tag The tag to encode.
0N/A */
0N/A
0N/A protected final void putTag(int tag) {
0N/A if (tag < 256) {
0N/A bytes[--start] = (byte)tag ;
0N/A }
0N/A else {
0N/A while (tag != 0) {
0N/A bytes[--start] = (byte)(tag & 127) ;
0N/A tag = tag << 7 ;
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Put a length and move the current position backward.
0N/A *
0N/A * @param length The length to encode.
0N/A */
0N/A
0N/A protected final void putLength(final int length) {
0N/A if (length < 0) {
0N/A throw new IllegalArgumentException() ;
0N/A }
0N/A else if (length < 128) {
0N/A bytes[--start] = (byte)length ;
0N/A }
0N/A else if (length < 256) {
0N/A bytes[--start] = (byte)length ;
0N/A bytes[--start] = (byte)0x81 ;
0N/A }
0N/A else if (length < 65536) {
0N/A bytes[--start] = (byte)(length) ;
0N/A bytes[--start] = (byte)(length >> 8) ;
0N/A bytes[--start] = (byte)0x82 ;
0N/A }
0N/A else if (length < 16777126) {
0N/A bytes[--start] = (byte)(length) ;
0N/A bytes[--start] = (byte)(length >> 8) ;
0N/A bytes[--start] = (byte)(length >> 16) ;
0N/A bytes[--start] = (byte)0x83 ;
0N/A }
0N/A else {
0N/A bytes[--start] = (byte)(length) ;
0N/A bytes[--start] = (byte)(length >> 8) ;
0N/A bytes[--start] = (byte)(length >> 16) ;
0N/A bytes[--start] = (byte)(length >> 24) ;
0N/A bytes[--start] = (byte)0x84 ;
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Put an integer value and move the current position backward.
0N/A *
0N/A * @param v The integer to encode.
0N/A */
0N/A
0N/A protected final void putIntegerValue(int v) {
0N/A final int end = start ;
0N/A int mask = 0x7f800000 ;
0N/A int byteNeeded = 4 ;
0N/A if (v < 0) {
0N/A while (((mask & v) == mask) && (byteNeeded > 1)) {
0N/A mask = mask >> 8 ;
0N/A byteNeeded-- ;
0N/A }
0N/A }
0N/A else {
0N/A while (((mask & v) == 0) && (byteNeeded > 1)) {
0N/A mask = mask >> 8 ;
0N/A byteNeeded-- ;
0N/A }
0N/A }
0N/A for (int i = 0 ; i < byteNeeded ; i++) {
0N/A bytes[--start] = (byte)v ;
0N/A v = v >> 8 ;
0N/A }
0N/A putLength(end - start) ;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Put an integer value expressed as a long.
0N/A *
0N/A * @param v The integer to encode.
0N/A */
0N/A
0N/A protected final void putIntegerValue(long v) {
0N/A final int end = start ;
0N/A long mask = 0x7f80000000000000L ;
0N/A int byteNeeded = 8 ;
0N/A if (v < 0) {
0N/A while (((mask & v) == mask) && (byteNeeded > 1)) {
0N/A mask = mask >> 8 ;
0N/A byteNeeded-- ;
0N/A }
0N/A }
0N/A else {
0N/A while (((mask & v) == 0) && (byteNeeded > 1)) {
0N/A mask = mask >> 8 ;
0N/A byteNeeded-- ;
0N/A }
0N/A }
0N/A for (int i = 0 ; i < byteNeeded ; i++) {
0N/A bytes[--start] = (byte)v ;
0N/A v = v >> 8 ;
0N/A }
0N/A putLength(end - start) ;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Put a byte string and move the current position backward.
0N/A *
0N/A * @param s The byte string to encode.
0N/A */
0N/A
0N/A protected final void putStringValue(byte[] s) {
0N/A final int datalen = s.length;
0N/A java.lang.System.arraycopy(s,0,bytes,start-datalen,datalen);
0N/A start -= datalen;
0N/A // for (int i = s.length - 1 ; i >= 0 ; i--) {
0N/A // bytes[--start] = s[i] ;
0N/A // }
0N/A putLength(datalen) ;
0N/A }
0N/A
0N/A
0N/A
0N/A /**
0N/A * Put an oid and move the current position backward.
0N/A *
0N/A * @param s The oid to encode.
0N/A */
0N/A
0N/A protected final void putOidValue(final long[] s) {
0N/A final int end = start ;
0N/A final int slength = s.length;
0N/A
0N/A // bugId 4641746: 0, 1, and 2 are legal values.
0N/A if ((slength < 2) || (s[0] > 2) || (s[1] >= 40)) {
0N/A throw new IllegalArgumentException() ;
0N/A }
0N/A for (int i = slength - 1 ; i >= 2 ; i--) {
0N/A long c = s[i] ;
0N/A if (c < 0) {
0N/A throw new IllegalArgumentException() ;
0N/A }
0N/A else if (c < 128) {
0N/A bytes[--start] = (byte)c ;
0N/A }
0N/A else {
0N/A bytes[--start] = (byte)(c & 127) ;
0N/A c = c >> 7 ;
0N/A while (c != 0) {
0N/A bytes[--start] = (byte)(c | 128) ;
0N/A c = c >> 7 ;
0N/A }
0N/A }
0N/A }
0N/A bytes[--start] = (byte)(s[0] * 40 + s[1]) ;
0N/A putLength(end - start) ;
0N/A }
0N/A
0N/A
0N/A //
0N/A // This is the byte array containing the encoding.
0N/A //
0N/A protected final byte bytes[];
0N/A
0N/A //
0N/A // This is the index of the first byte of the encoding.
0N/A // It is initialized to <CODE>bytes.length</CODE> and decrease each time
0N/A // an value is put in the encoder.
0N/A //
0N/A protected int start = -1 ;
0N/A
0N/A //
0N/A // This is the stack where end of sequences are kept.
0N/A // A value is computed and pushed in it each time the <CODE>openSequence</CODE> method
0N/A // is invoked.
0N/A // A value is pulled and checked each time the <CODE>closeSequence</CODE> method is called.
0N/A //
0N/A protected final int stackBuf[] = new int[200] ;
0N/A protected int stackTop = 0 ;
0N/A
0N/A}