View Javadoc
1   package nom.tam.fits;
2   
3   import java.io.PrintStream;
4   
5   import nom.tam.fits.header.IFitsHeader;
6   import nom.tam.fits.header.Standard;
7   import nom.tam.util.ArrayFuncs;
8   import nom.tam.util.Cursor;
9   
10  /*
11   * #%L
12   * nom.tam FITS library
13   * %%
14   * Copyright (C) 2004 - 2024 nom-tam-fits
15   * %%
16   * This is free and unencumbered software released into the public domain.
17   *
18   * Anyone is free to copy, modify, publish, use, compile, sell, or
19   * distribute this software, either in source code form or as a compiled
20   * binary, for any purpose, commercial or non-commercial, and by any
21   * means.
22   *
23   * In jurisdictions that recognize copyright laws, the author or authors
24   * of this software dedicate any and all copyright interest in the
25   * software to the public domain. We make this dedication for the benefit
26   * of the public at large and to the detriment of our heirs and
27   * successors. We intend this dedication to be an overt act of
28   * relinquishment in perpetuity of all present and future rights to this
29   * software under copyright law.
30   *
31   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
34   * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
35   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
36   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
37   * OTHER DEALINGS IN THE SOFTWARE.
38   * #L%
39   */
40  
41  import static nom.tam.fits.header.Standard.NAXIS1;
42  import static nom.tam.fits.header.Standard.NAXIS2;
43  import static nom.tam.fits.header.Standard.TBCOLn;
44  import static nom.tam.fits.header.Standard.TFIELDS;
45  import static nom.tam.fits.header.Standard.TFORMn;
46  import static nom.tam.fits.header.Standard.TNULLn;
47  import static nom.tam.fits.header.Standard.TTYPEn;
48  import static nom.tam.fits.header.Standard.TUNITn;
49  import static nom.tam.fits.header.Standard.TZEROn;
50  import static nom.tam.fits.header.Standard.XTENSION;
51  import static nom.tam.fits.header.Standard.XTENSION_ASCIITABLE;
52  
53  /**
54   * ASCII table header/data unit. ASCII table HDUs were desgined for human readability, e.g. on a console, without any
55   * special tools. However, they are far less flexible or compact than {@link BinaryTableHDU}. As such, users are
56   * generally discouraged from using this type of HDU to encapsulate FITS table data.
57   * {@link FitsFactory#setUseAsciiTables(boolean)} can be toggled to adjust whether {@link Fits#makeHDU(Object)} or
58   * similar methods should construct ASCII tables when possible. (The default setting is to produce binary tables
59   * always.)
60   * 
61   * @see AsciiTable
62   * @see BinaryTableHDU
63   */
64  public class AsciiTableHDU extends TableHDU<AsciiTable> {
65  
66      /**
67       * The standard column stems for an ASCII table. Note that TBCOL is not included here -- it needs to be handled
68       * specially since it does not simply shift.
69       */
70      private static final IFitsHeader[] KEY_STEMS = {TFORMn, TZEROn, TNULLn, TTYPEn, TUNITn};
71  
72      /**
73       * Create an ASCII table header/data unit.
74       * 
75       * @deprecated   (<i>for internal use</i>) Its visibility should be reduced to package level in the future.
76       *
77       * @param      h the template specifying the ASCII table.
78       * @param      d the FITS data structure containing the table data.
79       */
80      public AsciiTableHDU(Header h, AsciiTable d) {
81          super(h, d);
82      }
83  
84      @Override
85      protected final String getCanonicalXtension() {
86          return XTENSION_ASCIITABLE;
87      }
88  
89      /**
90       * @deprecated               (<i>for internal use</i>) Use {@link AsciiTable#fromColumnMajor(Object[])} instead.
91       *                               Will reduce visibility in the future
92       *
93       * @return                   a ASCII table data structure from an array of objects representing the columns.
94       *
95       * @param      o             the array of object to create the ASCII table
96       *
97       * @throws     FitsException if the table could not be created.
98       */
99      @Deprecated
100     public static AsciiTable encapsulate(Object o) throws FitsException {
101         return AsciiTable.fromColumnMajor((Object[]) o);
102     }
103 
104     /**
105      * @deprecated   (<i>for internal use</i>) Will reduce visibility in the future
106      *
107      * @return       true if this data is usable as an ASCII table.
108      *
109      * @param      o object representing the data
110      */
111     @Deprecated
112     public static boolean isData(Object o) {
113 
114         if (o instanceof Object[]) {
115             for (Object element : (Object[]) o) {
116                 if (!(element instanceof String[]) && //
117                         !(element instanceof int[]) && //
118                         !(element instanceof long[]) && //
119                         !(element instanceof float[]) && //
120                         !(element instanceof double[])) {
121                     return false;
122                 }
123             }
124             return true;
125         }
126 
127         return false;
128     }
129 
130     /**
131      * Check that this is a valid ascii table header.
132      *
133      * @deprecated        (<i>for internal use</i>) Will reduce visibility in the future
134      *
135      * @param      header to validate.
136      *
137      * @return            <CODE>true</CODE> if this is an ascii table header.
138      */
139     @Deprecated
140     public static boolean isHeader(Header header) {
141         String xtension = header.getStringValue(XTENSION);
142         xtension = xtension == null ? "" : xtension.trim();
143         return XTENSION_ASCIITABLE.equals(xtension);
144     }
145 
146     /**
147      * Prepares a data object into which the actual data can be read from an input subsequently or at a later time.
148      *
149      * @deprecated               (<i>for internal use</i>) Will reduce visibility in the future
150      *
151      * @param      hdr           The FITS header that describes the data
152      *
153      * @return                   A data object that support reading content from a stream.
154      *
155      * @throws     FitsException if the data could not be prepared to prescriotion.
156      */
157     @Deprecated
158     public static AsciiTable manufactureData(Header hdr) throws FitsException {
159         return new AsciiTable(hdr);
160     }
161 
162     /**
163      * @deprecated               (<i>for internal use</i>) Will reduce visibility in the future
164      *
165      * @return                   a created header to match the input data.
166      *
167      * @param      d             data to create a header for
168      *
169      * @throws     FitsException if the header could not b e created
170      */
171     @Deprecated
172     public static Header manufactureHeader(Data d) throws FitsException {
173         Header hdr = new Header();
174         d.fillHeader(hdr);
175         hdr.iterator();
176         return hdr;
177     }
178 
179     @Override
180     public void setColumnName(int index, String name, String comment)
181             throws IndexOutOfBoundsException, HeaderCardException {
182         super.setColumnName(index, name, comment);
183         myData.setColumnName(index, name);
184     }
185 
186     @SuppressWarnings("deprecation")
187     @Override
188     public int addColumn(Object newCol) throws FitsException {
189         Standard.context(AsciiTable.class);
190         myData.addColumn(newCol);
191         // Move the iterator to point after all the data describing
192         // the previous column.
193 
194         Cursor<String, HeaderCard> iter = myHeader.positionAfterIndex(TBCOLn, myData.getNCols());
195 
196         int rowlen = myData.addColInfo(getNCols() - 1, iter);
197         int oldRowlen = myHeader.getIntValue(NAXIS1);
198         myHeader.setNaxis(1, rowlen + oldRowlen);
199 
200         super.addColumn(newCol);
201         Standard.context(null);
202         return getNCols();
203     }
204 
205     @Override
206     protected IFitsHeader[] columnKeyStems() {
207         return KEY_STEMS;
208     }
209 
210     @Override
211     public void info(PrintStream stream) {
212         stream.println("ASCII Table:");
213         stream.println("  Header:");
214         stream.println("    Number of fields:" + myHeader.getIntValue(TFIELDS));
215         stream.println("    Number of rows:  " + myHeader.getIntValue(NAXIS2));
216         stream.println("    Length of row:   " + myHeader.getIntValue(NAXIS1));
217         stream.println("  Data:");
218         Object[] data = (Object[]) getKernel();
219         for (int i = 0; i < getNCols(); i++) {
220             stream.println("      " + i + ":" + ArrayFuncs.arrayDescription(data[i]));
221         }
222     }
223 
224     /**
225      * Checks if a table entry is <code>null</code>
226      * 
227      * @param  row row index of the element
228      * @param  col column index of the element
229      *
230      * @return     <code>true</code> if the specified element is <code>null</code>
231      * 
232      * @see        #setNull(int, int, boolean)
233      * @see        AsciiTable#isNull(int, int)
234      */
235     public boolean isNull(int row, int col) {
236         return myData.isNull(row, col);
237     }
238 
239     /**
240      * Mark an entry as null.
241      *
242      * @param row  row index of the element
243      * @param col  column index of the element
244      * @param flag set to null or not
245      * 
246      * @see        #isNull(int, int)
247      * @see        AsciiTable#setNull(int, int, boolean)
248      */
249     public void setNull(int row, int col, boolean flag) {
250 
251         if (flag) {
252             String nullStr = myHeader.getStringValue(TNULLn.n(col + 1));
253             if (nullStr == null) {
254                 setNullString(col, "NULL");
255             }
256         }
257         myData.setNull(row, col, flag);
258     }
259 
260     /**
261      * Set the null string for a column.
262      *
263      * @param  col                      the column index
264      * @param  newNull                  the String representing null
265      *
266      * @throws IllegalArgumentException if the string argument contains characters that are not allowed in FITS headers.
267      *                                      That is if it contains characters outside the range of 0x20 thru 0x7E.
268      */
269     public void setNullString(int col, String newNull) throws IllegalArgumentException {
270         myHeader.positionAfterIndex(TBCOLn, col + 1);
271         HeaderCard card = HeaderCard.create(TNULLn.n(col + 1), newNull);
272         myHeader.deleteKey(card.getKey());
273         myHeader.addLine(card);
274         myData.setNullString(col, newNull);
275     }
276 
277 }