001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 * 
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 * 
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 * 
019 */
020package org.apache.directory.api.asn1.ber.tlv;
021
022
023import org.apache.directory.api.asn1.util.Asn1StringUtils;
024
025
026/**
027 * This class is used to store Tags, Lengths and Values decoded from a PDU.
028 * 
029 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
030 */
031public class TLV
032{
033    /** The current Tag being processed */
034    private byte tag;
035
036    /** The current Length being processed */
037    private int length;
038
039    /** The number of byte to store the Length being processed */
040    private int lengthNbBytes;
041
042    /** The number of length's bytes currently read */
043    private int lengthBytesRead;
044
045    /** The current Value being processed */
046    private BerValue value;
047
048    /** An identity for the TLV. It store the TLV hashCode */
049    private int id;
050
051    /**
052     * Reference the TLV which contains the current TLV, if any. As the
053     * enclosing TLV of a PDU does not have parent, it can be null in this case.
054     * Otherwise, it must point to a constructed TLV
055     */
056    private TLV parent;
057
058    /**
059     * The expected length of the TLV's elements, if the current TLV is a
060     * constructed TLV.
061     */
062    private int expectedLength;
063
064    /** tag flag for the primitive/constructed bit - 0010 0000 - 0x20 */
065    public static final byte CONSTRUCTED_FLAG = 0x20;
066
067    /** mask to get the type class value */
068    public static final byte TYPE_CLASS_MASK = ( byte ) 0xC0;
069
070    /** value for the universal type class */
071    public static final byte TYPE_CLASS_UNIVERSAL = 0x00;
072
073    /** tag mask for the short tag format - 0001 1111 - 0x1F */
074    public static final int SHORT_MASK = 0x1F;
075
076    /** A mask to get the Length form */
077    public static final int LENGTH_LONG_FORM = 0x0080;
078
079    /** Value of the reserved extension */
080    public static final int LENGTH_EXTENSION_RESERVED = 0x7F;
081
082    /** A mask to get the long form value */
083    public static final int LENGTH_SHORT_MASK = 0x007F;
084
085    /** A speedup for single bytes length */
086    private static final byte[][] ONE_BYTE = new byte[128][];
087
088    // Initialize an array of byte[] used for encoding lengths below 128
089    static
090    {
091        for ( int i = 0; i < 128; i++ )
092        {
093            ONE_BYTE[i] = new byte[1];
094            ONE_BYTE[i][0] = ( byte ) i;
095        }
096    }
097
098
099    /**
100     * Creates a new TLV object.
101     * 
102     * @param id the TLV's id
103     */
104    public TLV( int id )
105    {
106        tag = 0;
107        length = 0;
108        lengthNbBytes = 0;
109        value = new BerValue();
110        this.id = id;
111
112        expectedLength = 0;
113    }
114
115
116    /**
117     * Checks to see if the tag is constructed.
118     * 
119     * @param tag the TLV's tag
120     * @return true if constructed, false if primitive
121     */
122    public static boolean isConstructed( byte tag )
123    {
124        return ( tag & CONSTRUCTED_FLAG ) != 0;
125    }
126
127
128    /**
129     * Checks to see if the current tlv's tag is constructed.
130     * 
131     * @return true if constructed, false if primitive
132     */
133    public boolean isConstructed()
134    {
135        return ( tag & CONSTRUCTED_FLAG ) != 0;
136    }
137
138
139    /**
140     * Checks to see if the tag represented by this Tag is primitive or
141     * constructed.
142     * 
143     * @param tag the tag to be checked
144     * @return true if it is primitive, false if it is constructed
145     */
146    public static boolean isPrimitive( byte tag )
147    {
148        return ( tag & CONSTRUCTED_FLAG ) == 0;
149    }
150
151
152    /**
153     * Tells if the tag is Universal or not
154     * 
155     * @param tag the tag to be checked
156     * @return true if it is primitive, false if it is constructed
157     */
158    public static boolean isUniversal( byte tag )
159    {
160        return ( tag & TYPE_CLASS_MASK ) == TYPE_CLASS_UNIVERSAL;
161    }
162
163
164    /**
165     * Reset the TLV, so it can be reused for the next PDU decoding.
166     */
167    public void reset()
168    {
169        tag = 0;
170        length = 0;
171        lengthNbBytes = 0;
172        value.reset();
173
174        expectedLength = 0;
175    }
176
177
178    /**
179     * @return Returns the tag.
180     */
181    public byte getTag()
182    {
183        return tag;
184    }
185
186
187    /**
188     * Set a tag value for this TLV.
189     * 
190     * @param tag the tag field for this TLV.
191     */
192    public void setTag( byte tag )
193    {
194        this.tag = tag;
195    }
196
197
198    /**
199     * @return Returns the value.
200     */
201    public BerValue getValue()
202    {
203        return value;
204    }
205
206
207    /**
208     * The TLV size is calculated by adding the Tag's size, the Length's size
209     * and the Value's length, if any.
210     * 
211     * @return Returns the size of the TLV.
212     */
213    public int getSize()
214    {
215        return 1 + lengthNbBytes + length;
216    }
217
218
219    /**
220     * Utility function that return the number of bytes necessary to store the
221     * length
222     * 
223     * @param length The length to store in a byte array
224     * @return The number of bytes necessary to store the length.
225     * @see <a href="http://en.wikipedia.org/wiki/X.690#Length_Octets">X.690</a>
226     */
227    public static int getNbBytes( int length )
228    {
229        if ( length >= 0 )
230        {
231            if ( length < 128 )
232            {
233                return 1;
234            }
235            else if ( length < 256 )
236            {
237                return 2;
238            }
239            else if ( length < 65536 )
240            {
241                return 3;
242            }
243            else if ( length < 16777216 )
244            {
245                return 4;
246            }
247            else
248            {
249                return 5;
250            }
251        }
252        else
253        {
254            return 5;
255        }
256    }
257
258
259    /**
260     * Utility function that return a byte array representing the length
261     * 
262     * @param length The length to store in a byte array
263     * @return The byte array representing the length.
264     */
265    public static byte[] getBytes( int length )
266    {
267        if ( length >= 0 )
268        {
269            if ( length < 128 )
270            {
271                return ONE_BYTE[length];
272            }
273            else
274            {
275                byte[] bytes = new byte[getNbBytes( length )];
276
277                if ( length < 256 )
278                {
279                    bytes[0] = ( byte ) 0x81;
280                    bytes[1] = ( byte ) length;
281                }
282                else if ( length < 65536 )
283                {
284                    bytes[0] = ( byte ) 0x82;
285                    bytes[1] = ( byte ) ( length >> 8 );
286                    bytes[2] = ( byte ) ( length & 0x00FF );
287                }
288                else if ( length < 16777216 )
289                {
290                    bytes[0] = ( byte ) 0x83;
291                    bytes[1] = ( byte ) ( length >> 16 );
292                    bytes[2] = ( byte ) ( ( length >> 8 ) & 0x00FF );
293                    bytes[3] = ( byte ) ( length & 0x00FF );
294                }
295                else
296                {
297                    bytes[0] = ( byte ) 0x84;
298                    bytes[1] = ( byte ) ( length >> 24 );
299                    bytes[2] = ( byte ) ( ( length >> 16 ) & 0x00FF );
300                    bytes[3] = ( byte ) ( ( length >> 8 ) & 0x00FF );
301                    bytes[4] = ( byte ) ( length & 0x00FF );
302                }
303
304                return bytes;
305            }
306        }
307        else
308        {
309            byte[] bytes = new byte[getNbBytes( length )];
310
311            bytes[0] = ( byte ) 0x84;
312            bytes[1] = ( byte ) ( length >> 24 );
313            bytes[2] = ( byte ) ( ( length >> 16 ) & 0x00FF );
314            bytes[3] = ( byte ) ( ( length >> 8 ) & 0x00FF );
315            bytes[4] = ( byte ) ( length & 0x00FF );
316
317            return bytes;
318        }
319    }
320
321
322    /**
323     * @return The parent.
324     */
325    public TLV getParent()
326    {
327        return parent;
328    }
329
330
331    /**
332     * @param parent The parent to set.
333     */
334    public void setParent( TLV parent )
335    {
336        this.parent = parent;
337    }
338
339
340    /**
341     * Get the TLV expected length.
342     * 
343     * @return The expectedLength.
344     */
345    public int getExpectedLength()
346    {
347        return expectedLength;
348    }
349
350
351    /**
352     * Set the new expected length of the current TLV.
353     * 
354     * @param expectedLength The expectedLength to set.
355     */
356    public void setExpectedLength( int expectedLength )
357    {
358        this.expectedLength = expectedLength;
359    }
360
361
362    /**
363     * @return The number of bytes necessary to store the TLV's length
364     */
365    public int getLengthNbBytes()
366    {
367        return lengthNbBytes;
368    }
369
370
371    /**
372     * Set the number of bytes we should use to store the TLV's length.
373     * 
374     * @param lengthNbBytes The number of bytes necessary to store the TLV's length
375     */
376    public void setLengthNbBytes( int lengthNbBytes )
377    {
378        this.lengthNbBytes = lengthNbBytes;
379    }
380
381
382    /**
383     * @return the TLV's length
384     */
385    public int getLength()
386    {
387        return length;
388    }
389
390
391    /**
392     * Set the TLV's length
393     *
394     * @param length the TLV's length
395     */
396    public void setLength( int length )
397    {
398        this.length = length;
399    }
400
401
402    /**
403     * @return The currently read TLV's length bytes
404     */
405    public int getLengthBytesRead()
406    {
407        return lengthBytesRead;
408    }
409
410
411    /**
412     * Set the currently read TLV's length bytes.
413     * 
414     * @param lengthBytesRead the currently read TLV's length bytes
415     */
416    public void setLengthBytesRead( int lengthBytesRead )
417    {
418        this.lengthBytesRead = lengthBytesRead;
419    }
420
421
422    /**
423     * Increment the number of bytes read for this TLV
424     *
425     */
426    public void incLengthBytesRead()
427    {
428        lengthBytesRead++;
429    }
430
431
432    /**
433     * @return The TLV's ID
434     */
435    public int getId()
436    {
437        return id;
438    }
439
440
441    /**
442     * Get a String representation of the TLV
443     * 
444     * @return A String
445     */
446    @Override
447    public String toString()
448    {
449
450        StringBuilder sb = new StringBuilder();
451
452        sb.append( "TLV[ " );
453        sb.append( Asn1StringUtils.dumpByte( tag ) ).append( ", " );
454        sb.append( length ).append( ", " );
455        sb.append( value.toString() );
456        sb.append( "]" );
457
458        return sb.toString();
459    }
460}