001/* 002 * Copyright 2010-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2010-2020 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2010-2020 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.util; 037 038 039 040import java.io.IOException; 041import java.io.OutputStream; 042import java.io.Serializable; 043 044import static com.unboundid.util.UtilityMessages.*; 045 046 047 048/** 049 * This class provides an {@code OutputStream} implementation that writes data 050 * to a provided byte array. It is similar to the 051 * {@code java.io.ByteArrayOutputStream} class, except that it allows you to 052 * pass in the array that it uses, and the array will not grow over time. 053 */ 054@Mutable() 055@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 056public final class FixedArrayOutputStream 057 extends OutputStream 058 implements Serializable 059{ 060 /** 061 * The serial version UID for this serializable class. 062 */ 063 private static final long serialVersionUID = 4678108653480347534L; 064 065 066 067 // The byte array used by this class. 068 private final byte[] array; 069 070 // The initial position for this array. 071 private final int initialPosition; 072 073 // The maximum number of bytes that may be written. 074 private final int length; 075 076 // The maximum position at which data may be written. 077 private final int maxPosition; 078 079 // The current position at which data may be written. 080 private int pos; 081 082 083 084 /** 085 * Creates a new output stream that will write data to the provided array. 086 * It will use the entire array. 087 * 088 * @param array The array to which data will be written. It must not be 089 * {@code null}. 090 */ 091 public FixedArrayOutputStream(final byte[] array) 092 { 093 this(array, 0, array.length); 094 } 095 096 097 098 /** 099 * Creates a new output stream that will write data to the provided array. 100 * It will use the specified portion of the array. 101 * 102 * @param array The array to which data will be written. It must not be 103 * {@code null}. 104 * @param pos The position at which to start writing data. It must be 105 * greater than or equal to zero and less than or equal to the 106 * length of the array. 107 * @param len The maximum number of bytes that may be written. It must 108 * be greater than or equal to zero and less than or equal to 109 * the difference between the length of the array and the 110 * provided {@code pos} value. 111 */ 112 public FixedArrayOutputStream(final byte[] array, final int pos, 113 final int len) 114 { 115 this.array = array; 116 this.pos = pos; 117 118 initialPosition = pos; 119 maxPosition = pos + len; 120 length = len; 121 122 Validator.ensureTrue((pos >= 0), 123 "The position must be greater than or equal to zero."); 124 Validator.ensureTrue((len >= 0), 125 "The length must be greater than or equal to zero."); 126 Validator.ensureTrue((maxPosition <= array.length), 127 "The sum of pos and len must not exceed the array length."); 128 } 129 130 131 132 /** 133 * Retrieves the backing array used by this output stream. 134 * 135 * @return The backing array used by this output stream. 136 */ 137 public byte[] getBackingArray() 138 { 139 return array; 140 } 141 142 143 144 /** 145 * Retrieves the initial position provided when this output stream was 146 * created. 147 * 148 * @return The initial position provided when this output stream was created. 149 */ 150 public int getInitialPosition() 151 { 152 return initialPosition; 153 } 154 155 156 157 /** 158 * Retrieves the maximum number of bytes that may be written to this output 159 * stream. 160 * 161 * @return The maximum number of bytes that may be written to this output 162 * stream. 163 */ 164 public int getLength() 165 { 166 return length; 167 } 168 169 170 171 /** 172 * Retrieves the number of bytes that have been written so far to this output 173 * stream. 174 * 175 * @return The number of bytes that have been written so far to this output 176 * stream. 177 */ 178 public int getBytesWritten() 179 { 180 return (pos - initialPosition); 181 } 182 183 184 185 /** 186 * Closes this output stream. This has no effect. 187 */ 188 @Override() 189 public void close() 190 { 191 // No implementation required. 192 } 193 194 195 196 /** 197 * Flushes this output stream. This has no effect. 198 */ 199 @Override() 200 public void flush() 201 { 202 // No implementation required. 203 } 204 205 206 207 /** 208 * Writes the provided byte to this output stream. 209 * 210 * @param b The byte to be written. 211 * 212 * @throws IOException If an attempt was made to write beyond the end of the 213 * array. 214 */ 215 @Override() 216 public void write(final int b) 217 throws IOException 218 { 219 if (pos >= maxPosition) 220 { 221 throw new IOException(ERR_FIXED_ARRAY_OS_WRITE_BEYOND_END.get()); 222 } 223 224 array[pos++] = (byte) b; 225 } 226 227 228 229 /** 230 * Writes the contents of the provided array to this output stream. 231 * 232 * @param b The byte array containing the data to be written. It must not 233 * be {@code null}. 234 * 235 * @throws IOException If an attempt was made to write beyond the end of the 236 * array. 237 */ 238 @Override() 239 public void write(final byte[] b) 240 throws IOException 241 { 242 write(b, 0, b.length); 243 } 244 245 246 247 /** 248 * Writes the contents of the provided array to this output stream. 249 * 250 * @param b The byte array containing the data to be written. It must not 251 * be {@code null}. 252 * @param off The offset within the provided array of the beginning of the 253 * data to be written. It must be greater than or equal to zero 254 * and less than or equal to the length of the provided array. 255 * @param len The number of bytes to be written. It must be greater than or 256 * equal to zero, and the sum of {@code off} and {@code len} must 257 * be less than the length of the provided array. 258 * 259 * @throws IOException If an attempt was made to write beyond the end of the 260 * array. 261 */ 262 @Override() 263 public void write(final byte[] b, final int off, final int len) 264 throws IOException 265 { 266 Validator.ensureTrue((off >= 0), 267 "The provided offset must be greater than or equal to zero."); 268 Validator.ensureTrue((len >= 0), 269 "The provided length must be greater than or equal to zero."); 270 Validator.ensureTrue(((off + len) <= b.length), 271 "The sum of off and len must not exceed the array length."); 272 273 if ((pos + len) > maxPosition) 274 { 275 throw new IOException(ERR_FIXED_ARRAY_OS_WRITE_BEYOND_END.get()); 276 } 277 278 System.arraycopy(b, off, array, pos, len); 279 pos += len; 280 } 281}