1 /* ImageInputStream.java --
2    Copyright (C) 2004  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package javax.imageio.stream;
40 
41 import gnu.java.lang.CPStringBuilder;
42 
43 import java.io.DataInputStream;
44 import java.io.EOFException;
45 import java.io.IOException;
46 import java.nio.ByteOrder;
47 import java.util.Stack;
48 
49 /**
50  * @author Michael Koch (konqueror@gmx.de)
51  */
52 public abstract class ImageInputStreamImpl implements ImageInputStream
53 {
54   private boolean closed;
55   private Stack markStack = new Stack();
56 
57   byte[] buffer = new byte[8];
58 
59   protected int bitOffset;
60   protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
61   protected long flushedPos;
62   protected long streamPos;
63 
ImageInputStreamImpl()64   public ImageInputStreamImpl()
65   {
66     // Do nothing here.
67   }
68 
checkClosed()69   protected final void checkClosed()
70     throws IOException
71   {
72     if (closed)
73       throw new IOException("stream closed");
74   }
75 
close()76   public void close()
77     throws IOException
78   {
79     checkClosed();
80     closed = true;
81   }
82 
finalize()83   protected void finalize()
84     throws Throwable
85   {
86     if (!closed)
87       close();
88   }
89 
flush()90   public void flush()
91     throws IOException
92   {
93     flushBefore(getStreamPosition());
94   }
95 
flushBefore(long position)96   public void flushBefore(long position)
97     throws IOException
98   {
99     if (position < flushedPos)
100       throw new IndexOutOfBoundsException();
101 
102     if (position > streamPos)
103       throw new IndexOutOfBoundsException();
104 
105     flushedPos = position;
106   }
107 
getBitOffset()108   public int getBitOffset()
109     throws IOException
110   {
111     checkClosed();
112     return bitOffset;
113   }
114 
getByteOrder()115   public ByteOrder getByteOrder()
116   {
117     return byteOrder;
118   }
119 
getFlushedPosition()120   public long getFlushedPosition()
121   {
122     return flushedPos;
123   }
124 
getStreamPosition()125   public long getStreamPosition()
126     throws IOException
127   {
128     checkClosed();
129     return streamPos;
130   }
131 
isCached()132   public boolean isCached()
133   {
134     return false;
135   }
136 
isCachedFile()137   public boolean isCachedFile()
138   {
139     return false;
140   }
141 
isCachedMemory()142   public boolean isCachedMemory()
143   {
144     return false;
145   }
146 
length()147   public long length()
148   {
149     return -1L;
150   }
151 
mark()152   public void mark()
153   {
154     try
155       {
156         markStack.push(new Long(getStreamPosition()));
157       }
158     catch (IOException e)
159       {
160         throw new RuntimeException(e);
161       }
162   }
163 
read()164   public abstract int read()
165     throws IOException;
166 
read(byte[] data, int offset, int len)167   public abstract int read(byte[] data, int offset, int len)
168     throws IOException;
169 
read(byte[] data)170   public int read(byte[] data)
171     throws IOException
172   {
173     return read(data, 0, data.length);
174   }
175 
readBit()176   public int readBit()
177     throws IOException
178   {
179     checkClosed();
180 
181     // Calculate new bit offset here as readByte clears it.
182     int newOffset = (bitOffset + 1) & 0x7;
183 
184     // Clears bitOffset.
185     byte data = readByte();
186 
187     // If newOffset is 0 it means we just read the 8th bit in a byte
188     // and therefore we want to advance to the next byte.  Otherwise
189     // we want to roll back the stream one byte so that future readBit
190     // calls read bits from the same current byte.
191     if (newOffset != 0)
192       {
193         seek(getStreamPosition() - 1);
194         data = (byte) (data >> (8 - newOffset));
195       }
196 
197     bitOffset = newOffset;
198     return data & 0x1;
199   }
200 
readBits(int numBits)201   public long readBits(int numBits)
202     throws IOException
203   {
204     checkClosed();
205 
206     if (numBits < 0 || numBits > 64)
207       throw new IllegalArgumentException();
208 
209     long bits = 0L;
210 
211     for (int i = 0; i < numBits; i++)
212       {
213         bits <<= 1;
214         bits |= readBit();
215       }
216     return bits;
217   }
218 
readBoolean()219   public boolean readBoolean()
220     throws IOException
221   {
222     byte data = readByte();
223 
224     return data != 0;
225   }
226 
readByte()227   public byte readByte()
228     throws IOException
229   {
230     checkClosed();
231 
232     int data = read();
233 
234     if (data == -1)
235       throw new EOFException();
236 
237     return (byte) data;
238   }
239 
readBytes(IIOByteBuffer buffer, int len)240   public void readBytes(IIOByteBuffer buffer, int len)
241     throws IOException
242   {
243     readFullyPrivate(buffer.getData(), buffer.getOffset(), len);
244 
245     buffer.setLength(len);
246   }
247 
readChar()248   public char readChar()
249     throws IOException
250   {
251     return (char) readShort();
252   }
253 
readDouble()254   public double readDouble()
255     throws IOException
256   {
257     return Double.longBitsToDouble(readLong());
258   }
259 
readFloat()260   public float readFloat()
261     throws IOException
262   {
263     return Float.intBitsToFloat(readInt());
264   }
265 
readFully(byte[] data)266   public void readFully(byte[] data)
267     throws IOException
268   {
269     readFully(data, 0, data.length);
270   }
271 
readFully(byte[] data, int offset, int len)272   public void readFully(byte[] data, int offset, int len)
273     throws IOException
274   {
275     readFullyPrivate(data, offset, len);
276   }
277 
readFully(char[] data, int offset, int len)278   public void readFully(char[] data, int offset, int len)
279     throws IOException
280   {
281     for (int i = 0; i < len; ++i)
282       data[offset + i] = readChar();
283   }
284 
readFully(double[] data, int offset, int len)285   public void readFully(double[] data, int offset, int len)
286     throws IOException
287   {
288     for (int i = 0; i < len; ++i)
289       data[offset + i] = readDouble();
290   }
291 
readFully(float[] data, int offset, int len)292   public void readFully(float[] data, int offset, int len)
293     throws IOException
294   {
295     for (int i = 0; i < len; ++i)
296       data[offset + i] = readFloat();
297   }
298 
readFully(int[] data, int offset, int len)299   public void readFully(int[] data, int offset, int len)
300     throws IOException
301   {
302     for (int i = 0; i < len; ++i)
303       data[offset + i] = readInt();
304   }
305 
readFully(long[] data, int offset, int len)306   public void readFully(long[] data, int offset, int len)
307     throws IOException
308   {
309     for (int i = 0; i < len; ++i)
310       data[offset + i] = readLong();
311   }
312 
readFully(short[] data, int offset, int len)313   public void readFully(short[] data, int offset, int len)
314     throws IOException
315   {
316     for (int i = 0; i < len; ++i)
317       data[offset + i] = readShort();
318   }
319 
readInt()320   public int readInt()
321     throws IOException
322   {
323     readFullyPrivate(buffer, 0, 4);
324 
325     if (getByteOrder() == ByteOrder.LITTLE_ENDIAN)
326       return (int)
327         (((int) (buffer[0] & 0xff) << 0)
328          | ((int) (buffer[1] & 0xff) << 8)
329          | ((int) (buffer[2] & 0xff) << 16)
330          | ((int) (buffer[3] & 0xff) << 24));
331 
332     return (int)
333       (((int) (buffer[0] & 0xff) << 24)
334        + ((int) (buffer[1] & 0xff) << 16)
335        + ((int) (buffer[2] & 0xff) << 8)
336        + ((int) (buffer[3] & 0xff) << 0));
337   }
338 
readLine()339   public String readLine()
340     throws IOException
341   {
342     checkClosed();
343 
344     int c = -1;
345     boolean eol = false;
346     CPStringBuilder buffer = new CPStringBuilder();
347 
348     c = read();
349     if (c == -1)
350       return null;
351 
352     while (!eol)
353       {
354         switch(c)
355           {
356           case '\r':
357             // Check for following '\n'.
358             long oldPosition = getStreamPosition();
359             c = read();
360             if (c == -1 || c == '\n')
361               eol = true;
362             else
363               {
364                 seek(oldPosition);
365                 eol = true;
366               }
367             continue;
368 
369           case '\n':
370             eol = true;
371             continue;
372 
373           default:
374             buffer.append((char) c);
375             break;
376           }
377         c = read();
378         if (c == -1)
379           eol = true;
380       }
381 
382     return buffer.toString();
383   }
384 
readLong()385   public long readLong()
386     throws IOException
387   {
388     readFullyPrivate(buffer, 0, 8);
389 
390     if (getByteOrder() == ByteOrder.LITTLE_ENDIAN)
391       return (long)
392         (((long) (buffer[0] & 0xff) << 0)
393          | ((long) (buffer[1] & 0xff) << 8)
394          | ((long) (buffer[2] & 0xff) << 16)
395          | ((long) (buffer[3] & 0xff) << 24)
396          | ((long) (buffer[4] & 0xff) << 32)
397          | ((long) (buffer[5] & 0xff) << 40)
398          | ((long) (buffer[6] & 0xff) << 48)
399          | ((long) (buffer[7] & 0xff) << 56));
400 
401     return  (long)
402       (((long) (buffer[0] & 0xff) << 56)
403        | ((long) (buffer[1] & 0xff) << 48)
404        | ((long) (buffer[2] & 0xff) << 40)
405        | ((long) (buffer[3] & 0xff) << 32)
406        | ((long) (buffer[4] & 0xff) << 24)
407        | ((long) (buffer[5] & 0xff) << 16)
408        | ((long) (buffer[6] & 0xff) << 8)
409        | ((long) (buffer[7] & 0xff) << 0));
410   }
411 
readShort()412   public short readShort()
413     throws IOException
414   {
415     readFullyPrivate(buffer, 0, 2);
416 
417     if (getByteOrder() == ByteOrder.LITTLE_ENDIAN)
418       return (short)
419         (((short) (buffer[0] & 0xff) << 0)
420          | ((short) (buffer[1] & 0xff) << 8));
421 
422     return (short)
423       (((short) (buffer[0] & 0xff) << 8)
424        | ((short) (buffer[1] & 0xff) << 0));
425   }
426 
readUnsignedByte()427   public int readUnsignedByte()
428     throws IOException
429   {
430     return (int) readByte() & 0xff;
431   }
432 
readUnsignedInt()433   public long readUnsignedInt()
434     throws IOException
435   {
436     return (long) readInt() & 0xffffffffL;
437   }
438 
readUnsignedShort()439   public int readUnsignedShort()
440     throws IOException
441   {
442     return (int) readShort() & 0xffff;
443   }
444 
readUTF()445   public String readUTF()
446     throws IOException
447   {
448     checkClosed();
449 
450     String data;
451     ByteOrder old = getByteOrder();
452     // Strings are always big endian.
453     setByteOrder(ByteOrder.BIG_ENDIAN);
454 
455     try
456       {
457         data = DataInputStream.readUTF(this);
458       }
459     finally
460       {
461         setByteOrder(old);
462       }
463 
464     return data;
465   }
466 
reset()467   public void reset()
468     throws IOException
469   {
470     checkClosed();
471 
472     long mark = ((Long) markStack.pop()).longValue();
473     seek(mark);
474   }
475 
seek(long position)476   public void seek(long position)
477     throws IOException
478   {
479     checkClosed();
480 
481     if (position < getFlushedPosition())
482       throw new IndexOutOfBoundsException("position < flushed position");
483 
484     streamPos = position;
485     bitOffset = 0;
486   }
487 
setBitOffset(int bitOffset)488   public void setBitOffset (int bitOffset)
489     throws IOException
490   {
491     checkClosed();
492 
493     if (bitOffset < 0 || bitOffset > 7)
494       throw new IllegalArgumentException("bitOffset not between 0 and 7 inclusive");
495 
496     this.bitOffset = bitOffset;
497   }
498 
setByteOrder(ByteOrder byteOrder)499   public void setByteOrder(ByteOrder byteOrder)
500   {
501     this.byteOrder = byteOrder;
502   }
503 
skipBytes(int num)504   public int skipBytes(int num)
505     throws IOException
506   {
507     checkClosed();
508 
509     seek(getStreamPosition() + num);
510     bitOffset = 0;
511     return num;
512   }
513 
skipBytes(long num)514   public long skipBytes(long num)
515     throws IOException
516   {
517     checkClosed();
518 
519     seek(getStreamPosition() + num);
520     bitOffset = 0;
521     return num;
522   }
523 
readFullyPrivate(byte[] buf, int offset, int len)524   private void readFullyPrivate (byte[] buf, int offset, int len) throws IOException
525   {
526     checkClosed();
527 
528     if (len < 0)
529       throw new IndexOutOfBoundsException("Negative length: " + len);
530 
531     while (len > 0)
532       {
533         // read will block until some data is available.
534         int numread = read (buf, offset, len);
535         if (numread < 0)
536           throw new EOFException ();
537         len -= numread;
538         offset += numread;
539       }
540     bitOffset = 0;
541   }
542 }
543