source: trunk/Mars/mcore/fits.h@ 17778

Last change on this file since 17778 was 17777, checked in by tbretz, 11 years ago
Solved the problem that so far cint does not define __MARS__; added an option to PrintKeys; remove all reserved keywords from the list of printed keys; some minor code cleanup.
File size: 31.4 KB
Line 
1#ifndef MARS_fits
2#define MARS_fits
3
4#include <stdint.h>
5
6#include <map>
7#include <string>
8#include <fstream>
9#include <sstream>
10#include <algorithm>
11#include <stdexcept>
12
13#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
14
15#ifndef __CINT__
16#include <unordered_map>
17#else
18#define off_t size_t
19namespace std
20{
21 template<class T, class S> class unordered_map<T, S>;
22}
23#endif
24
25#if defined(__MARS__) || defined(__CINT__)
26#include "MLog.h"
27#include "MLogManip.h"
28#define ___err___ err
29#define ___warn___ warn
30#define ___all___ all
31#else
32#include <vector>
33#include <iomanip>
34#include <iostream>
35#ifndef gLog
36#define gLog std::cerr
37#define ___err___ ""
38#define ___warn___ ""
39#define ___all___ ""
40#endif
41#endif
42
43#if defined(HAVE_ZLIB) || defined(__CINT__)
44#include "izstream.h"
45#else
46#include <fstream>
47#define izstream ifstream
48#warning Support for zipped FITS files disabled.
49#endif
50
51#include "FITS.h"
52#include "checksum.h"
53
54class fits : public izstream
55{
56public:
57 //I know I know, you're going to yiell that this does not belong here.
58 //It will belong in the global scope eventually, and it makes the coding of zfits much simpler this way.
59 enum Compression_t
60 {
61 kCompUnknown,
62 kCompFACT
63 };
64
65 struct Entry
66 {
67 char type;
68 std::string value;
69 std::string comment;
70 std::string fitsString;
71
72 template<typename T>
73 T Get() const
74 {
75 T t;
76
77 std::istringstream str(value);
78 str >> t;
79
80 return t;
81 }
82 };
83
84 struct Table
85 {
86 off_t offset;
87
88 bool is_compressed;
89
90 std::string name;
91 size_t bytes_per_row;
92 size_t num_rows;
93 size_t num_cols;
94 size_t total_bytes; // NAXIS1*NAXIS2
95
96 struct Column
97 {
98 size_t offset;
99 size_t num;
100 size_t size;
101 size_t bytes; // num*size
102 char type;
103 std::string unit;
104 Compression_t comp;
105 };
106
107 typedef std::map<std::string, Entry> Keys;
108 typedef std::map<std::string, Column> Columns;
109 typedef std::vector<Column> SortedColumns;
110
111 Columns cols;
112 SortedColumns sorted_cols;
113 Keys keys;
114
115 int64_t datasum;
116
117 std::string Trim(const std::string &str, char c=' ') const
118 {
119 // Trim Both leading and trailing spaces
120 const size_t pstart = str.find_first_not_of(c); // Find the first character position after excluding leading blank spaces
121 const size_t pend = str.find_last_not_of(c); // Find the first character position from reverse af
122
123 // if all spaces or empty return an empty string
124 if (std::string::npos==pstart || std::string::npos==pend)
125 return std::string();
126
127 return str.substr(pstart, pend-pstart+1);
128 }
129
130 bool Check(const std::string &key, char type, const std::string &value="") const
131 {
132 const Keys::const_iterator it = keys.find(key);
133 if (it==keys.end())
134 {
135 std::ostringstream str;
136 str << "Key '" << key << "' not found.";
137#ifdef __EXCEPTIONS
138 throw std::runtime_error(str.str());
139#else
140 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
141 return false;
142#endif
143 }
144
145 if (it->second.type!=type)
146 {
147 std::ostringstream str;
148 str << "Wrong type for key '" << key << "': expected " << type << ", found " << it->second.type << ".";
149#ifdef __EXCEPTIONS
150 throw std::runtime_error(str.str());
151#else
152 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
153 return false;
154#endif
155 }
156
157 if (!value.empty() && it->second.value!=value)
158 {
159 std::ostringstream str;
160 str << "Wrong value for key '" << key << "': expected " << value << ", found " << it->second.value << ".";
161#ifdef __EXCEPTIONS
162 throw std::runtime_error(str.str());
163#else
164 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
165 return false;
166#endif
167 }
168
169 return true;
170 }
171
172 Keys ParseBlock(const std::vector<std::string> &vec) const
173 {
174 Keys rc;
175
176 for (unsigned int i=0; i<vec.size(); i++)
177 {
178 const std::string key = Trim(vec[i].substr(0,8));
179 // Keywords without a value, like COMMENT / HISTORY
180 if (vec[i].substr(8,2)!="= ")
181 continue;
182
183 char type = 0;
184
185 std::string com;
186 std::string val = Trim(vec[i].substr(10));
187
188 if (val[0]=='\'')
189 {
190 // First skip all '' in the string
191 size_t p = 1;
192 while (1)
193 {
194 const size_t pp = val.find_first_of('\'', p);
195 if (pp==std::string::npos)
196 break;
197
198 p = val[pp+1]=='\'' ? pp+2 : pp+1;
199 }
200
201 // Now find the comment
202 const size_t ppp = val.find_first_of('/', p);
203
204 // Set value, comment and type
205 // comments could be just spaces. take care of this.
206 if (ppp!=std::string::npos && val.size()!=ppp+1)
207 com = Trim(val.substr(ppp+1));
208
209 val = Trim(val.substr(1, p-2));
210 type = 'T';
211 }
212 else
213 {
214 const size_t p = val.find_first_of('/');
215
216 if (p!=std::string::npos && val.size()!=p+1)
217 com = Trim(val.substr(p+2));
218
219 val = Trim(val.substr(0, p));
220
221 if (val.empty() || val.find_first_of('T')!=std::string::npos || val.find_first_of('F')!=std::string::npos)
222 type = 'B';
223 else
224 type = val.find_last_of('.')==std::string::npos ? 'I' : 'F';
225 }
226
227 const Entry e = { type, val, com, vec[i] };
228
229 rc[key] = e;
230 }
231
232 return rc;
233 }
234
235 Table() : offset(0), is_compressed(false) { }
236 Table(const std::vector<std::string> &vec, off_t off) : offset(off),
237 keys(ParseBlock(vec))
238 {
239 is_compressed = HasKey("ZTABLE") && Check("ZTABLE", 'B', "T");
240
241 if (!Check("XTENSION", 'T', "BINTABLE") ||
242 !Check("NAXIS", 'I', "2") ||
243 !Check("BITPIX", 'I', "8") ||
244 !Check("GCOUNT", 'I', "1") ||
245 !Check("EXTNAME", 'T') ||
246 !Check("NAXIS1", 'I') ||
247 !Check("NAXIS2", 'I') ||
248 !Check("TFIELDS", 'I'))
249 return;
250
251 if (is_compressed)
252 {
253 if (!Check("ZNAXIS1", 'I') ||
254 !Check("ZNAXIS2", 'I') ||
255 !Check("ZPCOUNT", 'I', "0"))
256 return;
257 }
258 else
259 {
260 if (!Check("PCOUNT", 'I', "0"))
261 return;
262 }
263
264 total_bytes = Get<size_t>("NAXIS1")*Get<size_t>("NAXIS2");
265 bytes_per_row = is_compressed ? Get<size_t>("ZNAXIS1") : Get<size_t>("NAXIS1");
266 num_rows = is_compressed ? Get<size_t>("ZNAXIS2") : Get<size_t>("NAXIS2");
267 num_cols = Get<size_t>("TFIELDS");
268 datasum = Get<int64_t>("DATASUM", -1);
269 size_t bytes = 0;
270
271 const std::string tFormName = is_compressed ? "ZFORM" : "TFORM";
272 for (long long unsigned int i=1; i<=num_cols; i++)
273 {
274 const std::string num(std::to_string(i));
275
276 if (!Check("TTYPE"+num, 'T') ||
277 !Check(tFormName+num, 'T'))
278 return;
279
280 const std::string id = Get<std::string>("TTYPE"+num);
281 const std::string fmt = Get<std::string>(tFormName+num);
282 const std::string unit = Get<std::string>("TUNIT"+num, "");
283 const std::string comp = Get<std::string>("ZCTYP"+num, "");
284
285 Compression_t compress = kCompUnknown;
286 if (comp == "FACT")
287 compress = kCompFACT;
288
289 std::istringstream sin(fmt);
290 int n = 0;
291 sin >> n;
292 if (!sin)
293 n = 1;
294
295 const char type = fmt[fmt.length()-1];
296
297 size_t size = 0;
298 switch (type)
299 {
300 // We could use negative values to mark floats
301 // otheriwse we could just cast them to int64_t?
302 case 'L': // logical
303 case 'A': // char
304 case 'B': size = 1; break; // byte
305 case 'I': size = 2; break; // short
306 case 'J': size = 4; break; // int
307 case 'K': size = 8; break; // long long
308 case 'E': size = 4; break; // float
309 case 'D': size = 8; break; // double
310 // case 'X': size = n; break; // bits (n=number of bytes needed to contain all bits)
311 // case 'C': size = 8; break; // complex float
312 // case 'M': size = 16; break; // complex double
313 // case 'P': size = 8; break; // array descriptor (32bit)
314 // case 'Q': size = 16; break; // array descriptor (64bit)
315 default:
316 {
317 std::ostringstream str;
318 str << "FITS format TFORM='" << fmt << "' not yet supported.";
319#ifdef __EXCEPTIONS
320 throw std::runtime_error(str.str());
321#else
322 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
323 return;
324#endif
325 }
326 }
327
328 const Table::Column col = { bytes, n, size, n*size, type, unit, compress};
329
330 cols[id] = col;
331 sorted_cols.emplace_back(col);
332 bytes += n*size;
333 }
334
335 if (bytes!=bytes_per_row)
336 {
337 std::ostringstream str;
338 str << "Sum of bytes in columns [" << bytes << "] does not match (Z)NAXIS2 [" << bytes_per_row << "].";
339
340#ifdef __EXCEPTIONS
341 throw std::runtime_error(str.str());
342#else
343 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
344 return;
345#endif
346 }
347
348 name = Get<std::string>("EXTNAME");
349 }
350
351 void PrintKeys(bool display_all=false) const
352 {
353 for (Keys::const_iterator it=keys.cbegin(); it!=keys.cend(); it++)
354 {
355 if (!display_all && FITS::IsReservedKeyWord(it->first))
356 continue;
357
358 gLog << ___all___ << std::setw(2) << it->second.type << '|' << it->first << '=' << it->second.value << '/' << it->second.comment << '|' << std::endl;
359 }
360 }
361
362 void PrintColumns() const
363 {
364 typedef std::map<std::pair<size_t, std::string>, Column> Sorted;
365
366 Sorted sorted;
367
368 for (Columns::const_iterator it=cols.cbegin(); it!=cols.cend(); it++)
369 sorted[std::make_pair(it->second.offset, it->first)] = it->second;
370
371 for (Sorted::const_iterator it=sorted.cbegin(); it!=sorted.cend(); it++)
372 {
373 gLog << ___all___ << std::setw(6) << it->second.offset << "| ";
374 gLog << it->second.num << 'x';
375 switch (it->second.type)
376 {
377 case 'A': gLog << "char(8)"; break;
378 case 'L': gLog << "bool(8)"; break;
379 case 'B': gLog << "byte(8)"; break;
380 case 'I': gLog << "short(16)"; break;
381 case 'J': gLog << "int(32)"; break;
382 case 'K': gLog << "int(64)"; break;
383 case 'E': gLog << "float(32)"; break;
384 case 'D': gLog << "double(64)"; break;
385 }
386 gLog << ": " << it->first.second << " [" << it->second.unit << "]" << std::endl;
387 }
388 }
389
390 operator bool() const { return !name.empty(); }
391
392 bool HasKey(const std::string &key) const
393 {
394 return keys.find(key)!=keys.end();
395 }
396
397 bool HasColumn(const std::string& col) const
398 {
399 return cols.find(col)!=cols.end();
400 }
401
402 const Columns &GetColumns() const
403 {
404 return cols;
405 }
406
407 const Keys &GetKeys() const
408 {
409 return keys;
410 }
411
412 // Values of keys are always signed
413 template<typename T>
414 T Get(const std::string &key) const
415 {
416 const Keys::const_iterator it = keys.find(key);
417 if (it==keys.end())
418 {
419 std::ostringstream str;
420 str << "Key '" << key << "' not found.";
421#ifdef __EXCEPTIONS
422 throw std::runtime_error(str.str());
423#else
424 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
425 return T();
426#endif
427 }
428 return it->second.Get<T>();
429 }
430
431 // Values of keys are always signed
432 template<typename T>
433 T Get(const std::string &key, const T &deflt) const
434 {
435 const Keys::const_iterator it = keys.find(key);
436 return it==keys.end() ? deflt :it->second.Get<T>();
437 }
438
439 size_t GetN(const std::string &key) const
440 {
441 const Columns::const_iterator it = cols.find(key);
442 return it==cols.end() ? 0 : it->second.num;
443 }
444
445
446
447 // There may be a gap between the main table and the start of the heap:
448 // this computes the offset
449 streamoff GetHeapShift() const
450 {
451 if (!HasKey("ZHEAPPTR"))
452 return 0;
453
454 const size_t shift = Get<size_t>("ZHEAPPTR");
455 return shift <= total_bytes ? 0 : shift - total_bytes;
456 }
457
458 // return total number of bytes 'all inclusive'
459 streamoff GetTotalBytes() const
460 {
461 //get offset of special data area from start of main table
462 const streamoff shift = GetHeapShift();
463
464 //and special data area size
465 const streamoff size = HasKey("PCOUNT") ? Get<streamoff>("PCOUNT") : 0;
466
467 // Get the total size
468 const streamoff total = total_bytes + size + shift;
469
470 // check for padding
471 if (total%2880==0)
472 return total;
473
474 // padding necessary
475 return total + (2880 - (total%2880));
476 }
477 };
478
479protected:
480 std::ofstream fCopy;
481 std::vector<std::string> fListOfTables; // List of skipped tables. Last table is open table
482
483 Table fTable;
484
485 typedef std::pair<void*, Table::Column> Address;
486 typedef std::vector<Address> Addresses;
487 //map<void*, Table::Column> fAddresses;
488 Addresses fAddresses;
489
490 typedef std::unordered_map<std::string, void*> Pointers;
491 Pointers fPointers;
492
493 std::vector<std::vector<char>> fGarbage;
494
495 std::vector<char> fBufferRow;
496 std::vector<char> fBufferDat;
497
498 size_t fRow;
499
500 Checksum fChkHeader;
501 Checksum fChkData;
502
503 bool ReadBlock(std::vector<std::string> &vec)
504 {
505 int endtag = 0;
506 for (int i=0; i<36; i++)
507 {
508 char c[81];
509 c[80] = 0;
510 read(c, 80);
511 if (!good())
512 break;
513
514 fChkHeader.add(c, 80);
515
516// if (c[0]==0)
517// return vector<string>();
518
519 std::string str(c);
520
521// if (!str.empty())
522// cout << setw(2) << i << "|" << str << "|" << (endtag?'-':'+') << endl;
523
524 if (endtag==2 || str=="END ")
525 {
526 endtag = 2; // valid END tag found
527 continue;
528 }
529
530 if (endtag==1 || str==" ")
531 {
532 endtag = 1; // end tag not found, but expected to be there
533 continue;
534 }
535
536 vec.emplace_back(str);
537 }
538
539 // Make sure that no empty vector is returned
540 if (endtag && vec.size()%36==0)
541 vec.emplace_back("END = '' / ");
542
543 return endtag==2;
544 }
545
546 std::string Compile(const std::string &key, int16_t i=-1) const
547 {
548#if GCC_VERSION < 40603
549 return i<0 ? key : key+std::to_string((long long int)(i));
550#else
551 return i<0 ? key : key+std::to_string(i);
552#endif
553 }
554
555 void Constructor(const std::string &fname, std::string fout="", const std::string& tableName="", bool force=false)
556 {
557 char simple[10];
558 read(simple, 10);
559 if (!good())
560 return;
561
562 if (memcmp(simple, "SIMPLE = ", 10))
563 {
564 clear(rdstate()|std::ios::badbit);
565#ifdef __EXCEPTIONS
566 throw std::runtime_error("File is not a FITS file.");
567#else
568 gLog << ___err___ << "ERROR - File is not a FITS file." << std::endl;
569 return;
570#endif
571 }
572
573 seekg(0);
574
575 while (good())
576 {
577 std::vector<std::string> block;
578 while (1)
579 {
580 // If we search for a table, we implicitly assume that
581 // not finding the table is not an error. The user
582 // can easily check that by eof() && !bad()
583 peek();
584 if (eof() && !bad() && !tableName.empty())
585 {
586 break;
587 }
588 // FIXME: Set limit on memory consumption
589 const int rc = ReadBlock(block);
590 if (!good())
591 {
592 clear(rdstate()|std::ios::badbit);
593#ifdef __EXCEPTIONS
594 throw std::runtime_error("FITS file corrupted.");
595#else
596 gLog << ___err___ << "ERROR - FITS file corrupted." << std::endl;
597 return;
598#endif
599 }
600
601 if (block.size()%36)
602 {
603 if (!rc && !force)
604 {
605 clear(rdstate()|std::ios::badbit);
606#ifdef __EXCEPTIONS
607 throw std::runtime_error("END keyword missing in FITS header.");
608#else
609 gLog << ___err___ << "ERROR - END keyword missing in FITS file... file might be corrupted." << std::endl;
610 return;
611#endif
612 }
613 break;
614 }
615 }
616
617 if (block.empty())
618 break;
619
620 if (block[0].substr(0, 9)=="SIMPLE =")
621 {
622 fChkHeader.reset();
623 continue;
624 }
625
626 if (block[0].substr(0, 9)=="XTENSION=")
627 {
628 fTable = Table(block, tellg());
629 fRow = (size_t)-1;
630
631 if (!fTable)
632 {
633 clear(rdstate()|std::ios::badbit);
634 return;
635 }
636
637 const std::string &tname = fTable.Get<std::string>("EXTNAME");
638
639 fListOfTables.emplace_back(tname);
640
641 // Check for table name. Skip until eof or requested table are found.
642 // skip the current table?
643 if ((!tableName.empty() && tableName!=tname) || (tableName.empty() && "ZDrsCellOffsets"==tname))
644 {
645 const streamoff skip = fTable.GetTotalBytes();
646 seekg(skip, std::ios_base::cur);
647
648 fChkHeader.reset();
649
650 continue;
651 }
652
653 fBufferRow.resize(fTable.bytes_per_row + 8-fTable.bytes_per_row%4);
654 fBufferDat.resize(fTable.bytes_per_row);
655
656 break;
657 }
658 }
659
660 if (fout.empty())
661 return;
662
663 if (*fout.rbegin()=='/')
664 {
665 const size_t p = fname.find_last_of('/');
666 fout.append(fname.substr(p+1));
667 }
668
669 fCopy.open(fout);
670 if (!fCopy)
671 {
672 clear(rdstate()|std::ios::badbit);
673#ifdef __EXCEPTIONS
674 throw std::runtime_error("Could not open output file.");
675#else
676 gLog << ___err___ << "ERROR - Failed to open output file." << std::endl;
677 return;
678#endif
679 }
680
681 const streampos p = tellg();
682 seekg(0);
683
684 std::vector<char> buf(p);
685 read(buf.data(), p);
686
687 fCopy.write(buf.data(), p);
688 if (!fCopy)
689 clear(rdstate()|std::ios::badbit);
690 }
691
692public:
693 fits(const std::string &fname, const std::string& tableName="", bool force=false) : izstream(fname.c_str())
694 {
695 Constructor(fname, "", tableName, force);
696 if ((fTable.is_compressed ||fTable.name=="ZDrsCellOffsets") && !force)
697 {
698#ifdef __EXCEPTIONS
699 throw std::runtime_error("You are trying to read a compressed fits with the base fits class. Please use factfits instead.");
700#else
701 gLog << ___err___ << "ERROR - You are trying to read a compressed fits with the base fits class. Please use factfits instead." << std::endl;
702#endif
703 clear(rdstate()|std::ios::badbit);
704 }
705 }
706
707 fits(const std::string &fname, const std::string &fout, const std::string& tableName, bool force=false) : izstream(fname.c_str())
708 {
709 Constructor(fname, fout, tableName, force);
710 if ((fTable.is_compressed || fTable.name=="ZDrsCellOffsets") && !force)
711 {
712#ifdef __EXCEPTIONS
713 throw std::runtime_error("You are trying to read a compressed fits with the base fits class. Please use factfits instead.");
714#else
715 gLog << ___err___ << "ERROR - You are trying to read a compressed fits with the base fits class. Please use factfits instead." << std::endl;
716#endif
717 clear(rdstate()|std::ios::badbit);
718 }
719 }
720
721 fits() : izstream()
722 {
723
724 }
725
726 ~fits()
727 {
728 std::copy(std::istreambuf_iterator<char>(*this),
729 std::istreambuf_iterator<char>(),
730 std::ostreambuf_iterator<char>(fCopy));
731 }
732
733 virtual void StageRow(size_t row, char* dest)
734 {
735 // if (row!=fRow+1) // Fast seeking is ensured by izstream
736 seekg(fTable.offset+row*fTable.bytes_per_row);
737 read(dest, fTable.bytes_per_row);
738 //fin.clear(fin.rdstate()&~ios::eofbit);
739 }
740
741 virtual void WriteRowToCopyFile(size_t row)
742 {
743 if (row==fRow+1)
744 {
745 const uint8_t offset = (row*fTable.bytes_per_row)%4;
746
747 fChkData.add(fBufferRow);
748 if (fCopy.is_open() && fCopy.good())
749 fCopy.write(fBufferRow.data()+offset, fTable.bytes_per_row);
750 if (!fCopy)
751 clear(rdstate()|std::ios::badbit);
752 }
753 else
754 if (fCopy.is_open())
755 clear(rdstate()|std::ios::badbit);
756 }
757
758 void ZeroBufferForChecksum(std::vector<char>& vec, const uint64_t extraZeros=0)
759 {
760 auto ib = vec.begin();
761 auto ie = vec.end();
762
763 *ib++ = 0;
764 *ib++ = 0;
765 *ib++ = 0;
766 *ib = 0;
767
768 for (uint64_t i=0;i<extraZeros+8;i++)
769 *--ie = 0;
770 }
771
772 uint8_t ReadRow(size_t row)
773 {
774 // For the checksum we need everything to be correctly aligned
775 const uint8_t offset = (row*fTable.bytes_per_row)%4;
776
777 ZeroBufferForChecksum(fBufferRow);
778
779 StageRow(row, fBufferRow.data()+offset);
780
781 WriteRowToCopyFile(row);
782
783 fRow = row;
784
785 return offset;
786 }
787
788 template<size_t N>
789 void revcpy(char *dest, const char *src, const int &num)
790 {
791 const char *pend = src + num*N;
792 for (const char *ptr = src; ptr<pend; ptr+=N, dest+=N)
793 std::reverse_copy(ptr, ptr+N, dest);
794 }
795
796 virtual void MoveColumnDataToUserSpace(char *dest, const char *src, const Table::Column& c)
797 {
798 // Let the compiler do some optimization by
799 // knowing that we only have 1, 2, 4 and 8
800 switch (c.size)
801 {
802 case 1: memcpy (dest, src, c.bytes); break;
803 case 2: revcpy<2>(dest, src, c.num); break;
804 case 4: revcpy<4>(dest, src, c.num); break;
805 case 8: revcpy<8>(dest, src, c.num); break;
806 }
807 }
808
809 virtual bool GetRow(size_t row, bool check=true)
810 {
811 if (check && row>=fTable.num_rows)
812 return false;
813
814 const uint8_t offset = ReadRow(row);
815 if (!good())
816 return good();
817
818 const char *ptr = fBufferRow.data() + offset;
819
820 for (Addresses::const_iterator it=fAddresses.cbegin(); it!=fAddresses.cend(); it++)
821 {
822 const Table::Column &c = it->second;
823
824 const char *src = ptr + c.offset;
825 char *dest = reinterpret_cast<char*>(it->first);
826
827 MoveColumnDataToUserSpace(dest, src, c);
828 }
829
830 return good();
831 }
832
833 bool GetNextRow(bool check=true)
834 {
835 return GetRow(fRow+1, check);
836 }
837
838 virtual bool SkipNextRow()
839 {
840 seekg(fTable.offset+(++fRow)*fTable.bytes_per_row);
841 return good();
842 }
843
844 static bool Compare(const Address &p1, const Address &p2)
845 {
846 return p1.first>p2.first;
847 }
848
849 template<class T, class S>
850 const T &GetAs(const std::string &name)
851 {
852 return *reinterpret_cast<S*>(fPointers[name]);
853 }
854
855 void *SetPtrAddress(const std::string &name)
856 {
857 if (fTable.cols.count(name)==0)
858 {
859 std::ostringstream str;
860 str << "SetPtrAddress('" << name << "') - Column not found.";
861#ifdef __EXCEPTIONS
862 throw std::runtime_error(str.str());
863#else
864 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
865 return NULL;
866#endif
867 }
868
869 Pointers::const_iterator it = fPointers.find(name);
870 if (it!=fPointers.end())
871 return it->second;
872
873 fGarbage.emplace_back(fTable.cols[name].bytes);
874
875 void *ptr = fGarbage.back().data();
876
877 fPointers[name] = ptr;
878 fAddresses.emplace_back(ptr, fTable.cols[name]);
879 sort(fAddresses.begin(), fAddresses.end(), Compare);
880 return ptr;
881 }
882
883 template<typename T>
884 bool SetPtrAddress(const std::string &name, T *ptr, size_t cnt)
885 {
886 if (fTable.cols.count(name)==0)
887 {
888 std::ostringstream str;
889 str << "SetPtrAddress('" << name << "') - Column not found.";
890#ifdef __EXCEPTIONS
891 throw std::runtime_error(str.str());
892#else
893 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
894 return false;
895#endif
896 }
897
898 if (sizeof(T)!=fTable.cols[name].size)
899 {
900 std::ostringstream str;
901 str << "SetPtrAddress('" << name << "') - Element size mismatch: expected "
902 << fTable.cols[name].size << " from header, got " << sizeof(T);
903#ifdef __EXCEPTIONS
904 throw std::runtime_error(str.str());
905#else
906 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
907 return false;
908#endif
909 }
910
911 if (cnt!=fTable.cols[name].num)
912 {
913 std::ostringstream str;
914 str << "SetPtrAddress('" << name << "') - Element count mismatch: expected "
915 << fTable.cols[name].num << " from header, got " << cnt;
916#ifdef __EXCEPTIONS
917 throw std::runtime_error(str.str());
918#else
919 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
920 return false;
921#endif
922 }
923
924 // if (fAddresses.count(ptr)>0)
925 // gLog << warn << "SetPtrAddress('" << name << "') - Pointer " << ptr << " already assigned." << endl;
926
927 //fAddresses[ptr] = fTable.cols[name];
928 fPointers[name] = ptr;
929 fAddresses.emplace_back(ptr, fTable.cols[name]);
930 sort(fAddresses.begin(), fAddresses.end(), Compare);
931 return true;
932 }
933
934 template<class T>
935 bool SetRefAddress(const std::string &name, T &ptr)
936 {
937 return SetPtrAddress(name, &ptr, sizeof(ptr)/sizeof(T));
938 }
939
940 template<typename T>
941 bool SetVecAddress(const std::string &name, std::vector<T> &vec)
942 {
943 return SetPtrAddress(name, vec.data(), vec.size());
944 }
945
946 template<typename T>
947 T Get(const std::string &key) const
948 {
949 return fTable.Get<T>(key);
950 }
951
952 template<typename T>
953 T Get(const std::string &key, const std::string &deflt) const
954 {
955 return fTable.Get<T>(key, deflt);
956 }
957
958 bool SetPtrAddress(const std::string &name, void *ptr, size_t cnt=0)
959 {
960 if (fTable.cols.count(name)==0)
961 {
962 std::ostringstream str;
963 str <<"SetPtrAddress('" << name << "') - Column not found.";
964#ifdef __EXCEPTIONS
965 throw std::runtime_error(str.str());
966#else
967 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
968 return false;
969#endif
970 }
971
972 if (cnt && cnt!=fTable.cols[name].num)
973 {
974 std::ostringstream str;
975 str << "SetPtrAddress('" << name << "') - Element count mismatch: expected "
976 << fTable.cols[name].num << " from header, got " << cnt;
977#ifdef __EXCEPTIONS
978 throw std::runtime_error(str.str());
979#else
980 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
981 return false;
982#endif
983 }
984
985 // if (fAddresses.count(ptr)>0)
986 // gLog << warn << "SetPtrAddress('" << name << "') - Pointer " << ptr << " already assigned." << endl;
987
988 //fAddresses[ptr] = fTable.cols[name];
989 fPointers[name] = ptr;
990 fAddresses.emplace_back(ptr, fTable.cols[name]);
991 sort(fAddresses.begin(), fAddresses.end(), Compare);
992 return true;
993 }
994
995 bool HasKey(const std::string &key) const { return fTable.HasKey(key); }
996 bool HasColumn(const std::string& col) const { return fTable.HasColumn(col);}
997 const Table::Columns &GetColumns() const { return fTable.GetColumns();}
998 const Table::SortedColumns& GetSortedColumns() const { return fTable.sorted_cols;}
999 const Table::Keys &GetKeys() const { return fTable.GetKeys();}
1000
1001 int64_t GetInt(const std::string &key) const { return fTable.Get<int64_t>(key); }
1002 uint64_t GetUInt(const std::string &key) const { return fTable.Get<uint64_t>(key); }
1003 double GetFloat(const std::string &key) const { return fTable.Get<double>(key); }
1004 std::string GetStr(const std::string &key) const { return fTable.Get<std::string>(key); }
1005
1006 size_t GetN(const std::string &key) const
1007 {
1008 return fTable.GetN(key);
1009 }
1010
1011// size_t GetNumRows() const { return fTable.num_rows; }
1012 size_t GetRow() const { return fRow==(size_t)-1 ? 0 : fRow; }
1013
1014 operator bool() const { return fTable && fTable.offset!=0; }
1015
1016 void PrintKeys(bool all_keys=false) const { fTable.PrintKeys(all_keys); }
1017 void PrintColumns() const { fTable.PrintColumns(); }
1018
1019 bool IsHeaderOk() const { return fTable.datasum<0?false:(fChkHeader+Checksum(fTable.datasum)).valid(); }
1020 virtual bool IsFileOk() const { return (fChkHeader+fChkData).valid(); }
1021
1022 bool IsCompressedFITS() const { return fTable.is_compressed;}
1023
1024 virtual size_t GetNumRows() const
1025 {
1026 return fTable.Get<size_t>("NAXIS2");
1027 }
1028
1029 virtual size_t GetBytesPerRow() const
1030 {
1031 return fTable.Get<size_t>("NAXIS1");
1032 }
1033
1034 const std::vector<std::string> &GetTables() const
1035 {
1036 return fListOfTables;
1037 }
1038};
1039
1040#endif
Note: See TracBrowser for help on using the repository browser.