001 /*
002 * Copyright 2008-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2014 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.asn1;
022
023
024
025 import java.io.IOException;
026 import java.io.OutputStream;
027 import java.nio.BufferOverflowException;
028 import java.nio.ByteBuffer;
029
030 import com.unboundid.util.ByteStringBuffer;
031
032 import static com.unboundid.util.Debug.*;
033
034
035
036 /**
037 * This class provides an efficient mechanism for writing ASN.1 elements to
038 * output streams.
039 */
040 public final class ASN1Writer
041 {
042 /**
043 * The thread-local buffers that will be used for encoding the elements.
044 */
045 private static final ThreadLocal<ByteStringBuffer> buffers =
046 new ThreadLocal<ByteStringBuffer>();
047
048
049
050 /**
051 * The maximum amount of memory that will be used for a thread-local buffer.
052 */
053 private static final int MAX_BUFFER_LENGTH = 524288;
054
055
056
057 /**
058 * Prevent this class from being instantiated.
059 */
060 private ASN1Writer()
061 {
062 // No implementation is required.
063 }
064
065
066
067 /**
068 * Writes an encoded representation of the provided ASN.1 element to the
069 * given output stream.
070 *
071 * @param element The ASN.1 element to be written.
072 * @param outputStream The output stream to which the encoded representation
073 * of the element should be written.
074 *
075 * @throws IOException If a problem occurs while writing the element.
076 */
077 public static void writeElement(final ASN1Element element,
078 final OutputStream outputStream)
079 throws IOException
080 {
081 debugASN1Write(element);
082
083 ByteStringBuffer buffer = buffers.get();
084 if (buffer == null)
085 {
086 buffer = new ByteStringBuffer();
087 buffers.set(buffer);
088 }
089
090 element.encodeTo(buffer);
091
092 try
093 {
094 buffer.write(outputStream);
095 }
096 finally
097 {
098 if (buffer.capacity() > MAX_BUFFER_LENGTH)
099 {
100 buffer.setCapacity(MAX_BUFFER_LENGTH);
101 }
102 buffer.clear();
103 }
104 }
105
106
107
108 /**
109 * Appends an encoded representation of the provided ASN.1 element to the
110 * given byte buffer. When this method completes, the position will be at the
111 * beginning of the written element, and the limit will be at the end.
112 *
113 * @param element The ASN.1 element to be written.
114 * @param buffer The buffer to which the element should be added.
115 *
116 * @throws BufferOverflowException If the provided buffer does not have
117 * enough space between the position and
118 * the limit to hold the encoded element.
119 */
120 public static void writeElement(final ASN1Element element,
121 final ByteBuffer buffer)
122 throws BufferOverflowException
123 {
124 debugASN1Write(element);
125
126 ByteStringBuffer b = buffers.get();
127 if (b == null)
128 {
129 b = new ByteStringBuffer();
130 buffers.set(b);
131 }
132
133 element.encodeTo(b);
134
135 try
136 {
137 if (buffer.remaining() < b.length())
138 {
139 throw new BufferOverflowException();
140 }
141
142 final int pos = buffer.position();
143 buffer.put(b.getBackingArray(), 0, b.length());
144 buffer.limit(buffer.position());
145 buffer.position(pos);
146 }
147 finally
148 {
149 if (b.capacity() > MAX_BUFFER_LENGTH)
150 {
151 b.setCapacity(MAX_BUFFER_LENGTH);
152 }
153 b.clear();
154 }
155 }
156 }