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

Last change on this file since 17751 was 17750, checked in by tbretz, 11 years ago
Improved error message.
File size: 31.9 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 std::ostringstream str;
338 str << "Sum of bytes in columns [" << bytes << "] does not match (Z)NAXIS2 [" << bytes_per_row << "].";
339
340#ifdef __EXCEPTIONS
341 throw std::runtime_error(str.str());
342#else
343 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
344 return;
345#endif
346 }
347
348 name = Get<std::string>("EXTNAME");
349 }
350
351 void PrintKeys(bool display_all=false) const
352 {
353 for (Keys::const_iterator it=keys.cbegin(); it!=keys.cend(); it++)
354 {
355 if (!display_all &&
356 (it->first.substr(0, 6)=="TTYPE" ||
357 it->first.substr(0, 6)=="TFORM" ||
358 it->first.substr(0, 6)=="TUNIT" ||
359 it->first=="TFIELDS" ||
360 it->first=="XTENSION" ||
361 it->first=="NAXIS" ||
362 it->first=="BITPIX" ||
363 it->first=="PCOUNT" ||
364 it->first=="GCOUNT")
365 )
366 continue;
367
368 gLog << ___all___ << std::setw(2) << it->second.type << '|' << it->first << '=' << it->second.value << '/' << it->second.comment << '|' << std::endl;
369 }}
370
371 void PrintColumns() const
372 {
373 typedef std::map<std::pair<size_t, std::string>, Column> Sorted;
374
375 Sorted sorted;
376
377 for (Columns::const_iterator it=cols.cbegin(); it!=cols.cend(); it++)
378 sorted[std::make_pair(it->second.offset, it->first)] = it->second;
379
380 for (Sorted::const_iterator it=sorted.cbegin(); it!=sorted.cend(); it++)
381 {
382 gLog << ___all___ << std::setw(6) << it->second.offset << "| ";
383 gLog << it->second.num << 'x';
384 switch (it->second.type)
385 {
386 case 'A': gLog << "char(8)"; break;
387 case 'L': gLog << "bool(8)"; break;
388 case 'B': gLog << "byte(8)"; break;
389 case 'I': gLog << "short(16)"; break;
390 case 'J': gLog << "int(32)"; break;
391 case 'K': gLog << "int(64)"; break;
392 case 'E': gLog << "float(32)"; break;
393 case 'D': gLog << "double(64)"; break;
394 }
395 gLog << ": " << it->first.second << " [" << it->second.unit << "]" << std::endl;
396 }
397 }
398
399 operator bool() const { return !name.empty(); }
400
401 bool HasKey(const std::string &key) const
402 {
403 return keys.find(key)!=keys.end();
404 }
405
406 bool HasColumn(const std::string& col) const
407 {
408 return cols.find(col)!=cols.end();
409 }
410
411 const Columns &GetColumns() const
412 {
413 return cols;
414 }
415
416 const Keys &GetKeys() const
417 {
418 return keys;
419 }
420
421 // Values of keys are always signed
422 template<typename T>
423 T Get(const std::string &key) const
424 {
425 const std::map<std::string,Entry>::const_iterator it = keys.find(key);
426 if (it==keys.end())
427 {
428 std::ostringstream str;
429 str << "Key '" << key << "' not found.";
430#ifdef __EXCEPTIONS
431 throw std::runtime_error(str.str());
432#else
433 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
434 return T();
435#endif
436 }
437 return it->second.Get<T>();
438 }
439
440 // Values of keys are always signed
441 template<typename T>
442 T Get(const std::string &key, const T &deflt) const
443 {
444 const std::map<std::string,Entry>::const_iterator it = keys.find(key);
445 return it==keys.end() ? deflt :it->second.Get<T>();
446 }
447
448 size_t GetN(const std::string &key) const
449 {
450 const Columns::const_iterator it = cols.find(key);
451 return it==cols.end() ? 0 : it->second.num;
452 }
453
454
455
456 // There may be a gap between the main table and the start of the heap:
457 // this computes the offset
458 streamoff GetHeapShift() const
459 {
460 if (!HasKey("ZHEAPPTR"))
461 return 0;
462
463 const size_t shift = Get<size_t>("ZHEAPPTR");
464 return shift <= total_bytes ? 0 : shift - total_bytes;
465 }
466
467 // return total number of bytes 'all inclusive'
468 streamoff GetTotalBytes() const
469 {
470 //get offset of special data area from start of main table
471 const streamoff shift = GetHeapShift();
472
473 //and special data area size
474 const streamoff size = HasKey("PCOUNT") ? Get<streamoff>("PCOUNT") : 0;
475
476 // Get the total size
477 const streamoff total = total_bytes + size + shift;
478
479 // check for padding
480 if (total%2880==0)
481 return total;
482
483 // padding necessary
484 return total + (2880 - (total%2880));
485 }
486 };
487
488protected:
489 std::ofstream fCopy;
490 std::vector<std::string> fListOfTables; // List of skipped tables. Last table is open table
491
492 Table fTable;
493
494 typedef std::pair<void*, Table::Column> Address;
495 typedef std::vector<Address> Addresses;
496 //map<void*, Table::Column> fAddresses;
497 Addresses fAddresses;
498
499 typedef std::unordered_map<std::string, void*> Pointers;
500 Pointers fPointers;
501
502 std::vector<std::vector<char>> fGarbage;
503
504 std::vector<char> fBufferRow;
505 std::vector<char> fBufferDat;
506
507 size_t fRow;
508
509 Checksum fChkHeader;
510 Checksum fChkData;
511
512 bool ReadBlock(std::vector<std::string> &vec)
513 {
514 int endtag = 0;
515 for (int i=0; i<36; i++)
516 {
517 char c[81];
518 c[80] = 0;
519 read(c, 80);
520 if (!good())
521 break;
522
523 fChkHeader.add(c, 80);
524
525// if (c[0]==0)
526// return vector<string>();
527
528 std::string str(c);
529
530// if (!str.empty())
531// cout << setw(2) << i << "|" << str << "|" << (endtag?'-':'+') << endl;
532
533 if (endtag==2 || str=="END ")
534 {
535 endtag = 2; // valid END tag found
536 continue;
537 }
538
539 if (endtag==1 || str==" ")
540 {
541 endtag = 1; // end tag not found, but expected to be there
542 continue;
543 }
544
545 vec.push_back(str);
546 }
547
548 // Make sure that no empty vector is returned
549 if (endtag && vec.size()%36==0)
550 vec.emplace_back("END = '' / ");
551
552 return endtag==2;
553 }
554
555 std::string Compile(const std::string &key, int16_t i=-1) const
556 {
557#if GCC_VERSION < 40603
558 return i<0 ? key : key+std::to_string((long long int)(i));
559#else
560 return i<0 ? key : key+std::to_string(i);
561#endif
562 }
563
564 void Constructor(const std::string &fname, std::string fout="", const std::string& tableName="", bool force=false)
565 {
566 char simple[10];
567 read(simple, 10);
568 if (!good())
569 return;
570
571 if (memcmp(simple, "SIMPLE = ", 10))
572 {
573 clear(rdstate()|std::ios::badbit);
574#ifdef __EXCEPTIONS
575 throw std::runtime_error("File is not a FITS file.");
576#else
577 gLog << ___err___ << "ERROR - File is not a FITS file." << std::endl;
578 return;
579#endif
580 }
581
582 seekg(0);
583
584 while (good())
585 {
586 std::vector<std::string> block;
587 while (1)
588 {
589 // If we search for a table, we implicitly assume that
590 // not finding the table is not an error. The user
591 // can easily check that by eof() && !bad()
592 peek();
593 if (eof() && !bad() && !tableName.empty())
594 {
595 break;
596 }
597 // FIXME: Set limit on memory consumption
598 const int rc = ReadBlock(block);
599 if (!good())
600 {
601 clear(rdstate()|std::ios::badbit);
602#ifdef __EXCEPTIONS
603 throw std::runtime_error("FITS file corrupted.");
604#else
605 gLog << ___err___ << "ERROR - FITS file corrupted." << std::endl;
606 return;
607#endif
608 }
609
610 if (block.size()%36)
611 {
612 if (!rc && !force)
613 {
614 clear(rdstate()|std::ios::badbit);
615#ifdef __EXCEPTIONS
616 throw std::runtime_error("END keyword missing in FITS header.");
617#else
618 gLog << ___err___ << "ERROR - END keyword missing in FITS file... file might be corrupted." << std::endl;
619 return;
620#endif
621 }
622 break;
623 }
624 }
625
626 if (block.empty())
627 break;
628
629 if (block[0].substr(0, 9)=="SIMPLE =")
630 {
631 fChkHeader.reset();
632 continue;
633 }
634
635 if (block[0].substr(0, 9)=="XTENSION=")
636 {
637 fTable = Table(block, tellg());
638 fRow = (size_t)-1;
639
640 if (!fTable)
641 {
642 clear(rdstate()|std::ios::badbit);
643 return;
644 }
645
646 const std::string &tname = fTable.Get<std::string>("EXTNAME");
647
648 fListOfTables.emplace_back(tname);
649
650 // Check for table name. Skip until eof or requested table are found.
651 // skip the current table?
652 if ((!tableName.empty() && tableName!=tname) || (tableName.empty() && "ZDrsCellOffsets"==tname))
653 {
654 const streamoff skip = fTable.GetTotalBytes();
655 seekg(skip, std::ios_base::cur);
656
657 fChkHeader.reset();
658
659 continue;
660 }
661
662 fBufferRow.resize(fTable.bytes_per_row + 8-fTable.bytes_per_row%4);
663 fBufferDat.resize(fTable.bytes_per_row);
664
665 break;
666 }
667 }
668
669 if (fout.empty())
670 return;
671
672 if (*fout.rbegin()=='/')
673 {
674 const size_t p = fname.find_last_of('/');
675 fout.append(fname.substr(p+1));
676 }
677
678 fCopy.open(fout);
679 if (!fCopy)
680 {
681 clear(rdstate()|std::ios::badbit);
682#ifdef __EXCEPTIONS
683 throw std::runtime_error("Could not open output file.");
684#else
685 gLog << ___err___ << "ERROR - Failed to open output file." << std::endl;
686 return;
687#endif
688 }
689
690 const streampos p = tellg();
691 seekg(0);
692
693 std::vector<char> buf(p);
694 read(buf.data(), p);
695
696 fCopy.write(buf.data(), p);
697 if (!fCopy)
698 clear(rdstate()|std::ios::badbit);
699 }
700
701public:
702 fits(const std::string &fname, const std::string& tableName="", bool force=false) : izstream(fname.c_str())
703 {
704 Constructor(fname, "", tableName, force);
705 if ((fTable.is_compressed ||fTable.name=="ZDrsCellOffsets") && !force)
706 {
707#ifdef __EXCEPTIONS
708 throw std::runtime_error("You are trying to read a compressed fits with the base fits class. Please use factfits instead.");
709#else
710 gLog << ___err___ << "ERROR - You are trying to read a compressed fits with the base fits class. Please use factfits instead." << std::endl;
711#endif
712 clear(rdstate()|std::ios::badbit);
713 }
714 }
715
716 fits(const std::string &fname, const std::string &fout, const std::string& tableName, bool force=false) : izstream(fname.c_str())
717 {
718 Constructor(fname, fout, tableName, force);
719 if ((fTable.is_compressed || fTable.name=="ZDrsCellOffsets") && !force)
720 {
721#ifdef __EXCEPTIONS
722 throw std::runtime_error("You are trying to read a compressed fits with the base fits class. Please use factfits instead.");
723#else
724 gLog << ___err___ << "ERROR - You are trying to read a compressed fits with the base fits class. Please use factfits instead." << std::endl;
725#endif
726 clear(rdstate()|std::ios::badbit);
727 }
728 }
729
730 fits() : izstream()
731 {
732
733 }
734
735 ~fits()
736 {
737 std::copy(std::istreambuf_iterator<char>(*this),
738 std::istreambuf_iterator<char>(),
739 std::ostreambuf_iterator<char>(fCopy));
740 }
741
742 virtual void StageRow(size_t row, char* dest)
743 {
744 // if (row!=fRow+1) // Fast seeking is ensured by izstream
745 seekg(fTable.offset+row*fTable.bytes_per_row);
746 read(dest, fTable.bytes_per_row);
747 //fin.clear(fin.rdstate()&~ios::eofbit);
748 }
749
750 virtual void WriteRowToCopyFile(size_t row)
751 {
752 if (row==fRow+1)
753 {
754 const uint8_t offset = (row*fTable.bytes_per_row)%4;
755
756 fChkData.add(fBufferRow);
757 if (fCopy.is_open() && fCopy.good())
758 fCopy.write(fBufferRow.data()+offset, fTable.bytes_per_row);
759 if (!fCopy)
760 clear(rdstate()|std::ios::badbit);
761 }
762 else
763 if (fCopy.is_open())
764 clear(rdstate()|std::ios::badbit);
765 }
766
767 void ZeroBufferForChecksum(std::vector<char>& vec, const uint64_t extraZeros=0)
768 {
769 auto ib = vec.begin();
770 auto ie = vec.end();
771
772 *ib++ = 0;
773 *ib++ = 0;
774 *ib++ = 0;
775 *ib = 0;
776
777 for (uint64_t i=0;i<extraZeros+8;i++)
778 *--ie = 0;
779 }
780
781 uint8_t ReadRow(size_t row)
782 {
783 // For the checksum we need everything to be correctly aligned
784 const uint8_t offset = (row*fTable.bytes_per_row)%4;
785
786 ZeroBufferForChecksum(fBufferRow);
787
788 StageRow(row, fBufferRow.data()+offset);
789
790 WriteRowToCopyFile(row);
791
792 fRow = row;
793
794 return offset;
795 }
796
797 template<size_t N>
798 void revcpy(char *dest, const char *src, const int &num)
799 {
800 const char *pend = src + num*N;
801 for (const char *ptr = src; ptr<pend; ptr+=N, dest+=N)
802 std::reverse_copy(ptr, ptr+N, dest);
803 }
804
805 virtual void MoveColumnDataToUserSpace(char *dest, const char *src, const Table::Column& c)
806 {
807 // Let the compiler do some optimization by
808 // knowing that we only have 1, 2, 4 and 8
809 switch (c.size)
810 {
811 case 1: memcpy (dest, src, c.bytes); break;
812 case 2: revcpy<2>(dest, src, c.num); break;
813 case 4: revcpy<4>(dest, src, c.num); break;
814 case 8: revcpy<8>(dest, src, c.num); break;
815 }
816 }
817
818 virtual bool GetRow(size_t row, bool check=true)
819 {
820 if (check && row>=fTable.num_rows)
821 return false;
822
823 const uint8_t offset = ReadRow(row);
824 if (!good())
825 return good();
826
827 const char *ptr = fBufferRow.data() + offset;
828
829 for (Addresses::const_iterator it=fAddresses.cbegin(); it!=fAddresses.cend(); it++)
830 {
831 const Table::Column &c = it->second;
832
833 const char *src = ptr + c.offset;
834 char *dest = reinterpret_cast<char*>(it->first);
835
836 MoveColumnDataToUserSpace(dest, src, c);
837 }
838
839 return good();
840 }
841
842 bool GetNextRow(bool check=true)
843 {
844 return GetRow(fRow+1, check);
845 }
846
847 virtual bool SkipNextRow()
848 {
849 seekg(fTable.offset+(++fRow)*fTable.bytes_per_row);
850 return good();
851 }
852
853 static bool Compare(const Address &p1, const Address &p2)
854 {
855 return p1.first>p2.first;
856 }
857
858 template<class T, class S>
859 const T &GetAs(const std::string &name)
860 {
861 return *reinterpret_cast<S*>(fPointers[name]);
862 }
863
864 void *SetPtrAddress(const std::string &name)
865 {
866 if (fTable.cols.count(name)==0)
867 {
868 std::ostringstream str;
869 str << "SetPtrAddress('" << name << "') - Column not found.";
870#ifdef __EXCEPTIONS
871 throw std::runtime_error(str.str());
872#else
873 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
874 return NULL;
875#endif
876 }
877
878 Pointers::const_iterator it = fPointers.find(name);
879 if (it!=fPointers.end())
880 return it->second;
881
882 fGarbage.emplace_back(fTable.cols[name].bytes);
883
884 void *ptr = fGarbage.back().data();
885
886 fPointers[name] = ptr;
887 fAddresses.emplace_back(ptr, fTable.cols[name]);
888 sort(fAddresses.begin(), fAddresses.end(), Compare);
889 return ptr;
890 }
891
892 template<typename T>
893 bool SetPtrAddress(const std::string &name, T *ptr, size_t cnt)
894 {
895 if (fTable.cols.count(name)==0)
896 {
897 std::ostringstream str;
898 str << "SetPtrAddress('" << name << "') - Column not found.";
899#ifdef __EXCEPTIONS
900 throw std::runtime_error(str.str());
901#else
902 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
903 return false;
904#endif
905 }
906
907 if (sizeof(T)!=fTable.cols[name].size)
908 {
909 std::ostringstream str;
910 str << "SetPtrAddress('" << name << "') - Element size mismatch: expected "
911 << fTable.cols[name].size << " from header, got " << sizeof(T);
912#ifdef __EXCEPTIONS
913 throw std::runtime_error(str.str());
914#else
915 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
916 return false;
917#endif
918 }
919
920 if (cnt!=fTable.cols[name].num)
921 {
922 std::ostringstream str;
923 str << "SetPtrAddress('" << name << "') - Element count mismatch: expected "
924 << fTable.cols[name].num << " from header, got " << cnt;
925#ifdef __EXCEPTIONS
926 throw std::runtime_error(str.str());
927#else
928 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
929 return false;
930#endif
931 }
932
933 // if (fAddresses.count(ptr)>0)
934 // gLog << warn << "SetPtrAddress('" << name << "') - Pointer " << ptr << " already assigned." << endl;
935
936 //fAddresses[ptr] = fTable.cols[name];
937 fPointers[name] = ptr;
938 fAddresses.emplace_back(ptr, fTable.cols[name]);
939 sort(fAddresses.begin(), fAddresses.end(), Compare);
940 return true;
941 }
942
943 template<class T>
944 bool SetRefAddress(const std::string &name, T &ptr)
945 {
946 return SetPtrAddress(name, &ptr, sizeof(ptr)/sizeof(T));
947 }
948
949 template<typename T>
950 bool SetVecAddress(const std::string &name, std::vector<T> &vec)
951 {
952 return SetPtrAddress(name, vec.data(), vec.size());
953 }
954
955 template<typename T>
956 T Get(const std::string &key) const
957 {
958 return fTable.Get<T>(key);
959 }
960
961 template<typename T>
962 T Get(const std::string &key, const std::string &deflt) const
963 {
964 return fTable.Get<T>(key, deflt);
965 }
966
967 bool SetPtrAddress(const std::string &name, void *ptr, size_t cnt=0)
968 {
969 if (fTable.cols.count(name)==0)
970 {
971 std::ostringstream str;
972 str <<"SetPtrAddress('" << name << "') - Column not found.";
973#ifdef __EXCEPTIONS
974 throw std::runtime_error(str.str());
975#else
976 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
977 return false;
978#endif
979 }
980
981 if (cnt && cnt!=fTable.cols[name].num)
982 {
983 std::ostringstream str;
984 str << "SetPtrAddress('" << name << "') - Element count mismatch: expected "
985 << fTable.cols[name].num << " from header, got " << cnt;
986#ifdef __EXCEPTIONS
987 throw std::runtime_error(str.str());
988#else
989 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
990 return false;
991#endif
992 }
993
994 // if (fAddresses.count(ptr)>0)
995 // gLog << warn << "SetPtrAddress('" << name << "') - Pointer " << ptr << " already assigned." << endl;
996
997 //fAddresses[ptr] = fTable.cols[name];
998 fPointers[name] = ptr;
999 fAddresses.emplace_back(ptr, fTable.cols[name]);
1000 sort(fAddresses.begin(), fAddresses.end(), Compare);
1001 return true;
1002 }
1003
1004 bool HasKey(const std::string &key) const { return fTable.HasKey(key); }
1005 bool HasColumn(const std::string& col) const { return fTable.HasColumn(col);}
1006 const Table::Columns &GetColumns() const { return fTable.GetColumns();}
1007 const Table::SortedColumns& GetSortedColumns() const { return fTable.sorted_cols;}
1008 const Table::Keys &GetKeys() const { return fTable.GetKeys();}
1009
1010 int64_t GetInt(const std::string &key) const { return fTable.Get<int64_t>(key); }
1011 uint64_t GetUInt(const std::string &key) const { return fTable.Get<uint64_t>(key); }
1012 double GetFloat(const std::string &key) const { return fTable.Get<double>(key); }
1013 std::string GetStr(const std::string &key) const { return fTable.Get<std::string>(key); }
1014
1015 size_t GetN(const std::string &key) const
1016 {
1017 return fTable.GetN(key);
1018 }
1019
1020// size_t GetNumRows() const { return fTable.num_rows; }
1021 size_t GetRow() const { return fRow==(size_t)-1 ? 0 : fRow; }
1022
1023 operator bool() const { return fTable && fTable.offset!=0; }
1024
1025 void PrintKeys() const { fTable.PrintKeys(); }
1026 void PrintColumns() const { fTable.PrintColumns(); }
1027
1028 bool IsHeaderOk() const { return fTable.datasum<0?false:(fChkHeader+Checksum(fTable.datasum)).valid(); }
1029 virtual bool IsFileOk() const { return (fChkHeader+fChkData).valid(); }
1030
1031 bool IsCompressedFITS() const { return fTable.is_compressed;}
1032
1033 virtual size_t GetNumRows() const
1034 {
1035 return fTable.Get<size_t>("NAXIS2");
1036 }
1037
1038 virtual size_t GetBytesPerRow() const
1039 {
1040 return fTable.Get<size_t>("NAXIS1");
1041 }
1042
1043 const std::vector<std::string> &GetTables() const
1044 {
1045 return fListOfTables;
1046 }
1047};
1048
1049#endif
Note: See TracBrowser for help on using the repository browser.