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

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