blob: 4256e8e2f177ddac2fce55c37a82aa90c4e2ec2c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.api.asn1.ber.tlv;
import org.apache.directory.api.asn1.util.Asn1StringUtils;
/**
* This class is used to store Tags, Lengths and Values decoded from a PDU.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class TLV
{
/** The current Tag being processed */
private byte tag;
/** The current Length being processed */
private int length;
/** The number of byte to store the Length being processed */
private int lengthNbBytes;
/** The number of length's bytes currently read */
private int lengthBytesRead;
/** The current Value being processed */
private BerValue value;
/** An identity for the TLV. It store the TLV hashCode */
private int id;
/**
* Reference the TLV which contains the current TLV, if any. As the
* enclosing TLV of a PDU does not have parent, it can be null in this case.
* Otherwise, it must point to a constructed TLV
*/
private TLV parent;
/**
* The expected length of the TLV's elements, if the current TLV is a
* constructed TLV.
*/
private int expectedLength;
/** tag flag for the primitive/constructed bit - 0010 0000 - 0x20 */
public static final byte CONSTRUCTED_FLAG = 0x20;
/** mask to get the type class value */
public static final byte TYPE_CLASS_MASK = ( byte ) 0xC0;
/** value for the universal type class */
public static final byte TYPE_CLASS_UNIVERSAL = 0x00;
/** tag mask for the short tag format - 0001 1111 - 0x1F */
public static final int SHORT_MASK = 0x1F;
/** A mask to get the Length form */
public static final int LENGTH_LONG_FORM = 0x0080;
/** Value of the reserved extension */
public static final int LENGTH_EXTENSION_RESERVED = 0x7F;
/** A mask to get the long form value */
public static final int LENGTH_SHORT_MASK = 0x007F;
/** A speedup for single bytes length */
private static final byte[][] ONE_BYTE = new byte[128][];
// Initialize an array of byte[] used for encoding lengths below 128
static
{
for ( int i = 0; i < 128; i++ )
{
ONE_BYTE[i] = new byte[1];
ONE_BYTE[i][0] = ( byte ) i;
}
}
/**
* Creates a new TLV object.
*
* @param id the TLV's id
*/
public TLV( int id )
{
tag = 0;
length = 0;
lengthNbBytes = 0;
value = new BerValue();
this.id = id;
expectedLength = 0;
}
/**
* Checks to see if the tag is constructed.
*
* @param tag the TLV's tag
* @return true if constructed, false if primitive
*/
public static boolean isConstructed( byte tag )
{
return ( tag & CONSTRUCTED_FLAG ) != 0;
}
/**
* Checks to see if the current tlv's tag is constructed.
*
* @return true if constructed, false if primitive
*/
public boolean isConstructed()
{
return ( tag & CONSTRUCTED_FLAG ) != 0;
}
/**
* Checks to see if the tag represented by this Tag is primitive or
* constructed.
*
* @param tag the tag to be checked
* @return true if it is primitive, false if it is constructed
*/
public static boolean isPrimitive( byte tag )
{
return ( tag & CONSTRUCTED_FLAG ) == 0;
}
/**
* Tells if the tag is Universal or not
*
* @param tag the tag to be checked
* @return true if it is primitive, false if it is constructed
*/
public static boolean isUniversal( byte tag )
{
return ( tag & TYPE_CLASS_MASK ) == TYPE_CLASS_UNIVERSAL;
}
/**
* Reset the TLV, so it can be reused for the next PDU decoding.
*/
public void reset()
{
tag = 0;
length = 0;
lengthNbBytes = 0;
value.reset();
expectedLength = 0;
}
/**
* @return Returns the tag.
*/
public byte getTag()
{
return tag;
}
/**
* Set a tag value for this TLV.
*
* @param tag the tag field for this TLV.
*/
public void setTag( byte tag )
{
this.tag = tag;
}
/**
* @return Returns the value.
*/
public BerValue getValue()
{
return value;
}
/**
* The TLV size is calculated by adding the Tag's size, the Length's size
* and the Value's length, if any.
*
* @return Returns the size of the TLV.
*/
public int getSize()
{
return 1 + lengthNbBytes + length;
}
/**
* Utility function that return the number of bytes necessary to store the
* length
*
* @param length The length to store in a byte array
* @return The number of bytes necessary to store the length.
* @see <a href="http://en.wikipedia.org/wiki/X.690#Length_Octets">X.690</a>
*/
public static int getNbBytes( int length )
{
if ( length >= 0 )
{
if ( length < 128 )
{
return 1;
}
else if ( length < 256 )
{
return 2;
}
else if ( length < 65536 )
{
return 3;
}
else if ( length < 16777216 )
{
return 4;
}
else
{
return 5;
}
}
else
{
return 5;
}
}
/**
* Utility function that return a byte array representing the length
*
* @param length The length to store in a byte array
* @return The byte array representing the length.
*/
public static byte[] getBytes( int length )
{
if ( length >= 0 )
{
if ( length < 128 )
{
return ONE_BYTE[length];
}
else
{
byte[] bytes = new byte[getNbBytes( length )];
if ( length < 256 )
{
bytes[0] = ( byte ) 0x81;
bytes[1] = ( byte ) length;
}
else if ( length < 65536 )
{
bytes[0] = ( byte ) 0x82;
bytes[1] = ( byte ) ( length >> 8 );
bytes[2] = ( byte ) ( length & 0x00FF );
}
else if ( length < 16777216 )
{
bytes[0] = ( byte ) 0x83;
bytes[1] = ( byte ) ( length >> 16 );
bytes[2] = ( byte ) ( ( length >> 8 ) & 0x00FF );
bytes[3] = ( byte ) ( length & 0x00FF );
}
else
{
bytes[0] = ( byte ) 0x84;
bytes[1] = ( byte ) ( length >> 24 );
bytes[2] = ( byte ) ( ( length >> 16 ) & 0x00FF );
bytes[3] = ( byte ) ( ( length >> 8 ) & 0x00FF );
bytes[4] = ( byte ) ( length & 0x00FF );
}
return bytes;
}
}
else
{
byte[] bytes = new byte[getNbBytes( length )];
bytes[0] = ( byte ) 0x84;
bytes[1] = ( byte ) ( length >> 24 );
bytes[2] = ( byte ) ( ( length >> 16 ) & 0x00FF );
bytes[3] = ( byte ) ( ( length >> 8 ) & 0x00FF );
bytes[4] = ( byte ) ( length & 0x00FF );
return bytes;
}
}
/**
* @return The parent.
*/
public TLV getParent()
{
return parent;
}
/**
* @param parent The parent to set.
*/
public void setParent( TLV parent )
{
this.parent = parent;
}
/**
* Get the TLV expected length.
*
* @return The expectedLength.
*/
public int getExpectedLength()
{
return expectedLength;
}
/**
* Set the new expected length of the current TLV.
*
* @param expectedLength The expectedLength to set.
*/
public void setExpectedLength( int expectedLength )
{
this.expectedLength = expectedLength;
}
/**
* @return The number of bytes necessary to store the TLV's length
*/
public int getLengthNbBytes()
{
return lengthNbBytes;
}
/**
* Set the number of bytes we should use to store the TLV's length.
*
* @param lengthNbBytes The number of bytes necessary to store the TLV's length
*/
public void setLengthNbBytes( int lengthNbBytes )
{
this.lengthNbBytes = lengthNbBytes;
}
/**
* @return the TLV's length
*/
public int getLength()
{
return length;
}
/**
* Set the TLV's length
*
* @param length the TLV's length
*/
public void setLength( int length )
{
this.length = length;
}
/**
* @return The currently read TLV's length bytes
*/
public int getLengthBytesRead()
{
return lengthBytesRead;
}
/**
* Set the currently read TLV's length bytes.
*
* @param lengthBytesRead the currently read TLV's length bytes
*/
public void setLengthBytesRead( int lengthBytesRead )
{
this.lengthBytesRead = lengthBytesRead;
}
/**
* Increment the number of bytes read for this TLV
*
*/
public void incLengthBytesRead()
{
lengthBytesRead++;
}
/**
* @return The TLV's ID
*/
public int getId()
{
return id;
}
/**
* Get a String representation of the TLV
*
* @return A String
*/
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append( "TLV[ " );
sb.append( Asn1StringUtils.dumpByte( tag ) ).append( ", " );
sb.append( length ).append( ", " );
sb.append( value.toString() );
sb.append( "]" );
return sb.toString();
}
}