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

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