1 /* 2 * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.imageio.stream; 27 28 import java.io.IOException; 29 import java.io.UTFDataFormatException; 30 import java.nio.ByteOrder; 31 32 /** 33 * An abstract class implementing the {@code ImageOutputStream} interface. 34 * This class is designed to reduce the number of methods that must 35 * be implemented by subclasses. 36 * 37 */ 38 public abstract class ImageOutputStreamImpl 39 extends ImageInputStreamImpl 40 implements ImageOutputStream { 41 42 /** 43 * Constructs an {@code ImageOutputStreamImpl}. 44 */ 45 public ImageOutputStreamImpl() { 46 } 47 48 public abstract void write(int b) throws IOException; 49 50 public void write(byte[] b) throws IOException { 51 write(b, 0, b.length); 52 } 53 54 public abstract void write(byte[] b, int off, int len) throws IOException; 55 56 public void writeBoolean(boolean v) throws IOException { 57 write(v ? 1 : 0); 58 } 59 60 public void writeByte(int v) throws IOException { 61 write(v); 62 } 63 64 public void writeShort(int v) throws IOException { 65 if (byteOrder == ByteOrder.BIG_ENDIAN) { 66 byteBuf[0] = (byte)(v >>> 8); 67 byteBuf[1] = (byte)(v >>> 0); 68 } else { 69 byteBuf[0] = (byte)(v >>> 0); 70 byteBuf[1] = (byte)(v >>> 8); 71 } 72 write(byteBuf, 0, 2); 73 } 74 75 public void writeChar(int v) throws IOException { 76 writeShort(v); 77 } 78 79 public void writeInt(int v) throws IOException { 80 if (byteOrder == ByteOrder.BIG_ENDIAN) { 81 byteBuf[0] = (byte)(v >>> 24); 82 byteBuf[1] = (byte)(v >>> 16); 83 byteBuf[2] = (byte)(v >>> 8); 84 byteBuf[3] = (byte)(v >>> 0); 85 } else { 86 byteBuf[0] = (byte)(v >>> 0); 87 byteBuf[1] = (byte)(v >>> 8); 88 byteBuf[2] = (byte)(v >>> 16); 89 byteBuf[3] = (byte)(v >>> 24); 90 } 91 write(byteBuf, 0, 4); 92 } 93 94 public void writeLong(long v) throws IOException { 95 if (byteOrder == ByteOrder.BIG_ENDIAN) { 96 byteBuf[0] = (byte)(v >>> 56); 97 byteBuf[1] = (byte)(v >>> 48); 98 byteBuf[2] = (byte)(v >>> 40); 99 byteBuf[3] = (byte)(v >>> 32); 100 byteBuf[4] = (byte)(v >>> 24); 101 byteBuf[5] = (byte)(v >>> 16); 102 byteBuf[6] = (byte)(v >>> 8); 103 byteBuf[7] = (byte)(v >>> 0); 104 } else { 105 byteBuf[0] = (byte)(v >>> 0); 106 byteBuf[1] = (byte)(v >>> 8); 107 byteBuf[2] = (byte)(v >>> 16); 108 byteBuf[3] = (byte)(v >>> 24); 109 byteBuf[4] = (byte)(v >>> 32); 110 byteBuf[5] = (byte)(v >>> 40); 111 byteBuf[6] = (byte)(v >>> 48); 112 byteBuf[7] = (byte)(v >>> 56); 113 } 114 // REMIND: Once 6277756 is fixed, we should do a bulk write of all 8 115 // bytes here as we do in writeShort() and writeInt() for even better 116 // performance. For now, two bulk writes of 4 bytes each is still 117 // faster than 8 individual write() calls (see 6347575 for details). 118 write(byteBuf, 0, 4); 119 write(byteBuf, 4, 4); 120 } 121 122 public void writeFloat(float v) throws IOException { 123 writeInt(Float.floatToIntBits(v)); 124 } 125 126 public void writeDouble(double v) throws IOException { 127 writeLong(Double.doubleToLongBits(v)); 128 } 129 130 public void writeBytes(String s) throws IOException { 131 int len = s.length(); 132 for (int i = 0 ; i < len ; i++) { 133 write((byte)s.charAt(i)); 134 } 135 } 136 137 public void writeChars(String s) throws IOException { 138 int len = s.length(); 139 140 byte[] b = new byte[len*2]; 141 int boff = 0; 142 if (byteOrder == ByteOrder.BIG_ENDIAN) { 143 for (int i = 0; i < len ; i++) { 144 int v = s.charAt(i); 145 b[boff++] = (byte)(v >>> 8); 146 b[boff++] = (byte)(v >>> 0); 147 } 148 } else { 149 for (int i = 0; i < len ; i++) { 150 int v = s.charAt(i); 151 b[boff++] = (byte)(v >>> 0); 152 b[boff++] = (byte)(v >>> 8); 153 } 154 } 155 156 write(b, 0, len*2); 157 } 158 159 public void writeUTF(String s) throws IOException { 160 int strlen = s.length(); 161 int utflen = 0; 162 char[] charr = new char[strlen]; 163 int c, boff = 0; 164 165 s.getChars(0, strlen, charr, 0); 166 167 for (int i = 0; i < strlen; i++) { 168 c = charr[i]; 169 if ((c >= 0x0001) && (c <= 0x007F)) { 170 utflen++; 171 } else if (c > 0x07FF) { 172 utflen += 3; 173 } else { 174 utflen += 2; 175 } 176 } 177 178 if (utflen > 65535) { 179 throw new UTFDataFormatException("utflen > 65536!"); 180 } 181 182 byte[] b = new byte[utflen+2]; 183 b[boff++] = (byte) ((utflen >>> 8) & 0xFF); 184 b[boff++] = (byte) ((utflen >>> 0) & 0xFF); 185 for (int i = 0; i < strlen; i++) { 186 c = charr[i]; 187 if ((c >= 0x0001) && (c <= 0x007F)) { 188 b[boff++] = (byte) c; 189 } else if (c > 0x07FF) { 190 b[boff++] = (byte) (0xE0 | ((c >> 12) & 0x0F)); 191 b[boff++] = (byte) (0x80 | ((c >> 6) & 0x3F)); 192 b[boff++] = (byte) (0x80 | ((c >> 0) & 0x3F)); 193 } else { 194 b[boff++] = (byte) (0xC0 | ((c >> 6) & 0x1F)); 195 b[boff++] = (byte) (0x80 | ((c >> 0) & 0x3F)); 196 } 197 } 198 write(b, 0, utflen + 2); 199 } 200 201 public void writeShorts(short[] s, int off, int len) throws IOException { 202 // Fix 4430357 - if off + len < 0, overflow occurred 203 if (off < 0 || len < 0 || off + len > s.length || off + len < 0) { 204 throw new IndexOutOfBoundsException 205 ("off < 0 || len < 0 || off + len > s.length!"); 206 } 207 208 byte[] b = new byte[len*2]; 209 int boff = 0; 210 if (byteOrder == ByteOrder.BIG_ENDIAN) { 211 for (int i = 0; i < len; i++) { 212 short v = s[off + i]; 213 b[boff++] = (byte)(v >>> 8); 214 b[boff++] = (byte)(v >>> 0); 215 } 216 } else { 217 for (int i = 0; i < len; i++) { 218 short v = s[off + i]; 219 b[boff++] = (byte)(v >>> 0); 220 b[boff++] = (byte)(v >>> 8); 221 } 222 } 223 224 write(b, 0, len*2); 225 } 226 227 public void writeChars(char[] c, int off, int len) throws IOException { 228 // Fix 4430357 - if off + len < 0, overflow occurred 229 if (off < 0 || len < 0 || off + len > c.length || off + len < 0) { 230 throw new IndexOutOfBoundsException 231 ("off < 0 || len < 0 || off + len > c.length!"); 232 } 233 234 byte[] b = new byte[len*2]; 235 int boff = 0; 236 if (byteOrder == ByteOrder.BIG_ENDIAN) { 237 for (int i = 0; i < len; i++) { 238 char v = c[off + i]; 239 b[boff++] = (byte)(v >>> 8); 240 b[boff++] = (byte)(v >>> 0); 241 } 242 } else { 243 for (int i = 0; i < len; i++) { 244 char v = c[off + i]; 245 b[boff++] = (byte)(v >>> 0); 246 b[boff++] = (byte)(v >>> 8); 247 } 248 } 249 250 write(b, 0, len*2); 251 } 252 253 public void writeInts(int[] i, int off, int len) throws IOException { 254 // Fix 4430357 - if off + len < 0, overflow occurred 255 if (off < 0 || len < 0 || off + len > i.length || off + len < 0) { 256 throw new IndexOutOfBoundsException 257 ("off < 0 || len < 0 || off + len > i.length!"); 258 } 259 260 byte[] b = new byte[len*4]; 261 int boff = 0; 262 if (byteOrder == ByteOrder.BIG_ENDIAN) { 263 for (int j = 0; j < len; j++) { 264 int v = i[off + j]; 265 b[boff++] = (byte)(v >>> 24); 266 b[boff++] = (byte)(v >>> 16); 267 b[boff++] = (byte)(v >>> 8); 268 b[boff++] = (byte)(v >>> 0); 269 } 270 } else { 271 for (int j = 0; j < len; j++) { 272 int v = i[off + j]; 273 b[boff++] = (byte)(v >>> 0); 274 b[boff++] = (byte)(v >>> 8); 275 b[boff++] = (byte)(v >>> 16); 276 b[boff++] = (byte)(v >>> 24); 277 } 278 } 279 280 write(b, 0, len*4); 281 } 282 283 public void writeLongs(long[] l, int off, int len) throws IOException { 284 // Fix 4430357 - if off + len < 0, overflow occurred 285 if (off < 0 || len < 0 || off + len > l.length || off + len < 0) { 286 throw new IndexOutOfBoundsException 287 ("off < 0 || len < 0 || off + len > l.length!"); 288 } 289 290 byte[] b = new byte[len*8]; 291 int boff = 0; 292 if (byteOrder == ByteOrder.BIG_ENDIAN) { 293 for (int i = 0; i < len; i++) { 294 long v = l[off + i]; 295 b[boff++] = (byte)(v >>> 56); 296 b[boff++] = (byte)(v >>> 48); 297 b[boff++] = (byte)(v >>> 40); 298 b[boff++] = (byte)(v >>> 32); 299 b[boff++] = (byte)(v >>> 24); 300 b[boff++] = (byte)(v >>> 16); 301 b[boff++] = (byte)(v >>> 8); 302 b[boff++] = (byte)(v >>> 0); 303 } 304 } else { 305 for (int i = 0; i < len; i++) { 306 long v = l[off + i]; 307 b[boff++] = (byte)(v >>> 0); 308 b[boff++] = (byte)(v >>> 8); 309 b[boff++] = (byte)(v >>> 16); 310 b[boff++] = (byte)(v >>> 24); 311 b[boff++] = (byte)(v >>> 32); 312 b[boff++] = (byte)(v >>> 40); 313 b[boff++] = (byte)(v >>> 48); 314 b[boff++] = (byte)(v >>> 56); 315 } 316 } 317 318 write(b, 0, len*8); 319 } 320 321 public void writeFloats(float[] f, int off, int len) throws IOException { 322 // Fix 4430357 - if off + len < 0, overflow occurred 323 if (off < 0 || len < 0 || off + len > f.length || off + len < 0) { 324 throw new IndexOutOfBoundsException 325 ("off < 0 || len < 0 || off + len > f.length!"); 326 } 327 328 byte[] b = new byte[len*4]; 329 int boff = 0; 330 if (byteOrder == ByteOrder.BIG_ENDIAN) { 331 for (int i = 0; i < len; i++) { 332 int v = Float.floatToIntBits(f[off + i]); 333 b[boff++] = (byte)(v >>> 24); 334 b[boff++] = (byte)(v >>> 16); 335 b[boff++] = (byte)(v >>> 8); 336 b[boff++] = (byte)(v >>> 0); 337 } 338 } else { 339 for (int i = 0; i < len; i++) { 340 int v = Float.floatToIntBits(f[off + i]); 341 b[boff++] = (byte)(v >>> 0); 342 b[boff++] = (byte)(v >>> 8); 343 b[boff++] = (byte)(v >>> 16); 344 b[boff++] = (byte)(v >>> 24); 345 } 346 } 347 348 write(b, 0, len*4); 349 } 350 351 public void writeDoubles(double[] d, int off, int len) throws IOException { 352 // Fix 4430357 - if off + len < 0, overflow occurred 353 if (off < 0 || len < 0 || off + len > d.length || off + len < 0) { 354 throw new IndexOutOfBoundsException 355 ("off < 0 || len < 0 || off + len > d.length!"); 356 } 357 358 byte[] b = new byte[len*8]; 359 int boff = 0; 360 if (byteOrder == ByteOrder.BIG_ENDIAN) { 361 for (int i = 0; i < len; i++) { 362 long v = Double.doubleToLongBits(d[off + i]); 363 b[boff++] = (byte)(v >>> 56); 364 b[boff++] = (byte)(v >>> 48); 365 b[boff++] = (byte)(v >>> 40); 366 b[boff++] = (byte)(v >>> 32); 367 b[boff++] = (byte)(v >>> 24); 368 b[boff++] = (byte)(v >>> 16); 369 b[boff++] = (byte)(v >>> 8); 370 b[boff++] = (byte)(v >>> 0); 371 } 372 } else { 373 for (int i = 0; i < len; i++) { 374 long v = Double.doubleToLongBits(d[off + i]); 375 b[boff++] = (byte)(v >>> 0); 376 b[boff++] = (byte)(v >>> 8); 377 b[boff++] = (byte)(v >>> 16); 378 b[boff++] = (byte)(v >>> 24); 379 b[boff++] = (byte)(v >>> 32); 380 b[boff++] = (byte)(v >>> 40); 381 b[boff++] = (byte)(v >>> 48); 382 b[boff++] = (byte)(v >>> 56); 383 } 384 } 385 386 write(b, 0, len*8); 387 } 388 389 public void writeBit(int bit) throws IOException { 390 writeBits((1L & bit), 1); 391 } 392 393 public void writeBits(long bits, int numBits) throws IOException { 394 checkClosed(); 395 396 if (numBits < 0 || numBits > 64) { 397 throw new IllegalArgumentException("Bad value for numBits!"); 398 } 399 if (numBits == 0) { 400 return; 401 } 402 403 // Prologue: deal with pre-existing bits 404 405 // Bug 4499158, 4507868 - if we're at the beginning of the stream 406 // and the bit offset is 0, there can't be any pre-existing bits 407 if ((getStreamPosition() > 0) || (bitOffset > 0)) { 408 int offset = bitOffset; // read() will reset bitOffset 409 int partialByte = read(); 410 if (partialByte != -1) { 411 seek(getStreamPosition() - 1); 412 } else { 413 partialByte = 0; 414 } 415 416 if (numBits + offset < 8) { 417 // Notch out the partial byte and drop in the new bits 418 int shift = 8 - (offset+numBits); 419 int mask = -1 >>> (32 - numBits); 420 partialByte &= ~(mask << shift); // Clear out old bits 421 partialByte |= ((bits & mask) << shift); // Or in new ones 422 write(partialByte); 423 seek(getStreamPosition() - 1); 424 bitOffset = offset + numBits; 425 numBits = 0; // Signal that we are done 426 } else { 427 // Fill out the partial byte and reduce numBits 428 int num = 8 - offset; 429 int mask = -1 >>> (32 - num); 430 partialByte &= ~mask; // Clear out bits 431 partialByte |= ((bits >> (numBits - num)) & mask); 432 // Note that bitOffset is already 0, so there is no risk 433 // of this advancing to the next byte 434 write(partialByte); 435 numBits -= num; 436 } 437 } 438 439 // Now write any whole bytes 440 if (numBits > 7) { 441 int extra = numBits % 8; 442 for (int numBytes = numBits / 8; numBytes > 0; numBytes--) { 443 int shift = (numBytes-1)*8+extra; 444 int value = (int) ((shift == 0) 445 ? bits & 0xFF 446 : (bits>>shift) & 0xFF); 447 write(value); 448 } 449 numBits = extra; 450 } 451 452 // Epilogue: write out remaining partial byte, if any 453 // Note that we may be at EOF, in which case we pad with 0, 454 // or not, in which case we must preserve the existing bits 455 if (numBits != 0) { 456 // If we are not at the end of the file, read the current byte 457 // If we are at the end of the file, initialize our byte to 0. 458 int partialByte = 0; 459 partialByte = read(); 460 if (partialByte != -1) { 461 seek(getStreamPosition() - 1); 462 } 463 // Fix 4494976: writeBit(int) does not pad the remainder 464 // of the current byte with 0s 465 else { // EOF 466 partialByte = 0; 467 } 468 469 int shift = 8 - numBits; 470 int mask = -1 >>> (32 - numBits); 471 partialByte &= ~(mask << shift); 472 partialByte |= (bits & mask) << shift; 473 // bitOffset is always already 0 when we get here. 474 write(partialByte); 475 seek(getStreamPosition() - 1); 476 bitOffset = numBits; 477 } 478 } 479 480 /** 481 * If the bit offset is non-zero, forces the remaining bits 482 * in the current byte to 0 and advances the stream position 483 * by one. This method should be called by subclasses at the 484 * beginning of the {@code write(int)} and 485 * {@code write(byte[], int, int)} methods. 486 * 487 * @exception IOException if an I/O error occurs. 488 */ 489 protected final void flushBits() throws IOException { 490 checkClosed(); 491 if (bitOffset != 0) { 492 int offset = bitOffset; 493 int partialByte = read(); // Sets bitOffset to 0 494 if (partialByte < 0) { 495 // Fix 4465683: When bitOffset is set 496 // to something non-zero beyond EOF, 497 // we should set that whole byte to 498 // zero and write it to stream. 499 partialByte = 0; 500 bitOffset = 0; 501 } 502 else { 503 seek(getStreamPosition() - 1); 504 partialByte &= -1 << (8 - offset); 505 } 506 write(partialByte); 507 } 508 } 509 510 }