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  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
54  
55  /**
56   * ASCII table header/data unit. ASCII table HDUs were desgined for human readability, e.g. on a console, without any
57   * special tools. However, they are far less flexible or compact than {@link BinaryTableHDU}. As such, users are
58   * generally discouraged from using this type of HDU to encapsulate FITS table data.
59   * {@link FitsFactory#setUseAsciiTables(boolean)} can be toggled to adjust whether {@link Fits#makeHDU(Object)} or
60   * similar methods should construct ASCII tables when possible. (The default setting is to produce binary tables
61   * always.)
62   * 
63   * @see AsciiTable
64   * @see BinaryTableHDU
65   */
66  public class AsciiTableHDU extends TableHDU<AsciiTable> {
67  
68      /**
69       * The standard column stems for an ASCII table. Note that TBCOL is not included here -- it needs to be handled
70       * specially since it does not simply shift.
71       */
72      private static final IFitsHeader[] KEY_STEMS = {TFORMn, TZEROn, TNULLn, TTYPEn, TUNITn};
73  
74      /**
75       * Create an ASCII table header/data unit.
76       * 
77       * @deprecated   (<i>for internal use</i>) Its visibility should be reduced to package level in the future.
78       *
79       * @param      h the template specifying the ASCII table.
80       * @param      d the FITS data structure containing the table data.
81       */
82      public AsciiTableHDU(Header h, AsciiTable d) {
83          super(h, d);
84      }
85  
86      @Override
87      protected final String getCanonicalXtension() {
88          return XTENSION_ASCIITABLE;
89      }
90  
91      /**
92       * @deprecated               (<i>for internal use</i>) Use {@link AsciiTable#fromColumnMajor(Object[])} instead.
93       *                               Will reduce visibility in the future
94       *
95       * @return                   a ASCII table data structure from an array of objects representing the columns.
96       *
97       * @param      o             the array of object to create the ASCII table
98       *
99       * @throws     FitsException if the table could not be created.
100      */
101     @Deprecated
102     public static AsciiTable encapsulate(Object o) throws FitsException {
103         return AsciiTable.fromColumnMajor((Object[]) o);
104     }
105 
106     /**
107      * @deprecated   (<i>for internal use</i>) Will reduce visibility in the future
108      *
109      * @return       true if this data is usable as an ASCII table.
110      *
111      * @param      o object representing the data
112      */
113     @SuppressFBWarnings(value = "HSM_HIDING_METHOD", justification = "deprecated existing method, kept for compatibility")
114     @Deprecated
115     public static boolean isData(Object o) {
116 
117         if (o instanceof Object[]) {
118             for (Object element : (Object[]) o) {
119                 if (!(element instanceof String[]) && //
120                         !(element instanceof int[]) && //
121                         !(element instanceof long[]) && //
122                         !(element instanceof float[]) && //
123                         !(element instanceof double[])) {
124                     return false;
125                 }
126             }
127             return true;
128         }
129 
130         return false;
131     }
132 
133     /**
134      * Check that this is a valid ascii table header.
135      *
136      * @deprecated        (<i>for internal use</i>) Will reduce visibility in the future
137      *
138      * @param      header to validate.
139      *
140      * @return            <CODE>true</CODE> if this is an ascii table header.
141      */
142     @SuppressFBWarnings(value = "HSM_HIDING_METHOD", justification = "deprecated existing method, kept for compatibility")
143     @Deprecated
144     public static boolean isHeader(Header header) {
145         String xtension = header.getStringValue(XTENSION);
146         xtension = xtension == null ? "" : xtension.trim();
147         return XTENSION_ASCIITABLE.equals(xtension);
148     }
149 
150     /**
151      * Prepares a data object into which the actual data can be read from an input subsequently or at a later time.
152      *
153      * @deprecated               (<i>for internal use</i>) Will reduce visibility in the future
154      *
155      * @param      hdr           The FITS header that describes the data
156      *
157      * @return                   A data object that support reading content from a stream.
158      *
159      * @throws     FitsException if the data could not be prepared to prescriotion.
160      */
161     @Deprecated
162     public static AsciiTable manufactureData(Header hdr) throws FitsException {
163         return new AsciiTable(hdr);
164     }
165 
166     /**
167      * @deprecated               (<i>for internal use</i>) Will reduce visibility in the future
168      *
169      * @return                   a created header to match the input data.
170      *
171      * @param      d             data to create a header for
172      *
173      * @throws     FitsException if the header could not b e created
174      */
175     @Deprecated
176     public static Header manufactureHeader(Data d) throws FitsException {
177         Header hdr = new Header();
178         d.fillHeader(hdr);
179         hdr.iterator();
180         return hdr;
181     }
182 
183     @Override
184     public void setColumnName(int index, String name, String comment)
185             throws IndexOutOfBoundsException, HeaderCardException {
186         super.setColumnName(index, name, comment);
187         myData.setColumnName(index, name);
188     }
189 
190     @SuppressWarnings("deprecation")
191     @Override
192     public int addColumn(Object newCol) throws FitsException {
193         Standard.context(AsciiTable.class);
194         myData.addColumn(newCol);
195         // Move the iterator to point after all the data describing
196         // the previous column.
197 
198         Cursor<String, HeaderCard> iter = myHeader.positionAfterIndex(TBCOLn, myData.getNCols());
199 
200         int rowlen = myData.addColInfo(getNCols() - 1, iter);
201         int oldRowlen = myHeader.getIntValue(NAXIS1);
202         myHeader.setNaxis(1, rowlen + oldRowlen);
203 
204         super.addColumn(newCol);
205         Standard.context(null);
206         return getNCols();
207     }
208 
209     @Override
210     protected IFitsHeader[] columnKeyStems() {
211         return KEY_STEMS;
212     }
213 
214     @Override
215     public void info(PrintStream stream) {
216         stream.println("ASCII Table:");
217         stream.println("  Header:");
218         stream.println("    Number of fields:" + myHeader.getIntValue(TFIELDS));
219         stream.println("    Number of rows:  " + myHeader.getIntValue(NAXIS2));
220         stream.println("    Length of row:   " + myHeader.getIntValue(NAXIS1));
221         stream.println("  Data:");
222         Object[] data = (Object[]) getKernel();
223         for (int i = 0; i < getNCols(); i++) {
224             stream.println("      " + i + ":" + ArrayFuncs.arrayDescription(data[i]));
225         }
226     }
227 
228     /**
229      * Checks if a table entry is <code>null</code>
230      * 
231      * @param  row row index of the element
232      * @param  col column index of the element
233      *
234      * @return     <code>true</code> if the specified element is <code>null</code>
235      * 
236      * @see        #setNull(int, int, boolean)
237      * @see        AsciiTable#isNull(int, int)
238      */
239     public boolean isNull(int row, int col) {
240         return myData.isNull(row, col);
241     }
242 
243     /**
244      * Mark an entry as null.
245      *
246      * @param row  row index of the element
247      * @param col  column index of the element
248      * @param flag set to null or not
249      * 
250      * @see        #isNull(int, int)
251      * @see        AsciiTable#setNull(int, int, boolean)
252      */
253     public void setNull(int row, int col, boolean flag) {
254 
255         if (flag) {
256             String nullStr = myHeader.getStringValue(TNULLn.n(col + 1));
257             if (nullStr == null) {
258                 setNullString(col, "NULL");
259             }
260         }
261         myData.setNull(row, col, flag);
262     }
263 
264     /**
265      * Set the null string for a column.
266      *
267      * @param  col                      the column index
268      * @param  newNull                  the String representing null
269      *
270      * @throws IllegalArgumentException if the string argument contains characters that are not allowed in FITS headers.
271      *                                      That is if it contains characters outside the range of 0x20 thru 0x7E.
272      */
273     public void setNullString(int col, String newNull) throws IllegalArgumentException {
274         myHeader.positionAfterIndex(TBCOLn, col + 1);
275         HeaderCard card = HeaderCard.create(TNULLn.n(col + 1), newNull);
276         myHeader.deleteKey(card.getKey());
277         myHeader.addLine(card);
278         myData.setNullString(col, newNull);
279     }
280 
281 }