Path: blob/master/src/java.desktop/share/classes/javax/imageio/stream/ImageOutputStreamImpl.java
41153 views
/*1* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.imageio.stream;2627import java.io.IOException;28import java.io.UTFDataFormatException;29import java.nio.ByteOrder;3031/**32* An abstract class implementing the {@code ImageOutputStream} interface.33* This class is designed to reduce the number of methods that must34* be implemented by subclasses.35*36*/37public abstract class ImageOutputStreamImpl38extends ImageInputStreamImpl39implements ImageOutputStream {4041/**42* Constructs an {@code ImageOutputStreamImpl}.43*/44public ImageOutputStreamImpl() {45}4647public abstract void write(int b) throws IOException;4849public void write(byte[] b) throws IOException {50write(b, 0, b.length);51}5253public abstract void write(byte[] b, int off, int len) throws IOException;5455public void writeBoolean(boolean v) throws IOException {56write(v ? 1 : 0);57}5859public void writeByte(int v) throws IOException {60write(v);61}6263public void writeShort(int v) throws IOException {64if (byteOrder == ByteOrder.BIG_ENDIAN) {65byteBuf[0] = (byte)(v >>> 8);66byteBuf[1] = (byte)(v >>> 0);67} else {68byteBuf[0] = (byte)(v >>> 0);69byteBuf[1] = (byte)(v >>> 8);70}71write(byteBuf, 0, 2);72}7374public void writeChar(int v) throws IOException {75writeShort(v);76}7778public void writeInt(int v) throws IOException {79if (byteOrder == ByteOrder.BIG_ENDIAN) {80byteBuf[0] = (byte)(v >>> 24);81byteBuf[1] = (byte)(v >>> 16);82byteBuf[2] = (byte)(v >>> 8);83byteBuf[3] = (byte)(v >>> 0);84} else {85byteBuf[0] = (byte)(v >>> 0);86byteBuf[1] = (byte)(v >>> 8);87byteBuf[2] = (byte)(v >>> 16);88byteBuf[3] = (byte)(v >>> 24);89}90write(byteBuf, 0, 4);91}9293public void writeLong(long v) throws IOException {94if (byteOrder == ByteOrder.BIG_ENDIAN) {95byteBuf[0] = (byte)(v >>> 56);96byteBuf[1] = (byte)(v >>> 48);97byteBuf[2] = (byte)(v >>> 40);98byteBuf[3] = (byte)(v >>> 32);99byteBuf[4] = (byte)(v >>> 24);100byteBuf[5] = (byte)(v >>> 16);101byteBuf[6] = (byte)(v >>> 8);102byteBuf[7] = (byte)(v >>> 0);103} else {104byteBuf[0] = (byte)(v >>> 0);105byteBuf[1] = (byte)(v >>> 8);106byteBuf[2] = (byte)(v >>> 16);107byteBuf[3] = (byte)(v >>> 24);108byteBuf[4] = (byte)(v >>> 32);109byteBuf[5] = (byte)(v >>> 40);110byteBuf[6] = (byte)(v >>> 48);111byteBuf[7] = (byte)(v >>> 56);112}113// REMIND: Once 6277756 is fixed, we should do a bulk write of all 8114// bytes here as we do in writeShort() and writeInt() for even better115// performance. For now, two bulk writes of 4 bytes each is still116// faster than 8 individual write() calls (see 6347575 for details).117write(byteBuf, 0, 4);118write(byteBuf, 4, 4);119}120121public void writeFloat(float v) throws IOException {122writeInt(Float.floatToIntBits(v));123}124125public void writeDouble(double v) throws IOException {126writeLong(Double.doubleToLongBits(v));127}128129public void writeBytes(String s) throws IOException {130int len = s.length();131for (int i = 0 ; i < len ; i++) {132write((byte)s.charAt(i));133}134}135136public void writeChars(String s) throws IOException {137int len = s.length();138139byte[] b = new byte[len*2];140int boff = 0;141if (byteOrder == ByteOrder.BIG_ENDIAN) {142for (int i = 0; i < len ; i++) {143int v = s.charAt(i);144b[boff++] = (byte)(v >>> 8);145b[boff++] = (byte)(v >>> 0);146}147} else {148for (int i = 0; i < len ; i++) {149int v = s.charAt(i);150b[boff++] = (byte)(v >>> 0);151b[boff++] = (byte)(v >>> 8);152}153}154155write(b, 0, len*2);156}157158public void writeUTF(String s) throws IOException {159int strlen = s.length();160int utflen = 0;161char[] charr = new char[strlen];162int c, boff = 0;163164s.getChars(0, strlen, charr, 0);165166for (int i = 0; i < strlen; i++) {167c = charr[i];168if ((c >= 0x0001) && (c <= 0x007F)) {169utflen++;170} else if (c > 0x07FF) {171utflen += 3;172} else {173utflen += 2;174}175}176177if (utflen > 65535) {178throw new UTFDataFormatException("utflen > 65536!");179}180181byte[] b = new byte[utflen+2];182b[boff++] = (byte) ((utflen >>> 8) & 0xFF);183b[boff++] = (byte) ((utflen >>> 0) & 0xFF);184for (int i = 0; i < strlen; i++) {185c = charr[i];186if ((c >= 0x0001) && (c <= 0x007F)) {187b[boff++] = (byte) c;188} else if (c > 0x07FF) {189b[boff++] = (byte) (0xE0 | ((c >> 12) & 0x0F));190b[boff++] = (byte) (0x80 | ((c >> 6) & 0x3F));191b[boff++] = (byte) (0x80 | ((c >> 0) & 0x3F));192} else {193b[boff++] = (byte) (0xC0 | ((c >> 6) & 0x1F));194b[boff++] = (byte) (0x80 | ((c >> 0) & 0x3F));195}196}197write(b, 0, utflen + 2);198}199200public void writeShorts(short[] s, int off, int len) throws IOException {201// Fix 4430357 - if off + len < 0, overflow occurred202if (off < 0 || len < 0 || off + len > s.length || off + len < 0) {203throw new IndexOutOfBoundsException204("off < 0 || len < 0 || off + len > s.length!");205}206207byte[] b = new byte[len*2];208int boff = 0;209if (byteOrder == ByteOrder.BIG_ENDIAN) {210for (int i = 0; i < len; i++) {211short v = s[off + i];212b[boff++] = (byte)(v >>> 8);213b[boff++] = (byte)(v >>> 0);214}215} else {216for (int i = 0; i < len; i++) {217short v = s[off + i];218b[boff++] = (byte)(v >>> 0);219b[boff++] = (byte)(v >>> 8);220}221}222223write(b, 0, len*2);224}225226public void writeChars(char[] c, int off, int len) throws IOException {227// Fix 4430357 - if off + len < 0, overflow occurred228if (off < 0 || len < 0 || off + len > c.length || off + len < 0) {229throw new IndexOutOfBoundsException230("off < 0 || len < 0 || off + len > c.length!");231}232233byte[] b = new byte[len*2];234int boff = 0;235if (byteOrder == ByteOrder.BIG_ENDIAN) {236for (int i = 0; i < len; i++) {237char v = c[off + i];238b[boff++] = (byte)(v >>> 8);239b[boff++] = (byte)(v >>> 0);240}241} else {242for (int i = 0; i < len; i++) {243char v = c[off + i];244b[boff++] = (byte)(v >>> 0);245b[boff++] = (byte)(v >>> 8);246}247}248249write(b, 0, len*2);250}251252public void writeInts(int[] i, int off, int len) throws IOException {253// Fix 4430357 - if off + len < 0, overflow occurred254if (off < 0 || len < 0 || off + len > i.length || off + len < 0) {255throw new IndexOutOfBoundsException256("off < 0 || len < 0 || off + len > i.length!");257}258259byte[] b = new byte[len*4];260int boff = 0;261if (byteOrder == ByteOrder.BIG_ENDIAN) {262for (int j = 0; j < len; j++) {263int v = i[off + j];264b[boff++] = (byte)(v >>> 24);265b[boff++] = (byte)(v >>> 16);266b[boff++] = (byte)(v >>> 8);267b[boff++] = (byte)(v >>> 0);268}269} else {270for (int j = 0; j < len; j++) {271int v = i[off + j];272b[boff++] = (byte)(v >>> 0);273b[boff++] = (byte)(v >>> 8);274b[boff++] = (byte)(v >>> 16);275b[boff++] = (byte)(v >>> 24);276}277}278279write(b, 0, len*4);280}281282public void writeLongs(long[] l, int off, int len) throws IOException {283// Fix 4430357 - if off + len < 0, overflow occurred284if (off < 0 || len < 0 || off + len > l.length || off + len < 0) {285throw new IndexOutOfBoundsException286("off < 0 || len < 0 || off + len > l.length!");287}288289byte[] b = new byte[len*8];290int boff = 0;291if (byteOrder == ByteOrder.BIG_ENDIAN) {292for (int i = 0; i < len; i++) {293long v = l[off + i];294b[boff++] = (byte)(v >>> 56);295b[boff++] = (byte)(v >>> 48);296b[boff++] = (byte)(v >>> 40);297b[boff++] = (byte)(v >>> 32);298b[boff++] = (byte)(v >>> 24);299b[boff++] = (byte)(v >>> 16);300b[boff++] = (byte)(v >>> 8);301b[boff++] = (byte)(v >>> 0);302}303} else {304for (int i = 0; i < len; i++) {305long v = l[off + i];306b[boff++] = (byte)(v >>> 0);307b[boff++] = (byte)(v >>> 8);308b[boff++] = (byte)(v >>> 16);309b[boff++] = (byte)(v >>> 24);310b[boff++] = (byte)(v >>> 32);311b[boff++] = (byte)(v >>> 40);312b[boff++] = (byte)(v >>> 48);313b[boff++] = (byte)(v >>> 56);314}315}316317write(b, 0, len*8);318}319320public void writeFloats(float[] f, int off, int len) throws IOException {321// Fix 4430357 - if off + len < 0, overflow occurred322if (off < 0 || len < 0 || off + len > f.length || off + len < 0) {323throw new IndexOutOfBoundsException324("off < 0 || len < 0 || off + len > f.length!");325}326327byte[] b = new byte[len*4];328int boff = 0;329if (byteOrder == ByteOrder.BIG_ENDIAN) {330for (int i = 0; i < len; i++) {331int v = Float.floatToIntBits(f[off + i]);332b[boff++] = (byte)(v >>> 24);333b[boff++] = (byte)(v >>> 16);334b[boff++] = (byte)(v >>> 8);335b[boff++] = (byte)(v >>> 0);336}337} else {338for (int i = 0; i < len; i++) {339int v = Float.floatToIntBits(f[off + i]);340b[boff++] = (byte)(v >>> 0);341b[boff++] = (byte)(v >>> 8);342b[boff++] = (byte)(v >>> 16);343b[boff++] = (byte)(v >>> 24);344}345}346347write(b, 0, len*4);348}349350public void writeDoubles(double[] d, int off, int len) throws IOException {351// Fix 4430357 - if off + len < 0, overflow occurred352if (off < 0 || len < 0 || off + len > d.length || off + len < 0) {353throw new IndexOutOfBoundsException354("off < 0 || len < 0 || off + len > d.length!");355}356357byte[] b = new byte[len*8];358int boff = 0;359if (byteOrder == ByteOrder.BIG_ENDIAN) {360for (int i = 0; i < len; i++) {361long v = Double.doubleToLongBits(d[off + i]);362b[boff++] = (byte)(v >>> 56);363b[boff++] = (byte)(v >>> 48);364b[boff++] = (byte)(v >>> 40);365b[boff++] = (byte)(v >>> 32);366b[boff++] = (byte)(v >>> 24);367b[boff++] = (byte)(v >>> 16);368b[boff++] = (byte)(v >>> 8);369b[boff++] = (byte)(v >>> 0);370}371} else {372for (int i = 0; i < len; i++) {373long v = Double.doubleToLongBits(d[off + i]);374b[boff++] = (byte)(v >>> 0);375b[boff++] = (byte)(v >>> 8);376b[boff++] = (byte)(v >>> 16);377b[boff++] = (byte)(v >>> 24);378b[boff++] = (byte)(v >>> 32);379b[boff++] = (byte)(v >>> 40);380b[boff++] = (byte)(v >>> 48);381b[boff++] = (byte)(v >>> 56);382}383}384385write(b, 0, len*8);386}387388public void writeBit(int bit) throws IOException {389writeBits((1L & bit), 1);390}391392public void writeBits(long bits, int numBits) throws IOException {393checkClosed();394395if (numBits < 0 || numBits > 64) {396throw new IllegalArgumentException("Bad value for numBits!");397}398if (numBits == 0) {399return;400}401402// Prologue: deal with pre-existing bits403404// Bug 4499158, 4507868 - if we're at the beginning of the stream405// and the bit offset is 0, there can't be any pre-existing bits406if ((getStreamPosition() > 0) || (bitOffset > 0)) {407int offset = bitOffset; // read() will reset bitOffset408int partialByte = read();409if (partialByte != -1) {410seek(getStreamPosition() - 1);411} else {412partialByte = 0;413}414415if (numBits + offset < 8) {416// Notch out the partial byte and drop in the new bits417int shift = 8 - (offset+numBits);418int mask = -1 >>> (32 - numBits);419partialByte &= ~(mask << shift); // Clear out old bits420partialByte |= ((bits & mask) << shift); // Or in new ones421write(partialByte);422seek(getStreamPosition() - 1);423bitOffset = offset + numBits;424numBits = 0; // Signal that we are done425} else {426// Fill out the partial byte and reduce numBits427int num = 8 - offset;428int mask = -1 >>> (32 - num);429partialByte &= ~mask; // Clear out bits430partialByte |= ((bits >> (numBits - num)) & mask);431// Note that bitOffset is already 0, so there is no risk432// of this advancing to the next byte433write(partialByte);434numBits -= num;435}436}437438// Now write any whole bytes439if (numBits > 7) {440int extra = numBits % 8;441for (int numBytes = numBits / 8; numBytes > 0; numBytes--) {442int shift = (numBytes-1)*8+extra;443int value = (int) ((shift == 0)444? bits & 0xFF445: (bits>>shift) & 0xFF);446write(value);447}448numBits = extra;449}450451// Epilogue: write out remaining partial byte, if any452// Note that we may be at EOF, in which case we pad with 0,453// or not, in which case we must preserve the existing bits454if (numBits != 0) {455// If we are not at the end of the file, read the current byte456// If we are at the end of the file, initialize our byte to 0.457int partialByte = 0;458partialByte = read();459if (partialByte != -1) {460seek(getStreamPosition() - 1);461}462// Fix 4494976: writeBit(int) does not pad the remainder463// of the current byte with 0s464else { // EOF465partialByte = 0;466}467468int shift = 8 - numBits;469int mask = -1 >>> (32 - numBits);470partialByte &= ~(mask << shift);471partialByte |= (bits & mask) << shift;472// bitOffset is always already 0 when we get here.473write(partialByte);474seek(getStreamPosition() - 1);475bitOffset = numBits;476}477}478479/**480* If the bit offset is non-zero, forces the remaining bits481* in the current byte to 0 and advances the stream position482* by one. This method should be called by subclasses at the483* beginning of the {@code write(int)} and484* {@code write(byte[], int, int)} methods.485*486* @exception IOException if an I/O error occurs.487*/488protected final void flushBits() throws IOException {489checkClosed();490if (bitOffset != 0) {491int offset = bitOffset;492int partialByte = read(); // Sets bitOffset to 0493if (partialByte < 0) {494// Fix 4465683: When bitOffset is set495// to something non-zero beyond EOF,496// we should set that whole byte to497// zero and write it to stream.498partialByte = 0;499bitOffset = 0;500}501else {502seek(getStreamPosition() - 1);503partialByte &= -1 << (8 - offset);504}505write(partialByte);506}507}508509}510511512