001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package javax.imageio.stream;
019:
020: import java.io.EOFException;
021: import java.io.IOException;
022: import java.nio.ByteOrder;
023:
024: import org.apache.harmony.luni.util.Util;
025:
026: public abstract class ImageInputStreamImpl implements ImageInputStream {
027:
028: protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
029:
030: protected long streamPos = 0;
031: protected long flushedPos = 0;
032: protected int bitOffset = 0;
033:
034: private boolean closed = false;
035:
036: private final PositionStack posStack = new PositionStack();
037: private final byte[] buff = new byte[8];
038:
039: public ImageInputStreamImpl() {
040: }
041:
042: protected final void checkClosed() throws IOException {
043: if (closed) {
044: throw new IOException("stream is closed");
045: }
046: }
047:
048: public void setByteOrder(ByteOrder byteOrder) {
049: this .byteOrder = byteOrder;
050: }
051:
052: public ByteOrder getByteOrder() {
053: return byteOrder;
054: }
055:
056: public abstract int read() throws IOException;
057:
058: public int read(byte[] b) throws IOException {
059: return read(b, 0, b.length);
060: }
061:
062: public abstract int read(byte[] b, int off, int len)
063: throws IOException;
064:
065: public void readBytes(IIOByteBuffer buf, int len)
066: throws IOException {
067: if (buf == null) {
068: throw new NullPointerException("buffer is NULL");
069: }
070:
071: byte[] b = new byte[len];
072: len = read(b, 0, b.length);
073:
074: buf.setData(b);
075: buf.setOffset(0);
076: buf.setLength(len);
077: }
078:
079: public boolean readBoolean() throws IOException {
080: int b = read();
081: if (b < 0) {
082: throw new EOFException("EOF reached");
083: }
084: return b != 0;
085: }
086:
087: public byte readByte() throws IOException {
088: int b = read();
089: if (b < 0) {
090: throw new EOFException("EOF reached");
091: }
092: return (byte) b;
093: }
094:
095: public int readUnsignedByte() throws IOException {
096: int b = read();
097: if (b < 0) {
098: throw new EOFException("EOF reached");
099: }
100: return b;
101: }
102:
103: public short readShort() throws IOException {
104: if (read(buff, 0, 2) < 0) {
105: throw new EOFException();
106: }
107:
108: return byteOrder == ByteOrder.BIG_ENDIAN ? (short) ((buff[0] << 8) | (buff[1] & 0xff))
109: : (short) ((buff[1] << 8) | (buff[0] & 0xff));
110: }
111:
112: public int readUnsignedShort() throws IOException {
113: return ((int) readShort()) & 0xffff;
114: }
115:
116: public char readChar() throws IOException {
117: return (char) readShort();
118: }
119:
120: public int readInt() throws IOException {
121: if (read(buff, 0, 4) < 0) {
122: throw new EOFException();
123: }
124:
125: return byteOrder == ByteOrder.BIG_ENDIAN ? ((buff[0] & 0xff) << 24)
126: | ((buff[1] & 0xff) << 16)
127: | ((buff[2] & 0xff) << 8)
128: | (buff[3] & 0xff)
129: : ((buff[3] & 0xff) << 24) | ((buff[2] & 0xff) << 16)
130: | ((buff[1] & 0xff) << 8) | (buff[0] & 0xff);
131: }
132:
133: public long readUnsignedInt() throws IOException {
134: return ((long) readInt()) & 0xffffffffL;
135: }
136:
137: public long readLong() throws IOException {
138: if (read(buff, 0, 8) < 0) {
139: throw new EOFException();
140: }
141:
142: if (byteOrder == ByteOrder.BIG_ENDIAN) {
143: int i1 = ((buff[0] & 0xff) << 24)
144: | ((buff[1] & 0xff) << 16)
145: | ((buff[2] & 0xff) << 8) | (buff[3] & 0xff);
146: int i2 = ((buff[4] & 0xff) << 24)
147: | ((buff[5] & 0xff) << 16)
148: | ((buff[6] & 0xff) << 8) | (buff[7] & 0xff);
149:
150: return ((i1 & 0xffffffffL) << 32) | (i2 & 0xffffffffL);
151: } else {
152: int i1 = ((buff[3] & 0xff) << 24)
153: | ((buff[2] & 0xff) << 16)
154: | ((buff[1] & 0xff) << 8) | (buff[0] & 0xff);
155: int i2 = ((buff[7] & 0xff) << 24)
156: | ((buff[6] & 0xff) << 16)
157: | ((buff[5] & 0xff) << 8) | (buff[4] & 0xff);
158:
159: return ((i2 & 0xffffffffL) << 32) | (i1 & 0xffffffffL);
160: }
161: }
162:
163: public float readFloat() throws IOException {
164: return Float.intBitsToFloat(readInt());
165: }
166:
167: public double readDouble() throws IOException {
168: return Double.longBitsToDouble(readLong());
169: }
170:
171: public String readLine() throws IOException {
172: final StringBuffer line = new StringBuffer(80);
173: boolean isEmpty = true;
174: int c = -1;
175:
176: while ((c = read()) != -1) {
177: isEmpty = false;
178: if (c == '\n') {
179: break;
180: } else if (c == '\r') {
181: c = read();
182: if ((c != '\n') && (c != -1)) {
183: seek(getStreamPosition() - 1);
184: }
185: break;
186: }
187: line.append((char) c);
188: }
189:
190: return isEmpty ? null : line.toString();
191: }
192:
193: public String readUTF() throws IOException {
194: final int size = readUnsignedShort();
195: final byte[] buf = new byte[size];
196: final char[] out = new char[size];
197:
198: readFully(buf, 0, size);
199: //return new DataInputStream(new ByteArrayInputStream(buff)).readUTF();
200: return Util.convertUTF8WithBuf(buf, out, 0, size);
201: }
202:
203: public void readFully(byte[] b, int off, int len)
204: throws IOException {
205: if ((off < 0) || (len < 0) || (off + len > b.length)) {
206: throw new IndexOutOfBoundsException();
207: }
208:
209: while (len > 0) {
210: int i = read(b, off, len);
211:
212: if (i == -1) {
213: throw new EOFException();
214: }
215:
216: off += i;
217: len -= i;
218: }
219: }
220:
221: public void readFully(byte[] b) throws IOException {
222: readFully(b, 0, b.length);
223: }
224:
225: public void readFully(short[] s, int off, int len)
226: throws IOException {
227: if ((off < 0) || (len < 0) || (off + len > s.length)) {
228: throw new IndexOutOfBoundsException();
229: }
230:
231: for (int i = 0; i < len; i++) {
232: s[off + i] = readShort();
233: }
234: }
235:
236: public void readFully(char[] c, int off, int len)
237: throws IOException {
238: if ((off < 0) || (len < 0) || (off + len > c.length)) {
239: throw new IndexOutOfBoundsException();
240: }
241:
242: for (int i = 0; i < len; i++) {
243: c[off + i] = readChar();
244: }
245: }
246:
247: public void readFully(int[] i, int off, int len) throws IOException {
248: if ((off < 0) || (len < 0) || (off + len > i.length)) {
249: throw new IndexOutOfBoundsException();
250: }
251:
252: for (int k = 0; k < len; k++) {
253: i[off + k] = readInt();
254: }
255: }
256:
257: public void readFully(long[] l, int off, int len)
258: throws IOException {
259: if ((off < 0) || (len < 0) || (off + len > l.length)) {
260: throw new IndexOutOfBoundsException();
261: }
262:
263: for (int i = 0; i < len; i++) {
264: l[off + i] = readLong();
265: }
266: }
267:
268: public void readFully(float[] f, int off, int len)
269: throws IOException {
270: if ((off < 0) || (len < 0) || (off + len > f.length)) {
271: throw new IndexOutOfBoundsException();
272: }
273:
274: for (int i = 0; i < len; i++) {
275: f[off + i] = readFloat();
276: }
277: }
278:
279: public void readFully(double[] d, int off, int len)
280: throws IOException {
281: if ((off < 0) || (len < 0) || (off + len > d.length)) {
282: throw new IndexOutOfBoundsException();
283: }
284:
285: for (int i = 0; i < len; i++) {
286: d[off + i] = readFloat();
287: }
288: }
289:
290: public long getStreamPosition() throws IOException {
291: checkClosed();
292: return streamPos;
293: }
294:
295: public int getBitOffset() throws IOException {
296: checkClosed();
297: return bitOffset;
298: }
299:
300: public void setBitOffset(int bitOffset) throws IOException {
301: checkClosed();
302: if ((bitOffset < 0) || (bitOffset > 7)) {
303: throw new IllegalArgumentException();
304: }
305: this .bitOffset = bitOffset;
306: }
307:
308: int currentByte;
309:
310: public int readBit() throws IOException {
311: checkClosed();
312:
313: int offset = bitOffset;
314: int currentByte = read();
315:
316: if (currentByte == -1) {
317: throw new EOFException();
318: }
319:
320: offset = (offset + 1) & 7;
321:
322: if (offset != 0) {
323: currentByte >>= 8 - offset;
324: seek(getStreamPosition() - 1);
325: }
326:
327: bitOffset = offset;
328: return currentByte & 1;
329: }
330:
331: public long readBits(int numBits) throws IOException {
332: checkClosed();
333:
334: if ((numBits < 0) || (numBits > 64)) {
335: throw new IllegalArgumentException();
336: }
337:
338: long res = 0;
339:
340: for (int i = 0; i < numBits; i++) {
341: res <<= 1;
342: res |= readBit();
343: }
344:
345: return res;
346: }
347:
348: public long length() {
349: return -1L;
350: }
351:
352: public int skipBytes(int n) throws IOException {
353: return (int) skipBytes((long) n);
354: }
355:
356: public long skipBytes(long n) throws IOException {
357: seek(getStreamPosition() + n);
358: return n;
359: }
360:
361: public void seek(long pos) throws IOException {
362: checkClosed();
363: if (pos < getFlushedPosition()) {
364: throw new IllegalArgumentException(
365: "trying to seek before flushed pos");
366: }
367: bitOffset = 0;
368: streamPos = pos;
369: }
370:
371: public void mark() {
372: try {
373: posStack.push(getStreamPosition());
374: } catch (IOException e) {
375: e.printStackTrace();
376: throw new RuntimeException("Stream marking error");
377: }
378: }
379:
380: public void reset() throws IOException {
381: // -- TODO bit pos
382: if (!posStack.isEmpty()) {
383: long p = posStack.pop();
384: if (p < flushedPos) {
385: throw new IOException(
386: "marked position lies in the flushed portion of the stream");
387: }
388: seek(p);
389: }
390: }
391:
392: public void flushBefore(long pos) throws IOException {
393: if (pos > getStreamPosition()) {
394: throw new IndexOutOfBoundsException(
395: "Trying to flush outside of current position");
396: }
397: if (pos < flushedPos) {
398: throw new IndexOutOfBoundsException(
399: "Trying to flush within already flushed portion");
400: }
401: flushedPos = pos;
402: // -- TODO implement
403: }
404:
405: public void flush() throws IOException {
406: flushBefore(getStreamPosition());
407: }
408:
409: public long getFlushedPosition() {
410: return flushedPos;
411: }
412:
413: public boolean isCached() {
414: return false; // def
415: }
416:
417: public boolean isCachedMemory() {
418: return false; // def
419: }
420:
421: public boolean isCachedFile() {
422: return false; // def
423: }
424:
425: public void close() throws IOException {
426: checkClosed();
427: closed = true;
428:
429: }
430:
431: @Override
432: protected void finalize() throws Throwable {
433: if (!closed) {
434: try {
435: close();
436: } finally {
437: super .finalize();
438: }
439: }
440: }
441:
442: private static class PositionStack {
443: private static final int SIZE = 10;
444:
445: private long[] values = new long[SIZE];
446: private int pos = 0;
447:
448: void push(long v) {
449: if (pos >= values.length) {
450: ensure(pos + 1);
451: }
452: values[pos++] = v;
453: }
454:
455: long pop() {
456: return values[--pos];
457: }
458:
459: boolean isEmpty() {
460: return pos == 0;
461: }
462:
463: private void ensure(int size) {
464: long[] arr = new long[Math.max(2 * values.length, size)];
465: System.arraycopy(values, 0, arr, 0, values.length);
466: values = arr;
467: }
468: }
469: }
|