001 /* 002 * Copyright 2008-2015 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005 /* 006 * Copyright (C) 2008-2015 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 }