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 final class Asn1Decoder implements TLVBerDecoderMBean 044{ 045 /** The logger */ 046 private static final Logger LOG = LoggerFactory.getLogger( Asn1Decoder.class ); 047 048 /** This flag is used to indicate that there are more bytes in the stream */ 049 private static final boolean MORE = true; 050 051 /** This flag is used to indicate that there are no more bytes in the stream */ 052 private static final boolean END = false; 053 054 /** Flag that is used to allow/disallow the indefinite form of Length */ 055 private boolean indefiniteLengthAllowed; 056 057 /** The maximum number of bytes that could be used to encode the Length */ 058 private int maxLengthLength; 059 060 /** The maximum number of bytes that could be used to encode the Tag */ 061 private int maxTagLength; 062 063 064 /** 065 * A public constructor of an Asn1 Decoder. 066 */ 067 private Asn1Decoder() 068 { 069 indefiniteLengthAllowed = false; 070 maxLengthLength = 1; 071 maxTagLength = 1; 072 } 073 074 075 /** 076 * Treat the start of a TLV. It reads the tag and get its value. 077 * 078 * @param stream The ByteBuffer containing the PDU to decode 079 * @param container The container that stores the current state, 080 * the result and other informations. 081 * @return <code>true</code> if there are more bytes to read, <code>false 082 * </code> otherwise 083 */ 084 private static boolean treatTagStartState( ByteBuffer stream, Asn1Container container ) 085 { 086 if ( stream.hasRemaining() ) 087 { 088 byte octet = stream.get(); 089 090 TLV tlv = new TLV( container.getNewTlvId() ); 091 tlv.setTag( octet ); 092 093 // Store the current TLV in the container. 094 container.setCurrentTLV( tlv ); 095 096 // Create a link between the current TLV with its parent 097 tlv.setParent( container.getParentTLV() ); 098 099 // 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}