1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.asn1new.ber.tlv;
18
19 import org.apache.asn1.codec.EncoderException;
20 import org.apache.asn1new.primitives.OID;
21 import org.apache.asn1new.primitives.OctetString;
22 import org.apache.asn1new.util.StringUtils;
23
24 import java.io.Serializable;
25 import java.io.UnsupportedEncodingException;
26 import java.nio.BufferOverflowException;
27 import java.nio.ByteBuffer;
28
29 /***
30 * This class stores the data decoded from a TLV.
31 *
32 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
33 */
34 public class Value implements Cloneable, Serializable
35 {
36 public static final long serialVersionUID = 1L;
37
38
39
40 /*** The data buffer.
41 * TODO Create a streamed data to store large data */
42 private byte[] data;
43
44 /*** The current position of the last byte in the data buffer */
45 private int currentPos;
46
47 /*** The encoded byte for a TRUE value */
48 public static final byte TRUE_VALUE = (byte)0xFF;
49
50 /*** The encoded byte for a FALSE value */
51 public static final byte FALSE_VALUE = (byte)0x00;
52
53 /*** Pre-encoded PDUs for a TRUE and FALSE TLV */
54 private static final byte[] ENCODED_TRUE = new byte[] { 0x01, 0x01, TRUE_VALUE};
55 private static final byte[] ENCODED_FALSE = new byte[] { 0x01, 0x01, FALSE_VALUE};
56
57 /*** Integer limits for encoding */
58 private static final int ONE_BYTE_MAX = ( 1 << 7 ) - 1;
59 private static final int ONE_BYTE_MIN = -(1<<7);
60 private static final int TWO_BYTE_MAX = ( 1 << 15 ) - 1;
61 private static final int TWO_BYTE_MIN = -(1<<15);
62 private static final int THREE_BYTE_MAX = ( 1 << 23 ) - 1;
63 private static final int THREE_BYTE_MIN = -(1<<23);
64 private static final int FOUR_BYTE_MAX = ( 1 << 31 ) - 1;
65 private static final int FOUR_BYTE_MIN = Integer.MIN_VALUE;
66
67
68
69 /***
70 * The constructor.
71 */
72 public Value( byte[] value )
73 {
74 data = value;
75 currentPos = 0;
76 }
77
78 /***
79 * The constructor.
80 */
81 public Value()
82 {
83 data = null;
84 currentPos = 0;
85 }
86
87 /***
88 * Initialize the Value
89 *
90 * @param size The data size to allocate.
91 */
92 public void init( int size )
93 {
94 data = new byte[size];
95 currentPos = 0;
96 }
97
98 /***
99 * Reset the Value so that it can be reused
100 */
101 public void reset()
102 {
103 data = null;
104 currentPos = 0;
105 }
106
107 /***
108 * Clone the Value
109 *
110 * @return An object that is a copy of this Value
111 *
112 * @throws CloneNotSupportedException Thrown when the cloning failed
113 */
114 public Object clone() throws CloneNotSupportedException
115 {
116
117 return super.clone();
118 }
119
120 /***
121 * Get the Values'data
122 *
123 * @return Returns the data.
124 */
125 public byte[] getData()
126 {
127 return data;
128 }
129
130 /***
131 * Set a block of bytes in the Value
132 *
133 * @param data The data to set.
134 */
135 public void setData( ByteBuffer data )
136 {
137 int length = data.remaining();
138 data.get( this.data, 0, length );
139 currentPos = length;
140 }
141
142 /***
143 * Append some bytes to the data buffer.
144 *
145 * @param data The data to append.
146 */
147 public void addData( ByteBuffer data )
148 {
149 int length = data.remaining();
150 data.get( this.data, currentPos, length );
151 currentPos += length;
152 }
153
154 /***
155 * Set a block of bytes in the Value
156 *
157 * @param data The data to set.
158 */
159 public void setData( byte[] data )
160 {
161 System.arraycopy( data, 0, this.data, 0, data.length );
162 currentPos = data.length;
163 }
164
165 /***
166 * Append some bytes to the data buffer.
167 *
168 * @param data The data to append.
169 */
170 public void addData( byte[] data )
171 {
172 System.arraycopy( data, 0, this.data, currentPos, data.length );
173 currentPos = data.length;
174 }
175
176 /***
177 * @return The number of bytes actually stored
178 */
179 public int getCurrentLength()
180 {
181 return currentPos;
182 }
183
184 /***
185 * Utility function that return the number of bytes necessary to store
186 * an integer value. Note that this value must be in [Integer.MIN_VALUE, Integer.MAX_VALUE].
187 *
188 * @param value The value to store in a byte array
189 * @param sign The integer value sign
190 * @return The number of bytes necessary to store the value.
191 */
192 public static int getNbBytes( int value )
193 {
194 if ( value >= ONE_BYTE_MIN && value <= ONE_BYTE_MAX )
195 {
196 return 1;
197 }
198 else if ( value >= TWO_BYTE_MIN && value <= TWO_BYTE_MAX )
199 {
200 return 2;
201 }
202 else if ( value >= THREE_BYTE_MIN && value <= THREE_BYTE_MAX )
203 {
204 return 3;
205 }
206 else if ( value >= FOUR_BYTE_MIN && value <= FOUR_BYTE_MAX )
207 {
208 return 4;
209 }
210 else
211 {
212 return 5;
213 }
214 }
215
216 /***
217 * Utility function that return a byte array representing the Value
218 * We must respect the ASN.1 BER encoding scheme :
219 * 1) positive integer
220 * - [0 - 0x7F] : 0xVV
221 * - [0x80 - 0xFF] : 0x00 0xVV
222 * - [0x0100 - 0x7FFF] : 0xVV 0xVV
223 * - [0x8000 - 0xFFFF] : 0x00 0xVV 0xVV
224 * - [0x010000 - 0x7FFFFF] : 0xVV 0xVV 0xVV
225 * - [0x800000 - 0xFFFFFF] : 0x00 0xVV 0xVV 0xVV
226 * - [0x01000000 - 0x7FFFFFFF] : 0xVV 0xVV 0xVV 0xVV
227 * - [0x80000000 - 0xFFFFFFFF] : 0x00 0xVV 0xVV 0xVV 0xVV
228 * 2) Negative number
229 * - (~value) + 1
230 *
231 * @param value The value to store in a byte array
232 * @param sign The value sign : positive or negative
233 * @return The byte array representing the value.
234 */
235 public static byte[] getBytes( int value )
236 {
237 byte[] bytes = null;
238
239 if ( value >= ONE_BYTE_MIN && value <= ONE_BYTE_MAX )
240 {
241 bytes = new byte[1];
242 bytes[0] = ( byte ) value;
243 }
244 else if ( value >= TWO_BYTE_MIN && value <= TWO_BYTE_MAX )
245 {
246 bytes = new byte[2];
247 bytes[1] = ( byte ) value;
248 bytes[0] = ( byte ) ( value >> 8 );
249 }
250 else if ( value >= THREE_BYTE_MIN && value <= THREE_BYTE_MAX )
251 {
252 bytes = new byte[3];
253 bytes[2] = ( byte ) value;
254 bytes[1] = ( byte ) ( value >> 8 );
255 bytes[0] = ( byte ) ( value >> 16 );
256 }
257 else if ( value >= FOUR_BYTE_MIN && value <= FOUR_BYTE_MAX )
258 {
259 bytes = new byte[4];
260 bytes[3] = ( byte ) value;
261 bytes[2] = ( byte ) ( value >> 8 );
262 bytes[1] = ( byte ) ( value >> 16 );
263 bytes[0] = ( byte ) ( value >> 24 );
264 }
265
266 return bytes;
267 }
268
269 /***
270 * Encode a String value
271 *
272 * @param buffer The PDU in which the value will be put
273 * @param string The String to be encoded. It is supposed to be UTF-8
274 */
275 public static void encode( ByteBuffer buffer, String string ) throws EncoderException
276 {
277 if ( buffer == null )
278 {
279 throw new EncoderException( "Cannot put a PDU in a null buffer !" );
280 }
281
282 try
283 {
284 buffer.put( UniversalTag.OCTET_STRING_TAG );
285
286 byte[] value = null;
287
288 try
289 {
290 value = string.getBytes("UTF-8");
291 }
292 catch (UnsupportedEncodingException uee)
293 {
294 throw new EncoderException("The Value encoding is not UTF-8");
295 }
296
297 buffer.put( Length.getBytes( value.length ) );
298
299 if ( value.length != 0 )
300 {
301 buffer.put( value );
302 }
303 }
304 catch ( BufferOverflowException boe )
305 {
306 throw new EncoderException("The PDU buffer size is too small !");
307 }
308
309 return;
310 }
311
312 /***
313 * Encode an OctetString value
314 *
315 * @param buffer The PDU in which the value will be put
316 * @param string The OctetString to be encoded
317 */
318 public static void encode( ByteBuffer buffer, OctetString string ) throws EncoderException
319 {
320 if ( buffer == null )
321 {
322 throw new EncoderException( "Cannot put a PDU in a null buffer !" );
323 }
324
325 try
326 {
327 buffer.put( UniversalTag.OCTET_STRING_TAG );
328 buffer.put( Length.getBytes( string.getNbBytes() ) );
329
330 if ( string.getNbBytes() != 0 )
331 {
332 buffer.put( string.getValue() );
333 }
334 }
335 catch ( BufferOverflowException boe )
336 {
337 throw new EncoderException("The PDU buffer size is too small !");
338 }
339
340 return;
341 }
342
343 /***
344 * Encode an OctetString value
345 *
346 * @param buffer The PDU in which the value will be put
347 * @param byte[] The bytes to be encoded
348 */
349 public static void encode( ByteBuffer buffer, byte[] bytes ) throws EncoderException
350 {
351 if ( buffer == null )
352 {
353 throw new EncoderException( "Cannot put a PDU in a null buffer !" );
354 }
355
356 try
357 {
358 buffer.put( UniversalTag.OCTET_STRING_TAG );
359
360 if ( ( bytes == null ) || ( bytes.length == 0 ) )
361 {
362 buffer.put( (byte) 0 );
363 }
364 else
365 {
366 buffer.put( Length.getBytes( bytes.length ) );
367 buffer.put( bytes );
368 }
369 }
370 catch ( BufferOverflowException boe )
371 {
372 throw new EncoderException("The PDU buffer size is too small !");
373 }
374
375 return;
376 }
377
378 /***
379 * Encode an OID value
380 *
381 * @param buffer The PDU in which the value will be put
382 * @param string The OID to be encoded
383 */
384 public static void encode( ByteBuffer buffer, OID oid ) throws EncoderException
385 {
386 if ( buffer == null )
387 {
388 throw new EncoderException( "Cannot put a PDU in a null buffer !" );
389 }
390
391 try
392 {
393 buffer.put( UniversalTag.OCTET_STRING_TAG );
394 buffer.put( Length.getBytes( oid.getOIDLength() ) );
395
396 if ( oid.getOIDLength() != 0 )
397 {
398 buffer.put( oid.getOID() );
399 }
400 }
401 catch ( BufferOverflowException boe )
402 {
403 throw new EncoderException("The PDU buffer size is too small !");
404 }
405
406 return;
407 }
408
409 /***
410 * Encode an integer value
411 *
412 * @param buffer The PDU in which the value will be put
413 * @param value The integer to be encoded
414 */
415 public static void encode( ByteBuffer buffer, int value ) throws EncoderException
416 {
417 if ( buffer == null )
418 {
419 throw new EncoderException( "Cannot put a PDU in a null buffer !" );
420 }
421
422 try
423 {
424 buffer.put( UniversalTag.INTEGER_TAG );
425 buffer.put( Length.getBytes( getNbBytes( value ) ) );
426 buffer.put( getBytes( value ) );
427 }
428 catch ( BufferOverflowException boe )
429 {
430 throw new EncoderException("The PDU buffer size is too small !");
431 }
432
433 return;
434 }
435
436 /***
437 * Encode an enumerated value
438 *
439 * @param buffer The PDU in which the value will be put
440 * @param value The integer to be encoded
441 */
442 public static void encodeEnumerated( ByteBuffer buffer, int value ) throws EncoderException
443 {
444 if ( buffer == null )
445 {
446 throw new EncoderException( "Cannot put a PDU in a null buffer !" );
447 }
448
449 try
450 {
451 buffer.put( UniversalTag.ENUMERATED_TAG );
452 buffer.put( Length.getBytes( getNbBytes( value ) ) );
453 buffer.put( getBytes( value ) );
454 }
455 catch ( BufferOverflowException boe )
456 {
457 throw new EncoderException("The PDU buffer size is too small !");
458 }
459
460 return;
461 }
462
463 /***
464 * Encode a boolean value
465 *
466 * @param buffer The PDU in which the value will be put
467 * @param bool The boolean to be encoded
468 */
469 public static void encode( ByteBuffer buffer, boolean bool ) throws EncoderException
470 {
471 if ( buffer == null )
472 {
473 throw new EncoderException( "Cannot put a PDU in a null buffer !" );
474 }
475
476 try
477 {
478 buffer.put( bool ? ENCODED_TRUE : ENCODED_FALSE ) ;
479 }
480 catch ( BufferOverflowException boe )
481 {
482 throw new EncoderException("The PDU buffer size is too small !");
483 }
484
485 return;
486 }
487
488 /***
489 * Return a string representing the Value
490 *
491 * @return A string representing the value
492 */
493 public String toString()
494 {
495
496 StringBuffer sb = new StringBuffer();
497 sb.append( "DATA" );
498
499 if ( data != null )
500 {
501 sb.append( '[' );
502 sb.append( StringUtils.dumpBytes( data ) );
503 sb.append( ']' );
504 }
505 else
506 {
507
508 return "[]";
509 }
510
511 return sb.toString();
512 }
513 }