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

Last change on this file since 17338 was 17304, checked in by lyard, 11 years ago
Adapted compilation on older Gcc
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 && !force) ||
709 (fTable.name == "ZDrsCellOffsets" && !force))
710 {
711#ifdef __EXCEPTIONS
712 throw std::runtime_error("You are trying to read a compressed fits with the base fits class. Please use factfits instead.");
713#else
714 gLog << ___err___ << "ERROR - You are trying to read a compressed fits with the base fits class. Please use factfits instead." << std::endl;
715#endif
716 clear(rdstate()|std::ios::badbit);
717 }
718 }
719
720 fits(const std::string &fname, const std::string &fout, const std::string& tableName, bool force=false) : izstream(fname.c_str())
721 {
722 Constructor(fname, fout, tableName, force);
723 if ((fTable.is_compressed && !force) ||
724 (fTable.name == "ZDrsCellOffsets" && !force))
725 {
726#ifdef __EXCEPTIONS
727 throw std::runtime_error("You are trying to read a compressed fits with the base fits class. Please use factfits instead.");
728#else
729 gLog << ___err___ << "ERROR - You are trying to read a compressed fits with the base fits class. Please use factfits instead." << std::endl;
730#endif
731 clear(rdstate()|std::ios::badbit);
732 }
733 }
734
735 fits() : izstream()
736 {
737
738 }
739
740 ~fits()
741 {
742 std::copy(std::istreambuf_iterator<char>(*this),
743 std::istreambuf_iterator<char>(),
744 std::ostreambuf_iterator<char>(fCopy));
745 }
746
747 virtual void StageRow(size_t row, char* dest)
748 {
749 // if (row!=fRow+1) // Fast seeking is ensured by izstream
750 seekg(fTable.offset+row*fTable.bytes_per_row);
751 read(dest, fTable.bytes_per_row);
752 //fin.clear(fin.rdstate()&~ios::eofbit);
753 }
754
755 virtual void WriteRowToCopyFile(size_t row)
756 {
757 if (row==fRow+1)
758 {
759 const uint8_t offset = (row*fTable.bytes_per_row)%4;
760
761 fChkData.add(fBufferRow);
762 if (fCopy.is_open() && fCopy.good())
763 fCopy.write(fBufferRow.data()+offset, fTable.bytes_per_row);
764 if (!fCopy)
765 clear(rdstate()|std::ios::badbit);
766 }
767 else
768 if (fCopy.is_open())
769 clear(rdstate()|std::ios::badbit);
770 }
771
772 void ZeroBufferForChecksum(std::vector<char>& vec, const uint64_t extraZeros=0)
773 {
774 auto ib = vec.begin();
775 auto ie = vec.end();
776
777 *ib++ = 0;
778 *ib++ = 0;
779 *ib++ = 0;
780 *ib = 0;
781
782 for (uint64_t i=0;i<extraZeros+8;i++)
783 *--ie = 0;
784 }
785
786 uint8_t ReadRow(size_t row)
787 {
788 // For the checksum we need everything to be correctly aligned
789 const uint8_t offset = (row*fTable.bytes_per_row)%4;
790
791 ZeroBufferForChecksum(fBufferRow);
792
793 StageRow(row, fBufferRow.data()+offset);
794
795 WriteRowToCopyFile(row);
796
797 fRow = row;
798
799 return offset;
800 }
801
802 template<size_t N>
803 void revcpy(char *dest, const char *src, const int &num)
804 {
805 const char *pend = src + num*N;
806 for (const char *ptr = src; ptr<pend; ptr+=N, dest+=N)
807 std::reverse_copy(ptr, ptr+N, dest);
808 }
809
810 virtual void MoveColumnDataToUserSpace(char *dest, const char *src, const Table::Column& c)
811 {
812 // Let the compiler do some optimization by
813 // knowing that we only have 1, 2, 4 and 8
814 switch (c.size)
815 {
816 case 1: memcpy (dest, src, c.bytes); break;
817 case 2: revcpy<2>(dest, src, c.num); break;
818 case 4: revcpy<4>(dest, src, c.num); break;
819 case 8: revcpy<8>(dest, src, c.num); break;
820 }
821 }
822
823 virtual bool GetRow(size_t row, bool check=true)
824 {
825 if (check && row>=fTable.num_rows)
826 return false;
827
828 const uint8_t offset = ReadRow(row);
829 if (!good())
830 return good();
831
832 const char *ptr = fBufferRow.data() + offset;
833
834 for (Addresses::const_iterator it=fAddresses.cbegin(); it!=fAddresses.cend(); it++)
835 {
836 const Table::Column &c = it->second;
837
838 const char *src = ptr + c.offset;
839 char *dest = reinterpret_cast<char*>(it->first);
840
841 MoveColumnDataToUserSpace(dest, src, c);
842 }
843
844 return good();
845 }
846
847 bool GetNextRow(bool check=true)
848 {
849 return GetRow(fRow+1, check);
850 }
851
852 virtual bool SkipNextRow()
853 {
854 seekg(fTable.offset+(++fRow)*fTable.bytes_per_row);
855 return good();
856 }
857
858 static bool Compare(const Address &p1, const Address &p2)
859 {
860 return p1.first>p2.first;
861 }
862
863 template<class T, class S>
864 const T &GetAs(const std::string &name)
865 {
866 return *reinterpret_cast<S*>(fPointers[name]);
867 }
868
869 void *SetPtrAddress(const std::string &name)
870 {
871 if (fTable.cols.count(name)==0)
872 {
873 std::ostringstream str;
874 str << "SetPtrAddress('" << name << "') - Column not found.";
875#ifdef __EXCEPTIONS
876 throw std::runtime_error(str.str());
877#else
878 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
879 return NULL;
880#endif
881 }
882
883 Pointers::const_iterator it = fPointers.find(name);
884 if (it!=fPointers.end())
885 return it->second;
886
887 fGarbage.emplace_back(fTable.cols[name].bytes);
888
889 void *ptr = fGarbage.back().data();
890
891 fPointers[name] = ptr;
892 fAddresses.emplace_back(ptr, fTable.cols[name]);
893 sort(fAddresses.begin(), fAddresses.end(), Compare);
894 return ptr;
895 }
896
897 template<typename T>
898 bool SetPtrAddress(const std::string &name, T *ptr, size_t cnt)
899 {
900 if (fTable.cols.count(name)==0)
901 {
902 std::ostringstream str;
903 str << "SetPtrAddress('" << name << "') - Column not found.";
904#ifdef __EXCEPTIONS
905 throw std::runtime_error(str.str());
906#else
907 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
908 return false;
909#endif
910 }
911
912 if (sizeof(T)!=fTable.cols[name].size)
913 {
914 std::ostringstream str;
915 str << "SetPtrAddress('" << name << "') - Element size mismatch: expected "
916 << fTable.cols[name].size << " from header, got " << sizeof(T);
917#ifdef __EXCEPTIONS
918 throw std::runtime_error(str.str());
919#else
920 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
921 return false;
922#endif
923 }
924
925 if (cnt!=fTable.cols[name].num)
926 {
927 std::ostringstream str;
928 str << "SetPtrAddress('" << name << "') - Element count mismatch: expected "
929 << fTable.cols[name].num << " from header, got " << cnt;
930#ifdef __EXCEPTIONS
931 throw std::runtime_error(str.str());
932#else
933 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
934 return false;
935#endif
936 }
937
938 // if (fAddresses.count(ptr)>0)
939 // gLog << warn << "SetPtrAddress('" << name << "') - Pointer " << ptr << " already assigned." << endl;
940
941 //fAddresses[ptr] = fTable.cols[name];
942 fPointers[name] = ptr;
943 fAddresses.emplace_back(ptr, fTable.cols[name]);
944 sort(fAddresses.begin(), fAddresses.end(), Compare);
945 return true;
946 }
947
948 template<class T>
949 bool SetRefAddress(const std::string &name, T &ptr)
950 {
951 return SetPtrAddress(name, &ptr, sizeof(ptr)/sizeof(T));
952 }
953
954 template<typename T>
955 bool SetVecAddress(const std::string &name, std::vector<T> &vec)
956 {
957 return SetPtrAddress(name, vec.data(), vec.size());
958 }
959
960 template<typename T>
961 T Get(const std::string &key) const
962 {
963 return fTable.Get<T>(key);
964 }
965
966 template<typename T>
967 T Get(const std::string &key, const std::string &deflt) const
968 {
969 return fTable.Get<T>(key, deflt);
970 }
971
972 bool SetPtrAddress(const std::string &name, void *ptr, size_t cnt=0)
973 {
974 if (fTable.cols.count(name)==0)
975 {
976 std::ostringstream str;
977 str <<"SetPtrAddress('" << name << "') - Column not found.";
978#ifdef __EXCEPTIONS
979 throw std::runtime_error(str.str());
980#else
981 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
982 return false;
983#endif
984 }
985
986 if (cnt && cnt!=fTable.cols[name].num)
987 {
988 std::ostringstream str;
989 str << "SetPtrAddress('" << name << "') - Element count mismatch: expected "
990 << fTable.cols[name].num << " from header, got " << cnt;
991#ifdef __EXCEPTIONS
992 throw std::runtime_error(str.str());
993#else
994 gLog << ___err___ << "ERROR - " << str.str() << std::endl;
995 return false;
996#endif
997 }
998
999 // if (fAddresses.count(ptr)>0)
1000 // gLog << warn << "SetPtrAddress('" << name << "') - Pointer " << ptr << " already assigned." << endl;
1001
1002 //fAddresses[ptr] = fTable.cols[name];
1003 fPointers[name] = ptr;
1004 fAddresses.emplace_back(ptr, fTable.cols[name]);
1005 sort(fAddresses.begin(), fAddresses.end(), Compare);
1006 return true;
1007 }
1008
1009 bool HasKey(const std::string &key) const { return fTable.HasKey(key); }
1010 bool HasColumn(const std::string& col) const { return fTable.HasColumn(col);}
1011 const Table::Columns &GetColumns() const { return fTable.GetColumns();}
1012 const Table::SortedColumns& GetSortedColumns() const { return fTable.sorted_cols;}
1013 const Table::Keys &GetKeys() const { return fTable.GetKeys();}
1014
1015 int64_t GetInt(const std::string &key) const { return fTable.Get<int64_t>(key); }
1016 uint64_t GetUInt(const std::string &key) const { return fTable.Get<uint64_t>(key); }
1017 double GetFloat(const std::string &key) const { return fTable.Get<double>(key); }
1018 std::string GetStr(const std::string &key) const { return fTable.Get<std::string>(key); }
1019
1020 size_t GetN(const std::string &key) const
1021 {
1022 return fTable.GetN(key);
1023 }
1024
1025// size_t GetNumRows() const { return fTable.num_rows; }
1026 size_t GetRow() const { return fRow==(size_t)-1 ? 0 : fRow; }
1027
1028 operator bool() const { return fTable && fTable.offset!=0; }
1029
1030 void PrintKeys() const { fTable.PrintKeys(); }
1031 void PrintColumns() const { fTable.PrintColumns(); }
1032
1033 bool IsHeaderOk() const { return fTable.datasum<0?false:(fChkHeader+Checksum(fTable.datasum)).valid(); }
1034 virtual bool IsFileOk() const { return (fChkHeader+fChkData).valid(); }
1035
1036 bool IsCompressedFITS() const { return fTable.is_compressed;}
1037
1038 virtual size_t GetNumRows() const
1039 {
1040 return fTable.Get<size_t>("NAXIS2");
1041 }
1042
1043 virtual size_t GetBytesPerRow() const
1044 {
1045 return fTable.Get<size_t>("NAXIS1");
1046 }
1047};
1048
1049#endif
Note: See TracBrowser for help on using the repository browser.