View Javadoc
1   /*
2    * #%L
3    * nom.tam FITS library
4    * %%
5    * Copyright (C) 1996 - 2024 nom-tam-fits
6    * %%
7    * This is free and unencumbered software released into the public domain.
8    *
9    * Anyone is free to copy, modify, publish, use, compile, sell, or
10   * distribute this software, either in source code form or as a compiled
11   * binary, for any purpose, commercial or non-commercial, and by any
12   * means.
13   *
14   * In jurisdictions that recognize copyright laws, the author or authors
15   * of this software dedicate any and all copyright interest in the
16   * software to the public domain. We make this dedication for the benefit
17   * of the public at large and to the detriment of our heirs and
18   * successors. We intend this dedication to be an overt act of
19   * relinquishment in perpetuity of all present and future rights to this
20   * software under copyright law.
21   *
22   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25   * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
26   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28   * OTHER DEALINGS IN THE SOFTWARE.
29   * #L%
30   */
31  
32  package nom.tam.util;
33  
34  // What do we use in here?
35  import java.io.DataInput;
36  import java.io.DataInputStream;
37  import java.io.EOFException;
38  import java.io.IOException;
39  import java.io.InputStream;
40  import java.nio.ByteBuffer;
41  
42  import nom.tam.fits.FitsFactory;
43  import nom.tam.fits.utilities.FitsCheckSum;
44  
45  /**
46   * For reading FITS files through an {@link InputStream}.
47   * <p>
48   * Testing and timing routines are provided in the nom.tam.util.test.BufferedFileTester class.
49   * <p>
50   * Prior versions under the old <code>BufferedDataInputStream</code>:
51   * <ul>
52   * <li>Version 1.1 -- October 12, 2000: Fixed handling of EOF to return partially read arrays when EOF is detected</li>
53   * <li>Version 1.2 -- July 20, 2009: Added handling of very large Object arrays. Additional work is required to handle
54   * very large arrays generally.</li>
55   * </ul>
56   * <p>
57   * Version 2.0 -- October 30, 2021: Completely overhauled, with new name and hierarchy. Performance is 2-4 times better
58   * than before (Attila Kovacs)
59   *
60   * @see FitsInputStream
61   * @see FitsFile
62   */
63  @SuppressWarnings("deprecation")
64  public class FitsInputStream extends ArrayInputStream implements ArrayDataInput {
65  
66      /** buffer for checksum calculation */
67      private ByteBuffer check;
68  
69      /** aggregated checksum */
70      private long sum;
71  
72      /** the input, as accessible via the <code>DataInput</code> interface */
73      private DataInput data;
74  
75      /**
76       * Create a BufferedInputStream based on a input stream with a specified buffer size.
77       *
78       * @param i         the input stream to use for reading.
79       * @param bufLength the buffer length to use.
80       */
81      public FitsInputStream(InputStream i, int bufLength) {
82          super(i, bufLength);
83          data = new DataInputStream(this);
84          check = ByteBuffer.allocate(FitsFactory.FITS_BLOCK_SIZE);
85          check.limit(check.capacity());
86          setDecoder(new FitsDecoder(this));
87      }
88  
89      /**
90       * Create a BufferedInputStream based on an input stream.
91       *
92       * @param i the input stream to use for reading.
93       */
94      public FitsInputStream(InputStream i) {
95          this(i, FitsIO.DEFAULT_BUFFER_SIZE);
96      }
97  
98      @Override
99      protected FitsDecoder getDecoder() {
100         return (FitsDecoder) super.getDecoder();
101     }
102 
103     @Override
104     public int read() throws IOException {
105         int i = super.read();
106         if (i >= 0) {
107             check.put((byte) i);
108             if (check.remaining() <= 0) {
109                 aggregate();
110             }
111         }
112         return i;
113     }
114 
115     @Override
116     public int read(byte[] b, int from, int len) throws IOException {
117         int n = super.read(b, from, len);
118         for (int i = 0; i < n;) {
119             int l = Math.min(n - i, check.remaining());
120             check.put(b, from + i, l);
121             if (check.remaining() <= 0) {
122                 aggregate();
123             }
124             i += l;
125         }
126         return n;
127     }
128 
129     private void aggregate() {
130         sum = FitsCheckSum.sumOf(sum, FitsCheckSum.checksum(check));
131         check.position(0);
132     }
133 
134     /**
135      * (<i>for internal use</i>) Returns the aggregated checksum for this stream since the last call to this method, or
136      * else since instantiation. Checksums for a block of data thus may be obtained by calling this method both before
137      * and after reading the data block -- the first call resets the checksum and the block checksum is returned on the
138      * second call. The checksummed block must be a multiple of 2880 bytes (the FITS block size) for the result to be
139      * valid.
140      * 
141      * @return the aggregated checksum since the last call to this method, or else since instantiation, on an integer
142      *             number of FITS blocks read in the meantime.
143      * 
144      * @since  1.18.1
145      */
146     public final long nextChecksum() {
147         long ret = sum;
148         sum = 0;
149         return ret;
150     }
151 
152     @Override
153     public void readFully(byte[] b) throws IOException {
154         readFully(b, 0, b.length);
155     }
156 
157     @Override
158     public void readFully(byte[] b, int off, int len) throws IOException {
159         getDecoder().readFully(b, off, len);
160     }
161 
162     @Override
163     public int read(boolean[] b, int start, int length) throws IOException {
164         return getDecoder().read(b, start, length);
165     }
166 
167     @Override
168     public int read(Boolean[] b, int start, int length) throws IOException {
169         return getDecoder().read(b, start, length);
170     }
171 
172     @Override
173     public int read(char[] c, int start, int length) throws IOException {
174         return getDecoder().read(c, start, length);
175     }
176 
177     @Override
178     public int read(short[] s, int start, int length) throws IOException {
179         return getDecoder().read(s, start, length);
180     }
181 
182     @Override
183     public int read(int[] i, int start, int length) throws IOException {
184         return getDecoder().read(i, start, length);
185     }
186 
187     @Override
188     public int read(long[] l, int start, int length) throws IOException {
189         return getDecoder().read(l, start, length);
190     }
191 
192     @Override
193     public int read(float[] f, int start, int length) throws IOException {
194         return getDecoder().read(f, start, length);
195     }
196 
197     @Override
198     public int read(double[] d, int start, int length) throws IOException {
199         return getDecoder().read(d, start, length);
200     }
201 
202     /**
203      * This routine provides efficient reading of arrays of any primitive type. It is an error to invoke this method
204      * with an object that is not an array of some primitive type. Note that there is no corresponding capability to
205      * writePrimitiveArray in BufferedDataOutputStream to read in an array of Strings.
206      *
207      * @return                 number of bytes read.
208      *
209      * @param      o           The object to be read. It must be an array of a primitive type, or an array of Object's.
210      *
211      * @throws     IOException if the underlying read operation fails
212      *
213      * @deprecated             use {@link #readLArray(Object)} instead
214      */
215     @Deprecated
216     public final int readPrimitiveArray(Object o) throws IOException {
217         return (int) readLArray(o);
218     }
219 
220     @Override
221     public long skip(long n) throws IOException {
222         byte[] b = new byte[FitsFactory.FITS_BLOCK_SIZE];
223 
224         // Always read so we can checksum.
225         long skipped = 0;
226         while (skipped < n) {
227             int got = read(b, 0, (int) Math.min(n - skipped, b.length));
228             if (got < 0) {
229                 break;
230             }
231             skipped += got;
232         }
233         return skipped;
234     }
235 
236     @Override
237     public int skipBytes(int n) throws IOException {
238         return (int) super.skip(n);
239     }
240 
241     @Override
242     public void skipAllBytes(long toSkip) throws EOFException, IOException {
243         long got = 0;
244 
245         while (got < toSkip) {
246             long n = skip(toSkip - got);
247             if (n <= 0) {
248                 break;
249             }
250             got += n;
251         }
252 
253         if (got != toSkip) {
254             throw new EOFException("Reached end-of-stream after skipping " + got + " of " + toSkip);
255         }
256     }
257 
258     @Override
259     public boolean readBoolean() throws IOException {
260         return getDecoder().readBoolean();
261     }
262 
263     @Override
264     public int readUnsignedByte() throws IOException {
265         return getDecoder().readUnsignedByte();
266     }
267 
268     @Override
269     public byte readByte() throws IOException {
270         return getDecoder().readByte();
271     }
272 
273     @Override
274     public char readChar() throws IOException {
275         return getDecoder().readChar();
276     }
277 
278     @Override
279     public int readUnsignedShort() throws IOException {
280         return getDecoder().readUnsignedShort();
281     }
282 
283     @Override
284     public short readShort() throws IOException {
285         return getDecoder().readShort();
286     }
287 
288     @Override
289     public int readInt() throws IOException {
290         return getDecoder().readInt();
291     }
292 
293     @Override
294     public long readLong() throws IOException {
295         return getDecoder().readLong();
296     }
297 
298     @Override
299     public float readFloat() throws IOException {
300         return getDecoder().readFloat();
301     }
302 
303     @Override
304     public double readDouble() throws IOException {
305         return getDecoder().readDouble();
306     }
307 
308     @Override
309     public String readUTF() throws IOException {
310         return data.readUTF();
311     }
312 
313     @Override
314     public final String readLine() throws IOException {
315         return getDecoder().readAsciiLine();
316     }
317 
318     @Override
319     public String toString() {
320         return super.toString() + "[count=" + count + ",pos=" + pos + "]";
321     }
322 
323 }