History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/imageio/stream/ImageInputStreamImpl.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/imageio/stream/ImageInputStreamImpl.java+880−0
@@ -0,0 +1,880 @@
1+/*
2+ * Copyright (c) 2000, 2008, 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.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 markByteStack = new Stack();
47+
48+ private Stack 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 >= 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+
203+ public boolean readBoolean() throws IOException {
204+ int ch = this.read();
205+ if (ch < 0) {
206+ throw new EOFException();
207+ }
208+ return (ch != 0);
209+ }
210+
211+ public byte readByte() throws IOException {
212+ int ch = this.read();
213+ if (ch < 0) {
214+ throw new EOFException();
215+ }
216+ return (byte)ch;
217+ }
218+
219+ public int readUnsignedByte() throws IOException {
220+ int ch = this.read();
221+ if (ch < 0) {
222+ throw new EOFException();
223+ }
224+ return ch;
225+ }
226+
227+ public short readShort() throws IOException {
228+ if (read(byteBuf, 0, 2) < 0) {
229+ throw new EOFException();
230+ }
231+
232+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
233+ return (short)
234+ (((byteBuf[0] & 0xff) << 8) | ((byteBuf[1] & 0xff) << 0));
235+ } else {
236+ return (short)
237+ (((byteBuf[1] & 0xff) << 8) | ((byteBuf[0] & 0xff) << 0));
238+ }
239+ }
240+
241+ public int readUnsignedShort() throws IOException {
242+ return ((int)readShort()) & 0xffff;
243+ }
244+
245+ public char readChar() throws IOException {
246+ return (char)readShort();
247+ }
248+
249+ public int readInt() throws IOException {
250+ if (read(byteBuf, 0, 4) < 0) {
251+ throw new EOFException();
252+ }
253+
254+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
255+ return
256+ (((byteBuf[0] & 0xff) << 24) | ((byteBuf[1] & 0xff) << 16) |
257+ ((byteBuf[2] & 0xff) << 8) | ((byteBuf[3] & 0xff) << 0));
258+ } else {
259+ return
260+ (((byteBuf[3] & 0xff) << 24) | ((byteBuf[2] & 0xff) << 16) |
261+ ((byteBuf[1] & 0xff) << 8) | ((byteBuf[0] & 0xff) << 0));
262+ }
263+ }
264+
265+ public long readUnsignedInt() throws IOException {
266+ return ((long)readInt()) & 0xffffffffL;
267+ }
268+
269+ public long readLong() throws IOException {
270+ // REMIND: Once 6277756 is fixed, we should do a bulk read of all 8
271+ // bytes here as we do in readShort() and readInt() for even better
272+ // performance (see 6347575 for details).
273+ int i1 = readInt();
274+ int i2 = readInt();
275+
276+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
277+ return ((long)i1 << 32) + (i2 & 0xFFFFFFFFL);
278+ } else {
279+ return ((long)i2 << 32) + (i1 & 0xFFFFFFFFL);
280+ }
281+ }
282+
283+ public float readFloat() throws IOException {
284+ return Float.intBitsToFloat(readInt());
285+ }
286+
287+ public double readDouble() throws IOException {
288+ return Double.longBitsToDouble(readLong());
289+ }
290+
291+ public String readLine() throws IOException {
292+ StringBuffer input = new StringBuffer();
293+ int c = -1;
294+ boolean eol = false;
295+
296+ while (!eol) {
297+ switch (c = read()) {
298+ case -1:
299+ case '\n':
300+ eol = true;
301+ break;
302+ case '\r':
303+ eol = true;
304+ long cur = getStreamPosition();
305+ if ((read()) != '\n') {
306+ seek(cur);
307+ }
308+ break;
309+ default:
310+ input.append((char)c);
311+ break;
312+ }
313+ }
314+
315+ if ((c == -1) && (input.length() == 0)) {
316+ return null;
317+ }
318+ return input.toString();
319+ }
320+
321+ public String readUTF() throws IOException {
322+ this.bitOffset = 0;
323+
324+ // Fix 4494369: method ImageInputStreamImpl.readUTF()
325+ // does not work as specified (it should always assume
326+ // network byte order).
327+ ByteOrder oldByteOrder = getByteOrder();
328+ setByteOrder(ByteOrder.BIG_ENDIAN);
329+
330+ String ret;
331+ try {
332+ ret = DataInputStream.readUTF(this);
333+ } catch (IOException e) {
334+ // Restore the old byte order even if an exception occurs
335+ setByteOrder(oldByteOrder);
336+ throw e;
337+ }
338+
339+ setByteOrder(oldByteOrder);
340+ return ret;
341+ }
342+
343+ public void readFully(byte[] b, int off, int len) throws IOException {
344+ // Fix 4430357 - if off + len < 0, overflow occurred
345+ if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
346+ throw new IndexOutOfBoundsException
347+ ("off < 0 || len < 0 || off + len > b.length!");
348+ }
349+
350+ while (len > 0) {
351+ int nbytes = read(b, off, len);
352+ if (nbytes == -1) {
353+ throw new EOFException();
354+ }
355+ off += nbytes;
356+ len -= nbytes;
357+ }
358+ }
359+
360+ public void readFully(byte[] b) throws IOException {
361+ readFully(b, 0, b.length);
362+ }
363+
364+ public void readFully(short[] s, int off, int len) throws IOException {
365+ // Fix 4430357 - if off + len < 0, overflow occurred
366+ if (off < 0 || len < 0 || off + len > s.length || off + len < 0) {
367+ throw new IndexOutOfBoundsException
368+ ("off < 0 || len < 0 || off + len > s.length!");
369+ }
370+
371+ while (len > 0) {
372+ int nelts = Math.min(len, byteBuf.length/2);
373+ readFully(byteBuf, 0, nelts*2);
374+ toShorts(byteBuf, s, off, nelts);
375+ off += nelts;
376+ len -= nelts;
377+ }
378+ }
379+
380+ public void readFully(char[] c, int off, int len) throws IOException {
381+ // Fix 4430357 - if off + len < 0, overflow occurred
382+ if (off < 0 || len < 0 || off + len > c.length || off + len < 0) {
383+ throw new IndexOutOfBoundsException
384+ ("off < 0 || len < 0 || off + len > c.length!");
385+ }
386+
387+ while (len > 0) {
388+ int nelts = Math.min(len, byteBuf.length/2);
389+ readFully(byteBuf, 0, nelts*2);
390+ toChars(byteBuf, c, off, nelts);
391+ off += nelts;
392+ len -= nelts;
393+ }
394+ }
395+
396+ public void readFully(int[] i, int off, int len) throws IOException {
397+ // Fix 4430357 - if off + len < 0, overflow occurred
398+ if (off < 0 || len < 0 || off + len > i.length || off + len < 0) {
399+ throw new IndexOutOfBoundsException
400+ ("off < 0 || len < 0 || off + len > i.length!");
401+ }
402+
403+ while (len > 0) {
404+ int nelts = Math.min(len, byteBuf.length/4);
405+ readFully(byteBuf, 0, nelts*4);
406+ toInts(byteBuf, i, off, nelts);
407+ off += nelts;
408+ len -= nelts;
409+ }
410+ }
411+
412+ public void readFully(long[] l, int off, int len) throws IOException {
413+ // Fix 4430357 - if off + len < 0, overflow occurred
414+ if (off < 0 || len < 0 || off + len > l.length || off + len < 0) {
415+ throw new IndexOutOfBoundsException
416+ ("off < 0 || len < 0 || off + len > l.length!");
417+ }
418+
419+ while (len > 0) {
420+ int nelts = Math.min(len, byteBuf.length/8);
421+ readFully(byteBuf, 0, nelts*8);
422+ toLongs(byteBuf, l, off, nelts);
423+ off += nelts;
424+ len -= nelts;
425+ }
426+ }
427+
428+ public void readFully(float[] f, int off, int len) throws IOException {
429+ // Fix 4430357 - if off + len < 0, overflow occurred
430+ if (off < 0 || len < 0 || off + len > f.length || off + len < 0) {
431+ throw new IndexOutOfBoundsException
432+ ("off < 0 || len < 0 || off + len > f.length!");
433+ }
434+
435+ while (len > 0) {
436+ int nelts = Math.min(len, byteBuf.length/4);
437+ readFully(byteBuf, 0, nelts*4);
438+ toFloats(byteBuf, f, off, nelts);
439+ off += nelts;
440+ len -= nelts;
441+ }
442+ }
443+
444+ public void readFully(double[] d, int off, int len) throws IOException {
445+ // Fix 4430357 - if off + len < 0, overflow occurred
446+ if (off < 0 || len < 0 || off + len > d.length || off + len < 0) {
447+ throw new IndexOutOfBoundsException
448+ ("off < 0 || len < 0 || off + len > d.length!");
449+ }
450+
451+ while (len > 0) {
452+ int nelts = Math.min(len, byteBuf.length/8);
453+ readFully(byteBuf, 0, nelts*8);
454+ toDoubles(byteBuf, d, off, nelts);
455+ off += nelts;
456+ len -= nelts;
457+ }
458+ }
459+
460+ private void toShorts(byte[] b, short[] s, int off, int len) {
461+ int boff = 0;
462+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
463+ for (int j = 0; j < len; j++) {
464+ int b0 = b[boff];
465+ int b1 = b[boff + 1] & 0xff;
466+ s[off + j] = (short)((b0 << 8) | b1);
467+ boff += 2;
468+ }
469+ } else {
470+ for (int j = 0; j < len; j++) {
471+ int b0 = b[boff + 1];
472+ int b1 = b[boff] & 0xff;
473+ s[off + j] = (short)((b0 << 8) | b1);
474+ boff += 2;
475+ }
476+ }
477+ }
478+
479+ private void toChars(byte[] b, char[] c, int off, int len) {
480+ int boff = 0;
481+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
482+ for (int j = 0; j < len; j++) {
483+ int b0 = b[boff];
484+ int b1 = b[boff + 1] & 0xff;
485+ c[off + j] = (char)((b0 << 8) | b1);
486+ boff += 2;
487+ }
488+ } else {
489+ for (int j = 0; j < len; j++) {
490+ int b0 = b[boff + 1];
491+ int b1 = b[boff] & 0xff;
492+ c[off + j] = (char)((b0 << 8) | b1);
493+ boff += 2;
494+ }
495+ }
496+ }
497+
498+ private void toInts(byte[] b, int[] i, int off, int len) {
499+ int boff = 0;
500+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
501+ for (int j = 0; j < len; j++) {
502+ int b0 = b[boff];
503+ int b1 = b[boff + 1] & 0xff;
504+ int b2 = b[boff + 2] & 0xff;
505+ int b3 = b[boff + 3] & 0xff;
506+ i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
507+ boff += 4;
508+ }
509+ } else {
510+ for (int j = 0; j < len; j++) {
511+ int b0 = b[boff + 3];
512+ int b1 = b[boff + 2] & 0xff;
513+ int b2 = b[boff + 1] & 0xff;
514+ int b3 = b[boff] & 0xff;
515+ i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
516+ boff += 4;
517+ }
518+ }
519+ }
520+
521+ private void toLongs(byte[] b, long[] l, int off, int len) {
522+ int boff = 0;
523+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
524+ for (int j = 0; j < len; j++) {
525+ int b0 = b[boff];
526+ int b1 = b[boff + 1] & 0xff;
527+ int b2 = b[boff + 2] & 0xff;
528+ int b3 = b[boff + 3] & 0xff;
529+ int b4 = b[boff + 4];
530+ int b5 = b[boff + 5] & 0xff;
531+ int b6 = b[boff + 6] & 0xff;
532+ int b7 = b[boff + 7] & 0xff;
533+
534+ int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
535+ int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
536+
537+ l[off + j] = ((long)i0 << 32) | (i1 & 0xffffffffL);
538+ boff += 8;
539+ }
540+ } else {
541+ for (int j = 0; j < len; j++) {
542+ int b0 = b[boff + 7];
543+ int b1 = b[boff + 6] & 0xff;
544+ int b2 = b[boff + 5] & 0xff;
545+ int b3 = b[boff + 4] & 0xff;
546+ int b4 = b[boff + 3];
547+ int b5 = b[boff + 2] & 0xff;
548+ int b6 = b[boff + 1] & 0xff;
549+ int b7 = b[boff] & 0xff;
550+
551+ int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
552+ int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
553+
554+ l[off + j] = ((long)i0 << 32) | (i1 & 0xffffffffL);
555+ boff += 8;
556+ }
557+ }
558+ }
559+
560+ private void toFloats(byte[] b, float[] f, int off, int len) {
561+ int boff = 0;
562+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
563+ for (int j = 0; j < len; j++) {
564+ int b0 = b[boff];
565+ int b1 = b[boff + 1] & 0xff;
566+ int b2 = b[boff + 2] & 0xff;
567+ int b3 = b[boff + 3] & 0xff;
568+ int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
569+ f[off + j] = Float.intBitsToFloat(i);
570+ boff += 4;
571+ }
572+ } else {
573+ for (int j = 0; j < len; j++) {
574+ int b0 = b[boff + 3];
575+ int b1 = b[boff + 2] & 0xff;
576+ int b2 = b[boff + 1] & 0xff;
577+ int b3 = b[boff + 0] & 0xff;
578+ int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
579+ f[off + j] = Float.intBitsToFloat(i);
580+ boff += 4;
581+ }
582+ }
583+ }
584+
585+ private void toDoubles(byte[] b, double[] d, int off, int len) {
586+ int boff = 0;
587+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
588+ for (int j = 0; j < len; j++) {
589+ int b0 = b[boff];
590+ int b1 = b[boff + 1] & 0xff;
591+ int b2 = b[boff + 2] & 0xff;
592+ int b3 = b[boff + 3] & 0xff;
593+ int b4 = b[boff + 4];
594+ int b5 = b[boff + 5] & 0xff;
595+ int b6 = b[boff + 6] & 0xff;
596+ int b7 = b[boff + 7] & 0xff;
597+
598+ int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
599+ int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
600+ long l = ((long)i0 << 32) | (i1 & 0xffffffffL);
601+
602+ d[off + j] = Double.longBitsToDouble(l);
603+ boff += 8;
604+ }
605+ } else {
606+ for (int j = 0; j < len; j++) {
607+ int b0 = b[boff + 7];
608+ int b1 = b[boff + 6] & 0xff;
609+ int b2 = b[boff + 5] & 0xff;
610+ int b3 = b[boff + 4] & 0xff;
611+ int b4 = b[boff + 3];
612+ int b5 = b[boff + 2] & 0xff;
613+ int b6 = b[boff + 1] & 0xff;
614+ int b7 = b[boff] & 0xff;
615+
616+ int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
617+ int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
618+ long l = ((long)i0 << 32) | (i1 & 0xffffffffL);
619+
620+ d[off + j] = Double.longBitsToDouble(l);
621+ boff += 8;
622+ }
623+ }
624+ }
625+
626+ public long getStreamPosition() throws IOException {
627+ checkClosed();
628+ return streamPos;
629+ }
630+
631+ public int getBitOffset() throws IOException {
632+ checkClosed();
633+ return bitOffset;
634+ }
635+
636+ public void setBitOffset(int bitOffset) throws IOException {
637+ checkClosed();
638+ if (bitOffset < 0 || bitOffset > 7) {
639+ throw new IllegalArgumentException("bitOffset must be betwwen 0 and 7!");
640+ }
641+ this.bitOffset = bitOffset;
642+ }
643+
644+ public int readBit() throws IOException {
645+ checkClosed();
646+
647+ // Compute final bit offset before we call read() and seek()
648+ int newBitOffset = (this.bitOffset + 1) & 0x7;
649+
650+ int val = read();
651+ if (val == -1) {
652+ throw new EOFException();
653+ }
654+
655+ if (newBitOffset != 0) {
656+ // Move byte position back if in the middle of a byte
657+ seek(getStreamPosition() - 1);
658+ // Shift the bit to be read to the rightmost position
659+ val >>= 8 - newBitOffset;
660+ }
661+ this.bitOffset = newBitOffset;
662+
663+ return val & 0x1;
664+ }
665+
666+ public long readBits(int numBits) throws IOException {
667+ checkClosed();
668+
669+ if (numBits < 0 || numBits > 64) {
670+ throw new IllegalArgumentException();
671+ }
672+ if (numBits == 0) {
673+ return 0L;
674+ }
675+
676+ // Have to read additional bits on the left equal to the bit offset
677+ int bitsToRead = numBits + bitOffset;
678+
679+ // Compute final bit offset before we call read() and seek()
680+ int newBitOffset = (this.bitOffset + numBits) & 0x7;
681+
682+ // Read a byte at a time, accumulate
683+ long accum = 0L;
684+ while (bitsToRead > 0) {
685+ int val = read();
686+ if (val == -1) {
687+ throw new EOFException();
688+ }
689+
690+ accum <<= 8;
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 = ((Long)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 = ((Integer)markBitStack.pop()).intValue();
809+ setBitOffset(offset);
810+ }
811+
812+ public void flushBefore(long pos) throws IOException {
813+ checkClosed();
814+ if (pos < flushedPos) {
815+ throw new IndexOutOfBoundsException("pos < flushedPos!");
816+ }
817+ if (pos > getStreamPosition()) {
818+ throw new IndexOutOfBoundsException("pos > getStreamPosition()!");
819+ }
820+ // Invariant: flushedPos >= 0
821+ flushedPos = pos;
822+ }
823+
824+ public void flush() throws IOException {
825+ flushBefore(getStreamPosition());
826+ }
827+
828+ public long getFlushedPosition() {
829+ return flushedPos;
830+ }
831+
832+ /**
833+ * Default implementation returns false. Subclasses should
834+ * override this if they cache data.
835+ */
836+ public boolean isCached() {
837+ return false;
838+ }
839+
840+ /**
841+ * Default implementation returns false. Subclasses should
842+ * override this if they cache data in main memory.
843+ */
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+}