View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    * 
10   *    https://www.apache.org/licenses/LICENSE-2.0
11   * 
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   * 
19   */
20  package org.apache.directory.api.asn1.ber;
21  
22  
23  import java.nio.ByteBuffer;
24  
25  import org.apache.directory.api.asn1.DecoderException;
26  import org.apache.directory.api.asn1.ber.tlv.BerValue;
27  import org.apache.directory.api.asn1.ber.tlv.TLV;
28  import org.apache.directory.api.asn1.ber.tlv.TLVBerDecoderMBean;
29  import org.apache.directory.api.asn1.ber.tlv.TLVStateEnum;
30  import org.apache.directory.api.asn1.util.Asn1StringUtils;
31  import org.apache.directory.api.i18n.I18n;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  
36  /**
37   * A BER TLV Tag component decoder. This decoder instantiate a Tag. The tag
38   * won't be implementations should not copy the handle to the Tag object
39   * delivered but should copy the data if they need it over the long term.
40   * 
41   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
42  */
43  public final class Asn1Decoder implements TLVBerDecoderMBean
44  {
45      /** The logger */
46      private static final Logger LOG = LoggerFactory.getLogger( Asn1Decoder.class );
47  
48      /** This flag is used to indicate that there are more bytes in the stream */
49      private static final boolean MORE = true;
50  
51      /** This flag is used to indicate that there are no more bytes in the stream */
52      private static final boolean END = false;
53  
54      /** Flag that is used to allow/disallow the indefinite form of Length */
55      private boolean indefiniteLengthAllowed;
56  
57      /** The maximum number of bytes that could be used to encode the Length */
58      private int maxLengthLength;
59  
60      /** The maximum number of bytes that could be used to encode the Tag */
61      private int maxTagLength;
62  
63  
64      /**
65       * A public constructor of an Asn1 Decoder.
66       */
67      private Asn1Decoder()
68      {
69          indefiniteLengthAllowed = false;
70          maxLengthLength = 1;
71          maxTagLength = 1;
72      }
73  
74  
75      /**
76       * Treat the start of a TLV. It reads the tag and get its value.
77       * 
78       * @param stream The ByteBuffer containing the PDU to decode
79       * @param container The container that stores the current state,
80       * the result and other informations.
81       * @return <code>true</code> if there are more bytes to read, <code>false
82       * </code> otherwise
83       */
84      private static  boolean treatTagStartState( ByteBuffer stream, Asn1Container container )
85      {
86          if ( stream.hasRemaining() )
87          {
88              byte octet = stream.get();
89  
90              TLV tlv = new TLV( container.getNewTlvId() );
91              tlv.setTag( octet );
92  
93              // Store the current TLV in the container.
94              container.setCurrentTLV( tlv );
95  
96              // Create a link between the current TLV with its parent
97              tlv.setParent( container.getParentTLV() );
98  
99              // Switch to the next state, which is the Length decoding
100             container.setState( TLVStateEnum.LENGTH_STATE_START );
101 
102             if ( LOG.isDebugEnabled() )
103             {
104                 byte tag = container.getCurrentTLV().getTag();
105                 LOG.debug( I18n.msg( I18n.MSG_01000_TAG_DECODED, Asn1StringUtils.dumpByte( tag ) ) );
106             }
107 
108             return MORE;
109         }
110         else
111         {
112             // The stream has been exhausted
113             return END;
114         }
115     }
116 
117 
118     /**
119      * Dump the current TLV tree
120      * 
121      * @param container The container
122      */
123     private static void dumpTLVTree( Asn1Container container )
124     {
125         StringBuilder sb = new StringBuilder();
126         TLV current = container.getCurrentTLV();
127 
128         sb.append( "TLV" ).append( Asn1StringUtils.dumpByte( current.getTag() ) ).append( "(" ).append(
129             current.getExpectedLength() ).append( ")" );
130 
131         current = current.getParent();
132 
133         while ( current != null )
134         {
135             sb.append( "-TLV" ).append( Asn1StringUtils.dumpByte( current.getTag() ) ).append( "(" ).append(
136                 current.getExpectedLength() ).append( ")" );
137             current = current.getParent();
138         }
139 
140         if ( LOG.isDebugEnabled() )
141         {
142             LOG.debug( I18n.msg( I18n.MSG_01001_TLV_TREE, sb.toString() ) );
143         }
144     }
145 
146 
147     /**
148      * Check if the TLV tree is fully decoded
149      * 
150      * @param container The container
151      * @return <code>true</code> if the TLV has been decoded
152      */
153     private static boolean isTLVDecoded( Asn1Container container )
154     {
155         TLV current = container.getCurrentTLV();
156         TLV parent = current.getParent();
157 
158         while ( parent != null )
159         {
160             if ( parent.getExpectedLength() != 0 )
161             {
162                 return false;
163             }
164 
165             parent = parent.getParent();
166         }
167 
168         BerValue value = current.getValue();
169 
170         if ( ( value != null ) && ( value.getData() != null ) )
171         {
172             return current.getExpectedLength() == value.getData().length;
173         }
174         else
175         {
176             return current.getExpectedLength() == 0;
177         }
178     }
179 
180 
181     /**
182      * Treat the Length start. The tag has been decoded, so we have to deal with
183      * the LENGTH, which can be multi-bytes.
184      * 
185      * @param stream  The ByteBuffer containing the PDU to decode
186      * @param container The container that stores the current state,
187      * the result and other informations.
188      * @return <code>true</code> if there are more bytes to read, <code>false
189      * </code> otherwise
190      * @throws DecoderException Thrown if anything went wrong
191      */
192     private static boolean treatLengthStartState( ByteBuffer stream, Asn1Container container ) throws DecoderException
193     {
194         if ( stream.hasRemaining() )
195         {
196             byte octet = stream.get();
197             TLV tlv = container.getCurrentTLV();
198 
199             if ( ( octet & TLV.LENGTH_LONG_FORM ) == 0 )
200             {
201                 // We don't have a long form. The Length of the Value part is
202                 // given by this byte.
203                 tlv.setLength( octet );
204                 tlv.setLengthNbBytes( 1 );
205 
206                 container.setState( TLVStateEnum.LENGTH_STATE_END );
207             }
208             else if ( ( octet & TLV.LENGTH_EXTENSION_RESERVED ) != TLV.LENGTH_EXTENSION_RESERVED )
209             {
210                 int expectedLength = octet & TLV.LENGTH_SHORT_MASK;
211 
212                 if ( expectedLength > 4 )
213                 {
214                     String msg = I18n.err( I18n.ERR_01000_LENGTH_OVERFLOW );
215                     LOG.error( msg );
216                     throw new DecoderException( msg );
217                 }
218 
219                 tlv.setLength( 0 );
220                 tlv.setLengthNbBytes( 1 + expectedLength );
221                 tlv.setLengthBytesRead( 1 );
222                 container.setState( TLVStateEnum.LENGTH_STATE_PENDING );
223             }
224             else
225             {
226                 String msg = I18n.err( I18n.ERR_01001_LENGTH_EXTENSION_RESERVED );
227                 LOG.error( msg );
228                 throw new DecoderException( msg );
229             }
230 
231             return MORE;
232         }
233         else
234         {
235             return END;
236         }
237     }
238 
239 
240     /**
241      * This function is called when a Length is in the process of being decoded,
242      * but the lack of bytes in the buffer stopped the process.
243      * 
244      * @param stream The ByteBuffer containing the PDU to decode
245      * @param container The container that stores the current state,
246      * the result and other informations.
247      * @return <code>true</code> if there are more bytes to read, <code>false
248      * </code> otherwise
249      */
250     private static boolean treatLengthPendingState( ByteBuffer stream, Asn1Container container )
251     {
252         if ( stream.hasRemaining() )
253         {
254             TLV tlv = container.getCurrentTLV();
255             int length = tlv.getLength();
256 
257             while ( tlv.getLengthBytesRead() < tlv.getLengthNbBytes() )
258             {
259                 byte octet = stream.get();
260 
261                 if ( LOG.isDebugEnabled() )
262                 {
263                     LOG.debug( I18n.msg( I18n.MSG_01002_CURRENT_BYTE, Asn1StringUtils.dumpByte( octet ) ) );
264                 }
265 
266                 tlv.incLengthBytesRead();
267                 length = ( length << 8 ) | ( octet & 0x00FF );
268 
269                 if ( !stream.hasRemaining() )
270                 {
271                     tlv.setLength( length );
272 
273                     if ( tlv.getLengthBytesRead() < tlv.getLengthNbBytes() )
274                     {
275                         container.setState( TLVStateEnum.LENGTH_STATE_PENDING );
276                         return END;
277                     }
278                     else
279                     {
280                         container.setState( TLVStateEnum.LENGTH_STATE_END );
281                         return MORE;
282                     }
283                 }
284             }
285 
286             tlv.setLength( length );
287             container.setState( TLVStateEnum.LENGTH_STATE_END );
288 
289             return MORE;
290         }
291         else
292         {
293 
294             return END;
295         }
296     }
297 
298 
299     /**
300      * A debug function used to dump the expected length stack.
301      * 
302      * @param tlv The current TLV.
303      * @return A string which represent the expected length stack.
304      */
305     private static String getParentLength( TLV tlv )
306     {
307         StringBuilder buffer = new StringBuilder();
308 
309         buffer.append( "TLV expected length stack : " );
310         TLV currentTlv = tlv;
311 
312         while ( true )
313         {
314             if ( currentTlv == null )
315             {
316                 buffer.append( " - null" );
317                 break;
318             }
319             else
320             {
321                 buffer.append( " - " ).append( currentTlv.getExpectedLength() );
322             }
323 
324             currentTlv = currentTlv.getParent();
325         }
326 
327         return buffer.toString();
328     }
329 
330 
331     /**
332      * The Length is fully decoded. We have to call an action to check the size.
333      * 
334      * @param container The container that stores the current state,
335      * the result and other informations.
336      * @throws DecoderException Thrown if anything went wrong
337      */
338     private static void treatLengthEndState( Asn1Container container ) throws DecoderException
339     {
340         TLV tlv = container.getCurrentTLV();
341 
342         if ( tlv == null )
343         {
344             String msg = I18n.err( I18n.ERR_01002_TLV_NULL );
345             LOG.error( msg );
346             throw new DecoderException( msg );
347         }
348 
349         int length = tlv.getLength();
350 
351         // We will check the length here. What we must control is
352         // that the enclosing constructed TLV expected length is not
353         // exceeded by the current TLV.
354         TLV parentTLV = container.getParentTLV();
355 
356         if ( LOG.isDebugEnabled() )
357         {
358             LOG.debug( I18n.msg( I18n.MSG_01003_PARENT_LENGTH, getParentLength( parentTLV ) ) );
359         }
360 
361         if ( parentTLV == null )
362         {
363             // This is the first TLV, so we can't check anything. We will
364             // just store this TLV as the root of the PDU
365             tlv.setExpectedLength( length );
366             container.setParentTLV( tlv );
367 
368             if ( LOG.isDebugEnabled() )
369             {
370                 LOG.debug( I18n.msg( I18n.MSG_01004_ROOT_TLV, Integer.valueOf( length ) ) );
371             }
372         }
373         else
374         {
375             // We have a parent, so we will check that its expected length is
376             // not exceeded.
377             int expectedLength = parentTLV.getExpectedLength();
378             int currentLength = tlv.getSize();
379 
380             if ( expectedLength < currentLength )
381             {
382                 // The expected length is lower than the Value length of the
383                 // current TLV. This is an error...
384                 if ( LOG.isDebugEnabled() )
385                 {
386                     LOG.debug( I18n.msg( I18n.MSG_01005_TLV, 
387                                 Integer.valueOf( expectedLength ), 
388                                 Integer.valueOf( currentLength ) ) );
389                 }
390                 
391                 throw new DecoderException( I18n.err( I18n.ERR_01003_VALUE_LENGTH_ABOVE_EXPECTED_LENGTH, Integer
392                     .valueOf( currentLength ), Integer.valueOf( expectedLength ) ) );
393             }
394 
395             // deal with the particular case where expected length equal
396             // the current length, which means that the parentTLV has been
397             // completed.
398             if ( expectedLength == currentLength )
399             {
400                 parentTLV.setExpectedLength( 0 );
401 
402                 // We also have to check that the current TLV is a constructed
403                 // one.
404                 // In this case, we have to switch from this parent TLV
405                 // to the parent's parent TLV.
406                 if ( tlv.isConstructed() )
407                 {
408                     // here, we also have another special case : a
409                     // zero length TLV. We must then unstack all
410                     // the parents which length is null.
411                     if ( length == 0 )
412                     {
413                         // We will set the parent to the first parentTLV which
414                         // expectedLength
415                         // is not null, and it will become the new parent TLV
416                         while ( parentTLV != null )
417                         {
418                             if ( parentTLV.getExpectedLength() != 0 )
419                             {
420                                 // ok, we have an incomplete parent. we will
421                                 // stop the recursion right here
422                                 break;
423                             }
424                             else
425                             {
426                                 parentTLV = parentTLV.getParent();
427                             }
428                         }
429 
430                         container.setParentTLV( parentTLV );
431                     }
432                     else
433                     {
434                         // The new Parent TLV is this Constructed TLV
435                         container.setParentTLV( tlv );
436                     }
437 
438                     tlv.setParent( parentTLV );
439                     tlv.setExpectedLength( length );
440                 }
441                 else
442                 {
443                     tlv.setExpectedLength( length );
444 
445                     // It's over, the parent TLV has been completed.
446                     // Go back to the parent's parent TLV until we find
447                     // a tlv which is not complete.
448                     while ( parentTLV != null )
449                     {
450                         if ( parentTLV.getExpectedLength() != 0 )
451                         {
452                             // ok, we have an incomplete parent. we will
453                             // stop the recursion right here
454                             break;
455                         }
456                         else
457                         {
458                             parentTLV = parentTLV.getParent();
459                         }
460                     }
461 
462                     container.setParentTLV( parentTLV );
463                 }
464             }
465             else
466             {
467                 // Renew the expected Length.
468                 parentTLV.setExpectedLength( expectedLength - currentLength );
469                 tlv.setExpectedLength( length );
470 
471                 if ( tlv.isConstructed() )
472                 {
473                     // We have a constructed tag, so we must switch the
474                     // parentTLV
475                     tlv.setParent( parentTLV );
476                     container.setParentTLV( tlv );
477                 }
478             }
479 
480         }
481 
482         if ( LOG.isDebugEnabled() )
483         {
484             LOG.debug( I18n.msg( I18n.MSG_01006_LENGTH_DECODED, Integer.valueOf( length ) ) );
485         }
486 
487         if ( length == 0 )
488         {
489             // The length is 0, so we can't expect a value.
490             container.setState( TLVStateEnum.TLV_STATE_DONE );
491         }
492         else
493         {
494             // Go ahead and decode the value part
495             container.setState( TLVStateEnum.VALUE_STATE_START );
496         }
497     }
498 
499 
500     /**
501      * Treat the Value part. We will distinguish two cases : - if the Tag is a
502      * Primitive one, we will get the value. - if the Tag is a Constructed one,
503      * nothing will be done.
504      * 
505      * @param stream The ByteBuffer containing the PDU to decode
506      * @param container The container that stores the current state,
507      * the result and other informations.
508      * @return <code>true</code> if there are more bytes to read, <code>false
509      * </code> otherwise
510      */
511     private static  boolean treatValueStartState( ByteBuffer stream, Asn1Container container )
512     {
513         TLV currentTlv = container.getCurrentTLV();
514 
515         if ( TLV.isConstructed( currentTlv.getTag() ) && !container.isGathering() )
516         {
517             container.setState( TLVStateEnum.TLV_STATE_DONE );
518 
519             return MORE;
520         }
521         else
522         {
523             int length = currentTlv.getLength();
524             int nbBytes = stream.remaining();
525 
526             if ( nbBytes < length )
527             {
528                 currentTlv.getValue().init( length );
529                 currentTlv.getValue().setData( stream );
530                 container.setState( TLVStateEnum.VALUE_STATE_PENDING );
531 
532                 return END;
533             }
534             else
535             {
536                 currentTlv.getValue().init( length );
537                 stream.get( currentTlv.getValue().getData(), 0, length );
538                 container.setState( TLVStateEnum.TLV_STATE_DONE );
539 
540                 return MORE;
541             }
542         }
543     }
544 
545 
546     /**
547      * Treat a pending Value when we get more bytes in the buffer.
548      * 
549      * @param stream The ByteBuffer containing the PDU to decode
550      * @param container The container that stores the current state,
551      * the result and other informations.
552      * @return <code>MORE</code> if some bytes remain in the buffer when the
553      * value has been decoded, <code>END</code> if whe still need to get some
554      * more bytes.
555      */
556     private static boolean treatValuePendingState( ByteBuffer stream, Asn1Container container )
557     {
558         TLV currentTlv = container.getCurrentTLV();
559 
560         int length = currentTlv.getLength();
561         int currentLength = currentTlv.getValue().getCurrentLength();
562         int nbBytes = stream.remaining();
563 
564         if ( ( currentLength + nbBytes ) < length )
565         {
566             currentTlv.getValue().addData( stream );
567             container.setState( TLVStateEnum.VALUE_STATE_PENDING );
568 
569             return END;
570         }
571         else
572         {
573             int remaining = length - currentLength;
574             byte[] data = new byte[remaining];
575             stream.get( data, 0, remaining );
576             currentTlv.getValue().addData( data );
577             container.setState( TLVStateEnum.TLV_STATE_DONE );
578 
579             return MORE;
580         }
581     }
582 
583 
584     /**
585      * When the TLV has been fully decoded, we have to execute the associated
586      * action and switch to the next TLV, which will start with a Tag.
587      * 
588      * @param stream The ByteBuffer containing the PDU to decode
589      * @param container The container that stores the current state,
590      * the result and other informations.
591      * @return <code>true</code> if there are more bytes to read, <code>false
592      * </code> otherwise
593      * @throws DecoderException Thrown if anything went wrong
594      */
595     @SuppressWarnings("unchecked")
596     private static boolean treatTLVDoneState( ByteBuffer stream, Asn1Container container ) throws DecoderException
597     {
598         if ( LOG.isDebugEnabled() )
599         {
600             dumpTLVTree( container );
601         }
602 
603         // First, we have to execute the associated action
604         container.getGrammar().executeAction( container );
605 
606         // Check if the PDU has been fully decoded.
607         if ( isTLVDecoded( container ) )
608         {
609             if ( container.getState() == TLVStateEnum.GRAMMAR_END )
610             {
611                 // Change the state to DECODED
612                 container.setState( TLVStateEnum.PDU_DECODED );
613             }
614             else
615             {
616                 if ( container.isGrammarEndAllowed() )
617                 {
618                     // Change the state to DECODED
619                     container.setState( TLVStateEnum.PDU_DECODED );
620                 }
621                 else
622                 {
623                     LOG.error( I18n.err( I18n.ERR_01004_MORE_TLV_EXPECTED ) );
624                     throw new DecoderException( I18n.err( I18n.ERR_01005_TRUNCATED_PDU ) );
625                 }
626             }
627         }
628         else
629         {
630             // Then we switch to the Start tag state and free the current TLV
631             container.setState( TLVStateEnum.TAG_STATE_START );
632         }
633 
634         return stream.hasRemaining();
635     }
636 
637 
638     /**
639      * The decoder main function. This is where we read bytes from the stream
640      * and go through the automaton. It's an inifnite loop which stop when no
641      * more bytes are to be read. It can occurs if the ByteBuffer is exhausted
642      * or if the PDU has been fully decoded.
643      * 
644      * @param stream The ByteBuffer containing the PDU to decode
645      * @param container The container that store the state, the result
646      * and other elements.
647      * @throws DecoderException Thrown if anything went wrong!
648      */
649     public static void decode( ByteBuffer stream, Asn1Container container ) throws DecoderException
650     {
651         /*
652          * We have to deal with the current state. This is an infinite loop,
653          * which will stop for any of these reasons :
654          * - STATE_END has been reached (hopefully, the most frequent case)
655          * - buffer is empty (it could happen)
656          * - STATE_OVERFLOW : bad situation ! The PDU may be a
657          * malevolous hand crafted ones, that try to "kill" our decoder. We
658          * must log it with all information to track back this case, and punish
659          * the guilty !
660          */
661         boolean hasRemaining = stream.hasRemaining();
662 
663         // Increment the PDU size counter.
664         container.incrementDecodedBytes( stream.remaining() );
665 
666         if ( container.getDecodedBytes() > container.getMaxPDUSize() )
667         {
668             String message = I18n.err( I18n.ERR_01007_PDU_SIZE_TOO_LONG, container.getDecodedBytes(), container
669                 .getMaxPDUSize() );
670             LOG.error( message );
671             throw new DecoderException( message );
672         }
673 
674         if ( LOG.isDebugEnabled() )
675         {
676             LOG.debug( I18n.msg( I18n.MSG_01007_LINE_SEPARATOR1 ) );
677             LOG.debug( I18n.msg( I18n.MSG_01011_DECODING_PDU ) );
678             LOG.debug( I18n.msg( I18n.MSG_01008_LINE_SEPARATOR2 ) );
679         }
680 
681         while ( hasRemaining )
682         {
683             if ( LOG.isDebugEnabled() )
684             {
685                 LOG.debug( I18n.msg( I18n.MSG_01012_STATE, container.getState() ) );
686 
687                 if ( stream.hasRemaining() )
688                 {
689                     byte octet = stream.get( stream.position() );
690 
691                     LOG.debug( I18n.msg( I18n.MSG_01013_CURRENT_BYTE, Asn1StringUtils.dumpByte( octet ) ) );
692                 }
693                 else
694                 {
695                     LOG.debug( I18n.msg( I18n.MSG_01014_NO_MORE_BYTE ) );
696                 }
697             }
698 
699             switch ( container.getState() )
700             {
701                 case TAG_STATE_START:
702                     // Reset the GrammarEnd flag first
703                     container.setGrammarEndAllowed( false );
704                     hasRemaining = treatTagStartState( stream, container );
705 
706                     break;
707 
708                 case LENGTH_STATE_START:
709                     hasRemaining = treatLengthStartState( stream, container );
710 
711                     break;
712 
713                 case LENGTH_STATE_PENDING:
714                     hasRemaining = treatLengthPendingState( stream, container );
715 
716                     break;
717 
718                 case LENGTH_STATE_END:
719                     treatLengthEndState( container );
720 
721                     break;
722 
723                 case VALUE_STATE_START:
724                     hasRemaining = treatValueStartState( stream, container );
725 
726                     break;
727 
728                 case VALUE_STATE_PENDING:
729                     hasRemaining = treatValuePendingState( stream, container );
730 
731                     break;
732 
733                 case VALUE_STATE_END:
734                     hasRemaining = stream.hasRemaining();
735 
736                     // Nothing to do. We will never reach this state
737                     break;
738 
739                 case TLV_STATE_DONE:
740                     hasRemaining = treatTLVDoneState( stream, container );
741 
742                     break;
743 
744                 case PDU_DECODED:
745                     // We have to deal with the case where there are
746                     // more bytes in the buffer, but the PDU has been decoded.
747                     if ( LOG.isDebugEnabled() )
748                     {
749                         LOG.debug( I18n.err( I18n.ERR_01008_REMAINING_BYTES_FOR_DECODED_PDU ) );
750                     }
751 
752                     hasRemaining = false;
753 
754                     break;
755 
756                 default:
757                     break;
758             }
759         }
760 
761         if ( LOG.isDebugEnabled() )
762         {
763             LOG.debug( I18n.msg( I18n.MSG_01009_LINE_SEPARATOR3 ) );
764 
765             if ( container.getState() == TLVStateEnum.PDU_DECODED )
766             {
767                 if ( container.getCurrentTLV() != null )
768                 {
769                     LOG.debug( I18n.msg( I18n.MSG_01015_STOP_DECODING, container.getCurrentTLV().toString() ) );
770                 }
771                 else
772                 {
773                     LOG.debug( I18n.msg( I18n.MSG_01016_STOP_DECODING_NULL_TLV ) );
774                 }
775             }
776             else
777             {
778                 if ( container.getCurrentTLV() != null )
779                 {
780                     LOG.debug( I18n.msg( I18n.MSG_01017_END_DECODING, container.getCurrentTLV().toString() ) );
781                 }
782                 else
783                 {
784                     LOG.debug( I18n.msg( I18n.MSG_01018_END_DECODING_NULL_TLV ) );
785                 }
786             }
787 
788             LOG.debug( I18n.msg( I18n.MSG_01010_LINE_SEPARATOR4 ) );
789         }
790     }
791 
792 
793     /**
794      * {@inheritDoc}
795      */
796     @Override
797     public int getMaxLengthLength()
798     {
799         return maxLengthLength;
800     }
801 
802 
803     /**
804      * {@inheritDoc}
805      */
806     @Override
807     public int getMaxTagLength()
808     {
809         return maxTagLength;
810     }
811 
812 
813     /**
814      * {@inheritDoc}
815      */
816     @Override
817     public boolean isIndefiniteLengthAllowed()
818     {
819 
820         return indefiniteLengthAllowed;
821     }
822 }