1 /*
2  * Copyright (c) 2000, 2007, 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</code> 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</code>.
44      */
ImageOutputStreamImpl()45     public ImageOutputStreamImpl() {
46     }
47 
write(int b)48     public abstract void write(int b) throws IOException;
49 
write(byte b[])50     public void write(byte b[]) throws IOException {
51         write(b, 0, b.length);
52     }
53 
write(byte b[], int off, int len)54     public abstract void write(byte b[], int off, int len) throws IOException;
55 
writeBoolean(boolean v)56     public void writeBoolean(boolean v) throws IOException {
57         write(v ? 1 : 0);
58     }
59 
writeByte(int v)60     public void writeByte(int v) throws IOException {
61         write(v);
62     }
63 
writeShort(int v)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 
writeChar(int v)75     public void writeChar(int v) throws IOException {
76         writeShort(v);
77     }
78 
writeInt(int v)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 
writeLong(long v)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 
writeFloat(float v)122     public void writeFloat(float v) throws IOException {
123         writeInt(Float.floatToIntBits(v));
124     }
125 
writeDouble(double v)126     public void writeDouble(double v) throws IOException {
127         writeLong(Double.doubleToLongBits(v));
128     }
129 
writeBytes(String s)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 
writeChars(String s)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 
writeUTF(String s)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 
writeShorts(short[] s, int off, int len)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 
writeChars(char[] c, int off, int len)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 
writeInts(int[] i, int off, int len)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 
writeLongs(long[] l, int off, int len)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 
writeFloats(float[] f, int off, int len)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 
writeDoubles(double[] d, int off, int len)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 
writeBit(int bit)389     public void writeBit(int bit) throws IOException {
390         writeBits((1L & bit), 1);
391     }
392 
writeBits(long bits, int numBits)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)</code> and
485      * <code>write(byte[], int, int)</code> methods.
486      *
487      * @exception IOException if an I/O error occurs.
488      */
flushBits()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 }
511