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

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