View Javadoc
1   package nom.tam.fits.header;
2   
3   import java.util.NoSuchElementException;
4   
5   import nom.tam.fits.HeaderCard;
6   
7   /*
8    * #%L
9    * INDI for Java Utilities for the fits image format
10   * %%
11   * Copyright (C) 2012 - 2015 indiforjava
12   * %%
13   * This is free and unencumbered software released into the public domain.
14   *
15   * Anyone is free to copy, modify, publish, use, compile, sell, or
16   * distribute this software, either in source code form or as a compiled
17   * binary, for any purpose, commercial or non-commercial, and by any
18   * means.
19   *
20   * In jurisdictions that recognize copyright laws, the author or authors
21   * of this software dedicate any and all copyright interest in the
22   * software to the public domain. We make this dedication for the benefit
23   * of the public at large and to the detriment of our heirs and
24   * successors. We intend this dedication to be an overt act of
25   * relinquishment in perpetuity of all present and future rights to this
26   * software under copyright law.
27   *
28   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
31   * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
32   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
33   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
34   * OTHER DEALINGS IN THE SOFTWARE.
35   * #L%
36   */
37  
38  /**
39   * Interface for standardized header keyword implementations. Standardized header keys help with proper usage, with
40   * restricted use and value types as appropriate. Using keywords that implement this interface make it less likely for
41   * one to end up with inproperly constructed FITS files. Therefore, their usage is highly encouranged when possible.
42   * 
43   * @see HeaderCard#setValueCheckingPolicy(nom.tam.fits.HeaderCard.ValueCheck)
44   * @see nom.tam.fits.Header#setKeywordChecking(nom.tam.fits.Header.KeywordCheck)
45   */
46  public interface IFitsHeader {
47  
48      /** Max numeric index we may use to replace <i>n</i> in the Java name of indexed variables. */
49      int MAX_INDEX = 999;
50  
51      /** An enumeration of HDU types in which a header keyword may be used. */
52      enum HDU {
53          /** keyword may be used in any HDU */
54          ANY,
55          /** image and/or random groups keywords */
56          IMAGE,
57          /** keyword for random groups only */
58          GROUPS,
59          /** Generic table keyword, can be used both in ASCII and binary tables */
60          TABLE,
61          /** keyword for ASCII tables only */
62          ASCII_TABLE,
63          /** keyword for binary tables */
64          BINTABLE,
65          /** keyword must appear in the primary HDU only */
66          PRIMARY,
67          /** keyword must appear in extension HDUs only */
68          EXTENSION,
69          /** @deprecated Use {@link #ANY} instead. */
70          @Deprecated
71          PRIMARY_EXTENSION;
72  
73      }
74  
75      /** Documentation sources for the various known conventions. */
76      enum SOURCE {
77          /**
78           * Checksum keywords. See
79           * <a href="http://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/general/checksum/checksum.html">checksum doc</a>
80           */
81          CHECKSUM("http://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/general/checksum/checksum.html"),
82  
83          /**
84           * CXC keywords. See <a href=
85           * "http://cxc.harvard.edu/contrib/arots/fits/content.txt">http://cxc.harvard.edu/contrib/arots/fits/content.txt</a>
86           */
87          CXC("http://cxc.harvard.edu/contrib/arots/fits/content.txt"),
88          /**
89           * ESO keywords. See <a href=
90           * "http://arcdev.hq.eso.org/dicb/dicd/dic-1-1.4.html">http://arcdev.hq.eso.org/dicb/dicd/dic-1-1.4.html</a>
91           */
92          ESO("http://arcdev.hq.eso.org/dicb/dicd/dic-1-1.4.html"),
93          /**
94           * HEASARC keywords. See <a href=
95           * "http://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/ofwg_recomm/r13.html">http://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/ofwg_recomm/r13.html</a>
96           */
97          HEASARC("http://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/ofwg_recomm/r13.html"),
98          /**
99           * The keyword is integral to the workings of the library. Users should not attempt set set or modify.
100          */
101         INTEGRAL(null),
102         /**
103          * Mandatory keywords defined by the FITS standard.
104          */
105         MANDATORY("http://heasarc.gsfc.nasa.gov/docs/fcg/standard_dict.html"),
106         /**
107          * MaxImDL keywords. See <a href=
108          * "http://www.cyanogen.com/help/maximdl/FITS_File_Header_Definitions.htm">http://www.cyanogen.com/help/maximdl/FITS_File_Header_Definitions.htm</a>
109          */
110         MaxImDL("http://www.cyanogen.com/help/maximdl/FITS_File_Header_Definitions.htm"),
111         /**
112          * NOAO keywords. See <a href=
113          * "http://iraf.noao.edu/iraf/web/projects/ccdmosaic/imagedef/fitsdic.html">http://iraf.noao.edu/iraf/web/projects/ccdmosaic/imagedef/fitsdic.html</a>
114          */
115         NOAO("http://iraf.noao.edu/iraf/web/projects/ccdmosaic/imagedef/fitsdic.html"),
116         /**
117          * Reserved keywords specified by the FITS standard.
118          */
119         RESERVED("http://heasarc.gsfc.nasa.gov/docs/fcg/standard_dict.html"),
120         /**
121          * ROSAT keywords. (No link available.)
122          */
123         ROSAT(null),
124         /**
125          * SBIG keywords. See <a href=
126          * "http://archive.sbig.com/pdffiles/SBFITSEXT_1r0.pdf">http://archive.sbig.com/pdffiles/SBFITSEXT_1r0.pdf</a>
127          */
128         SBIG("http://archive.sbig.com/pdffiles/SBFITSEXT_1r0.pdf"),
129         /**
130          * STScI keywords. See <a href=
131          * "http://tucana.noao.edu/ADASS/adass_proc/adass_95/zaraten/zaraten.html">http://tucana.noao.edu/ADASS/adass_proc/adass_95/zaraten/zaraten.html</a>
132          */
133         STScI("http://tucana.noao.edu/ADASS/adass_proc/adass_95/zaraten/zaraten.html"),
134         /**
135          * UCOLICK keywords. See <a href="http://www.ucolick.org">http://www.ucolick.org</a>
136          */
137         UCOLICK("http://www.ucolick.org"),
138         /**
139          * developed over time, source long forgotten.
140          */
141         UNKNOWN(null);
142 
143         private final String url;
144 
145         SOURCE(String url) {
146             this.url = url;
147         }
148 
149         /**
150          * Returns the URL that defines this particular header value, which may be <code>null</code>.
151          * 
152          * @return The URL that contains the keyword specification or <code>null</code> if unknown or undefined.
153          */
154         public String url() {
155             return url;
156         }
157     }
158 
159     /** Values types to which implementing keywords can be restricted to. */
160     enum VALUE {
161         /** The keyword takes no value (i.e. END or comment-style keywords */
162         NONE,
163 
164         /** keyword expects a logical 'T' or 'F' value */
165         LOGICAL,
166 
167         /** keyword expects a String value */
168         STRING,
169 
170         /** keyword expects an integer type value */
171         INTEGER,
172 
173         /** keyword expects a floating-point value (integers allowed). */
174         REAL,
175 
176         /** keyword expects a complex value */
177         COMPLEX,
178 
179         /** The keyword may be used with any value type */
180         ANY
181     }
182 
183     /**
184      * (<i>primarily for internal use</i>) Returns the concrete implementation of this header entry, which provides
185      * implementation of access methods.
186      * 
187      * @return the implementation of this keyword, which provides the actual access methods. Implementations of this
188      *             interface should simply return themselves.
189      * 
190      * @since  1.19
191      */
192     default FitsKey impl() {
193         return null;
194     }
195 
196     /**
197      * Returns the comment associated to this FITS header entry. The comment is entirely optional, and it may not be
198      * appear in full (or at all) in the FITS header. Comments should thus never contain essential information. Their
199      * purpose is only to provide non-essential extra information for human use.
200      * 
201      * @return the associated standard comment.
202      * 
203      * @see    HeaderCard#getComment()
204      * @see    HeaderCard#setComment(String)
205      */
206     default String comment() {
207         return impl().comment();
208     }
209 
210     /**
211      * Returns the type of HDU(s) in which this header entry may be used.
212      * 
213      * @return the HDU type(s) that this keyword may support.
214      */
215     default HDU hdu() {
216         return impl().hdu();
217     }
218 
219     /**
220      * <p>
221      * Returns the FITS header keyword (or keyword template) for this header entry. Standard FITS keywords are limited
222      * to 8 characters, and contain only epper-case letters, numbers, hyphen, and underscore characters. Lower-case 'n'
223      * characters may be included as placeholders for indexing conventions that must be filled before the keyword may be
224      * used in headers and/or header cards.
225      * </p>
226      * 
227      * @return the FITS header keyword for this entry. The returned keyword may include an indexing pattern (lower-case
228      *             'n' characters), which may need to be filled via {@link #n(int...)} before the keyword may be used to
229      *             construct header cards or be used in FITS headers. (Alternative coordinate markers, via lower case
230      *             'a' at the end of the keyword definition, are stripped and should not be included in the returned
231      *             keyword name pattern.)
232      * 
233      * @see    #n(int...)
234      */
235     default String key() {
236         return impl().key();
237     }
238 
239     /**
240      * Constructs an indexed FITS header keyword entry from this stem, replacing index place-holders (indicated by
241      * lower-case 'n' in the name) with actual numerical values. Numbering for FITS header keywords always starts from
242      * 1, and should never exceed 999. Note, that for keywords that have multiple indices, you may specify them all in a
243      * single call, or may use successive calls to fill indices in the order they appear (the latter is somewhat less
244      * efficient, but still entirely legal).
245      * 
246      * @param  numbers                   the 1-based indices to add to the stem, in the order they appear in the the
247      *                                       enum name.
248      * 
249      * @return                           an indexed instance of this FITS header entry
250      * 
251      * @throws IndexOutOfBoundsException if the index is less than 0 or exceeds 999. (In truth we should throw an
252      *                                       exception for 0 as well, but seems to be common not-quite-legal FITS usage
253      *                                       with 0 indices. Hence we relax the condition).
254      * @throws IllegalStateException     if the resulting indexed keyword exceeds the maximum 8-bytes allowed for
255      *                                       standard FITS keywords.
256      * @throws NoSuchElementException    If more indices were supplied than can be filled for this keyword.
257      * 
258      * @see                              #extractIndices(String)
259      */
260     default IFitsHeader n(int... numbers) throws IndexOutOfBoundsException, NoSuchElementException, IllegalStateException {
261         StringBuffer headerName = new StringBuffer(key());
262         for (int number : numbers) {
263             if (number < 0 || number > MAX_INDEX) {
264                 throw new IndexOutOfBoundsException(key() + ": index " + number + " is out of bounds.");
265             }
266 
267             int indexOfN = headerName.indexOf("n");
268 
269             if (indexOfN < 0) {
270                 throw new NoSuchElementException("Too many indices (" + numbers.length + ") supplied for " + key());
271             }
272 
273             headerName.replace(indexOfN, indexOfN + 1, Integer.toString(number));
274         }
275 
276         if (headerName.length() > HeaderCard.MAX_KEYWORD_LENGTH) {
277             throw new IllegalStateException("indexed keyword " + headerName.toString() + " is too long.");
278         }
279 
280         return new FitsKey(headerName.toString(), status(), hdu(), valueType(), comment());
281     }
282 
283     /**
284      * Returns the standard convention, which defines this FITS header entry
285      * 
286      * @return the standard or convention that specifies this FITS heacer keyword
287      */
288     default SOURCE status() {
289         return impl().status();
290     }
291 
292     /**
293      * The type(s) of value(s) this FITS header entry might take.
294      * 
295      * @return the value type(s) for this FITS header entry
296      */
297     default VALUE valueType() {
298         return impl().valueType();
299     }
300 
301     /**
302      * Extracts the indices for this stndardized key from an actual keyword realization. The keyword realization must be
303      * match the indexing and/or alternative coordinate system pattern for this key, or else an exception will be
304      * thrown.
305      * 
306      * @param  key                      The actual keyword as it appears in a FITS header
307      * 
308      * @return                          An array of indices that appear in the key, or <code>null</code> if the keyword
309      *                                      is not one that can be indexed.
310      * 
311      * @throws IllegalArgumentException if the keyword does not match the pattern of this standardized FITS key
312      * 
313      * @see                             #n(int...)
314      * @see                             Standard#match(String)
315      * 
316      * @since                           1.19
317      */
318     default int[] extractIndices(String key) throws IllegalArgumentException {
319         String pattern = key();
320         int i, j = 0, lp = pattern.length(), lk = key.length();
321         int n = 0;
322 
323         for (i = 0; i < lp; i++) {
324             if (pattern.charAt(i) == 'n') {
325                 n++;
326             }
327         }
328 
329         if (n == 0) {
330             return null;
331         }
332 
333         int[] idx = new int[n];
334 
335         for (i = 0, n = 0; i < lp; i++) {
336             if (pattern.charAt(i) == 'n') {
337                 if (i + 1 < lp && pattern.charAt(i + 1) == 'n') {
338                     idx[n++] = key.charAt(j++) - '0';
339                 } else {
340                     int value = 0;
341                     while (j < lk && Character.isDigit(key.charAt(j))) {
342                         value = FitsKey.BASE_10 * value + key.charAt(j++) - '0';
343                     }
344                     idx[n++] = value;
345                 }
346             } else if (key.charAt(j++) != pattern.charAt(i)) {
347                 throw new IllegalArgumentException("Key " + key + " does no match pattern " + pattern);
348             }
349         }
350 
351         return idx;
352     }
353 
354 }