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 }