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 synchronized 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 synchronized 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 
130     private void aggregate() {
131         sum = FitsCheckSum.sumOf(sum, FitsCheckSum.checksum(check));
132         check.position(0);
133     }
134 
135     /**
136      * (<i>for internal use</i>) Returns the aggregated checksum for this stream since the last call to this method, or
137      * else since instantiation. Checksums for a block of data thus may be obtained by calling this method both before
138      * and after reading the data block -- the first call resets the checksum and the block checksum is returned on the
139      * second call. The checksummed block must be a multiple of 2880 bytes (the FITS block size) for the result to be
140      * valid.
141      * 
142      * @return the aggregated checksum since the last call to this method, or else since instantiation, on an integer
143      *             number of FITS blocks read in the meantime.
144      * 
145      * @since  1.18.1
146      */
147     public final long nextChecksum() {
148         long ret = sum;
149         sum = 0;
150         return ret;
151     }
152 
153     @Override
154     public void readFully(byte[] b) throws IOException {
155         readFully(b, 0, b.length);
156     }
157 
158     @Override
159     public void readFully(byte[] b, int off, int len) throws IOException {
160         getDecoder().readFully(b, off, len);
161     }
162 
163     @Override
164     public int read(boolean[] b, int start, int length) throws IOException {
165         return getDecoder().read(b, start, length);
166     }
167 
168     @Override
169     public int read(Boolean[] b, int start, int length) throws IOException {
170         return getDecoder().read(b, start, length);
171     }
172 
173     @Override
174     public int read(char[] c, int start, int length) throws IOException {
175         return getDecoder().read(c, start, length);
176     }
177 
178     @Override
179     public int read(short[] s, int start, int length) throws IOException {
180         return getDecoder().read(s, start, length);
181     }
182 
183     @Override
184     public int read(int[] i, int start, int length) throws IOException {
185         return getDecoder().read(i, start, length);
186     }
187 
188     @Override
189     public int read(long[] l, int start, int length) throws IOException {
190         return getDecoder().read(l, start, length);
191     }
192 
193     @Override
194     public int read(float[] f, int start, int length) throws IOException {
195         return getDecoder().read(f, start, length);
196     }
197 
198     @Override
199     public int read(double[] d, int start, int length) throws IOException {
200         return getDecoder().read(d, start, length);
201     }
202 
203     /**
204      * This routine provides efficient reading of arrays of any primitive type. It is an error to invoke this method
205      * with an object that is not an array of some primitive type. Note that there is no corresponding capability to
206      * writePrimitiveArray in BufferedDataOutputStream to read in an array of Strings.
207      *
208      * @return                 number of bytes read.
209      *
210      * @param      o           The object to be read. It must be an array of a primitive type, or an array of Object's.
211      *
212      * @throws     IOException if the underlying read operation fails
213      *
214      * @deprecated             use {@link #readLArray(Object)} instead
215      */
216     @Deprecated
217     public final int readPrimitiveArray(Object o) throws IOException {
218         return (int) readLArray(o);
219     }
220 
221     @Override
222     public synchronized long skip(long n) throws IOException {
223         byte[] b = new byte[FitsFactory.FITS_BLOCK_SIZE];
224 
225         // Always read so we can checksum.
226         long skipped = 0;
227 
228         while (skipped < n) {
229             int got = read(b, 0, (int) Math.min(n - skipped, b.length));
230             if (got < 0) {
231                 break;
232             }
233             skipped += got;
234         }
235 
236         return skipped;
237     }
238 
239     @Override
240     public int skipBytes(int n) throws IOException {
241         return (int) super.skip(n);
242     }
243 
244     @Override
245     public void skipAllBytes(long toSkip) throws EOFException, IOException {
246         long got = 0;
247 
248         while (got < toSkip) {
249             long n = skip(toSkip - got);
250             if (n <= 0) {
251                 break;
252             }
253             got += n;
254         }
255 
256         if (got != toSkip) {
257             throw new EOFException("Reached end-of-stream after skipping " + got + " of " + toSkip);
258         }
259     }
260 
261     @Override
262     public boolean readBoolean() throws IOException {
263         return getDecoder().readBoolean();
264     }
265 
266     @Override
267     public int readUnsignedByte() throws IOException {
268         return getDecoder().readUnsignedByte();
269     }
270 
271     @Override
272     public byte readByte() throws IOException {
273         return getDecoder().readByte();
274     }
275 
276     @Override
277     public char readChar() throws IOException {
278         return getDecoder().readChar();
279     }
280 
281     @Override
282     public int readUnsignedShort() throws IOException {
283         return getDecoder().readUnsignedShort();
284     }
285 
286     @Override
287     public short readShort() throws IOException {
288         return getDecoder().readShort();
289     }
290 
291     @Override
292     public int readInt() throws IOException {
293         return getDecoder().readInt();
294     }
295 
296     @Override
297     public long readLong() throws IOException {
298         return getDecoder().readLong();
299     }
300 
301     @Override
302     public float readFloat() throws IOException {
303         return getDecoder().readFloat();
304     }
305 
306     @Override
307     public double readDouble() throws IOException {
308         return getDecoder().readDouble();
309     }
310 
311     @Override
312     public String readUTF() throws IOException {
313         return data.readUTF();
314     }
315 
316     @Override
317     public final String readLine() throws IOException {
318         return getDecoder().readAsciiLine();
319     }
320 
321     @Override
322     public String toString() {
323         return super.toString() + "[count=" + count + ",pos=" + pos + "]";
324     }
325 
326 }