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;
021
022
023 import java.nio.ByteBuffer;
024
025 import org.apache.directory.shared.asn1.ber.grammar.IStates;
026 import org.apache.directory.shared.asn1.ber.tlv.ITLVBerDecoderMBean;
027 import org.apache.directory.shared.asn1.ber.tlv.TLV;
028 import org.apache.directory.shared.asn1.ber.tlv.TLVStateEnum;
029 import org.apache.directory.shared.asn1.ber.tlv.Value;
030 import org.apache.directory.shared.asn1.codec.DecoderException;
031 import org.apache.directory.shared.asn1.util.Asn1StringUtils;
032 import org.slf4j.Logger;
033 import org.slf4j.LoggerFactory;
034
035
036 /**
037 * A BER TLV Tag component decoder. This decoder instanciate a Tag. The tag
038 * won't be implementations should not copy the handle to the Tag object
039 * delivered but should copy the data if they need it over the long term.
040 *
041 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
042 * @version $Rev: 725712 $, $Date: 2008-12-11 16:32:04 +0100 (Jeu, 11 déc 2008) $
043 */
044 public class Asn1Decoder implements ITLVBerDecoderMBean
045 {
046 // ~ Static fields/initializers
047 // -----------------------------------------------------------------
048
049 /** The logger */
050 private static final Logger LOG = LoggerFactory.getLogger( Asn1Decoder.class );
051
052 /** A speedup for logger */
053 private static final boolean IS_DEBUG = LOG.isDebugEnabled();
054
055 /** This flag is used to indicate that there are more bytes in the stream */
056 private static final boolean MORE = true;
057
058 /** This flag is used to indicate that there are no more bytes in the stream */
059 private static final boolean END = false;
060
061 // ~ Instance fields
062 // ----------------------------------------------------------------------------
063
064 /** Flag that is used to allow/disallow the indefinite form of Length */
065 private boolean indefiniteLengthAllowed;
066
067 /** The maximum number of bytes that could be used to encode the Length */
068 private int maxLengthLength;
069
070 /** The maximum number of bytes that could be used to encode the Tag */
071 private int maxTagLength;
072
073
074 // ~ Constructors
075 // -------------------------------------------------------------------------------
076
077 /**
078 * A public constructor of an Asn1 Decoder.
079 */
080 public Asn1Decoder()
081 {
082 indefiniteLengthAllowed = false;
083 maxLengthLength = 1;
084 maxTagLength = 1;
085 }
086
087
088 // ~ Methods
089 // ------------------------------------------------------------------------------------
090
091 /**
092 * Treat the start of a TLV. It reads the tag and get its value.
093 *
094 * @param stream The ByteBuffer containing the PDU to decode
095 * @param container The container that stores the current state,
096 * the result and other informations.
097 * @return <code>true</code> if there are more bytes to read, <code>false
098 * </code> otherwise
099 */
100 private boolean treatTagStartState( ByteBuffer stream, IAsn1Container container )
101 {
102
103 if ( stream.hasRemaining() )
104 {
105
106 byte octet = stream.get();
107
108 TLV tlv = new TLV( container.getNewTlvId() );
109 tlv.setTag( octet );
110
111 // Store the current TLV in the container.
112 container.setCurrentTLV( tlv );
113
114 // Create a link between the current TLV with its parent
115 tlv.setParent( container.getParentTLV() );
116
117 // Switch to the next state, which is the Length decoding
118 container.setState( TLVStateEnum.LENGTH_STATE_START );
119
120 if ( IS_DEBUG )
121 {
122 byte tag = container.getCurrentTLV().getTag();
123 LOG.debug( "Tag {} has been decoded", Asn1StringUtils.dumpByte( tag ) );
124 }
125
126 return MORE;
127 }
128 else
129 {
130
131 // The stream has been exhausted
132 return END;
133 }
134 }
135
136 /**
137 * Dump the current TLV tree
138 *
139 * @param container The container
140 */
141 private void dumpTLVTree( IAsn1Container container )
142 {
143 StringBuffer sb = new StringBuffer();
144 TLV current = container.getCurrentTLV();
145
146 sb.append( "TLV" ).append( Asn1StringUtils.dumpByte( current.getTag() ) ).append( "(" )
147 .append( current.getExpectedLength() ).append( ")" );
148
149 current = current.getParent();
150
151 while ( current != null )
152 {
153 sb.append( "-TLV" ).append( Asn1StringUtils.dumpByte( current.getTag() ) ).append( "(" )
154 .append( current.getExpectedLength() ).append( ")" );
155 current = current.getParent();
156 }
157
158 if ( IS_DEBUG )
159 {
160 LOG.debug( "TLV Tree : {}", sb.toString() );
161 }
162 }
163
164
165 /**
166 * Check if the TLV tree is fully decoded
167 *
168 * @param container The container
169 * @return <code>true</code> if the TLV has been decoded
170 */
171 private boolean isTLVDecoded( IAsn1Container container )
172 {
173 TLV current = container.getCurrentTLV();
174
175 TLV parent = current.getParent();
176
177 while ( parent != null )
178 {
179 if ( parent.getExpectedLength() != 0 )
180 {
181 return false;
182 }
183
184 parent = parent.getParent();
185 }
186
187 Value value = current.getValue();
188
189 if ( ( value != null ) && ( value.getData() != null ) )
190 {
191 return ( current.getExpectedLength() == value.getData().length );
192 }
193 else
194 {
195 return current.getExpectedLength() == 0;
196 }
197 }
198
199 /**
200 * Treat the Length start. The tag has been decoded, so we have to deal with
201 * the LENGTH, which can be multi-bytes.
202 *
203 * @param stream The ByteBuffer containing the PDU to decode
204 * @param container The container that stores the current state,
205 * the result and other informations.
206 * @return <code>true</code> if there are more bytes to read, <code>false
207 * </code> otherwise
208 * @throws DecoderException Thrown if anything went wrong
209 */
210 private boolean treatLengthStartState( ByteBuffer stream, IAsn1Container container ) throws DecoderException
211 {
212
213 if ( stream.hasRemaining() )
214 {
215 byte octet = stream.get();
216 TLV tlv = container.getCurrentTLV();
217
218 if ( ( octet & TLV.LENGTH_LONG_FORM ) == 0 )
219 {
220
221 // We don't have a long form. The Length of the Value part is
222 // given by this byte.
223 tlv.setLength( octet );
224 tlv.setLengthNbBytes( 1 );
225
226 container.setState( TLVStateEnum.LENGTH_STATE_END );
227 }
228 else if ( ( octet & TLV.LENGTH_EXTENSION_RESERVED ) != TLV.LENGTH_EXTENSION_RESERVED )
229 {
230
231 int expectedLength = octet & TLV.LENGTH_SHORT_MASK;
232
233 if ( expectedLength > 4 )
234 {
235 LOG.error( "Overflow : can't have more than 4 bytes long length" );
236 throw new DecoderException( "Overflow : can't have more than 4 bytes long length" );
237 }
238
239 tlv.setLength( 0 );
240 tlv.setLengthNbBytes( 1 + expectedLength );
241 tlv.setLengthBytesRead( 1 );
242 container.setState( TLVStateEnum.LENGTH_STATE_PENDING );
243 }
244 else
245 {
246 LOG.error( "Length reserved extension used" );
247 throw new DecoderException( "Length reserved extension used" );
248 }
249
250 return MORE;
251 }
252 else
253 {
254 return END;
255 }
256 }
257
258
259 /**
260 * This function is called when a Length is in the process of being decoded,
261 * but the lack of bytes in the buffer stopped the process.
262 *
263 * @param stream The ByteBuffer containing the PDU to decode
264 * @param container The container that stores the current state,
265 * the result and other informations.
266 * @return <code>true</code> if there are more bytes to read, <code>false
267 * </code> otherwise
268 */
269 private boolean treatLengthPendingState( ByteBuffer stream, IAsn1Container container )
270 {
271
272 if ( stream.hasRemaining() )
273 {
274
275 TLV tlv = container.getCurrentTLV();
276 int length = tlv.getLength();
277
278 while ( tlv.getLengthBytesRead() < tlv.getLengthNbBytes() )
279 {
280
281 byte octet = stream.get();
282
283 if ( IS_DEBUG )
284 {
285 LOG.debug( " current byte : {}", Asn1StringUtils.dumpByte( octet ) );
286 }
287
288 tlv.incLengthBytesRead();
289 length = ( length << 8 ) | ( octet & 0x00FF );
290
291 if ( !stream.hasRemaining() )
292 {
293 tlv.setLength( length );
294
295 if ( tlv.getLengthBytesRead() < tlv.getLengthNbBytes() )
296 {
297 container.setState( TLVStateEnum.LENGTH_STATE_PENDING );
298 return END;
299 }
300 else
301 {
302 container.setState( TLVStateEnum.LENGTH_STATE_END );
303 return MORE;
304 }
305 }
306 }
307
308 tlv.setLength( length );
309 container.setState( TLVStateEnum.LENGTH_STATE_END );
310
311 return MORE;
312 }
313 else
314 {
315
316 return END;
317 }
318 }
319
320
321 /**
322 * A debug function used to dump the expected length stack.
323 *
324 * @param tlv The current TLV.
325 * @return A string which represent the expected length stack.
326 */
327 private String getParentLength( TLV tlv )
328 {
329 StringBuffer buffer = new StringBuffer();
330
331 buffer.append( "TLV expected length stack : " );
332
333 while ( true )
334 {
335 if ( tlv == null )
336 {
337 buffer.append( " - null" );
338 break;
339 }
340 else
341 {
342 buffer.append( " - " ).append( tlv.getExpectedLength() );
343 }
344
345 tlv = tlv.getParent();
346 }
347
348 return buffer.toString();
349 }
350
351
352 /**
353 * The Length is fully decoded. We have to call an action to check the size.
354 *
355 * @param container The container that stores the current state,
356 * the result and other informations.
357 * @throws DecoderException Thrown if anything went wrong
358 */
359 private void treatLengthEndState( IAsn1Container container ) throws DecoderException
360 {
361 TLV tlv = container.getCurrentTLV();
362
363 if ( tlv == null )
364 {
365 LOG.error( "The current container TLV is null." );
366 throw new DecoderException( "Current TLV is null" );
367 }
368
369 int length = tlv.getLength();
370
371 // We will check the length here. What we must control is
372 // that the enclosing constructed TLV expected length is not
373 // exceeded by the current TLV.
374 TLV parentTLV = container.getParentTLV();
375
376 if ( IS_DEBUG )
377 {
378 LOG.debug( "Parent length : {}", getParentLength( parentTLV ) );
379 }
380
381 if ( parentTLV == null )
382 {
383 // This is the first TLV, so we can't check anything. We will
384 // just store this TLV as the root of the PDU
385 tlv.setExpectedLength( length );
386 container.setParentTLV( tlv );
387
388 if ( IS_DEBUG )
389 {
390 LOG.debug( "Root TLV[{}]", Integer.valueOf( length ) );
391 }
392 }
393 else
394 {
395 // We have a parent, so we will check that its expected length is
396 // not exceeded.
397 int expectedLength = parentTLV.getExpectedLength();
398 int currentLength = tlv.getSize();
399
400 if ( expectedLength < currentLength )
401 {
402 // The expected length is lower than the Value length of the
403 // current TLV. This is an error...
404 LOG.error( "tlv[{}, {}]", Integer.valueOf( expectedLength ), Integer.valueOf( currentLength ) );
405 throw new DecoderException( "The current Value length is above the expected length" );
406 }
407
408 // deal with the particular case where expected length equal
409 // the current length, which means that the parentTLV has been
410 // completed.
411 if ( expectedLength == currentLength )
412 {
413 parentTLV.setExpectedLength( 0 );
414
415 // We also have to check that the current TLV is a constructed
416 // one.
417 // In this case, we have to switch from this parent TLV
418 // to the parent's parent TLV.
419 if ( tlv.isConstructed() )
420 {
421 // here, we also have another special case : a
422 // zero length TLV. We must then unstack all
423 // the parents which length is null.
424 if ( length == 0 )
425 {
426 // We will set the parent to the first parentTLV which
427 // expectedLength
428 // is not null, and it will become the new parent TLV
429 while ( parentTLV != null )
430 {
431 if ( parentTLV.getExpectedLength() != 0 )
432 {
433 // ok, we have an incomplete parent. we will
434 // stop the recursion right here
435 break;
436 }
437 else
438 {
439 parentTLV = parentTLV.getParent();
440 }
441 }
442
443 container.setParentTLV( parentTLV );
444 }
445 else
446 {
447 // The new Parent TLV is this Constructed TLV
448 container.setParentTLV( tlv );
449 }
450
451 tlv.setParent( parentTLV );
452 tlv.setExpectedLength( length );
453 }
454 else
455 {
456 tlv.setExpectedLength( length );
457
458 // It's over, the parent TLV has been completed.
459 // Go back to the parent's parent TLV until we find
460 // a tlv which is not complete.
461 while ( parentTLV != null )
462 {
463 if ( parentTLV.getExpectedLength() != 0 )
464 {
465 // ok, we have an incomplete parent. we will
466 // stop the recursion right here
467 break;
468 }
469 else
470 {
471 parentTLV = parentTLV.getParent();
472 }
473 }
474
475 container.setParentTLV( parentTLV );
476 }
477 }
478 else
479 {
480 // Renew the expected Length.
481 parentTLV.setExpectedLength( expectedLength - currentLength );
482 tlv.setExpectedLength( length );
483
484 if ( tlv.isConstructed() )
485 {
486 // We have a constructed tag, so we must switch the
487 // parentTLV
488 tlv.setParent( parentTLV );
489 container.setParentTLV( tlv );
490 }
491 }
492
493 }
494
495 if ( IS_DEBUG )
496 {
497 LOG.debug( "Length {} has been decoded", Integer.valueOf( length ) );
498 }
499
500 if ( length == 0 )
501 {
502 // The length is 0, so we can't expect a value.
503 container.setState( TLVStateEnum.TLV_STATE_DONE );
504 }
505 else
506 {
507 // Go ahead and decode the value part
508 container.setState( TLVStateEnum.VALUE_STATE_START );
509 }
510 }
511
512
513 /**
514 * Treat the Value part. We will distinguish two cases : - if the Tag is a
515 * Primitive one, we will get the value. - if the Tag is a Constructed one,
516 * nothing will be done.
517 *
518 * @param stream The ByteBuffer containing the PDU to decode
519 * @param container The container that stores the current state,
520 * the result and other informations.
521 * @return <code>true</code> if there are more bytes to read, <code>false
522 * </code> otherwise
523 */
524 private boolean treatValueStartState( ByteBuffer stream, IAsn1Container container )
525 {
526
527 TLV currentTlv = container.getCurrentTLV();
528
529 if ( TLV.isConstructed( currentTlv.getTag() ) )
530 {
531 container.setState( TLVStateEnum.TLV_STATE_DONE );
532
533 return MORE;
534 }
535 else
536 {
537
538 int length = currentTlv.getLength();
539 int nbBytes = stream.remaining();
540
541 if ( nbBytes < length )
542 {
543 currentTlv.getValue().init( length );
544 currentTlv.getValue().setData( stream );
545 container.setState( TLVStateEnum.VALUE_STATE_PENDING );
546
547 return END;
548 }
549 else
550 {
551 currentTlv.getValue().init( length );
552 stream.get( currentTlv.getValue().getData(), 0, length );
553 container.setState( TLVStateEnum.TLV_STATE_DONE );
554
555 return MORE;
556 }
557 }
558 }
559
560
561 /**
562 * Treat a pending Value when we get more bytes in the buffer.
563 *
564 * @param stream The ByteBuffer containing the PDU to decode
565 * @param container The container that stores the current state,
566 * the result and other informations.
567 * @return <code>MORE</code> if some bytes remain in the buffer when the
568 * value has been decoded, <code>END</code> if whe still need to get some
569 * more bytes.
570 */
571 private boolean treatValuePendingState( ByteBuffer stream, IAsn1Container container )
572 {
573
574 TLV currentTlv = container.getCurrentTLV();
575
576 int length = currentTlv.getLength();
577 int currentLength = currentTlv.getValue().getCurrentLength();
578 int nbBytes = stream.remaining();
579
580 if ( ( currentLength + nbBytes ) < length )
581 {
582 currentTlv.getValue().addData( stream );
583 container.setState( TLVStateEnum.VALUE_STATE_PENDING );
584
585 return END;
586 }
587 else
588 {
589
590 int remaining = length - currentLength;
591 byte[] data = new byte[remaining];
592 stream.get( data, 0, remaining );
593 currentTlv.getValue().addData( data );
594 container.setState( TLVStateEnum.TLV_STATE_DONE );
595
596 return MORE;
597 }
598 }
599
600
601 /**
602 * When the TLV has been fully decoded, we have to execute the associated
603 * action and switch to the next TLV, which will start with a Tag.
604 *
605 * @param stream The ByteBuffer containing the PDU to decode
606 * @param container The container that stores the current state,
607 * the result and other informations.
608 * @return <code>true</code> if there are more bytes to read, <code>false
609 * </code> otherwise
610 * @throws DecoderException Thrown if anything went wrong
611 */
612 private boolean treatTLVDoneState( ByteBuffer stream, IAsn1Container container ) throws DecoderException
613 {
614 if ( IS_DEBUG )
615 {
616 dumpTLVTree( container );
617 }
618
619 // First, we have to execute the associated action
620 container.getGrammar().executeAction( container );
621
622 // Check if the PDU has been fully decoded.
623 if ( isTLVDecoded( container ) )
624 {
625 if ( container.getState() == IStates.GRAMMAR_END )
626 {
627 // Change the state to DECODED
628 container.setState( TLVStateEnum.PDU_DECODED );
629 }
630 else
631 {
632 if ( container.isGrammarEndAllowed() )
633 {
634 // Change the state to DECODED
635 container.setState( TLVStateEnum.PDU_DECODED );
636 }
637 else
638 {
639 LOG.error( "The PDU is decoded, but we should have had more TLVs" );
640 throw new DecoderException( "Truncated PDU. Some elements are lacking, accordingly to the grammar" );
641 }
642 }
643
644 }
645 else
646 {
647 // Then we switch to the Start tag state and free the current TLV
648 container.setState( TLVStateEnum.TAG_STATE_START );
649 }
650
651 return stream.hasRemaining();
652 }
653
654
655 /**
656 * An helper function that return a string representing the current state
657 * for debuging purpose.
658 *
659 * @param state The state
660 * @return A string representation of the state
661 */
662 private String stateToString( int state )
663 {
664
665 switch ( state )
666 {
667
668 case TLVStateEnum.TAG_STATE_START:
669 return "TAG_STATE_START";
670
671 case TLVStateEnum.TAG_STATE_END:
672 return "TAG_STATE_END";
673
674 case TLVStateEnum.TAG_STATE_OVERFLOW:
675 return "TAG_STATE_OVERFLOW";
676
677 case TLVStateEnum.LENGTH_STATE_START:
678 return "LENGTH_STATE_START";
679
680 case TLVStateEnum.LENGTH_STATE_PENDING:
681 return "LENGTH_STATE_PENDING";
682
683 case TLVStateEnum.LENGTH_STATE_END:
684 return "LENGTH_STATE_END";
685
686 case TLVStateEnum.VALUE_STATE_START:
687 return "VALUE_STATE_START";
688
689 case TLVStateEnum.VALUE_STATE_PENDING:
690 return "VALUE_STATE_PENDING";
691
692 case TLVStateEnum.TLV_STATE_DONE:
693 return "TLV_STATE_DONE";
694
695 default:
696 return "UNKNOWN_STATE";
697 }
698 }
699
700
701 /**
702 * The decoder main function. This is where we read bytes from the stream
703 * and go through the automaton. It's an inifnite loop which stop when no
704 * more bytes are to be read. It can occurs if the ByteBuffer is exhausted
705 * or if the PDU has been fully decoded.
706 *
707 * @param stream The ByteBuffer containing the PDU to decode
708 * @param container The container that store the state, the result
709 * and other elements.
710 * @throws DecoderException Thrown if anything went wrong!
711 */
712 public void decode( ByteBuffer stream, IAsn1Container container ) throws DecoderException
713 {
714
715 /*
716 * We have to deal with the current state. This is an infinite loop,
717 * which will stop for any of these reasons :
718 * - STATE_END has been reached (hopefully, the most frequent case)
719 * - buffer is empty (it could happen)
720 * - STATE_OVERFLOW : bad situation ! The PDU may be a
721 * malevolous hand crafted ones, that try to "kill" our decoder. Whe
722 * must log it with all information to track back this case, and punish
723 * the guilty !
724 */
725
726 boolean hasRemaining = stream.hasRemaining();
727
728 // Increment the PDU size counter.
729 container.incrementDecodeBytes( stream.remaining() );
730
731 if ( container.getDecodeBytes() > container.getMaxPDUSize() )
732 {
733 String message = "The PDU current size (" + container.getDecodeBytes() +
734 ") exceeds the maximum allowed PDU size (" + container.getMaxPDUSize() +")";
735 LOG.error( message );
736 throw new DecoderException( message );
737 }
738
739 if ( IS_DEBUG )
740 {
741 LOG.debug( ">>>==========================================" );
742 LOG.debug( "--> Decoding a PDU" );
743 LOG.debug( ">>>------------------------------------------" );
744 }
745
746 while ( hasRemaining )
747 {
748
749 if ( IS_DEBUG )
750 {
751 LOG.debug( "--- State = {} ---", stateToString( container.getState() ) );
752
753 if ( stream.hasRemaining() )
754 {
755 byte octet = stream.get( stream.position() );
756
757 LOG.debug( " current byte : {}", Asn1StringUtils.dumpByte( octet ) );
758 }
759 else
760 {
761 LOG.debug( " no more byte to decode in the stream" );
762 }
763 }
764
765 switch ( container.getState() )
766 {
767
768 case TLVStateEnum.TAG_STATE_START:
769 // Reset the GrammarEnd flag first
770 container.grammarEndAllowed( false );
771 hasRemaining = treatTagStartState( stream, container );
772
773 break;
774
775 case TLVStateEnum.LENGTH_STATE_START:
776 hasRemaining = treatLengthStartState( stream, container );
777
778 break;
779
780 case TLVStateEnum.LENGTH_STATE_PENDING:
781 hasRemaining = treatLengthPendingState( stream, container );
782
783 break;
784
785 case TLVStateEnum.LENGTH_STATE_END:
786 treatLengthEndState( container );
787
788 break;
789
790 case TLVStateEnum.VALUE_STATE_START:
791 hasRemaining = treatValueStartState( stream, container );
792
793 break;
794
795 case TLVStateEnum.VALUE_STATE_PENDING:
796 hasRemaining = treatValuePendingState( stream, container );
797
798 break;
799
800 case TLVStateEnum.VALUE_STATE_END:
801 hasRemaining = stream.hasRemaining();
802
803 // Nothing to do. We will never reach this state
804 break;
805
806 case TLVStateEnum.TLV_STATE_DONE:
807 hasRemaining = treatTLVDoneState( stream, container );
808
809 break;
810
811 case TLVStateEnum.PDU_DECODED:
812 // We have to deal with the case where there are
813 // more bytes in the buffer, but the PDU has been decoded.
814 LOG.warn( "The PDU has been fully decoded but there are still bytes in the buffer." );
815
816 hasRemaining = false;
817
818 break;
819
820 default :
821 break;
822 }
823 }
824
825 if ( IS_DEBUG )
826 {
827 LOG.debug( "<<<------------------------------------------" );
828
829 if ( container.getState() == TLVStateEnum.PDU_DECODED )
830 {
831 if ( container.getCurrentTLV() != null )
832 {
833 LOG.debug( "<-- Stop decoding : {}", container.getCurrentTLV().toString() );
834 }
835 else
836 {
837 LOG.debug( "<-- Stop decoding : null current TLV" );
838 }
839 }
840 else
841 {
842 if ( container.getCurrentTLV() != null )
843 {
844 LOG.debug( "<-- End decoding : {}", container.getCurrentTLV().toString() );
845 }
846 else
847 {
848 LOG.debug( "<-- End decoding : null current TLV" );
849 }
850 }
851
852 LOG.debug( "<<<==========================================" );
853 }
854
855 return;
856 }
857
858
859 /**
860 * Get the length's Length.
861 *
862 * @return Returns the length's Length.
863 */
864 public int getMaxLengthLength()
865 {
866 return maxLengthLength;
867 }
868
869
870 /**
871 * Get the maximum Tag's length
872 *
873 * @return Returns the maximum tag Length.
874 */
875 public int getMaxTagLength()
876 {
877 return maxTagLength;
878 }
879
880
881 /**
882 * Disallow indefinite length.
883 */
884 public void disallowIndefiniteLength()
885 {
886 this.indefiniteLengthAllowed = false;
887 }
888
889
890 /**
891 * Allow indefinite length.
892 */
893 public void allowIndefiniteLength()
894 {
895 this.indefiniteLengthAllowed = true;
896 }
897
898
899 /**
900 * Tells if indefinite length form could be used for Length
901 *
902 * @return Returns <code>true</code> if the current decoder support
903 * indefinite length
904 */
905 public boolean isIndefiniteLengthAllowed()
906 {
907
908 return indefiniteLengthAllowed;
909 }
910
911
912 /**
913 * Set the maximul length for a Length
914 *
915 * @param maxLengthLength The lengthLength to set.
916 * @throws DecoderException Thrown if the indefinite length is
917 * allowed or if the length's Length is above 126 bytes
918 */
919 public void setMaxLengthLength( int maxLengthLength ) throws DecoderException
920 {
921
922 if ( ( this.indefiniteLengthAllowed ) && ( maxLengthLength > 126 ) )
923 {
924 throw new DecoderException( "Length above 126 bytes are not allowed for a definite form Length" );
925 }
926
927 this.maxLengthLength = maxLengthLength;
928 }
929
930
931 /**
932 * Set the maximum Tag length
933 *
934 * @param maxTagLength The tagLength to set.
935 */
936 public void setMaxTagLength( int maxTagLength )
937 {
938 this.maxTagLength = maxTagLength;
939 }
940 }