View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    * 
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   * 
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   * 
19   */
20  package org.apache.directory.api.asn1.ber.tlv;
21  
22  
23  import org.apache.directory.api.asn1.util.Asn1StringUtils;
24  
25  
26  /**
27   * This class is used to store Tags, Lengths and Values decoded from a PDU.
28   * 
29   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
30   */
31  public class TLV
32  {
33      /** The current Tag being processed */
34      private byte tag;
35  
36      /** The current Length being processed */
37      private int length;
38  
39      /** The number of byte to store the Length being processed */
40      private int lengthNbBytes;
41  
42      /** The number of length's bytes currently read */
43      private int lengthBytesRead;
44  
45      /** The current Value being processed */
46      private BerValue value;
47  
48      /** An identity for the TLV. It store the TLV hashCode */
49      private int id;
50  
51      /**
52       * Reference the TLV which contains the current TLV, if any. As the
53       * enclosing TLV of a PDU does not have parent, it can be null in this case.
54       * Otherwise, it must point to a constructed TLV
55       */
56      private TLV parent;
57  
58      /**
59       * The expected length of the TLV's elements, if the current TLV is a
60       * constructed TLV.
61       */
62      private int expectedLength;
63  
64      /** tag flag for the primitive/constructed bit - 0010 0000 - 0x20 */
65      public static final byte CONSTRUCTED_FLAG = 0x20;
66  
67      /** mask to get the type class value */
68      public static final byte TYPE_CLASS_MASK = ( byte ) 0xC0;
69  
70      /** value for the universal type class */
71      public static final byte TYPE_CLASS_UNIVERSAL = 0x00;
72  
73      /** tag mask for the short tag format - 0001 1111 - 0x1F */
74      public static final int SHORT_MASK = 0x1F;
75  
76      /** A mask to get the Length form */
77      public static final int LENGTH_LONG_FORM = 0x0080;
78  
79      /** Value of the reserved extension */
80      public static final int LENGTH_EXTENSION_RESERVED = 0x7F;
81  
82      /** A mask to get the long form value */
83      public static final int LENGTH_SHORT_MASK = 0x007F;
84  
85      /** A speedup for single bytes length */
86      private static final byte[][] ONE_BYTE = new byte[128][];
87  
88      // Initialize an array of byte[] used for encoding lengths below 128
89      static
90      {
91          for ( int i = 0; i < 128; i++ )
92          {
93              ONE_BYTE[i] = new byte[1];
94              ONE_BYTE[i][0] = ( byte ) i;
95          }
96      }
97  
98  
99      /**
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     public String toString()
447     {
448 
449         StringBuilder sb = new StringBuilder();
450 
451         sb.append( "TLV[ " );
452         sb.append( Asn1StringUtils.dumpByte( tag ) ).append( ", " );
453         sb.append( length ).append( ", " );
454         sb.append( value.toString() );
455         sb.append( "]" );
456 
457         return sb.toString();
458     }
459 }