View Javadoc
1   package nom.tam.fits;
2   
3   /*-
4    * #%L
5    * nom.tam.fits
6    * %%
7    * Copyright (C) 1996 - 2024 nom-tam-fits
8    * %%
9    * This is free and unencumbered software released into the public domain.
10   * 
11   * Anyone is free to copy, modify, publish, use, compile, sell, or
12   * distribute this software, either in source code form or as a compiled
13   * binary, for any purpose, commercial or non-commercial, and by any
14   * means.
15   * 
16   * In jurisdictions that recognize copyright laws, the author or authors
17   * of this software dedicate any and all copyright interest in the
18   * software to the public domain. We make this dedication for the benefit
19   * of the public at large and to the detriment of our heirs and
20   * successors. We intend this dedication to be an overt act of
21   * relinquishment in perpetuity of all present and future rights to this
22   * software under copyright law.
23   * 
24   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27   * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
28   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
29   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
30   * OTHER DEALINGS IN THE SOFTWARE.
31   * #L%
32   */
33  
34  import java.io.IOException;
35  
36  import nom.tam.fits.header.Bitpix;
37  import nom.tam.fits.header.Standard;
38  import nom.tam.util.ArrayDataInput;
39  import nom.tam.util.ArrayDataOutput;
40  import nom.tam.util.ArrayFuncs;
41  import nom.tam.util.Cursor;
42  import nom.tam.util.FitsEncoder;
43  
44  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
45  
46  /**
47   * A container for unknown binary data types. We can still retrieve the data as a <code>byte[]</code> array, we just
48   * don't know how to interpret it ourselves. This class makes sure we don't break when we encouter HDUs that we don't
49   * (yet) support, such as HDU types defined by future FITS standards.
50   * 
51   * @see UndefinedHDU
52   */
53  public class UndefinedData extends Data {
54  
55      private static final String XTENSION_UNKNOWN = "UNKNOWN";
56      // private static final Logger LOG = getLogger(UndefinedData.class);
57  
58      private Bitpix bitpix = Bitpix.BYTE;
59      private int[] dims;
60      private int byteSize = 0;
61      private byte[] data;
62      private int pCount = 0;
63      private int gCount = 1;
64  
65      private String extensionType = XTENSION_UNKNOWN;
66  
67      /**
68       * Creates a new empty container for data of unknown type based on the provided FITS header information.
69       *
70       * @param      h             The FITS header corresponding to the data segment in the HDU
71       * 
72       * @throws     FitsException if there wan an error accessing or interpreting the provided header information.
73       * 
74       * @deprecated               (<i>for internal use</i>). Visibility will be reduced to the package level in the
75       *                               future.
76       */
77      public UndefinedData(Header h) throws FitsException {
78          extensionType = h.getStringValue(Standard.XTENSION, XTENSION_UNKNOWN);
79  
80          int naxis = h.getIntValue(Standard.NAXIS);
81  
82          dims = new int[naxis];
83  
84          int size = naxis > 0 ? 1 : 0;
85          for (int i = 1; i <= naxis; i++) {
86              dims[naxis - i] = h.getIntValue(Standard.NAXISn.n(i));
87              size *= dims[naxis - i];
88          }
89  
90          pCount = h.getIntValue(Standard.PCOUNT);
91          size += pCount;
92  
93          gCount = h.getIntValue(Standard.GCOUNT);
94          if (gCount > 1) {
95              size *= h.getIntValue(Standard.GCOUNT);
96          }
97  
98          bitpix = Bitpix.fromHeader(h);
99          size *= bitpix.byteSize();
100 
101         byteSize = size;
102     }
103 
104     /**
105      * @deprecated                          (<i>for internal use</i>). Users should always construct known data types.
106      *                                          Reduce visibility to the package level.
107      * 
108      * @param      x                        object to create the hdu from
109      * 
110      * @throws     IllegalArgumentException If the object is not an array or contains elements that do not have a known
111      *                                          binary size.
112      */
113     public UndefinedData(Object x) throws IllegalArgumentException {
114         byteSize = (int) FitsEncoder.computeSize(x);
115         dims = ArrayFuncs.getDimensions(x);
116         data = new byte[byteSize];
117         ArrayFuncs.copyInto(x, data);
118     }
119 
120     @SuppressWarnings("deprecation")
121     @Override
122     protected void fillHeader(Header head) {
123         // We'll assume it's a primary image, until we know better...
124         // Just in case, we don't want an XTENSION key lingering around...
125         head.deleteKey(Standard.SIMPLE);
126         head.deleteKey(Standard.EXTEND);
127 
128         Standard.context(UndefinedData.class);
129 
130         Cursor<String, HeaderCard> c = head.iterator();
131         c.add(HeaderCard.create(Standard.XTENSION, extensionType));
132         c.add(HeaderCard.create(Standard.BITPIX, bitpix.getHeaderValue()));
133 
134         c.add(HeaderCard.create(Standard.NAXIS, dims.length));
135 
136         for (int i = 1; i <= dims.length; i++) {
137             c.add(HeaderCard.create(Standard.NAXISn.n(i), dims[dims.length - i]));
138         }
139 
140         c.add(HeaderCard.create(Standard.PCOUNT, pCount));
141         c.add(HeaderCard.create(Standard.GCOUNT, gCount));
142 
143         Standard.context(null);
144     }
145 
146     @Override
147     @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "intended exposure of mutable data")
148     protected byte[] getCurrentData() {
149         return data;
150     }
151 
152     @Override
153     protected long getTrueSize() {
154         return byteSize;
155     }
156 
157     /**
158      * Returns the FITS extension type as stored by the XTENSION keyword in the FITS header.
159      * 
160      * @return The value used for the XTENSION keyword in the FITS header
161      * 
162      * @since  1.19
163      */
164     public final String getXtension() {
165         return extensionType;
166     }
167 
168     /**
169      * Returns the FITS element type as a Bitpux value.
170      * 
171      * @return The FITS Bitpix value for the type of primitive data element used by this data
172      * 
173      * @since  1.19
174      */
175     public final Bitpix getBitpix() {
176         return bitpix;
177     }
178 
179     /**
180      * Returns the size of the optional parameter space as stored by the PCOUNT keyword in the FITS header.
181      * 
182      * @return The element count of the optional parameter space accompanying the main data, as stored by the PCOUNT
183      *             header value.
184      * 
185      * @since  1.19
186      */
187     public final int getParameterCount() {
188         return pCount;
189     }
190 
191     /**
192      * Returns the number of repeated (data + parameter) groups in this data object
193      * 
194      * @return The number of repeated data + parameter blocks, as stored by the GCOUNT header value.
195      * 
196      * @since  1.19
197      */
198     public final int getGroupCount() {
199         return gCount;
200     }
201 
202     /**
203      * Returns the dimensionality of the data (if any), in Java array index order. That is, The value for NAXIS1 is the
204      * last value in the returned array
205      * 
206      * @return the regular dimensions of the data in Java index order (that is NAXIS1 is the last entry in the array),
207      *             or possibly <code>null</code> if no dimensions have been defined.
208      */
209     public final int[] getDimensions() {
210         return dims;
211     }
212 
213     @Override
214     public byte[] getData() throws FitsException {
215         byte[] bytes = (byte[]) super.getData();
216         if (bytes != null) {
217             return bytes;
218         }
219 
220         data = new byte[byteSize];
221         return data;
222     }
223 
224     @Override
225     protected void loadData(ArrayDataInput in) throws IOException {
226         data = new byte[byteSize];
227         in.readFully(data);
228     }
229 
230     @SuppressWarnings({"resource", "deprecation"})
231     @Override
232     public void write(ArrayDataOutput o) throws FitsException {
233         if (o != getRandomAccessInput()) {
234             ensureData();
235         }
236         try {
237             o.write(data);
238         } catch (IOException e) {
239             throw new FitsException("IO Error on unknown data write", e);
240         }
241         FitsUtil.pad(o, getTrueSize());
242     }
243 
244     @Override
245     @SuppressWarnings("deprecation")
246     public UndefinedHDU toHDU() {
247         Header h = new Header();
248         fillHeader(h);
249         return new UndefinedHDU(h, this);
250     }
251 }