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      @Deprecated
83      public AsciiTableHDU(Header h, AsciiTable d) {
84          super(h, d);
85      }
86  
87      @Override
88      protected final String getCanonicalXtension() {
89          return XTENSION_ASCIITABLE;
90      }
91  
92      /**
93       * @deprecated               (<i>for internal use</i>) Use {@link AsciiTable#fromColumnMajor(Object[])} instead.
94       *                               Will reduce visibility in the future
95       *
96       * @return                   a ASCII table data structure from an array of objects representing the columns.
97       *
98       * @param      o             the array of object to create the ASCII table
99       *
100      * @throws     FitsException if the table could not be created.
101      */
102     @Deprecated
103     public static AsciiTable encapsulate(Object o) throws FitsException {
104         return AsciiTable.fromColumnMajor((Object[]) o);
105     }
106 
107     /**
108      * @deprecated   (<i>for internal use</i>) Will reduce visibility in the future
109      *
110      * @return       true if this data is usable as an ASCII table.
111      *
112      * @param      o object representing the data
113      */
114     @SuppressFBWarnings(value = "HSM_HIDING_METHOD", justification = "deprecated existing method, kept for compatibility")
115     @Deprecated
116     public static boolean isData(Object o) {
117 
118         if (o instanceof Object[]) {
119             for (Object element : (Object[]) o) {
120                 if (!(element instanceof String[]) && //
121                         !(element instanceof int[]) && //
122                         !(element instanceof long[]) && //
123                         !(element instanceof float[]) && //
124                         !(element instanceof double[])) {
125                     return false;
126                 }
127             }
128             return true;
129         }
130 
131         return false;
132     }
133 
134     /**
135      * Check that this is a valid ascii table header.
136      *
137      * @deprecated        (<i>for internal use</i>) Will reduce visibility in the future
138      *
139      * @param      header to validate.
140      *
141      * @return            <CODE>true</CODE> if this is an ascii table header.
142      */
143     @SuppressFBWarnings(value = "HSM_HIDING_METHOD", justification = "deprecated existing method, kept for compatibility")
144     @Deprecated
145     public static boolean isHeader(Header header) {
146         String xtension = header.getStringValue(XTENSION);
147         xtension = xtension == null ? "" : xtension.trim();
148         return XTENSION_ASCIITABLE.equals(xtension);
149     }
150 
151     /**
152      * Prepares a data object into which the actual data can be read from an input subsequently or at a later time.
153      *
154      * @deprecated               (<i>for internal use</i>) Will reduce visibility in the future
155      *
156      * @param      hdr           The FITS header that describes the data
157      *
158      * @return                   A data object that support reading content from a stream.
159      *
160      * @throws     FitsException if the data could not be prepared to prescriotion.
161      */
162     @Deprecated
163     public static AsciiTable manufactureData(Header hdr) throws FitsException {
164         return new AsciiTable(hdr);
165     }
166 
167     /**
168      * @deprecated               (<i>for internal use</i>) Will reduce visibility in the future
169      *
170      * @return                   a created header to match the input data.
171      *
172      * @param      d             data to create a header for
173      *
174      * @throws     FitsException if the header could not b e created
175      */
176     @Deprecated
177     public static Header manufactureHeader(Data d) throws FitsException {
178         Header hdr = new Header();
179         d.fillHeader(hdr);
180         hdr.iterator();
181         return hdr;
182     }
183 
184     @Override
185     public void setColumnName(int index, String name, String comment)
186             throws IndexOutOfBoundsException, HeaderCardException {
187         super.setColumnName(index, name, comment);
188         myData.setColumnName(index, name);
189     }
190 
191     @SuppressWarnings("deprecation")
192     @Override
193     public int addColumn(Object newCol) throws FitsException {
194         Standard.context(AsciiTable.class);
195         myData.addColumn(newCol);
196         // Move the iterator to point after all the data describing
197         // the previous column.
198 
199         Cursor<String, HeaderCard> iter = myHeader.positionAfterIndex(TBCOLn, myData.getNCols());
200 
201         int rowlen = myData.addColInfo(getNCols() - 1, iter);
202         int oldRowlen = myHeader.getIntValue(NAXIS1);
203         myHeader.setNaxis(1, rowlen + oldRowlen);
204 
205         super.addColumn(newCol);
206         Standard.context(null);
207         return getNCols();
208     }
209 
210     @Override
211     protected IFitsHeader[] columnKeyStems() {
212         return KEY_STEMS;
213     }
214 
215     @Override
216     public void info(PrintStream stream) {
217         stream.println("ASCII Table:");
218         stream.println("  Header:");
219         stream.println("    Number of fields:" + myHeader.getIntValue(TFIELDS));
220         stream.println("    Number of rows:  " + myHeader.getIntValue(NAXIS2));
221         stream.println("    Length of row:   " + myHeader.getIntValue(NAXIS1));
222         stream.println("  Data:");
223         Object[] data = (Object[]) getKernel();
224         for (int i = 0; i < getNCols(); i++) {
225             stream.println("      " + i + ":" + ArrayFuncs.arrayDescription(data[i]));
226         }
227     }
228 
229     /**
230      * Checks if a table entry is <code>null</code>
231      * 
232      * @param  row row index of the element
233      * @param  col column index of the element
234      *
235      * @return     <code>true</code> if the specified element is <code>null</code>
236      * 
237      * @see        #setNull(int, int, boolean)
238      * @see        AsciiTable#isNull(int, int)
239      */
240     public boolean isNull(int row, int col) {
241         return myData.isNull(row, col);
242     }
243 
244     /**
245      * Mark an entry as null.
246      *
247      * @param row  row index of the element
248      * @param col  column index of the element
249      * @param flag set to null or not
250      * 
251      * @see        #isNull(int, int)
252      * @see        AsciiTable#setNull(int, int, boolean)
253      */
254     public void setNull(int row, int col, boolean flag) {
255 
256         if (flag) {
257             String nullStr = myHeader.getStringValue(TNULLn.n(col + 1));
258             if (nullStr == null) {
259                 setNullString(col, "NULL");
260             }
261         }
262         myData.setNull(row, col, flag);
263     }
264 
265     /**
266      * Set the null string for a column.
267      *
268      * @param  col                      the column index
269      * @param  newNull                  the String representing null
270      *
271      * @throws IllegalArgumentException if the string argument contains characters that are not allowed in FITS headers.
272      *                                      That is if it contains characters outside the range of 0x20 thru 0x7E.
273      */
274     public void setNullString(int col, String newNull) throws IllegalArgumentException {
275         myHeader.positionAfterIndex(TBCOLn, col + 1);
276         HeaderCard card = HeaderCard.create(TNULLn.n(col + 1), newNull);
277         myHeader.deleteKey(card.getKey());
278         myHeader.addLine(card);
279         myData.setNullString(col, newNull);
280     }
281 
282 }