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 */ 9 package com.vladium.util; 10 11 import java.io.IOException; 12 import java.io.OutputStream; 13 14 import 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 */ 28 public 29 final 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 // ----------------------------------------------------------------------------