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

Last change on this file since 17048 was 17035, checked in by lyard, 11 years ago
Added error when using wrong fits class and adapted MRawFitsRead to deal with compressed .fz fits
File size: 30.8 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 gLog << "Here..." <<endl;
717 Constructor(fname, "", tableName, force);
718 if ((fTable.is_compressed && !force) ||
719 (fTable.name == "ZDrsCellOffsets" && !force))
720 {
721#ifdef __EXCEPTIONS
722 throw runtime_error("You are trying to read a compressed fits with the base fits class. Please use factfits instead.");
723#else
724 gLog << ___err___ << "ERROR - You are trying to read a compressed fits with the base fits class. Please use factfits instead." << endl;
725#endif
726 clear(rdstate()|ios::badbit);
727 }
728 }
729
730 fits(const string &fname, const string &fout, const string& tableName, bool force=false) : izstream(fname.c_str())
731 {
732 gLog << "There..." << endl;
733 Constructor(fname, fout, tableName, force);
734 if ((fTable.is_compressed && !force) ||
735 (fTable.name == "ZDrsCellOffsets" && !force))
736 {
737#ifdef __EXCEPTIONS
738 throw runtime_error("You are trying to read a compressed fits with the base fits class. Please use factfits instead.");
739#else
740 gLog << ___err___ << "ERROR - You are trying to read a compressed fits with the base fits class. Please use factfits instead." << endl;
741#endif
742 clear(rdstate()|ios::badbit);
743 }
744 }
745
746 fits() : izstream()
747 {
748
749 }
750
751 ~fits()
752 {
753 copy(istreambuf_iterator<char>(*this),
754 istreambuf_iterator<char>(),
755 ostreambuf_iterator<char>(fCopy));
756 }
757
758 virtual void StageRow(size_t row, char* dest)
759 {
760 // if (row!=fRow+1) // Fast seeking is ensured by izstream
761 seekg(fTable.offset+row*fTable.bytes_per_row);
762 read(dest, fTable.bytes_per_row);
763 //fin.clear(fin.rdstate()&~ios::eofbit);
764 }
765
766 virtual void WriteRowToCopyFile(size_t row)
767 {
768 if (row==fRow+1)
769 {
770 const uint8_t offset = (row*fTable.bytes_per_row)%4;
771
772 fChkData.add(fBufferRow);
773 if (fCopy.is_open() && fCopy.good())
774 fCopy.write(fBufferRow.data()+offset, fTable.bytes_per_row);
775 if (!fCopy)
776 clear(rdstate()|ios::badbit);
777 }
778 else
779 if (fCopy.is_open())
780 clear(rdstate()|ios::badbit);
781 }
782
783 void ZeroBufferForChecksum(vector<char>& vec, const uint64_t extraZeros=0)
784 {
785 auto ib = vec.begin();
786 auto ie = vec.end();
787
788 *ib++ = 0;
789 *ib++ = 0;
790 *ib++ = 0;
791 *ib = 0;
792
793 for (uint64_t i=0;i<extraZeros+8;i++)
794 *--ie = 0;
795 }
796
797 uint8_t ReadRow(size_t row)
798 {
799 // For the checksum we need everything to be correctly aligned
800 const uint8_t offset = (row*fTable.bytes_per_row)%4;
801
802 ZeroBufferForChecksum(fBufferRow);
803
804 StageRow(row, fBufferRow.data()+offset);
805
806 WriteRowToCopyFile(row);
807
808 fRow = row;
809
810 return offset;
811 }
812
813 template<size_t N>
814 void revcpy(char *dest, const char *src, const int &num)
815 {
816 const char *pend = src + num*N;
817 for (const char *ptr = src; ptr<pend; ptr+=N, dest+=N)
818 reverse_copy(ptr, ptr+N, dest);
819 }
820
821 virtual void MoveColumnDataToUserSpace(char *dest, const char *src, const Table::Column& c)
822 {
823 // Let the compiler do some optimization by
824 // knowing that we only have 1, 2, 4 and 8
825 switch (c.size)
826 {
827 case 1: memcpy (dest, src, c.bytes); break;
828 case 2: revcpy<2>(dest, src, c.num); break;
829 case 4: revcpy<4>(dest, src, c.num); break;
830 case 8: revcpy<8>(dest, src, c.num); break;
831 }
832 }
833
834#if !defined(__MARS__) && !defined(__CINT__)
835 virtual bool GetRow(size_t row, bool check=true)
836#else
837 virtual bool GetRowNum(size_t row, bool check=true)
838#endif
839 {
840 if (check && row>=fTable.num_rows)
841 return false;
842
843 const uint8_t offset = ReadRow(row);
844 if (!good())
845 return good();
846
847 const char *ptr = fBufferRow.data() + offset;
848
849 for (Addresses::const_iterator it=fAddresses.begin(); it!=fAddresses.end(); it++)
850 {
851 const Table::Column &c = it->second;
852
853 const char *src = ptr + c.offset;
854 char *dest = reinterpret_cast<char*>(it->first);
855
856 MoveColumnDataToUserSpace(dest, src, c);
857 }
858
859 return good();
860 }
861
862 bool GetNextRow(bool check=true)
863 {
864#if !defined(__MARS__) && !defined(__CINT__)
865 return GetRow(fRow+1, check);
866#else
867 return GetRowNum(fRow+1, check);
868#endif
869 }
870
871 virtual bool SkipNextRow()
872 {
873 seekg(fTable.offset+(++fRow)*fTable.bytes_per_row);
874 return good();
875 }
876
877 static bool Compare(const Address &p1, const Address &p2)
878 {
879 return p1.first>p2.first;
880 }
881
882 template<class T, class S>
883 const T &GetAs(const string &name)
884 {
885 return *reinterpret_cast<S*>(fPointers[name]);
886 }
887
888 void *SetPtrAddress(const string &name)
889 {
890 if (fTable.cols.count(name)==0)
891 {
892 ostringstream str;
893 str << "SetPtrAddress('" << name << "') - Column not found." << endl;
894#ifdef __EXCEPTIONS
895 throw runtime_error(str.str());
896#else
897 gLog << ___err___ << "ERROR - " << str.str() << endl;
898 return NULL;
899#endif
900 }
901
902 Pointers::const_iterator it = fPointers.find(name);
903 if (it!=fPointers.end())
904 return it->second;
905
906 fGarbage.emplace_back(fTable.cols[name].bytes);
907
908 void *ptr = fGarbage.back().data();
909
910 fPointers[name] = ptr;
911 fAddresses.emplace_back(ptr, fTable.cols[name]);
912 sort(fAddresses.begin(), fAddresses.end(), Compare);
913 return ptr;
914 }
915
916 template<typename T>
917 bool SetPtrAddress(const string &name, T *ptr, size_t cnt)
918 {
919 if (fTable.cols.count(name)==0)
920 {
921 ostringstream str;
922 str << "SetPtrAddress('" << name << "') - Column not found." << endl;
923#ifdef __EXCEPTIONS
924 throw runtime_error(str.str());
925#else
926 gLog << ___err___ << "ERROR - " << str.str() << endl;
927 return false;
928#endif
929 }
930
931 if (sizeof(T)!=fTable.cols[name].size)
932 {
933 ostringstream str;
934 str << "SetPtrAddress('" << name << "') - Element size mismatch: expected "
935 << fTable.cols[name].size << " from header, got " << sizeof(T) << endl;
936#ifdef __EXCEPTIONS
937 throw runtime_error(str.str());
938#else
939 gLog << ___err___ << "ERROR - " << str.str() << endl;
940 return false;
941#endif
942 }
943
944 if (cnt!=fTable.cols[name].num)
945 {
946 ostringstream str;
947 str << "SetPtrAddress('" << name << "') - Element count mismatch: expected "
948 << fTable.cols[name].num << " from header, got " << cnt << endl;
949#ifdef __EXCEPTIONS
950 throw runtime_error(str.str());
951#else
952 gLog << ___err___ << "ERROR - " << str.str() << endl;
953 return false;
954#endif
955 }
956
957 // if (fAddresses.count(ptr)>0)
958 // gLog << warn << "SetPtrAddress('" << name << "') - Pointer " << ptr << " already assigned." << endl;
959
960 //fAddresses[ptr] = fTable.cols[name];
961 fPointers[name] = ptr;
962 fAddresses.emplace_back(ptr, fTable.cols[name]);
963 sort(fAddresses.begin(), fAddresses.end(), Compare);
964 return true;
965 }
966
967 template<class T>
968 bool SetRefAddress(const string &name, T &ptr)
969 {
970 return SetPtrAddress(name, &ptr, sizeof(ptr)/sizeof(T));
971 }
972
973 template<typename T>
974 bool SetVecAddress(const string &name, vector<T> &vec)
975 {
976 return SetPtrAddress(name, vec.data(), vec.size());
977 }
978
979 template<typename T>
980 T Get(const string &key) const
981 {
982 return fTable.Get<T>(key);
983 }
984
985 template<typename T>
986 T Get(const string &key, const string &deflt) const
987 {
988 return fTable.Get<T>(key, deflt);
989 }
990
991 bool SetPtrAddress(const string &name, void *ptr)
992 {
993 if (fTable.cols.count(name)==0)
994 {
995 ostringstream str;
996 str <<"SetPtrAddress('" << name << "') - Column not found." << endl;
997#ifdef __EXCEPTIONS
998 throw runtime_error(str.str());
999#else
1000 gLog << ___err___ << "ERROR - " << str.str() << endl;
1001 return false;
1002#endif
1003 }
1004
1005 // if (fAddresses.count(ptr)>0)
1006 // gLog << warn << "SetPtrAddress('" << name << "') - Pointer " << ptr << " already assigned." << endl;
1007
1008 //fAddresses[ptr] = fTable.cols[name];
1009 fPointers[name] = ptr;
1010 fAddresses.emplace_back(ptr, fTable.cols[name]);
1011 sort(fAddresses.begin(), fAddresses.end(), Compare);
1012 return true;
1013 }
1014
1015 bool HasKey(const string &key) const { return fTable.HasKey(key); }
1016 bool HasColumn(const string& col) const { return fTable.HasColumn(col);}
1017 const Table::Columns &GetColumns() const { return fTable.GetColumns();}
1018 const Table::SortedColumns& GetSortedColumns() const { return fTable.sorted_cols;}
1019 const Table::Keys &GetKeys() const { return fTable.GetKeys();}
1020
1021 int64_t GetInt(const string &key) const { return fTable.Get<int64_t>(key); }
1022 uint64_t GetUInt(const string &key) const { return fTable.Get<uint64_t>(key); }
1023 double GetFloat(const string &key) const { return fTable.Get<double>(key); }
1024 string GetStr(const string &key) const { return fTable.Get<string>(key); }
1025
1026 size_t GetN(const string &key) const
1027 {
1028 return fTable.GetN(key);
1029 }
1030
1031// size_t GetNumRows() const { return fTable.num_rows; }
1032 size_t GetRow() const { return fRow==(size_t)-1 ? 0 : fRow; }
1033
1034 operator bool() const { return fTable && fTable.offset!=0; }
1035
1036 void PrintKeys() const { fTable.PrintKeys(); }
1037 void PrintColumns() const { fTable.PrintColumns(); }
1038
1039 bool IsHeaderOk() const { return fTable.datasum<0?false:(fChkHeader+Checksum(fTable.datasum)).valid(); }
1040 virtual bool IsFileOk() const { return (fChkHeader+fChkData).valid(); }
1041
1042 bool IsCompressedFITS() const { return fTable.is_compressed;}
1043
1044 virtual size_t GetNumRows() const
1045 {
1046 return fTable.Get<size_t>("NAXIS2");
1047 }
1048
1049 virtual size_t GetBytesPerRow() const
1050 {
1051 return fTable.Get<size_t>("NAXIS1");
1052 }
1053};
1054
1055#ifndef __MARS__
1056};
1057#endif
1058#endif
Note: See TracBrowser for help on using the repository browser.