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

Last change on this file since 18827 was 18594, checked in by tbretz, 8 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.