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