| File was renamed from sdk/src/com/sun/opends/sdk/ldap/ASN1StreamReader.java |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package com.sun.opends.sdk.ldap; |
| | | |
| | | |
| | | |
| | | import static com.sun.opends.sdk.ldap.LDAPConstants.ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES; |
| | | import static com.sun.opends.sdk.ldap.LDAPConstants.ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE; |
| | | import static com.sun.opends.sdk.ldap.LDAPConstants.ELEMENT_READ_STATE_NEED_TYPE; |
| | | import static com.sun.opends.sdk.ldap.LDAPConstants.ELEMENT_READ_STATE_NEED_VALUE_BYTES; |
| | | import static com.sun.opends.sdk.messages.Messages.*; |
| | | import static com.sun.opends.sdk.ldap.LDAPConstants.*; |
| | | |
| | | import java.io.IOException; |
| | | import java.nio.BufferUnderflowException; |
| | | import java.util.logging.Level; |
| | | |
| | | import org.opends.sdk.ByteString; |
| | |
| | | import org.opends.sdk.asn1.ASN1Reader; |
| | | import org.opends.sdk.asn1.AbstractASN1Reader; |
| | | |
| | | import com.sun.grizzly.streams.StreamReader; |
| | | import com.sun.grizzly.utils.PoolableObject; |
| | | import com.sun.grizzly.Buffer; |
| | | import com.sun.grizzly.memory.ByteBuffersBuffer; |
| | | import com.sun.grizzly.memory.CompositeBuffer; |
| | | import com.sun.opends.sdk.util.StaticUtils; |
| | | |
| | | |
| | |
| | | /** |
| | | * Grizzly ASN1 reader implementation. |
| | | */ |
| | | public final class ASN1StreamReader extends AbstractASN1Reader implements |
| | | PoolableObject, ASN1Reader |
| | | final class ASN1BufferReader extends AbstractASN1Reader implements ASN1Reader |
| | | { |
| | | class ChildSequenceLimiter implements SequenceLimiter |
| | | private final class ChildSequenceLimiter implements SequenceLimiter |
| | | { |
| | | private SequenceLimiter parent; |
| | | |
| | |
| | | |
| | | |
| | | |
| | | public void checkLimit(int readSize) throws IOException, |
| | | BufferUnderflowException |
| | | public void checkLimit(final int readSize) throws IOException |
| | | { |
| | | if ((readLimit > 0) && (bytesRead + readSize > readLimit)) |
| | | { |
| | | throw new BufferUnderflowException(); |
| | | final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get(); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | | parent.checkLimit(readSize); |
| | |
| | | { |
| | | parent.checkLimit(remaining()); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE) |
| | | && remaining() > 0) |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE) && remaining() > 0) |
| | | { |
| | | StaticUtils.DEBUG_LOG.fine(String.format( |
| | | "Ignoring %d unused trailing bytes in ASN.1 SEQUENCE", |
| | | remaining())); |
| | | StaticUtils.DEBUG_LOG |
| | | .fine(String.format( |
| | | "Ignoring %d unused trailing bytes in ASN.1 SEQUENCE", |
| | | remaining())); |
| | | } |
| | | |
| | | for (int i = 0; i < remaining(); i++) |
| | | { |
| | | streamReader.readByte(); |
| | | buffer.get(); |
| | | } |
| | | |
| | | return parent; |
| | |
| | | |
| | | |
| | | |
| | | public ChildSequenceLimiter startSequence(int readLimit) |
| | | public ChildSequenceLimiter startSequence(final int readLimit) |
| | | { |
| | | if (child == null) |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | class RootSequenceLimiter implements SequenceLimiter |
| | | private final class RootSequenceLimiter implements SequenceLimiter |
| | | { |
| | | private ChildSequenceLimiter child; |
| | | |
| | | |
| | | |
| | | public void checkLimit(int readSize) |
| | | public void checkLimit(final int readSize) throws IOException |
| | | { |
| | | if (buffer.remaining() < readSize) |
| | | { |
| | | final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get(); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public ChildSequenceLimiter endSequence() throws DecodeException |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED.get(); |
| | | final LocalizableMessage message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED |
| | | .get(); |
| | | throw new IllegalStateException(message.toString()); |
| | | } |
| | | |
| | |
| | | |
| | | public int remaining() |
| | | { |
| | | return streamReader.availableDataSize(); |
| | | return buffer.remaining(); |
| | | } |
| | | |
| | | |
| | | |
| | | public ChildSequenceLimiter startSequence(int readLimit) |
| | | public ChildSequenceLimiter startSequence(final int readLimit) |
| | | { |
| | | if (child == null) |
| | | { |
| | |
| | | |
| | | private interface SequenceLimiter |
| | | { |
| | | public void checkLimit(int readSize) throws IOException, |
| | | BufferUnderflowException; |
| | | public void checkLimit(int readSize) throws IOException; |
| | | |
| | | |
| | | |
| | |
| | | |
| | | private final int maxElementSize; |
| | | |
| | | private StreamReader streamReader; |
| | | |
| | | private final RootSequenceLimiter rootLimiter; |
| | | private final CompositeBuffer buffer; |
| | | |
| | | private SequenceLimiter readLimiter; |
| | | |
| | | private final byte[] buffer; |
| | | private final byte[] stringBuffer; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new ASN1 reader whose source is the provided input stream |
| | | * and having a user defined maximum BER element size. |
| | | * Creates a new ASN1 reader whose source is the provided input stream and |
| | | * having a user defined maximum BER element size. |
| | | * |
| | | * @param maxElementSize |
| | | * The maximum BER element size, or <code>0</code> to |
| | | * indicate that there is no limit. |
| | | * The maximum BER element size, or <code>0</code> to indicate that |
| | | * there is no limit. |
| | | */ |
| | | public ASN1StreamReader(int maxElementSize) |
| | | ASN1BufferReader(final int maxElementSize) |
| | | { |
| | | this.readLimiter = this.rootLimiter = new RootSequenceLimiter(); |
| | | this.buffer = new byte[MAX_STRING_BUFFER_SIZE]; |
| | | this.readLimiter = new RootSequenceLimiter(); |
| | | this.stringBuffer = new byte[MAX_STRING_BUFFER_SIZE]; |
| | | this.maxElementSize = maxElementSize; |
| | | this.buffer = ByteBuffersBuffer.create(); |
| | | } |
| | | |
| | | |
| | |
| | | */ |
| | | public void close() throws IOException |
| | | { |
| | | // close the stream reader. |
| | | streamReader.close(); |
| | | buffer.dispose(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Determines if a complete ASN.1 element is ready to be read from the |
| | | * stream reader. |
| | | * Determines if a complete ASN.1 element is ready to be read from the stream |
| | | * reader. |
| | | * |
| | | * @return <code>true</code> if another complete element is available |
| | | * or <code>false</code> otherwise. |
| | | * @return <code>true</code> if another complete element is available or |
| | | * <code>false</code> otherwise. |
| | | * @throws IOException |
| | | * If an error occurs while trying to decode an ASN1 |
| | | * element. |
| | | * If an error occurs while trying to decode an ASN1 element. |
| | | */ |
| | | public boolean elementAvailable() throws IOException |
| | | { |
| | | if ((state == ELEMENT_READ_STATE_NEED_TYPE) && !needTypeState(true)) |
| | | { |
| | | return false; |
| | | } |
| | | if ((state == ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE) |
| | | && !needFirstLengthByteState(true)) |
| | | { |
| | | return false; |
| | | } |
| | | return !((state == ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES) |
| | | && !needAdditionalLengthBytesState(true)) && |
| | | peekLength <= readLimiter.remaining(); |
| | | return !((state == ELEMENT_READ_STATE_NEED_TYPE) && !needTypeState(true)) |
| | | && !((state == ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE) |
| | | && !needFirstLengthByteState(true)) |
| | | && !((state == ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES) |
| | | && !needAdditionalLengthBytesState(true)) |
| | | && peekLength <= readLimiter.remaining(); |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Determines if the input stream contains at least one ASN.1 element |
| | | * to be read. |
| | | * Determines if the input stream contains at least one ASN.1 element to be |
| | | * read. |
| | | * |
| | | * @return <code>true</code> if another element is available or |
| | | * <code>false</code> otherwise. |
| | | * @throws IOException |
| | | * If an error occurs while trying to decode an ASN1 |
| | | * element. |
| | | * If an error occurs while trying to decode an ASN1 element. |
| | | */ |
| | | public boolean hasNextElement() throws IOException |
| | | { |
| | | return (state != ELEMENT_READ_STATE_NEED_TYPE) |
| | | || needTypeState(true); |
| | | return (state != ELEMENT_READ_STATE_NEED_TYPE) || needTypeState(true); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | |
| | | public void prepare() |
| | | { |
| | | // Nothing to do |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | |
| | | |
| | | if (peekLength != 1) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_BOOLEAN_INVALID_LENGTH.get(peekLength); |
| | | final LocalizableMessage message = ERR_ASN1_BOOLEAN_INVALID_LENGTH |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | | readLimiter.checkLimit(peekLength); |
| | | byte readByte = streamReader.readByte(); |
| | | final byte readByte = buffer.get(); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 BOOLEAN(type=0x%x, length=%d, value=%s)", |
| | | peekType, peekLength, String.valueOf(readByte != 0x00))); |
| | | "READ ASN.1 BOOLEAN(type=0x%x, length=%d, value=%s)", peekType, |
| | | peekLength, String.valueOf(readByte != 0x00))); |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void readEndSequence() throws IOException, |
| | | IllegalStateException |
| | | public void readEndSequence() throws IOException, IllegalStateException |
| | | { |
| | | readLimiter = readLimiter.endSequence(); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String |
| | | .format("READ ASN.1 END SEQUENCE")); |
| | | StaticUtils.DEBUG_LOG.finest(String.format("READ ASN.1 END SEQUENCE")); |
| | | } |
| | | |
| | | // Reset the state |
| | |
| | | |
| | | if ((peekLength < 1) || (peekLength > 4)) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH.get(peekLength); |
| | | final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | |
| | | |
| | | if ((peekLength < 1) || (peekLength > 8)) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH.get(peekLength); |
| | | final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | |
| | | long longValue = 0; |
| | | for (int i = 0; i < peekLength; i++) |
| | | { |
| | | int readByte = streamReader.readByte(); |
| | | final int readByte = buffer.get(); |
| | | if ((i == 0) && (((byte) readByte) < 0)) |
| | | { |
| | | longValue = 0xFFFFFFFFFFFFFFFFL; |
| | |
| | | int intValue = 0; |
| | | for (int i = 0; i < peekLength; i++) |
| | | { |
| | | int readByte = streamReader.readByte(); |
| | | final int readByte = buffer.get(); |
| | | if ((i == 0) && (((byte) readByte) < 0)) |
| | | { |
| | | intValue = 0xFFFFFFFF; |
| | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", |
| | | peekType, peekLength, intValue)); |
| | | "READ ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", peekType, |
| | | peekLength, intValue)); |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | |
| | | // Make sure that the decoded length is exactly zero byte. |
| | | if (peekLength != 0) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_NULL_INVALID_LENGTH.get(peekLength); |
| | | final LocalizableMessage message = ERR_ASN1_NULL_INVALID_LENGTH |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String |
| | | .format("READ ASN.1 NULL(type=0x%x, length=%d)", peekType, |
| | | peekLength)); |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 NULL(type=0x%x, length=%d)", peekType, peekLength)); |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | |
| | | |
| | | readLimiter.checkLimit(peekLength); |
| | | // Copy the value and construct the element to return. |
| | | byte[] value = new byte[peekLength]; |
| | | streamReader.readByteArray(value); |
| | | final byte[] value = new byte[peekLength]; |
| | | buffer.get(value); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 OCTETSTRING(type=0x%x, length=%d)", peekType, |
| | | peekLength)); |
| | | StaticUtils.DEBUG_LOG |
| | | .finest(String.format("READ ASN.1 OCTETSTRING(type=0x%x, length=%d)", |
| | | peekType, peekLength)); |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ByteStringBuilder readOctetString(ByteStringBuilder builder) |
| | | public ByteStringBuilder readOctetString(final ByteStringBuilder builder) |
| | | throws IOException |
| | | { |
| | | // Read the header if haven't done so already |
| | |
| | | // TODO: Is there a more efficient way to do this? |
| | | for (int i = 0; i < peekLength; i++) |
| | | { |
| | | builder.append(streamReader.readByte()); |
| | | builder.append(buffer.get()); |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 OCTETSTRING(type=0x%x, length=%d)", peekType, |
| | | peekLength)); |
| | | StaticUtils.DEBUG_LOG |
| | | .finest(String.format("READ ASN.1 OCTETSTRING(type=0x%x, length=%d)", |
| | | peekType, peekLength)); |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | |
| | | } |
| | | |
| | | byte[] readBuffer; |
| | | if (peekLength <= buffer.length) |
| | | if (peekLength <= stringBuffer.length) |
| | | { |
| | | readBuffer = buffer; |
| | | readBuffer = stringBuffer; |
| | | } |
| | | else |
| | | { |
| | |
| | | } |
| | | |
| | | readLimiter.checkLimit(peekLength); |
| | | streamReader.readByteArray(readBuffer, 0, peekLength); |
| | | buffer.get(readBuffer, 0, peekLength); |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | |
| | |
| | | { |
| | | str = new String(readBuffer, 0, peekLength, "UTF-8"); |
| | | } |
| | | catch (Exception e) |
| | | catch (final Exception e) |
| | | { |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING)) |
| | | { |
| | |
| | | + e.toString()); |
| | | } |
| | | |
| | | str = new String(buffer, 0, peekLength); |
| | | str = new String(stringBuffer, 0, peekLength); |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 OCTETSTRING(type=0x%x, length=%d, value=%s)", |
| | | peekType, peekLength, str)); |
| | | "READ ASN.1 OCTETSTRING(type=0x%x, length=%d, value=%s)", peekType, |
| | | peekLength, str)); |
| | | } |
| | | |
| | | return str; |
| | |
| | | |
| | | |
| | | |
| | | public void release() |
| | | { |
| | | streamReader = null; |
| | | peekLength = -1; |
| | | peekType = 0; |
| | | readLimiter = rootLimiter; |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | } |
| | | |
| | | |
| | | |
| | | public void setStreamReader(StreamReader streamReader) |
| | | { |
| | | this.streamReader = streamReader; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | |
| | | readLimiter.checkLimit(peekLength); |
| | | for (int i = 0; i < peekLength; i++) |
| | | { |
| | | streamReader.readByte(); |
| | | buffer.get(); |
| | | } |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return this; |
| | |
| | | |
| | | |
| | | |
| | | void appendBytesRead(final Buffer buffer) |
| | | { |
| | | this.buffer.append(buffer); |
| | | } |
| | | |
| | | |
| | | |
| | | void disposeBytesRead() |
| | | { |
| | | this.buffer.disposeUnused(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Internal helper method reading the additional ASN.1 length bytes |
| | | * and transition to the next state if successful. |
| | | * Internal helper method reading the additional ASN.1 length bytes and |
| | | * transition to the next state if successful. |
| | | * |
| | | * @param ensureRead |
| | | * <code>true</code> to check for availability first. |
| | | * @return <code>true</code> if the length bytes was successfully |
| | | * read. |
| | | * @return <code>true</code> if the length bytes was successfully read. |
| | | * @throws IOException |
| | | * If an error occurs while reading from the stream. |
| | | */ |
| | | private boolean needAdditionalLengthBytesState(boolean ensureRead) |
| | | private boolean needAdditionalLengthBytesState(final boolean ensureRead) |
| | | throws IOException |
| | | { |
| | | if (ensureRead && (readLimiter.remaining() < lengthBytesNeeded)) |
| | |
| | | readLimiter.checkLimit(lengthBytesNeeded); |
| | | while (lengthBytesNeeded > 0) |
| | | { |
| | | readByte = streamReader.readByte(); |
| | | readByte = buffer.get(); |
| | | peekLength = (peekLength << 8) | (readByte & 0xFF); |
| | | lengthBytesNeeded--; |
| | | } |
| | |
| | | // message size. |
| | | if ((maxElementSize > 0) && (peekLength > maxElementSize)) |
| | | { |
| | | LocalizableMessage m = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED.get( |
| | | peekLength, maxElementSize); |
| | | final LocalizableMessage m = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED |
| | | .get(peekLength, maxElementSize); |
| | | throw DecodeException.fatalError(m); |
| | | } |
| | | state = ELEMENT_READ_STATE_NEED_VALUE_BYTES; |
| | |
| | | |
| | | |
| | | /** |
| | | * Internal helper method reading the first length bytes and |
| | | * transition to the next state if successful. |
| | | * Internal helper method reading the first length bytes and transition to the |
| | | * next state if successful. |
| | | * |
| | | * @param ensureRead |
| | | * <code>true</code> to check for availability first. |
| | | * @return <code>true</code> if the length bytes was successfully read |
| | | * @throws IOException |
| | | * If an error occurs while trying to decode an ASN1 |
| | | * element. |
| | | * If an error occurs while trying to decode an ASN1 element. |
| | | */ |
| | | private boolean needFirstLengthByteState(boolean ensureRead) |
| | | private boolean needFirstLengthByteState(final boolean ensureRead) |
| | | throws IOException |
| | | { |
| | | if (ensureRead && (readLimiter.remaining() <= 0)) |
| | |
| | | } |
| | | |
| | | readLimiter.checkLimit(1); |
| | | byte readByte = streamReader.readByte(); |
| | | byte readByte = buffer.get(); |
| | | peekLength = (readByte & 0x7F); |
| | | if (peekLength != readByte) |
| | | { |
| | | lengthBytesNeeded = peekLength; |
| | | if (lengthBytesNeeded > 4) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES |
| | | final LocalizableMessage message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES |
| | | .get(lengthBytesNeeded); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | |
| | | readLimiter.checkLimit(lengthBytesNeeded); |
| | | while (lengthBytesNeeded > 0) |
| | | { |
| | | readByte = streamReader.readByte(); |
| | | readByte = buffer.get(); |
| | | peekLength = (peekLength << 8) | (readByte & 0xFF); |
| | | lengthBytesNeeded--; |
| | | } |
| | |
| | | // message size. |
| | | if ((maxElementSize > 0) && (peekLength > maxElementSize)) |
| | | { |
| | | LocalizableMessage m = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED.get( |
| | | peekLength, maxElementSize); |
| | | final LocalizableMessage m = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED |
| | | .get(peekLength, maxElementSize); |
| | | throw DecodeException.fatalError(m); |
| | | } |
| | | state = ELEMENT_READ_STATE_NEED_VALUE_BYTES; |
| | |
| | | |
| | | |
| | | /** |
| | | * Internal helper method reading the ASN.1 type byte and transition |
| | | * to the next state if successful. |
| | | * Internal helper method reading the ASN.1 type byte and transition to the |
| | | * next state if successful. |
| | | * |
| | | * @param ensureRead |
| | | * <code>true</code> to check for availability first. |
| | | * @return <code>true</code> if the type byte was successfully read |
| | | * @throws IOException |
| | | * If an error occurs while trying to decode an ASN1 |
| | | * element. |
| | | * If an error occurs while trying to decode an ASN1 element. |
| | | */ |
| | | private boolean needTypeState(boolean ensureRead) throws IOException |
| | | private boolean needTypeState(final boolean ensureRead) throws IOException |
| | | { |
| | | // Read just the type. |
| | | if (ensureRead && (readLimiter.remaining() <= 0)) |
| | |
| | | } |
| | | |
| | | readLimiter.checkLimit(1); |
| | | peekType = streamReader.readByte(); |
| | | peekType = buffer.get(); |
| | | state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE; |
| | | return true; |
| | | } |