001/* 002 * Copyright 2008-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2017 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 */ 021package com.unboundid.asn1; 022 023 024 025import java.io.IOException; 026import java.io.OutputStream; 027import java.nio.BufferOverflowException; 028import java.nio.ByteBuffer; 029 030import com.unboundid.util.ByteStringBuffer; 031import com.unboundid.util.ThreadSafety; 032import com.unboundid.util.ThreadSafetyLevel; 033 034import static com.unboundid.util.Debug.*; 035 036 037 038/** 039 * This class provides an efficient mechanism for writing ASN.1 elements to 040 * output streams. 041 */ 042@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 043public final class ASN1Writer 044{ 045 /** 046 * The thread-local buffers that will be used for encoding the elements. 047 */ 048 private static final ThreadLocal<ByteStringBuffer> buffers = 049 new ThreadLocal<ByteStringBuffer>(); 050 051 052 053 /** 054 * The maximum amount of memory that will be used for a thread-local buffer. 055 */ 056 private static final int MAX_BUFFER_LENGTH = 524288; 057 058 059 060 /** 061 * Prevent this class from being instantiated. 062 */ 063 private ASN1Writer() 064 { 065 // No implementation is required. 066 } 067 068 069 070 /** 071 * Writes an encoded representation of the provided ASN.1 element to the 072 * given output stream. 073 * 074 * @param element The ASN.1 element to be written. 075 * @param outputStream The output stream to which the encoded representation 076 * of the element should be written. 077 * 078 * @throws IOException If a problem occurs while writing the element. 079 */ 080 public static void writeElement(final ASN1Element element, 081 final OutputStream outputStream) 082 throws IOException 083 { 084 debugASN1Write(element); 085 086 ByteStringBuffer buffer = buffers.get(); 087 if (buffer == null) 088 { 089 buffer = new ByteStringBuffer(); 090 buffers.set(buffer); 091 } 092 093 element.encodeTo(buffer); 094 095 try 096 { 097 buffer.write(outputStream); 098 } 099 finally 100 { 101 if (buffer.capacity() > MAX_BUFFER_LENGTH) 102 { 103 buffer.setCapacity(MAX_BUFFER_LENGTH); 104 } 105 buffer.clear(); 106 } 107 } 108 109 110 111 /** 112 * Appends an encoded representation of the provided ASN.1 element to the 113 * given byte buffer. When this method completes, the position will be at the 114 * beginning of the written element, and the limit will be at the end. 115 * 116 * @param element The ASN.1 element to be written. 117 * @param buffer The buffer to which the element should be added. 118 * 119 * @throws BufferOverflowException If the provided buffer does not have 120 * enough space between the position and 121 * the limit to hold the encoded element. 122 */ 123 public static void writeElement(final ASN1Element element, 124 final ByteBuffer buffer) 125 throws BufferOverflowException 126 { 127 debugASN1Write(element); 128 129 ByteStringBuffer b = buffers.get(); 130 if (b == null) 131 { 132 b = new ByteStringBuffer(); 133 buffers.set(b); 134 } 135 136 element.encodeTo(b); 137 138 try 139 { 140 if (buffer.remaining() < b.length()) 141 { 142 throw new BufferOverflowException(); 143 } 144 145 final int pos = buffer.position(); 146 buffer.put(b.getBackingArray(), 0, b.length()); 147 buffer.limit(buffer.position()); 148 buffer.position(pos); 149 } 150 finally 151 { 152 if (b.capacity() > MAX_BUFFER_LENGTH) 153 { 154 b.setCapacity(MAX_BUFFER_LENGTH); 155 } 156 b.clear(); 157 } 158 } 159}