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