Path: blob/master/src/java.desktop/share/classes/javax/imageio/stream/ImageInputStreamImpl.java
41153 views
/*1* Copyright (c) 2000, 2017, 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.DataInputStream;28import java.io.EOFException;29import java.io.IOException;30import java.nio.ByteOrder;31import java.util.Stack;32import javax.imageio.IIOException;3334/**35* An abstract class implementing the {@code ImageInputStream} interface.36* This class is designed to reduce the number of methods that must37* be implemented by subclasses.38*39* <p> In particular, this class handles most or all of the details of40* byte order interpretation, buffering, mark/reset, discarding,41* closing, and disposing.42*/43public abstract class ImageInputStreamImpl implements ImageInputStream {4445private Stack<Long> markByteStack = new Stack<>();4647private Stack<Integer> markBitStack = new Stack<>();4849private boolean isClosed = false;5051// Length of the buffer used for readFully(type[], int, int)52private static final int BYTE_BUF_LENGTH = 8192;5354/**55* Byte buffer used for readFully(type[], int, int). Note that this56* array is also used for bulk reads in readShort(), readInt(), etc, so57* it should be large enough to hold a primitive value (i.e. >= 8 bytes).58* Also note that this array is package protected, so that it can be59* used by ImageOutputStreamImpl in a similar manner.60*/61byte[] byteBuf = new byte[BYTE_BUF_LENGTH];6263/**64* The byte order of the stream as an instance of the enumeration65* class {@code java.nio.ByteOrder}, where66* {@code ByteOrder.BIG_ENDIAN} indicates network byte order67* and {@code ByteOrder.LITTLE_ENDIAN} indicates the reverse68* order. By default, the value is69* {@code ByteOrder.BIG_ENDIAN}.70*/71protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;7273/**74* The current read position within the stream. Subclasses are75* responsible for keeping this value current from any method they76* override that alters the read position.77*/78protected long streamPos;7980/**81* The current bit offset within the stream. Subclasses are82* responsible for keeping this value current from any method they83* override that alters the bit offset.84*/85protected int bitOffset;8687/**88* The position prior to which data may be discarded. Seeking89* to a smaller position is not allowed. {@code flushedPos}90* will always be {@literal >= 0}.91*/92protected long flushedPos = 0;9394/**95* Constructs an {@code ImageInputStreamImpl}.96*/97public ImageInputStreamImpl() {98}99100/**101* Throws an {@code IOException} if the stream has been closed.102* Subclasses may call this method from any of their methods that103* require the stream not to be closed.104*105* @exception IOException if the stream is closed.106*/107protected final void checkClosed() throws IOException {108if (isClosed) {109throw new IOException("closed");110}111}112113public void setByteOrder(ByteOrder byteOrder) {114this.byteOrder = byteOrder;115}116117public ByteOrder getByteOrder() {118return byteOrder;119}120121/**122* Reads a single byte from the stream and returns it as an123* {@code int} between 0 and 255. If EOF is reached,124* {@code -1} is returned.125*126* <p> Subclasses must provide an implementation for this method.127* The subclass implementation should update the stream position128* before exiting.129*130* <p> The bit offset within the stream must be reset to zero before131* the read occurs.132*133* @return the value of the next byte in the stream, or {@code -1}134* if EOF is reached.135*136* @exception IOException if the stream has been closed.137*/138public abstract int read() throws IOException;139140/**141* A convenience method that calls {@code read(b, 0, b.length)}.142*143* <p> The bit offset within the stream is reset to zero before144* the read occurs.145*146* @return the number of bytes actually read, or {@code -1}147* to indicate EOF.148*149* @exception NullPointerException if {@code b} is150* {@code null}.151* @exception IOException if an I/O error occurs.152*/153public int read(byte[] b) throws IOException {154return read(b, 0, b.length);155}156157/**158* Reads up to {@code len} bytes from the stream, and stores159* them into {@code b} starting at index {@code off}.160* If no bytes can be read because the end of the stream has been161* reached, {@code -1} is returned.162*163* <p> The bit offset within the stream must be reset to zero before164* the read occurs.165*166* <p> Subclasses must provide an implementation for this method.167* The subclass implementation should update the stream position168* before exiting.169*170* @param b an array of bytes to be written to.171* @param off the starting position within {@code b} to write to.172* @param len the maximum number of bytes to read.173*174* @return the number of bytes actually read, or {@code -1}175* to indicate EOF.176*177* @exception IndexOutOfBoundsException if {@code off} is178* negative, {@code len} is negative, or {@code off + len}179* is greater than {@code b.length}.180* @exception NullPointerException if {@code b} is181* {@code null}.182* @exception IOException if an I/O error occurs.183*/184public abstract int read(byte[] b, int off, int len) throws IOException;185186public void readBytes(IIOByteBuffer buf, int len) throws IOException {187if (len < 0) {188throw new IndexOutOfBoundsException("len < 0!");189}190if (buf == null) {191throw new NullPointerException("buf == null!");192}193194byte[] data = new byte[len];195len = read(data, 0, len);196197buf.setData(data);198buf.setOffset(0);199buf.setLength(len);200}201202public boolean readBoolean() throws IOException {203int ch = this.read();204if (ch < 0) {205throw new EOFException();206}207return (ch != 0);208}209210public byte readByte() throws IOException {211int ch = this.read();212if (ch < 0) {213throw new EOFException();214}215return (byte)ch;216}217218public int readUnsignedByte() throws IOException {219int ch = this.read();220if (ch < 0) {221throw new EOFException();222}223return ch;224}225226public short readShort() throws IOException {227if (read(byteBuf, 0, 2) != 2) {228throw new EOFException();229}230231if (byteOrder == ByteOrder.BIG_ENDIAN) {232return (short)233(((byteBuf[0] & 0xff) << 8) | ((byteBuf[1] & 0xff) << 0));234} else {235return (short)236(((byteBuf[1] & 0xff) << 8) | ((byteBuf[0] & 0xff) << 0));237}238}239240public int readUnsignedShort() throws IOException {241return ((int)readShort()) & 0xffff;242}243244public char readChar() throws IOException {245return (char)readShort();246}247248public int readInt() throws IOException {249if (read(byteBuf, 0, 4) != 4) {250throw new EOFException();251}252253if (byteOrder == ByteOrder.BIG_ENDIAN) {254return255(((byteBuf[0] & 0xff) << 24) | ((byteBuf[1] & 0xff) << 16) |256((byteBuf[2] & 0xff) << 8) | ((byteBuf[3] & 0xff) << 0));257} else {258return259(((byteBuf[3] & 0xff) << 24) | ((byteBuf[2] & 0xff) << 16) |260((byteBuf[1] & 0xff) << 8) | ((byteBuf[0] & 0xff) << 0));261}262}263264public long readUnsignedInt() throws IOException {265return ((long)readInt()) & 0xffffffffL;266}267268public long readLong() throws IOException {269// REMIND: Once 6277756 is fixed, we should do a bulk read of all 8270// bytes here as we do in readShort() and readInt() for even better271// performance (see 6347575 for details).272int i1 = readInt();273int i2 = readInt();274275if (byteOrder == ByteOrder.BIG_ENDIAN) {276return ((long)i1 << 32) + (i2 & 0xFFFFFFFFL);277} else {278return ((long)i2 << 32) + (i1 & 0xFFFFFFFFL);279}280}281282public float readFloat() throws IOException {283return Float.intBitsToFloat(readInt());284}285286public double readDouble() throws IOException {287return Double.longBitsToDouble(readLong());288}289290public String readLine() throws IOException {291StringBuilder input = new StringBuilder();292int c = -1;293boolean eol = false;294295while (!eol) {296switch (c = read()) {297case -1:298case '\n':299eol = true;300break;301case '\r':302eol = true;303long cur = getStreamPosition();304if ((read()) != '\n') {305seek(cur);306}307break;308default:309input.append((char)c);310break;311}312}313314if ((c == -1) && (input.length() == 0)) {315return null;316}317return input.toString();318}319320public String readUTF() throws IOException {321this.bitOffset = 0;322323// Fix 4494369: method ImageInputStreamImpl.readUTF()324// does not work as specified (it should always assume325// network byte order).326ByteOrder oldByteOrder = getByteOrder();327setByteOrder(ByteOrder.BIG_ENDIAN);328329String ret;330try {331ret = DataInputStream.readUTF(this);332} catch (IOException e) {333// Restore the old byte order even if an exception occurs334setByteOrder(oldByteOrder);335throw e;336}337338setByteOrder(oldByteOrder);339return ret;340}341342public void readFully(byte[] b, int off, int len) throws IOException {343// Fix 4430357 - if off + len < 0, overflow occurred344if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {345throw new IndexOutOfBoundsException346("off < 0 || len < 0 || off + len > b.length!");347}348349while (len > 0) {350int nbytes = read(b, off, len);351if (nbytes == -1) {352throw new EOFException();353}354off += nbytes;355len -= nbytes;356}357}358359public void readFully(byte[] b) throws IOException {360readFully(b, 0, b.length);361}362363public void readFully(short[] s, int off, int len) throws IOException {364// Fix 4430357 - if off + len < 0, overflow occurred365if (off < 0 || len < 0 || off + len > s.length || off + len < 0) {366throw new IndexOutOfBoundsException367("off < 0 || len < 0 || off + len > s.length!");368}369370while (len > 0) {371int nelts = Math.min(len, byteBuf.length/2);372readFully(byteBuf, 0, nelts*2);373toShorts(byteBuf, s, off, nelts);374off += nelts;375len -= nelts;376}377}378379public void readFully(char[] c, int off, int len) throws IOException {380// Fix 4430357 - if off + len < 0, overflow occurred381if (off < 0 || len < 0 || off + len > c.length || off + len < 0) {382throw new IndexOutOfBoundsException383("off < 0 || len < 0 || off + len > c.length!");384}385386while (len > 0) {387int nelts = Math.min(len, byteBuf.length/2);388readFully(byteBuf, 0, nelts*2);389toChars(byteBuf, c, off, nelts);390off += nelts;391len -= nelts;392}393}394395public void readFully(int[] i, int off, int len) throws IOException {396// Fix 4430357 - if off + len < 0, overflow occurred397if (off < 0 || len < 0 || off + len > i.length || off + len < 0) {398throw new IndexOutOfBoundsException399("off < 0 || len < 0 || off + len > i.length!");400}401402while (len > 0) {403int nelts = Math.min(len, byteBuf.length/4);404readFully(byteBuf, 0, nelts*4);405toInts(byteBuf, i, off, nelts);406off += nelts;407len -= nelts;408}409}410411public void readFully(long[] l, int off, int len) throws IOException {412// Fix 4430357 - if off + len < 0, overflow occurred413if (off < 0 || len < 0 || off + len > l.length || off + len < 0) {414throw new IndexOutOfBoundsException415("off < 0 || len < 0 || off + len > l.length!");416}417418while (len > 0) {419int nelts = Math.min(len, byteBuf.length/8);420readFully(byteBuf, 0, nelts*8);421toLongs(byteBuf, l, off, nelts);422off += nelts;423len -= nelts;424}425}426427public void readFully(float[] f, int off, int len) throws IOException {428// Fix 4430357 - if off + len < 0, overflow occurred429if (off < 0 || len < 0 || off + len > f.length || off + len < 0) {430throw new IndexOutOfBoundsException431("off < 0 || len < 0 || off + len > f.length!");432}433434while (len > 0) {435int nelts = Math.min(len, byteBuf.length/4);436readFully(byteBuf, 0, nelts*4);437toFloats(byteBuf, f, off, nelts);438off += nelts;439len -= nelts;440}441}442443public void readFully(double[] d, int off, int len) throws IOException {444// Fix 4430357 - if off + len < 0, overflow occurred445if (off < 0 || len < 0 || off + len > d.length || off + len < 0) {446throw new IndexOutOfBoundsException447("off < 0 || len < 0 || off + len > d.length!");448}449450while (len > 0) {451int nelts = Math.min(len, byteBuf.length/8);452readFully(byteBuf, 0, nelts*8);453toDoubles(byteBuf, d, off, nelts);454off += nelts;455len -= nelts;456}457}458459private void toShorts(byte[] b, short[] s, int off, int len) {460int boff = 0;461if (byteOrder == ByteOrder.BIG_ENDIAN) {462for (int j = 0; j < len; j++) {463int b0 = b[boff];464int b1 = b[boff + 1] & 0xff;465s[off + j] = (short)((b0 << 8) | b1);466boff += 2;467}468} else {469for (int j = 0; j < len; j++) {470int b0 = b[boff + 1];471int b1 = b[boff] & 0xff;472s[off + j] = (short)((b0 << 8) | b1);473boff += 2;474}475}476}477478private void toChars(byte[] b, char[] c, int off, int len) {479int boff = 0;480if (byteOrder == ByteOrder.BIG_ENDIAN) {481for (int j = 0; j < len; j++) {482int b0 = b[boff];483int b1 = b[boff + 1] & 0xff;484c[off + j] = (char)((b0 << 8) | b1);485boff += 2;486}487} else {488for (int j = 0; j < len; j++) {489int b0 = b[boff + 1];490int b1 = b[boff] & 0xff;491c[off + j] = (char)((b0 << 8) | b1);492boff += 2;493}494}495}496497private void toInts(byte[] b, int[] i, int off, int len) {498int boff = 0;499if (byteOrder == ByteOrder.BIG_ENDIAN) {500for (int j = 0; j < len; j++) {501int b0 = b[boff];502int b1 = b[boff + 1] & 0xff;503int b2 = b[boff + 2] & 0xff;504int b3 = b[boff + 3] & 0xff;505i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;506boff += 4;507}508} else {509for (int j = 0; j < len; j++) {510int b0 = b[boff + 3];511int b1 = b[boff + 2] & 0xff;512int b2 = b[boff + 1] & 0xff;513int b3 = b[boff] & 0xff;514i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;515boff += 4;516}517}518}519520private void toLongs(byte[] b, long[] l, int off, int len) {521int boff = 0;522if (byteOrder == ByteOrder.BIG_ENDIAN) {523for (int j = 0; j < len; j++) {524int b0 = b[boff];525int b1 = b[boff + 1] & 0xff;526int b2 = b[boff + 2] & 0xff;527int b3 = b[boff + 3] & 0xff;528int b4 = b[boff + 4];529int b5 = b[boff + 5] & 0xff;530int b6 = b[boff + 6] & 0xff;531int b7 = b[boff + 7] & 0xff;532533int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;534int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;535536l[off + j] = ((long)i0 << 32) | (i1 & 0xffffffffL);537boff += 8;538}539} else {540for (int j = 0; j < len; j++) {541int b0 = b[boff + 7];542int b1 = b[boff + 6] & 0xff;543int b2 = b[boff + 5] & 0xff;544int b3 = b[boff + 4] & 0xff;545int b4 = b[boff + 3];546int b5 = b[boff + 2] & 0xff;547int b6 = b[boff + 1] & 0xff;548int b7 = b[boff] & 0xff;549550int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;551int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;552553l[off + j] = ((long)i0 << 32) | (i1 & 0xffffffffL);554boff += 8;555}556}557}558559private void toFloats(byte[] b, float[] f, int off, int len) {560int boff = 0;561if (byteOrder == ByteOrder.BIG_ENDIAN) {562for (int j = 0; j < len; j++) {563int b0 = b[boff];564int b1 = b[boff + 1] & 0xff;565int b2 = b[boff + 2] & 0xff;566int b3 = b[boff + 3] & 0xff;567int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;568f[off + j] = Float.intBitsToFloat(i);569boff += 4;570}571} else {572for (int j = 0; j < len; j++) {573int b0 = b[boff + 3];574int b1 = b[boff + 2] & 0xff;575int b2 = b[boff + 1] & 0xff;576int b3 = b[boff + 0] & 0xff;577int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;578f[off + j] = Float.intBitsToFloat(i);579boff += 4;580}581}582}583584private void toDoubles(byte[] b, double[] d, int off, int len) {585int boff = 0;586if (byteOrder == ByteOrder.BIG_ENDIAN) {587for (int j = 0; j < len; j++) {588int b0 = b[boff];589int b1 = b[boff + 1] & 0xff;590int b2 = b[boff + 2] & 0xff;591int b3 = b[boff + 3] & 0xff;592int b4 = b[boff + 4];593int b5 = b[boff + 5] & 0xff;594int b6 = b[boff + 6] & 0xff;595int b7 = b[boff + 7] & 0xff;596597int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;598int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;599long l = ((long)i0 << 32) | (i1 & 0xffffffffL);600601d[off + j] = Double.longBitsToDouble(l);602boff += 8;603}604} else {605for (int j = 0; j < len; j++) {606int b0 = b[boff + 7];607int b1 = b[boff + 6] & 0xff;608int b2 = b[boff + 5] & 0xff;609int b3 = b[boff + 4] & 0xff;610int b4 = b[boff + 3];611int b5 = b[boff + 2] & 0xff;612int b6 = b[boff + 1] & 0xff;613int b7 = b[boff] & 0xff;614615int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;616int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;617long l = ((long)i0 << 32) | (i1 & 0xffffffffL);618619d[off + j] = Double.longBitsToDouble(l);620boff += 8;621}622}623}624625public long getStreamPosition() throws IOException {626checkClosed();627return streamPos;628}629630public int getBitOffset() throws IOException {631checkClosed();632return bitOffset;633}634635public void setBitOffset(int bitOffset) throws IOException {636checkClosed();637if (bitOffset < 0 || bitOffset > 7) {638throw new IllegalArgumentException("bitOffset must be betwwen 0 and 7!");639}640this.bitOffset = bitOffset;641}642643public int readBit() throws IOException {644checkClosed();645646// Compute final bit offset before we call read() and seek()647int newBitOffset = (this.bitOffset + 1) & 0x7;648649int val = read();650if (val == -1) {651throw new EOFException();652}653654if (newBitOffset != 0) {655// Move byte position back if in the middle of a byte656seek(getStreamPosition() - 1);657// Shift the bit to be read to the rightmost position658val >>= 8 - newBitOffset;659}660this.bitOffset = newBitOffset;661662return val & 0x1;663}664665public long readBits(int numBits) throws IOException {666checkClosed();667668if (numBits < 0 || numBits > 64) {669throw new IllegalArgumentException();670}671if (numBits == 0) {672return 0L;673}674675// Have to read additional bits on the left equal to the bit offset676int bitsToRead = numBits + bitOffset;677678// Compute final bit offset before we call read() and seek()679int newBitOffset = (this.bitOffset + numBits) & 0x7;680681// Read a byte at a time, accumulate682long accum = 0L;683while (bitsToRead > 0) {684int val = read();685if (val == -1) {686throw new EOFException();687}688689accum <<= 8;690accum |= val;691bitsToRead -= 8;692}693694// Move byte position back if in the middle of a byte695if (newBitOffset != 0) {696seek(getStreamPosition() - 1);697}698this.bitOffset = newBitOffset;699700// Shift away unwanted bits on the right.701accum >>>= (-bitsToRead); // Negative of bitsToRead == extra bits read702703// Mask out unwanted bits on the left704accum &= (-1L >>> (64 - numBits));705706return accum;707}708709/**710* Returns {@code -1L} to indicate that the stream has unknown711* length. Subclasses must override this method to provide actual712* length information.713*714* @return -1L to indicate unknown length.715*/716public long length() {717return -1L;718}719720/**721* Advances the current stream position by calling722* {@code seek(getStreamPosition() + n)}.723*724* <p> The bit offset is reset to zero.725*726* @param n the number of bytes to seek forward.727*728* @return an {@code int} representing the number of bytes729* skipped.730*731* @exception IOException if {@code getStreamPosition}732* throws an {@code IOException} when computing either733* the starting or ending position.734*/735public int skipBytes(int n) throws IOException {736long pos = getStreamPosition();737seek(pos + n);738return (int)(getStreamPosition() - pos);739}740741/**742* Advances the current stream position by calling743* {@code seek(getStreamPosition() + n)}.744*745* <p> The bit offset is reset to zero.746*747* @param n the number of bytes to seek forward.748*749* @return a {@code long} representing the number of bytes750* skipped.751*752* @exception IOException if {@code getStreamPosition}753* throws an {@code IOException} when computing either754* the starting or ending position.755*/756public long skipBytes(long n) throws IOException {757long pos = getStreamPosition();758seek(pos + n);759return getStreamPosition() - pos;760}761762public void seek(long pos) throws IOException {763checkClosed();764765// This test also covers pos < 0766if (pos < flushedPos) {767throw new IndexOutOfBoundsException("pos < flushedPos!");768}769770this.streamPos = pos;771this.bitOffset = 0;772}773774/**775* Pushes the current stream position onto a stack of marked776* positions.777*/778public void mark() {779try {780markByteStack.push(Long.valueOf(getStreamPosition()));781markBitStack.push(Integer.valueOf(getBitOffset()));782} catch (IOException e) {783}784}785786/**787* Resets the current stream byte and bit positions from the stack788* of marked positions.789*790* <p> An {@code IOException} will be thrown if the previous791* marked position lies in the discarded portion of the stream.792*793* @exception IOException if an I/O error occurs.794*/795public void reset() throws IOException {796if (markByteStack.empty()) {797return;798}799800long pos = markByteStack.pop().longValue();801if (pos < flushedPos) {802throw new IIOException803("Previous marked position has been discarded!");804}805seek(pos);806807int offset = markBitStack.pop().intValue();808setBitOffset(offset);809}810811public void flushBefore(long pos) throws IOException {812checkClosed();813if (pos < flushedPos) {814throw new IndexOutOfBoundsException("pos < flushedPos!");815}816if (pos > getStreamPosition()) {817throw new IndexOutOfBoundsException("pos > getStreamPosition()!");818}819// Invariant: flushedPos >= 0820flushedPos = pos;821}822823public void flush() throws IOException {824flushBefore(getStreamPosition());825}826827public long getFlushedPosition() {828return flushedPos;829}830831/**832* Default implementation returns false. Subclasses should833* override this if they cache data.834*/835public boolean isCached() {836return false;837}838839/**840* Default implementation returns false. Subclasses should841* override this if they cache data in main memory.842*/843public boolean isCachedMemory() {844return false;845}846847/**848* Default implementation returns false. Subclasses should849* override this if they cache data in a temporary file.850*/851public boolean isCachedFile() {852return false;853}854855public void close() throws IOException {856checkClosed();857858isClosed = true;859}860861/**862* Finalizes this object prior to garbage collection. The863* {@code close} method is called to close any open input864* source. This method should not be called from application865* code.866*867* @exception Throwable if an error occurs during superclass868* finalization.869*870* @deprecated The {@code finalize} method has been deprecated.871* Subclasses that override {@code finalize} in order to perform cleanup872* should be modified to use alternative cleanup mechanisms and873* to remove the overriding {@code finalize} method.874* When overriding the {@code finalize} method, its implementation must explicitly875* ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.876* See the specification for {@link Object#finalize()} for further877* information about migration options.878*/879@Deprecated(since="9")880protected void finalize() throws Throwable {881if (!isClosed) {882try {883close();884} catch (IOException e) {885}886}887super.finalize();888}889}890891892