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

Last change on this file since 16358 was 16331, checked in by lyard, 12 years ago
Added comment functions to ofits.h
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.size()==0)
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[0]=='\''?std::left:std::right);
198 sout << setw(20) << value << std::left;
199
200 if (comment.size()>0)
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 (string::iterator c=s.begin(); c<s.end(); c++)
431 if (*c=='\'')
432 s.insert(c++, '\'');
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.push_back(Key());
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 col.name = name;
599 col.type = typechar;
600 col.num = cnt;
601 col.size = size;
602 col.offset = fTable.bytes_per_row;
603
604 fTable.cols.push_back(col);
605
606 fTable.bytes_per_row += size*cnt;
607
608 // Align to four bytes
609 fOutputBuffer.resize(fTable.bytes_per_row + 4-fTable.bytes_per_row%4);
610
611 return true;
612 }
613
614 bool AddColumnShort(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
615 { return AddColumn(cnt, 'I', name, unit, comment); }
616 bool AddColumnInt(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
617 { return AddColumn(cnt, 'J', name, unit, comment); }
618 bool AddColumnLong(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
619 { return AddColumn(cnt, 'K', name, unit, comment); }
620 bool AddColumnFloat(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
621 { return AddColumn(cnt, 'E', name, unit, comment); }
622 bool AddColumnDouble(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
623 { return AddColumn(cnt, 'D', name, unit, comment); }
624 bool AddColumnChar(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
625 { return AddColumn(cnt, 'A', name, unit, comment); }
626 bool AddColumnByte(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
627 { return AddColumn(cnt, 'B', name, unit, comment); }
628 bool AddColumnBool(uint32_t cnt, const string &name, const string &unit="", const string &comment="")
629 { return AddColumn(cnt, 'L', name, unit, comment); }
630
631 bool AddColumnShort(const string &name, const string &unit="", const string &comment="")
632 { return AddColumn(1, 'I', name, unit, comment); }
633 bool AddColumnInt(const string &name, const string &unit="", const string &comment="")
634 { return AddColumn(1, 'J', name, unit, comment); }
635 bool AddColumnLong(const string &name, const string &unit="", const string &comment="")
636 { return AddColumn(1, 'K', name, unit, comment); }
637 bool AddColumnFloat(const string &name, const string &unit="", const string &comment="")
638 { return AddColumn(1, 'E', name, unit, comment); }
639 bool AddColumnDouble(const string &name, const string &unit="", const string &comment="")
640 { return AddColumn(1, 'D', name, unit, comment); }
641 bool AddColumnChar(const string &name, const string &unit="", const string &comment="")
642 { return AddColumn(1, 'A', name, unit, comment); }
643 bool AddColumnByte(const string &name, const string &unit="", const string &comment="")
644 { return AddColumn(1, 'B', name, unit, comment); }
645 bool AddColumnBool(const string &name, const string &unit="", const string &comment="")
646 { return AddColumn(1, 'L', name, unit, comment); }
647
648 /*
649 bool AddKey(string key, double d, const string &comment)
650 {
651 ostringstream out;
652 out << d;
653
654 string s = out.str();
655
656 replace(s.begin(), s.end(), "e", "E");
657
658 return AddKey(key, s, comment);
659 }*/
660
661
662 Checksum WriteHeader(ofstream &fout)
663 {
664 Checksum sum;
665 for (auto it=fKeys.begin(); it!=fKeys.end(); it++)
666 {
667 it->Out(fout);
668 sum += it->checksum;
669 }
670 fout.flush();
671
672 return sum;
673 }
674
675 Checksum WriteHeader()
676 {
677 return WriteHeader(*this);
678 }
679
680 void FlushHeader()
681 {
682 const off_t pos = tellp();
683 WriteHeader();
684 seekp(pos);
685 }
686
687 Checksum WriteFitsHeader()
688 {
689 ofits h;
690
691 h.SetBool("SIMPLE", true, "file does conform to FITS standard");
692 h.SetInt ("BITPIX", 8, "number of bits per data pixel");
693 h.SetInt ("NAXIS", 0, "number of data axes");
694 h.SetBool("EXTEND", true, "FITS dataset may contain extensions");
695 h.SetStr ("CHECKSUM","0000000000000000", "Checksum for the whole HDU");
696 h.SetStr ("DATASUM", " 0", "Checksum for the data block");
697 h.AddComment("FITS (Flexible Image Transport System) format is defined in 'Astronomy");
698 h.AddComment("and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H");
699 h.End();
700
701 const Checksum sum = h.WriteHeader(*this);
702
703 h.SetStr("CHECKSUM", sum.str());
704
705 const size_t offset = tellp();
706 h.WriteHeader(*this);
707 seekp(offset);
708
709 return sum;
710 }
711
712 bool WriteTableHeader(const char *name="DATA")
713 {
714 if (tellp()>0)
715 {
716#ifdef __EXCEPTIONS
717 throw runtime_error("File not empty anymore.");
718#else
719 gLog << ___err___ << "ERROR - File not empty anymore." << endl;
720 return false;
721#endif
722 }
723
724 fHeaderSum = WriteFitsHeader();
725
726 if (!fManualExtName)
727 SetStr("EXTNAME", name);
728 SetInt("NAXIS1", fTable.bytes_per_row);
729 SetInt("TFIELDS", fTable.cols.size());
730
731 End();
732
733 WriteHeader();
734
735 return good();
736 }
737
738 template<size_t N>
739 void revcpy(char *dest, const char *src, int num)
740 {
741 const char *pend = src + num*N;
742 for (const char *ptr = src; ptr<pend; ptr+=N, dest+=N)
743 reverse_copy(ptr, ptr+N, dest);
744 }
745
746 uint32_t GetBytesPerRow() const { return fTable.bytes_per_row; }
747
748 bool WriteRow(const void *ptr, size_t cnt, bool byte_swap=true)
749 {
750 // FIXME: Make sure that header was already written
751 // or write header now!
752 if (cnt!=fTable.bytes_per_row)
753 {
754 ostringstream sout;
755 sout << "WriteRow - Size " << cnt << " does not match expected size " << fTable.bytes_per_row;
756#ifdef __EXCEPTIONS
757 throw runtime_error(sout.str());
758#else
759 gLog << ___err___ << "ERROR - " << sout.str() << endl;
760 return false;
761#endif
762 }
763
764 // For the checksum we need everything to be correctly aligned
765 const uint8_t offset = fTable.offset%4;
766
767 char *buffer = fOutputBuffer.data() + offset;
768
769 auto ib = fOutputBuffer.begin();
770 auto ie = fOutputBuffer.end();
771 *ib++ = 0;
772 *ib++ = 0;
773 *ib++ = 0;
774 *ib = 0;
775
776 *--ie = 0;
777 *--ie = 0;
778 *--ie = 0;
779 *--ie = 0;
780
781 if (!byte_swap)
782 memcpy(buffer, ptr, cnt);
783 else
784 {
785 for (auto it=fTable.cols.begin(); it!=fTable.cols.end(); it++)
786 {
787 const char *src = reinterpret_cast<const char*>(ptr) + it->offset;
788 char *dest = buffer + it->offset;
789
790 // Let the compiler do some optimization by
791 // knowing the we only have 1, 2, 4 and 8
792 switch (it->size)
793 {
794 case 1: memcpy (dest, src, it->num*it->size); break;
795 case 2: revcpy<2>(dest, src, it->num); break;
796 case 4: revcpy<4>(dest, src, it->num); break;
797 case 8: revcpy<8>(dest, src, it->num); break;
798 }
799 }
800 }
801
802 write(buffer, cnt);
803 fDataSum.add(fOutputBuffer);
804
805 fTable.num_rows++;
806 fTable.offset += cnt;
807 return good();
808 }
809
810 template<typename N>
811 bool WriteRow(const vector<N> &vec)
812 {
813 return WriteRow(vec.data(), vec.size()*sizeof(N));
814 }
815
816 // Flushes the number of rows to the header on disk
817 void FlushNumRows()
818 {
819 SetInt("NAXIS2", fTable.num_rows);
820 FlushHeader();
821 }
822
823 size_t GetNumRows() const { return fTable.num_rows; }
824
825 bool close()
826 {
827 if (tellp()<0)
828 return false;
829
830 if (tellp()%(80*36)>0)
831 {
832 const vector<char> filler(80*36-tellp()%(80*36));
833 write(filler.data(), filler.size());
834 }
835
836 // We don't have to jump back to the end of the file
837 SetInt("NAXIS2", fTable.num_rows);
838
839 ostringstream dataSumStr;
840 dataSumStr << fDataSum.val();
841 SetStr("DATASUM", dataSumStr.str());
842
843 const Checksum sum = WriteHeader();
844
845 //sum += headersum;
846
847 SetStr("CHECKSUM", (sum+fDataSum).str());
848
849 const Checksum chk = WriteHeader();
850
851 ofstream::close();
852
853 if ((chk+fDataSum).valid())
854 return true;
855
856 ostringstream sout;
857 sout << "Checksum (" << std::hex << chk.val() << ") invalid.";
858#ifdef __EXCEPTIONS
859 throw runtime_error(sout.str());
860#else
861 gLog << ___err___ << "ERROR - " << sout.str() << endl;
862 return false;
863#endif
864 }
865
866 pair<string, int> GetChecksumData()
867 {
868 string datasum;
869 string checksum;
870 //cannot directly use the Get methods, because they are only in fits.h
871 for (vector<Key>::const_iterator it=fKeys.begin(); it!= fKeys.end(); it++)
872 {
873 if (it->key == "CHECKSUM") checksum = it->value;
874 if (it->key == "DATASUM") datasum = it->value;
875 }
876 if (checksum[0] == '\'')
877 checksum = checksum.substr(1,checksum.size()-2);
878 if (datasum[0] == '\'')
879 datasum = datasum.substr(1, datasum.size()-2);
880 return make_pair(checksum, atoi(datasum.c_str()));
881 }
882};
883
884#ifndef __MARS__
885};
886#endif
887
888#if 0
889#include "fits.h"
890
891int main()
892{
893 using namespace std;
894
895 ofits h2("delme.fits");
896
897 h2.SetInt("KEY1", 1, "comment 1");
898 h2.AddColumnInt(2, "testcol1", "counts", "My comment");
899 h2.AddColumnInt("testcol2", "counts", "My comment");
900 //h2.AddColumnInt("testcol2", "counts", "My comment");
901 h2.SetInt("KEY2", 2, "comment 2");
902
903 /*
904 AddFloat("X0", 0.000123456, "number of fields in each row");
905 AddFloat("X1", 0, "number of fields in each row");
906 AddFloat("X2", 12345, "number of fields in each row");
907 AddFloat("X3", 123456.67890, "number of fields in each row");
908 AddFloat("X4", 1234567890123456789.12345678901234567890, "number of fields in each row");
909 AddFloat("X5", 1234567890.1234567890e20, "number of fields in each row");
910 AddFloat("X6", 1234567890.1234567890e-20, "number of fields in each row");
911 AddFloat("XB", 1234567890.1234567890e-111, "number of fields in each row");
912 AddFloat("X7", 1e-5, "number of fields in each row");
913 AddFloat("X8", 1e-6, "number of fields in each row");
914 //AddStr("12345678", "123456789012345678", "12345678901234567890123456789012345678901234567");
915 */
916 // -
917
918 h2.WriteTableHeader("TABLE_NAME");
919
920 for (int i=0; i<10; i++)
921 {
922 int j[3] = { i+10, i*10, i*100 };
923 h2.WriteRow(j, 3*sizeof(i));
924 }
925
926 //h2.AddColumnInt("testcol2", "counts", "My comment");
927 //h2.SetInt("KEY3", 2, "comment 2");
928 h2.SetInt("KEY2", 2, "comment 2xxx");
929 h2.SetInt("KEY1", 11);
930
931 h2.close();
932
933 cout << "---" << endl;
934
935 fits f("delme.fits");
936 if (!f)
937 throw runtime_error("xxx");
938
939 cout << "Header is valid: " << f.IsHeaderOk() << endl;
940
941 while (f.GetNextRow());
942
943 cout << "File is valid: " << f.IsFileOk() << endl;
944
945 cout << "---" << endl;
946
947 return 0;
948}
949#endif
950
951#endif
Note: See TracBrowser for help on using the repository browser.