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 PRIMARY_EXTENSION; 71 72 } 73 74 /** Documentation sources for the various known conventions. */ 75 enum SOURCE { 76 /** 77 * Checksum keywords. See 78 * <a href="http://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/general/checksum/checksum.html">checksum doc</a> 79 */ 80 CHECKSUM("http://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/general/checksum/checksum.html"), 81 82 /** 83 * CXC keywords. See <a href= 84 * "http://cxc.harvard.edu/contrib/arots/fits/content.txt">http://cxc.harvard.edu/contrib/arots/fits/content.txt</a> 85 */ 86 CXC("http://cxc.harvard.edu/contrib/arots/fits/content.txt"), 87 /** 88 * ESO keywords. See <a href= 89 * "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> 90 */ 91 ESO("http://arcdev.hq.eso.org/dicb/dicd/dic-1-1.4.html"), 92 /** 93 * HEASARC keywords. See <a href= 94 * "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> 95 */ 96 HEASARC("http://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/ofwg_recomm/r13.html"), 97 /** 98 * The keyword is integral to the workings of the library. Users should not attempt set set or modify. 99 */ 100 INTEGRAL(null), 101 /** 102 * Mandatory keywords defined by the FITS standard. 103 */ 104 MANDATORY("http://heasarc.gsfc.nasa.gov/docs/fcg/standard_dict.html"), 105 /** 106 * MaxImDL keywords. See <a href= 107 * "http://www.cyanogen.com/help/maximdl/FITS_File_Header_Definitions.htm">http://www.cyanogen.com/help/maximdl/FITS_File_Header_Definitions.htm</a> 108 */ 109 MaxImDL("http://www.cyanogen.com/help/maximdl/FITS_File_Header_Definitions.htm"), 110 /** 111 * NOAO keywords. See <a href= 112 * "http://iraf.noao.edu/iraf/web/projects/ccdmosaic/imagedef/fitsdic.html">http://iraf.noao.edu/iraf/web/projects/ccdmosaic/imagedef/fitsdic.html</a> 113 */ 114 NOAO("http://iraf.noao.edu/iraf/web/projects/ccdmosaic/imagedef/fitsdic.html"), 115 /** 116 * Reserved keywords specified by the FITS standard. 117 */ 118 RESERVED("http://heasarc.gsfc.nasa.gov/docs/fcg/standard_dict.html"), 119 /** 120 * ROSAT keywords. (No link available.) 121 */ 122 ROSAT(null), 123 /** 124 * SBIG keywords. See <a href= 125 * "http://archive.sbig.com/pdffiles/SBFITSEXT_1r0.pdf">http://archive.sbig.com/pdffiles/SBFITSEXT_1r0.pdf</a> 126 */ 127 SBIG("http://archive.sbig.com/pdffiles/SBFITSEXT_1r0.pdf"), 128 /** 129 * STScI keywords. See <a href= 130 * "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> 131 */ 132 STScI("http://tucana.noao.edu/ADASS/adass_proc/adass_95/zaraten/zaraten.html"), 133 /** 134 * UCOLICK keywords. See <a href="http://www.ucolick.org">http://www.ucolick.org</a> 135 */ 136 UCOLICK("http://www.ucolick.org"), 137 /** 138 * developed over time, source long forgotten. 139 */ 140 UNKNOWN(null); 141 142 private final String url; 143 144 SOURCE(String url) { 145 this.url = url; 146 } 147 148 /** 149 * Returns the URL that defines this particular header value, which may be <code>null</code>. 150 * 151 * @return The URL that contains the keyword specification or <code>null</code> if unknown or undefined. 152 */ 153 public String url() { 154 return url; 155 } 156 } 157 158 /** Values types to which implementing keywords can be restricted to. */ 159 enum VALUE { 160 /** The keyword takes no value (i.e. END or comment-style keywords */ 161 NONE, 162 163 /** keyword expects a logical 'T' or 'F' value */ 164 LOGICAL, 165 166 /** keyword expects a String value */ 167 STRING, 168 169 /** keyword expects an integer type value */ 170 INTEGER, 171 172 /** keyword expects a floating-point value (integers allowed). */ 173 REAL, 174 175 /** keyword expects a complex value */ 176 COMPLEX, 177 178 /** The keyword may be used with any value type */ 179 ANY 180 } 181 182 /** 183 * (<i>primarily for internal use</i>) Returns the concrete implementation of this header entry, which provides 184 * implementation of access methods. 185 * 186 * @return the implementation of this keyword, which provides the actual access methods. Implementations of this 187 * interface should simply return themselves. 188 * 189 * @since 1.19 190 */ 191 default FitsKey impl() { 192 return null; 193 } 194 195 /** 196 * Returns the comment associated to this FITS header entry. The comment is entirely optional, and it may not be 197 * appear in full (or at all) in the FITS header. Comments should thus never contain essential information. Their 198 * purpose is only to provide non-essential extra information for human use. 199 * 200 * @return the associated standard comment. 201 * 202 * @see HeaderCard#getComment() 203 * @see HeaderCard#setComment(String) 204 */ 205 default String comment() { 206 return impl().comment(); 207 } 208 209 /** 210 * Returns the type of HDU(s) in which this header entry may be used. 211 * 212 * @return the HDU type(s) that this keyword may support. 213 */ 214 default HDU hdu() { 215 return impl().hdu(); 216 } 217 218 /** 219 * <p> 220 * Returns the FITS header keyword (or keyword template) for this header entry. Standard FITS keywords are limited 221 * to 8 characters, and contain only epper-case letters, numbers, hyphen, and underscore characters. Lower-case 'n' 222 * characters may be included as placeholders for indexing conventions that must be filled before the keyword may be 223 * used in headers and/or header cards. 224 * </p> 225 * 226 * @return the FITS header keyword for this entry. The returned keyword may include an indexing pattern (lower-case 227 * 'n' characters), which may need to be filled via {@link #n(int...)} before the keyword may be used to 228 * construct header cards or be used in FITS headers. (Alternative coordinate markers, via lower case 229 * 'a' at the end of the keyword definition, are stripped and should not be included in the returned 230 * keyword name pattern.) 231 * 232 * @see #n(int...) 233 */ 234 default String key() { 235 return impl().key(); 236 } 237 238 /** 239 * Constructs an indexed FITS header keyword entry from this stem, replacing index place-holders (indicated by 240 * lower-case 'n' in the name) with actual numerical values. Numbering for FITS header keywords always starts from 241 * 1, and should never exceed 999. Note, that for keywords that have multiple indices, you may specify them all in a 242 * single call, or may use successive calls to fill indices in the order they appear (the latter is somewhat less 243 * efficient, but still entirely legal). 244 * 245 * @param numbers the 1-based indices to add to the stem, in the order they appear in the the 246 * enum name. 247 * 248 * @return an indexed instance of this FITS header entry 249 * 250 * @throws IndexOutOfBoundsException if the index is less than 0 or exceeds 999. (In truth we should throw an 251 * exception for 0 as well, but seems to be common not-quite-legal FITS usage 252 * with 0 indices. Hence we relax the condition). 253 * @throws IllegalStateException if the resulting indexed keyword exceeds the maximum 8-bytes allowed for 254 * standard FITS keywords. 255 * @throws NoSuchElementException If more indices were supplied than can be filled for this keyword. 256 * 257 * @see #extractIndices(String) 258 */ 259 default IFitsHeader n(int... numbers) throws IndexOutOfBoundsException, NoSuchElementException, IllegalStateException { 260 StringBuffer headerName = new StringBuffer(key()); 261 for (int number : numbers) { 262 if (number < 0 || number > MAX_INDEX) { 263 throw new IndexOutOfBoundsException(key() + ": index " + number + " is out of bounds."); 264 } 265 266 int indexOfN = headerName.indexOf("n"); 267 268 if (indexOfN < 0) { 269 throw new NoSuchElementException("Too many indices (" + numbers.length + ") supplied for " + key()); 270 } 271 272 headerName.replace(indexOfN, indexOfN + 1, Integer.toString(number)); 273 } 274 275 if (headerName.length() > HeaderCard.MAX_KEYWORD_LENGTH) { 276 throw new IllegalStateException("indexed keyword " + headerName.toString() + " is too long."); 277 } 278 279 return new FitsKey(headerName.toString(), status(), hdu(), valueType(), comment()); 280 } 281 282 /** 283 * Returns the standard convention, which defines this FITS header entry 284 * 285 * @return the standard or convention that specifies this FITS heacer keyword 286 */ 287 default SOURCE status() { 288 return impl().status(); 289 } 290 291 /** 292 * The type(s) of value(s) this FITS header entry might take. 293 * 294 * @return the value type(s) for this FITS header entry 295 */ 296 default VALUE valueType() { 297 return impl().valueType(); 298 } 299 300 /** 301 * Extracts the indices for this stndardized key from an actual keyword realization. The keyword realization must be 302 * match the indexing and/or alternative coordinate system pattern for this key, or else an exception will be 303 * thrown. 304 * 305 * @param key The actual keyword as it appears in a FITS header 306 * 307 * @return An array of indices that appear in the key, or <code>null</code> if the keyword 308 * is not one that can be indexed. 309 * 310 * @throws IllegalArgumentException if the keyword does not match the pattern of this standardized FITS key 311 * 312 * @see #n(int...) 313 * @see Standard#match(String) 314 * 315 * @since 1.19 316 */ 317 default int[] extractIndices(String key) throws IllegalArgumentException { 318 String pattern = key(); 319 int i, j = 0, lp = pattern.length(), lk = key.length(); 320 int n = 0; 321 322 for (i = 0; i < lp; i++) { 323 if (pattern.charAt(i) == 'n') { 324 n++; 325 } 326 } 327 328 if (n == 0) { 329 return null; 330 } 331 332 int[] idx = new int[n]; 333 334 for (i = 0, n = 0; i < lp; i++) { 335 if (pattern.charAt(i) == 'n') { 336 if (i + 1 < lp && pattern.charAt(i + 1) == 'n') { 337 idx[n++] = key.charAt(j++) - '0'; 338 } else { 339 int value = 0; 340 while (j < lk && Character.isDigit(key.charAt(j))) { 341 value = FitsKey.BASE_10 * value + key.charAt(j++) - '0'; 342 } 343 idx[n++] = value; 344 } 345 } else if (key.charAt(j++) != pattern.charAt(i)) { 346 throw new IllegalArgumentException("Key " + key + " does no match pattern " + pattern); 347 } 348 } 349 350 return idx; 351 } 352 353 }