1 /*
2 * Copyright 2004 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.asn1.ber ;
18
19
20 import java.nio.ByteBuffer;
21 import java.util.List;
22
23 import org.apache.commons.lang.ArrayUtils;
24
25
26 /**
27 * TLV Tuple used by the value chunking decoder. Because the length field is
28 * a primitive int it's maximum value is 2,147,483,647 a single TLV's tuple
29 * cannot have a length over this amount or a value size over 2 GB.
30 *
31 * @author <a href="mailto:dev@directory.apache.org">
32 * Apache Directory Project</a>
33 * @version $Rev: 157644 $
34 */
35 public class Tuple
36 {
37 /** empty buffer reused for handling null */
38 private static final ByteBuffer EMPTY_BUFFER =
39 ByteBuffer.wrap( ArrayUtils.EMPTY_BYTE_ARRAY ) ;
40
41 /** mask for bit 5 with 0-based index */
42 private static final int BIT_5 = 0x20 ;
43 /** mask for bit 6 with 0-based index */
44 private static final int BIT_6 = 0x40 ;
45 /** mask for bit 7 with 0-based index */
46 private static final int BIT_7 = 0x80 ;
47
48 /** precalculated left shift of 1 by 14 places */
49 private static final int BIT_13 = 1 << 14 ;
50 /** precalculated left shift of 1 by 16 places */
51 private static final int BIT_15 = 1 << 16 ;
52 /** precalculated left shift of 1 by 21 places */
53 private static final int BIT_20 = 1 << 21 ;
54 /** precalculated left shift of 1 by 24 places */
55 private static final int BIT_23 = 1 << 24 ;
56 /** precalculated left shift of 1 by 28 places */
57 private static final int BIT_27 = 1 << 28 ;
58
59 /** the raw tag data */
60 int rawTag = 0 ;
61 /** the tag id for this TLV tuple */
62 int id = 0 ;
63 /** the flag for whether or not this TLV is constructed or primitive */
64 boolean isPrimitive = true ;
65 /** the type class for this TLV */
66 TypeClass typeClass = TypeClass.APPLICATION ;
67 /** the length for this TLV tuple's value field */
68 int length = 0 ;
69 /** the present value chunk buffer read for this TLV tuple */
70 ByteBuffer valueChunk = EMPTY_BUFFER ;
71
72 /** tlv byte index */
73 int index = Length.UNDEFINED ;
74 /** tlv value index for how far into the value we have read */
75 int valueIndex = Length.UNDEFINED ;
76
77
78 // ------------------------------------------------------------------------
79 // C O N S T R U C T O R S
80 // ------------------------------------------------------------------------
81
82
83 /**
84 * Empty do nothing tuple.
85 */
86 public Tuple()
87 {
88 }
89
90
91 /**
92 * Creates constructed application type tlv tuples. Constructed TLV's with
93 * a definate length will use this constructor predominantly. The TypeClass
94 * defualts to APPLICATION.
95 *
96 * @param id the tag id of the tlv
97 * @param length the length of the value which is the length of all the
98 * nested tuples.
99 */
100 public Tuple( int id, int length )
101 {
102 this( id, length, TypeClass.APPLICATION ) ;
103 }
104
105
106 /**
107 * Creates constructed application type tlv tuples. Constructed TLV's with
108 * a definate length will use this constructor predominantly.
109 *
110 * @param id the tag id of the tlv
111 * @param length the length of the value which is the length of all the
112 * nested tuples.
113 * @param typeClass the type class of this tlv tuple
114 */
115 public Tuple( int id, int length, TypeClass typeClass )
116 {
117 this.id = id ;
118 this.length = length ;
119 valueChunk = EMPTY_BUFFER ;
120 isPrimitive = false ;
121
122 if ( typeClass != null )
123 {
124 this.typeClass = typeClass ;
125 }
126 }
127
128
129 /**
130 * Creates constructed application type tlv tuples. Constructed TLV's with
131 * a definate length will use this constructor predominantly.
132 *
133 * @param id the tag id of the tlv
134 * @param length the length of the value which is the length of all the
135 * nested tuples.
136 * @param isPrimitive whether or not this Tuple is primitive or constructed
137 * @param typeClass the type class of this tlv tuple
138 */
139 public Tuple( int id, int length, boolean isPrimitive, TypeClass typeClass )
140 {
141 this.id = id ;
142 this.length = length ;
143 valueChunk = EMPTY_BUFFER ;
144 isPrimitive = false ;
145
146 if ( typeClass != null )
147 {
148 this.typeClass = typeClass ;
149 }
150 }
151
152
153 /**
154 * Creates a tuple where the length is indefinite. The tuple according to
155 * the BER encoding must be of the constructed type.
156 *
157 * @param id the tag id of the tlv
158 * @param typeClass the type class for the tlv
159 */
160 public Tuple( int id, TypeClass typeClass )
161 {
162 this.id = id ;
163 this.isPrimitive = false ;
164 valueChunk = EMPTY_BUFFER ;
165 length = Length.INDEFINITE ;
166
167 if ( typeClass != null )
168 {
169 this.typeClass = typeClass ;
170 }
171 }
172
173
174 // ------------------------------------------------------------------------
175 // Public Accessors and Mutators
176 // ------------------------------------------------------------------------
177
178
179 /**
180 * Gets the tag id for this TLV Tuple.
181 *
182 * @return the tag id
183 */
184 public int getId()
185 {
186 return id ;
187 }
188
189
190 /**
191 * Sets the id of this Tuple and as a side effect the rawTag.
192 *
193 * @param id the new tag id to set
194 */
195 public void setId( int id )
196 {
197 this.id = id ;
198 rawTag = Tag.setIntEncodedId( rawTag, id );
199 }
200
201
202 /**
203 * Gets the raw tag as it is stuffed into a primitive int.
204 *
205 * @return a primitive int stuffed with the first four octets of the tag
206 */
207 public int getRawTag()
208 {
209 return rawTag ;
210 }
211
212
213 /**
214 * Sets the raw tag encoded as a primitive int and as a side effect this
215 * call also sets the id, primitive flag, and typeClass of this TLV tuple.
216 *
217 * @param rawTag the raw primitive int encoded tag.
218 */
219 public void setRawTag( int rawTag )
220 {
221 this.rawTag = rawTag;
222 this.id = Tag.getTagId( rawTag );
223 this.isPrimitive = ! Tag.isRawTagConstructed( rawTag );
224 this.typeClass = TypeClass.getTypeClass( rawTag >> 24 );
225 }
226
227
228 /**
229 * Sets the tag parameters using a tag enumeration type. This operation
230 * sets the id, isPrimitive, typeClass, and rawTag fields at the same time.
231 *
232 * @param tag the tag enumeration constant
233 */
234 public void setTag( TagEnum tag )
235 {
236 this.rawTag = tag.getValue();
237 this.id = tag.getTagId();
238 this.isPrimitive = ! Tag.isRawTagConstructed( tag.getValue() ) ;
239 this.typeClass = tag.getTypeClass();
240 }
241
242
243 /**
244 * Sets the tag parameters using a tag enumeration type explicitly setting
245 * the primitive/constructed bit. This operation sets the id, isPrimitive,
246 * typeClass, and rawTag fields at the same time.
247 *
248 * @param tag the tag enumeration constant
249 * @param isPrimitive primitive/constructed bit override
250 */
251 public void setTag( TagEnum tag, boolean isPrimitive )
252 {
253 this.rawTag = tag.getValue();
254 this.id = tag.getTagId();
255 this.isPrimitive = isPrimitive;
256 this.typeClass = tag.getTypeClass();
257 }
258
259
260 /**
261 * Gets the raw tag with the primitive/constructed flag dubbed out.
262 * Effectively this makes every tag appear primitive and is done
263 * to remove encoding ambiguities that could interfere with pattern
264 * matching.
265 *
266 * @return the raw tag with the primitive/constructed flag dubbed out
267 */
268 public int getRawPrimitiveTag()
269 {
270 return rawTag & 0xDFFFFFFF ;
271 }
272
273
274 /**
275 * Get's whether or not this tuples's length is indefinite.
276 *
277 * @return whether or not this tuple's length is indefinite
278 */
279 public boolean isIndefinite()
280 {
281 return length == Length.INDEFINITE ;
282 }
283
284
285 /**
286 * Get's whether or not this tuple terminates an indefinite constructed
287 * tuple. This means that length == 0 && isPrimitive = true && id == 0
288 * and the type class is universal.
289 *
290 * @return whether or not this node's length is indefinite
291 */
292 public boolean isIndefiniteTerminator()
293 {
294 return isPrimitive && id == 0 && length <= 0 &&
295 typeClass.equals( TypeClass.UNIVERSAL ) ;
296 }
297
298
299 /**
300 * Gets whether or not this TLV tuple is primitive or constructed.
301 *
302 * @return true if it is primitive, false if it is constructed
303 */
304 public boolean isPrimitive()
305 {
306 return isPrimitive ;
307 }
308
309
310 /**
311 * Gets the value length for this TLV Tuple.
312 *
313 * @return the length in bytes of the value field for this TLV tuple
314 */
315 public int getLength()
316 {
317 return length ;
318 }
319
320
321
322 public void setLength( int length )
323 {
324 this.length = length;
325 }
326
327
328 /**
329 * Gets the BER TLV TypeClass for this TLV Tuple.
330 *
331 * @return the BER TLV TypeClass for this TLV Tuple
332 */
333 public TypeClass getTypeClass()
334 {
335 return typeClass ;
336 }
337
338
339 /**
340 * Gets the last chunk read for the value field (V-part) for this TLV Tuple.
341 *
342 * @return the last valueChunk field for this TLV Tuple
343 */
344 public ByteBuffer getLastValueChunk()
345 {
346 return valueChunk ;
347 }
348
349
350 /**
351 * Sets the value representing the last chunk read or the last chunch to
352 * write.
353 *
354 * @param buf the last chunk as a buffer
355 */
356 public void setLastValueChunk( ByteBuffer buf )
357 {
358 this.valueChunk = buf;
359 }
360
361
362 /**
363 * Gets the total size of this TLV tuple in bytes. This includes the
364 * length of the tag field, the length of the length field and the length
365 * of the value feild.
366 *
367 * @return the total TLV size in bytes
368 */
369 public int size()
370 {
371 if ( this.length == Length.INDEFINITE )
372 {
373 return getTagLength() + getLengthLength() ;
374 }
375 else
376 {
377 return getTagLength() + getLengthLength() + length ;
378 }
379 }
380
381
382 // ------------------------------------------------------------------------
383 // Utility methods and java.lang.Object overrides
384 // ------------------------------------------------------------------------
385
386
387 /**
388 * Clears the values of this tuple.
389 */
390 public void clear()
391 {
392 this.id = 0 ;
393 this.index = 0 ;
394 this.rawTag = 0 ;
395 this.isPrimitive = true ;
396 this.length = Length.UNDEFINED ;
397 this.typeClass = TypeClass.APPLICATION ;
398 this.valueChunk = EMPTY_BUFFER ;
399 this.valueIndex = Length.UNDEFINED ;
400 }
401
402
403 /**
404 * Does not take into account the value, index or the valueIndex values when
405 * checking for equality. Technically if both are being constructed by
406 * the decoder then they should only be equal when these values are equal
407 * because the tag, length or value would not be correct. Plus since this
408 * is a chunking tuple the valueChunk means nothing with respect to the
409 * final value.
410 *
411 * @see java.lang.Object#equals(java.lang.Object)
412 */
413 public boolean equals( Object o )
414 {
415 if ( o == this )
416 {
417 return true ;
418 }
419
420 if ( o instanceof Tuple )
421 {
422 Tuple t = ( Tuple ) o ;
423
424 if ( t.id != id )
425 {
426 return false ;
427 }
428
429 if ( t.isPrimitive != isPrimitive )
430 {
431 return false ;
432 }
433
434 if ( t.length != length )
435 {
436 return false ;
437 }
438
439 if ( t.typeClass != typeClass )
440 {
441 return false ;
442 }
443
444 return true ;
445 }
446
447 return false ;
448 }
449
450
451 /*
452 * (non-Javadoc)
453 * @see java.lang.Object#clone()
454 */
455 public Object clone()
456 {
457 Tuple t = new Tuple() ;
458 t.id = id ;
459 t.rawTag = rawTag ;
460 t.isPrimitive = isPrimitive ;
461 t.typeClass = typeClass ;
462 t.length = length ;
463
464 /* ------------------------------------------------------------------ +/
465 * @todo figure out if we should remove this section
466 *
467 * Do think we need this anymore since the last valueChunk does not
468 * factor into the result returned by the equals(Object) method?
469 * ------------------------------------------------------------------ */
470 ByteBuffer bb = valueChunk ;
471 ByteBuffer cloned = ByteBuffer.allocate( bb.capacity() ) ;
472 int oldPos = bb.position() ;
473 bb.rewind() ;
474 cloned.put( bb ) ;
475 cloned.limit( bb.limit() ) ;
476 bb.position( oldPos ) ;
477 cloned.rewind() ;
478 t.valueChunk = cloned ;
479 /* ------------------------------------------------------------------ */
480
481 t.index = index ;
482 t.valueIndex = valueIndex ;
483
484 return t ;
485 }
486
487
488 // ------------------------------------------------------------------------
489 // Tuple encoding operations
490 // ------------------------------------------------------------------------
491
492
493 /**
494 * If this is a primitive TLV then the valueBytes argument is used to
495 * produce an encoded image of this TLV. If it is constructed then
496 * only the TL part of the tuple is encoded leaving the value to be encoded
497 * by the set of child TLVs.
498 *
499 * @todo this should produce chunking output and needs to be removed from
500 * here actually and made into a standalone encoder. You give it a buffer
501 * and it fills it as much as it can remembering where the encode stopped.
502 * Hence it is stateful as expected from the statemachine.
503 *
504 * @return partial encoded image if constructed or complete TLV if primitive
505 */
506 public ByteBuffer toEncodedBuffer( List valueChunks )
507 {
508 ByteBuffer octets = null ;
509 int tagLength = getTagLength() ;
510 int lengthLength = getLengthLength() ;
511 int total = tagLength + lengthLength ;
512
513 if ( isPrimitive )
514 {
515 total += length ;
516 }
517
518 octets = ByteBuffer.allocate( total ) ;
519 setTag( octets, tagLength ) ;
520 setLength( octets, lengthLength ) ;
521
522 if ( isPrimitive )
523 {
524 for ( int ii = 0; ii < valueChunks.size(); ii++ )
525 {
526 octets.put( ( ByteBuffer ) valueChunks.get(ii) ) ;
527 }
528 }
529
530 return ( ByteBuffer ) octets.flip() ;
531 }
532
533
534 /**
535 * Sets the tag section within the buffer.
536 *
537 * @param octets the buffer to set the tag in
538 * @param tagLength the length of the tag section
539 */
540 public void setTag( ByteBuffer octets, int tagLength )
541 {
542 if ( tagLength >= 6 )
543 {
544 throw new IllegalArgumentException( "cannot support id's as large "
545 + "as " + id + " unless we start using longs for the id" ) ;
546 }
547
548 byte octet = ( byte ) typeClass.getValue() ;
549 int i = octets.position();
550
551 if ( ! isPrimitive )
552 {
553 octet |= BIT_5;
554 }
555
556 if ( id < 31 )
557 {
558 octets.put( ( byte ) ( octet | (id & Tag.SHORT_MASK ) ) ) ;
559 return;
560
561 }
562 else
563 {
564 octets.put( ( byte ) ( octet | Tag.SHORT_MASK ) ) ;
565 i++;
566 }
567
568 switch ( tagLength - 1) {
569 case 5 :
570 octets.put( ( byte ) ( ( ( id >> 21 ) & Tag.LONG_MASK ) | BIT_7 ) ) ;
571 i++;
572 // fallthrough
573
574 case 4:
575 octets.put( ( byte ) ( ( ( id >> 21 ) & Tag.LONG_MASK ) | BIT_7 ) ) ;
576 i++;
577 // fallthrough
578
579 case 3 :
580 octets.put( ( byte ) ( ( ( id >> 14 ) & Tag.LONG_MASK ) | BIT_7 ) ) ;
581 i++;
582 // fallthrough
583
584 case 2 :
585 octets.put( ( byte ) ( ( ( id >> 7 ) & Tag.LONG_MASK ) | BIT_7 ) ) ;
586 i++;
587 // fallthrough
588
589 case 1 :
590 octets.put( ( byte ) ( id & Tag.LONG_MASK ) ) ;
591 break;
592 }
593
594 //octets.f
595 return ;
596 }
597
598
599 /**
600 * Sets the value length of this Tuple.
601 *
602 * @param length the length of this tuple's value.
603 * @see Tuple#size() to get the entire determinate length of tuple
604 */
605 public void setValueLength( int length )
606 {
607 this.length = length;
608 }
609
610
611 /**
612 * Sets the length bytes.
613 *
614 * @param octets the byte [] to set length in
615 * @param lengthBytes the number bytes for the length section
616 */
617 public void setLength( ByteBuffer octets, int lengthBytes )
618 {
619 if ( lengthBytes >= 6 )
620 {
621 throw new IllegalArgumentException( "cannot support lengths larger "
622 + "than a max integer using " + lengthBytes
623 + " bytes unless we start using longs or BigIntegers for "
624 + "the length" ) ;
625 }
626
627 if ( length == Length.INDEFINITE )
628 {
629 octets.put( ( byte ) BIT_7 ) ;
630 return ;
631 }
632 else if ( lengthBytes == 1 )
633 {
634 octets.put( ( byte ) length ) ;
635 return ;
636 }
637 else
638 {
639 /*
640 * Here we basically set the first byte of the length field which
641 * is in the long form. In this case the first byte's 7 least
642 * significant bits hold the length of the length field or the
643 * number of bytes used to hold the size of the value. BTW the
644 * first most significant bit is set to 1 to mark the long form and
645 * hence why we bitwise or it with 0x80 which is BIT_7.
646 */
647
648 /*
649 * the lengthBytes argument is the number of octets for the L field
650 * total which for the long form includes the first octet for the
651 * length of length (N) value where N < 127. Technically with the
652 * 7 bits we can specify an N of up to 127 but this value of N is
653 * reserved. Anyway below we subtract one from lengthBytes to get
654 * N which is set as the last 7 bits of the first octet of the L
655 * field.
656 */
657 octets.put( ( byte ) ( BIT_7 | ( lengthBytes - 1 ) ) ) ;
658 }
659
660
661 // using the long form so we calculate the length from all octets
662 for ( int ii = 0, shift = (lengthBytes-2)<<3; ii <= lengthBytes-2; ii++, shift -= 8 )
663 {
664 octets.put( octets.position() + ii, ( byte ) ( ( ( 0xff << shift ) & length ) >> shift ) );
665 }
666
667 octets.position( octets.position() + lengthBytes - 1 );
668
669 // if ( lengthBytes >= 2 )
670 // {
671 // octets.put( ( byte ) ( 0xff & length ) ) ;
672 // }
673 // else
674 // {
675 // return ;
676 // }
677 //
678 // if ( lengthBytes >= 3 )
679 // {
680 // octets.put( ( byte ) ( ( 0xff00 & length ) >> 8 ) ) ;
681 // }
682 // else
683 // {
684 // return ;
685 // }
686 //
687 // if ( lengthBytes >= 4 )
688 // {
689 // octets.put( ( byte ) ( ( 0xff0000 & length ) >> 16 ) ) ;
690 // }
691 // else
692 // {
693 // return ;
694 // }
695 //
696 // if ( lengthBytes >= 5 )
697 // {
698 // octets.put( ( byte ) ( ( 0xff000000 & length ) >> 24 ) ) ;
699 // }
700 // else
701 // {
702 // return ;
703 // }
704
705 }
706
707
708 /**
709 * Gets the length in bytes of the tag section for this TLV tuple.
710 *
711 * @return the length in bytes of the tag section for this TLV tuple
712 */
713 public int getTagLength()
714 {
715 if ( id < 31 )
716 {
717 return 1 ;
718 }
719 else if ( id < BIT_6 )
720 {
721 return 2 ;
722 }
723
724 else if ( id < BIT_13 )
725 {
726 return 3 ;
727 }
728 else if ( id < BIT_20 )
729 {
730 return 4 ;
731 }
732 else if ( id < BIT_27 )
733 {
734 return 5 ;
735 }
736
737 throw new IllegalArgumentException( "cannot support id's larger than "
738 + id + " unless we start using longs for the id" ) ;
739 }
740
741
742 /**
743 * Gets the length in bytes of the length section of this TLV Tuple.
744 *
745 * @return the length in bytes of the length section
746 */
747 public int getLengthLength()
748 {
749 if ( length == Length.INDEFINITE )
750 {
751 return 1 ;
752 }
753
754 if ( length < 0 )
755 {
756 throw new IllegalArgumentException( "integer overflow makes id "
757 + "negative with a value of " + id
758 + " - unless we start using longs for"
759 + " the id there you've hit a limitation" ) ;
760 }
761 else if ( length < BIT_7 )
762 {
763 return 1 ;
764 }
765 else if ( length < 256 )
766 {
767 return 2 ;
768 }
769 else if ( length < BIT_15 )
770 {
771 return 3 ;
772 }
773 else if ( length < BIT_23 )
774 {
775 return 4 ;
776 }
777 else
778 {
779 return 5 ;
780 }
781 }
782 }