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
26package javax.imageio.stream;
27
28import java.io.IOException;
29import java.io.UTFDataFormatException;
30import 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 */
38public 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}
511