alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (BerDecoder.java)

This example Java source code file (BerDecoder.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

berdecoder, berexception, booleantag, decoded, indexoutofboundsexception, integertag, nulltag, octetstringtag, oidtag, sequencetag, string, stringbuffer

The BerDecoder.java Java example source code

/*
 * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


package com.sun.jmx.snmp;




/**
 * The <CODE>BerDecoder class is used for decoding
 * BER-encoded data.
 *
 * A <CODE>BerDecoder needs to be set up with the byte string containing
 * the encoding. It maintains a current position in the byte string.
 *
 * Methods allows to fetch integer, string, OID, etc., from the current
 * position. After a fetch the current position is moved forward.
 *
 * A fetch throws a <CODE>BerException if the encoding is not of the
 * expected type.
 *
 * <p>This API is a Sun Microsystems internal API  and is subject
 * to change without notice.</b>

* * @since 1.5 */ public class BerDecoder { /** * Constructs a new decoder and attaches it to the specified byte string. * * @param b The byte string containing the encoded data. */ public BerDecoder(byte b[]) { bytes = b ; reset() ; } public void reset() { next = 0 ; stackTop = 0 ; } /** * Fetch an integer. * * @return The decoded integer. * * @exception BerException Current position does not point to an integer. */ public int fetchInteger() throws BerException { return fetchInteger(IntegerTag) ; } /** * Fetch an integer with the specified tag. * * @param tag The expected tag. * * @return The decoded integer. * * @exception BerException Current position does not point to an integer * or the tag is not the expected one. */ public int fetchInteger(int tag) throws BerException { int result = 0 ; final int backup = next ; try { if (fetchTag() != tag) { throw new BerException() ; } result = fetchIntegerValue() ; } catch(BerException e) { next = backup ; throw e ; } return result ; } /** * Fetch an integer and return a long value. * * @return The decoded integer. * * @exception BerException Current position does not point to an integer. */ public long fetchIntegerAsLong() throws BerException { return fetchIntegerAsLong(IntegerTag) ; } /** * Fetch an integer with the specified tag and return a long value. * * @param tag The expected tag. * * @return The decoded integer. * * @exception BerException Current position does not point to an integer * or the tag is not the expected one. */ public long fetchIntegerAsLong(int tag) throws BerException { long result = 0 ; final int backup = next ; try { if (fetchTag() != tag) { throw new BerException() ; } result = fetchIntegerValueAsLong() ; } catch(BerException e) { next = backup ; throw e ; } return result ; } /** * Fetch an octet string. * * @return The decoded string. * * @exception BerException Current position does not point to an octet string. */ public byte[] fetchOctetString() throws BerException { return fetchOctetString(OctetStringTag) ; } /** * Fetch an octet string with a specified tag. * * @param tag The expected tag. * * @return The decoded string. * * @exception BerException Current position does not point to an octet string * or the tag is not the expected one. */ public byte[] fetchOctetString(int tag) throws BerException { byte[] result = null ; final int backup = next ; try { if (fetchTag() != tag) { throw new BerException() ; } result = fetchStringValue() ; } catch(BerException e) { next = backup ; throw e ; } return result ; } /** * Fetch an object identifier. * * @return The decoded object identifier as an array of long. */ public long[] fetchOid() throws BerException { return fetchOid(OidTag) ; } /** * Fetch an object identifier with a specified tag. * * @param tag The expected tag. * * @return The decoded object identifier as an array of long. * * @exception BerException Current position does not point to an oid * or the tag is not the expected one. */ public long[] fetchOid(int tag) throws BerException { long[] result = null ; final int backup = next ; try { if (fetchTag() != tag) { throw new BerException() ; } result = fetchOidValue() ; } catch(BerException e) { next = backup ; throw e ; } return result ; } /** * Fetch a <CODE>NULL value. * * @exception BerException Current position does not point to <CODE>NULL value. */ public void fetchNull() throws BerException { fetchNull(NullTag) ; } /** * Fetch a <CODE>NULL value with a specified tag. * * @param tag The expected tag. * * @exception BerException Current position does not point to * <CODE>NULL value or the tag is not the expected one. */ public void fetchNull(int tag) throws BerException { final int backup = next ; try { if (fetchTag() != tag) { throw new BerException() ; } final int length = fetchLength(); if (length != 0) throw new BerException(); } catch(BerException e) { next = backup ; throw e ; } } /** * Fetch an <CODE>ANY value. In fact, this method does not decode anything * it simply returns the next TLV as an array of bytes. * * @return The TLV as a byte array. * * @exception BerException The next TLV is really badly encoded... */ public byte[] fetchAny() throws BerException { byte[] result = null ; final int backup = next ; try { final int tag = fetchTag() ; final int contentLength = fetchLength() ; if (contentLength < 0) throw new BerException() ; final int tlvLength = next + contentLength - backup ; if (contentLength > (bytes.length - next)) throw new IndexOutOfBoundsException("Decoded length exceeds buffer"); final byte[] data = new byte[tlvLength] ; java.lang.System.arraycopy(bytes,backup,data,0,tlvLength); // for (int i = 0 ; i < tlvLength ; i++) { // data[i] = bytes[backup + i] ; // } next = next + contentLength ; result = data; } catch(IndexOutOfBoundsException e) { next = backup ; throw new BerException() ; } // catch(Error e) { // debug("fetchAny: Error decoding BER: " + e); // throw e; // } return result ; } /** * Fetch an <CODE>ANY value with a specific tag. * * @param tag The expected tag. * * @return The TLV as a byte array. * * @exception BerException The next TLV is really badly encoded... */ public byte[] fetchAny(int tag) throws BerException { if (getTag() != tag) { throw new BerException() ; } return fetchAny() ; } /** * Fetch a sequence header. * The decoder computes the end position of the sequence and push it * on its stack. * * @exception BerException Current position does not point to a sequence header. */ public void openSequence() throws BerException { openSequence(SequenceTag) ; } /** * Fetch a sequence header with a specific tag. * * @param tag The expected tag. * * @exception BerException Current position does not point to a sequence header * or the tag is not the expected one. */ public void openSequence(int tag) throws BerException { final int backup = next ; try { if (fetchTag() != tag) { throw new BerException() ; } final int l = fetchLength() ; if (l < 0) throw new BerException(); if (l > (bytes.length - next)) throw new BerException(); stackBuf[stackTop++] = next + l ; } catch(BerException e) { next = backup ; throw e ; } } /** * Close a sequence. * The decode pull the stack and verifies that the current position * matches with the calculated end of the sequence. If not it throws * an exception. * * @exception BerException The sequence is not expected to finish here. */ public void closeSequence() throws BerException { if (stackBuf[stackTop - 1] == next) { stackTop-- ; } else { throw new BerException() ; } } /** * Return <CODE>true if the end of the current sequence is not reached. * When this method returns <CODE>false, closeSequence can (and must) be * invoked. * * @return <CODE>true if there is still some data in the sequence. */ public boolean cannotCloseSequence() { return (next < stackBuf[stackTop - 1]) ; } /** * Get the tag of the data at the current position. * Current position is unchanged. * * @return The next tag. */ public int getTag() throws BerException { int result = 0 ; final int backup = next ; try { result = fetchTag() ; } finally { next = backup ; } return result ; } public String toString() { final StringBuffer result = new StringBuffer(bytes.length * 2) ; for (int i = 0 ; i < bytes.length ; i++) { final int b = (bytes[i] > 0) ? bytes[i] : bytes[i] + 256 ; if (i == next) { result.append("(") ; } result.append(Character.forDigit(b / 16, 16)) ; result.append(Character.forDigit(b % 16, 16)) ; if (i == next) { result.append(")") ; } } if (bytes.length == next) { result.append("()") ; } return new String(result) ; } // // 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 ; ////////////////////////// PRIVATE /////////////////////////////// /** * Fetch a tag and move the current position forward. * * @return The tag */ private final int fetchTag() throws BerException { int result = 0 ; final int backup = next ; try { final byte b0 = bytes[next++] ; result = (b0 >= 0) ? b0 : b0 + 256 ; if ((result & 31) == 31) { while ((bytes[next] & 128) != 0) { result = result << 7 ; result = result | (bytes[next++] & 127); } } } catch(IndexOutOfBoundsException e) { next = backup ; throw new BerException() ; } return result ; } /** * Fetch a length and move the current position forward. * * @return The length */ private final int fetchLength() throws BerException { int result = 0 ; final int backup = next ; try { final byte b0 = bytes[next++] ; if (b0 >= 0) { result = b0 ; } else { for (int c = 128 + b0 ; c > 0 ; c--) { final byte bX = bytes[next++] ; result = result << 8 ; result = result | ((bX >= 0) ? bX : bX+256) ; } } } catch(IndexOutOfBoundsException e) { next = backup ; throw new BerException() ; } return result ; } /** * Fetch an integer value and move the current position forward. * * @return The integer */ private int fetchIntegerValue() throws BerException { int result = 0 ; final int backup = next ; try { final int length = fetchLength() ; if (length <= 0) throw new BerException() ; if (length > (bytes.length - next)) throw new IndexOutOfBoundsException("Decoded length exceeds buffer"); final int end = next + length ; result = bytes[next++] ; while (next < end) { final byte b = bytes[next++] ; if (b < 0) { result = (result << 8) | (256 + b) ; } else { result = (result << 8) | b ; } } } catch(BerException e) { next = backup ; throw e ; } catch(IndexOutOfBoundsException e) { next = backup ; throw new BerException() ; } catch(ArithmeticException e) { next = backup ; throw new BerException() ; } return result ; } /** * Fetch an integer value and return a long value. * FIX ME: someday we could have only on fetchIntegerValue() which always * returns a long value. * * @return The integer */ private final long fetchIntegerValueAsLong() throws BerException { long result = 0 ; final int backup = next ; try { final int length = fetchLength() ; if (length <= 0) throw new BerException() ; if (length > (bytes.length - next)) throw new IndexOutOfBoundsException("Decoded length exceeds buffer"); final int end = next + length ; result = bytes[next++] ; while (next < end) { final byte b = bytes[next++] ; if (b < 0) { result = (result << 8) | (256 + b) ; } else { result = (result << 8) | b ; } } } catch(BerException e) { next = backup ; throw e ; } catch(IndexOutOfBoundsException e) { next = backup ; throw new BerException() ; } catch(ArithmeticException e) { next = backup ; throw new BerException() ; } return result ; } /** * Fetch a byte string and move the current position forward. * * @return The byte string */ private byte[] fetchStringValue() throws BerException { byte[] result = null ; final int backup = next ; try { final int length = fetchLength() ; if (length < 0) throw new BerException() ; if (length > (bytes.length - next)) throw new IndexOutOfBoundsException("Decoded length exceeds buffer"); final byte data[] = new byte[length] ; java.lang.System.arraycopy(bytes,next,data,0,length); next += length; // int i = 0 ; // while (i < length) { // result[i++] = bytes[next++] ; // } result = data; } catch(BerException e) { next = backup ; throw e ; } catch(IndexOutOfBoundsException e) { next = backup ; throw new BerException() ; } catch(ArithmeticException e) { next = backup ; throw new BerException() ; } // catch(Error e) { // debug("fetchStringValue: Error decoding BER: " + e); // throw e; // } return result ; } /** * Fetch an oid and move the current position forward. * * @return The oid */ private final long[] fetchOidValue() throws BerException { long[] result = null ; final int backup = next ; try { final int length = fetchLength() ; if (length <= 0) throw new BerException() ; if (length > (bytes.length - next)) throw new IndexOutOfBoundsException("Decoded length exceeds buffer"); // Count how many bytes have their 8th bit to 0 // -> this gives the number of components in the oid int subidCount = 2 ; for (int i = 1 ; i < length ; i++) { if ((bytes[next + i] & 0x80) == 0) { subidCount++ ; } } final int datalen = subidCount; final long[] data = new long[datalen]; final byte b0 = bytes[next++] ; // bugId 4641746 // The 8th bit of the first byte should always be set to 0 if (b0 < 0) throw new BerException(); // bugId 4641746 // The first sub Id cannot be greater than 2 final long lb0 = b0 / 40 ; if (lb0 > 2) throw new BerException(); final long lb1 = b0 % 40; data[0] = lb0 ; data[1] = lb1 ; int i = 2 ; while (i < datalen) { long subid = 0 ; byte b = bytes[next++] ; while ((b & 0x80) != 0) { subid = (subid << 7) | (b & 0x7f) ; // bugId 4654674 if (subid < 0) throw new BerException(); b = bytes[next++] ; } subid = (subid << 7) | b ; // bugId 4654674 if (subid < 0) throw new BerException(); data[i++] = subid ; } result = data; } catch(BerException e) { next = backup ; throw e ; } catch(IndexOutOfBoundsException e) { next = backup ; throw new BerException() ; } // catch(Error e) { // debug("fetchOidValue: Error decoding BER: " + e); // throw e; // } return result ; } // private static final void debug(String str) { // System.out.println(str); // } // // This is the byte array containing the encoding. // private final byte bytes[]; // // This is the current location. It is the next byte // to be decoded. It's an index in bytes[]. // private int next = 0 ; // // This is the stack where end of sequences are kept. // A value is computed and pushed in it each time openSequence() // is invoked. // A value is pulled and checked each time closeSequence() is called. // private final int stackBuf[] = new int[200] ; private int stackTop = 0 ; }

Other Java examples (source code examples)

Here is a short list of links related to this Java BerDecoder.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.