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

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