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

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