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