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

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