FACT++  1.0
ofits.h
Go to the documentation of this file.
1 #ifndef MARS_ofits
2 #define MARS_ofits
3 
4 #include "FITS.h"
5 #include "fits.h"
6 
7 #ifndef PACKAGE_NAME
8 #define PACKAGE_NAME "n/a"
9 #endif
10 
11 #ifndef PACKAGE_VERSION
12 #define PACKAGE_VERSION "n/a"
13 #endif
14 
15 #ifndef REVISION
16 #define REVISION "n/a"
17 #endif
18 
19 #ifdef __CINT__
20 #define off_t size_t
21 #endif
22 
23 // Sloppy: allow / <--- left
24 // allow all characters (see specs for what is possible)
25 
26 // units: m kg s rad sr K A mol cd Hz J W V N Pa C Ohm S F Wb T Hlm lx
27 
28 
29 class ofits : public std::ostream
30 {
31 protected:
32  std::filebuf fFilebuf;
33 
34 public:
35  struct Key
36  {
37  std::string key;
38  bool delim;
39  std::string value;
40  std::string comment;
41  std::string fitsString;
42 
43  off_t offset; // offset in file
44 
45  bool changed; // For closing the file
46 
47  Key() : delim(false), offset(0), changed(true) { }
48  Key(const std::string &s) : delim(false), fitsString(s), offset(0), changed(true) { }
49 
50  std::string Trim(const std::string &str)
51  {
52  // Trim Both leading and trailing spaces
53  const size_t first = str.find_first_not_of(' '); // Find the first character position after excluding leading blank spaces
54  const size_t last = str.find_last_not_of(' '); // Find the first character position from reverse af
55 
56  // if all spaces or empty return an empty string
57  if (std::string::npos==first || std::string::npos==last)
58  return std::string();
59 
60  return str.substr(first, last-first+1);
61  }
62 
63  bool FormatKey()
64  {
65  key = Trim(key);
66  if (key.empty())
67  {
68 #ifdef __EXCEPTIONS
69  throw std::runtime_error("Key name empty.");
70 #else
71  gLog << ___err___ << "ERROR - Key name empty." << std::endl;
72  return false;
73 #endif
74  }
75  if (key.size()>8)
76  {
77  std::ostringstream sout;
78  sout << "Key '" << key << "' exceeds 8 bytes.";
79 #ifdef __EXCEPTIONS
80  throw std::runtime_error(sout.str());
81 #else
82  gLog << ___err___ << "ERROR - " << sout.str() << std::endl;
83  return false;
84 #endif
85  }
86 
87  //transform(key.begin(), key.end(), key.begin(), toupper);
88 #if GCC_VERSION < 40603
89  for (std::string::const_iterator c=key.begin(); c<key.end(); c++)
90 #else
91  for (std::string::const_iterator c=key.cbegin(); c<key.cend(); c++)
92 #endif
93  if ((*c<'A' || *c>'Z') && (*c<'0' || *c>'9') && *c!='-' && *c!='_')
94  {
95  std::ostringstream sout;
96  sout << "Invalid character '" << *c << "' found in key '" << key << "'";
97 #ifdef __EXCEPTIONS
98  throw std::runtime_error(sout.str());
99 #else
100  gLog << ___err___ << "ERROR - " << sout.str() << std::endl;
101  return false;
102 #endif
103  }
104 
105  return true;
106  }
107 
109  {
110  comment = Trim(comment);
111 
112 #if GCC_VERSION < 40603
113  for (std::string::const_iterator c=key.begin(); c<key.end(); c++)
114 #else
115  for (std::string::const_iterator c=key.cbegin(); c<key.cend(); c++)
116 #endif
117  if (*c<32 || *c>126)
118  {
119  std::ostringstream sout;
120  sout << "Invalid character '" << *c << "' [" << int(*c) << "] found in comment '" << comment << "'";
121 #ifdef __EXCEPTIONS
122  throw std::runtime_error(sout.str());
123 #else
124  gLog << ___err___ << "ERROR - " << sout.str() << std::endl;
125  return false;
126 #endif
127  }
128 
129  return true;
130  }
131 
132  bool check(bool trim=false)
133  {
134  if (!FormatKey())
135  return false;
136 
137  if (!FormatComment())
138  return false;
139 
140  size_t sz = CalcSize();
141  if (sz<=80)
142  return true;
143 
144  if (!trim)
145  {
146  std::ostringstream sout;
147  sout << "Size " << sz << " of entry for key '" << key << "' exceeds 80 characters.";
148 #ifdef __EXCEPTIONS
149  throw std::runtime_error(sout.str());
150 #else
151  gLog << ___err___ << "ERROR - " << sout.str() << std::endl;
152 #endif
153  return false;
154  }
155 
156  //looks like something went wrong. Maybe entry is too long ?
157  //try to remove the comment
158  comment = "";
159 
160  sz = CalcSize();
161  if (sz<=80)
162  {
163 #ifndef __EXCEPTIONS
164  std::ostringstream sout;
165  sout << "Size " << sz << " of entry for key '" << key << "' exceeds 80 characters... removed comment.";
166  gLog << ___warn___ << "WARNING - " << sout.str() << std::endl;
167 #endif
168  return true;
169  }
170 
171  std::ostringstream sout;
172  sout << "Size " << sz << " of entry for key '" << key << "' exceeds 80 characters even without comment.";
173 #ifdef __EXCEPTIONS
174  throw std::runtime_error(sout.str());
175 #else
176  gLog << ___err___ << "ERROR - " << sout.str() << std::endl;
177  return false;
178 #endif
179  }
180 
181  size_t CalcSize() const
182  {
183  if (!delim)
184  return 10+comment.size();
185 
186  return 10 + (value.size()<20?20:value.size()) + 3 + comment.size();
187  }
188 
189  std::string Compile()
190  {
191  if (!fitsString.empty())
192  return fitsString;
193 
194  std::ostringstream sout;
195  sout << std::left << std::setw(8) << key;
196 
197  if (!delim)
198  {
199  sout << " " << comment;
200  return sout.str();
201  }
202 
203  sout << "= ";
204  sout << (!value.empty() && value[0]=='\''?std::left:std::right);
205  sout << std::setw(20) << value << std::left;
206 
207  if (!comment.empty())
208  sout << " / " << comment;
209 
210  return sout.str();
211  }
212 
214 
215  void Out(std::ostream &fout)
216  {
217  if (!changed)
218  return;
219 
220  std::string str = Compile();
221  str.insert(str.end(), 80-str.size(), ' ');
222 
223  if (offset==0)
224  offset = fout.tellp();
225 
226  //cout << "Write[" << offset << "]: " << key << "/" << value << endl;
227 
228  fout.seekp(offset);
229  fout << str;
230 
231  checksum.reset();
232  checksum.add(str.c_str(), 80);
233 
234  changed = false;
235  }
236  /*
237  void Out(ostream &out)
238  {
239  std::string str = Compile();
240 
241  str.insert(str.end(), 80-str.size(), ' ');
242 
243  out << str;
244  changed = false;
245  }*/
246  };
247 
248 private:
249  std::vector<Key> fKeys;
250 
251  std::vector<Key>::iterator findkey(const std::string &key)
252  {
253  for (auto it=fKeys.begin(); it!=fKeys.end(); it++)
254  if (key==it->key)
255  return it;
256 
257  return fKeys.end();
258  }
259 
260  bool Set(const std::string &key="", bool delim=false, const std::string &value="", const std::string &comment="")
261  {
262  // If no delimit add the row no matter if it alread exists
263  if (delim)
264  {
265  // if the row already exists: update it
266  auto it = findkey(key);
267  if (it!=fKeys.end())
268  {
269  it->value = value;
270  it->changed = true;
271  return true;
272  }
273  }
274 
275  if (fTable.num_rows>0)
276  {
277  std::ostringstream sout;
278  sout << "No new header key can be defined, rows were already written to the file... ignoring new key '" << key << "'";
279 #ifdef __EXCEPTIONS
280  throw std::runtime_error(sout.str());
281 #else
282  gLog << ___err___ << "ERROR - " << sout.str() << std::endl;
283  return false;
284 #endif
285  }
286 
287  Key entry;
288 
289  entry.key = key;
290  entry.delim = delim;
291  entry.value = value;
292  entry.comment = comment;
293 
294  if (!entry.check(fCommentTrimming))
295  return false;
296 
297  fKeys.emplace_back(entry);
298  return true;
299  }
300 
301 protected:
302  struct Table
303  {
304  off_t offset;
305 
307  size_t num_rows;
308  size_t num_cols;
309 
310  struct Column
311  {
312  std::string name;
313  size_t offset;
314  size_t num;
315  size_t size;
316  char type;
317  };
318 
319  std::vector<Column> cols;
320 
321  Table() : offset(0), bytes_per_row(0), num_rows(0), num_cols(0)
322  {
323  }
324  };
325 
326 
328 
329  std::vector<char> fOutputBuffer;
330 
331  std::vector<Table::Column>::const_iterator findcol(const std::string &name)
332  {
333  for (auto it=fTable.cols.cbegin(); it!=fTable.cols.cend(); it++)
334  if (name==it->name)
335  return it;
336 
337  return fTable.cols.cend();
338  }
339 
342 
345 
346 public:
348  : std::ostream(), fFilebuf(), fCommentTrimming(false), fManualExtName(false)
349  {
350  init(&fFilebuf);
351  }
352 
353  ofits(const char *fname)
354  : std::ostream(), fFilebuf(), fCommentTrimming(false), fManualExtName(false)
355  {
356  init(&fFilebuf);
357  open(fname);
358  }
359 
360 #ifdef __GXX_EXPERIMENTAL_CXX0X__
361  ofits(const std::string &fname)
362  : std::ostream(), fCommentTrimming(false), fManualExtName(false)
363  {
364  init(&fFilebuf);
365  open(fname);
366  }
367 #endif
368 
369  virtual ~ofits()
370  {
371  if (is_open())
372  close();
373  }
374 /*
375  filebuf *rdbuf() const
376  {
377  return const_cast<filebuf*>(&fFilebuf);
378  }
379 */
380  bool is_open()
381  {
382  return fFilebuf.is_open();
383  }
384 
385  bool is_open() const
386  {
387  return fFilebuf.is_open();
388  }
389 
390  virtual void open(const char *filename, bool addEXTNAMEKey=true)
391  {
392  fDataSum = 0;
393  fHeaderSum = 0;
394 
395  fTable = Table();
396  fKeys.clear();
397 
398  SetStr("XTENSION", "BINTABLE", "binary table extension");
399  SetInt("BITPIX", 8, "8-bit bytes");
400  SetInt("NAXIS", 2, "2-dimensional binary table");
401  SetInt("NAXIS1", 0, "width of table in bytes");
402  SetInt("NAXIS2", 0, "number of rows in table");
403  SetInt("PCOUNT", 0, "size of special data area");
404  SetInt("GCOUNT", 1, "one data group (required keyword)");
405  SetInt("TFIELDS", 0, "number of fields in each row");
406  if (addEXTNAMEKey)
407  SetStr("EXTNAME", "", "name of extension table");
408  else
409  fManualExtName = true;
410  SetStr("CHECKSUM", "0000000000000000", "Checksum for the whole HDU");
411  SetStr("DATASUM", " 0", "Checksum for the data block");
412 
413  if (!fFilebuf.open(filename, ios_base::out|ios_base::trunc))
414  setstate(ios_base::failbit);
415  else
416  clear();
417  }
418 
419  virtual void open(const std::string &filename, bool addEXTNAMEKey=true)
420  {
421  open(filename.c_str(), addEXTNAMEKey);
422  }
423 
424  void AllowCommentsTrimming(bool allow)
425  {
426  fCommentTrimming = allow;
427  }
428 
429  //Etienne: required to enable 1 to 1 reconstruction of files
430  bool SetKeyComment(const std::string& key, const std::string& comment)
431  {
432  auto it = findkey(key);
433  if (it==fKeys.end())
434  return false;
435 
436  it->comment = comment;
437  it->changed = true;
438  return true;
439  }
440  /* tbretz, I removed that, because it does not comply
441  with the FITS standard, it omits all checks... it
442  neither checks if a row already exists, not
443  checks the chcracter set
444  bool SetKeyFromFitsString(const std::string& fitsString)
445  {
446  if (fTable.num_rows>0)
447  {
448  std::ostringstream sout;
449  sout << "No new header key can be defined, rows were already written to the file... ignoring new key '" << fitsString << "'";
450 #ifdef __EXCEPTIONS
451  throw std::runtime_error(sout.str());
452 #else
453  gLog << ___err___ << "ERROR - " << sout.str() << std::endl;
454  return false;
455 #endif
456  }
457 
458  Key entry;
459  entry.fitsString = fitsString;
460  entry.changed = true;
461  fKeys.push_back(entry);
462  return true;
463 }*/
464 
465 
466  bool CopyKeys(const fits &fin, bool update=false)
467  {
468  if (fTable.num_rows>0)
469  {
470 #ifdef __EXCEPTIONS
471  throw std::runtime_error("No header keys can be copied, rows were already written to the file... ignoring CopyKeys().");
472 #else
473  gLog << ___err___ << "ERROR - No header key can be copyied, rows were already written to the file... ignoring CopyKeys()." << std::endl;
474  return false;
475 #endif
476  }
477 
478  const auto &keys = fin.GetKeys();
479 
480  // We can assume that the keys are all valid
481  for (auto it=keys.cbegin(); it!=keys.cend(); it++)
482  {
483  const std::string &key = it->first;
484 
485  if (FITS::IsReservedKeyWord(key))
486  continue;
487 
488  const auto &entry = it->second;
489 
490  // If no delimit add the row no matter if it alread exists
491  if (entry.fitsString[9]=='=')
492  {
493  // if the row already exists: remove it
494  const auto it2 = findkey(key);
495  if (it2!=fKeys.end())
496  {
497  if (!update)
498  continue;
499 
500  fKeys.erase(it2);
501  }
502  }
503 
504  fKeys.emplace_back(entry.fitsString);
505  }
506 
507  return true;
508  }
509 
510 
511  bool SetRaw(const std::string &key, const std::string &val, const std::string &comment)
512  {
513  return Set(key, true, val, comment);
514  }
515 
516  bool SetBool(const std::string &key, bool b, const std::string &comment="")
517  {
518  return Set(key, true, b?"T":"F", comment);
519  }
520 
521  bool AddEmpty(const std::string &key, const std::string &comment="")
522  {
523  return Set(key, true, "", comment);
524  }
525 
526  bool SetStr(const std::string &key, std::string s, const std::string &comment="")
527  {
528  for (uint i=0; i<s.length(); i++)
529  if (s[i]=='\'')
530  s.insert(i++, "\'");
531 
532  return Set(key, true, "'"+s+"'", comment);
533  }
534 
535  bool SetInt(const std::string &key, int64_t i, const std::string &comment="")
536  {
537  std::ostringstream sout;
538  sout << i;
539 
540  return Set(key, true, sout.str(), comment);
541  }
542 
543  bool SetFloat(const std::string &key, double f, int p, const std::string &comment="")
544  {
545  std::ostringstream sout;
546 
547  if (p<0)
548  sout << std::setprecision(-p) << fixed;
549  if (p>0)
550  sout << std::setprecision(p);
551  if (p==0)
552  sout << std::setprecision(f>1e-100 && f<1e100 ? 15 : 14);
553 
554  sout << f;
555 
556  std::string str = sout.str();
557 
558  replace(str.begin(), str.end(), 'e', 'E');
559 
560  if (str.find_first_of('E')==std::string::npos && str.find_first_of('.')==std::string::npos)
561  str += ".";
562 
563  return Set(key, true, str, comment);
564  }
565 
566  bool SetFloat(const std::string &key, double f, const std::string &comment="")
567  {
568  return SetFloat(key, f, 0, comment);
569  }
570 
571  bool SetHex(const std::string &key, uint64_t i, const std::string &comment="")
572  {
573  std::ostringstream sout;
574  sout << std::hex << "0x" << i;
575  return SetStr(key, sout.str(), comment);
576  }
577 
578  bool AddComment(const std::string &comment)
579  {
580  return Set("COMMENT", false, "", comment);
581  }
582 
583  bool AddHistory(const std::string &comment)
584  {
585  return Set("HISTORY", false, "", comment);
586  }
587 
588  void End()
589  {
590  Set("END");
591  while (fKeys.size()%36!=0)
592  fKeys.emplace_back();
593  }
594 
595  //ETIENNE to be able to restore the file 1 to 1, I must restore the header keys myself
596  virtual bool AddColumn(uint32_t cnt, char typechar, const std::string &name, const std::string &unit, const std::string &comment="", bool addHeaderKeys=true)
597  {
598  if (tellp()<0)
599  {
600  std::ostringstream sout;
601  sout << "File not open... ignoring column '" << name << "'";
602 #ifdef __EXCEPTIONS
603  throw std::runtime_error(sout.str());
604 #else
605  gLog << ___err___ << "ERROR - " << sout.str() << std::endl;
606  return false;
607 #endif
608  }
609 
610  if (tellp()>0)
611  {
612  std::ostringstream sout;
613  sout << "Header already written, no new column can be defined... ignoring column '" << name << "'";
614 #ifdef __EXCEPTIONS
615  throw std::runtime_error(sout.str());
616 #else
617  gLog << ___err___ << "ERROR - " << sout.str() << std::endl;
618  return false;
619 #endif
620  }
621 
622  if (findcol(name)!=fTable.cols.cend())
623  {
624  std::ostringstream sout;
625  sout << "A column with the name '" << name << "' already exists.";
626 #ifdef __EXCEPTIONS
627  throw std::runtime_error(sout.str());
628 #else
629  gLog << ___err___ << "ERROR - " << sout.str() << std::endl;
630  return false;
631 #endif
632  }
633 
634  typechar = toupper(typechar);
635 
636  static const std::string allow("LABIJKEDQ");
637 #if GCC_VERSION < 40603
638  if (std::find(allow.begin(), allow.end(), typechar)==allow.end())
639 #else
640  if (std::find(allow.cbegin(), allow.cend(), typechar)==allow.end())
641 #endif
642  {
643  std::ostringstream sout;
644  sout << "Column type '" << typechar << "' not supported.";
645 #ifdef __EXCEPTIONS
646  throw std::runtime_error(sout.str());
647 #else
648  gLog << ___err___ << "ERROR - " << sout.str() << std::endl;
649  return false;
650 #endif
651  }
652 
653  std::ostringstream type;
654  type << cnt;
655  if (typechar=='Q')
656  type << "QB";
657  else
658  type << typechar;
659 
660  fTable.num_cols++;
661 
662  if (addHeaderKeys)
663  {
664 #if GCC_VERSION < 40603
665  const std::string nc = std::to_string((long long int)(fTable.num_cols));
666 #else
667  const std::string nc = std::to_string(fTable.num_cols);
668 #endif
669  SetStr("TFORM"+nc, type.str(), "format of "+name+" "+FITS::CommentFromType(typechar));
670  SetStr("TTYPE"+nc, name, comment);
671  if (!unit.empty())
672  SetStr("TUNIT"+nc, unit, "unit of "+name);
673  }
674 
675  const size_t size = FITS::SizeFromType(typechar);
676 
677  Table::Column col;
678 
679  col.name = name;
680  col.type = typechar;
681  col.num = cnt;
682  col.size = size;
683  col.offset = fTable.bytes_per_row;
684 
685  fTable.cols.emplace_back(col);
686 
687  fTable.bytes_per_row += size*cnt;
688 
689  // Align to four bytes
690  fOutputBuffer.resize(fTable.bytes_per_row + 4-fTable.bytes_per_row%4);
691 
692  return true;
693  }
694 
695  virtual bool AddColumn(const FITS::Compression&, uint32_t cnt, char typechar, const std::string& name, const std::string& unit, const std::string& comment="", bool addHeaderKeys=true)
696  {
697  return AddColumn(cnt, typechar, name, unit, comment, addHeaderKeys);
698  }
699 
700  bool AddColumnShort(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
701  { return AddColumn(cnt, 'I', name, unit, comment); }
702  bool AddColumnInt(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
703  { return AddColumn(cnt, 'J', name, unit, comment); }
704  bool AddColumnLong(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
705  { return AddColumn(cnt, 'K', name, unit, comment); }
706  bool AddColumnFloat(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
707  { return AddColumn(cnt, 'E', name, unit, comment); }
708  bool AddColumnDouble(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
709  { return AddColumn(cnt, 'D', name, unit, comment); }
710  bool AddColumnChar(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
711  { return AddColumn(cnt, 'A', name, unit, comment); }
712  bool AddColumnByte(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
713  { return AddColumn(cnt, 'B', name, unit, comment); }
714  bool AddColumnBool(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
715  { return AddColumn(cnt, 'L', name, unit, comment); }
716 
717  bool AddColumnShort(const std::string &name, const std::string &unit="", const std::string &comment="")
718  { return AddColumn(1, 'I', name, unit, comment); }
719  bool AddColumnInt(const std::string &name, const std::string &unit="", const std::string &comment="")
720  { return AddColumn(1, 'J', name, unit, comment); }
721  bool AddColumnLong(const std::string &name, const std::string &unit="", const std::string &comment="")
722  { return AddColumn(1, 'K', name, unit, comment); }
723  bool AddColumnFloat(const std::string &name, const std::string &unit="", const std::string &comment="")
724  { return AddColumn(1, 'E', name, unit, comment); }
725  bool AddColumnDouble(const std::string &name, const std::string &unit="", const std::string &comment="")
726  { return AddColumn(1, 'D', name, unit, comment); }
727  bool AddColumnChar(const std::string &name, const std::string &unit="", const std::string &comment="")
728  { return AddColumn(1, 'A', name, unit, comment); }
729  bool AddColumnByte(const std::string &name, const std::string &unit="", const std::string &comment="")
730  { return AddColumn(1, 'B', name, unit, comment); }
731  bool AddColumnBool(const std::string &name, const std::string &unit="", const std::string &comment="")
732  { return AddColumn(1, 'L', name, unit, comment); }
733 
734  bool AddColumnShort(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
735  { return AddColumn(comp, cnt, 'I', name, unit, comment); }
736  bool AddColumnInt(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
737  { return AddColumn(comp, cnt, 'J', name, unit, comment); }
738  bool AddColumnLong(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
739  { return AddColumn(comp, cnt, 'K', name, unit, comment); }
740  bool AddColumnFloat(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
741  { return AddColumn(comp, cnt, 'E', name, unit, comment); }
742  bool AddColumnDouble(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
743  { return AddColumn(comp, cnt, 'D', name, unit, comment); }
744  bool AddColumnChar(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
745  { return AddColumn(comp, cnt, 'A', name, unit, comment); }
746  bool AddColumnByte(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
747  { return AddColumn(comp, cnt, 'B', name, unit, comment); }
748  bool AddColumnBool(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
749  { return AddColumn(comp, cnt, 'L', name, unit, comment); }
750 
751  bool AddColumnShort(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
752  { return AddColumn(comp, 1, 'I', name, unit, comment); }
753  bool AddColumnInt(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
754  { return AddColumn(comp, 1, 'J', name, unit, comment); }
755  bool AddColumnLong(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
756  { return AddColumn(comp, 1, 'K', name, unit, comment); }
757  bool AddColumnFloat(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
758  { return AddColumn(comp, 1, 'E', name, unit, comment); }
759  bool AddColumnDouble(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
760  { return AddColumn(comp, 1, 'D', name, unit, comment); }
761  bool AddColumnChar(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
762  { return AddColumn(comp, 1, 'A', name, unit, comment); }
763  bool AddColumnByte(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
764  { return AddColumn(comp, 1, 'B', name, unit, comment); }
765  bool AddColumnBool(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
766  { return AddColumn(comp, 1, 'L', name, unit, comment); }
767 
768  /*
769  bool AddKey(string key, double d, const std::string &comment)
770  {
771  ostringstream out;
772  out << d;
773 
774  std::string s = out.str();
775 
776  replace(s.begin(), s.end(), "e", "E");
777 
778  return AddKey(key, s, comment);
779  }*/
780 
781 
782  Checksum WriteHeader(std::ostream &fout)
783  {
784  Checksum sum;
785  uint32_t count=0;
786  for (auto it=fKeys.begin(); it!=fKeys.end(); it++)
787  {
788  it->Out(fout);
789  sum += it->checksum;
790  count++;
791  }
792  fout.flush();
793 
794  return sum;
795  }
796 
798  {
799  return WriteHeader(*this);
800  }
801 
802  void FlushHeader()
803  {
804  const off_t pos = tellp();
805  WriteHeader();
806  seekp(pos);
807  }
808 
810  {
811  ofits h;
812 
813  h.SetBool("SIMPLE", true, "file does conform to FITS standard");
814  h.SetInt ("BITPIX", 8, "number of bits per data pixel");
815  h.SetInt ("NAXIS", 0, "number of data axes");
816  h.SetBool("EXTEND", true, "FITS dataset may contain extensions");
817  h.SetStr ("CHECKSUM","0000000000000000", "Checksum for the whole HDU");
818  h.SetStr ("DATASUM", " 0", "Checksum for the data block");
819  h.AddComment("FITS (Flexible Image Transport System) format is defined in 'Astronomy");
820  h.AddComment("and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H");
821  h.End();
822 
823  const Checksum sum = h.WriteHeader(*this);
824 
825  h.SetStr("CHECKSUM", sum.str());
826 
827  const size_t offset = tellp();
828  h.WriteHeader(*this);
829  seekp(offset);
830 
831  return sum;
832  }
833 
834  virtual bool WriteDrsOffsetsTable ()
835  {
836  return true;
837  }
838 
839  virtual bool WriteCatalog()
840  {
841  return true;
842  }
843 
844  virtual bool WriteTableHeader(const char *name="DATA")
845  {
846  if (tellp()>0)
847  {
848 #ifdef __EXCEPTIONS
849  throw std::runtime_error("File not empty anymore.");
850 #else
851  gLog << ___err___ << "ERROR - File not empty anymore." << std::endl;
852  return false;
853 #endif
854  }
855 
856  fHeaderSum = WriteFitsHeader();
857 
859 
860  if (!fManualExtName)
861  SetStr("EXTNAME", name);
862  SetInt("NAXIS1", fTable.bytes_per_row);
863  SetInt("TFIELDS", fTable.cols.size());
864 
865  End();
866 
867  WriteHeader();
868 
869  WriteCatalog();
870 
871  return good();
872  }
873 
874  template<size_t N>
875  void revcpy(char *dest, const char *src, int num)
876  {
877  const char *pend = src + num*N;
878  for (const char *ptr = src; ptr<pend; ptr+=N, dest+=N)
879  std::reverse_copy(ptr, ptr+N, dest);
880  }
881 
882  virtual uint32_t GetBytesPerRow() const { return fTable.bytes_per_row; }
883 
884  virtual bool WriteRow(const void *ptr, size_t cnt, bool byte_swap=true)
885  {
886  // FIXME: Make sure that header was already written
887  // or write header now!
888  if (cnt!=fTable.bytes_per_row)
889  {
890  std::ostringstream sout;
891  sout << "WriteRow - Size " << cnt << " does not match expected size " << fTable.bytes_per_row;
892 #ifdef __EXCEPTIONS
893  throw std::runtime_error(sout.str());
894 #else
895  gLog << ___err___ << "ERROR - " << sout.str() << std::endl;
896  return false;
897 #endif
898  }
899 
900  // For the checksum we need everything to be correctly aligned
901  const uint8_t offset = fTable.offset%4;
902 
903  char *buffer = fOutputBuffer.data() + offset;
904 
905  auto ib = fOutputBuffer.begin();
906  auto ie = fOutputBuffer.rbegin();
907  *ib++ = 0;
908  *ib++ = 0;
909  *ib++ = 0;
910  *ib = 0;
911 
912  *ie++ = 0;
913  *ie++ = 0;
914  *ie++ = 0;
915  *ie = 0;
916 
917  if (!byte_swap)
918  memcpy(buffer, ptr, cnt);
919  else
920  {
921  for (auto it=fTable.cols.cbegin(); it!=fTable.cols.cend(); it++)
922  {
923  const char *src = reinterpret_cast<const char*>(ptr) + it->offset;
924  char *dest = buffer + it->offset;
925 
926  // Let the compiler do some optimization by
927  // knowing the we only have 1, 2, 4 and 8
928  switch (it->size)
929  {
930  case 1: memcpy (dest, src, it->num*it->size); break;
931  case 2: revcpy<2>(dest, src, it->num); break;
932  case 4: revcpy<4>(dest, src, it->num); break;
933  case 8: revcpy<8>(dest, src, it->num); break;
934  }
935  }
936  }
937 
938  write(buffer, cnt);
939  fDataSum.add(fOutputBuffer);
940 
941  fTable.num_rows++;
942  fTable.offset += cnt;
943  return good();
944  }
945 
946  template<typename N>
947  bool WriteRow(const std::vector<N> &vec)
948  {
949  return WriteRow(vec.data(), vec.size()*sizeof(N));
950  }
951 
952  // Flushes the number of rows to the header on disk
953  virtual void FlushNumRows()
954  {
955  SetInt("NAXIS2", fTable.num_rows);
956  FlushHeader();
957  }
958 
959  size_t GetNumRows() const { return fTable.num_rows; }
960 
962  {
963  if (tellp()%(80*36)>0)
964  {
965  std::vector<char> filler(80*36-tellp()%(80*36));
966  write(filler.data(), filler.size());
967  }
968  }
969 
971  {
972  std::ostringstream dataSumStr;
973  dataSumStr << fDataSum.val();
974  SetStr("DATASUM", dataSumStr.str());
975 
976  const Checksum sum = WriteHeader();
977 
978  //sum += headersum;
979 
980  SetStr("CHECKSUM", (sum+fDataSum).str());
981 
982  return WriteHeader();
983  }
984  virtual bool close()
985  {
986  if (tellp()<0)
987  return false;
988 
990 
991  // We don't have to jump back to the end of the file
992  SetInt("NAXIS2", fTable.num_rows);
993 
994  const Checksum chk = UpdateHeaderChecksum();
995 
996  if (!fFilebuf.close())
997  setstate(ios_base::failbit);
998 
999  if ((chk+fDataSum).valid())
1000  return true;
1001 
1002  std::ostringstream sout;
1003  sout << "Checksum (" << std::hex << chk.val() << ") invalid.";
1004 #ifdef __EXCEPTIONS
1005  throw std::runtime_error(sout.str());
1006 #else
1007  gLog << ___err___ << "ERROR - " << sout.str() << std::endl;
1008  return false;
1009 #endif
1010  }
1011 
1012  std::pair<std::string, int> GetChecksumData()
1013  {
1014  std::string datasum;
1015  std::string checksum;
1016  //cannot directly use the Get methods, because they are only in fits.h
1017  for (std::vector<Key>::const_iterator it=fKeys.cbegin(); it!= fKeys.cend(); it++)
1018  {
1019  if (it->key == "CHECKSUM") checksum = it->value;
1020  if (it->key == "DATASUM") datasum = it->value;
1021  }
1022  if (checksum[0] == '\'')
1023  checksum = checksum.substr(1,checksum.size()-2);
1024  if (datasum[0] == '\'')
1025  datasum = datasum.substr(1, datasum.size()-2);
1026  return std::make_pair(checksum, atoi(datasum.c_str()));
1027  }
1028 
1030  {
1031  SetStr("TELESCOP", "FACT", "Telescope that acquired this data");
1032  SetStr("CREATOR", typeid(*this).name(), "Class that wrote this file");
1033  SetFloat("EXTREL", 1.0, "Release Number");
1034  SetStr("COMPILED", __DATE__" " __TIME__, "Compile time");
1035  SetStr("ORIGIN", "FACT", "Institution that wrote the file");
1036  SetStr("TIMESYS", "UTC", "Time system");
1037  SetStr("TIMEUNIT", "d", "Time given in days w.r.t. to MJDREF");
1038  SetInt("MJDREF", 40587, "MJD to UNIX time (seconds since 1970/1/1)");
1039  SetStr("PACKAGE", PACKAGE_NAME, "Package name");
1040  SetStr("VERSION", PACKAGE_VERSION, "Package description");
1041  SetStr("REVISION", REVISION, "SVN revision");
1042 
1043  const time_t t0 = time(NULL);
1044  const struct tm *tmp1 = gmtime(&t0);
1045 
1046  std::string str(19, '\0');
1047  if (tmp1 && strftime(const_cast<char*>(str.data()), 20, "%Y-%m-%dT%H:%M:%S", tmp1))
1048  SetStr("DATE", str, "File creation date");
1049  }
1050 };
1051 
1052 #if 0
1053 #include "fits.h"
1054 
1055 int main()
1056 {
1057  using namespace std;
1058 
1059  ofits h2("delme.fits");
1060 
1061  h2.SetInt("KEY1", 1, "comment 1");
1062  h2.AddColumnInt(2, "testcol1", "counts", "My comment");
1063  h2.AddColumnInt("testcol2", "counts", "My comment");
1064  //h2.AddColumnInt("testcol2", "counts", "My comment");
1065  h2.SetInt("KEY2", 2, "comment 2");
1066 
1067  /*
1068  AddFloat("X0", 0.000123456, "number of fields in each row");
1069  AddFloat("X1", 0, "number of fields in each row");
1070  AddFloat("X2", 12345, "number of fields in each row");
1071  AddFloat("X3", 123456.67890, "number of fields in each row");
1072  AddFloat("X4", 1234567890123456789.12345678901234567890, "number of fields in each row");
1073  AddFloat("X5", 1234567890.1234567890e20, "number of fields in each row");
1074  AddFloat("X6", 1234567890.1234567890e-20, "number of fields in each row");
1075  AddFloat("XB", 1234567890.1234567890e-111, "number of fields in each row");
1076  AddFloat("X7", 1e-5, "number of fields in each row");
1077  AddFloat("X8", 1e-6, "number of fields in each row");
1078  //AddStr("12345678", "123456789012345678", "12345678901234567890123456789012345678901234567");
1079  */
1080  // -
1081 
1082  h2.WriteTableHeader("TABLE_NAME");
1083 
1084  for (int i=0; i<10; i++)
1085  {
1086  int j[3] = { i+10, i*10, i*100 };
1087  h2.WriteRow(j, 3*sizeof(i));
1088  }
1089 
1090  //h2.AddColumnInt("testcol2", "counts", "My comment");
1091  //h2.SetInt("KEY3", 2, "comment 2");
1092  h2.SetInt("KEY2", 2, "comment 2xxx");
1093  h2.SetInt("KEY1", 11);
1094 
1095  h2.close();
1096 
1097  cout << "---" << endl;
1098 
1099  fits f("delme.fits");
1100  if (!f)
1101  throw std::runtime_error("xxx");
1102 
1103  cout << "Header is valid: " << f.IsHeaderOk() << endl;
1104 
1105  while (f.GetNextRow());
1106 
1107  cout << "File is valid: " << f.IsFileOk() << endl;
1108 
1109  cout << "---" << endl;
1110 
1111  return 0;
1112 }
1113 #endif
1114 
1115 #endif
bool SetInt(const std::string &key, int64_t i, const std::string &comment="")
Definition: ofits.h:535
#define PACKAGE_NAME
Definition: ofits.h:8
bool AddColumnByte(const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:729
bool SetHex(const std::string &key, uint64_t i, const std::string &comment="")
Definition: ofits.h:571
virtual ~ofits()
Definition: ofits.h:369
void AlignTo2880Bytes()
Definition: ofits.h:961
static bool IsReservedKeyWord(const std::string &key)
Definition: FITS.h:26
Checksum WriteHeader()
Definition: ofits.h:797
Checksum fDataSum
Definition: ofits.h:340
std::string fitsString
Definition: ofits.h:41
void FlushHeader()
Definition: ofits.h:802
void init(S &s)
Definition: ByteOrder.h:19
Checksum UpdateHeaderChecksum()
Definition: ofits.h:970
bool AddColumnLong(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:738
bool AddColumnLong(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:755
std::string key
Definition: ofits.h:37
virtual void open(const std::string &filename, bool addEXTNAMEKey=true)
Definition: ofits.h:419
bool AddColumnShort(const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:717
bool AddColumnDouble(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:759
bool AddColumnDouble(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:742
bool WriteRow(const std::vector< N > &vec)
Definition: ofits.h:947
void revcpy(char *dest, const char *src, int num)
Definition: ofits.h:875
Checksum checksum
Definition: ofits.h:213
Key()
Definition: ofits.h:47
std::pair< std::string, int > GetChecksumData()
Definition: ofits.h:1012
int i
Definition: db_dim_client.c:21
char str[80]
Definition: test_client.c:7
void SetDefaultKeys()
Definition: ofits.h:1029
bool is_open()
Definition: ofits.h:380
bool check(bool trim=false)
Definition: ofits.h:132
bool SetKeyComment(const std::string &key, const std::string &comment)
Definition: ofits.h:430
off_t offset
Definition: ofits.h:304
STL namespace.
bool AddColumnByte(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:712
bool AddHistory(const std::string &comment)
Definition: ofits.h:583
bool AddColumnByte(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:763
void Out(std::ostream &fout)
Definition: ofits.h:215
virtual uint32_t GetBytesPerRow() const
Definition: ofits.h:882
bool is_open() const
Definition: ofits.h:385
bool CopyKeys(const fits &fin, bool update=false)
Definition: ofits.h:466
virtual bool AddColumn(uint32_t cnt, char typechar, const std::string &name, const std::string &unit, const std::string &comment="", bool addHeaderKeys=true)
Definition: ofits.h:596
bool changed
Definition: ofits.h:45
#define PACKAGE_VERSION
Definition: ofits.h:12
bool SetBool(const std::string &key, bool b, const std::string &comment="")
Definition: ofits.h:516
bool AddColumnChar(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:710
int64_t first
Size of this column in the tile.
Definition: zofits.h:26
Checksum fHeaderSum
Definition: ofits.h:341
uint32_t val() const
Definition: checksum.h:20
#define REVISION
Definition: ofits.h:16
bool AddColumnFloat(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:740
#define gLog
Definition: fits.h:36
bool FormatKey()
Definition: ofits.h:63
bool AddComment(const std::string &comment)
Definition: ofits.h:578
virtual bool WriteDrsOffsetsTable()
Definition: ofits.h:834
ofits()
Definition: ofits.h:347
bool AddColumnInt(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:753
bool delim
Definition: ofits.h:38
bool AddColumnInt(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:702
bool AddColumnChar(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:744
#define ___err___
Definition: fits.h:37
bool AddColumnShort(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:700
bool GetNextRow(bool check=true)
Definition: fits.h:851
bool AddColumnChar(const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:727
bool AddColumnBool(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:748
Table fTable
Definition: ofits.h:327
static uint32_t SizeFromType(char type)
Definition: FITS.h:70
size_t bytes_per_row
Definition: ofits.h:306
const Table::Keys & GetKeys() const
Definition: fits.h:1006
std::vector< Column > cols
Definition: ofits.h:319
bool AddColumnFloat(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:706
Definition: fits.h:54
virtual void open(const char *filename, bool addEXTNAMEKey=true)
Definition: ofits.h:390
bool AddColumnLong(const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:721
Definition: ofits.h:29
bool SetStr(const std::string &key, std::string s, const std::string &comment="")
Definition: ofits.h:526
int type
std::filebuf fFilebuf
Definition: ofits.h:32
void reset()
Definition: checksum.h:15
std::vector< Key > fKeys
Definition: ofits.h:249
bool FormatComment()
Definition: ofits.h:108
bool AddColumnDouble(const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:725
Key(const std::string &s)
Definition: ofits.h:48
virtual bool AddColumn(const FITS::Compression &, uint32_t cnt, char typechar, const std::string &name, const std::string &unit, const std::string &comment="", bool addHeaderKeys=true)
Definition: ofits.h:695
bool AddColumnBool(const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:731
std::string comment
Definition: ofits.h:40
virtual bool WriteCatalog()
Definition: ofits.h:839
virtual bool close()
Definition: ofits.h:984
bool AddColumnFloat(const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:723
bool SetRaw(const std::string &key, const std::string &val, const std::string &comment)
Definition: ofits.h:511
size_t CalcSize() const
Definition: ofits.h:181
std::string str(bool complm=true) const
Definition: checksum.h:148
#define ___warn___
Definition: fits.h:38
Warning because the service this data corrsponds to might have been last updated longer ago than Local time
Definition: smartfact.txt:92
std::vector< Table::Column >::const_iterator findcol(const std::string &name)
Definition: ofits.h:331
void AllowCommentsTrimming(bool allow)
Definition: ofits.h:424
std::vector< Key >::iterator findkey(const std::string &key)
Definition: ofits.h:251
bool AddColumnChar(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:761
virtual void FlushNumRows()
Definition: ofits.h:953
int buffer[BUFFSIZE]
Definition: db_dim_client.c:14
bool AddColumnInt(const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:719
int count
Definition: db_dim_server.c:18
bool AddColumnByte(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:746
bool Set(const std::string &key="", bool delim=false, const std::string &value="", const std::string &comment="")
Definition: ofits.h:260
bool AddColumnShort(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:751
bool AddColumnShort(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:734
std::string Trim(const std::string &str)
Definition: ofits.h:50
int size
Definition: db_dim_server.c:17
size_t num_cols
Definition: ofits.h:308
bool AddColumnBool(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:714
size_t num_rows
Definition: ofits.h:307
bool SetFloat(const std::string &key, double f, int p, const std::string &comment="")
Definition: ofits.h:543
bool IsHeaderOk() const
Definition: fits.h:1026
std::vector< char > fOutputBuffer
Definition: ofits.h:329
void End()
Definition: ofits.h:588
std::string name
Definition: ofits.h:312
std::string Compile()
Definition: ofits.h:189
void clear()
Definition: HeadersFTM.h:216
virtual bool IsFileOk() const
Definition: fits.h:1027
bool AddColumnFloat(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:757
bool fManualExtName
Definition: ofits.h:344
size_t GetNumRows() const
Definition: ofits.h:959
bool AddColumnInt(const FITS::Compression &comp, uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:736
off_t offset
Definition: ofits.h:43
virtual bool WriteTableHeader(const char *name="DATA")
Definition: ofits.h:844
static std::string CommentFromType(char type)
Definition: FITS.h:50
ofits(const char *fname)
Definition: ofits.h:353
bool add(const char *buf, size_t len, bool big_endian=true)
Definition: checksum.h:49
Checksum WriteHeader(std::ostream &fout)
Definition: ofits.h:782
bool AddColumnLong(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:704
std::string value
Definition: ofits.h:39
bool AddColumnDouble(uint32_t cnt, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:708
bool AddColumnBool(const FITS::Compression &comp, const std::string &name, const std::string &unit="", const std::string &comment="")
Definition: ofits.h:765
virtual bool WriteRow(const void *ptr, size_t cnt, bool byte_swap=true)
Definition: ofits.h:884
Checksum WriteFitsHeader()
Definition: ofits.h:809
bool AddEmpty(const std::string &key, const std::string &comment="")
Definition: ofits.h:521
bool fCommentTrimming
Definition: ofits.h:343
bool SetFloat(const std::string &key, double f, const std::string &comment="")
Definition: ofits.h:566
#define main
Definition: dns.c:14