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.DataInputStream;
29 import java.io.EOFException;
30 import java.io.IOException;
31 import java.nio.ByteOrder;
32 import java.util.Stack;
33 import javax.imageio.IIOException;
34
35 /**
36 * An abstract class implementing the <code>ImageInputStream</code> interface.
37 * This class is designed to reduce the number of methods that must
38 * be implemented by subclasses.
39 *
40 * <p> In particular, this class handles most or all of the details of
41 * byte order interpretation, buffering, mark/reset, discarding,
42 * closing, and disposing.
43 */
44 public abstract class ImageInputStreamImpl implements ImageInputStream {
45
46 private Stack<Long> markByteStack = new Stack<>();
47
48 private Stack<Integer> markBitStack = new Stack<>();
49
50 private boolean isClosed = false;
51
52 // Length of the buffer used for readFully(type[], int, int)
53 private static final int BYTE_BUF_LENGTH = 8192;
54
55 /**
56 * Byte buffer used for readFully(type[], int, int). Note that this
57 * array is also used for bulk reads in readShort(), readInt(), etc, so
58 * it should be large enough to hold a primitive value (i.e. >= 8 bytes).
59 * Also note that this array is package protected, so that it can be
60 * used by ImageOutputStreamImpl in a similar manner.
61 */
62 byte[] byteBuf = new byte[BYTE_BUF_LENGTH];
63
64 /**
65 * The byte order of the stream as an instance of the enumeration
66 * class <code>java.nio.ByteOrder</code>, where
67 * <code>ByteOrder.BIG_ENDIAN</code> indicates network byte order
68 * and <code>ByteOrder.LITTLE_ENDIAN</code> indicates the reverse
69 * order. By default, the value is
70 * <code>ByteOrder.BIG_ENDIAN</code>.
71 */
72 protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
73
74 /**
75 * The current read position within the stream. Subclasses are
76 * responsible for keeping this value current from any method they
77 * override that alters the read position.
78 */
79 protected long streamPos;
80
81 /**
82 * The current bit offset within the stream. Subclasses are
83 * responsible for keeping this value current from any method they
84 * override that alters the bit offset.
85 */
86 protected int bitOffset;
87
88 /**
89 * The position prior to which data may be discarded. Seeking
90 * to a smaller position is not allowed. <code>flushedPos</code>
91 * will always be {@literal >= 0}.
92 */
93 protected long flushedPos = 0;
94
95 /**
96 * Constructs an <code>ImageInputStreamImpl</code>.
97 */
98 public ImageInputStreamImpl() {
99 }
100
101 /**
102 * Throws an <code>IOException</code> if the stream has been closed.
103 * Subclasses may call this method from any of their methods that
104 * require the stream not to be closed.
105 *
106 * @exception IOException if the stream is closed.
107 */
108 protected final void checkClosed() throws IOException {
109 if (isClosed) {
110 throw new IOException("closed");
111 }
112 }
113
114 public void setByteOrder(ByteOrder byteOrder) {
115 this.byteOrder = byteOrder;
116 }
117
118 public ByteOrder getByteOrder() {
119 return byteOrder;
120 }
121
122 /**
123 * Reads a single byte from the stream and returns it as an
124 * <code>int</code> between 0 and 255. If EOF is reached,
125 * <code>-1</code> is returned.
126 *
127 * <p> Subclasses must provide an implementation for this method.
128 * The subclass implementation should update the stream position
129 * before exiting.
130 *
131 * <p> The bit offset within the stream must be reset to zero before
132 * the read occurs.
133 *
134 * @return the value of the next byte in the stream, or <code>-1</code>
135 * if EOF is reached.
136 *
137 * @exception IOException if the stream has been closed.
138 */
139 public abstract int read() throws IOException;
140
141 /**
142 * A convenience method that calls <code>read(b, 0, b.length)</code>.
143 *
144 * <p> The bit offset within the stream is reset to zero before
145 * the read occurs.
146 *
147 * @return the number of bytes actually read, or <code>-1</code>
148 * to indicate EOF.
149 *
150 * @exception NullPointerException if <code>b</code> is
151 * <code>null</code>.
152 * @exception IOException if an I/O error occurs.
153 */
154 public int read(byte[] b) throws IOException {
155 return read(b, 0, b.length);
156 }
157
158 /**
159 * Reads up to <code>len</code> bytes from the stream, and stores
160 * them into <code>b</code> starting at index <code>off</code>.
161 * If no bytes can be read because the end of the stream has been
162 * reached, <code>-1</code> is returned.
163 *
164 * <p> The bit offset within the stream must be reset to zero before
165 * the read occurs.
166 *
167 * <p> Subclasses must provide an implementation for this method.
168 * The subclass implementation should update the stream position
169 * before exiting.
170 *
171 * @param b an array of bytes to be written to.
172 * @param off the starting position within <code>b</code> to write to.
173 * @param len the maximum number of bytes to read.
174 *
175 * @return the number of bytes actually read, or <code>-1</code>
176 * to indicate EOF.
177 *
178 * @exception IndexOutOfBoundsException if <code>off</code> is
179 * negative, <code>len</code> is negative, or <code>off +
180 * len</code> is greater than <code>b.length</code>.
181 * @exception NullPointerException if <code>b</code> is
182 * <code>null</code>.
183 * @exception IOException if an I/O error occurs.
184 */
185 public abstract int read(byte[] b, int off, int len) throws IOException;
186
187 public void readBytes(IIOByteBuffer buf, int len) throws IOException {
188 if (len < 0) {
189 throw new IndexOutOfBoundsException("len < 0!");
190 }
191 if (buf == null) {
192 throw new NullPointerException("buf == null!");
193 }
194
195 byte[] data = new byte[len];
196 len = read(data, 0, len);
197
198 buf.setData(data);
199 buf.setOffset(0);
200 buf.setLength(len);
201 }
202
691 accum |= val;
692 bitsToRead -= 8;
693 }
694
695 // Move byte position back if in the middle of a byte
696 if (newBitOffset != 0) {
697 seek(getStreamPosition() - 1);
698 }
699 this.bitOffset = newBitOffset;
700
701 // Shift away unwanted bits on the right.
702 accum >>>= (-bitsToRead); // Negative of bitsToRead == extra bits read
703
704 // Mask out unwanted bits on the left
705 accum &= (-1L >>> (64 - numBits));
706
707 return accum;
708 }
709
710 /**
711 * Returns <code>-1L</code> to indicate that the stream has unknown
712 * length. Subclasses must override this method to provide actual
713 * length information.
714 *
715 * @return -1L to indicate unknown length.
716 */
717 public long length() {
718 return -1L;
719 }
720
721 /**
722 * Advances the current stream position by calling
723 * <code>seek(getStreamPosition() + n)</code>.
724 *
725 * <p> The bit offset is reset to zero.
726 *
727 * @param n the number of bytes to seek forward.
728 *
729 * @return an <code>int</code> representing the number of bytes
730 * skipped.
731 *
732 * @exception IOException if <code>getStreamPosition</code>
733 * throws an <code>IOException</code> when computing either
734 * the starting or ending position.
735 */
736 public int skipBytes(int n) throws IOException {
737 long pos = getStreamPosition();
738 seek(pos + n);
739 return (int)(getStreamPosition() - pos);
740 }
741
742 /**
743 * Advances the current stream position by calling
744 * <code>seek(getStreamPosition() + n)</code>.
745 *
746 * <p> The bit offset is reset to zero.
747 *
748 * @param n the number of bytes to seek forward.
749 *
750 * @return a <code>long</code> representing the number of bytes
751 * skipped.
752 *
753 * @exception IOException if <code>getStreamPosition</code>
754 * throws an <code>IOException</code> when computing either
755 * the starting or ending position.
756 */
757 public long skipBytes(long n) throws IOException {
758 long pos = getStreamPosition();
759 seek(pos + n);
760 return getStreamPosition() - pos;
761 }
762
763 public void seek(long pos) throws IOException {
764 checkClosed();
765
766 // This test also covers pos < 0
767 if (pos < flushedPos) {
768 throw new IndexOutOfBoundsException("pos < flushedPos!");
769 }
770
771 this.streamPos = pos;
772 this.bitOffset = 0;
773 }
774
775 /**
776 * Pushes the current stream position onto a stack of marked
777 * positions.
778 */
779 public void mark() {
780 try {
781 markByteStack.push(Long.valueOf(getStreamPosition()));
782 markBitStack.push(Integer.valueOf(getBitOffset()));
783 } catch (IOException e) {
784 }
785 }
786
787 /**
788 * Resets the current stream byte and bit positions from the stack
789 * of marked positions.
790 *
791 * <p> An <code>IOException</code> will be thrown if the previous
792 * marked position lies in the discarded portion of the stream.
793 *
794 * @exception IOException if an I/O error occurs.
795 */
796 public void reset() throws IOException {
797 if (markByteStack.empty()) {
798 return;
799 }
800
801 long pos = markByteStack.pop().longValue();
802 if (pos < flushedPos) {
803 throw new IIOException
804 ("Previous marked position has been discarded!");
805 }
806 seek(pos);
807
808 int offset = markBitStack.pop().intValue();
809 setBitOffset(offset);
810 }
811
844 public boolean isCachedMemory() {
845 return false;
846 }
847
848 /**
849 * Default implementation returns false. Subclasses should
850 * override this if they cache data in a temporary file.
851 */
852 public boolean isCachedFile() {
853 return false;
854 }
855
856 public void close() throws IOException {
857 checkClosed();
858
859 isClosed = true;
860 }
861
862 /**
863 * Finalizes this object prior to garbage collection. The
864 * <code>close</code> method is called to close any open input
865 * source. This method should not be called from application
866 * code.
867 *
868 * @exception Throwable if an error occurs during superclass
869 * finalization.
870 */
871 protected void finalize() throws Throwable {
872 if (!isClosed) {
873 try {
874 close();
875 } catch (IOException e) {
876 }
877 }
878 super.finalize();
879 }
880 }
|
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.DataInputStream;
29 import java.io.EOFException;
30 import java.io.IOException;
31 import java.nio.ByteOrder;
32 import java.util.Stack;
33 import javax.imageio.IIOException;
34
35 /**
36 * An abstract class implementing the {@code ImageInputStream} interface.
37 * This class is designed to reduce the number of methods that must
38 * be implemented by subclasses.
39 *
40 * <p> In particular, this class handles most or all of the details of
41 * byte order interpretation, buffering, mark/reset, discarding,
42 * closing, and disposing.
43 */
44 public abstract class ImageInputStreamImpl implements ImageInputStream {
45
46 private Stack<Long> markByteStack = new Stack<>();
47
48 private Stack<Integer> markBitStack = new Stack<>();
49
50 private boolean isClosed = false;
51
52 // Length of the buffer used for readFully(type[], int, int)
53 private static final int BYTE_BUF_LENGTH = 8192;
54
55 /**
56 * Byte buffer used for readFully(type[], int, int). Note that this
57 * array is also used for bulk reads in readShort(), readInt(), etc, so
58 * it should be large enough to hold a primitive value (i.e. >= 8 bytes).
59 * Also note that this array is package protected, so that it can be
60 * used by ImageOutputStreamImpl in a similar manner.
61 */
62 byte[] byteBuf = new byte[BYTE_BUF_LENGTH];
63
64 /**
65 * The byte order of the stream as an instance of the enumeration
66 * class {@code java.nio.ByteOrder}, where
67 * {@code ByteOrder.BIG_ENDIAN} indicates network byte order
68 * and {@code ByteOrder.LITTLE_ENDIAN} indicates the reverse
69 * order. By default, the value is
70 * {@code ByteOrder.BIG_ENDIAN}.
71 */
72 protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
73
74 /**
75 * The current read position within the stream. Subclasses are
76 * responsible for keeping this value current from any method they
77 * override that alters the read position.
78 */
79 protected long streamPos;
80
81 /**
82 * The current bit offset within the stream. Subclasses are
83 * responsible for keeping this value current from any method they
84 * override that alters the bit offset.
85 */
86 protected int bitOffset;
87
88 /**
89 * The position prior to which data may be discarded. Seeking
90 * to a smaller position is not allowed. {@code flushedPos}
91 * will always be {@literal >= 0}.
92 */
93 protected long flushedPos = 0;
94
95 /**
96 * Constructs an {@code ImageInputStreamImpl}.
97 */
98 public ImageInputStreamImpl() {
99 }
100
101 /**
102 * Throws an {@code IOException} if the stream has been closed.
103 * Subclasses may call this method from any of their methods that
104 * require the stream not to be closed.
105 *
106 * @exception IOException if the stream is closed.
107 */
108 protected final void checkClosed() throws IOException {
109 if (isClosed) {
110 throw new IOException("closed");
111 }
112 }
113
114 public void setByteOrder(ByteOrder byteOrder) {
115 this.byteOrder = byteOrder;
116 }
117
118 public ByteOrder getByteOrder() {
119 return byteOrder;
120 }
121
122 /**
123 * Reads a single byte from the stream and returns it as an
124 * {@code int} between 0 and 255. If EOF is reached,
125 * {@code -1} is returned.
126 *
127 * <p> Subclasses must provide an implementation for this method.
128 * The subclass implementation should update the stream position
129 * before exiting.
130 *
131 * <p> The bit offset within the stream must be reset to zero before
132 * the read occurs.
133 *
134 * @return the value of the next byte in the stream, or {@code -1}
135 * if EOF is reached.
136 *
137 * @exception IOException if the stream has been closed.
138 */
139 public abstract int read() throws IOException;
140
141 /**
142 * A convenience method that calls {@code read(b, 0, b.length)}.
143 *
144 * <p> The bit offset within the stream is reset to zero before
145 * the read occurs.
146 *
147 * @return the number of bytes actually read, or {@code -1}
148 * to indicate EOF.
149 *
150 * @exception NullPointerException if {@code b} is
151 * {@code null}.
152 * @exception IOException if an I/O error occurs.
153 */
154 public int read(byte[] b) throws IOException {
155 return read(b, 0, b.length);
156 }
157
158 /**
159 * Reads up to {@code len} bytes from the stream, and stores
160 * them into {@code b} starting at index {@code off}.
161 * If no bytes can be read because the end of the stream has been
162 * reached, {@code -1} is returned.
163 *
164 * <p> The bit offset within the stream must be reset to zero before
165 * the read occurs.
166 *
167 * <p> Subclasses must provide an implementation for this method.
168 * The subclass implementation should update the stream position
169 * before exiting.
170 *
171 * @param b an array of bytes to be written to.
172 * @param off the starting position within {@code b} to write to.
173 * @param len the maximum number of bytes to read.
174 *
175 * @return the number of bytes actually read, or {@code -1}
176 * to indicate EOF.
177 *
178 * @exception IndexOutOfBoundsException if {@code off} is
179 * negative, {@code len} is negative, or {@code off + len}
180 * is greater than {@code b.length}.
181 * @exception NullPointerException if {@code b} is
182 * {@code null}.
183 * @exception IOException if an I/O error occurs.
184 */
185 public abstract int read(byte[] b, int off, int len) throws IOException;
186
187 public void readBytes(IIOByteBuffer buf, int len) throws IOException {
188 if (len < 0) {
189 throw new IndexOutOfBoundsException("len < 0!");
190 }
191 if (buf == null) {
192 throw new NullPointerException("buf == null!");
193 }
194
195 byte[] data = new byte[len];
196 len = read(data, 0, len);
197
198 buf.setData(data);
199 buf.setOffset(0);
200 buf.setLength(len);
201 }
202
691 accum |= val;
692 bitsToRead -= 8;
693 }
694
695 // Move byte position back if in the middle of a byte
696 if (newBitOffset != 0) {
697 seek(getStreamPosition() - 1);
698 }
699 this.bitOffset = newBitOffset;
700
701 // Shift away unwanted bits on the right.
702 accum >>>= (-bitsToRead); // Negative of bitsToRead == extra bits read
703
704 // Mask out unwanted bits on the left
705 accum &= (-1L >>> (64 - numBits));
706
707 return accum;
708 }
709
710 /**
711 * Returns {@code -1L} to indicate that the stream has unknown
712 * length. Subclasses must override this method to provide actual
713 * length information.
714 *
715 * @return -1L to indicate unknown length.
716 */
717 public long length() {
718 return -1L;
719 }
720
721 /**
722 * Advances the current stream position by calling
723 * {@code seek(getStreamPosition() + n)}.
724 *
725 * <p> The bit offset is reset to zero.
726 *
727 * @param n the number of bytes to seek forward.
728 *
729 * @return an {@code int} representing the number of bytes
730 * skipped.
731 *
732 * @exception IOException if {@code getStreamPosition}
733 * throws an {@code IOException} when computing either
734 * the starting or ending position.
735 */
736 public int skipBytes(int n) throws IOException {
737 long pos = getStreamPosition();
738 seek(pos + n);
739 return (int)(getStreamPosition() - pos);
740 }
741
742 /**
743 * Advances the current stream position by calling
744 * {@code seek(getStreamPosition() + n)}.
745 *
746 * <p> The bit offset is reset to zero.
747 *
748 * @param n the number of bytes to seek forward.
749 *
750 * @return a {@code long} representing the number of bytes
751 * skipped.
752 *
753 * @exception IOException if {@code getStreamPosition}
754 * throws an {@code IOException} when computing either
755 * the starting or ending position.
756 */
757 public long skipBytes(long n) throws IOException {
758 long pos = getStreamPosition();
759 seek(pos + n);
760 return getStreamPosition() - pos;
761 }
762
763 public void seek(long pos) throws IOException {
764 checkClosed();
765
766 // This test also covers pos < 0
767 if (pos < flushedPos) {
768 throw new IndexOutOfBoundsException("pos < flushedPos!");
769 }
770
771 this.streamPos = pos;
772 this.bitOffset = 0;
773 }
774
775 /**
776 * Pushes the current stream position onto a stack of marked
777 * positions.
778 */
779 public void mark() {
780 try {
781 markByteStack.push(Long.valueOf(getStreamPosition()));
782 markBitStack.push(Integer.valueOf(getBitOffset()));
783 } catch (IOException e) {
784 }
785 }
786
787 /**
788 * Resets the current stream byte and bit positions from the stack
789 * of marked positions.
790 *
791 * <p> An {@code IOException} will be thrown if the previous
792 * marked position lies in the discarded portion of the stream.
793 *
794 * @exception IOException if an I/O error occurs.
795 */
796 public void reset() throws IOException {
797 if (markByteStack.empty()) {
798 return;
799 }
800
801 long pos = markByteStack.pop().longValue();
802 if (pos < flushedPos) {
803 throw new IIOException
804 ("Previous marked position has been discarded!");
805 }
806 seek(pos);
807
808 int offset = markBitStack.pop().intValue();
809 setBitOffset(offset);
810 }
811
844 public boolean isCachedMemory() {
845 return false;
846 }
847
848 /**
849 * Default implementation returns false. Subclasses should
850 * override this if they cache data in a temporary file.
851 */
852 public boolean isCachedFile() {
853 return false;
854 }
855
856 public void close() throws IOException {
857 checkClosed();
858
859 isClosed = true;
860 }
861
862 /**
863 * Finalizes this object prior to garbage collection. The
864 * {@code close} method is called to close any open input
865 * source. This method should not be called from application
866 * code.
867 *
868 * @exception Throwable if an error occurs during superclass
869 * finalization.
870 */
871 protected void finalize() throws Throwable {
872 if (!isClosed) {
873 try {
874 close();
875 } catch (IOException e) {
876 }
877 }
878 super.finalize();
879 }
880 }
|