| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| package org.apache.directory.api.asn1.ber; |
| |
| |
| import java.nio.ByteBuffer; |
| |
| import org.apache.directory.api.asn1.DecoderException; |
| import org.apache.directory.api.asn1.ber.tlv.BerValue; |
| import org.apache.directory.api.asn1.ber.tlv.TLV; |
| import org.apache.directory.api.asn1.ber.tlv.TLVBerDecoderMBean; |
| import org.apache.directory.api.asn1.ber.tlv.TLVStateEnum; |
| import org.apache.directory.api.asn1.util.Asn1StringUtils; |
| import org.apache.directory.api.i18n.I18n; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| |
| /** |
| * A BER TLV Tag component decoder. This decoder instantiate a Tag. The tag |
| * won't be implementations should not copy the handle to the Tag object |
| * delivered but should copy the data if they need it over the long term. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| public class Asn1Decoder implements TLVBerDecoderMBean |
| { |
| /** The logger */ |
| private static final Logger LOG = LoggerFactory.getLogger( Asn1Decoder.class ); |
| |
| /** A speedup for logger */ |
| private static final boolean IS_DEBUG = LOG.isDebugEnabled(); |
| |
| /** This flag is used to indicate that there are more bytes in the stream */ |
| private static final boolean MORE = true; |
| |
| /** This flag is used to indicate that there are no more bytes in the stream */ |
| private static final boolean END = false; |
| |
| /** Flag that is used to allow/disallow the indefinite form of Length */ |
| private boolean indefiniteLengthAllowed; |
| |
| /** The maximum number of bytes that could be used to encode the Length */ |
| private int maxLengthLength; |
| |
| /** The maximum number of bytes that could be used to encode the Tag */ |
| private int maxTagLength; |
| |
| |
| /** |
| * A public constructor of an Asn1 Decoder. |
| */ |
| public Asn1Decoder() |
| { |
| indefiniteLengthAllowed = false; |
| maxLengthLength = 1; |
| maxTagLength = 1; |
| } |
| |
| |
| /** |
| * Treat the start of a TLV. It reads the tag and get its value. |
| * |
| * @param stream The ByteBuffer containing the PDU to decode |
| * @param container The container that stores the current state, |
| * the result and other informations. |
| * @return <code>true</code> if there are more bytes to read, <code>false |
| * </code> otherwise |
| */ |
| private boolean treatTagStartState( ByteBuffer stream, Asn1Container container ) |
| { |
| if ( stream.hasRemaining() ) |
| { |
| byte octet = stream.get(); |
| |
| TLV tlv = new TLV( container.getNewTlvId() ); |
| tlv.setTag( octet ); |
| |
| // Store the current TLV in the container. |
| container.setCurrentTLV( tlv ); |
| |
| // Create a link between the current TLV with its parent |
| tlv.setParent( container.getParentTLV() ); |
| |
| // Switch to the next state, which is the Length decoding |
| container.setState( TLVStateEnum.LENGTH_STATE_START ); |
| |
| if ( IS_DEBUG ) |
| { |
| byte tag = container.getCurrentTLV().getTag(); |
| LOG.debug( "Tag {} has been decoded", Asn1StringUtils.dumpByte( tag ) ); |
| } |
| |
| return MORE; |
| } |
| else |
| { |
| // The stream has been exhausted |
| return END; |
| } |
| } |
| |
| |
| /** |
| * Dump the current TLV tree |
| * |
| * @param container The container |
| */ |
| private void dumpTLVTree( Asn1Container container ) |
| { |
| StringBuffer sb = new StringBuffer(); |
| TLV current = container.getCurrentTLV(); |
| |
| sb.append( "TLV" ).append( Asn1StringUtils.dumpByte( current.getTag() ) ).append( "(" ).append( |
| current.getExpectedLength() ).append( ")" ); |
| |
| current = current.getParent(); |
| |
| while ( current != null ) |
| { |
| sb.append( "-TLV" ).append( Asn1StringUtils.dumpByte( current.getTag() ) ).append( "(" ).append( |
| current.getExpectedLength() ).append( ")" ); |
| current = current.getParent(); |
| } |
| |
| if ( IS_DEBUG ) |
| { |
| LOG.debug( "TLV Tree : {}", sb.toString() ); |
| } |
| } |
| |
| |
| /** |
| * Check if the TLV tree is fully decoded |
| * |
| * @param container The container |
| * @return <code>true</code> if the TLV has been decoded |
| */ |
| private boolean isTLVDecoded( Asn1Container container ) |
| { |
| TLV current = container.getCurrentTLV(); |
| TLV parent = current.getParent(); |
| |
| while ( parent != null ) |
| { |
| if ( parent.getExpectedLength() != 0 ) |
| { |
| return false; |
| } |
| |
| parent = parent.getParent(); |
| } |
| |
| BerValue value = current.getValue(); |
| |
| if ( ( value != null ) && ( value.getData() != null ) ) |
| { |
| return ( current.getExpectedLength() == value.getData().length ); |
| } |
| else |
| { |
| return current.getExpectedLength() == 0; |
| } |
| } |
| |
| |
| /** |
| * Treat the Length start. The tag has been decoded, so we have to deal with |
| * the LENGTH, which can be multi-bytes. |
| * |
| * @param stream The ByteBuffer containing the PDU to decode |
| * @param container The container that stores the current state, |
| * the result and other informations. |
| * @return <code>true</code> if there are more bytes to read, <code>false |
| * </code> otherwise |
| * @throws DecoderException Thrown if anything went wrong |
| */ |
| private boolean treatLengthStartState( ByteBuffer stream, Asn1Container container ) throws DecoderException |
| { |
| if ( stream.hasRemaining() ) |
| { |
| byte octet = stream.get(); |
| TLV tlv = container.getCurrentTLV(); |
| |
| if ( ( octet & TLV.LENGTH_LONG_FORM ) == 0 ) |
| { |
| // We don't have a long form. The Length of the Value part is |
| // given by this byte. |
| tlv.setLength( octet ); |
| tlv.setLengthNbBytes( 1 ); |
| |
| container.setState( TLVStateEnum.LENGTH_STATE_END ); |
| } |
| else if ( ( octet & TLV.LENGTH_EXTENSION_RESERVED ) != TLV.LENGTH_EXTENSION_RESERVED ) |
| { |
| int expectedLength = octet & TLV.LENGTH_SHORT_MASK; |
| |
| if ( expectedLength > 4 ) |
| { |
| String msg = I18n.err( I18n.ERR_00005_LENGTH_OVERFLOW ); |
| LOG.error( msg ); |
| throw new DecoderException( msg ); |
| } |
| |
| tlv.setLength( 0 ); |
| tlv.setLengthNbBytes( 1 + expectedLength ); |
| tlv.setLengthBytesRead( 1 ); |
| container.setState( TLVStateEnum.LENGTH_STATE_PENDING ); |
| } |
| else |
| { |
| String msg = I18n.err( I18n.ERR_00006_LENGTH_EXTENSION_RESERVED ); |
| LOG.error( msg ); |
| throw new DecoderException( msg ); |
| } |
| |
| return MORE; |
| } |
| else |
| { |
| return END; |
| } |
| } |
| |
| |
| /** |
| * This function is called when a Length is in the process of being decoded, |
| * but the lack of bytes in the buffer stopped the process. |
| * |
| * @param stream The ByteBuffer containing the PDU to decode |
| * @param container The container that stores the current state, |
| * the result and other informations. |
| * @return <code>true</code> if there are more bytes to read, <code>false |
| * </code> otherwise |
| */ |
| private boolean treatLengthPendingState( ByteBuffer stream, Asn1Container container ) |
| { |
| if ( stream.hasRemaining() ) |
| { |
| TLV tlv = container.getCurrentTLV(); |
| int length = tlv.getLength(); |
| |
| while ( tlv.getLengthBytesRead() < tlv.getLengthNbBytes() ) |
| { |
| byte octet = stream.get(); |
| |
| if ( IS_DEBUG ) |
| { |
| LOG.debug( " current byte : {}", Asn1StringUtils.dumpByte( octet ) ); |
| } |
| |
| tlv.incLengthBytesRead(); |
| length = ( length << 8 ) | ( octet & 0x00FF ); |
| |
| if ( !stream.hasRemaining() ) |
| { |
| tlv.setLength( length ); |
| |
| if ( tlv.getLengthBytesRead() < tlv.getLengthNbBytes() ) |
| { |
| container.setState( TLVStateEnum.LENGTH_STATE_PENDING ); |
| return END; |
| } |
| else |
| { |
| container.setState( TLVStateEnum.LENGTH_STATE_END ); |
| return MORE; |
| } |
| } |
| } |
| |
| tlv.setLength( length ); |
| container.setState( TLVStateEnum.LENGTH_STATE_END ); |
| |
| return MORE; |
| } |
| else |
| { |
| |
| return END; |
| } |
| } |
| |
| |
| /** |
| * A debug function used to dump the expected length stack. |
| * |
| * @param tlv The current TLV. |
| * @return A string which represent the expected length stack. |
| */ |
| private String getParentLength( TLV tlv ) |
| { |
| StringBuffer buffer = new StringBuffer(); |
| |
| buffer.append( "TLV expected length stack : " ); |
| |
| while ( true ) |
| { |
| if ( tlv == null ) |
| { |
| buffer.append( " - null" ); |
| break; |
| } |
| else |
| { |
| buffer.append( " - " ).append( tlv.getExpectedLength() ); |
| } |
| |
| tlv = tlv.getParent(); |
| } |
| |
| return buffer.toString(); |
| } |
| |
| |
| /** |
| * The Length is fully decoded. We have to call an action to check the size. |
| * |
| * @param container The container that stores the current state, |
| * the result and other informations. |
| * @throws DecoderException Thrown if anything went wrong |
| */ |
| private void treatLengthEndState( Asn1Container container ) throws DecoderException |
| { |
| TLV tlv = container.getCurrentTLV(); |
| |
| if ( tlv == null ) |
| { |
| String msg = I18n.err( I18n.ERR_00007_TLV_NULL ); |
| LOG.error( msg ); |
| throw new DecoderException( msg ); |
| } |
| |
| int length = tlv.getLength(); |
| |
| // We will check the length here. What we must control is |
| // that the enclosing constructed TLV expected length is not |
| // exceeded by the current TLV. |
| TLV parentTLV = container.getParentTLV(); |
| |
| if ( IS_DEBUG ) |
| { |
| LOG.debug( "Parent length : {}", getParentLength( parentTLV ) ); |
| } |
| |
| if ( parentTLV == null ) |
| { |
| // This is the first TLV, so we can't check anything. We will |
| // just store this TLV as the root of the PDU |
| tlv.setExpectedLength( length ); |
| container.setParentTLV( tlv ); |
| |
| if ( IS_DEBUG ) |
| { |
| LOG.debug( "Root TLV[{}]", Integer.valueOf( length ) ); |
| } |
| } |
| else |
| { |
| // We have a parent, so we will check that its expected length is |
| // not exceeded. |
| int expectedLength = parentTLV.getExpectedLength(); |
| int currentLength = tlv.getSize(); |
| |
| if ( expectedLength < currentLength ) |
| { |
| // The expected length is lower than the Value length of the |
| // current TLV. This is an error... |
| LOG.debug( "tlv[{}, {}]", Integer.valueOf( expectedLength ), Integer.valueOf( currentLength ) ); |
| throw new DecoderException( I18n.err( I18n.ERR_00008_VALUE_LENGTH_ABOVE_EXPECTED_LENGTH, Integer |
| .valueOf( currentLength ), Integer.valueOf( expectedLength ) ) ); |
| } |
| |
| // deal with the particular case where expected length equal |
| // the current length, which means that the parentTLV has been |
| // completed. |
| if ( expectedLength == currentLength ) |
| { |
| parentTLV.setExpectedLength( 0 ); |
| |
| // We also have to check that the current TLV is a constructed |
| // one. |
| // In this case, we have to switch from this parent TLV |
| // to the parent's parent TLV. |
| if ( tlv.isConstructed() ) |
| { |
| // here, we also have another special case : a |
| // zero length TLV. We must then unstack all |
| // the parents which length is null. |
| if ( length == 0 ) |
| { |
| // We will set the parent to the first parentTLV which |
| // expectedLength |
| // is not null, and it will become the new parent TLV |
| while ( parentTLV != null ) |
| { |
| if ( parentTLV.getExpectedLength() != 0 ) |
| { |
| // ok, we have an incomplete parent. we will |
| // stop the recursion right here |
| break; |
| } |
| else |
| { |
| parentTLV = parentTLV.getParent(); |
| } |
| } |
| |
| container.setParentTLV( parentTLV ); |
| } |
| else |
| { |
| // The new Parent TLV is this Constructed TLV |
| container.setParentTLV( tlv ); |
| } |
| |
| tlv.setParent( parentTLV ); |
| tlv.setExpectedLength( length ); |
| } |
| else |
| { |
| tlv.setExpectedLength( length ); |
| |
| // It's over, the parent TLV has been completed. |
| // Go back to the parent's parent TLV until we find |
| // a tlv which is not complete. |
| while ( parentTLV != null ) |
| { |
| if ( parentTLV.getExpectedLength() != 0 ) |
| { |
| // ok, we have an incomplete parent. we will |
| // stop the recursion right here |
| break; |
| } |
| else |
| { |
| parentTLV = parentTLV.getParent(); |
| } |
| } |
| |
| container.setParentTLV( parentTLV ); |
| } |
| } |
| else |
| { |
| // Renew the expected Length. |
| parentTLV.setExpectedLength( expectedLength - currentLength ); |
| tlv.setExpectedLength( length ); |
| |
| if ( tlv.isConstructed() ) |
| { |
| // We have a constructed tag, so we must switch the |
| // parentTLV |
| tlv.setParent( parentTLV ); |
| container.setParentTLV( tlv ); |
| } |
| } |
| |
| } |
| |
| if ( IS_DEBUG ) |
| { |
| LOG.debug( "Length {} has been decoded", Integer.valueOf( length ) ); |
| } |
| |
| if ( length == 0 ) |
| { |
| // The length is 0, so we can't expect a value. |
| container.setState( TLVStateEnum.TLV_STATE_DONE ); |
| } |
| else |
| { |
| // Go ahead and decode the value part |
| container.setState( TLVStateEnum.VALUE_STATE_START ); |
| } |
| } |
| |
| |
| /** |
| * Treat the Value part. We will distinguish two cases : - if the Tag is a |
| * Primitive one, we will get the value. - if the Tag is a Constructed one, |
| * nothing will be done. |
| * |
| * @param stream The ByteBuffer containing the PDU to decode |
| * @param container The container that stores the current state, |
| * the result and other informations. |
| * @return <code>true</code> if there are more bytes to read, <code>false |
| * </code> otherwise |
| */ |
| private boolean treatValueStartState( ByteBuffer stream, Asn1Container container ) |
| { |
| TLV currentTlv = container.getCurrentTLV(); |
| |
| if ( TLV.isConstructed( currentTlv.getTag() ) && !container.isGathering() ) |
| { |
| container.setState( TLVStateEnum.TLV_STATE_DONE ); |
| |
| return MORE; |
| } |
| else |
| { |
| int length = currentTlv.getLength(); |
| int nbBytes = stream.remaining(); |
| |
| if ( nbBytes < length ) |
| { |
| currentTlv.getValue().init( length ); |
| currentTlv.getValue().setData( stream ); |
| container.setState( TLVStateEnum.VALUE_STATE_PENDING ); |
| |
| return END; |
| } |
| else |
| { |
| currentTlv.getValue().init( length ); |
| stream.get( currentTlv.getValue().getData(), 0, length ); |
| container.setState( TLVStateEnum.TLV_STATE_DONE ); |
| |
| return MORE; |
| } |
| } |
| } |
| |
| |
| /** |
| * Treat a pending Value when we get more bytes in the buffer. |
| * |
| * @param stream The ByteBuffer containing the PDU to decode |
| * @param container The container that stores the current state, |
| * the result and other informations. |
| * @return <code>MORE</code> if some bytes remain in the buffer when the |
| * value has been decoded, <code>END</code> if whe still need to get some |
| * more bytes. |
| */ |
| private boolean treatValuePendingState( ByteBuffer stream, Asn1Container container ) |
| { |
| TLV currentTlv = container.getCurrentTLV(); |
| |
| int length = currentTlv.getLength(); |
| int currentLength = currentTlv.getValue().getCurrentLength(); |
| int nbBytes = stream.remaining(); |
| |
| if ( ( currentLength + nbBytes ) < length ) |
| { |
| currentTlv.getValue().addData( stream ); |
| container.setState( TLVStateEnum.VALUE_STATE_PENDING ); |
| |
| return END; |
| } |
| else |
| { |
| int remaining = length - currentLength; |
| byte[] data = new byte[remaining]; |
| stream.get( data, 0, remaining ); |
| currentTlv.getValue().addData( data ); |
| container.setState( TLVStateEnum.TLV_STATE_DONE ); |
| |
| return MORE; |
| } |
| } |
| |
| |
| /** |
| * When the TLV has been fully decoded, we have to execute the associated |
| * action and switch to the next TLV, which will start with a Tag. |
| * |
| * @param stream The ByteBuffer containing the PDU to decode |
| * @param container The container that stores the current state, |
| * the result and other informations. |
| * @return <code>true</code> if there are more bytes to read, <code>false |
| * </code> otherwise |
| * @throws DecoderException Thrown if anything went wrong |
| */ |
| @SuppressWarnings("unchecked") |
| private boolean treatTLVDoneState( ByteBuffer stream, Asn1Container container ) throws DecoderException |
| { |
| if ( IS_DEBUG ) |
| { |
| dumpTLVTree( container ); |
| } |
| |
| // First, we have to execute the associated action |
| container.getGrammar().executeAction( container ); |
| |
| // Check if the PDU has been fully decoded. |
| if ( isTLVDecoded( container ) ) |
| { |
| if ( container.getState() == TLVStateEnum.GRAMMAR_END ) |
| { |
| // Change the state to DECODED |
| container.setState( TLVStateEnum.PDU_DECODED ); |
| } |
| else |
| { |
| if ( container.isGrammarEndAllowed() ) |
| { |
| // Change the state to DECODED |
| container.setState( TLVStateEnum.PDU_DECODED ); |
| } |
| else |
| { |
| LOG.error( I18n.err( I18n.ERR_00009_MORE_TLV_EXPECTED ) ); |
| throw new DecoderException( I18n.err( I18n.ERR_00010_TRUNCATED_PDU ) ); |
| } |
| } |
| } |
| else |
| { |
| // Then we switch to the Start tag state and free the current TLV |
| container.setState( TLVStateEnum.TAG_STATE_START ); |
| } |
| |
| return stream.hasRemaining(); |
| } |
| |
| |
| /** |
| * The decoder main function. This is where we read bytes from the stream |
| * and go through the automaton. It's an inifnite loop which stop when no |
| * more bytes are to be read. It can occurs if the ByteBuffer is exhausted |
| * or if the PDU has been fully decoded. |
| * |
| * @param stream The ByteBuffer containing the PDU to decode |
| * @param container The container that store the state, the result |
| * and other elements. |
| * @throws DecoderException Thrown if anything went wrong! |
| */ |
| public void decode( ByteBuffer stream, Asn1Container container ) throws DecoderException |
| { |
| /* |
| * We have to deal with the current state. This is an infinite loop, |
| * which will stop for any of these reasons : |
| * - STATE_END has been reached (hopefully, the most frequent case) |
| * - buffer is empty (it could happen) |
| * - STATE_OVERFLOW : bad situation ! The PDU may be a |
| * malevolous hand crafted ones, that try to "kill" our decoder. We |
| * must log it with all information to track back this case, and punish |
| * the guilty ! |
| */ |
| boolean hasRemaining = stream.hasRemaining(); |
| |
| // Increment the PDU size counter. |
| container.incrementDecodedBytes( stream.remaining() ); |
| |
| if ( container.getDecodedBytes() > container.getMaxPDUSize() ) |
| { |
| String message = I18n.err( I18n.ERR_00042_PDU_SIZE_TOO_LONG, container.getDecodedBytes(), container |
| .getMaxPDUSize() ); |
| LOG.error( message ); |
| throw new DecoderException( message ); |
| } |
| |
| if ( IS_DEBUG ) |
| { |
| LOG.debug( ">>>==========================================" ); |
| LOG.debug( "--> Decoding a PDU" ); |
| LOG.debug( ">>>------------------------------------------" ); |
| } |
| |
| while ( hasRemaining ) |
| { |
| if ( IS_DEBUG ) |
| { |
| LOG.debug( "--- State = {} ---", container.getState() ); |
| |
| if ( stream.hasRemaining() ) |
| { |
| byte octet = stream.get( stream.position() ); |
| |
| LOG.debug( " current byte : {}", Asn1StringUtils.dumpByte( octet ) ); |
| } |
| else |
| { |
| LOG.debug( " no more byte to decode in the stream" ); |
| } |
| } |
| |
| switch ( container.getState() ) |
| { |
| case TAG_STATE_START: |
| // Reset the GrammarEnd flag first |
| container.setGrammarEndAllowed( false ); |
| hasRemaining = treatTagStartState( stream, container ); |
| |
| break; |
| |
| case LENGTH_STATE_START: |
| hasRemaining = treatLengthStartState( stream, container ); |
| |
| break; |
| |
| case LENGTH_STATE_PENDING: |
| hasRemaining = treatLengthPendingState( stream, container ); |
| |
| break; |
| |
| case LENGTH_STATE_END: |
| treatLengthEndState( container ); |
| |
| break; |
| |
| case VALUE_STATE_START: |
| hasRemaining = treatValueStartState( stream, container ); |
| |
| break; |
| |
| case VALUE_STATE_PENDING: |
| hasRemaining = treatValuePendingState( stream, container ); |
| |
| break; |
| |
| case VALUE_STATE_END: |
| hasRemaining = stream.hasRemaining(); |
| |
| // Nothing to do. We will never reach this state |
| break; |
| |
| case TLV_STATE_DONE: |
| hasRemaining = treatTLVDoneState( stream, container ); |
| |
| break; |
| |
| case PDU_DECODED: |
| // We have to deal with the case where there are |
| // more bytes in the buffer, but the PDU has been decoded. |
| if ( LOG.isDebugEnabled() ) |
| { |
| LOG.debug( I18n.err( I18n.ERR_00043_REMAINING_BYTES_FOR_DECODED_PDU ) ); |
| } |
| |
| hasRemaining = false; |
| |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| if ( IS_DEBUG ) |
| { |
| LOG.debug( "<<<------------------------------------------" ); |
| |
| if ( container.getState() == TLVStateEnum.PDU_DECODED ) |
| { |
| if ( container.getCurrentTLV() != null ) |
| { |
| LOG.debug( "<-- Stop decoding : {}", container.getCurrentTLV().toString() ); |
| } |
| else |
| { |
| LOG.debug( "<-- Stop decoding : null current TLV" ); |
| } |
| } |
| else |
| { |
| if ( container.getCurrentTLV() != null ) |
| { |
| LOG.debug( "<-- End decoding : {}", container.getCurrentTLV().toString() ); |
| } |
| else |
| { |
| LOG.debug( "<-- End decoding : null current TLV" ); |
| } |
| } |
| |
| LOG.debug( "<<<==========================================" ); |
| } |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public int getMaxLengthLength() |
| { |
| return maxLengthLength; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public int getMaxTagLength() |
| { |
| return maxTagLength; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void disallowIndefiniteLength() |
| { |
| this.indefiniteLengthAllowed = false; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void allowIndefiniteLength() |
| { |
| this.indefiniteLengthAllowed = true; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean isIndefiniteLengthAllowed() |
| { |
| |
| return indefiniteLengthAllowed; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setMaxLengthLength( int maxLengthLength ) throws DecoderException |
| { |
| if ( ( this.indefiniteLengthAllowed ) && ( maxLengthLength > 126 ) ) |
| { |
| throw new DecoderException( I18n.err( I18n.ERR_00011_LENGTH_TOO_LONG_FOR_DEFINITE_FORM ) ); |
| } |
| |
| this.maxLengthLength = maxLengthLength; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setMaxTagLength( int maxTagLength ) |
| { |
| this.maxTagLength = maxTagLength; |
| } |
| } |