001/* 002 * Copyright 2010-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2010-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.util; 022 023 024 025import java.io.IOException; 026import java.io.OutputStream; 027import java.io.Serializable; 028 029import static com.unboundid.util.UtilityMessages.*; 030 031 032 033/** 034 * This class provides an {@code OutputStream} implementation that writes data 035 * to a provided byte array. It is similar to the 036 * {@code java.io.ByteArrayOutputStream} class, except that it allows you to 037 * pass in the array that it uses, and the array will not grow over time. 038 */ 039@Mutable() 040@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 041public final class FixedArrayOutputStream 042 extends OutputStream 043 implements Serializable 044{ 045 /** 046 * The serial version UID for this serializable class. 047 */ 048 private static final long serialVersionUID = 4678108653480347534L; 049 050 051 052 // The byte array used by this class. 053 private final byte[] array; 054 055 // The initial position for this array. 056 private final int initialPosition; 057 058 // The maximum number of bytes that may be written. 059 private final int length; 060 061 // The maximum position at which data may be written. 062 private final int maxPosition; 063 064 // The current position at which data may be written. 065 private int pos; 066 067 068 069 /** 070 * Creates a new output stream that will write data to the provided array. 071 * It will use the entire array. 072 * 073 * @param array The array to which data will be written. It must not be 074 * {@code null}. 075 */ 076 public FixedArrayOutputStream(final byte[] array) 077 { 078 this(array, 0, array.length); 079 } 080 081 082 083 /** 084 * Creates a new output stream that will write data to the provided array. 085 * It will use the specified portion of the array. 086 * 087 * @param array The array to which data will be written. It must not be 088 * {@code null}. 089 * @param pos The position at which to start writing data. It must be 090 * greater than or equal to zero and less than or equal to the 091 * length of the array. 092 * @param len The maximum number of bytes that may be written. It must 093 * be greater than or equal to zero and less than or equal to 094 * the difference between the length of the array and the 095 * provided {@code pos} value. 096 */ 097 public FixedArrayOutputStream(final byte[] array, final int pos, 098 final int len) 099 { 100 this.array = array; 101 this.pos = pos; 102 103 initialPosition = pos; 104 maxPosition = pos + len; 105 length = len; 106 107 Validator.ensureTrue((pos >= 0), 108 "The position must be greater than or equal to zero."); 109 Validator.ensureTrue((len >= 0), 110 "The length must be greater than or equal to zero."); 111 Validator.ensureTrue((maxPosition <= array.length), 112 "The sum of pos and len must not exceed the array length."); 113 } 114 115 116 117 /** 118 * Retrieves the backing array used by this output stream. 119 * 120 * @return The backing array used by this output stream. 121 */ 122 public byte[] getBackingArray() 123 { 124 return array; 125 } 126 127 128 129 /** 130 * Retrieves the initial position provided when this output stream was 131 * created. 132 * 133 * @return The initial position provided when this output stream was created. 134 */ 135 public int getInitialPosition() 136 { 137 return initialPosition; 138 } 139 140 141 142 /** 143 * Retrieves the maximum number of bytes that may be written to this output 144 * stream. 145 * 146 * @return The maximum number of bytes that may be written to this output 147 * stream. 148 */ 149 public int getLength() 150 { 151 return length; 152 } 153 154 155 156 /** 157 * Retrieves the number of bytes that have been written so far to this output 158 * stream. 159 * 160 * @return The number of bytes that have been written so far to this output 161 * stream. 162 */ 163 public int getBytesWritten() 164 { 165 return (pos - initialPosition); 166 } 167 168 169 170 /** 171 * Closes this output stream. This has no effect. 172 */ 173 @Override() 174 public void close() 175 { 176 // No implementation required. 177 } 178 179 180 181 /** 182 * Flushes this output stream. This has no effect. 183 */ 184 @Override() 185 public void flush() 186 { 187 // No implementation required. 188 } 189 190 191 192 /** 193 * Writes the provided byte to this output stream. 194 * 195 * @param b The byte to be written. 196 * 197 * @throws IOException If an attempt was made to write beyond the end of the 198 * array. 199 */ 200 @Override() 201 public void write(final int b) 202 throws IOException 203 { 204 if (pos >= maxPosition) 205 { 206 throw new IOException(ERR_FIXED_ARRAY_OS_WRITE_BEYOND_END.get()); 207 } 208 209 array[pos++] = (byte) b; 210 } 211 212 213 214 /** 215 * Writes the contents of the provided array to this output stream. 216 * 217 * @param b The byte array containing the data to be written. It must not 218 * be {@code null}. 219 * 220 * @throws IOException If an attempt was made to write beyond the end of the 221 * array. 222 */ 223 @Override() 224 public void write(final byte[] b) 225 throws IOException 226 { 227 write(b, 0, b.length); 228 } 229 230 231 232 /** 233 * Writes the contents of the provided array to this output stream. 234 * 235 * @param b The byte array containing the data to be written. It must not 236 * be {@code null}. 237 * @param off The offset within the provided array of the beginning of the 238 * data to be written. It must be greater than or equal to zero 239 * and less than or equal to the length of the provided array. 240 * @param len The number of bytes to be written. It must be greater than or 241 * equal to zero, and the sum of {@code off} and {@code len} must 242 * be less than the length of the provided array. 243 * 244 * @throws IOException If an attempt was made to write beyond the end of the 245 * array. 246 */ 247 @Override() 248 public void write(final byte[] b, final int off, final int len) 249 throws IOException 250 { 251 Validator.ensureTrue((off >= 0), 252 "The provided offset must be greater than or equal to zero."); 253 Validator.ensureTrue((len >= 0), 254 "The provided length must be greater than or equal to zero."); 255 Validator.ensureTrue(((off + len) <= b.length), 256 "The sum of off and len must not exceed the array length."); 257 258 if ((pos + len) > maxPosition) 259 { 260 throw new IOException(ERR_FIXED_ARRAY_OS_WRITE_BEYOND_END.get()); 261 } 262 263 System.arraycopy(b, off, array, pos, len); 264 pos += len; 265 } 266}