opendj-core/src/main/java/org/forgerock/opendj/io/ASN1.java
@@ -45,6 +45,12 @@ public final class ASN1 { /** * Maximum buffer size when reading ASN1. Buffers above this threshold will * be discarded for garbage collection to avoid OutOfMemoryErrors. */ private static final int DEFAULT_MAX_BUFFER_SIZE = 32 * 1024; /** * The byte array containing the pre-encoded ASN.1 encoding for a boolean * value of "false". */ @@ -62,14 +68,18 @@ public static final byte UNIVERSAL_BOOLEAN_TYPE = 0x01; /** * The BER type that is assigned to the universal enumerated type. */ public static final byte UNIVERSAL_ENUMERATED_TYPE = 0x0A; /** * The BER type that is assigned to the universal integer type. */ public static final byte UNIVERSAL_INTEGER_TYPE = 0x02; /** * The BER type that is assigned to the universal bit string type. */ public static final byte UNIVERSAL_BIT_STRING_TYPE = 0x03; /** * The BER type that is assigned to the universal octet string type. */ public static final byte UNIVERSAL_OCTET_STRING_TYPE = 0x04; /** * The BER type that is assigned to the universal null type. @@ -77,9 +87,9 @@ public static final byte UNIVERSAL_NULL_TYPE = 0x05; /** * The BER type that is assigned to the universal octet string type. * The BER type that is assigned to the universal enumerated type. */ public static final byte UNIVERSAL_OCTET_STRING_TYPE = 0x04; public static final byte UNIVERSAL_ENUMERATED_TYPE = 0x0A; /** * The BER type that is assigned to the universal sequence type. @@ -139,12 +149,12 @@ * The bitmask that can be ANDed with the BER type to determine if the * element is constructed. */ static final byte TYPE_MASK_CONSTRUCTED = 0x20; public static final byte TYPE_MASK_CONSTRUCTED = 0x20; /** * The bitmask that can be ANDed with the BER type to determine if the * element is in the context-specific class. */ static final byte TYPE_MASK_CONTEXT = (byte) 0x80; public static final byte TYPE_MASK_CONTEXT = (byte) 0x80; /** * The bitmask that can be ANDed with the BER type to determine if the * element is a primitive. @@ -278,7 +288,22 @@ * @return The new ASN.1 writer. */ public static ASN1Writer getWriter(final ByteStringBuilder builder) { return getWriter(builder.asOutputStream()); return getWriter(builder.asOutputStream(), DEFAULT_MAX_BUFFER_SIZE); } /** * Returns an ASN.1 writer whose destination is the provided byte string * builder. * * @param builder * The output stream to use. * @param maxBufferSize * The threshold capacity beyond which internal cached buffers used * for encoding and decoding ASN1 will be trimmed after use. * @return The new ASN.1 writer. */ public static ASN1Writer getWriter(final ByteStringBuilder builder, final int maxBufferSize) { return getWriter(builder.asOutputStream(), maxBufferSize); } /** @@ -289,7 +314,21 @@ * @return The new ASN.1 writer. */ public static ASN1Writer getWriter(final OutputStream stream) { return new ASN1OutputStreamWriter(stream); return getWriter(stream, DEFAULT_MAX_BUFFER_SIZE); } /** * Returns an ASN.1 writer whose destination is the provided output stream. * * @param stream * The output stream to use. * @param maxBufferSize * The threshold capacity beyond which internal cached buffers used * for encoding and decoding ASN1 will be trimmed after use. * @return The new ASN.1 writer. */ public static ASN1Writer getWriter(final OutputStream stream, final int maxBufferSize) { return new ASN1OutputStreamWriter(stream, maxBufferSize); } // Prevent instantiation. opendj-core/src/main/java/org/forgerock/opendj/io/ASN1ByteSequenceReader.java
@@ -174,6 +174,12 @@ state = ASN1.ELEMENT_READ_STATE_NEED_TYPE; } /** {@inheritDoc} */ @Override public void readEndExplicitTag() throws DecodeException, IOException { readEndSequence(); } /** * {@inheritDoc} */ @@ -333,6 +339,12 @@ state = ASN1.ELEMENT_READ_STATE_NEED_TYPE; } /** {@inheritDoc} */ @Override public void readStartExplicitTag() throws DecodeException, IOException { readStartSequence(); } /** * {@inheritDoc} */ opendj-core/src/main/java/org/forgerock/opendj/io/ASN1InputStreamReader.java
@@ -206,6 +206,12 @@ state = ASN1.ELEMENT_READ_STATE_NEED_TYPE; } /** {@inheritDoc} */ @Override public void readEndExplicitTag() throws DecodeException, IOException { readEndSequence(); } /** * {@inheritDoc} */ @@ -429,6 +435,12 @@ state = ASN1.ELEMENT_READ_STATE_NEED_TYPE; } /** {@inheritDoc} */ @Override public void readStartExplicitTag() throws DecodeException, IOException { readStartSequence(); } /** * {@inheritDoc} */ opendj-core/src/main/java/org/forgerock/opendj/io/ASN1OutputStreamWriter.java
@@ -42,21 +42,26 @@ /** * An ASN1Writer implementation that outputs to an outputstream. */ final class ASN1OutputStreamWriter extends AbstractASN1Writer implements ASN1Writer { final class ASN1OutputStreamWriter extends AbstractASN1Writer { private final OutputStream rootStream; private OutputStream out; private final ArrayList<ByteStringBuilder> streamStack; private int stackDepth; private final int maxBufferSize; /** * Creates a new ASN.1 output stream reader. * * @param stream * The underlying output stream. * @param maxBufferSize * The threshold capacity beyond which internal cached buffers used * for encoding and decoding ASN1 will be trimmed after use. */ ASN1OutputStreamWriter(final OutputStream stream) { ASN1OutputStreamWriter(final OutputStream stream, final int maxBufferSize) { this.out = stream; this.rootStream = stream; this.maxBufferSize = maxBufferSize; this.streamStack = new ArrayList<ByteStringBuilder>(); this.stackDepth = -1; } @@ -64,6 +69,7 @@ /** * {@inheritDoc} */ @Override public void close() throws IOException { while (stackDepth >= 0) { writeEndSequence(); @@ -76,6 +82,7 @@ /** * {@inheritDoc} */ @Override public void flush() throws IOException { rootStream.flush(); } @@ -83,6 +90,7 @@ /** * {@inheritDoc} */ @Override public ASN1Writer writeBoolean(final byte type, final boolean booleanValue) throws IOException { out.write(type); writeLength(1); @@ -96,6 +104,7 @@ /** * {@inheritDoc} */ @Override public ASN1Writer writeEndSequence() throws IOException { if (stackDepth < 0) { final LocalizableMessage message = ERR_ASN1_SEQUENCE_WRITE_NOT_STARTED.get(); @@ -118,13 +127,19 @@ IO_LOG.trace("WRITE ASN.1 END SEQUENCE(length={})", childStream.length()); childStream.clear(); if (childStream.capacity() > maxBufferSize) { // garbage collect excessively large buffers childStream.clear(maxBufferSize); } else { childStream.clear(); } return this; } /** * {@inheritDoc} */ @Override public ASN1Writer writeEndSet() throws IOException { return writeEndSequence(); } @@ -132,6 +147,7 @@ /** * {@inheritDoc} */ @Override public ASN1Writer writeEnumerated(final byte type, final int intValue) throws IOException { return writeInteger(type, intValue); } @@ -139,6 +155,7 @@ /** * {@inheritDoc} */ @Override public ASN1Writer writeInteger(final byte type, final int intValue) throws IOException { out.write(type); if (((intValue < 0) && ((intValue & 0xFFFFFF80) == 0xFFFFFF80)) @@ -173,6 +190,7 @@ /** * {@inheritDoc} */ @Override public ASN1Writer writeInteger(final byte type, final long longValue) throws IOException { out.write(type); if (((longValue < 0) && ((longValue & 0xFFFFFFFFFFFFFF80L) == 0xFFFFFFFFFFFFFF80L)) @@ -249,6 +267,7 @@ /** * {@inheritDoc} */ @Override public ASN1Writer writeNull(final byte type) throws IOException { out.write(type); writeLength(0); @@ -260,6 +279,7 @@ /** * {@inheritDoc} */ @Override public ASN1Writer writeOctetString(final byte type, final byte[] value, final int offset, final int length) throws IOException { out.write(type); @@ -273,6 +293,7 @@ /** * {@inheritDoc} */ @Override public ASN1Writer writeOctetString(final byte type, final ByteSequence value) throws IOException { out.write(type); @@ -287,6 +308,7 @@ /** * {@inheritDoc} */ @Override public ASN1Writer writeOctetString(final byte type, final String value) throws IOException { out.write(type); @@ -307,6 +329,7 @@ /** * {@inheritDoc} */ @Override public ASN1Writer writeStartSequence(final byte type) throws IOException { // Write the type in current stream switch to next sub-stream out.write(type); @@ -330,6 +353,7 @@ /** * {@inheritDoc} */ @Override public ASN1Writer writeStartSet(final byte type) throws IOException { // From an implementation point of view, a set is equivalent to a // sequence. opendj-core/src/main/java/org/forgerock/opendj/io/ASN1Reader.java
@@ -144,6 +144,19 @@ void readEndSequence() throws DecodeException, IOException; /** * Finishes reading an explicit tag and discards any unread elements. * * @throws DecodeException * If an error occurs while advancing to the end of the * explicit tag. * @throws IOException * If an unexpected IO error occurred. * @throws IllegalStateException * If there is no explicit tag being read. */ void readEndExplicitTag() throws DecodeException, IOException; /** * Finishes reading a set and discards any unread elements. * * @throws DecodeException @@ -325,6 +338,18 @@ void readStartSequence() throws DecodeException, IOException; /** * Reads the next element as an explicit tag having the Universal Sequence * ASN.1 type tag. All further reads will read the elements in the explicit * tag until {@link #readEndExplicitTag()} is called. * * @throws DecodeException * If the element cannot be decoded as an explicit tag. * @throws IOException * If an unexpected IO error occurred. */ void readStartExplicitTag() throws DecodeException, IOException; /** * Reads the next element as a sequence having the provided type tag. All * further reads will read the elements in the sequence until * {@link #readEndSequence()} is called. opendj-core/src/test/java/org/forgerock/opendj/io/ASN1OutputStreamWriterTestCase.java
@@ -34,7 +34,7 @@ */ public class ASN1OutputStreamWriterTestCase extends ASN1WriterTestCase { private final ByteArrayOutputStream outStream = new ByteArrayOutputStream(); private final ASN1Writer writer = new ASN1OutputStreamWriter(outStream); private final ASN1Writer writer = new ASN1OutputStreamWriter(outStream, 1); @Override protected byte[] getEncodedBytes() { opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/ASN1BufferReader.java
@@ -269,6 +269,12 @@ state = ASN1.ELEMENT_READ_STATE_NEED_TYPE; } /** {@inheritDoc} */ @Override public void readEndExplicitTag() throws DecodeException, IOException { readEndSequence(); } /** * {@inheritDoc} */ @@ -462,6 +468,12 @@ state = ASN1.ELEMENT_READ_STATE_NEED_TYPE; } /** {@inheritDoc} */ @Override public void readStartExplicitTag() throws DecodeException, IOException { readStartSequence(); } /** * {@inheritDoc} */