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 }