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