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

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