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

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