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

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