From 263d085885df024dca9250cc03c807912b0a7662 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Tue, 24 Apr 2012 22:33:21 +0000
Subject: [PATCH] Reformat to comply with new Checkstyle rules.
---
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/ASN1InputStreamReader.java | 1261 +++++++++++++++++++++++++-------------------------------
1 files changed, 559 insertions(+), 702 deletions(-)
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/ASN1InputStreamReader.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/ASN1InputStreamReader.java
index b98198e..b88c07f 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/ASN1InputStreamReader.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/ASN1InputStreamReader.java
@@ -6,17 +6,16 @@
* (the "License"). You may not use this file except in compliance
* with the License.
*
- * You can obtain a copy of the license at
- * trunk/opendj3/legal-notices/CDDLv1_0.txt
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable,
- * add the following below this CDDL HEADER, with the fields enclosed
- * by brackets "[]" replaced with your own identifying information:
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
@@ -28,9 +27,10 @@
package org.forgerock.opendj.asn1;
-
-
-import static org.forgerock.opendj.asn1.ASN1Constants.*;
+import static org.forgerock.opendj.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
+import static org.forgerock.opendj.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
+import static org.forgerock.opendj.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_TYPE;
+import static org.forgerock.opendj.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_VALUE_BYTES;
import static org.forgerock.opendj.ldap.CoreMessages.*;
import java.io.IOException;
@@ -46,739 +46,596 @@
import com.forgerock.opendj.util.SizeLimitInputStream;
import com.forgerock.opendj.util.StaticUtils;
-
-
/**
* An ASN1Reader that reads from an input stream.
*/
-final class ASN1InputStreamReader extends AbstractASN1Reader implements
- ASN1Reader
-{
- private int state = ELEMENT_READ_STATE_NEED_TYPE;
+final class ASN1InputStreamReader extends AbstractASN1Reader implements ASN1Reader {
+ private int state = ELEMENT_READ_STATE_NEED_TYPE;
- private byte peekType = 0;
+ private byte peekType = 0;
- private int peekLength = -1;
+ private int peekLength = -1;
- private int lengthBytesNeeded = 0;
+ private int lengthBytesNeeded = 0;
- private final int maxElementSize;
+ private final int maxElementSize;
- private InputStream in;
+ private InputStream in;
- private final LinkedList<InputStream> streamStack;
+ private final LinkedList<InputStream> streamStack;
- private byte[] buffer;
+ private byte[] buffer;
-
-
- /**
- * Creates a new ASN1 reader whose source is the provided input stream and
- * having a user defined maximum BER element size.
- *
- * @param stream
- * The input stream to be read.
- * @param maxElementSize
- * The maximum BER element size, or <code>0</code> to indicate that
- * there is no limit.
- */
- ASN1InputStreamReader(final InputStream stream, final int maxElementSize)
- {
- this.in = stream;
- this.streamStack = new LinkedList<InputStream>();
- this.buffer = new byte[512];
- this.maxElementSize = maxElementSize;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public void close() throws IOException
- {
- // Calling close of SizeLimitInputStream should close the parent
- // stream.
- in.close();
- streamStack.clear();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public boolean elementAvailable() throws IOException
- {
- if ((state == ELEMENT_READ_STATE_NEED_TYPE) && !needTypeState(false, false))
- {
- return false;
- }
- if ((state == ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE)
- && !needFirstLengthByteState(false, false))
- {
- return false;
- }
- if ((state == ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES)
- && !needAdditionalLengthBytesState(false, false))
- {
- return false;
+ /**
+ * Creates a new ASN1 reader whose source is the provided input stream and
+ * having a user defined maximum BER element size.
+ *
+ * @param stream
+ * The input stream to be read.
+ * @param maxElementSize
+ * The maximum BER element size, or <code>0</code> to indicate
+ * that there is no limit.
+ */
+ ASN1InputStreamReader(final InputStream stream, final int maxElementSize) {
+ this.in = stream;
+ this.streamStack = new LinkedList<InputStream>();
+ this.buffer = new byte[512];
+ this.maxElementSize = maxElementSize;
}
- return peekLength <= in.available();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public boolean hasNextElement() throws IOException
- {
- if (!streamStack.isEmpty())
- {
- // We are reading a sub sequence. Return true as long as we
- // haven't exhausted the size limit for the sub sequence sub input
- // stream.
- final SizeLimitInputStream subSq = (SizeLimitInputStream) in;
- return (subSq.getSizeLimit() - subSq.getBytesRead() > 0);
+ /**
+ * {@inheritDoc}
+ */
+ public void close() throws IOException {
+ // Calling close of SizeLimitInputStream should close the parent
+ // stream.
+ in.close();
+ streamStack.clear();
}
- return (state != ELEMENT_READ_STATE_NEED_TYPE)
- || needTypeState(true, false);
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public int peekLength() throws IOException
- {
- peekType();
-
- switch (state)
- {
- case ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE:
- needFirstLengthByteState(true, true);
- break;
-
- case ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES:
- needAdditionalLengthBytesState(true, true);
- }
-
- return peekLength;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public byte peekType() throws IOException
- {
- if (state == ELEMENT_READ_STATE_NEED_TYPE)
- {
- needTypeState(true, true);
- }
-
- return peekType;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public boolean readBoolean() throws IOException
- {
- // Read the header if haven't done so already
- peekLength();
-
- if (peekLength != 1)
- {
- final LocalizableMessage message = ERR_ASN1_BOOLEAN_INVALID_LENGTH
- .get(peekLength);
- throw DecodeException.fatalError(message);
- }
-
- final int readByte = in.read();
- if (readByte == -1)
- {
- final LocalizableMessage message = ERR_ASN1_BOOLEAN_TRUNCATED_VALUE
- .get(peekLength);
- throw DecodeException.fatalError(message);
- }
-
- 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)));
- }
-
- state = ELEMENT_READ_STATE_NEED_TYPE;
- return readByte != 0x00;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public void readEndSequence() throws IOException
- {
- if (streamStack.isEmpty())
- {
- final LocalizableMessage message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED
- .get();
- throw new IllegalStateException(message.toString());
- }
-
- // Ignore all unused trailing components.
- final SizeLimitInputStream subSq = (SizeLimitInputStream) in;
- if (subSq.getSizeLimit() - subSq.getBytesRead() > 0)
- {
- if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
- {
- StaticUtils.DEBUG_LOG.fine(String.format(
- "Ignoring %d unused trailing bytes in ASN.1 SEQUENCE", subSq
- .getSizeLimit()
- - subSq.getBytesRead()));
- }
-
- subSq.skip(subSq.getSizeLimit() - subSq.getBytesRead());
- }
-
- if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
- {
- StaticUtils.DEBUG_LOG.finest(String.format("READ ASN.1 END SEQUENCE"));
- }
-
- in = streamStack.removeFirst();
-
- // Reset the state
- state = ELEMENT_READ_STATE_NEED_TYPE;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public void readEndSet() throws IOException
- {
- // From an implementation point of view, a set is equivalent to a
- // sequence.
- readEndSequence();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public int readEnumerated() throws IOException
- {
- // Read the header if haven't done so already
- peekLength();
-
- if ((peekLength < 1) || (peekLength > 4))
- {
- final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH
- .get(peekLength);
- throw DecodeException.fatalError(message);
- }
-
- // From an implementation point of view, an enumerated value is
- // equivalent to an integer.
- return (int) readInteger();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public long readInteger() throws IOException
- {
- // Read the header if haven't done so already
- peekLength();
-
- if ((peekLength < 1) || (peekLength > 8))
- {
- final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH
- .get(peekLength);
- throw DecodeException.fatalError(message);
- }
-
- if (peekLength > 4)
- {
- long longValue = 0;
- for (int i = 0; i < peekLength; i++)
- {
- final int readByte = in.read();
- if (readByte == -1)
- {
- final LocalizableMessage message = ERR_ASN1_INTEGER_TRUNCATED_VALUE
- .get(peekLength);
- throw DecodeException.fatalError(message);
+ /**
+ * {@inheritDoc}
+ */
+ public boolean elementAvailable() throws IOException {
+ if ((state == ELEMENT_READ_STATE_NEED_TYPE) && !needTypeState(false, false)) {
+ return false;
}
- if ((i == 0) && (((byte) readByte) < 0))
- {
- longValue = 0xFFFFFFFFFFFFFFFFL;
+ if ((state == ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE)
+ && !needFirstLengthByteState(false, false)) {
+ return false;
}
- longValue = (longValue << 8) | (readByte & 0xFF);
- }
-
- state = ELEMENT_READ_STATE_NEED_TYPE;
- return longValue;
- }
- else
- {
- int intValue = 0;
- for (int i = 0; i < peekLength; i++)
- {
- final int readByte = in.read();
- if (readByte == -1)
- {
- final LocalizableMessage message = ERR_ASN1_INTEGER_TRUNCATED_VALUE
- .get(peekLength);
- throw DecodeException.fatalError(message);
+ if ((state == ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES)
+ && !needAdditionalLengthBytesState(false, false)) {
+ return false;
}
- if ((i == 0) && (((byte) readByte) < 0))
- {
- intValue = 0xFFFFFFFF;
+
+ return peekLength <= in.available();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasNextElement() throws IOException {
+ if (!streamStack.isEmpty()) {
+ // We are reading a sub sequence. Return true as long as we
+ // haven't exhausted the size limit for the sub sequence sub input
+ // stream.
+ final SizeLimitInputStream subSq = (SizeLimitInputStream) in;
+ return (subSq.getSizeLimit() - subSq.getBytesRead() > 0);
}
- intValue = (intValue << 8) | (readByte & 0xFF);
- }
- 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));
- }
-
- state = ELEMENT_READ_STATE_NEED_TYPE;
- return intValue;
- }
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public void readNull() throws IOException
- {
- // Read the header if haven't done so already
- peekLength();
-
- // Make sure that the decoded length is exactly zero byte.
- if (peekLength != 0)
- {
- final LocalizableMessage message = ERR_ASN1_NULL_INVALID_LENGTH
- .get(peekLength);
- throw DecodeException.fatalError(message);
+ return (state != ELEMENT_READ_STATE_NEED_TYPE) || needTypeState(true, false);
}
- if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
- {
- StaticUtils.DEBUG_LOG.finest(String.format(
- "READ ASN.1 NULL(type=0x%x, length=%d)", peekType, peekLength));
- }
+ /**
+ * {@inheritDoc}
+ */
+ public int peekLength() throws IOException {
+ peekType();
- state = ELEMENT_READ_STATE_NEED_TYPE;
- }
+ switch (state) {
+ case ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE:
+ needFirstLengthByteState(true, true);
+ break;
-
-
- /**
- * {@inheritDoc}
- */
- public ByteString readOctetString() throws IOException
- {
- // Read the header if haven't done so already
- peekLength();
-
- if (peekLength == 0)
- {
- state = ELEMENT_READ_STATE_NEED_TYPE;
- return ByteString.empty();
- }
-
- // Copy the value and construct the element to return.
- final byte[] value = new byte[peekLength];
- int bytesNeeded = peekLength;
- int bytesRead;
- while (bytesNeeded > 0)
- {
- bytesRead = in.read(value, peekLength - bytesNeeded, bytesNeeded);
- if (bytesRead < 0)
- {
- final LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE
- .get(peekLength);
- throw DecodeException.fatalError(message);
- }
-
- bytesNeeded -= bytesRead;
- }
-
- if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
- {
- StaticUtils.DEBUG_LOG
- .finest(String.format("READ ASN.1 OCTETSTRING(type=0x%x, length=%d)",
- peekType, peekLength));
- }
-
- state = ELEMENT_READ_STATE_NEED_TYPE;
- return ByteString.wrap(value);
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public ByteStringBuilder readOctetString(final ByteStringBuilder builder)
- throws IOException
- {
- // Read the header if haven't done so already
- peekLength();
-
- if (peekLength == 0)
- {
- state = ELEMENT_READ_STATE_NEED_TYPE;
- return builder;
- }
-
- // Copy the value and construct the element to return.
- int bytesNeeded = peekLength;
- int bytesRead;
- while (bytesNeeded > 0)
- {
- bytesRead = builder.append(in, bytesNeeded);
- if (bytesRead < 0)
- {
- final LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE
- .get(peekLength);
- throw DecodeException.fatalError(message);
- }
- bytesNeeded -= bytesRead;
- }
-
- if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
- {
- StaticUtils.DEBUG_LOG
- .finest(String.format("READ ASN.1 OCTETSTRING(type=0x%x, length=%d)",
- peekType, peekLength));
- }
-
- state = ELEMENT_READ_STATE_NEED_TYPE;
- return builder;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public String readOctetStringAsString() throws IOException
- {
- // Read the header if haven't done so already
- peekLength();
-
- if (peekLength == 0)
- {
- state = ELEMENT_READ_STATE_NEED_TYPE;
- return "";
- }
-
- // Resize the temp buffer if needed
- if (peekLength > buffer.length)
- {
- buffer = new byte[peekLength];
- }
-
- int bytesNeeded = peekLength;
- int bytesRead;
- while (bytesNeeded > 0)
- {
- bytesRead = in.read(buffer, peekLength - bytesNeeded, bytesNeeded);
- if (bytesRead < 0)
- {
- final LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE
- .get(peekLength);
- throw DecodeException.fatalError(message);
- }
- bytesNeeded -= bytesRead;
- }
-
- state = ELEMENT_READ_STATE_NEED_TYPE;
-
- String str;
- try
- {
- str = new String(buffer, 0, peekLength, "UTF-8");
- }
- catch (final Exception e)
- {
- if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING))
- {
- StaticUtils.DEBUG_LOG.warning("Unable to decode ASN.1 OCTETSTRING "
- + "bytes as UTF-8 string: " + e.toString());
- }
-
- str = new String(buffer, 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));
- }
-
- return str;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public void readStartSequence() throws IOException
- {
- // Read the header if haven't done so already
- peekLength();
-
- final SizeLimitInputStream subStream = new SizeLimitInputStream(in,
- peekLength);
-
- if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
- {
- StaticUtils.DEBUG_LOG.finest(String.format(
- "READ ASN.1 START SEQUENCE(type=0x%x, length=%d)", peekType,
- peekLength));
- }
-
- streamStack.addFirst(in);
- in = subStream;
-
- // Reset the state
- state = ELEMENT_READ_STATE_NEED_TYPE;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public void readStartSet() throws IOException
- {
- // From an implementation point of view, a set is equivalent to a
- // sequence.
- readStartSequence();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public ASN1Reader skipElement() throws IOException
- {
- // Read the header if haven't done so already
- peekLength();
-
- final long bytesSkipped = in.skip(peekLength);
- if (bytesSkipped != peekLength)
- {
- final LocalizableMessage message = ERR_ASN1_SKIP_TRUNCATED_VALUE
- .get(peekLength);
- throw DecodeException.fatalError(message);
- }
- state = ELEMENT_READ_STATE_NEED_TYPE;
- return this;
- }
-
-
-
- /**
- * Internal helper method reading the additional ASN.1 length bytes and
- * transition to the next state if successful.
- *
- * @param isBlocking
- * <code>true</code> to block if the type byte is not available or
- * <code>false</code> to check for availability first.
- * @param throwEofException
- * <code>true</code> to throw an exception when an EOF is encountered
- * or <code>false</code> to return false.
- * @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(final boolean isBlocking,
- final boolean throwEofException) throws IOException
- {
- if (!isBlocking && (in.available() < lengthBytesNeeded))
- {
- return false;
- }
-
- int readByte;
- while (lengthBytesNeeded > 0)
- {
- readByte = in.read();
- if (readByte == -1)
- {
- state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
- if (throwEofException)
- {
- final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTES
- .get(lengthBytesNeeded);
- throw DecodeException.fatalError(message);
+ case ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES:
+ needAdditionalLengthBytesState(true, true);
}
- return false;
- }
- peekLength = (peekLength << 8) | (readByte & 0xFF);
- lengthBytesNeeded--;
+
+ return peekLength;
}
- // Make sure that the element is not larger than the maximum allowed
- // message size.
- if ((maxElementSize > 0) && (peekLength > maxElementSize))
- {
- final LocalizableMessage message = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED
- .get(peekLength, maxElementSize);
- throw DecodeException.fatalError(message);
- }
- state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
- return true;
- }
+ /**
+ * {@inheritDoc}
+ */
+ public byte peekType() throws IOException {
+ if (state == ELEMENT_READ_STATE_NEED_TYPE) {
+ needTypeState(true, true);
+ }
-
-
- /**
- * Internal helper method reading the first length bytes and transition to the
- * next state if successful.
- *
- * @param isBlocking
- * <code>true</code> to block if the type byte is not available or
- * <code>false</code> to check for availability first.
- * @param throwEofException
- * <code>true</code> to throw an exception when an EOF is encountered
- * or <code>false</code> to return false.
- * @return <code>true</code> if the length bytes was successfully read
- * @throws IOException
- * If an error occurs while reading from the stream.
- */
- private boolean needFirstLengthByteState(final boolean isBlocking,
- final boolean throwEofException) throws IOException
- {
- if (!isBlocking && (in.available() <= 0))
- {
- return false;
+ return peekType;
}
- int readByte = in.read();
- if (readByte == -1)
- {
- if (throwEofException)
- {
- final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get();
- throw DecodeException.fatalError(message);
- }
- return false;
- }
- peekLength = (readByte & 0x7F);
- if (peekLength != readByte)
- {
- lengthBytesNeeded = peekLength;
- if (lengthBytesNeeded > 4)
- {
- final LocalizableMessage message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES
- .get(lengthBytesNeeded);
- throw DecodeException.fatalError(message);
- }
- peekLength = 0x00;
+ /**
+ * {@inheritDoc}
+ */
+ public boolean readBoolean() throws IOException {
+ // Read the header if haven't done so already
+ peekLength();
- if (!isBlocking && (in.available() < lengthBytesNeeded))
- {
- state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
- return false;
- }
-
- while (lengthBytesNeeded > 0)
- {
- readByte = in.read();
- if (readByte == -1)
- {
- state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
- if (throwEofException)
- {
- final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTES
- .get(lengthBytesNeeded);
+ if (peekLength != 1) {
+ final LocalizableMessage message = ERR_ASN1_BOOLEAN_INVALID_LENGTH.get(peekLength);
throw DecodeException.fatalError(message);
- }
- return false;
}
- peekLength = (peekLength << 8) | (readByte & 0xFF);
- lengthBytesNeeded--;
- }
+
+ final int readByte = in.read();
+ if (readByte == -1) {
+ final LocalizableMessage message = ERR_ASN1_BOOLEAN_TRUNCATED_VALUE.get(peekLength);
+ throw DecodeException.fatalError(message);
+ }
+
+ 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)));
+ }
+
+ state = ELEMENT_READ_STATE_NEED_TYPE;
+ return readByte != 0x00;
}
- // Make sure that the element is not larger than the maximum allowed
- // message size.
- if ((maxElementSize > 0) && (peekLength > maxElementSize))
- {
- final LocalizableMessage message = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED
- .get(peekLength, maxElementSize);
- throw DecodeException.fatalError(message);
- }
- state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
- return true;
- }
+ /**
+ * {@inheritDoc}
+ */
+ public void readEndSequence() throws IOException {
+ if (streamStack.isEmpty()) {
+ final LocalizableMessage message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED.get();
+ throw new IllegalStateException(message.toString());
+ }
+ // Ignore all unused trailing components.
+ final SizeLimitInputStream subSq = (SizeLimitInputStream) in;
+ if (subSq.getSizeLimit() - subSq.getBytesRead() > 0) {
+ if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE)) {
+ StaticUtils.DEBUG_LOG.fine(String.format(
+ "Ignoring %d unused trailing bytes in ASN.1 SEQUENCE", subSq.getSizeLimit()
+ - subSq.getBytesRead()));
+ }
+ subSq.skip(subSq.getSizeLimit() - subSq.getBytesRead());
+ }
- /**
- * Internal helper method reading the ASN.1 type byte and transition to the
- * next state if successful.
- *
- * @param isBlocking
- * <code>true</code> to block if the type byte is not available or
- * <code>false</code> to check for availability first.
- * @param throwEofException
- * <code>true</code> to throw an exception when an EOF is encountered
- * or <code>false</code> to return false.
- * @return <code>true</code> if the type byte was successfully read
- * @throws IOException
- * If an error occurs while reading from the stream.
- */
- private boolean needTypeState(final boolean isBlocking,
- final boolean throwEofException) throws IOException
- {
- // Read just the type.
- if (!isBlocking && (in.available() <= 0))
- {
- return false;
+ if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) {
+ StaticUtils.DEBUG_LOG.finest(String.format("READ ASN.1 END SEQUENCE"));
+ }
+
+ in = streamStack.removeFirst();
+
+ // Reset the state
+ state = ELEMENT_READ_STATE_NEED_TYPE;
}
- final int type = in.read();
- if (type == -1)
- {
- if (throwEofException)
- {
- final LocalizableMessage message = ERR_ASN1_TRUCATED_TYPE_BYTE.get();
- throw DecodeException.fatalError(message);
- }
- return false;
+ /**
+ * {@inheritDoc}
+ */
+ public void readEndSet() throws IOException {
+ // From an implementation point of view, a set is equivalent to a
+ // sequence.
+ readEndSequence();
}
- peekType = (byte) type;
- state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
- return true;
- }
+ /**
+ * {@inheritDoc}
+ */
+ public int readEnumerated() throws IOException {
+ // Read the header if haven't done so already
+ peekLength();
+
+ if ((peekLength < 1) || (peekLength > 4)) {
+ final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH.get(peekLength);
+ throw DecodeException.fatalError(message);
+ }
+
+ // From an implementation point of view, an enumerated value is
+ // equivalent to an integer.
+ return (int) readInteger();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long readInteger() throws IOException {
+ // Read the header if haven't done so already
+ peekLength();
+
+ if ((peekLength < 1) || (peekLength > 8)) {
+ final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH.get(peekLength);
+ throw DecodeException.fatalError(message);
+ }
+
+ if (peekLength > 4) {
+ long longValue = 0;
+ for (int i = 0; i < peekLength; i++) {
+ final int readByte = in.read();
+ if (readByte == -1) {
+ final LocalizableMessage message =
+ ERR_ASN1_INTEGER_TRUNCATED_VALUE.get(peekLength);
+ throw DecodeException.fatalError(message);
+ }
+ if ((i == 0) && (((byte) readByte) < 0)) {
+ longValue = 0xFFFFFFFFFFFFFFFFL;
+ }
+ longValue = (longValue << 8) | (readByte & 0xFF);
+ }
+
+ state = ELEMENT_READ_STATE_NEED_TYPE;
+ return longValue;
+ } else {
+ int intValue = 0;
+ for (int i = 0; i < peekLength; i++) {
+ final int readByte = in.read();
+ if (readByte == -1) {
+ final LocalizableMessage message =
+ ERR_ASN1_INTEGER_TRUNCATED_VALUE.get(peekLength);
+ throw DecodeException.fatalError(message);
+ }
+ if ((i == 0) && (((byte) readByte) < 0)) {
+ intValue = 0xFFFFFFFF;
+ }
+ intValue = (intValue << 8) | (readByte & 0xFF);
+ }
+
+ 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));
+ }
+
+ state = ELEMENT_READ_STATE_NEED_TYPE;
+ return intValue;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void readNull() throws IOException {
+ // Read the header if haven't done so already
+ peekLength();
+
+ // Make sure that the decoded length is exactly zero byte.
+ if (peekLength != 0) {
+ 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));
+ }
+
+ state = ELEMENT_READ_STATE_NEED_TYPE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ByteString readOctetString() throws IOException {
+ // Read the header if haven't done so already
+ peekLength();
+
+ if (peekLength == 0) {
+ state = ELEMENT_READ_STATE_NEED_TYPE;
+ return ByteString.empty();
+ }
+
+ // Copy the value and construct the element to return.
+ final byte[] value = new byte[peekLength];
+ int bytesNeeded = peekLength;
+ int bytesRead;
+ while (bytesNeeded > 0) {
+ bytesRead = in.read(value, peekLength - bytesNeeded, bytesNeeded);
+ if (bytesRead < 0) {
+ final LocalizableMessage message =
+ ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE.get(peekLength);
+ throw DecodeException.fatalError(message);
+ }
+
+ bytesNeeded -= bytesRead;
+ }
+
+ if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) {
+ StaticUtils.DEBUG_LOG.finest(String.format(
+ "READ ASN.1 OCTETSTRING(type=0x%x, length=%d)", peekType, peekLength));
+ }
+
+ state = ELEMENT_READ_STATE_NEED_TYPE;
+ return ByteString.wrap(value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ByteStringBuilder readOctetString(final ByteStringBuilder builder) throws IOException {
+ // Read the header if haven't done so already
+ peekLength();
+
+ if (peekLength == 0) {
+ state = ELEMENT_READ_STATE_NEED_TYPE;
+ return builder;
+ }
+
+ // Copy the value and construct the element to return.
+ int bytesNeeded = peekLength;
+ int bytesRead;
+ while (bytesNeeded > 0) {
+ bytesRead = builder.append(in, bytesNeeded);
+ if (bytesRead < 0) {
+ final LocalizableMessage message =
+ ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE.get(peekLength);
+ throw DecodeException.fatalError(message);
+ }
+ bytesNeeded -= bytesRead;
+ }
+
+ if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) {
+ StaticUtils.DEBUG_LOG.finest(String.format(
+ "READ ASN.1 OCTETSTRING(type=0x%x, length=%d)", peekType, peekLength));
+ }
+
+ state = ELEMENT_READ_STATE_NEED_TYPE;
+ return builder;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String readOctetStringAsString() throws IOException {
+ // Read the header if haven't done so already
+ peekLength();
+
+ if (peekLength == 0) {
+ state = ELEMENT_READ_STATE_NEED_TYPE;
+ return "";
+ }
+
+ // Resize the temp buffer if needed
+ if (peekLength > buffer.length) {
+ buffer = new byte[peekLength];
+ }
+
+ int bytesNeeded = peekLength;
+ int bytesRead;
+ while (bytesNeeded > 0) {
+ bytesRead = in.read(buffer, peekLength - bytesNeeded, bytesNeeded);
+ if (bytesRead < 0) {
+ final LocalizableMessage message =
+ ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE.get(peekLength);
+ throw DecodeException.fatalError(message);
+ }
+ bytesNeeded -= bytesRead;
+ }
+
+ state = ELEMENT_READ_STATE_NEED_TYPE;
+
+ String str;
+ try {
+ str = new String(buffer, 0, peekLength, "UTF-8");
+ } catch (final Exception e) {
+ if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING)) {
+ StaticUtils.DEBUG_LOG.warning("Unable to decode ASN.1 OCTETSTRING "
+ + "bytes as UTF-8 string: " + e.toString());
+ }
+
+ str = new String(buffer, 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));
+ }
+
+ return str;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void readStartSequence() throws IOException {
+ // Read the header if haven't done so already
+ peekLength();
+
+ final SizeLimitInputStream subStream = new SizeLimitInputStream(in, peekLength);
+
+ if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) {
+ StaticUtils.DEBUG_LOG.finest(String.format(
+ "READ ASN.1 START SEQUENCE(type=0x%x, length=%d)", peekType, peekLength));
+ }
+
+ streamStack.addFirst(in);
+ in = subStream;
+
+ // Reset the state
+ state = ELEMENT_READ_STATE_NEED_TYPE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void readStartSet() throws IOException {
+ // From an implementation point of view, a set is equivalent to a
+ // sequence.
+ readStartSequence();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ASN1Reader skipElement() throws IOException {
+ // Read the header if haven't done so already
+ peekLength();
+
+ final long bytesSkipped = in.skip(peekLength);
+ if (bytesSkipped != peekLength) {
+ final LocalizableMessage message = ERR_ASN1_SKIP_TRUNCATED_VALUE.get(peekLength);
+ throw DecodeException.fatalError(message);
+ }
+ state = ELEMENT_READ_STATE_NEED_TYPE;
+ return this;
+ }
+
+ /**
+ * Internal helper method reading the additional ASN.1 length bytes and
+ * transition to the next state if successful.
+ *
+ * @param isBlocking
+ * <code>true</code> to block if the type byte is not available
+ * or <code>false</code> to check for availability first.
+ * @param throwEofException
+ * <code>true</code> to throw an exception when an EOF is
+ * encountered or <code>false</code> to return false.
+ * @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(final boolean isBlocking,
+ final boolean throwEofException) throws IOException {
+ if (!isBlocking && (in.available() < lengthBytesNeeded)) {
+ return false;
+ }
+
+ int readByte;
+ while (lengthBytesNeeded > 0) {
+ readByte = in.read();
+ if (readByte == -1) {
+ state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
+ if (throwEofException) {
+ final LocalizableMessage message =
+ ERR_ASN1_TRUNCATED_LENGTH_BYTES.get(lengthBytesNeeded);
+ throw DecodeException.fatalError(message);
+ }
+ return false;
+ }
+ peekLength = (peekLength << 8) | (readByte & 0xFF);
+ lengthBytesNeeded--;
+ }
+
+ // Make sure that the element is not larger than the maximum allowed
+ // message size.
+ if ((maxElementSize > 0) && (peekLength > maxElementSize)) {
+ final LocalizableMessage message =
+ ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED
+ .get(peekLength, maxElementSize);
+ throw DecodeException.fatalError(message);
+ }
+ state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
+ return true;
+ }
+
+ /**
+ * Internal helper method reading the first length bytes and transition to
+ * the next state if successful.
+ *
+ * @param isBlocking
+ * <code>true</code> to block if the type byte is not available
+ * or <code>false</code> to check for availability first.
+ * @param throwEofException
+ * <code>true</code> to throw an exception when an EOF is
+ * encountered or <code>false</code> to return false.
+ * @return <code>true</code> if the length bytes was successfully read
+ * @throws IOException
+ * If an error occurs while reading from the stream.
+ */
+ private boolean needFirstLengthByteState(final boolean isBlocking,
+ final boolean throwEofException) throws IOException {
+ if (!isBlocking && (in.available() <= 0)) {
+ return false;
+ }
+
+ int readByte = in.read();
+ if (readByte == -1) {
+ if (throwEofException) {
+ final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get();
+ throw DecodeException.fatalError(message);
+ }
+ return false;
+ }
+ peekLength = (readByte & 0x7F);
+ if (peekLength != readByte) {
+ lengthBytesNeeded = peekLength;
+ if (lengthBytesNeeded > 4) {
+ final LocalizableMessage message =
+ ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(lengthBytesNeeded);
+ throw DecodeException.fatalError(message);
+ }
+ peekLength = 0x00;
+
+ if (!isBlocking && (in.available() < lengthBytesNeeded)) {
+ state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
+ return false;
+ }
+
+ while (lengthBytesNeeded > 0) {
+ readByte = in.read();
+ if (readByte == -1) {
+ state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
+ if (throwEofException) {
+ final LocalizableMessage message =
+ ERR_ASN1_TRUNCATED_LENGTH_BYTES.get(lengthBytesNeeded);
+ throw DecodeException.fatalError(message);
+ }
+ return false;
+ }
+ peekLength = (peekLength << 8) | (readByte & 0xFF);
+ lengthBytesNeeded--;
+ }
+ }
+
+ // Make sure that the element is not larger than the maximum allowed
+ // message size.
+ if ((maxElementSize > 0) && (peekLength > maxElementSize)) {
+ final LocalizableMessage message =
+ ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED
+ .get(peekLength, maxElementSize);
+ throw DecodeException.fatalError(message);
+ }
+ state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
+ return true;
+ }
+
+ /**
+ * Internal helper method reading the ASN.1 type byte and transition to the
+ * next state if successful.
+ *
+ * @param isBlocking
+ * <code>true</code> to block if the type byte is not available
+ * or <code>false</code> to check for availability first.
+ * @param throwEofException
+ * <code>true</code> to throw an exception when an EOF is
+ * encountered or <code>false</code> to return false.
+ * @return <code>true</code> if the type byte was successfully read
+ * @throws IOException
+ * If an error occurs while reading from the stream.
+ */
+ private boolean needTypeState(final boolean isBlocking, final boolean throwEofException)
+ throws IOException {
+ // Read just the type.
+ if (!isBlocking && (in.available() <= 0)) {
+ return false;
+ }
+
+ final int type = in.read();
+ if (type == -1) {
+ if (throwEofException) {
+ final LocalizableMessage message = ERR_ASN1_TRUCATED_TYPE_BYTE.get();
+ throw DecodeException.fatalError(message);
+ }
+ return false;
+ }
+
+ peekType = (byte) type;
+ state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
+ return true;
+ }
}
--
Gitblit v1.10.0