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

Last change on this file since 17387 was 17382, checked in by tbretz, 11 years ago
Simplified conditional.
File size: 32.0 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>("ZDATASUM", -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
488 Table fTable;
489
490 typedef std::pair<void*, Table::Column> Address;
491 typedef std::vector<Address> Addresses;
492 //map<void*, Table::Column> fAddresses;
493 Addresses fAddresses;
494
495 typedef std::unordered_map<std::string, void*> Pointers;
496 Pointers fPointers;
497
498 std::vector<std::vector<char>> fGarbage;
499
500 std::vector<char> fBufferRow;
501 std::vector<char> fBufferDat;
502
503 size_t fRow;
504
505 Checksum fChkHeader;
506 Checksum fChkData;
507
508 bool ReadBlock(std::vector<std::string> &vec)
509 {
510 int endtag = 0;
511 for (int i=0; i<36; i++)
512 {
513 char c[81];
514 c[80] = 0;
515 read(c, 80);
516 if (!good())
517 break;
518
519 fChkHeader.add(c, 80);
520
521// if (c[0]==0)
522// return vector<string>();
523
524 std::string str(c);
525
526// if (!str.empty())
527// cout << setw(2) << i << "|" << str << "|" << (endtag?'-':'+') << endl;
528
529 if (endtag==2 || str=="END ")
530 {
531 endtag = 2; // valid END tag found
532 continue;
533 }
534
535 if (endtag==1 || str==" ")
536 {
537 endtag = 1; // end tag not found, but expected to be there
538 continue;
539 }
540
541 vec.push_back(str);
542 }
543
544 // Make sure that no empty vector is returned
545 if (endtag && vec.size()%36==0)
546 vec.emplace_back("END = '' / ");
547
548 return endtag==2;
549 }
550
551 std::string Compile(const std::string &key, int16_t i=-1) const
552 {
553#if GCC_VERSION < 40603
554 return i<0 ? key : key+std::to_string((long long int)(i));
555#else
556 return i<0 ? key : key+std::to_string(i);
557#endif
558 }
559
560 void Constructor(const std::string &fname, std::string fout, const std::string& tableName, bool force, int tableNumber=-1)
561 {
562 char simple[10];
563 read(simple, 10);
564 if (!good())
565 return;
566
567 int current_table = 0;
568
569 if (memcmp(simple, "SIMPLE = ", 10))
570 {
571 clear(rdstate()|std::ios::badbit);
572#ifdef __EXCEPTIONS
573 throw std::runtime_error("File is not a FITS file.");
574#else
575 gLog << ___err___ << "ERROR - File is not a FITS file." << std::endl;
576 return;
577#endif
578 }
579
580 seekg(0);
581
582 while (good())
583 {
584 std::vector<std::string> block;
585 while (1)
586 {
587 // If we search for a table, we implicitly assume that
588 // not finding the table is not an error. The user
589 // can easily check that by eof() && !bad()
590 peek();
591 if (eof() && !bad() && !tableName.empty())
592 {
593 break;
594 }
595 // FIXME: Set limit on memory consumption
596 const int rc = ReadBlock(block);
597 if (!good())
598 {
599 clear(rdstate()|std::ios::badbit);
600#ifdef __EXCEPTIONS
601 throw std::runtime_error("FITS file corrupted.");
602#else
603 gLog << ___err___ << "ERROR - FITS file corrupted." << std::endl;
604 return;
605#endif
606 }
607
608 if (block.size()%36)
609 {
610 if (!rc && !force)
611 {
612 clear(rdstate()|std::ios::badbit);
613#ifdef __EXCEPTIONS
614 throw std::runtime_error("END keyword missing in FITS header.");
615#else
616 gLog << ___err___ << "ERROR - END keyword missing in FITS file... file might be corrupted." << std::endl;
617 return;
618#endif
619 }
620 break;
621 }
622 }
623
624 if (block.empty())
625 break;
626
627 if (block[0].substr(0, 9)=="SIMPLE =")
628 {
629 fChkHeader.reset();
630 continue;
631 }
632
633 if (block[0].substr(0, 9)=="XTENSION=")
634 {
635 fTable = Table(block, tellg());
636 fRow = (size_t)-1;
637
638 if (!fTable)
639 {
640 clear(rdstate()|std::ios::badbit);
641 return;
642 }
643
644 // Check for table name. Skip until eof or requested table are found.
645 // skip the current table?
646 if ((!tableName.empty() && tableName!=fTable.Get<std::string>("EXTNAME")) ||
647 ( tableName.empty() && "ZDrsCellOffsets"==fTable.Get<std::string>("EXTNAME")) ||
648 (tableNumber != -1))
649 {
650 if (current_table == tableNumber)
651 {
652 fBufferRow.resize(fTable.bytes_per_row + 8-fTable.bytes_per_row%4);
653 fBufferDat.resize(fTable.bytes_per_row);
654
655 break;
656 }
657 const streamoff skip = fTable.GetTotalBytes();
658 seekg(skip, std::ios_base::cur);
659
660 fChkHeader.reset();
661 current_table++;
662
663 continue;
664 }
665
666 fBufferRow.resize(fTable.bytes_per_row + 8-fTable.bytes_per_row%4);
667 fBufferDat.resize(fTable.bytes_per_row);
668
669 break;
670 }
671 }
672
673 if (fout.empty())
674 return;
675
676 if (*fout.rbegin()=='/')
677 {
678 const size_t p = fname.find_last_of('/');
679 fout.append(fname.substr(p+1));
680 }
681
682 fCopy.open(fout);
683 if (!fCopy)
684 {
685 clear(rdstate()|std::ios::badbit);
686#ifdef __EXCEPTIONS
687 throw std::runtime_error("Could not open output file.");
688#else
689 gLog << ___err___ << "ERROR - Failed to open output file." << std::endl;
690#endif
691 }
692
693 const streampos p = tellg();
694 seekg(0);
695
696 std::vector<char> buf(p);
697 read(buf.data(), p);
698
699 fCopy.write(buf.data(), p);
700 if (!fCopy)
701 clear(rdstate()|std::ios::badbit);
702 }
703
704public:
705 fits(const std::string &fname, const std::string& tableName="", bool force=false) : izstream(fname.c_str())
706 {
707 Constructor(fname, "", tableName, force);
708 if ((fTable.is_compressed ||fTable.name=="ZDrsCellOffsets") && !force)
709 {
710#ifdef __EXCEPTIONS
711 throw std::runtime_error("You are trying to read a compressed fits with the base fits class. Please use factfits instead.");
712#else
713 gLog << ___err___ << "ERROR - You are trying to read a compressed fits with the base fits class. Please use factfits instead." << std::endl;
714#endif
715 clear(rdstate()|std::ios::badbit);
716 }
717 }
718
719 fits(const std::string &fname, const std::string &fout, const std::string& tableName, bool force=false) : izstream(fname.c_str())
720 {
721 Constructor(fname, fout, tableName, force);
722 if ((fTable.is_compressed || fTable.name=="ZDrsCellOffsets") && !force)
723 {
724#ifdef __EXCEPTIONS
725 throw std::runtime_error("You are trying to read a compressed fits with the base fits class. Please use factfits instead.");
726#else
727 gLog << ___err___ << "ERROR - You are trying to read a compressed fits with the base fits class. Please use factfits instead." << std::endl;
728#endif
729 clear(rdstate()|std::ios::badbit);
730 }
731 }
732
733 fits() : izstream()
734 {
735
736 }
737
738 ~fits()
739 {
740 std::copy(std::istreambuf_iterator<char>(*this),
741 std::istreambuf_iterator<char>(),
742 std::ostreambuf_iterator<char>(fCopy));
743 }
744
745 virtual void StageRow(size_t row, char* dest)
746 {
747 // if (row!=fRow+1) // Fast seeking is ensured by izstream
748 seekg(fTable.offset+row*fTable.bytes_per_row);
749 read(dest, fTable.bytes_per_row);
750 //fin.clear(fin.rdstate()&~ios::eofbit);
751 }
752
753 virtual void WriteRowToCopyFile(size_t row)
754 {
755 if (row==fRow+1)
756 {
757 const uint8_t offset = (row*fTable.bytes_per_row)%4;
758
759 fChkData.add(fBufferRow);
760 if (fCopy.is_open() && fCopy.good())
761 fCopy.write(fBufferRow.data()+offset, fTable.bytes_per_row);
762 if (!fCopy)
763 clear(rdstate()|std::ios::badbit);
764 }
765 else
766 if (fCopy.is_open())
767 clear(rdstate()|std::ios::badbit);
768 }
769
770 void ZeroBufferForChecksum(std::vector<char>& vec, const uint64_t extraZeros=0)
771 {
772 auto ib = vec.begin();
773 auto ie = vec.end();
774
775 *ib++ = 0;
776 *ib++ = 0;
777 *ib++ = 0;
778 *ib = 0;
779
780 for (uint64_t i=0;i<extraZeros+8;i++)
781 *--ie = 0;
782 }
783
784 uint8_t ReadRow(size_t row)
785 {
786 // For the checksum we need everything to be correctly aligned
787 const uint8_t offset = (row*fTable.bytes_per_row)%4;
788
789 ZeroBufferForChecksum(fBufferRow);
790
791 StageRow(row, fBufferRow.data()+offset);
792
793 WriteRowToCopyFile(row);
794
795 fRow = row;
796
797 return offset;
798 }
799
800 template<size_t N>
801 void revcpy(char *dest, const char *src, const int &num)
802 {
803 const char *pend = src + num*N;
804 for (const char *ptr = src; ptr<pend; ptr+=N, dest+=N)
805 std::reverse_copy(ptr, ptr+N, dest);
806 }
807
808 virtual void MoveColumnDataToUserSpace(char *dest, const char *src, const Table::Column& c)
809 {
810 // Let the compiler do some optimization by
811 // knowing that we only have 1, 2, 4 and 8
812 switch (c.size)
813 {
814 case 1: memcpy (dest, src, c.bytes); break;
815 case 2: revcpy<2>(dest, src, c.num); break;
816 case 4: revcpy<4>(dest, src, c.num); break;
817 case 8: revcpy<8>(dest, src, c.num); break;
818 }
819 }
820
821 virtual bool GetRow(size_t row, bool check=true)
822 {
823 if (check && row>=fTable.num_rows)
824 return false;
825
826 const uint8_t offset = ReadRow(row);
827 if (!good())
828 return good();
829
830 const char *ptr = fBufferRow.data() + offset;
831
832 for (Addresses::const_iterator it=fAddresses.cbegin(); it!=fAddresses.cend(); it++)
833 {
834 const Table::Column &c = it->second;
835
836 const char *src = ptr + c.offset;
837 char *dest = reinterpret_cast<char*>(it->first);
838
839 MoveColumnDataToUserSpace(dest, src, c);
840 }
841
842 return good();
843 }
844
845 bool GetNextRow(bool check=true)
846 {
847 return GetRow(fRow+1, check);
848 }
849
850 virtual bool SkipNextRow()
851 {
852 seekg(fTable.offset+(++fRow)*fTable.bytes_per_row);
853 return good();
854 }
855
856 static bool Compare(const Address &p1, const Address &p2)
857 {
858 return p1.first>p2.first;
859 }
860
861 template<class T, class S>
862 const T &GetAs(const std::string &name)
863 {
864 return *reinterpret_cast<S*>(fPointers[name]);
865 }
866
867 void *SetPtrAddress(const std::string &name)
868 {
869 if (fTable.cols.count(name)==0)
870 {
871 std::ostringstream str;
872 str << "SetPtrAddress('" << name << "') - Column not found.";
873#ifdef __EXCEPTIONS
874 throw std::runtime_error(str.str());
875#else
876 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
877 return NULL;
878#endif
879 }
880
881 Pointers::const_iterator it = fPointers.find(name);
882 if (it!=fPointers.end())
883 return it->second;
884
885 fGarbage.emplace_back(fTable.cols[name].bytes);
886
887 void *ptr = fGarbage.back().data();
888
889 fPointers[name] = ptr;
890 fAddresses.emplace_back(ptr, fTable.cols[name]);
891 sort(fAddresses.begin(), fAddresses.end(), Compare);
892 return ptr;
893 }
894
895 template<typename T>
896 bool SetPtrAddress(const std::string &name, T *ptr, size_t cnt)
897 {
898 if (fTable.cols.count(name)==0)
899 {
900 std::ostringstream str;
901 str << "SetPtrAddress('" << name << "') - Column not found.";
902#ifdef __EXCEPTIONS
903 throw std::runtime_error(str.str());
904#else
905 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
906 return false;
907#endif
908 }
909
910 if (sizeof(T)!=fTable.cols[name].size)
911 {
912 std::ostringstream str;
913 str << "SetPtrAddress('" << name << "') - Element size mismatch: expected "
914 << fTable.cols[name].size << " from header, got " << sizeof(T);
915#ifdef __EXCEPTIONS
916 throw std::runtime_error(str.str());
917#else
918 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
919 return false;
920#endif
921 }
922
923 if (cnt!=fTable.cols[name].num)
924 {
925 std::ostringstream str;
926 str << "SetPtrAddress('" << name << "') - Element count mismatch: expected "
927 << fTable.cols[name].num << " from header, got " << cnt;
928#ifdef __EXCEPTIONS
929 throw std::runtime_error(str.str());
930#else
931 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
932 return false;
933#endif
934 }
935
936 // if (fAddresses.count(ptr)>0)
937 // gLog << warn << "SetPtrAddress('" << name << "') - Pointer " << ptr << " already assigned." << endl;
938
939 //fAddresses[ptr] = fTable.cols[name];
940 fPointers[name] = ptr;
941 fAddresses.emplace_back(ptr, fTable.cols[name]);
942 sort(fAddresses.begin(), fAddresses.end(), Compare);
943 return true;
944 }
945
946 template<class T>
947 bool SetRefAddress(const std::string &name, T &ptr)
948 {
949 return SetPtrAddress(name, &ptr, sizeof(ptr)/sizeof(T));
950 }
951
952 template<typename T>
953 bool SetVecAddress(const std::string &name, std::vector<T> &vec)
954 {
955 return SetPtrAddress(name, vec.data(), vec.size());
956 }
957
958 template<typename T>
959 T Get(const std::string &key) const
960 {
961 return fTable.Get<T>(key);
962 }
963
964 template<typename T>
965 T Get(const std::string &key, const std::string &deflt) const
966 {
967 return fTable.Get<T>(key, deflt);
968 }
969
970 bool SetPtrAddress(const std::string &name, void *ptr, size_t cnt=0)
971 {
972 if (fTable.cols.count(name)==0)
973 {
974 std::ostringstream str;
975 str <<"SetPtrAddress('" << name << "') - Column not found.";
976#ifdef __EXCEPTIONS
977 throw std::runtime_error(str.str());
978#else
979 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
980 return false;
981#endif
982 }
983
984 if (cnt && cnt!=fTable.cols[name].num)
985 {
986 std::ostringstream str;
987 str << "SetPtrAddress('" << name << "') - Element count mismatch: expected "
988 << fTable.cols[name].num << " from header, got " << cnt;
989#ifdef __EXCEPTIONS
990 throw std::runtime_error(str.str());
991#else
992 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
993 return false;
994#endif
995 }
996
997 // if (fAddresses.count(ptr)>0)
998 // gLog << warn << "SetPtrAddress('" << name << "') - Pointer " << ptr << " already assigned." << endl;
999
1000 //fAddresses[ptr] = fTable.cols[name];
1001 fPointers[name] = ptr;
1002 fAddresses.emplace_back(ptr, fTable.cols[name]);
1003 sort(fAddresses.begin(), fAddresses.end(), Compare);
1004 return true;
1005 }
1006
1007 bool HasKey(const std::string &key) const { return fTable.HasKey(key); }
1008 bool HasColumn(const std::string& col) const { return fTable.HasColumn(col);}
1009 const Table::Columns &GetColumns() const { return fTable.GetColumns();}
1010 const Table::SortedColumns& GetSortedColumns() const { return fTable.sorted_cols;}
1011 const Table::Keys &GetKeys() const { return fTable.GetKeys();}
1012
1013 int64_t GetInt(const std::string &key) const { return fTable.Get<int64_t>(key); }
1014 uint64_t GetUInt(const std::string &key) const { return fTable.Get<uint64_t>(key); }
1015 double GetFloat(const std::string &key) const { return fTable.Get<double>(key); }
1016 std::string GetStr(const std::string &key) const { return fTable.Get<std::string>(key); }
1017
1018 size_t GetN(const std::string &key) const
1019 {
1020 return fTable.GetN(key);
1021 }
1022
1023// size_t GetNumRows() const { return fTable.num_rows; }
1024 size_t GetRow() const { return fRow==(size_t)-1 ? 0 : fRow; }
1025
1026 operator bool() const { return fTable && fTable.offset!=0; }
1027
1028 void PrintKeys() const { fTable.PrintKeys(); }
1029 void PrintColumns() const { fTable.PrintColumns(); }
1030
1031 bool IsHeaderOk() const { return fTable.datasum<0?false:(fChkHeader+Checksum(fTable.datasum)).valid(); }
1032 virtual bool IsFileOk() const { return (fChkHeader+fChkData).valid(); }
1033
1034 bool IsCompressedFITS() const { return fTable.is_compressed;}
1035
1036 virtual size_t GetNumRows() const
1037 {
1038 return fTable.Get<size_t>("NAXIS2");
1039 }
1040
1041 virtual size_t GetBytesPerRow() const
1042 {
1043 return fTable.Get<size_t>("NAXIS1");
1044 }
1045};
1046
1047#endif
Note: See TracBrowser for help on using the repository browser.