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}