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