| | |
| | | |
| | | |
| | | import static com.sun.opends.sdk.messages.Messages.*; |
| | | import static org.opends.sdk.asn1.ASN1Constants.*; |
| | | import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE; |
| | | import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_TYPE; |
| | | import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_VALUE_BYTES; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.LinkedList; |
| | |
| | | |
| | | |
| | | /** |
| | | * Creates a new ASN1 reader whose source is the provided byte |
| | | * sequence reader and having a user defined maximum BER element size. |
| | | * Creates a new ASN1 reader whose source is the provided byte sequence reader |
| | | * and having a user defined maximum BER element size. |
| | | * |
| | | * @param reader |
| | | * The byte sequence reader to be read. |
| | | * @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. |
| | | */ |
| | | ASN1ByteSequenceReader(ByteSequenceReader reader, int maxElementSize) |
| | | ASN1ByteSequenceReader(final ByteSequenceReader reader, |
| | | final int maxElementSize) |
| | | { |
| | | this.reader = reader; |
| | | this.readerStack = new LinkedList<ByteSequenceReader>(); |
| | |
| | | */ |
| | | public boolean elementAvailable() throws IOException |
| | | { |
| | | if ((state == ELEMENT_READ_STATE_NEED_TYPE) |
| | | && !needTypeState(false)) |
| | | if ((state == ELEMENT_READ_STATE_NEED_TYPE) && !needTypeState(false)) |
| | | { |
| | | return false; |
| | | } |
| | |
| | | */ |
| | | public boolean hasNextElement() throws IOException |
| | | { |
| | | return (state != ELEMENT_READ_STATE_NEED_TYPE) |
| | | || needTypeState(false); |
| | | return (state != ELEMENT_READ_STATE_NEED_TYPE) || needTypeState(false); |
| | | } |
| | | |
| | | |
| | |
| | | // Read just the type. |
| | | if (reader.remaining() <= 0) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_TRUCATED_TYPE_BYTE.get(); |
| | | final LocalizableMessage message = ERR_ASN1_TRUCATED_TYPE_BYTE.get(); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | int type = reader.get(); |
| | | final int type = reader.get(); |
| | | |
| | | peekType = (byte) type; |
| | | state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE; |
| | |
| | | |
| | | 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); |
| | | } |
| | | |
| | | if (reader.remaining() < peekLength) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_BOOLEAN_TRUNCATED_VALUE |
| | | final LocalizableMessage message = ERR_ASN1_BOOLEAN_TRUNCATED_VALUE |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | int readByte = reader.get(); |
| | | final int readByte = reader.get(); |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return readByte != 0x00; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void readEndSequence() throws IOException, |
| | | IllegalStateException |
| | | public void readEndSequence() throws IOException, IllegalStateException |
| | | { |
| | | if (readerStack.isEmpty()) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED.get(); |
| | | final LocalizableMessage message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED |
| | | .get(); |
| | | throw new IllegalStateException(message.toString()); |
| | | } |
| | | |
| | |
| | | |
| | | 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); |
| | | } |
| | | |
| | | if (reader.remaining() < peekLength) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_INTEGER_TRUNCATED_VALUE |
| | | final LocalizableMessage message = ERR_ASN1_INTEGER_TRUNCATED_VALUE |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | |
| | | long longValue = 0; |
| | | for (int i = 0; i < peekLength; i++) |
| | | { |
| | | int readByte = reader.get(); |
| | | final int readByte = reader.get(); |
| | | if ((i == 0) && (readByte < 0)) |
| | | { |
| | | longValue = 0xFFFFFFFFFFFFFFFFL; |
| | |
| | | int intValue = 0; |
| | | for (int i = 0; i < peekLength; i++) |
| | | { |
| | | int readByte = reader.get(); |
| | | final int readByte = reader.get(); |
| | | if ((i == 0) && (readByte < 0)) |
| | | { |
| | | intValue = 0xFFFFFFFF; |
| | |
| | | // 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 (reader.remaining() < peekLength) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE |
| | | final LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ByteStringBuilder readOctetString(ByteStringBuilder builder) |
| | | public ByteStringBuilder readOctetString(final ByteStringBuilder builder) |
| | | throws IOException |
| | | { |
| | | // Read the header if haven't done so already |
| | |
| | | // Copy the value. |
| | | if (reader.remaining() < peekLength) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE |
| | | final LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | |
| | | |
| | | if (reader.remaining() < peekLength) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE |
| | | final LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | |
| | | |
| | | if (reader.remaining() < peekLength) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_SEQUENCE_SET_TRUNCATED_VALUE |
| | | final LocalizableMessage message = ERR_ASN1_SEQUENCE_SET_TRUNCATED_VALUE |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | | ByteSequenceReader subByteString = reader.getByteSequence( |
| | | peekLength).asReader(); |
| | | final ByteSequenceReader subByteString = reader.getByteSequence(peekLength) |
| | | .asReader(); |
| | | readerStack.addFirst(reader); |
| | | reader = subByteString; |
| | | |
| | |
| | | |
| | | if (reader.remaining() < peekLength) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_SKIP_TRUNCATED_VALUE.get(peekLength); |
| | | final LocalizableMessage message = ERR_ASN1_SKIP_TRUNCATED_VALUE |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * 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 throwEofException |
| | | * <code>true</code> to throw an exception when the end of |
| | | * the sequence is encountered. |
| | | * <code>true</code> to throw an exception when the end of the |
| | | * sequence is encountered. |
| | | * @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 throwEofException) |
| | | private boolean needFirstLengthByteState(final boolean throwEofException) |
| | | throws IOException |
| | | { |
| | | if (reader.remaining() <= 0) |
| | | { |
| | | if (throwEofException) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get(); |
| | | final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get(); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | return false; |
| | |
| | | int 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); |
| | | } |
| | |
| | | { |
| | | if (throwEofException) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTES |
| | | final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTES |
| | | .get(lengthBytesNeeded); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | |
| | | // message size. |
| | | if ((maxElementSize > 0) && (peekLength > maxElementSize)) |
| | | { |
| | | LocalizableMessage message = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED |
| | | final LocalizableMessage message = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED |
| | | .get(peekLength, maxElementSize); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | |
| | | |
| | | |
| | | /** |
| | | * 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 throwEofException |
| | | * <code>true</code> to throw an exception when the end of |
| | | * the sequence is encountered. |
| | | * <code>true</code> to throw an exception when the end of the |
| | | * sequence is encountered. |
| | | * @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 throwEofException) |
| | | private boolean needTypeState(final boolean throwEofException) |
| | | throws IOException |
| | | { |
| | | // Read just the type. |
| | |
| | | { |
| | | if (throwEofException) |
| | | { |
| | | LocalizableMessage message = ERR_ASN1_TRUCATED_TYPE_BYTE.get(); |
| | | final LocalizableMessage message = ERR_ASN1_TRUCATED_TYPE_BYTE.get(); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | return false; |
| | | } |
| | | int type = reader.get(); |
| | | final int type = reader.get(); |
| | | |
| | | peekType = (byte) type; |
| | | state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE; |