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

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