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

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