1 /*
2 # This file is part of the Astrometry.net suite.
3 # Licensed under a 3-clause BSD style license - see LICENSE
4 */
5
6 #include <string.h>
7 #include <assert.h>
8 #include <stdarg.h>
9 #include <errors.h>
10
11 #include "os-features.h"
12 #include "fitstable.h"
13 #include "fitsioutils.h"
14 #include "fitsfile.h"
15 #include "ioutils.h"
16 #include "an-endian.h"
17 #include "anqfits.h"
18
19 #include "log.h"
20
21 struct fitscol_t {
22 char* colname;
23
24 tfits_type fitstype;
25 tfits_type ctype;
26 char* units;
27 int arraysize;
28
29 anbool required;
30
31 // size of one data item
32 // computed: fits_sizeof({fits,c}type)
33 int fitssize;
34 int csize;
35
36 // When being used to write to a C struct, the offset in the struct.
37 anbool in_struct;
38 int coffset;
39
40 // column number of the FITS table.
41 int col;
42 };
43 typedef struct fitscol_t fitscol_t;
44
45 // For in-memory: storage of previously-written extensions.
46 struct fitsext {
47 qfits_header* header;
48 qfits_table* table;
49 // bl data size == row size.
50 bl* rows;
51 };
52 typedef struct fitsext fitsext_t;
53
54
55
need_endian_flip()56 static anbool need_endian_flip() {
57 return IS_BIG_ENDIAN == 0;
58 }
59
60 //static void fitstable_add_columns(fitstable_t* tab, fitscol_t* cols, int Ncols);
61 static fitscol_t* fitstable_add_column(fitstable_t* tab, fitscol_t* col);
62 static void fitstable_create_table(fitstable_t* tab);
63
ncols(const fitstable_t * t)64 static int ncols(const fitstable_t* t) {
65 return bl_size(t->cols);
66 }
getcol(const fitstable_t * t,int i)67 static fitscol_t* getcol(const fitstable_t* t, int i) {
68 return bl_access(t->cols, i);
69 }
70
get_row_offset(const fitstable_t * table,int row)71 static off_t get_row_offset(const fitstable_t* table, int row) {
72 assert(table->end_table_offset);
73 assert(table->table);
74 assert(table->table->tab_w);
75 return table->end_table_offset + (off_t)(table->table->tab_w) * (off_t)(row);
76 }
77
fitstable_n_extensions(const fitstable_t * t)78 int fitstable_n_extensions(const fitstable_t* t) {
79 assert(t);
80 assert(t->anq);
81 return anqfits_n_ext(t->anq);
82 }
83
fitscolumn_get_size(fitscol_t * col)84 int fitscolumn_get_size(fitscol_t* col) {
85 return col->fitssize * col->arraysize;
86 }
87
offset_of_column(const fitstable_t * table,int colnum)88 static int offset_of_column(const fitstable_t* table, int colnum) {
89 int i;
90 int offset = 0;
91 assert(colnum <= ncols(table));
92 for (i=0; i<colnum; i++) {
93 fitscol_t* col;
94 col = getcol(table, i);
95 offset += fitscolumn_get_size(col);
96 }
97 return offset;
98 }
99
fitstable_get_struct_size(const fitstable_t * table)100 int fitstable_get_struct_size(const fitstable_t* table) {
101 int rowsize = offset_of_column(table, bl_size(table->cols));
102 return rowsize;
103 }
104
is_writing(const fitstable_t * t)105 static anbool is_writing(const fitstable_t* t) {
106 return t->fid ? TRUE : FALSE;
107 //return t->writing;
108 }
109
ensure_row_list_exists(fitstable_t * table)110 static void ensure_row_list_exists(fitstable_t* table) {
111 if (!table->rows) {
112 // how big are the rows?
113 int rowsize = offset_of_column(table, bl_size(table->cols));
114 table->rows = bl_new(1024, rowsize);
115 }
116 }
117
in_memory(const fitstable_t * t)118 static anbool in_memory(const fitstable_t* t) {
119 return t->inmemory;
120 }
121
fitscolumn_int_type()122 tfits_type fitscolumn_int_type() {
123 switch (sizeof(int)) {
124 case 2:
125 return TFITS_BIN_TYPE_I;
126 case 4:
127 return TFITS_BIN_TYPE_J;
128 case 8:
129 return TFITS_BIN_TYPE_K;
130 }
131 return -1;
132 }
133
134 /*
135 char fitscolumn_tfits_to_char(tfits_type t) {
136 }
137 */
138
fitscolumn_double_type()139 tfits_type fitscolumn_double_type() {
140 return TFITS_BIN_TYPE_D;
141 }
142
fitscolumn_float_type()143 tfits_type fitscolumn_float_type() {
144 return TFITS_BIN_TYPE_E;
145 }
146
fitscolumn_char_type()147 tfits_type fitscolumn_char_type() {
148 return TFITS_BIN_TYPE_A;
149 }
150
fitscolumn_u8_type()151 tfits_type fitscolumn_u8_type() {
152 return TFITS_BIN_TYPE_B;
153 }
fitscolumn_i16_type()154 tfits_type fitscolumn_i16_type() {
155 return TFITS_BIN_TYPE_I;
156 }
fitscolumn_i32_type()157 tfits_type fitscolumn_i32_type() {
158 return TFITS_BIN_TYPE_J;
159 }
fitscolumn_i64_type()160 tfits_type fitscolumn_i64_type() {
161 return TFITS_BIN_TYPE_K;
162 }
fitscolumn_boolean_type()163 tfits_type fitscolumn_boolean_type() {
164 return TFITS_BIN_TYPE_L;
165 }
166
fitscolumn_bool_type()167 tfits_type fitscolumn_bool_type() {
168 return TFITS_BIN_TYPE_B;
169 }
170
fitscolumn_bitfield_type()171 tfits_type fitscolumn_bitfield_type() {
172 return TFITS_BIN_TYPE_X;
173 }
174
175 // When reading: allow this column to match to any FITS type.
fitscolumn_any_type()176 tfits_type fitscolumn_any_type() {
177 return (tfits_type)-1;
178 }
179
180 /*
181 const char* fitscolumn_format_string(tfits_type t) {
182 switch (t) {
183 case TFITS_BIN_TYPE_D:
184 return "
185 */
186
fitstable_ncols(const fitstable_t * t)187 int fitstable_ncols(const fitstable_t* t) {
188 return ncols(t);
189 }
190
fitstable_read_row_data(fitstable_t * table,int row,void * dest)191 int fitstable_read_row_data(fitstable_t* table, int row, void* dest) {
192 return fitstable_read_nrows_data(table, row, 1, dest);
193 }
194
fitstable_read_nrows_data(fitstable_t * table,int row0,int nrows,void * dest)195 int fitstable_read_nrows_data(fitstable_t* table, int row0, int nrows,
196 void* dest) {
197 int R;
198 size_t nread;
199 off_t off;
200 assert(table);
201 assert(row0 >= 0);
202 assert((row0 + nrows) <= fitstable_nrows(table));
203 assert(dest);
204 R = fitstable_row_size(table);
205 if (in_memory(table)) {
206 int i;
207 char* cdest = dest;
208 for (i=0; i<nrows; i++)
209 memcpy(cdest, bl_access(table->rows, row0 + i), R);
210 return 0;
211 }
212 if (!table->readfid) {
213 table->readfid = fopen(table->fn, "rb");
214 if (!table->readfid) {
215 SYSERROR("Failed to open FITS table %s for reading", table->fn);
216 return -1;
217 }
218
219 assert(table->anq);
220 off_t start;
221 start = anqfits_data_start(table->anq, table->extension);
222 table->end_table_offset = start;
223 }
224 off = get_row_offset(table, row0);
225 if (fseeko(table->readfid, off, SEEK_SET)) {
226 SYSERROR("Failed to fseeko() to read a row");
227 return -1;
228 }
229 nread = (size_t)R * (size_t)nrows;
230 if (fread(dest, 1, nread, table->readfid) != nread) {
231 SYSERROR("Failed to read %i rows starting from %i, from %s", nrows, row0, table->fn);
232 return -1;
233 }
234 return 0;
235 }
236
fitstable_endian_flip_row_data(fitstable_t * table,void * data)237 void fitstable_endian_flip_row_data(fitstable_t* table, void* data) {
238 int i;
239 char* cursor;
240 if (!need_endian_flip())
241 return;
242 cursor = data;
243 for (i=0; i<ncols(table); i++) {
244 int j;
245 fitscol_t* col = getcol(table, i);
246 for (j=0; j<col->arraysize; j++) {
247 /*
248 if (col->fitssize == 8)
249 printf("col '%s': d=%g, i=%li\n",
250 col->colname, *((double*)cursor), *((uint64_t*)cursor));
251 */
252 endian_swap(cursor, col->fitssize);
253 /*
254 if (col->fitssize == 8)
255 printf(" --> d=%g, i=%li\n",
256 *((double*)cursor), *((uint64_t*)cursor));
257 */
258
259 cursor += col->fitssize;
260 }
261 }
262 }
263
write_row_data(fitstable_t * table,void * data,int R)264 static int write_row_data(fitstable_t* table, void* data, int R) {
265 assert(table);
266 assert(data);
267 if (in_memory(table)) {
268 ensure_row_list_exists(table);
269 bl_append(table->rows, data);
270 // ?
271 table->table->nr++;
272 return 0;
273 }
274 if (R == 0)
275 R = fitstable_row_size(table);
276 if (fwrite(data, 1, R, table->fid) != R) {
277 SYSERROR("Failed to write a row to %s", table->fn);
278 return -1;
279 }
280 assert(table->table);
281 table->table->nr++;
282 return 0;
283 }
284
fitstable_write_row_data(fitstable_t * table,void * data)285 int fitstable_write_row_data(fitstable_t* table, void* data) {
286 return write_row_data(table, data, 0);
287 }
288
fitstable_copy_rows_data(fitstable_t * intable,int * rows,int N,fitstable_t * outtable)289 int fitstable_copy_rows_data(fitstable_t* intable, int* rows, int N, fitstable_t* outtable) {
290 int R;
291 char* buf = NULL;
292 int i;
293 // We need to endian-flip if we're going from FITS file <--> memory.
294 anbool flip = need_endian_flip() && (in_memory(intable) != in_memory(outtable));
295 R = fitstable_row_size(intable);
296 buf = malloc(R);
297 for (i=0; i<N; i++) {
298 if (fitstable_read_row_data(intable, rows ? rows[i] : i, buf)) {
299 ERROR("Failed to read data from input table");
300 return -1;
301 }
302 // The in-memory side (input/output) does the flip.
303 if (flip) {
304 if (in_memory(intable))
305 fitstable_endian_flip_row_data(intable, buf);
306 else if (in_memory(outtable))
307 fitstable_endian_flip_row_data(outtable, buf);
308 }
309
310 if (write_row_data(outtable, buf, R)) {
311 ERROR("Failed to write data to output table");
312 return -1;
313 }
314 }
315 free(buf);
316 return 0;
317 }
318
fitstable_copy_row_data(fitstable_t * table,int row,fitstable_t * outtable)319 int fitstable_copy_row_data(fitstable_t* table, int row, fitstable_t* outtable) {
320 return fitstable_copy_rows_data(table, &row, 1, outtable);
321 }
322
fitstable_row_size(const fitstable_t * t)323 int fitstable_row_size(const fitstable_t* t) {
324 // FIXME - should this return the size of the *existing* FITS table
325 // (when reading), or just the columns we care about (those in "cols")?
326 return t->table->tab_w;
327 /*
328 int i, N, sz;
329 N = ncols(t);
330 sz = 0;
331 for (i=0; i<N; i++)
332 sz += fitscolumn_get_size(getcol(t, i));
333 return sz;
334 */
335 }
336
fitstable_get_column_name(const fitstable_t * src,int i)337 char* fitstable_get_column_name(const fitstable_t* src, int i) {
338 fitscol_t* col = getcol(src, i);
339 return col->colname;
340 }
341
fitstable_copy_columns(const fitstable_t * src,fitstable_t * dest)342 void fitstable_copy_columns(const fitstable_t* src, fitstable_t* dest) {
343 int i;
344 for (i=0; i<ncols(src); i++) {
345 fitscol_t* col = getcol(src, i);
346 fitscol_t* newcol = fitstable_add_column(dest, col);
347 // fix string fields...
348 newcol->colname = strdup_safe(newcol->colname);
349 newcol->units = strdup_safe(newcol->units);
350 }
351 }
352
fitstable_get_fits_column_names(const fitstable_t * t,sl * lst)353 sl* fitstable_get_fits_column_names(const fitstable_t* t, sl* lst) {
354 int i;
355 if (!lst)
356 lst = sl_new(16);
357 for (i=0; i<t->table->nc; i++) {
358 qfits_col* qcol = t->table->col + i;
359 sl_append(lst, qcol->tlabel);
360 }
361 return lst;
362 }
363
fitstable_get_N_fits_columns(const fitstable_t * t)364 int fitstable_get_N_fits_columns(const fitstable_t* t) {
365 return t->table->nc;
366 }
367
fitstable_get_fits_column_name(const fitstable_t * t,int i)368 const char* fitstable_get_fits_column_name(const fitstable_t* t, int i) {
369 assert(i >= 0);
370 assert(i < t->table->nc);
371 return t->table->col[i].tlabel;
372 }
373
fitstable_get_fits_column_type(const fitstable_t * t,int i)374 tfits_type fitstable_get_fits_column_type(const fitstable_t* t, int i) {
375 assert(i >= 0);
376 assert(i < t->table->nc);
377 return t->table->col[i].atom_type;
378 }
379
fitstable_get_fits_column_array_size(const fitstable_t * t,int i)380 int fitstable_get_fits_column_array_size(const fitstable_t* t, int i) {
381 assert(i >= 0);
382 assert(i < t->table->nc);
383 return t->table->col[i].atom_nb;
384 }
385
fitstable_add_write_column(fitstable_t * tab,tfits_type t,const char * name,const char * units)386 void fitstable_add_write_column(fitstable_t* tab, tfits_type t,
387 const char* name, const char* units) {
388 fitstable_add_write_column_array_convert(tab, t, t, 1, name, units);
389 }
390
fitstable_add_write_column_convert(fitstable_t * tab,tfits_type fits_type,tfits_type c_type,const char * name,const char * units)391 void fitstable_add_write_column_convert(fitstable_t* tab,
392 tfits_type fits_type,
393 tfits_type c_type,
394 const char* name,
395 const char* units) {
396 fitstable_add_write_column_array_convert(tab, fits_type, c_type, 1, name, units);
397 }
398
fitstable_add_write_column_array(fitstable_t * tab,tfits_type t,int arraysize,const char * name,const char * units)399 void fitstable_add_write_column_array(fitstable_t* tab, tfits_type t,
400 int arraysize,
401 const char* name,
402 const char* units) {
403 fitstable_add_write_column_array_convert(tab, t, t, arraysize, name, units);
404 }
405
fitstable_add_write_column_array_convert(fitstable_t * tab,tfits_type fits_type,tfits_type c_type,int arraysize,const char * name,const char * units)406 void fitstable_add_write_column_array_convert(fitstable_t* tab,
407 tfits_type fits_type,
408 tfits_type c_type,
409 int arraysize,
410 const char* name,
411 const char* units) {
412 fitscol_t col;
413 memset(&col, 0, sizeof(fitscol_t));
414 col.colname = strdup_safe(name);
415 col.units = strdup_safe(units);
416 col.fitstype = fits_type;
417 col.ctype = c_type;
418 col.arraysize = arraysize;
419 col.in_struct = FALSE;
420 fitstable_add_column(tab, &col);
421 }
422
fitstable_add_write_column_struct(fitstable_t * tab,tfits_type c_type,int arraysize,int structoffset,tfits_type fits_type,const char * name,const char * units)423 void fitstable_add_write_column_struct(fitstable_t* tab,
424 tfits_type c_type,
425 int arraysize,
426 int structoffset,
427 tfits_type fits_type,
428 const char* name,
429 const char* units) {
430 fitstable_add_column_struct(tab, c_type, arraysize, structoffset,
431 fits_type, name, units, FALSE);
432 }
433
fitstable_n_fits_columns(const fitstable_t * tab)434 int fitstable_n_fits_columns(const fitstable_t* tab) {
435 return tab->table->nc;
436 }
437
fitstable_add_fits_columns_as_struct4(const fitstable_t * intab,fitstable_t * outtab,const sl * colnames,int c_offset,tfits_type fitstype)438 int fitstable_add_fits_columns_as_struct4(const fitstable_t* intab,
439 fitstable_t* outtab,
440 const sl* colnames,
441 int c_offset,
442 tfits_type fitstype) {
443 int i, NC;
444 int noc = ncols(outtab);
445 NC = sl_size(colnames);
446 for (i=0; i<NC; i++) {
447 const qfits_col* qcol;
448 fitscol_t* col;
449 const char* name = sl_get_const(colnames, i);
450 int j = fits_find_column(intab->table, name);
451 int off;
452 if (j == -1) {
453 ERROR("Failed to find FITS column \"%s\"", name);
454 return -1;
455 }
456 qcol = qfits_table_get_col(intab->table, j);
457 // We give the offset of the column in the *input* table, so that
458 // the resulting "outtab" can handle raw data from the "intab".
459 off = fits_offset_of_column(intab->table, j);
460
461 if (fitstype == TFITS_BIN_TYPE_UNKNOWN)
462 fitstable_add_read_column_struct(outtab, qcol->atom_type, qcol->atom_nb,
463 c_offset + off, qcol->atom_type, qcol->tlabel, TRUE);
464 else
465 fitstable_add_read_column_struct(outtab, qcol->atom_type, qcol->atom_nb,
466 c_offset + off, fitstype, qcol->tlabel, TRUE);
467
468 // set the FITS column number.
469 col = getcol(outtab, ncols(outtab)-1);
470 col->col = noc + i;
471 }
472 return 0;
473 }
474
fitstable_add_fits_columns_as_struct3(const fitstable_t * intab,fitstable_t * outtab,const sl * colnames,int c_offset)475 int fitstable_add_fits_columns_as_struct3(const fitstable_t* intab,
476 fitstable_t* outtab,
477 const sl* colnames,
478 int c_offset) {
479 return fitstable_add_fits_columns_as_struct4(intab, outtab, colnames,
480 c_offset, TFITS_BIN_TYPE_UNKNOWN);
481 }
482
fitstable_add_fits_columns_as_struct2(const fitstable_t * intab,fitstable_t * outtab)483 void fitstable_add_fits_columns_as_struct2(const fitstable_t* intab,
484 fitstable_t* outtab) {
485 int i, NC;
486 int off = 0;
487 int noc = ncols(outtab);
488 NC = fitstable_get_N_fits_columns(intab);
489 for (i=0; i<NC; i++) {
490 const qfits_col* qcol = qfits_table_get_col(intab->table, i);
491 fitscol_t* col;
492 /*
493 if (qcol->atom_type == TFITS_BIN_TYPE_X) {
494 }
495 */
496 fitstable_add_read_column_struct(outtab, qcol->atom_type, qcol->atom_nb,
497 off, qcol->atom_type, qcol->tlabel, TRUE);
498 // set the FITS column number.
499 col = getcol(outtab, ncols(outtab)-1);
500 col->col = noc + i;
501 off += fitscolumn_get_size(col); //getcol(tab, ncols(tab)-1));
502 }
503 }
504
fitstable_add_fits_columns_as_struct(fitstable_t * tab)505 void fitstable_add_fits_columns_as_struct(fitstable_t* tab) {
506 int i;
507 int off = 0;
508 for (i=0; i<tab->table->nc; i++) {
509 qfits_col* qcol = tab->table->col + i;
510 fitscol_t* col;
511 /*
512 if (qcol->atom_type == TFITS_BIN_TYPE_X) {
513 }
514 */
515 fitstable_add_read_column_struct(tab, qcol->atom_type, qcol->atom_nb,
516 off, qcol->atom_type, qcol->tlabel, TRUE);
517 // set the FITS column number.
518 col = getcol(tab, ncols(tab)-1);
519 col->col = i;
520
521 off += fitscolumn_get_size(getcol(tab, ncols(tab)-1));
522 }
523 }
524
fitstable_find_fits_column(fitstable_t * tab,const char * colname,char ** units,tfits_type * type,int * arraysize)525 int fitstable_find_fits_column(fitstable_t* tab, const char* colname,
526 char** units, tfits_type* type, int* arraysize) {
527 int i;
528 for (i=0; i<tab->table->nc; i++) {
529 qfits_col* qcol = tab->table->col + i;
530 if (!strcaseeq(colname, qcol->tlabel))
531 continue;
532 // found it!
533 if (units)
534 *units = qcol->tunit;
535 if (type)
536 *type = qcol->atom_type;
537 if (arraysize)
538 *arraysize = qcol->atom_nb;
539 return 0;
540 }
541 return -1;
542 }
543
544
fitstable_add_read_column_struct(fitstable_t * tab,tfits_type c_type,int arraysize,int structoffset,tfits_type fits_type,const char * name,anbool required)545 void fitstable_add_read_column_struct(fitstable_t* tab,
546 tfits_type c_type,
547 int arraysize,
548 int structoffset,
549 tfits_type fits_type,
550 const char* name,
551 anbool required) {
552 fitstable_add_column_struct(tab, c_type, arraysize, structoffset,
553 fits_type, name, NULL, required);
554 }
555
fitstable_add_column_struct(fitstable_t * tab,tfits_type c_type,int arraysize,int structoffset,tfits_type fits_type,const char * name,const char * units,anbool required)556 void fitstable_add_column_struct(fitstable_t* tab,
557 tfits_type c_type,
558 int arraysize,
559 int structoffset,
560 tfits_type fits_type,
561 const char* name,
562 const char* units,
563 anbool required) {
564 fitscol_t col;
565 memset(&col, 0, sizeof(fitscol_t));
566 col.colname = strdup_safe(name);
567 col.units = strdup_safe(units);
568 col.fitstype = fits_type;
569 col.ctype = c_type;
570 col.arraysize = arraysize;
571 col.in_struct = TRUE;
572 col.coffset = structoffset;
573 col.required = required;
574 fitstable_add_column(tab, &col);
575 }
576
fitstable_remove_column(fitstable_t * tab,const char * name)577 int fitstable_remove_column(fitstable_t* tab, const char* name) {
578 int i;
579 for (i=0; i<ncols(tab); i++) {
580 fitscol_t* col = getcol(tab, i);
581 if (strcasecmp(name, col->colname) == 0) {
582 free(col->colname);
583 free(col->units);
584 bl_remove_index(tab->cols, i);
585 return 0;
586 }
587 }
588 return -1;
589 }
590
fitstable_print_columns(fitstable_t * tab)591 void fitstable_print_columns(fitstable_t* tab) {
592 int i;
593 printf("Table columns:\n");
594 for (i=0; i<ncols(tab); i++) {
595 fitscol_t* col = getcol(tab, i);
596 printf(" %i: %s: fits type %i, C type %i, arraysize %i, fitssize %i, C size %i, C offset %i (if in a struct), FITS column num: %i\n",
597 i, col->colname, col->fitstype, col->ctype, col->arraysize, col->fitssize, col->csize, col->coffset, col->col);
598 }
599 }
600
fitstable_read_structs(fitstable_t * tab,void * struc,int strucstride,int offset,int N)601 int fitstable_read_structs(fitstable_t* tab, void* struc,
602 int strucstride, int offset, int N) {
603 int i;
604 void* tempdata = NULL;
605 int highwater = 0;
606
607 //printf("fitstable_read_structs: stride %i, offset %i, N %i\n",strucstride, offset, N);
608
609 for (i=0; i<ncols(tab); i++) {
610 void* dest;
611 int stride;
612 void* finaldest;
613 int finalstride;
614 fitscol_t* col = getcol(tab, i);
615 if (col->col == -1)
616 continue;
617 if (!col->in_struct)
618 continue;
619 finaldest = ((char*)struc) + col->coffset;
620 finalstride = strucstride;
621
622 if (col->fitstype != col->ctype) {
623 int NB = fitscolumn_get_size(col) * N;
624 if (NB > highwater) {
625 free(tempdata);
626 tempdata = malloc(NB);
627 highwater = NB;
628 }
629 dest = tempdata;
630 stride = fitscolumn_get_size(col);
631 } else {
632 dest = finaldest;
633 stride = finalstride;
634 }
635
636 if (in_memory(tab)) {
637 int j;
638 int off = offset_of_column(tab, i);
639 int sz;
640 if (!tab->rows) {
641 ERROR("No data has been written to this fitstable");
642 return -1;
643 }
644 if (offset + N > bl_size(tab->rows)) {
645 ERROR("Number of data items requested exceeds number of rows: offset %i, n %i, nrows %zu", offset, N, bl_size(tab->rows));
646 return -1;
647 }
648
649 //logverb("column %i: dest offset %i, stride %i, row offset %i, input offset %i, size %i (%ix%i)\n", i, (int)(dest - struc), stride, offset, off, fitscolumn_get_size(col), col->fitssize, col->arraysize);
650 sz = fitscolumn_get_size(col);
651 for (j=0; j<N; j++)
652 memcpy(((char*)dest) + j * stride,
653 ((char*)bl_access(tab->rows, offset+j)) + off,
654 sz);
655 } else {
656 // Read from FITS file...
657 qfits_query_column_seq_to_array(tab->table, col->col, offset, N, dest, stride);
658 }
659
660 if (col->fitstype != col->ctype) {
661 fits_convert_data(finaldest, finalstride, col->ctype,
662 dest, stride, col->fitstype,
663 col->arraysize, N);
664 }
665 }
666 free(tempdata);
667
668 if (tab->postprocess_read_structs)
669 return tab->postprocess_read_structs(tab, struc, strucstride, offset, N);
670
671 return 0;
672 }
673
fitstable_read_struct(fitstable_t * tab,int offset,void * struc)674 int fitstable_read_struct(fitstable_t* tab, int offset, void* struc) {
675 return fitstable_read_structs(tab, struc, 0, offset, 1);
676 }
677
678 // One of "struc" or "ap" should be non-null.
write_one(fitstable_t * table,const void * struc,anbool flip,va_list * ap)679 static int write_one(fitstable_t* table, const void* struc, anbool flip,
680 va_list* ap) {
681 int i;
682 char* buf = NULL;
683 int Nbuf = 0;
684 int ret = 0;
685 int nc = ncols(table);
686
687 char* thisrow = NULL;
688 int rowoff = 0;
689
690 if (in_memory(table)) {
691 ensure_row_list_exists(table);
692 thisrow = calloc(1, bl_datasize(table->rows));
693 }
694
695 for (i=0; i<nc; i++) {
696 fitscol_t* col;
697 const char* columndata;
698 col = getcol(table, i);
699 if (col->in_struct) {
700 if (struc)
701 columndata = struc + col->coffset;
702 else
703 columndata = NULL;
704 } else {
705 if (struc)
706 columndata = NULL;
707 else
708 columndata = va_arg(*ap, void *);
709 }
710 // If "columndata" is NULL, fits_write_data_array
711 // skips the required number of bytes.
712 // This allows both structs and normal columns to coexist
713 // (in theory -- is this ever used?)
714 // (yes, by onefield.c when writing rdls and correspondence files
715 // with tag-along data...)
716
717 if (columndata && col->fitstype != col->ctype) {
718 int sz = MAX(256, MAX(col->csize, col->fitssize) * col->arraysize);
719 if (sz > Nbuf) {
720 free(buf);
721 buf = malloc(sz);
722 }
723
724 fits_convert_data(buf, col->fitssize, col->fitstype,
725 columndata, col->csize, col->ctype,
726 col->arraysize, 1);
727 columndata = buf;
728 }
729
730 if (in_memory(table)) {
731 int nb = fitscolumn_get_size(col);
732 memcpy(thisrow + rowoff, columndata, nb);
733 rowoff += nb;
734 } else {
735 ret = fits_write_data_array(table->fid, columndata,
736 col->fitstype, col->arraysize, flip);
737 if (ret)
738 break;
739 }
740 }
741 free(buf);
742 if (in_memory(table))
743 bl_append(table->rows, thisrow);
744 free(thisrow);
745 table->table->nr++;
746 return ret;
747 }
748
749
fitstable_write_struct(fitstable_t * table,const void * struc)750 int fitstable_write_struct(fitstable_t* table, const void* struc) {
751 return write_one(table, struc, TRUE, NULL);
752 }
753
fitstable_write_struct_noflip(fitstable_t * table,const void * struc)754 int fitstable_write_struct_noflip(fitstable_t* table, const void* struc) {
755 return write_one(table, struc, FALSE, NULL);
756 }
757
758
fitstable_write_structs(fitstable_t * table,const void * struc,int stride,int N)759 int fitstable_write_structs(fitstable_t* table, const void* struc, int stride, int N) {
760 int i;
761 char* s = (char*)struc;
762 for (i=0; i<N; i++) {
763 if (fitstable_write_struct(table, s)) {
764 return -1;
765 }
766 s += stride;
767 }
768 return 0;
769 }
770
fitstable_write_row(fitstable_t * table,...)771 int fitstable_write_row(fitstable_t* table, ...) {
772 int ret;
773 va_list ap;
774 if (!table->table)
775 fitstable_create_table(table);
776 va_start(ap, table);
777 ret = write_one(table, NULL, TRUE, &ap);
778 va_end(ap);
779 return ret;
780 }
781
fitstable_write_row_noflip(fitstable_t * table,...)782 int fitstable_write_row_noflip(fitstable_t* table, ...) {
783 int ret;
784 va_list ap;
785 if (!table->table)
786 fitstable_create_table(table);
787 va_start(ap, table);
788 ret = write_one(table, NULL, FALSE, &ap);
789 va_end(ap);
790 return ret;
791 }
792
793
fitstable_write_one_column(fitstable_t * table,int colnum,int rowoffset,int nrows,const void * src,int src_stride)794 int fitstable_write_one_column(fitstable_t* table, int colnum,
795 int rowoffset, int nrows,
796 const void* src, int src_stride) {
797 anbool flip = TRUE;
798 off_t foffset = 0;
799 off_t start = 0;
800 int i;
801 char* buf = NULL;
802 fitscol_t* col;
803 int off;
804
805 off = offset_of_column(table, colnum);
806 if (!in_memory(table)) {
807 foffset = ftello(table->fid);
808 // jump to row start...
809 start = get_row_offset(table, rowoffset) + off;
810 if (fseeko(table->fid, start, SEEK_SET)) {
811 SYSERROR("Failed to fseeko() to the start of the file.");
812 return -1;
813 }
814 }
815
816 col = getcol(table, colnum);
817 if (col->fitstype != col->ctype) {
818 int sz = col->fitssize * col->arraysize * nrows;
819 buf = malloc(sz);
820 fits_convert_data(buf, col->fitssize * col->arraysize, col->fitstype,
821 src, src_stride, col->ctype,
822 col->arraysize, nrows);
823 src = buf;
824 src_stride = col->fitssize * col->arraysize;
825 }
826
827 if (in_memory(table)) {
828 for (i=0; i<nrows; i++) {
829 memcpy(((char*)bl_access(table->rows, rowoffset + i)) + off,
830 src, col->fitssize * col->arraysize);
831 src = ((const char*)src) + src_stride;
832 }
833 } else {
834 for (i=0; i<nrows; i++) {
835 if (fseeko(table->fid, start + i * table->table->tab_w, SEEK_SET) ||
836 fits_write_data_array(table->fid, src, col->fitstype, col->arraysize, flip)) {
837 SYSERROR("Failed to write row %i of column %i", rowoffset+i, colnum);
838 return -1;
839 }
840 src = ((const char*)src) + src_stride;
841 }
842 }
843 free(buf);
844
845 if (!in_memory(table)) {
846 if (fseeko(table->fid, foffset, SEEK_SET)) {
847 SYSERROR("Failed to restore file offset.");
848 return -1;
849 }
850 }
851 return 0;
852 }
853
fitstable_clear_table(fitstable_t * tab)854 void fitstable_clear_table(fitstable_t* tab) {
855 int i;
856 for (i=0; i<ncols(tab); i++) {
857 fitscol_t* col = getcol(tab, i);
858 free(col->colname);
859 free(col->units);
860 }
861 bl_remove_all(tab->cols);
862 }
863
864 /**
865 If "inds" is non-NULL, it's a list of indices to read.
866 */
read_array_into(const fitstable_t * tab,const char * colname,tfits_type ctype,anbool array_ok,int offset,const int * inds,int Nread,void * dest,int deststride,int desired_arraysize,int * p_arraysize)867 static void* read_array_into(const fitstable_t* tab,
868 const char* colname, tfits_type ctype,
869 anbool array_ok,
870 int offset, const int* inds, int Nread,
871 void* dest, int deststride,
872 int desired_arraysize,
873 int* p_arraysize) {
874 int colnum;
875 qfits_col* col;
876 int fitssize;
877 int csize;
878 int fitstype;
879 int arraysize;
880
881 char* tempdata = NULL;
882 char* cdata;
883 char* fitsdata;
884 int cstride;
885 int fitsstride;
886 int N;
887
888 colnum = fits_find_column(tab->table, colname);
889 if (colnum == -1) {
890 ERROR("Column \"%s\" not found in FITS table %s", colname, tab->fn);
891 return NULL;
892 }
893 col = tab->table->col + colnum;
894 if (!array_ok && (col->atom_nb != 1)) {
895 ERROR("Column \"%s\" in FITS table %s is an array of size %i, not a scalar",
896 colname, tab->fn, col->atom_nb);
897 return NULL;
898 }
899
900 arraysize = col->atom_nb;
901 if (p_arraysize)
902 *p_arraysize = arraysize;
903 if (desired_arraysize && arraysize != desired_arraysize) {
904 ERROR("Column \"%s\" has array size %i but you wanted %i", colname, arraysize, desired_arraysize);
905 return NULL;
906 }
907 fitstype = col->atom_type;
908 fitssize = fits_get_atom_size(fitstype);
909 csize = fits_get_atom_size(ctype);
910 N = tab->table->nr;
911 if (Nread == -1)
912 Nread = N;
913 if (offset == -1)
914 offset = 0;
915
916 if (dest)
917 cdata = dest;
918 else
919 cdata = calloc(Nread * arraysize, csize);
920
921 if (dest && deststride > 0)
922 cstride = deststride;
923 else
924 cstride = csize * arraysize;
925
926 fitsstride = fitssize * arraysize;
927 if (csize < fitssize) {
928 // Need to allocate a bigger temp array and down-convert the data.
929 // HACK - could set data=tempdata and realloc after (if 'dest' is NULL)
930 tempdata = calloc(Nread * arraysize, fitssize);
931 fitsdata = tempdata;
932 } else {
933 // We'll read the data into the first fraction of the output array.
934 fitsdata = cdata;
935 }
936
937 if (in_memory(tab)) {
938 int i;
939 int off;
940 int sz;
941 if (!tab->rows) {
942 ERROR("No data has been written to this fitstable");
943 return NULL;
944 }
945 if (offset + Nread > bl_size(tab->rows)) {
946 ERROR("Number of data items requested exceeds number of rows: offset %i, n %i, nrows %zu", offset, Nread, bl_size(tab->rows));
947 return NULL;
948 }
949 off = fits_offset_of_column(tab->table, colnum);
950 sz = fitsstride;
951 if (inds) {
952 for (i=0; i<Nread; i++)
953 memcpy(fitsdata + i * fitsstride,
954 ((char*)bl_access(tab->rows, inds[i])) + off,
955 sz);
956 } else {
957 for (i=0; i<Nread; i++)
958 memcpy(fitsdata + i * fitsstride,
959 ((char*)bl_access(tab->rows, offset+i)) + off,
960 sz);
961 }
962 } else {
963 int res;
964 if (inds) {
965 res = qfits_query_column_seq_to_array_inds(tab->table, colnum, inds, Nread,
966 (unsigned char*)fitsdata, fitsstride);
967 } else {
968 res = qfits_query_column_seq_to_array(tab->table, colnum, offset, Nread,
969 (unsigned char*)fitsdata, fitsstride);
970 }
971 if (res) {
972 ERROR("Failed to read column from FITS file");
973 // MEMLEAK!
974 return NULL;
975 }
976 }
977
978 if (fitstype != ctype) {
979 if (csize <= fitssize) {
980 // work forward
981 fits_convert_data(cdata, cstride, ctype,
982 fitsdata, fitsstride, fitstype,
983 arraysize, Nread);
984 } else {
985 // work backward from the end of the array
986 fits_convert_data(cdata + (((off_t)Nread*(off_t)arraysize)-1) * (off_t)csize,
987 -csize, ctype,
988 fitsdata + (((off_t)Nread*(off_t)arraysize)-1) * (off_t)fitssize,
989 -fitssize, fitstype,
990 1, Nread * arraysize);
991 }
992 }
993
994 free(tempdata);
995 return cdata;
996 }
997
read_array(const fitstable_t * tab,const char * colname,tfits_type ctype,anbool array_ok,int offset,int Nread)998 static void* read_array(const fitstable_t* tab,
999 const char* colname, tfits_type ctype,
1000 anbool array_ok, int offset, int Nread) {
1001 return read_array_into(tab, colname, ctype, array_ok, offset, NULL, Nread, NULL, 0, 0, NULL);
1002 }
1003
fitstable_read_column_inds_into(const fitstable_t * tab,const char * colname,tfits_type read_as_type,void * dest,int stride,const int * inds,int N)1004 int fitstable_read_column_inds_into(const fitstable_t* tab,
1005 const char* colname, tfits_type read_as_type,
1006 void* dest, int stride, const int* inds, int N) {
1007 return (read_array_into(tab, colname, read_as_type, FALSE, 0, inds, N, dest, stride, 0, NULL)
1008 == NULL ? -1 : 0);
1009 }
1010
fitstable_read_column_inds(const fitstable_t * tab,const char * colname,tfits_type read_as_type,const int * inds,int N)1011 void* fitstable_read_column_inds(const fitstable_t* tab,
1012 const char* colname, tfits_type read_as_type,
1013 const int* inds, int N) {
1014 return read_array_into(tab, colname, read_as_type, FALSE, 0, inds, N, NULL, 0, 0, NULL);
1015 }
1016
fitstable_read_column_array_inds_into(const fitstable_t * tab,const char * colname,tfits_type read_as_type,void * dest,int stride,int arraysize,const int * inds,int N)1017 int fitstable_read_column_array_inds_into(const fitstable_t* tab,
1018 const char* colname, tfits_type read_as_type,
1019 void* dest, int stride, int arraysize,
1020 const int* inds, int N) {
1021 return (read_array_into(tab, colname, read_as_type, TRUE, 0, inds, N, dest, stride, arraysize, NULL)
1022 == NULL ? -1 : 0);
1023 }
1024
fitstable_read_column_array_inds(const fitstable_t * tab,const char * colname,tfits_type read_as_type,const int * inds,int N,int * arraysize)1025 void* fitstable_read_column_array_inds(const fitstable_t* tab,
1026 const char* colname, tfits_type read_as_type,
1027 const int* inds, int N, int* arraysize) {
1028 return read_array_into(tab, colname, read_as_type, TRUE, 0, inds, N, NULL, 0, 0, arraysize);
1029 }
1030
fitstable_read_column_offset_into(const fitstable_t * tab,const char * colname,tfits_type read_as_type,void * dest,int stride,int start,int N)1031 int fitstable_read_column_offset_into(const fitstable_t* tab,
1032 const char* colname, tfits_type read_as_type,
1033 void* dest, int stride, int start, int N) {
1034 return (read_array_into(tab, colname, read_as_type, FALSE, start, NULL, N, dest, stride, 0, NULL)
1035 == NULL ? -1 : 0);
1036 }
1037
fitstable_read_column_into(const fitstable_t * tab,const char * colname,tfits_type read_as_type,void * dest,int stride)1038 int fitstable_read_column_into(const fitstable_t* tab,
1039 const char* colname, tfits_type read_as_type,
1040 void* dest, int stride) {
1041 return fitstable_read_column_offset_into(tab, colname, read_as_type, dest, stride, 0, -1);
1042 }
1043
fitstable_read_column(const fitstable_t * tab,const char * colname,tfits_type ctype)1044 void* fitstable_read_column(const fitstable_t* tab,
1045 const char* colname, tfits_type ctype) {
1046 return read_array(tab, colname, ctype, FALSE, -1, -1);
1047 }
1048
fitstable_read_column_array(const fitstable_t * tab,const char * colname,tfits_type t)1049 void* fitstable_read_column_array(const fitstable_t* tab,
1050 const char* colname, tfits_type t) {
1051 return read_array(tab, colname, t, TRUE, -1, -1);
1052 }
1053
fitstable_read_column_offset(const fitstable_t * tab,const char * colname,tfits_type ctype,int offset,int N)1054 void* fitstable_read_column_offset(const fitstable_t* tab,
1055 const char* colname, tfits_type ctype,
1056 int offset, int N) {
1057 return read_array(tab, colname, ctype, FALSE, offset, N);
1058 }
1059
fitstable_get_primary_header(const fitstable_t * t)1060 qfits_header* fitstable_get_primary_header(const fitstable_t* t) {
1061 return t->primheader;
1062 }
1063
fitstable_get_header(fitstable_t * t)1064 qfits_header* fitstable_get_header(fitstable_t* t) {
1065 if (!t->header) {
1066 fitstable_new_table(t);
1067 }
1068 return t->header;
1069 }
1070
fitstable_next_extension(fitstable_t * tab)1071 void fitstable_next_extension(fitstable_t* tab) {
1072 if (is_writing(tab))
1073 fits_pad_file(tab->fid);
1074
1075 if (in_memory(tab)) {
1076 fitsext_t ext;
1077 if (!tab->table)
1078 return;
1079 // update NAXIS2
1080 fitstable_fix_header(tab);
1081 ext.table = tab->table;
1082 ext.header = tab->header;
1083 ext.rows = tab->rows;
1084 bl_append(tab->extensions, &ext);
1085 tab->rows = NULL;
1086 } else {
1087 qfits_table_close(tab->table);
1088 qfits_header_destroy(tab->header);
1089 }
1090 tab->extension++;
1091 tab->table = NULL;
1092 tab->header = NULL;
1093 }
1094
fitstable_new()1095 static fitstable_t* fitstable_new() {
1096 fitstable_t* tab;
1097 tab = calloc(1, sizeof(fitstable_t));
1098 if (!tab)
1099 return tab;
1100 tab->cols = bl_new(8, sizeof(fitscol_t));
1101 return tab;
1102 }
1103
fitstable_open_in_memory()1104 fitstable_t* fitstable_open_in_memory() {
1105 fitstable_t* tab;
1106 tab = fitstable_new();
1107 if (!tab) {
1108 ERROR("Failed to allocate new FITS table structure");
1109 goto bailout;
1110 }
1111 tab->fn = NULL;
1112 tab->fid = NULL;
1113 tab->primheader = qfits_table_prim_header_default();
1114 tab->inmemory = TRUE;
1115 tab->extensions = bl_new(16, sizeof(fitsext_t));
1116 return tab;
1117
1118 bailout:
1119 if (tab) {
1120 fitstable_close(tab);
1121 }
1122 return NULL;
1123 }
1124
fitstable_switch_to_reading(fitstable_t * table)1125 int fitstable_switch_to_reading(fitstable_t* table) {
1126 assert(in_memory(table));
1127 // store the current extension.
1128 fitstable_next_extension(table);
1129 // This resets all the meta-data about the table, meaning a reader
1130 // can then re-add columns it is interested in.
1131 fitstable_clear_table(table);
1132 table->extension = 1;
1133 return fitstable_open_extension(table, table->extension);
1134 }
1135
1136 static
_fitstable_open(const char * fn)1137 fitstable_t* _fitstable_open(const char* fn) {
1138 fitstable_t* tab;
1139 tab = fitstable_new();
1140 if (!tab) {
1141 ERROR("Failed to allocate new FITS table structure");
1142 goto bailout;
1143 }
1144 tab->extension = 1;
1145 tab->fn = strdup_safe(fn);
1146
1147 tab->anq = anqfits_open(fn);
1148 if (!tab->anq) {
1149 ERROR("Failed to open FITS file \"%s\"", fn);
1150 goto bailout;
1151 }
1152 tab->primheader = anqfits_get_header(tab->anq, 0);
1153 if (!tab->primheader) {
1154 ERROR("Failed to read primary FITS header from %s", fn);
1155 goto bailout;
1156 }
1157 return tab;
1158 bailout:
1159 if (tab) {
1160 fitstable_close(tab);
1161 }
1162 return NULL;
1163 }
1164
fitstable_open(const char * fn)1165 fitstable_t* fitstable_open(const char* fn) {
1166 fitstable_t* tab = _fitstable_open(fn);
1167 if (!tab) {
1168 return NULL;
1169 }
1170 if (fitstable_open_extension(tab, tab->extension)) {
1171 ERROR("Failed to open extension %i in file %s", tab->extension, fn);
1172 goto bailout;
1173 }
1174 return tab;
1175 bailout:
1176 if (tab) {
1177 fitstable_close(tab);
1178 }
1179 return NULL;
1180 }
1181
fitstable_open_mixed(const char * fn)1182 fitstable_t* fitstable_open_mixed(const char* fn) {
1183 return _fitstable_open(fn);
1184 }
1185
fitstable_open_extension_2(const char * fn,int ext)1186 fitstable_t* fitstable_open_extension_2(const char* fn, int ext) {
1187 fitstable_t* tab = _fitstable_open(fn);
1188 if (!tab)
1189 return tab;
1190 if (fitstable_open_extension(tab, ext)) {
1191 fitstable_close(tab);
1192 return NULL;
1193 }
1194 return tab;
1195 }
1196
open_for_writing(const char * fn,const char * mode,FILE * fid)1197 static fitstable_t* open_for_writing(const char* fn, const char* mode, FILE* fid) {
1198 fitstable_t* tab;
1199 tab = fitstable_new();
1200 if (!tab)
1201 goto bailout;
1202 tab->fn = strdup_safe(fn);
1203 if (fid)
1204 tab->fid = fid;
1205 else {
1206 tab->fid = fopen(fn, mode);
1207 if (!tab->fid) {
1208 SYSERROR("Couldn't open output file %s for writing", fn);
1209 goto bailout;
1210 }
1211 }
1212 return tab;
1213 bailout:
1214 if (tab) {
1215 fitstable_close(tab);
1216 }
1217 return NULL;
1218 }
1219
fitstable_open_for_writing(const char * fn)1220 fitstable_t* fitstable_open_for_writing(const char* fn) {
1221 fitstable_t* tab = open_for_writing(fn, "wb", NULL);
1222 if (!tab)
1223 return tab;
1224 tab->primheader = qfits_table_prim_header_default();
1225 return tab;
1226 }
1227
fitstable_open_for_appending(const char * fn)1228 fitstable_t* fitstable_open_for_appending(const char* fn) {
1229 fitstable_t* tab = open_for_writing(fn, "r+b", NULL);
1230 if (!tab)
1231 return tab;
1232 if (fseeko(tab->fid, 0, SEEK_END)) {
1233 SYSERROR("Failed to seek to end of file");
1234 fitstable_close(tab);
1235 return NULL;
1236 }
1237 tab->primheader = anqfits_get_header2(fn, 0);
1238 if (!tab->primheader) {
1239 ERROR("Failed to read primary FITS header from %s", fn);
1240 fitstable_close(tab);
1241 return NULL;
1242 }
1243 return tab;
1244 }
1245
fitstable_open_for_appending_to(FILE * fid)1246 fitstable_t* fitstable_open_for_appending_to(FILE* fid) {
1247 fitstable_t* tab = open_for_writing(NULL, NULL, fid);
1248 if (!tab)
1249 return tab;
1250 if (fseeko(tab->fid, 0, SEEK_END)) {
1251 SYSERROR("Failed to seek to end of file");
1252 fitstable_close(tab);
1253 return NULL;
1254 }
1255 return tab;
1256 }
1257
fitstable_append_to(fitstable_t * intable,FILE * fid)1258 int fitstable_append_to(fitstable_t* intable, FILE* fid) {
1259 fitstable_t* outtable;
1260 qfits_header* tmphdr;
1261 outtable = fitstable_open_for_appending_to(fid);
1262 fitstable_clear_table(intable);
1263 fitstable_add_fits_columns_as_struct(intable);
1264 fitstable_copy_columns(intable, outtable);
1265 outtable->table = fits_copy_table(intable->table);
1266 outtable->table->nr = 0;
1267 // swap in the input header.
1268 tmphdr = outtable->header;
1269 outtable->header = intable->header;
1270 if (fitstable_write_header(outtable)) {
1271 ERROR("Failed to write output table header");
1272 return -1;
1273 }
1274 if (fitstable_copy_rows_data(intable, NULL, fitstable_nrows(intable), outtable)) {
1275 ERROR("Failed to copy rows from input table to output");
1276 return -1;
1277 }
1278 if (fitstable_fix_header(outtable)) {
1279 ERROR("Failed to fix output table header");
1280 return -1;
1281 }
1282 outtable->header = tmphdr;
1283 // clear this so that fitstable_close() doesn't fclose() it.
1284 outtable->fid = NULL;
1285 fitstable_close(outtable);
1286 return 0;
1287 }
1288
fitstable_close(fitstable_t * tab)1289 int fitstable_close(fitstable_t* tab) {
1290 int i;
1291 int rtn = 0;
1292 if (!tab) return 0;
1293 if (is_writing(tab)) {
1294 if (tab->fid) {
1295 if (fclose(tab->fid)) {
1296 SYSERROR("Failed to close output file %s", tab->fn);
1297 rtn = -1;
1298 }
1299 }
1300 }
1301 if (tab->anq) {
1302 anqfits_close(tab->anq);
1303 }
1304 if (tab->readfid) {
1305 fclose(tab->readfid);
1306 }
1307 if (tab->primheader)
1308 qfits_header_destroy(tab->primheader);
1309 if (tab->header)
1310 qfits_header_destroy(tab->header);
1311 if (tab->table)
1312 qfits_table_close(tab->table);
1313 free(tab->fn);
1314 for (i=0; i<ncols(tab); i++) {
1315 fitscol_t* col = getcol(tab, i);
1316 free(col->colname);
1317 free(col->units);
1318 }
1319 bl_free(tab->cols);
1320 if (tab->br) {
1321 buffered_read_free(tab->br);
1322 free(tab->br);
1323 }
1324 if (tab->rows) {
1325 bl_free(tab->rows);
1326 }
1327 if (tab->extensions) {
1328 for (i=0; i<bl_size(tab->extensions); i++) {
1329 fitsext_t* ext = bl_access(tab->extensions, i);
1330 if (ext->rows != tab->rows)
1331 bl_free(ext->rows);
1332 if (ext->header != tab->header)
1333 qfits_header_destroy(ext->header);
1334 if (ext->table != tab->table)
1335 qfits_table_close(ext->table);
1336 }
1337 bl_free(tab->extensions);
1338 }
1339 free(tab);
1340 return rtn;
1341 }
1342
fitstable_add_column(fitstable_t * tab,fitscol_t * col)1343 static fitscol_t* fitstable_add_column(fitstable_t* tab, fitscol_t* col) {
1344 col = bl_append(tab->cols, col);
1345 col->csize = fits_get_atom_size(col->ctype);
1346 col->fitssize = fits_get_atom_size(col->fitstype);
1347 return col;
1348 }
1349
1350 /*
1351 static void fitstable_add_columns(fitstable_t* tab, fitscol_t* cols, int Ncols) {
1352 int i;
1353 for (i=0; i<Ncols; i++) {
1354 fitstable_add_column(tab, cols + i);
1355 }
1356 }
1357 */
1358
fitstable_get_array_size(fitstable_t * tab,const char * name)1359 int fitstable_get_array_size(fitstable_t* tab, const char* name) {
1360 qfits_col* qcol;
1361 int colnum;
1362 colnum = fits_find_column(tab->table, name);
1363 if (colnum == -1)
1364 return -1;
1365 qcol = tab->table->col + colnum;
1366 return qcol->atom_nb;
1367 }
1368
fitstable_get_type(fitstable_t * tab,const char * name)1369 int fitstable_get_type(fitstable_t* tab, const char* name) {
1370 qfits_col* qcol;
1371 int colnum;
1372 colnum = fits_find_column(tab->table, name);
1373 if (colnum == -1)
1374 return -1;
1375 qcol = tab->table->col + colnum;
1376 return qcol->atom_type;
1377 }
1378
fitstable_open_next_extension(fitstable_t * tab)1379 int fitstable_open_next_extension(fitstable_t* tab) {
1380 tab->extension++;
1381 return fitstable_open_extension(tab, tab->extension);
1382 }
1383
fitstable_open_extension(fitstable_t * tab,int ext)1384 int fitstable_open_extension(fitstable_t* tab, int ext) {
1385 if (in_memory(tab)) {
1386 fitsext_t* theext;
1387 if (ext > bl_size(tab->extensions)) {
1388 ERROR("Table has only %zu extensions, but you requested #%i",
1389 bl_size(tab->extensions), ext);
1390 return -1;
1391 }
1392 theext = bl_access(tab->extensions, ext-1);
1393 tab->table = theext->table;
1394 tab->header = theext->header;
1395 tab->rows = theext->rows;
1396 tab->extension = ext;
1397
1398 } else {
1399 if (tab->table) {
1400 qfits_table_close(tab->table);
1401 tab->table = NULL;
1402 }
1403
1404 assert(tab->anq);
1405 if (ext >= anqfits_n_ext(tab->anq)) {
1406 ERROR("Requested FITS extension %i in file %s, but there are only %i extensions.\n", ext, tab->fn, anqfits_n_ext(tab->anq));
1407 return -1;
1408 }
1409 tab->table = anqfits_get_table(tab->anq, ext);
1410
1411 if (!tab->table) {
1412 ERROR("FITS extension %i in file %s is not a table (or there was an error opening the file)", ext, tab->fn);
1413 return -1;
1414 }
1415 if (tab->header) {
1416 qfits_header_destroy(tab->header);
1417 }
1418
1419 tab->header = anqfits_get_header(tab->anq, ext);
1420 if (!tab->header) {
1421 ERROR("Couldn't get header for FITS extension %i in file %s", ext, tab->fn);
1422 return -1;
1423 }
1424 tab->extension = ext;
1425 }
1426 return 0;
1427 }
1428
fitstable_read_extension(fitstable_t * tab,int ext)1429 int fitstable_read_extension(fitstable_t* tab, int ext) {
1430 int i;
1431 int ok = 1;
1432
1433 if (fitstable_open_extension(tab, ext))
1434 return -1;
1435
1436 if (tab->readfid) {
1437 // close FID so that table->end_table_offset gets refreshed.
1438 fclose(tab->readfid);
1439 tab->readfid = NULL;
1440 }
1441
1442 for (i=0; i<ncols(tab); i++) {
1443 fitscol_t* col = getcol(tab, i);
1444 qfits_col* qcol;
1445
1446 // FIXME? set this here?
1447 col->csize = fits_get_atom_size(col->ctype);
1448
1449 // Column found?
1450 col->col = fits_find_column(tab->table, col->colname);
1451 if (col->col == -1)
1452 continue;
1453 qcol = tab->table->col + col->col;
1454
1455 // Type & array size correct?
1456 if (col->fitstype != fitscolumn_any_type() &&
1457 col->fitstype != qcol->atom_type) {
1458 col->col = -1;
1459 continue;
1460 }
1461 col->fitstype = qcol->atom_type;
1462 col->fitssize = fits_get_atom_size(col->fitstype);
1463
1464 if (col->arraysize) {
1465 if (col->arraysize != qcol->atom_nb) {
1466 col->col = -1;
1467 continue;
1468 }
1469 }
1470 /* This was causing problems with copying startree tag-along data (Tycho2 test case: FLAGS column)
1471
1472 if (col->fitstype == TFITS_BIN_TYPE_X) {
1473 // ??? really??
1474 col->arraysize = 8 * qcol->atom_nb;
1475 } else {
1476 col->arraysize = qcol->atom_nb;
1477 }
1478 */
1479 col->arraysize = qcol->atom_nb;
1480 }
1481
1482 if (tab->br) {
1483 buffered_read_reset(tab->br);
1484 tab->br->ntotal = tab->table->nr;
1485 }
1486
1487 for (i=0; i<ncols(tab); i++) {
1488 fitscol_t* col = getcol(tab, i);
1489 if (col->col == -1 && col->required) {
1490 ok = 0;
1491 break;
1492 }
1493 }
1494 if (ok) return 0;
1495 return -1;
1496 }
1497
fitstable_write_primary_header(fitstable_t * t)1498 int fitstable_write_primary_header(fitstable_t* t) {
1499 if (in_memory(t)) return 0;
1500 return fitsfile_write_primary_header(t->fid, t->primheader,
1501 &t->end_header_offset, t->fn);
1502 }
1503
fitstable_fix_primary_header(fitstable_t * t)1504 int fitstable_fix_primary_header(fitstable_t* t) {
1505 if (in_memory(t)) return 0;
1506 return fitsfile_fix_primary_header(t->fid, t->primheader,
1507 &t->end_header_offset, t->fn);
1508 }
1509
1510 // Called just before starting to write a new field.
fitstable_new_table(fitstable_t * t)1511 int fitstable_new_table(fitstable_t* t) {
1512 if (t->table) {
1513 qfits_table_close(t->table);
1514 }
1515 fitstable_create_table(t);
1516 if (t->header) {
1517 qfits_header_destroy(t->header);
1518 }
1519 t->header = qfits_table_ext_header_default(t->table);
1520 return 0;
1521 }
1522
fitstable_write_header(fitstable_t * t)1523 int fitstable_write_header(fitstable_t* t) {
1524 if (!t->header) {
1525 if (fitstable_new_table(t)) {
1526 return -1;
1527 }
1528 }
1529 if (in_memory(t)) return 0;
1530
1531 return fitsfile_write_header(t->fid, t->header,
1532 &t->table_offset, &t->end_table_offset,
1533 t->extension, t->fn);
1534 }
1535
fitstable_pad_with(fitstable_t * t,char pad)1536 int fitstable_pad_with(fitstable_t* t, char pad) {
1537 return fitsfile_pad_with(t->fid, pad);
1538 }
1539
fitstable_fix_header(fitstable_t * t)1540 int fitstable_fix_header(fitstable_t* t) {
1541 // update NAXIS2 to reflect the number of rows written.
1542 fits_header_mod_int(t->header, "NAXIS2", t->table->nr, NULL);
1543
1544 if (in_memory(t)) return 0;
1545
1546 //printf("fitstable_fix_header: ext %i, table offset was %lu, fn %s\n",
1547 //t->extension, (long)t->table_offset, t->fn);
1548 if (fitsfile_fix_header(t->fid, t->header,
1549 &t->table_offset, &t->end_table_offset,
1550 t->extension, t->fn)) {
1551 return -1;
1552 }
1553 return 0; //fits_pad_file(t->fid);
1554 }
1555
fitstable_close_table(fitstable_t * tab)1556 void fitstable_close_table(fitstable_t* tab) {
1557 int i;
1558 if (tab->table) {
1559 qfits_table_close(tab->table);
1560 tab->table = NULL;
1561 }
1562 for (i=0; i<ncols(tab); i++) {
1563 fitscol_t* col = getcol(tab, i);
1564 col->col = -1;
1565 col->fitssize = 0;
1566 col->arraysize = 0;
1567 col->fitstype = fitscolumn_any_type();
1568 }
1569 }
1570
fitstable_nrows(const fitstable_t * t)1571 int fitstable_nrows(const fitstable_t* t) {
1572 if (!t->table) return 0;
1573 return t->table->nr;
1574 }
1575
fitstable_print_missing(fitstable_t * tab,FILE * f)1576 void fitstable_print_missing(fitstable_t* tab, FILE* f) {
1577 int i;
1578 fprintf(f, "Missing required columns: ");
1579 for (i=0; i<ncols(tab); i++) {
1580 fitscol_t* col = getcol(tab, i);
1581 if (col->col == -1 && col->required) {
1582 fprintf(f, "%s ", col->colname);
1583 }
1584 }
1585 }
1586
fitstable_error_report_missing(fitstable_t * tab)1587 void fitstable_error_report_missing(fitstable_t* tab) {
1588 int i;
1589 sl* missing = sl_new(4);
1590 char* mstr;
1591 for (i=0; i<ncols(tab); i++) {
1592 fitscol_t* col = getcol(tab, i);
1593 if (col->col == -1 && col->required)
1594 sl_append(missing, col->colname);
1595 }
1596 mstr = sl_join(missing, ", ");
1597 sl_free2(missing);
1598 ERROR("Missing required columns: %s", mstr);
1599 free(mstr);
1600 }
1601
fitstable_create_table(fitstable_t * tab)1602 static void fitstable_create_table(fitstable_t* tab) {
1603 qfits_table* qt;
1604 int i;
1605
1606 qt = qfits_table_new("", QFITS_BINTABLE, 0, ncols(tab), 0);
1607 tab->table = qt;
1608
1609 for (i=0; i<ncols(tab); i++) {
1610 fitscol_t* col = getcol(tab, i);
1611 char* nil = "";
1612 int arraysize;
1613 assert(col->colname);
1614 arraysize = col->arraysize;
1615 if (col->fitstype == TFITS_BIN_TYPE_X)
1616 arraysize = col->arraysize * 8;
1617 fits_add_column(qt, i, col->fitstype, arraysize,
1618 col->units ? col->units : nil, col->colname);
1619 }
1620 }
1621
refill_buffer(void * userdata,void * buffer,unsigned int offset,unsigned int n)1622 static int refill_buffer(void* userdata, void* buffer, unsigned int offset, unsigned int n) {
1623 fitstable_t* tab = userdata;
1624 //logverb("fitstable.c:refill_buffer: offset %i, n %i\n", offset, n);
1625 if (fitstable_read_structs(tab, buffer, tab->br->elementsize, offset, n)) {
1626 ERROR("Error refilling FITS table read buffer");
1627 return -1;
1628 }
1629 return 0;
1630 }
1631
fitstable_use_buffered_reading(fitstable_t * tab,int elementsize,int Nbuffer)1632 void fitstable_use_buffered_reading(fitstable_t* tab, int elementsize, int Nbuffer) {
1633 if (tab->br) {
1634 assert(tab->br->elementsize == elementsize);
1635 buffered_read_resize(tab->br, Nbuffer);
1636 } else {
1637 tab->br = buffered_read_new(elementsize, Nbuffer, 0, refill_buffer, tab);
1638 }
1639 }
1640
fitstable_set_buffer_fill_function(fitstable_t * tab,int (* refill_buffer)(void * userdata,void * buffer,unsigned int offs,unsigned int nelems),void * userdata)1641 void fitstable_set_buffer_fill_function(fitstable_t* tab,
1642 int (*refill_buffer)(void* userdata, void* buffer, unsigned int offs, unsigned int nelems),
1643 void* userdata) {
1644 assert(tab->br);
1645 tab->br->refill_buffer = refill_buffer;
1646 tab->br->userdata = userdata;
1647 }
1648
fitstable_next_struct(fitstable_t * tab)1649 void* fitstable_next_struct(fitstable_t* tab) {
1650 if (!tab->br) return NULL;
1651 return buffered_read(tab->br);
1652 }
1653
fitstable_pushback(fitstable_t * tab)1654 int fitstable_pushback(fitstable_t* tab) {
1655 if (!tab->br) return -1;
1656 buffered_read_pushback(tab->br);
1657 return 0;
1658 }
1659
1660