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

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