source: branches/MarsMoreSimulationTruth/mcore/fits.h@ 19082

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