source: trunk/Mars/mcore/ofits.h@ 17205

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