1 package nom.tam.fits; 2 3 import java.util.concurrent.ExecutorService; 4 import java.util.concurrent.Executors; 5 import java.util.concurrent.ThreadFactory; 6 7 import nom.tam.fits.header.Standard; 8 import nom.tam.fits.header.hierarch.IHierarchKeyFormatter; 9 import nom.tam.fits.header.hierarch.StandardIHierarchKeyFormatter; 10 import nom.tam.image.compression.hdu.CompressedImageData; 11 import nom.tam.image.compression.hdu.CompressedImageHDU; 12 import nom.tam.image.compression.hdu.CompressedTableData; 13 import nom.tam.image.compression.hdu.CompressedTableHDU; 14 15 /* 16 * #%L 17 * nom.tam FITS library 18 * %% 19 * Copyright (C) 2004 - 2024 nom-tam-fits 20 * %% 21 * This is free and unencumbered software released into the public domain. 22 * 23 * Anyone is free to copy, modify, publish, use, compile, sell, or 24 * distribute this software, either in source code form or as a compiled 25 * binary, for any purpose, commercial or non-commercial, and by any 26 * means. 27 * 28 * In jurisdictions that recognize copyright laws, the author or authors 29 * of this software dedicate any and all copyright interest in the 30 * software to the public domain. We make this dedication for the benefit 31 * of the public at large and to the detriment of our heirs and 32 * successors. We intend this dedication to be an overt act of 33 * relinquishment in perpetuity of all present and future rights to this 34 * software under copyright law. 35 * 36 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 37 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 38 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 39 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 40 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 41 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 42 * OTHER DEALINGS IN THE SOFTWARE. 43 * #L% 44 */ 45 46 /** 47 * Controls the creation of HDUs to encapsulate a variery of data, based on a few configuration switches. The switches 48 * allow for toggling support for different conventions to set the desired compatibility level. The default settings 49 * produce FITS that are compatibel with version 4.0 of the standard (the latest at the time of writing this). The 50 * switches may also be used to make this library more backward compatible with its previous version also. 51 */ 52 public final class FitsFactory { 53 54 private static final boolean DEFAULT_USE_ASCII_TABLES = false; 55 56 private static final boolean DEFAULT_USE_HIERARCH = true; 57 58 private static final boolean DEFAULT_USE_EXPONENT_D = false; 59 60 private static final boolean DEFAULT_LONG_STRINGS_ENABLED = true; 61 62 private static final boolean DEFAULT_CHECK_ASCII_STRINGS = false; 63 64 private static final boolean DEFAULT_ALLOW_TERMINAL_JUNK = true; 65 66 private static final boolean DEFAULT_ALLOW_HEADER_REPAIRS = true; 67 68 private static final boolean DEFAULT_SKIP_BLANK_AFTER_ASSIGN = false; 69 70 private static final boolean DEFAULT_CASE_SENSITIVE_HIERARCH = false; 71 72 /** 73 * AK: true is the legacy behavior TODO If and when it is changed to false, the corresponding Logger warnings in 74 * BinaryTable should also be removed. 75 */ 76 private static final boolean DEFAULT_USE_UNICODE_CHARS = true; 77 78 private static final IHierarchKeyFormatter DEFAULT_HIERARCH_FORMATTER = new StandardIHierarchKeyFormatter(); 79 80 /** 81 * An class for aggregating all the settings internal to {@link FitsFactory}. 82 * 83 * @author Attila Kovacs 84 */ 85 protected static final class FitsSettings implements Cloneable { 86 87 private boolean useAsciiTables; 88 89 private boolean useHierarch; 90 91 private boolean useExponentD; 92 93 private boolean checkAsciiStrings; 94 95 private boolean allowTerminalJunk; 96 97 private boolean allowHeaderRepairs; 98 99 private boolean longStringsEnabled; 100 101 private boolean useUnicodeChars; 102 103 @Deprecated 104 private boolean skipBlankAfterAssign; 105 106 private IHierarchKeyFormatter hierarchKeyFormatter = DEFAULT_HIERARCH_FORMATTER; 107 108 private FitsSettings() { 109 useAsciiTables = DEFAULT_USE_ASCII_TABLES; 110 useHierarch = DEFAULT_USE_HIERARCH; 111 useUnicodeChars = DEFAULT_USE_UNICODE_CHARS; 112 checkAsciiStrings = DEFAULT_CHECK_ASCII_STRINGS; 113 useExponentD = DEFAULT_USE_EXPONENT_D; 114 allowTerminalJunk = DEFAULT_ALLOW_TERMINAL_JUNK; 115 allowHeaderRepairs = DEFAULT_ALLOW_HEADER_REPAIRS; 116 longStringsEnabled = DEFAULT_LONG_STRINGS_ENABLED; 117 skipBlankAfterAssign = DEFAULT_SKIP_BLANK_AFTER_ASSIGN; 118 hierarchKeyFormatter = DEFAULT_HIERARCH_FORMATTER; 119 hierarchKeyFormatter.setCaseSensitive(DEFAULT_CASE_SENSITIVE_HIERARCH); 120 } 121 122 @Override 123 protected FitsSettings clone() { 124 try { 125 return (FitsSettings) super.clone(); 126 } catch (CloneNotSupportedException e) { 127 return null; 128 } 129 } 130 131 private FitsSettings copy() { 132 return clone(); 133 } 134 135 /** 136 * Returns the formatter instance for HIERARCH style keywords. Our own standard is to define such keywords 137 * internally as starting with the string <code>HIERARCH.</code> followed by a dot-separated hierarchy, or just 138 * an unusually long FITS keywords that cannot be represented by a standard 8-byte keyword. The HIERARCH 139 * formatted will take such string keywords and will format them according to its rules when writing them to 140 * FITS headers. 141 * 142 * @return The formatter instance used for HIERARCH-style keywords. 143 */ 144 protected IHierarchKeyFormatter getHierarchKeyFormatter() { 145 return hierarchKeyFormatter; 146 } 147 148 /** 149 * Checks if we should use the letter 'D' to mark exponents of double-precision values (in FITS headers and 150 * ASCII tables). For ecample, in the typical Java number formatting the String <code>1.37E-13</code> may 151 * represent either a <code>float</code> or <code>double</code> value -- which are not exactly the same. For 152 * that reason FITS offers the possibility to replace 'E' in the string formatted number with 'D' when the value 153 * specifies a double-precision number, thus disambiguating the two. 154 * 155 * @return <code>true</code> if we will use 'D' to denote the exponent of double-precision values in FITS 156 * headers and ASCII tables. 157 */ 158 protected boolean isUseExponentD() { 159 return useExponentD; 160 } 161 162 /** 163 * Checks if we treat junk after the last properly formed HDU silently withotu generating an exception. When 164 * this setting is <code>true</code> we can read corrupted FITS files (at least partially) without raising an 165 * alarm. 166 * 167 * @return <code>true</code> if we allow additional bytes after the last readable HDU to be present in FITS 168 * files without throwing an exception. Otherwise <code>false</code>. 169 */ 170 protected boolean isAllowTerminalJunk() { 171 return allowTerminalJunk; 172 } 173 174 /** 175 * Whether we check if ASCII strings in FITS files conform to the restricted set of characters (0x20 trough 176 * 0x7E) allowed by the FITS standard. If the checking is enabled, we will log any such violations so they can 177 * be inspected and perhaps fixed. 178 * 179 * @return <code>true</code> if we should check and report if string appearing in FITS files do not conform to 180 * specification. Otherwise <code>false</code> 181 */ 182 protected boolean isCheckAsciiStrings() { 183 return checkAsciiStrings; 184 } 185 186 /** 187 * Checks if we allow storing long string values (using the OGIP 1.0 convention) in FITS headers. Such long 188 * string may span multiple 80-character header records. They are now standard as of FITS 4.0, but they were not 189 * in earlier specifications. When long strings are not enabled, we will throw a {@link LongValueException} 190 * whenever one tries to add a string value that cannot be contained in a single 80-character header record. 191 * 192 * @return <code>true</code> (default) if we allow adding long string values to out FITS headers. Otherwise 193 * <code>false</code>. 194 */ 195 protected boolean isLongStringsEnabled() { 196 return longStringsEnabled; 197 } 198 199 /** 200 * @deprecated The FITS standard is very explicit that assignment must be "= " (equals followed by a space). If 201 * we allow skipping the space, it will result in a non-standard FITS, and may render it 202 * unreadable for other tools. 203 * 204 * @return whether to use only "=", instead of the standard "= " between the keyword and the value. 205 */ 206 @Deprecated 207 protected boolean isSkipBlankAfterAssign() { 208 return skipBlankAfterAssign; 209 } 210 211 /** 212 * Whether to write tables as ASCII tables automatically if possible. Binary tables are generally always a 213 * better option, as they are both more compact and flexible but sometimes we might want to make our table data 214 * to be human readable in a terminal without needing any FITS-specific tool -- even though the 1970s is long 215 * past... 216 * 217 * @return <code>true</code> if we have a preference for writing table data in ASCII format (rather than 218 * binary), whenever that is possible. Otherwise <code>false</code> 219 */ 220 protected boolean isUseAsciiTables() { 221 return useAsciiTables; 222 } 223 224 /** 225 * Whether we allow using HIERARCH-style keywords, which may be longer than the standard 8-character FITS 226 * keywords, and may specify a hierarchy, and may also allow upper and lower-case characters depending on what 227 * formatting rules we use. Our own standard is to define such keywords internally as starting with the string 228 * <code>HIERARCH.</code> followed by a dot-separated hierarchy, or just an unusually long FITS keywords that 229 * cannot be represented by a standard 8-byte keyword. 230 * 231 * @return <code>true</code> if we allow HIERARCH keywords. Otherwise <code>false</code> 232 */ 233 protected boolean isUseHierarch() { 234 return useHierarch; 235 } 236 237 /** 238 * Checks if we allow storing Java <code>char[]</code> arrays in binary tables as 16-bit <code>short[]</code>. 239 * Otherwise we will store them as simple 8-bit ASCII. 240 * 241 * @return <code>true</code> if <code>char[]</code> is stored as <code>short[]</code> in binary tables, or 242 * <code>false</code> if we store than as 8-bit ASCII. 243 */ 244 protected boolean isUseUnicodeChars() { 245 return useUnicodeChars; 246 } 247 248 /** 249 * Checks if we are tolerant to FITS standard violations when reading 3rd party FITS files. 250 * 251 * @return <code>true</code> if we tolerate minor violations of the FITS standard when interpreting headers, 252 * which are unlikely to affect the integrity of the FITS otherwise. The violations will still be 253 * logged, but no exception will be generated. Or, <code>false</code> if we want to generate 254 * exceptions for such error.s 255 */ 256 protected boolean isAllowHeaderRepairs() { 257 return allowHeaderRepairs; 258 } 259 260 } 261 262 private static final FitsSettings GLOBAL_SETTINGS = new FitsSettings(); 263 264 private static final ThreadLocal<FitsSettings> LOCAL_SETTINGS = new ThreadLocal<>(); 265 266 private static ExecutorService threadPool; 267 268 /** 269 * the size of a FITS block in bytes. 270 */ 271 public static final int FITS_BLOCK_SIZE = 2880; 272 273 /** 274 * @deprecated (<i>for internal use</i>) Will reduce visibility in the future 275 * 276 * @return Given a Header construct an appropriate data. 277 * 278 * @param hdr header to create the data from 279 * 280 * @throws FitsException if the header did not contain enough information to detect the type of the data 281 */ 282 @Deprecated 283 public static Data dataFactory(Header hdr) throws FitsException { 284 285 if (ImageHDU.isHeader(hdr)) { 286 if (hdr.getIntValue(Standard.NAXIS, 0) == 0) { 287 return new NullData(); 288 } 289 290 Data d = ImageHDU.manufactureData(hdr); 291 // Fix for positioning error noted by V. Forchi 292 if (hdr.findCard(Standard.EXTEND) != null) { 293 hdr.nextCard(); 294 } 295 return d; 296 } 297 if (RandomGroupsHDU.isHeader(hdr)) { 298 return RandomGroupsHDU.manufactureData(hdr); 299 } 300 if (AsciiTableHDU.isHeader(hdr)) { 301 return AsciiTableHDU.manufactureData(hdr); 302 } 303 if (CompressedImageHDU.isHeader(hdr)) { 304 return CompressedImageHDU.manufactureData(hdr); 305 } 306 if (CompressedTableHDU.isHeader(hdr)) { 307 return CompressedTableHDU.manufactureData(hdr); 308 } 309 if (BinaryTableHDU.isHeader(hdr)) { 310 return BinaryTableHDU.manufactureData(hdr); 311 } 312 if (UndefinedHDU.isHeader(hdr)) { 313 return UndefinedHDU.manufactureData(hdr); 314 } 315 throw new FitsException("Unrecognizable header in dataFactory"); 316 } 317 318 /** 319 * Whether the letter 'D' may replace 'E' in the exponential notation of doubl-precision values. FITS allows (even 320 * encourages) the use of 'D' to indicate double-recision values. For example to disambiguate between 1.37E-3 321 * (single-precision) and 1.37D-3 (double-precision), which are not exatly the same value in binary representation. 322 * 323 * @return Do we allow automatic header repairs, like missing end quotes? 324 * 325 * @since 1.16 326 * 327 * @see #setUseExponentD(boolean) 328 */ 329 public static boolean isUseExponentD() { 330 return current().isUseExponentD(); 331 } 332 333 /** 334 * Whether <code>char[]</code> arrays are written as 16-bit integers (<code>short[]</code>) int binary tables as 335 * opposed as FITS character arrays (<code>byte[]</code> with column type 'A'). See more explanation in 336 * {@link #setUseUnicodeChars(boolean)}. 337 * 338 * @return <code>true</code> if <code>char[]</code> get written as 16-bit integers in binary table columns (column 339 * type 'I'), or as FITS 1-byte ASCII character arrays (as is always the case for <code>String</code>) 340 * with column type 'A'. 341 * 342 * @since 1.16 343 * 344 * @see #setUseUnicodeChars(boolean) 345 */ 346 public static boolean isUseUnicodeChars() { 347 return current().isUseUnicodeChars(); 348 } 349 350 /** 351 * Whether extra bytes are tolerated after the end of an HDU. Normally if there is additional bytes present after an 352 * HDU, it would be the beginning of another HDU -- which must start with a very specific sequence of bytes. So, 353 * when there is data beyond the end of an HDU that does not appear to be another HDU, it's junk. We can either 354 * ignore it, or throw an exception. 355 * 356 * @return Is terminal junk (i.e., non-FITS data following a valid HDU) allowed. 357 * 358 * @see #setAllowTerminalJunk(boolean) 359 */ 360 public static boolean getAllowTerminalJunk() { 361 return current().isAllowTerminalJunk(); 362 } 363 364 /** 365 * Whether we allow 3rd party FITS headers to be in violation of the standard, attempting to make sense of corrupted 366 * header data as much as possible. 367 * 368 * @return Do we allow automatic header repairs, like missing end quotes? 369 * 370 * @see #setAllowHeaderRepairs(boolean) 371 */ 372 public static boolean isAllowHeaderRepairs() { 373 return current().isAllowHeaderRepairs(); 374 } 375 376 /** 377 * Returns the formatter instance for HIERARCH style keywords. Our own standard is to define such keywords 378 * internally as starting with the string <code>HIERARCH.</code> followed by a dot-separated hierarchy, or just an 379 * unusually long FITS keywords that cannot be represented by a standard 8-byte keyword. The HIERARCH formatted will 380 * take such string keywords and will format them according to its rules when writing them to FITS headers. 381 * 382 * @return the formatter to use for hierarch keys. 383 * 384 * @see #setHierarchFormater(IHierarchKeyFormatter) 385 */ 386 public static IHierarchKeyFormatter getHierarchFormater() { 387 return current().getHierarchKeyFormatter(); 388 } 389 390 /** 391 * Whether we can use HIERARCH style keywords. Such keywords are not part of the current FITS standard, although 392 * they constitute a recognised convention. Even if other programs may not process HIRARCH keywords themselves, 393 * there is generally no harm to putting them into FITS headers, since the convention is such that these keywords 394 * will be simply treated as comments by programs that do not recognise them. 395 * 396 * @return <code>true</code> if we are processing HIERARCH style keywords 397 * 398 * @see #setUseHierarch(boolean) 399 */ 400 public static boolean getUseHierarch() { 401 return current().isUseHierarch(); 402 } 403 404 /** 405 * whether ASCII tables should be used where feasible. 406 * 407 * @return <code>true</code> if we ASCII tables are allowed. 408 * 409 * @see #setUseAsciiTables(boolean) 410 */ 411 public static boolean getUseAsciiTables() { 412 return current().isUseAsciiTables(); 413 } 414 415 /** 416 * Checks whether we should check and validated ASCII strings that goe into FITS. FITS only allows ASCII characters 417 * between 0x20 and 0x7E in ASCII tables. 418 * 419 * @return Get the current status for string checking. 420 * 421 * @see #setCheckAsciiStrings(boolean) 422 */ 423 public static boolean getCheckAsciiStrings() { 424 return current().isCheckAsciiStrings(); 425 } 426 427 /** 428 * Whether we allow storing long string in the header, which do not fit into a single 80-byte header record. Such 429 * strings are then wrapped into multiple consecutive header records, OGIP 1.0 standard -- which is nart of FITS 430 * 4.0, and was a recognised convention before. 431 * 432 * @return <code>true</code> If long string support is enabled. 433 * 434 * @see #setLongStringsEnabled(boolean) 435 */ 436 public static boolean isLongStringsEnabled() { 437 return current().isLongStringsEnabled(); 438 } 439 440 /** 441 * @return whether to use only "=", instead of the standard "= " between the keyword and the value. 442 * 443 * @deprecated The FITS standard is very explicit that assignment must be "= " (equals followed by a blank space). 444 * If we allow skipping the space, it will result in a non-standard FITS, that is likely to break 445 * compatibility with other tools. 446 * 447 * @see #setSkipBlankAfterAssign(boolean) 448 */ 449 @Deprecated 450 public static boolean isSkipBlankAfterAssign() { 451 return current().isSkipBlankAfterAssign(); 452 } 453 454 /** 455 * . 456 * 457 * @deprecated (<i>for internal use</i>)/ Will reduce visibility in the future 458 * 459 * @return Given Header and data objects return the appropriate type of HDU. 460 * 461 * @param hdr the header, including a description of the data layout. 462 * @param d the type of data object 463 * @param <DataClass> the class of the data 464 * 465 * @throws FitsException if the operation failed 466 */ 467 @Deprecated 468 @SuppressWarnings("unchecked") 469 public static <DataClass extends Data> BasicHDU<DataClass> hduFactory(Header hdr, DataClass d) throws FitsException { 470 if (d == null) { 471 return (BasicHDU<DataClass>) new NullDataHDU(hdr); 472 } 473 if (d instanceof ImageData) { 474 return (BasicHDU<DataClass>) new ImageHDU(hdr, (ImageData) d); 475 } 476 if (d instanceof CompressedImageData) { 477 return (BasicHDU<DataClass>) new CompressedImageHDU(hdr, (CompressedImageData) d); 478 } 479 if (d instanceof RandomGroupsData) { 480 return (BasicHDU<DataClass>) new RandomGroupsHDU(hdr, (RandomGroupsData) d); 481 } 482 if (d instanceof AsciiTable) { 483 return (BasicHDU<DataClass>) new AsciiTableHDU(hdr, (AsciiTable) d); 484 } 485 if (d instanceof CompressedTableData) { 486 return (BasicHDU<DataClass>) new CompressedTableHDU(hdr, (CompressedTableData) d); 487 } 488 if (d instanceof BinaryTable) { 489 return (BasicHDU<DataClass>) new BinaryTableHDU(hdr, (BinaryTable) d); 490 } 491 if (d instanceof UndefinedData) { 492 return (BasicHDU<DataClass>) new UndefinedHDU(hdr, (UndefinedData) d); 493 } 494 return null; 495 } 496 497 /** 498 * Creates an HDU that wraps around the specified data object. The HDUs header will be created and populated with 499 * the essential description of the data. The following HDU types may be returned depending on the nature of the 500 * argument: 501 * <ul> 502 * <li>{@link NullDataHDU} -- if the argument is <code>null</code></li> 503 * <li>{@link ImageHDU} -- if the argument is a regular numerical array, such as a <code>double[]</code>, 504 * <code>float[][]</code>, or <code>short[][][]</code></li> 505 * <li>{@link BinaryTableHDU} -- the the argument is an <code>Object[rows][cols]</code> type array with a regular 506 * structure and supported column data types, provided that it cannot be represented by an ASCII table <b>OR</b> if 507 * {@link FitsFactory#getUseAsciiTables()} is <code>false</code></li> 508 * <li>{@link AsciiTableHDU} -- Like above, but only when the data can be represented by an ASCII table <b>AND</b> 509 * {@link FitsFactory#getUseAsciiTables()} is <code>true</code></li> 510 * </ul> 511 * 512 * @return An appropriate HDU to encapsulate the given Java data object 513 * 514 * @param o The object to be described. 515 * 516 * @throws FitsException if the parameter could not be converted to a HDU because the binary representation of 517 * the object is not known.. 518 * 519 * @deprecated Use {@link Fits#makeHDU(Object)} instead (this method may either be migrated to 520 * {@link Fits} entirely or else have visibility reduced to the package level). 521 */ 522 public static BasicHDU<?> hduFactory(Object o) throws FitsException { 523 Data d; 524 Header h; 525 526 if (o == null) { 527 return new NullDataHDU(); 528 } else if (o instanceof Header) { 529 h = (Header) o; 530 d = dataFactory(h); 531 } else if (ImageHDU.isData(o)) { 532 d = ImageHDU.encapsulate(o); 533 h = ImageHDU.manufactureHeader(d); 534 } else if (current().isUseAsciiTables() && AsciiTableHDU.isData(o)) { 535 d = AsciiTableHDU.encapsulate(o); 536 h = AsciiTableHDU.manufactureHeader(d); 537 } else if (BinaryTableHDU.isData(o)) { 538 d = BinaryTableHDU.encapsulate(o); 539 h = BinaryTableHDU.manufactureHeader(d); 540 } else { 541 throw new FitsException("This type of data is not supported for FITS representation"); 542 } 543 544 return hduFactory(h, d); 545 } 546 547 // CHECKSTYLE:OFF 548 /** 549 * @deprecated (<i>duplicate method for internal use</i>) Same as {@link #hduFactory(Header, Data)}, 550 * and will be removed in the future. 551 * 552 * @return Given Header and data objects return the appropriate type of HDU. 553 * 554 * @param hdr the header of the date 555 * @param d the data 556 * @param <DataClass> the class of the data 557 * 558 * @throws FitsException if the operation failed 559 */ 560 @Deprecated 561 public static <DataClass extends Data> BasicHDU<DataClass> HDUFactory(Header hdr, DataClass d) throws FitsException { 562 return hduFactory(hdr, d); 563 } 564 565 // CHECKSTYLE:ON 566 567 // CHECKSTYLE:OFF 568 /** 569 * @return Given an object, create the appropriate FITS header to describe it. 570 * 571 * @param o The object to be described. 572 * 573 * @throws FitsException if the parameter could not be converted to a hdu. 574 * 575 * @deprecated Use {@link Fits#makeHDU(Object)} instead (will removed in the future. Duplicate of 576 * {@link #hduFactory(Object)} 577 */ 578 @Deprecated 579 public static BasicHDU<?> HDUFactory(Object o) throws FitsException { 580 return hduFactory(o); 581 } 582 583 // CHECKSTYLE:ON 584 585 /** 586 * Restores all settings to their default values. 587 * 588 * @since 1.16 589 */ 590 public static void setDefaults() { 591 FitsSettings s = current(); 592 s.useExponentD = DEFAULT_USE_EXPONENT_D; 593 s.allowHeaderRepairs = DEFAULT_ALLOW_HEADER_REPAIRS; 594 s.allowTerminalJunk = DEFAULT_ALLOW_TERMINAL_JUNK; 595 s.checkAsciiStrings = DEFAULT_CHECK_ASCII_STRINGS; 596 s.longStringsEnabled = DEFAULT_LONG_STRINGS_ENABLED; 597 s.skipBlankAfterAssign = DEFAULT_SKIP_BLANK_AFTER_ASSIGN; 598 s.useAsciiTables = DEFAULT_USE_ASCII_TABLES; 599 s.useHierarch = DEFAULT_USE_HIERARCH; 600 s.useUnicodeChars = DEFAULT_USE_UNICODE_CHARS; 601 s.hierarchKeyFormatter = DEFAULT_HIERARCH_FORMATTER; 602 s.hierarchKeyFormatter.setCaseSensitive(DEFAULT_CASE_SENSITIVE_HIERARCH); 603 } 604 605 /** 606 * Sets whether 'D' may be used instead of 'E' to mark the exponent for a floating point value with precision beyond 607 * that of a 32-bit float. 608 * 609 * @param allowExponentD if <code>true</code> D will be used instead of E to indicate the exponent of a decimal with 610 * more precision than a 32-bit float. 611 * 612 * @since 1.16 613 * 614 * @see #isUseExponentD() 615 */ 616 public static void setUseExponentD(boolean allowExponentD) { 617 current().useExponentD = allowExponentD; 618 } 619 620 /** 621 * Do we allow junk after a valid FITS file? 622 * 623 * @param allowTerminalJunk value to set 624 * 625 * @see #getAllowTerminalJunk() 626 */ 627 public static void setAllowTerminalJunk(boolean allowTerminalJunk) { 628 current().allowTerminalJunk = allowTerminalJunk; 629 } 630 631 /** 632 * Do we allow automatic header repairs, like missing end quotes? 633 * 634 * @param allowHeaderRepairs value to set 635 * 636 * @see #isAllowHeaderRepairs() 637 */ 638 public static void setAllowHeaderRepairs(boolean allowHeaderRepairs) { 639 current().allowHeaderRepairs = allowHeaderRepairs; 640 } 641 642 /** 643 * Enable/Disable checking of strings values used in tables to ensure that they are within the range specified by 644 * the FITS standard. The standard only allows the values 0x20 - 0x7E with null bytes allowed in one limited 645 * context. Disabled by default. 646 * 647 * @param checkAsciiStrings value to set 648 * 649 * @see #getCheckAsciiStrings() 650 */ 651 public static void setCheckAsciiStrings(boolean checkAsciiStrings) { 652 current().checkAsciiStrings = checkAsciiStrings; 653 } 654 655 /** 656 * There is not a real standard how to write hierarch keys, default we use the one where every key is separated by a 657 * blank. If you want or need another format assing the formater here. 658 * 659 * @param formatter the hierarch key formatter. 660 */ 661 public static void setHierarchFormater(IHierarchKeyFormatter formatter) { 662 current().hierarchKeyFormatter = formatter; 663 } 664 665 /** 666 * Enable/Disable longstring support. 667 * 668 * @param longStringsEnabled value to set 669 * 670 * @see #isLongStringsEnabled() 671 */ 672 public static void setLongStringsEnabled(boolean longStringsEnabled) { 673 current().longStringsEnabled = longStringsEnabled; 674 } 675 676 /** 677 * If set to true the blank after the assign in the header cards in not written. The blank is stronly recommendet 678 * but in some cases it is important that it can be ommitted. 679 * 680 * @param skipBlankAfterAssign value to set 681 * 682 * @deprecated The FITS standard is very explicit that assignment must be "= " (equals followed 683 * by a blank space). It is also very specific that string values must have 684 * their opening quote in byte 11 (counted from 1). If we allow skipping the 685 * space, we will violate both standards in a way that is likely to break 686 * compatibility with other tools. 687 * 688 * @see #isSkipBlankAfterAssign() 689 */ 690 @Deprecated 691 public static void setSkipBlankAfterAssign(boolean skipBlankAfterAssign) { 692 current().skipBlankAfterAssign = skipBlankAfterAssign; 693 } 694 695 /** 696 * Indicate whether ASCII tables should be used where feasible. 697 * 698 * @param useAsciiTables value to set 699 */ 700 public static void setUseAsciiTables(boolean useAsciiTables) { 701 current().useAsciiTables = useAsciiTables; 702 } 703 704 /** 705 * Enable/Disable hierarchical keyword processing. 706 * 707 * @param useHierarch value to set 708 */ 709 public static void setUseHierarch(boolean useHierarch) { 710 current().useHierarch = useHierarch; 711 } 712 713 /** 714 * <p> 715 * Enable/Disable writing <code>char[]</code> arrays as <code>short[]</code> in FITS binary tables (with column type 716 * 'I'), instead of as standard FITS 1-byte ASCII characters (with column type 'A'). The old default of this library 717 * has been to use unicode, and that behavior remains the default — the same as setting the argument to 718 * <code>true</code>. On the flipside, setting it to <code>false</code> provides more convergence between the 719 * handling of <code>char[]</code> columns and the nearly identical <code>String</code> columns, which have already 720 * been restricted to ASCII before. 721 * </p> 722 * 723 * @param value <code>true</code> to write <code>char[]</code> arrays as if <code>short[]</code> with column type 724 * 'I' to binary tables (old behaviour, and hence default), or else <code>false</code> to write 725 * them as <code>byte[]</code> with column type 'A', the same as for <code>String</code> (preferred 726 * behaviour) 727 * 728 * @since 1.16 729 * 730 * @see #isUseUnicodeChars() 731 */ 732 public static void setUseUnicodeChars(boolean value) { 733 current().useUnicodeChars = value; 734 } 735 736 /** 737 * Returns the common thread pool that we use for processing FITS files. 738 * 739 * @return the thread pool for processing FITS files. 740 */ 741 public static ExecutorService threadPool() { 742 if (threadPool == null) { 743 initializeThreadPool(); 744 } 745 return threadPool; 746 } 747 748 /** 749 * Use thread local settings for the current thread instead of the global ones if the parameter is set to true, else 750 * use the shared global settings. 751 * 752 * @param useThreadSettings true if the thread should not share the global settings. 753 */ 754 public static void useThreadLocalSettings(boolean useThreadSettings) { 755 if (useThreadSettings) { 756 LOCAL_SETTINGS.set(GLOBAL_SETTINGS.copy()); 757 } else { 758 LOCAL_SETTINGS.remove(); 759 } 760 } 761 762 private static void initializeThreadPool() { 763 synchronized (GLOBAL_SETTINGS) { 764 if (threadPool == null) { 765 threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2, // 766 new ThreadFactory() { 767 private int counter = 1; 768 769 @Override 770 public Thread newThread(Runnable r) { 771 Thread thread = new Thread(r, "nom-tam-fits worker " + counter++); 772 thread.setDaemon(true); 773 return thread; 774 } 775 }); 776 } 777 } 778 } 779 780 /** 781 * Returns the current settings that guide how we read or produce FITS files. 782 * 783 * @return the current active settings for generating or interpreting FITS files. 784 */ 785 protected static FitsSettings current() { 786 FitsSettings settings = LOCAL_SETTINGS.get(); 787 if (settings == null) { 788 return GLOBAL_SETTINGS; 789 } 790 return settings; 791 } 792 793 private FitsFactory() { 794 } 795 }