Bug Summary

File:src/fits/GFitsTable.cpp
Location:line 1035, column 21
Description:Array access (from variable 'ttype') results in a null pointer dereference

Annotated Source Code

1/***************************************************************************
2 * GFitsTable.cpp - FITS table base class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2008-2013 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * *
20 ***************************************************************************/
21/**
22 * @file GFitsTable.cpp
23 * @brief FITS table abstract base class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H1
29#include <config.h>
30#endif
31#include <cstring>
32#include <iostream>
33#include <vector>
34#include <cstdio>
35#include <cstdlib>
36#include "GException.hpp"
37#include "GTools.hpp"
38#include "GFitsCfitsio.hpp"
39#include "GFits.hpp"
40#include "GFitsTable.hpp"
41#include "GFitsTableBitCol.hpp"
42#include "GFitsTableByteCol.hpp"
43#include "GFitsTableBoolCol.hpp"
44#include "GFitsTableStringCol.hpp"
45#include "GFitsTableUShortCol.hpp"
46#include "GFitsTableShortCol.hpp"
47#include "GFitsTableULongCol.hpp"
48#include "GFitsTableLongCol.hpp"
49#include "GFitsTableLongLongCol.hpp"
50#include "GFitsTableFloatCol.hpp"
51#include "GFitsTableDoubleCol.hpp"
52#include "GFitsTableCFloatCol.hpp"
53#include "GFitsTableCDoubleCol.hpp"
54
55/* __ Method name definitions ____________________________________________ */
56#define G_ACCESS1"GFitsTable::operator[](int&)" "GFitsTable::operator[](int&)"
57#define G_ACCESS2"GFitsTable::operator[](std::string&)" "GFitsTable::operator[](std::string&)"
58#define G_SET1"GFitsTable::set(int&, GFitsTableCol&)" "GFitsTable::set(int&, GFitsTableCol&)"
59#define G_SET2"GFitsTable::set(std::string&, GFitsTableCol&)" "GFitsTable::set(std::string&, GFitsTableCol&)"
60#define G_INSERT1"GFitsTable::insert(int, GFitsTableCol&)" "GFitsTable::insert(int, GFitsTableCol&)"
61#define G_INSERT2"GFitsTable::insert(std::string&, GFitsTableCol&)" "GFitsTable::insert(std::string&, GFitsTableCol&)"
62#define G_INSERT_ROWS"GFitsTable::insert_rows(int&, int&)" "GFitsTable::insert_rows(int&, int&)"
63#define G_REMOVE_ROWS"GFitsTable::remove_rows(int&, int&)" "GFitsTable::remove_rows(int&, int&)"
64#define G_DATA_OPEN"GFitsTable::data_open(void*)" "GFitsTable::data_open(void*)"
65#define G_DATA_SAVE"GFitsTable::data_save()" "GFitsTable::data_save()"
66#define G_GET_TFORM"GFitsTable::get_tform(int&)" "GFitsTable::get_tform(int&)"
67
68/* __ Macros _____________________________________________________________ */
69
70/* __ Coding definitions _________________________________________________ */
71
72/* __ Debug definitions __________________________________________________ */
73//#define G_DEBUG_SAVE //!< Debug data_save() method
74
75
76/*==========================================================================
77 = =
78 = Constructors/destructors =
79 = =
80 ==========================================================================*/
81
82/***********************************************************************//**
83 * @brief Void constructor
84 *
85 * Construct void instance.
86 ***************************************************************************/
87GFitsTable::GFitsTable(void) : GFitsHDU()
88{
89 // Initialise class members for clean destruction
90 init_members();
91
92 // Return
93 return;
94}
95
96
97/***********************************************************************//**
98 * @brief Table constructor
99 *
100 * @param[in] nrows Number of rows in table.
101 *
102 * Construct instance for a specified number of table rows.
103 ***************************************************************************/
104GFitsTable::GFitsTable(const int& nrows) : GFitsHDU()
105{
106 // Initialise class members for clean destruction
107 init_members();
108
109 // Store numnber of rows
110 m_rows = nrows;
111
112 // Return
113 return;
114}
115
116
117/***********************************************************************//**
118 * @brief Copy constructor
119 *
120 * @param[in] table Table.
121 ***************************************************************************/
122GFitsTable::GFitsTable(const GFitsTable& table) : GFitsHDU(table)
123{
124 // Initialise class members for clean destruction
125 init_members();
126
127 // Copy members
128 copy_members(table);
129
130 // Return
131 return;
132}
133
134
135/***********************************************************************//**
136 * @brief Destructor
137 ***************************************************************************/
138GFitsTable::~GFitsTable(void)
139{
140 // Free members
141 free_members();
142
143 // Return
144 return;
145}
146
147
148/*==========================================================================
149 = =
150 = Operators =
151 = =
152 ==========================================================================*/
153
154/***********************************************************************//**
155 * @brief Assignment operator
156 *
157 * @param[in] table Table.
158 * @return Table.
159 ***************************************************************************/
160GFitsTable& GFitsTable::operator=(const GFitsTable& table)
161{
162 // Execute only if object is not identical
163 if (this != &table) {
164
165 // Copy base class members
166 this->GFitsHDU::operator=(table);
167
168 // Free members
169 free_members();
170
171 // Initialise private members for clean destruction
172 init_members();
173
174 // Copy members
175 copy_members(table);
176
177 } // endif: object was not identical
178
179 // Return this object
180 return *this;
181}
182
183
184/***********************************************************************//**
185 * @brief Returns pointer to table column
186 *
187 * @param[in] colnum Column number [0,...,ncols()-1].
188 * @return Table column pointer.
189 *
190 * @exception GException::fits_no_data
191 * No data found in table.
192 * @exception GException::out_of_range
193 * Column number is out of range.
194 ***************************************************************************/
195GFitsTableCol* GFitsTable::operator[](const int& colnum)
196{
197 // If there is no data then throw an exception
198 if (m_columns == NULL__null) {
199 throw GException::fits_no_data(G_ACCESS1"GFitsTable::operator[](int&)", "No columns in table.");
200 }
201
202 // Compile option: raise exception if column number is out of range
203 #if defined(G_RANGE_CHECK1)
204 if (colnum < 0 || colnum >= m_cols) {
205 throw GException::out_of_range(G_ACCESS1"GFitsTable::operator[](int&)", colnum, 0, m_cols-1);
206 }
207 #endif
208
209 // Get column pointer
210 GFitsTableCol* ptr = m_columns[colnum];
211 if (ptr == NULL__null) {
212 throw GException::fits_no_data(G_ACCESS1"GFitsTable::operator[](int&)", "No data for this column.");
213 }
214
215 // Return pointer
216 return ptr;
217}
218
219
220/***********************************************************************//**
221 * @brief Returns pointer to table column (const version)
222 *
223 * @param[in] colnum Column number [0,...,ncols()-1].
224 * @return Table column pointer.
225 *
226 * @exception GException::fits_no_data
227 * No data found in table.
228 * @exception GException::out_of_range
229 * Column number is out of range.
230 ***************************************************************************/
231const GFitsTableCol* GFitsTable::operator[](const int& colnum) const
232{
233 // If there is no data then throw an exception
234 if (m_columns == NULL__null) {
235 throw GException::fits_no_data(G_ACCESS1"GFitsTable::operator[](int&)", "No columns in table.");
236 }
237
238 // Compile option: raise exception if column number is out of range
239 #if defined(G_RANGE_CHECK1)
240 if (colnum < 0 || colnum >= m_cols) {
241 throw GException::out_of_range(G_ACCESS1"GFitsTable::operator[](int&)", colnum, 0, m_cols-1);
242 }
243 #endif
244
245 // Get column pointer
246 const GFitsTableCol* ptr = m_columns[colnum];
247 if (ptr == NULL__null) {
248 throw GException::fits_no_data(G_ACCESS1"GFitsTable::operator[](int&)", "No data for this column.");
249 }
250
251 // Return pointer
252 return ptr;
253}
254
255
256/***********************************************************************//**
257 * @brief Returns pointer to table column
258 *
259 * @param[in] colname Column name.
260 * @return Table column pointer.
261 *
262 * @exception GException::fits_no_data
263 * No data found in table.
264 * @exception GException::fits_column_not_found
265 * Column name not found.
266 ***************************************************************************/
267GFitsTableCol* GFitsTable::operator[](const std::string& colname)
268{
269 // If there is no data then throw an exception
270 if (m_columns == NULL__null) {
271 throw GException::fits_no_data(G_ACCESS2"GFitsTable::operator[](std::string&)", "No columns in table.");
272 }
273
274 // Get column pointer
275 GFitsTableCol* ptr = ptr_column(colname);
276
277 // If column has not been found throw an exception
278 if (ptr == NULL__null) {
279 throw GException::fits_column_not_found(G_ACCESS2"GFitsTable::operator[](std::string&)", colname);
280 }
281
282 // Return pointer
283 return ptr;
284}
285
286
287/***********************************************************************//**
288 * @brief Returns pointer to table column (const version)
289 *
290 * @param[in] colname Column name.
291 * @return Table column pointer.
292 *
293 * @exception GException::fits_no_data
294 * No data found in table.
295 * @exception GException::fits_column_not_found
296 * Column name not found.
297 ***************************************************************************/
298const GFitsTableCol* GFitsTable::operator[](const std::string& colname) const
299{
300 // If there is no data then throw an exception
301 if (m_columns == NULL__null) {
302 throw GException::fits_no_data(G_ACCESS2"GFitsTable::operator[](std::string&)", "No columns in table.");
303 }
304
305 // Get column pointer
306 GFitsTableCol* ptr = ptr_column(colname);
307
308 // If column has not been found throw an exception
309 if (ptr == NULL__null) {
310 throw GException::fits_column_not_found(G_ACCESS2"GFitsTable::operator[](std::string&)", colname);
311 }
312
313 // Return pointer
314 return ptr;
315}
316
317
318/*==========================================================================
319 = =
320 = Public methods =
321 = =
322 ==========================================================================*/
323
324/***********************************************************************//**
325 * @brief Set column
326 *
327 * @param[in] colnum Column number [0,...,ncols()-1].
328 * @param[in] column Table column.
329 * @return Pointer to table column that has been set.
330 *
331 * Sets the column of a table by making a deep copy of the @p column
332 * provided.
333 ***************************************************************************/
334GFitsTableCol* GFitsTable::set(const int& colnum, const GFitsTableCol& column)
335{
336 // Check if column number is valid
337 if (colnum < 0 || colnum >= ncols()) {
338 throw GException::out_of_range(G_SET1"GFitsTable::set(int&, GFitsTableCol&)", "Column number", colnum, ncols());
339 }
340
341 // Free existing column
342 if (m_columns[colnum] != NULL__null) delete m_columns[colnum];
343
344 // Clone column
345 m_columns[colnum] = column.clone();
346
347 // Return pointer to column
348 return m_columns[colnum];
349}
350
351
352/***********************************************************************//**
353 * @brief Set column
354 *
355 * @param[in] colname Column name.
356 * @param[in] column Table column.
357 * @return Pointer to table column that has been set.
358 *
359 * Sets the column of a table by making a deep copy of the @p column
360 * provided.
361 ***************************************************************************/
362GFitsTableCol* GFitsTable::set(const std::string& colname,
363 const GFitsTableCol& column)
364{
365 // Get column number
366 int colnum = this->colnum(colname);
367
368 // If column has not been found throw an exception
369 if (colnum < 0) {
370 throw GException::fits_column_not_found(G_SET2"GFitsTable::set(std::string&, GFitsTableCol&)", colname);
371 }
372
373 // Set column and return pointer to column
374 return (set(colnum, column));
375}
376
377
378
379/***********************************************************************//**
380 * @brief Insert column into the table
381 *
382 * @param[in] colnum Column number [0,...,ncols()].
383 * @param[in] column Table column.
384 * @return Pointer to table column that has been appended.
385 *
386 * @exception GException::fits_bad_col_length
387 * The length of the column is incompatible with the number of
388 * rows in the table.
389 *
390 * A column will be inserted at position 'colnum' of the table. If the
391 * position is beyond the end of the table the column will be appended.
392 *
393 * If the table is empty and has 0 rows, the number of rows will be set to
394 * the length of the column.
395 *
396 * The length of the column to be inserted has to be identical to the number
397 * of rows in the table.
398 ***************************************************************************/
399GFitsTableCol* GFitsTable::insert(int colnum, const GFitsTableCol& column)
400{
401 // Make sure that 'colnum' is valid. Since we add one column the total
402 // number of columns at return will be m_cols+1, hence the column
403 // index is comprised between [0,m_cols]
404 //if (colnum < 0) colnum = 0;
405 //if (colnum > m_cols) colnum = m_cols;
406
407 // Check if column number is valid
408 if (colnum < 0 || colnum > ncols()) {
409 throw GException::out_of_range(G_INSERT1"GFitsTable::insert(int, GFitsTableCol&)", "Column number", colnum, ncols()+1);
410 }
411
412 // If the table is empty and has 0 rows then set the number of rows in
413 // the table to the length of the column
414 if (m_columns == NULL__null && m_rows == 0) {
415 m_rows = column.length();
416 }
417
418 // Throw exception if the column length is incompatible with number of
419 // rows in the table
420 if (m_rows != column.length()) {
421 throw GException::fits_bad_col_length(G_INSERT1"GFitsTable::insert(int, GFitsTableCol&)",
422 column.length(), m_rows);
423 }
424
425 // If no column data exist then allocate them now
426 if (m_columns == NULL__null) {
427 m_columns = new GFitsTableCol*[1];
428 m_cols = 1;
429 m_columns[0] = NULL__null;
430 colnum = 0; // We insert at the first place
431 }
432
433 // ... otherwise make space to insert column
434 else {
435
436 // Allocate fresh memory
437 GFitsTableCol** tmp = new GFitsTableCol*[m_cols+1];
438
439 // Copy over old column pointers. Leave some space at the position
440 // where we want to insert the column
441 int src;
442 int dst;
443 for (src = 0, dst = 0; dst < m_cols+1; ++dst) {
444 if (dst == colnum) {
445 tmp[dst] = NULL__null;
446 }
447 else {
448 tmp[dst] = m_columns[src];
449 src++;
450 }
451 }
452
453 // Free old column pointer array
454 delete [] m_columns;
455
456 // Connect new memory
457 m_columns = tmp;
458
459 // Increment column counter
460 m_cols++;
461
462 } // endelse: we made space to insert a column
463
464 // Copy column by cloning it
465 m_columns[colnum] = column.clone();
466
467 // Reset column number since column does not already exist in FITS
468 // file
469 m_columns[colnum]->colnum(0);
470
471 // Return column pointer
472 return (m_columns[colnum]);
473}
474
475
476/***********************************************************************//**
477 * @brief Insert column into the table
478 *
479 * @param[in] colname Column name.
480 * @param[in] column Table column.
481 * @return Pointer to table column that has been appended
482 *
483 * Inserts the column at the position given by the specified column name.
484 ***************************************************************************/
485GFitsTableCol* GFitsTable::insert(const std::string& colname,
486 const GFitsTableCol& column)
487{
488 // Get column number
489 int colnum = this->colnum(colname);
490
491 // If column has not been found throw an exception
492 if (colnum < 0) {
493 throw GException::fits_column_not_found(G_INSERT2"GFitsTable::insert(std::string&, GFitsTableCol&)", colname);
494 }
495
496 // Insert column and return pointer to column
497 return (insert(colnum, column));
498}
499
500
501/***********************************************************************//**
502 * @brief Append rows to the table
503 *
504 * @param[in] nrows Number of rows to be appended.
505 *
506 * Appends @p nrows rows at the end of the FITS table. The method calls the
507 * insert() method to do the job. Note that a call of this method will lead
508 * to loading all table data into memory.
509 ***************************************************************************/
510void GFitsTable::append_rows(const int& nrows)
511{
512 // Set row number for insertion to end of the file
513 int rownum = this->nrows();
514
515 // Insert rows
516 insert_rows(rownum, nrows);
517
518 // Return
519 return;
520}
521
522
523/***********************************************************************//**
524 * @brief Insert rows into the table
525 *
526 * @param[in] row Row at which rows are inserted [0,...,nrows()].
527 * @param[in] nrows Number of rows to be inserted.
528 *
529 * @exception GException::fits_invalid_row
530 * Specified rownum is invalid.
531 *
532 * Inserts @p nrows table rows at the specified @p row into the table. If the
533 * @p row index is set to the number of existing rows, nrows(), @p nrows
534 * will be appened at the end of the table.
535 *
536 * Note that this method will load all table data into memory.
537 ***************************************************************************/
538void GFitsTable::insert_rows(const int& row, const int& nrows)
539{
540 // Make sure that row is valid
541 if (row < 0 || row > m_rows) {
542 throw GException::fits_invalid_row(G_INSERT_ROWS"GFitsTable::insert_rows(int&, int&)", row, m_rows);
543 }
544
545 // Continue only if there are rows to be inserted
546 if (nrows > 0) {
547
548 // Insert rows for all columns
549 for (int icol = 0; icol < m_cols; ++icol) {
550 m_columns[icol]->insert(row, nrows);
551 }
552
553 // Increment number of rows in table
554 m_rows += nrows;
555
556 } // endfor: there were rows to be inserted
557
558 // Return
559 return;
560}
561
562
563/***********************************************************************//**
564 * @brief Remove rows from the table
565 *
566 * @param[in] row Row from which on rows are removed [0,...,nrows()-1].
567 * @param[in] nrows Number of rows to be removed.
568 *
569 * @exception GException::fits_invalid_row
570 * Specified rownum is invalid.
571 * @exception GException::fits_invalid_nrows
572 * Invalid number of rows specified.
573 *
574 * Removes @p nrows table rows from the specified @p row on from the table.
575 *
576 * Note that this method will load all column data into memory.
577 ***************************************************************************/
578void GFitsTable::remove_rows(const int& row, const int& nrows)
579{
580 // Make sure that row is valid
581 if (row < 0 || row >= m_rows) {
582 throw GException::fits_invalid_row(G_REMOVE_ROWS"GFitsTable::remove_rows(int&, int&)", row, m_rows-1);
583 }
584
585 // Make sure that we don't remove beyond the limit
586 if (nrows < 0 || nrows > m_rows-row) {
587 throw GException::fits_invalid_nrows(G_REMOVE_ROWS"GFitsTable::remove_rows(int&, int&)", nrows, m_rows-row);
588 }
589
590 // Continue only if there are rows to be removed
591 if (nrows > 0) {
592
593 // Remove rows for all columns
594 for (int icol = 0; icol < m_cols; ++icol) {
595 m_columns[icol]->remove(row, nrows);
596 }
597
598 // Decrement number of rows in table
599 m_rows -= nrows;
600
601 } // endfor: there were rows to be removed
602
603 // Return
604 return;
605}
606
607
608/***********************************************************************//**
609 * @brief Checks the presence of a column in table
610 *
611 * @param[in] colname Column name.
612 * @return True of the column exists, false otherwise.
613 ***************************************************************************/
614bool GFitsTable::contains(const std::string& colname) const
615{
616 // Get pointer in column
617 GFitsTableCol* ptr = ptr_column(colname);
618
619 // Return state
620 return (ptr != NULL__null);
621}
622
623
624/***********************************************************************//**
625 * @brief Print table information
626 *
627 * @param[in] chatter Chattiness (defaults to NORMAL).
628 * @return String containing table information.
629 ***************************************************************************/
630std::string GFitsTable::print(const GChatter& chatter) const
631{
632 // Initialise result string
633 std::string result;
634
635 // Continue only if chatter is not silent
636 if (chatter != SILENT) {
637
638 // Append header
639 result.append("=== GFitsTable ===");
640
641 // Append HDU information
642 result.append("\n"+print_hdu(chatter));
643
644 // Append table type
645 result.append("\n"+gammalib::parformat("Table type"));
646 switch (m_type) {
647 case GFitsHDU::HT_ASCII_TABLE:
648 result.append("ASCII table");
649 break;
650 case GFitsHDU::HT_BIN_TABLE:
651 result.append("Binary table");
652 break;
653 default:
654 result.append("Unknown");
655 break;
656 }
657
658 // Append table dimensions
659 result.append("\n"+gammalib::parformat("Number of rows"));
660 result.append(gammalib::str(m_rows));
661 result.append("\n"+gammalib::parformat("Number of columns"));
662 result.append(gammalib::str(m_cols));
663
664 // NORMAL: Append header information
665 if (chatter >= NORMAL) {
666 result.append("\n"+m_header.print(gammalib::reduce(chatter)));
667 }
668
669 // NORMAL: Append table columns
670 if (chatter >= VERBOSE) {
671 if (m_columns != NULL__null) {
672 for (int i = 0; i < m_cols; ++i) {
673 result.append("\n");
674 if (m_columns[i] != NULL__null) {
675 result.append(m_columns[i]->print(gammalib::reduce(chatter)));
676 }
677 else {
678 result.append(" Column "+gammalib::str(i)+" undefined");
679 }
680 }
681 }
682 else {
683 result.append("\n Table columns undefined");
684 }
685 }
686
687 } // endif: chatter was not silent
688
689 // Return result
690 return result;
691}
692
693
694/*==========================================================================
695 = =
696 = Protected methods =
697 = =
698 ==========================================================================*/
699
700/***********************************************************************//**
701 * @brief Open Table
702 *
703 * @param[in] vptr FITS file pointer.
704 *
705 * @exception GException::fits_hdu_not_found
706 * Specified HDU not found in FITS file.
707 * @exception GException::fits_error
708 * A CFITSIO error occured during loading the table.
709 * @exception GException::fits_unknown_coltype
710 * FITS column of unsupported type has been found in the FITS file.
711 * @exception GException::fits_inconsistent_tdim
712 * The TDIM information provided in the header is inconsistent
713 * with the size of the column.
714 *
715 * This method loads a description of the table into memory. Column data are
716 * not loaded at this point to save memory. They will be loaded on request
717 * later.
718 ***************************************************************************/
719void GFitsTable::data_open(void* vptr)
720{
721 // Move to HDU
722 gammalib::fits_move_to_hdu(G_DATA_OPEN"GFitsTable::data_open(void*)", vptr);
723
724 // Save FITS file pointer
725 FPTR_COPY(m_fitsfile, vptr)*((__fitsfile*)m_fitsfile) = *((__fitsfile*)vptr);
726
727 // Determine number of rows in table
728 int status = 0;
729 long nrows = 0;
730 status = __ffgnrw(FPTR(m_fitsfile), &nrows, &status)ffgnrw(((__fitsfile*)m_fitsfile), &nrows, &status);
731 if (status != 0) {
732 throw GException::fits_error(G_DATA_OPEN"GFitsTable::data_open(void*)", status);
733 }
734 else {
735 m_rows = (int)nrows;
736 }
737
738 // Determine number of columns in table
739 status = __ffgncl(FPTR(m_fitsfile), &m_cols, &status)ffgncl(((__fitsfile*)m_fitsfile), &m_cols, &status);
740 if (status != 0) {
741 throw GException::fits_error(G_DATA_OPEN"GFitsTable::data_open(void*)", status);
742 }
743
744 // Allocate and initialise memory for column pointers. Note that this
745 // initialisation is needed to allow for a clean free_members() call
746 // in case of any exception.
747 if (m_columns != NULL__null) delete [] m_columns;
748 m_columns = new GFitsTableCol*[m_cols];
749 for (int i = 0; i < m_cols; ++i) {
750 m_columns[i] = NULL__null;
751 }
752
753 // Get table column information
754 int typecode = 0;
755 long repeat = 0;
756 long width = 0;
757 for (int i = 0; i < m_cols; ++i) {
758
759 // Get column name
760 char keyname[10];
761 char value[80];
762 sprintf(keyname, "TTYPE%d", i+1);
763 status = __ffgkey(FPTR(m_fitsfile), keyname, value, NULL, &status)ffgkey(((__fitsfile*)m_fitsfile), keyname, value, __null, &
status)
;
764 if (status != 0) {
765 throw GException::fits_error(G_DATA_OPEN"GFitsTable::data_open(void*)", status);
766 }
767 value[strlen(value)-1] = '\0';
768
769 // Get column definition
770 status = __ffgtcl(FPTR(m_fitsfile), i+1, &typecode, &repeat, &width,ffgtcl(((__fitsfile*)m_fitsfile), i+1, &typecode, &repeat
, &width, &status)
771 &status)ffgtcl(((__fitsfile*)m_fitsfile), i+1, &typecode, &repeat
, &width, &status)
;
772 if (status != 0) {
773 throw GException::fits_error(G_DATA_OPEN"GFitsTable::data_open(void*)", status);
774 }
775
776 // Check for unsigned columns
777 unsigned long offset = 0;
778 sprintf(keyname, "TZERO%d", i+1);
779 status = __ffgky(FPTR(m_fitsfile), __TULONG, keyname, &offset, NULL, &status)ffgky(((__fitsfile*)m_fitsfile), 40, keyname, &offset, __null
, &status)
;
780 if (status == 0) {
781 if (typecode == __TSHORT21 && offset == 32768u) {
782 typecode = __TUSHORT20;
783 }
784 else if (typecode == -__TSHORT21 && offset == 32768u) {
785 typecode = -__TUSHORT20;
786 }
787 else if (typecode == __TLONG41 && offset == 2147483648u) {
788 typecode = __TULONG40;
789 }
790 else if (typecode == -__TLONG41 && offset == 2147483648u) {
791 typecode = -__TULONG40;
792 }
793 else if (typecode == __TINT31 && offset == 2147483648u) {
794 typecode = __TUINT30;
795 }
796 else if (typecode == -__TINT31 && offset == 2147483648u) {
797 typecode = -__TUINT30;
798 }
799 else {
800 std::string msg = "But column '"+std::string(value)+"' has"
801 " typecode "+gammalib::str(typecode)+" and"
802 " unexpected associated TZERO="+
803 gammalib::str(offset)+".";
804 throw GException::fits_error(G_DATA_OPEN"GFitsTable::data_open(void*)", 0, msg);
805 }
806 }
807 else
808 status = 0;
809
810 // Get column unit (optional, leave blank if not found)
811 char unit[80];
812 sprintf(keyname, "TUNIT%d", i+1);
813 status = __ffgkey(FPTR(m_fitsfile), keyname, unit, NULL, &status)ffgkey(((__fitsfile*)m_fitsfile), keyname, unit, __null, &
status)
;
814 if (status != 0) {
815 status = 0;
816 unit[0] = '\0';
817 unit[1] = '\0';
818 }
819 else {
820 unit[strlen(unit)-1] = '\0';
821 }
822
823 // Get column dimension (optional, leave blank if not found)
824 char dim[80];
825 sprintf(keyname, "TDIM%d", i+1);
826 status = __ffgkey(FPTR(m_fitsfile), keyname, dim, NULL, &status)ffgkey(((__fitsfile*)m_fitsfile), keyname, dim, __null, &
status)
;
827 if (status != 0) {
828 status = 0;
829 dim[0] = '\0';
830 dim[1] = '\0';
831 }
832 else {
833 dim[strlen(dim)-1] = '\0';
834 }
835
836 // If found, extract column dimension into vector array of integers
837 std::vector<int> vdim;
838 std::string sdim = gammalib::strip_chars(gammalib::strip_whitespace(&(dim[1])),"()");
839 if (sdim.length() > 0) {
840 std::vector<std::string> elements = gammalib::split(sdim, ",");
841 for (int k = 0; k < elements.size(); ++k) {
842 vdim.push_back(gammalib::toint(elements[k]));
843 }
844 }
845
846 // Allocate column
847 m_columns[i] = alloc_column(typecode);
848 if (m_columns[i] == NULL__null) {
849 std::ostringstream colname;
850 colname << value;
851 throw GException::fits_unknown_coltype(G_DATA_OPEN"GFitsTable::data_open(void*)", colname.str(), typecode);
852 }
853
854 // Store column definition
855 m_columns[i]->name(gammalib::strip_whitespace(&(value[1])));
856 m_columns[i]->unit(gammalib::strip_whitespace(&(unit[1])));
857 m_columns[i]->dim(vdim);
858 m_columns[i]->colnum(i+1);
859 m_columns[i]->type(typecode);
860 m_columns[i]->repeat(repeat);
861 m_columns[i]->width(width);
862 m_columns[i]->length(m_rows);
863 m_columns[i]->isvariable(typecode < 0);
864 m_columns[i]->connect(FPTR(m_fitsfile)((__fitsfile*)m_fitsfile));
865
866 // Extract column vector size
867 if (m_columns[i]->repeat() == 1) { // ASCII tables
868 m_columns[i]->number(1);
869 }
870 else { // Binary tables
871 if (typecode == __TSTRING16) {
872 m_columns[i]->number(m_columns[i]->repeat() /
873 m_columns[i]->width());
874 }
875 else {
876 m_columns[i]->number(m_columns[i]->repeat());
877 }
878 }
879
880 // If TDIM information was set then check its consistency
881 if (!vdim.empty()) {
882
883 // Compute expectation
884 int num = vdim[0];
885 for (int k = 1; k < vdim.size(); ++k) {
886 num *= vdim[k];
887 }
888
889 // Compare with real size
890 if (num != m_columns[i]->number()) {
891 throw GException::fits_inconsistent_tdim(G_DATA_OPEN"GFitsTable::data_open(void*)",
892 vdim,
893 m_columns[i]->number());
894 }
895
896 } // endif: Valid TDIM information was found
897
898 } // endfor: looped over all columns
899
900 // Return
901 return;
902}
903
904
905/***********************************************************************//**
906 * @brief Save table into FITS file
907 *
908 * @exception GException::fits_error
909 * A CFITSIO error occured in this method.
910 * @exception GException::fits_bad_col_length
911 * Table columns have inconsistent lengths.
912 *
913 * Saves the FITS table into the FITS file.
914 *
915 * In case that no table HDU exists so far in the FITS file, a new table
916 * will be appended to the FITS file. In case that a different HDU type
917 * exists at the requested extension number, the existing HDU will be
918 * deleted and be replaced by the requested table type.
919 *
920 * The method also verifies the consistency of all table columns. Table
921 * columns need to have identical lengths to be saved into a FITS table.
922 * All columns with a length of zero will be excluded from saving, and if
923 * they exist in the FITS file, they will be removed from the file.
924 *
925 * @todo This method should also update the header. Even easier, this method
926 * should save the header into the file using the m_header.save()
927 * method.
928 * Only this assures coherence between the files !!!! Once this has
929 * been implemented (also in the GFitsImage method) we should delete
930 * the m_header.save() call in GFitsHDU::save.
931 ***************************************************************************/
932void GFitsTable::data_save(void)
933{
934 // Debug definition: Dump method entry
935 #if defined(G_DEBUG_SAVE)
936 std::cout << "GFitsTable::save: entry" << std::endl;
937 for (int i = 0; i < m_cols; ++i) {
938 std::cout << m_columns[i]->print() << std::endl;
939 }
940 #endif
941
942 // Make sure that column lengths are consistent with table length.
943 // Columns with zero length will not be considered (why?)
944 for (int i = 0; i < m_cols; ++i) {
1
Loop condition is false. Execution continues on line 955
945 if (m_columns[i] != NULL__null && m_columns[i]->length() > 0) {
946 if (m_columns[i]->length() != m_rows) {
947 throw GException::fits_bad_col_length(G_DATA_SAVE"GFitsTable::data_save()",
948 m_columns[i]->length(),
949 m_rows);
950 }
951 }
952 }
953
954 // Move to HDU
955 int status = 0;
956 int type = 0;
957 status = __ffmahd(FPTR(m_fitsfile), m_hdunum+1, &type, &status)ffmahd(((__fitsfile*)m_fitsfile), m_hdunum+1, &type, &
status)
;
958
959 // If move was successful but HDU type in file differs from HDU type
960 // of object then replace the HDU in the file
961 bool replace = (status == 0 && type != m_type);
2
Assuming 'status' is equal to 0
962
963 // If HDU does not exist in file or should be replaced then create or
964 // replace it now
965 if (status == 107 || replace) {
3
Taking true branch
966
967 // Reset status
968 status = 0;
969
970 // Initialise number of fields
971 int tfields = 0;
972
973 // Setup cfitsio column definition arrays
974 char** ttype = NULL__null;
4
'ttype' initialized to a null pointer value
975 char** tform = NULL__null;
976 char** tunit = NULL__null;
977 if (m_cols > 0) {
5
Taking false branch
978 ttype = new char*[m_cols];
979 tform = new char*[m_cols];
980 tunit = new char*[m_cols];
981 for (int i = 0; i < m_cols; ++i) {
982 ttype[i] = NULL__null;
983 tform[i] = NULL__null;
984 tunit[i] = NULL__null;
985 }
986 for (int i = 0; i < m_cols; ++i) {
987 ttype[tfields] = get_ttype(i);
988 tform[tfields] = get_tform(i);
989 tunit[tfields] = get_tunit(i);
990 if (ttype[tfields] != NULL__null && tform[tfields] != NULL__null &&
991 tunit[tfields] != NULL__null)
992 tfields++;
993 }
994 }
995
996 // Replace FITS HDU by table
997 if (replace) {
6
Taking true branch
998
999 // Delete current FITS HDU
1000 status = __ffdhdu(FPTR(m_fitsfile), NULL, &status)ffdhdu(((__fitsfile*)m_fitsfile), __null, &status);
1001 if (status != 0) {
7
Assuming 'status' is equal to 0
8
Taking false branch
1002 throw GException::fits_error(G_DATA_SAVE"GFitsTable::data_save()", status);
1003 }
1004
1005 // Insert either ASCII or Binary table at current HDU position
1006 if (exttype() == GFitsHDU::HT_ASCII_TABLE) {
9
Taking false branch
1007 long tbcol = 0;
1008 long rowlen = 0;
1009 status = __ffgabc(tfields, tform, 1, &rowlen, &tbcol, &status)ffgabc(tfields, tform, 1, &rowlen, &tbcol, &status
)
;
1010 status = __ffitab(FPTR(m_fitsfile), rowlen, m_rows, tfields, ttype,ffitab(((__fitsfile*)m_fitsfile), rowlen, m_rows, tfields, ttype
, &tbcol, tform, tunit, __null, &status)
1011 &tbcol, tform, tunit, NULL, &status)ffitab(((__fitsfile*)m_fitsfile), rowlen, m_rows, tfields, ttype
, &tbcol, tform, tunit, __null, &status)
;
1012 }
1013 else {
1014 status = __ffibin(FPTR(m_fitsfile), m_rows, tfields, ttype, tform,ffibin(((__fitsfile*)m_fitsfile), m_rows, tfields, ttype, tform
, tunit, __null, 0, &status)
1015 tunit, NULL, 0, &status)ffibin(((__fitsfile*)m_fitsfile), m_rows, tfields, ttype, tform
, tunit, __null, 0, &status)
;
1016 }
1017 if (status != 0) {
10
Assuming 'status' is equal to 0
11
Taking false branch
1018 throw GException::fits_error(G_DATA_SAVE"GFitsTable::data_save()", status);
1019 }
1020
1021 }
1022
1023 // ... otherwise create FITS table
1024 else {
1025 status = __ffcrtb(FPTR(m_fitsfile), m_type, m_rows, tfields,ffcrtb(((__fitsfile*)m_fitsfile), m_type, m_rows, tfields, ttype
, tform, tunit, __null, &status)
1026 ttype, tform, tunit, NULL, &status)ffcrtb(((__fitsfile*)m_fitsfile), m_type, m_rows, tfields, ttype
, tform, tunit, __null, &status)
;
1027 if (status != 0) {
1028 throw GException::fits_error(G_DATA_SAVE"GFitsTable::data_save()", status);
1029 }
1030 }
1031
1032 // De-allocate column definition arrays
1033 if (m_cols > 0) {
12
Taking true branch
1034 for (int i = 0; i < m_cols; ++i) {
13
Loop condition is true. Entering loop body
1035 if (ttype[i] != NULL__null) delete [] ttype[i];
14
Array access (from variable 'ttype') results in a null pointer dereference
1036 if (tform[i] != NULL__null) delete [] tform[i];
1037 if (tunit[i] != NULL__null) delete [] tunit[i];
1038 }
1039 if (ttype != NULL__null) delete [] ttype;
1040 if (ttype != NULL__null) delete [] tform;
1041 if (ttype != NULL__null) delete [] tunit;
1042 }
1043
1044 // Connect all existing columns to FITS table
1045 if (m_columns != NULL__null) {
1046 for (int i = 0; i < m_cols; ++i) {
1047 if (m_columns[i] != NULL__null) {
1048 FPTR_COPY(m_columns[i]->m_fitsfile, m_fitsfile)*((__fitsfile*)m_columns[i]->m_fitsfile) = *((__fitsfile*)
m_fitsfile)
;
1049 m_columns[i]->colnum(i+1);
1050 }
1051 }
1052 }
1053
1054 // Debug option: Signal table creation
1055 #if defined(G_DEBUG_SAVE)
1056 std::cout << "GFitsTable::save: created new table" << std::endl;
1057 #endif
1058
1059 }
1060
1061 // ... otherwise we signal a FITS error
1062 else if (status != 0) {
1063 throw GException::fits_error(G_DATA_SAVE"GFitsTable::data_save()", status);
1064 }
1065
1066 // Determine number of columns in table
1067 int num_cols = 0;
1068 status = __ffgncl(FPTR(m_fitsfile), &num_cols, &status)ffgncl(((__fitsfile*)m_fitsfile), &num_cols, &status);
1069 if (status != 0) {
1070 throw GException::fits_error(G_DATA_SAVE"GFitsTable::data_save()", status);
1071 }
1072
1073 // Debug option: Log number of columns in FITS table
1074 #if defined(G_DEBUG_SAVE)
1075 std::cout << "GFitsTable::save: FITS table contains ";
1076 std::cout << num_cols << " columns." << std::endl;
1077 #endif
1078
1079 // If we have no columns in the table then delete all columns from
1080 // FITS table
1081 if (m_columns == NULL__null && num_cols > 0) {
1082 for (int i = 0; i < num_cols; ++i) {
1083 status = __ffdcol(FPTR(m_fitsfile), i, &status)ffdcol(((__fitsfile*)m_fitsfile), i, &status);
1084 if (status != 0) {
1085 throw GException::fits_error(G_DATA_SAVE"GFitsTable::data_save()", status);
1086 }
1087 }
1088 }
1089
1090 // ... otherwise update the FITS table
1091 else {
1092
1093 // Determine number of rows in table
1094 long num_rows = 0;
1095 status = __ffgnrw(FPTR(m_fitsfile), &num_rows, &status)ffgnrw(((__fitsfile*)m_fitsfile), &num_rows, &status);
1096 if (status != 0) {
1097 throw GException::fits_error(G_DATA_SAVE"GFitsTable::data_save()", status);
1098 }
1099
1100 // Debug option: Log number of rows in FITS table
1101 #if defined(G_DEBUG_SAVE)
1102 std::cout << "GFitsTable::save: FITS table contains ";
1103 std::cout << num_rows << " rows." << std::endl;
1104 #endif
1105
1106 // If the table length differs from number of rows in the FITS file
1107 // then readjust FITS table length. We do this by adding or
1108 // deleting rows at the end of the table as we anyways rewrite the
1109 // entire table later
1110 if (m_rows > num_rows) {
1111
1112 // Insert rows at the end of the table
1113 long long firstrow = num_rows;
1114 long long nrows = m_rows - num_rows;
1115 status = __ffirow(FPTR(m_fitsfile), firstrow, nrows, &status)ffirow(((__fitsfile*)m_fitsfile), firstrow, nrows, &status
)
;
1116 if (status != 0) {
1117 throw GException::fits_error(G_DATA_SAVE"GFitsTable::data_save()", status);
1118 }
1119
1120 // Debug option: Log row adding
1121 #if defined(G_DEBUG_SAVE)
1122 std::cout << "GFitsTable::save: Added " << nrows;
1123 std::cout << " rows to FITS table." << std::endl;
1124 #endif
1125
1126 }
1127 else if (m_rows < num_rows) {
1128
1129 // Delete rows at the end of the table
1130 long long firstrow = num_rows;
1131 long long nrows = num_rows - m_rows;
1132 status = __ffdrow(FPTR(m_fitsfile), firstrow, nrows, &status)ffdrow(((__fitsfile*)m_fitsfile), firstrow, nrows, &status
)
;
1133 if (status != 0) {
1134 throw GException::fits_error(G_DATA_SAVE"GFitsTable::data_save()", status);
1135 }
1136
1137 // Debug option: Log row adding
1138 #if defined(G_DEBUG_SAVE)
1139 std::cout << "GFitsTable::save: Deleted " << nrows;
1140 std::cout << " rows from FITS table." << std::endl;
1141 #endif
1142
1143 }
1144
1145 // Debug option: Show where we are
1146 #if defined(G_DEBUG_SAVE)
1147 std::cout << "GFitsTable::save: Now update all columns." << std::endl;
1148 #endif
1149
1150 // Update all columns. The 'm_colnum' field specifies where in the
1151 // FITS file the column resides. If 'm_colnum=0' then we have a new
1152 // column that does not yet exist. In this case we append a new column
1153 // to the FITS file.
1154 for (int i = 0; i < m_cols; ++i) {
1155
1156 // Only consider valid columns
1157 if (m_columns[i] != NULL__null) {
1158
1159 // If column has no correspondance than add new column in
1160 // FITS table and link column to table.
1161 if (m_columns[i]->colnum() == 0) {
1162
1163 // Increment number of columns in FITS file
1164 num_cols++;
1165
1166 // Append column to FITS file
1167 status = __fficol(FPTR(m_fitsfile), num_cols, get_ttype(i),fficol(((__fitsfile*)m_fitsfile), num_cols, get_ttype(i), get_tform
(i), &status)
1168 get_tform(i), &status)fficol(((__fitsfile*)m_fitsfile), num_cols, get_ttype(i), get_tform
(i), &status)
;
1169 if (status != 0) {
1170 throw GException::fits_error(G_DATA_SAVE"GFitsTable::data_save()", status);
1171 }
1172
1173 // Connect all column to FITS table by copying over the
1174 // FITS file pointer.
1175 FPTR_COPY(m_columns[i]->m_fitsfile, m_fitsfile)*((__fitsfile*)m_columns[i]->m_fitsfile) = *((__fitsfile*)
m_fitsfile)
;
1176 m_columns[i]->colnum(num_cols);
1177
1178 } // endif: column appended to FITS file
1179
1180 // Now write column into FITS file (only if length is positive)
1181 if (m_columns[i]->length() > 0) {
1182 // Debug option: Show which column we're going to write
1183 #if defined(G_DEBUG_SAVE)
1184 std::cout << "GFitsTable::save: Write column " << i;
1185 std::cout << "." << std::endl;
1186 #endif
1187 m_columns[i]->save();
1188 }
1189
1190 } // endif: column was valid
1191 } // endfor: looped over all table columns
1192
1193 // Debug option: Show where we are
1194 #if defined(G_DEBUG_SAVE)
1195 std::cout << "GFitsTable::save: Now delete all obsolete columns.";
1196 std::cout << std::endl;
1197 #endif
1198
1199 // Delete all obsolete columns from FITS file. We do this from last to
1200 // first so that the column numbers remain valid. Also note that
1201 // FITS column counting starts from 1.
1202 for (int colnum = num_cols; colnum > 0; --colnum) {
1203
1204 // Get column name from FITS file
1205 char keyname[10];
1206 char value[80];
1207 sprintf(keyname, "TTYPE%d", colnum);
1208 status = __ffgkey(FPTR(m_fitsfile), keyname, value, NULL, &status)ffgkey(((__fitsfile*)m_fitsfile), keyname, value, __null, &
status)
;
1209 if (status != 0) {
1210 throw GException::fits_error(G_DATA_SAVE"GFitsTable::data_save()", status);
1211 }
1212 value[strlen(value)-1] = '\0';
1213 std::string colname = gammalib::strip_whitespace(&(value[1]));
1214
1215 // Check if this column is actually in our list of columns
1216 bool used = false;
1217 for (int i = 0; i < m_cols; ++i) {
1218 if (m_columns[i] != NULL__null &&
1219 m_columns[i]->length() > 0 &&
1220 m_columns[i]->name() == colname) {
1221 used = true;
1222 break;
1223 }
1224 }
1225
1226 // If column is not used then delete it now from FITS table
1227 if (!used) {
1228
1229 // Delete column
1230 status = __ffdcol(FPTR(m_fitsfile), colnum, &status)ffdcol(((__fitsfile*)m_fitsfile), colnum, &status);
1231 if (status != 0) {
1232 throw GException::fits_error(G_DATA_SAVE"GFitsTable::data_save()", status);
1233 }
1234
1235 // Debug option: Log column deletion
1236 #if defined(G_DEBUG_SAVE)
1237 std::cout << "GFitsTable::save: Deleted obsolete column ";
1238 std::cout << value << " from FITS table." << std::endl;
1239 #endif
1240
1241 } // endif: deleted column
1242
1243 } // endfor: Looped over all FITS columns
1244
1245 } // endelse: FITS table has been updated
1246
1247 // Debug option: Show where we are
1248 #if defined(G_DEBUG_SAVE)
1249 std::cout << "GFitsTable::save: Now update the FITS header for all columns.";
1250 std::cout << std::endl;
1251 #endif
1252
1253 // Now update the header for all columns (unit and TDIM information)
1254 for (int i = 0; i < m_cols; ++i) {
1255
1256 // Only consider valid columns
1257 if (m_columns[i] != NULL__null) {
1258
1259 // Get column number
1260 int colnum = m_columns[i]->colnum();
1261
1262 // Update column units if available
1263 if (m_columns[i]->unit().length() > 0) {
1264
1265 // Build keyname
1266 std::string keyname = "TUNIT"+gammalib::str(colnum);
1267
1268 // Update header card
1269 card(keyname, m_columns[i]->unit(), "physical unit of field");
1270 }
1271
1272 // Write TDIM keyword if available
1273 if (m_columns[i]->dim().size() > 0) {
1274
1275 // Build keyname
1276 std::string keyname = "TDIM"+gammalib::str(colnum);
1277
1278 // Build value string
1279 std::string value = "("+gammalib::str(m_columns[i]->dim()[0]);
1280 for (int k = 1; k < m_columns[i]->dim().size(); ++k) {
1281 value += ","+gammalib::str(m_columns[i]->dim()[k]);
1282 }
1283 value += ")";
1284
1285 // Update header card
1286 card(keyname, value, "dimensions of field");
1287
1288 } // endif: wrote TDIM keyword
1289
1290 } // endif: column was valid
1291
1292 } // endfor: looped over all columns
1293
1294 // Debug definition: Dump method exit
1295 #if defined(G_DEBUG_SAVE)
1296 std::cout << "GFitsTable::save: exit" << std::endl;
1297 #endif
1298
1299 // Return
1300 return;
1301}
1302
1303
1304/***********************************************************************//**
1305 * @brief Close table
1306 ***************************************************************************/
1307void GFitsTable::data_close(void)
1308{
1309 // Free members
1310 free_members();
1311
1312 // Initialise members
1313 init_members();
1314
1315 // Return
1316 return;
1317}
1318
1319
1320/***********************************************************************//**
1321 * @brief Connect table data to FITS file
1322 *
1323 * @param[in] vptr FITS file pointer.
1324 *
1325 * Connects the table columns to the file specified by the FITS file pointer.
1326 * This method does nothing if the file pointer in not valid.
1327 ***************************************************************************/
1328void GFitsTable::data_connect(void* vptr)
1329{
1330 // Continue only if file pointer is valid
1331 if (vptr != NULL__null) {
1332
1333 // Connect all columns
1334 if (m_columns != NULL__null) {
1335 for (int i = 0; i < m_cols; ++i) {
1336 if (m_columns[i] != NULL__null) m_columns[i]->connect(vptr);
1337 }
1338 }
1339
1340 } // endif: file pointer was valid
1341
1342 // Return
1343 return;
1344}
1345
1346
1347/***********************************************************************//**
1348 * @brief Returns pointer to column type
1349 *
1350 * @param[in] colnum Column number for which type is to be returned
1351 *
1352 * This methods allocates memory for the character string that holds the
1353 * column type. The client has to de-allocate this memory after usage.
1354 * In case that the column does not exist a NULL pointer is returned.
1355 ***************************************************************************/
1356char* GFitsTable::get_ttype(const int& colnum) const
1357{
1358 // Initialise result with NULL pointer
1359 char* ptr = NULL__null;
1360
1361 // Get type only if column exists
1362 if (m_columns != NULL__null && colnum >=0 && colnum < m_cols &&
1363 m_columns[colnum] != NULL__null) {
1364 int size = m_columns[colnum]->name().length();
1365 ptr = new char[size+1];
1366 std::strncpy(ptr, m_columns[colnum]->name().c_str(), size);
1367 ptr[size] = '\0';
1368 }
1369
1370 // Return result
1371 return ptr;
1372}
1373
1374
1375/***********************************************************************//**
1376 * @brief Returns pointer to column format
1377 *
1378 * @param[in] colnum Column number (starting from 0).
1379 *
1380 * @exception GException::fits_unknown_tabtype
1381 * Table is neither ASCII nor Binary.
1382 *
1383 * This methods allocates memory for the character string that holds the
1384 * column format. The client has to de-allocate this memory after usage.
1385 * In case that the column does not exist a NULL pointer is returned.
1386 ***************************************************************************/
1387char* GFitsTable::get_tform(const int& colnum) const
1388{
1389 // Initialise result with NULL pointer
1390 char* ptr = NULL__null;
1391
1392 // Get type only if column exists
1393 if (m_columns != NULL__null && colnum >=0 && colnum < m_cols &&
1394 m_columns[colnum] != NULL__null) {
1395
1396 // Get table type specific format
1397 int size;
1398 switch (m_type) {
1399 case GFitsHDU::HT_ASCII_TABLE:
1400 size = m_columns[colnum]->ascii_format().length();
1401 ptr = new char[size+1];
1402 std::strncpy(ptr, m_columns[colnum]->ascii_format().c_str(), size);
1403 break;
1404 case GFitsHDU::HT_BIN_TABLE:
1405 size = m_columns[colnum]->tform_binary().length();
1406 ptr = new char[size+1];
1407 std::strncpy(ptr, m_columns[colnum]->tform_binary().c_str(), size);
1408 break;
1409 default:
1410 throw GException::fits_unknown_tabtype(G_GET_TFORM"GFitsTable::get_tform(int&)", m_type);
1411 break;
1412 }
1413 ptr[size] = '\0';
1414 }
1415
1416 // Return result
1417 return ptr;
1418}
1419
1420
1421/***********************************************************************//**
1422 * @brief Returns pointer to column unit
1423 *
1424 * @param[in] colnum Column number (starting from 0).
1425 *
1426 * This methods allocates memory for the character string that holds the
1427 * column unit. The client has to de-allocate this memory after usage.
1428 * In case that the column does not exist a NULL pointer is returned.
1429 ***************************************************************************/
1430char* GFitsTable::get_tunit(const int& colnum) const
1431{
1432 // Initialise result with NULL pointer
1433 char* ptr = NULL__null;
1434
1435 // Get type only if column exists
1436 if (m_columns != NULL__null && colnum >=0 && colnum < m_cols &&
1437 m_columns[colnum] != NULL__null) {
1438 int size = m_columns[colnum]->unit().length();
1439 ptr = new char[size+1];
1440 std::strncpy(ptr, m_columns[colnum]->unit().c_str(), size);
1441 ptr[size] = '\0';
1442 }
1443
1444 // Return result
1445 return ptr;
1446}
1447
1448
1449/*==========================================================================
1450 = =
1451 = Private methods =
1452 = =
1453 ==========================================================================*/
1454
1455/***********************************************************************//**
1456 * @brief Initialise class members
1457 ***************************************************************************/
1458void GFitsTable::init_members(void)
1459{
1460 // Initialise members
1461 m_type = -1;
1462 m_rows = 0;
1463 m_cols = 0;
1464 m_columns = NULL__null;
1465
1466 // Return
1467 return;
1468}
1469
1470
1471/***********************************************************************//**
1472 * @brief Copy class members
1473 *
1474 * @param[in] table Table to copy
1475 ***************************************************************************/
1476void GFitsTable::copy_members(const GFitsTable& table)
1477{
1478 // Copy attributes
1479 m_type = table.m_type;
1480 m_rows = table.m_rows;
1481 m_cols = table.m_cols;
1482
1483 // Copy column definition
1484 if (table.m_columns != NULL__null && m_cols > 0) {
1485 m_columns = new GFitsTableCol*[m_cols];
1486 for (int i = 0; i < m_cols; ++i) {
1487 if (table.m_columns[i] != NULL__null) {
1488 m_columns[i] = table.m_columns[i]->clone();
1489 }
1490 else {
1491 m_columns[i] = NULL__null;
1492 }
1493 }
1494 }
1495
1496 // Return
1497 return;
1498}
1499
1500
1501/***********************************************************************//**
1502 * @brief Delete class members
1503 *
1504 * De-allocates all column pointers
1505 ***************************************************************************/
1506void GFitsTable::free_members(void)
1507{
1508 // Free memory
1509 if (m_columns != NULL__null) {
1510 for (int i = 0; i < m_cols; ++i) {
1511 if (m_columns[i] != NULL__null) delete m_columns[i];
1512 }
1513 delete [] m_columns;
1514 }
1515
1516 // Mark memory as freed
1517 m_columns = NULL__null;
1518
1519 // Return
1520 return;
1521}
1522
1523
1524/***********************************************************************//**
1525 * @brief Allocates column
1526 *
1527 * @param[in] typecode cfitsio type code
1528 *
1529 * Allocates a table column depending on the cfitsio type code. If the type
1530 * code is not found then return a NULL pointer.
1531 ***************************************************************************/
1532GFitsTableCol* GFitsTable::alloc_column(int typecode) const
1533{
1534 // Initialise table column pointer
1535 GFitsTableCol* ptr = NULL__null;
1536
1537 // Allocate column
1538 switch (std::abs(typecode)) {
1539 case __TBIT1:
1540 ptr = new GFitsTableBitCol;
1541 break;
1542 case __TBYTE11:
1543 ptr = new GFitsTableByteCol;
1544 break;
1545 case __TLOGICAL14:
1546 ptr = new GFitsTableBoolCol;
1547 break;
1548 case __TSTRING16:
1549 ptr = new GFitsTableStringCol;
1550 break;
1551 case __TUSHORT20:
1552 ptr = new GFitsTableUShortCol;
1553 break;
1554 case __TSHORT21:
1555 ptr = new GFitsTableShortCol;
1556 break;
1557 case __TULONG40:
1558 ptr = new GFitsTableULongCol;
1559 break;
1560 case __TLONG41:
1561 ptr = new GFitsTableLongCol;
1562 break;
1563 case __TFLOAT42:
1564 ptr = new GFitsTableFloatCol;
1565 break;
1566 case __TLONGLONG81:
1567 ptr = new GFitsTableLongLongCol;
1568 break;
1569 case __TDOUBLE82:
1570 ptr = new GFitsTableDoubleCol;
1571 break;
1572 case __TCOMPLEX83:
1573 ptr = new GFitsTableCFloatCol;
1574 break;
1575 case __TDBLCOMPLEX163:
1576 ptr = new GFitsTableCDoubleCol;
1577 break;
1578 default:
1579 break;
1580 }
1581
1582 // Return
1583 return ptr;
1584}
1585
1586
1587/***********************************************************************//**
1588 * @brief Returns pointer of column with given name
1589 *
1590 * @param[in] colname Name of column.
1591 * @return Pointer to table column (NULL if column has not been found).
1592 *
1593 * Returns a pointer to the column with the specified name. If more columns
1594 * with the same name exist, a pointer to the first of these columns is
1595 * returned. If no column with the specified name is found, a NULL pointer
1596 * will be returned.
1597 ***************************************************************************/
1598GFitsTableCol* GFitsTable::ptr_column(const std::string& colname) const
1599{
1600 // Initialise pointer
1601 GFitsTableCol* ptr = NULL__null;
1602
1603 // If there are columns then search for the specified name
1604 if (m_columns != NULL__null) {
1605 for (int i = 0; i < m_cols; ++i) {
1606 if (m_columns[i]->name() == colname) {
1607 ptr = m_columns[i];
1608 break;
1609 }
1610 }
1611 }
1612
1613 // Return pointer
1614 return ptr;
1615}
1616
1617
1618/***********************************************************************//**
1619 * @brief Returns column number of a given column name
1620 *
1621 * @param[in] colname Name of column.
1622 * @return Column number (-1 if column has not been found).
1623 *
1624 * Returns the column number of the column with the specified name. If more
1625 * columns with the same name exist, the first of these columns is returned.
1626 ***************************************************************************/
1627int GFitsTable::colnum(const std::string& colname) const
1628{
1629 // Initialise column number
1630 int colnum = -1;
1631
1632 // If there are columns then search for the specified name
1633 if (m_columns != NULL__null) {
1634 for (int i = 0; i < m_cols; ++i) {
1635 if (m_columns[i]->name() == colname) {
1636 colnum = i;
1637 break;
1638 }
1639 }
1640 }
1641
1642 // Return column number
1643 return colnum;
1644}