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

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