FileDocCategorySizeDatePackage
BerDecoder.javaAPI DocJava SE 5 API17486Fri Aug 26 14:55:02 BST 2005com.sun.jmx.snmp

BerDecoder

public class BerDecoder extends Object
The BerDecoder class is used for decoding BER-encoded data. A 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 BerException if the encoding is not of the expected type.

This API is a Sun Microsystems internal API and is subject to change without notice.

version
4.20 12/19/03
author
Sun Microsystems, Inc
since
1.5

Fields Summary
public static final int
BooleanTag
public static final int
IntegerTag
public static final int
OctetStringTag
public static final int
NullTag
public static final int
OidTag
public static final int
SequenceTag
private final byte[]
bytes
private int
next
private final int[]
stackBuf
private int
stackTop
Constructors Summary
public BerDecoder(byte[] b)
Constructs a new decoder and attaches it to the specified byte string.

param
b The byte string containing the encoded data.

    bytes = b ;
    reset() ;
  
Methods Summary
public booleancannotCloseSequence()
Return true if the end of the current sequence is not reached. When this method returns false, closeSequence can (and must) be invoked.

return
true if there is still some data in the sequence.

    return (next < stackBuf[stackTop - 1]) ;
  
public voidcloseSequence()
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.

    if (stackBuf[stackTop - 1] == next) {
      stackTop-- ;
    }
    else {
      throw new BerException() ;
    }
  
public byte[]fetchAny()
Fetch an 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...

    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 ;
  
public byte[]fetchAny(int tag)
Fetch an 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...

    if (getTag() != tag) {
      throw new BerException() ;
    }
    return fetchAny() ;
  
public intfetchInteger()
Fetch an integer.

return
The decoded integer.
exception
BerException Current position does not point to an integer.

    return fetchInteger(IntegerTag) ;
  
public intfetchInteger(int tag)
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.

    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 ;
  
public longfetchIntegerAsLong()
Fetch an integer and return a long value.

return
The decoded integer.
exception
BerException Current position does not point to an integer.

    return fetchIntegerAsLong(IntegerTag) ;
  
public longfetchIntegerAsLong(int tag)
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.

    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 ;
  
private intfetchIntegerValue()
Fetch an integer value and move the current position forward.

return
The integer

    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 ;
  
private final longfetchIntegerValueAsLong()
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

    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 ;
  
private final intfetchLength()
Fetch a length and move the current position forward.

return
The length

    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 ;
  
public voidfetchNull()
Fetch a NULL value.

exception
BerException Current position does not point to NULL value.

    fetchNull(NullTag) ;
  
public voidfetchNull(int tag)
Fetch a NULL value with a specified tag.

param
tag The expected tag.
exception
BerException Current position does not point to NULL value or the tag is not the expected one.

    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 ;
    }
  
public byte[]fetchOctetString()
Fetch an octet string.

return
The decoded string.
exception
BerException Current position does not point to an octet string.

    return fetchOctetString(OctetStringTag) ;
  
public byte[]fetchOctetString(int tag)
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.

    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 ;
  
public long[]fetchOid(int tag)
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.

    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 ;
  
public long[]fetchOid()
Fetch an object identifier.

return
The decoded object identifier as an array of long.

    return fetchOid(OidTag) ;
  
private final long[]fetchOidValue()
Fetch an oid and move the current position forward.

return
The oid

    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 byte[]fetchStringValue()
Fetch a byte string and move the current position forward.

return
The byte string

    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 ;
  
private final intfetchTag()
Fetch a tag and move the current position forward.

return
The tag





  ////////////////////////// PRIVATE ///////////////////////////////



                 

        
    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 ;
  
public intgetTag()
Get the tag of the data at the current position. Current position is unchanged.

return
The next tag.

    int result = 0 ;
    final int backup = next ;
    try {
      result = fetchTag() ;
    }
    finally {
      next = backup ;
    }
    
    return result ;
  
public voidopenSequence()
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.

    openSequence(SequenceTag) ;
  
public voidopenSequence(int tag)
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.

    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 ;
    }
  
public voidreset()

    next = 0 ;
    stackTop = 0 ;
  
public java.lang.StringtoString()

    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) ;