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

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