1/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. 2 * 3 * This program and the accompanying materials are made available under 4 * the terms of the Common Public License v1.0 which accompanies this distribution, 5 * and is available at http://www.eclipse.org/legal/cpl-v10.html 6 * 7 * $Id: ByteArrayOStream.java,v 1.1.1.1 2004/05/09 16:57:52 vlad_r Exp $ 8 */ 9package com.vladium.util; 10 11import java.io.IOException; 12import java.io.OutputStream; 13 14import com.vladium.util.asserts.$assert; 15 16// ---------------------------------------------------------------------------- 17/** 18 * An unsynchronized version of java.io.ByteArrayOutputStream that can expose 19 * the underlying byte array without a defensive clone and can also be converted 20 * to a {@link ByteArrayIStream} without intermediate array copies.<p> 21 * 22 * All argument validation is disabled in release mode.<p> 23 * 24 * NOTE: copy-on-write not supported 25 * 26 * @author (C) 2001, Vlad Roubtsov 27 */ 28public 29final class ByteArrayOStream extends OutputStream 30{ 31 // public: ................................................................ 32 33 /** 34 * Callee takes ownership of 'buf'. 35 */ 36 public ByteArrayOStream (final int initialCapacity) 37 { 38 if ($assert.ENABLED) 39 $assert.ASSERT (initialCapacity >= 0, "negative initial capacity: " + initialCapacity); 40 41 m_buf = new byte [initialCapacity]; 42 } 43 44 public final ByteArrayIStream toByteIStream () 45 { 46 return new ByteArrayIStream (m_buf, m_pos); 47 } 48 49 public final void write2 (final int b1, final int b2) 50 { 51 final int pos = m_pos; 52 final int capacity = pos + 2; 53 byte [] mbuf = m_buf; 54 final int mbuflen = mbuf.length; 55 56 if (mbuflen < capacity) 57 { 58 final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; 59 60 if (pos < NATIVE_COPY_THRESHOLD) 61 for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; 62 else 63 System.arraycopy (mbuf, 0, newbuf, 0, pos); 64 65 m_buf = mbuf = newbuf; 66 } 67 68 mbuf [pos] = (byte) b1; 69 mbuf [pos + 1] = (byte) b2; 70 m_pos = capacity; 71 } 72 73 public final void write3 (final int b1, final int b2, final int b3) 74 { 75 final int pos = m_pos; 76 final int capacity = pos + 3; 77 byte [] mbuf = m_buf; 78 final int mbuflen = mbuf.length; 79 80 if (mbuflen < capacity) 81 { 82 final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; 83 84 if (pos < NATIVE_COPY_THRESHOLD) 85 for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; 86 else 87 System.arraycopy (mbuf, 0, newbuf, 0, pos); 88 89 m_buf = mbuf = newbuf; 90 } 91 92 mbuf [pos] = (byte) b1; 93 mbuf [pos + 1] = (byte) b2; 94 mbuf [pos + 2] = (byte) b3; 95 m_pos = capacity; 96 } 97 98 public final void write4 (final int b1, final int b2, final int b3, final int b4) 99 { 100 final int pos = m_pos; 101 final int capacity = pos + 4; 102 byte [] mbuf = m_buf; 103 final int mbuflen = mbuf.length; 104 105 if (mbuflen < capacity) 106 { 107 final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; 108 109 if (pos < NATIVE_COPY_THRESHOLD) 110 for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; 111 else 112 System.arraycopy (mbuf, 0, newbuf, 0, pos); 113 114 m_buf = mbuf = newbuf; 115 } 116 117 mbuf [pos] = (byte) b1; 118 mbuf [pos + 1] = (byte) b2; 119 mbuf [pos + 2] = (byte) b3; 120 mbuf [pos + 3] = (byte) b4; 121 m_pos = capacity; 122 } 123 124 public final void writeTo (final OutputStream out) 125 throws IOException 126 { 127 out.write (m_buf, 0, m_pos); 128 } 129 130// public final void readFully (final InputStream in) 131// throws IOException 132// { 133// while (true) 134// { 135// int chunk = in.available (); 136// 137// System.out.println ("available = " + chunk); 138// 139// // TODO: this case is handled poorly (on EOF) 140// if (chunk == 0) chunk = READ_CHUNK_SIZE; 141// 142// // read at least 'available' bytes: extend the capacity as needed 143// 144// int free = m_buf.length - m_pos; 145// 146// final int read; 147// if (free > chunk) 148// { 149// // try reading more than 'chunk' anyway: 150// read = in.read (m_buf, m_pos, free); 151// } 152// else 153// { 154// // extend the capacity to match 'chunk': 155// { 156// System.out.println ("reallocation"); 157// final byte [] newbuf = new byte [m_pos + chunk]; 158// 159// if (m_pos < NATIVE_COPY_THRESHOLD) 160// for (int i = 0; i < m_pos; ++ i) newbuf [i] = m_buf [i]; 161// else 162// System.arraycopy (m_buf, 0, newbuf, 0, m_pos); 163// 164// m_buf = newbuf; 165// } 166// 167// read = in.read (m_buf, m_pos, chunk); 168// } 169// 170// if (read < 0) 171// break; 172// else 173// m_pos += read; 174// } 175// } 176 177// public final void addCapacity (final int extraCapacity) 178// { 179// final int pos = m_pos; 180// final int capacity = pos + extraCapacity; 181// byte [] mbuf = m_buf; 182// final int mbuflen = mbuf.length; 183// 184// if (mbuflen < capacity) 185// { 186// final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; 187// 188// if (pos < NATIVE_COPY_THRESHOLD) 189// for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; 190// else 191// System.arraycopy (mbuf, 0, newbuf, 0, pos); 192// 193// m_buf = newbuf; 194// } 195// } 196 197 public final byte [] getByteArray () 198 { 199 return m_buf; 200 } 201 202 /** 203 * 204 * @return [result.length = size()] 205 */ 206 public final byte [] copyByteArray () 207 { 208 final int pos = m_pos; 209 210 final byte [] result = new byte [pos]; 211 final byte [] mbuf = m_buf; 212 213 if (pos < NATIVE_COPY_THRESHOLD) 214 for (int i = 0; i < pos; ++ i) result [i] = mbuf [i]; 215 else 216 System.arraycopy (mbuf, 0, result, 0, pos); 217 218 return result; 219 } 220 221 public final int size () 222 { 223 return m_pos; 224 } 225 226 public final int capacity () 227 { 228 return m_buf.length; 229 } 230 231 /** 232 * Does not reduce the current capacity. 233 */ 234 public final void reset () 235 { 236 m_pos = 0; 237 } 238 239 // OutputStream: 240 241 public final void write (final int b) 242 { 243 final int pos = m_pos; 244 final int capacity = pos + 1; 245 byte [] mbuf = m_buf; 246 final int mbuflen = mbuf.length; 247 248 if (mbuflen < capacity) 249 { 250 final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; 251 252 if (pos < NATIVE_COPY_THRESHOLD) 253 for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; 254 else 255 System.arraycopy (mbuf, 0, newbuf, 0, pos); 256 257 m_buf = mbuf = newbuf; 258 } 259 260 mbuf [pos] = (byte) b; 261 m_pos = capacity; 262 } 263 264 265 public final void write (final byte [] buf, final int offset, final int length) 266 { 267 if ($assert.ENABLED) 268 $assert.ASSERT ((offset >= 0) && (offset <= buf.length) && 269 (length >= 0) && ((offset + length) <= buf.length), 270 "invalid input (" + buf.length + ", " + offset + ", " + length + ")"); 271 272 final int pos = m_pos; 273 final int capacity = pos + length; 274 byte [] mbuf = m_buf; 275 final int mbuflen = mbuf.length; 276 277 if (mbuflen < capacity) 278 { 279 final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; 280 281 if (pos < NATIVE_COPY_THRESHOLD) 282 for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; 283 else 284 System.arraycopy (mbuf, 0, newbuf, 0, pos); 285 286 m_buf = mbuf = newbuf; 287 } 288 289 if (length < NATIVE_COPY_THRESHOLD) 290 for (int i = 0; i < length; ++ i) mbuf [pos + i] = buf [offset + i]; 291 else 292 System.arraycopy (buf, offset, mbuf, pos, length); 293 294 m_pos = capacity; 295 } 296 297 298 /** 299 * Equivalent to {@link #reset()}. 300 */ 301 public final void close () 302 { 303 reset (); 304 } 305 306 // protected: ............................................................. 307 308 // package: ............................................................... 309 310 // private: ............................................................... 311 312 313 private byte [] m_buf; 314 private int m_pos; 315 316// private static final int READ_CHUNK_SIZE = 16 * 1024; 317 private static final int NATIVE_COPY_THRESHOLD = 9; 318 319} // end of class 320// ----------------------------------------------------------------------------