source: Sophya/trunk/SophyaExt/FitsIOServer/fitsinoutfile.cc@ 3447

Last change on this file since 3447 was 3447, checked in by ansari, 18 years ago

Ajout methodes Fits::ImageType(int_8 ) LONGLONG et FitsInOutFile::SetBScaleBZero()
Enregistrement conditionnel handlet FITS pour TArray<int_8>

Reza , 31/01/2008

  • Property svn:executable set to *
File size: 18.6 KB
Line 
1#include "sopnamsp.h"
2#include "machdefs.h"
3#include "segdatablock.h"
4#include "fitsinoutfile.h"
5#include "strutil.h"
6#include <stdio.h>
7#include <string.h>
8#include <iostream>
9
10string FitsTypes::ImageTypeToTypeString(int ityp)
11{
12 switch (ityp) {
13 case BYTE_IMG :
14 return "uint_1";
15 break;
16 case SHORT_IMG :
17 return "int_2";
18 break;
19 case LONG_IMG :
20 return "int_4";
21 break;
22 case FLOAT_IMG :
23 return "r_4";
24 break;
25 case DOUBLE_IMG :
26 return "r_8";
27 break;
28 default:
29 return "???" ;
30 break;
31 }
32 return "";
33}
34string FitsTypes::DataTypeToTypeString(int ityp)
35{
36 switch (ityp) {
37 case TBYTE :
38 return "uint_1";
39 break;
40 case TSHORT :
41 return "int_2";
42 break;
43 case TUSHORT :
44 return "uint_2";
45 break;
46 case TINT :
47 if (sizeof(int) == 4) return "int_4";
48 else if (sizeof(int) == 8) return "int_8";
49 else if (sizeof(int) == 2) return "int_2";
50 break;
51 case TUINT :
52 if (sizeof(int) == 4) return "uint_4";
53 else if (sizeof(int) == 8) return "uint_8";
54 else if (sizeof(int) == 2) return "uint_2";
55 break;
56 case TLONG :
57 if (sizeof(long) == 4) return "int_4";
58 else if (sizeof(long) == 8) return "int_8";
59 else if (sizeof(long) == 2) return "int_2";
60 break;
61 case TULONG :
62 if (sizeof(long) == 4) return "uint_4";
63 else if (sizeof(long) == 8) return "uint_8";
64 else if (sizeof(long) == 2) return "uint_2";
65 break;
66#ifdef TLONGLONG
67 case TLONGLONG :
68 return "int_8";
69 break;
70#endif
71 case TFLOAT :
72 return "r_4";
73 break;
74 case TDOUBLE :
75 return "r_8";
76 break;
77 case TCOMPLEX :
78 return "complex< r_4 >";
79 break;
80 case TDBLCOMPLEX :
81 return "complex< r_8 >";
82 break;
83 case TSTRING :
84 return "string";
85 break;
86 default:
87 return "???" ;
88 break;
89 }
90 return "";
91}
92
93/*!
94 \class SOPHYA::FitsInOutFile
95 \ingroup FitsIOServer
96 \brief Wrapper class for cfitsio library functions
97*/
98
99/*-- Methode --*/
100//! Default constructor - The file should be opened subsequently using Open
101FitsInOutFile::FitsInOutFile()
102{
103 fptr_ = NULL;
104 mode_ = Fits_RO;
105 SetDef_BinTable();
106 SetDef_StrColWidth();
107}
108
109/*-- Methode --*/
110//! Constructor with specification of file name and access mode
111FitsInOutFile::FitsInOutFile(string const & name, FitsIOMode mode)
112{
113 // cout << " DBG - FitsInOutFile(string name= " << name << ")" << endl;
114 fptr_ = NULL;
115 ownfptr = true;
116 SetDef_BinTable();
117 SetDef_StrColWidth();
118 Open(name.c_str(), mode);
119}
120
121/*-- Methode --*/
122//! Constructor with specification of file name and access mode
123FitsInOutFile::FitsInOutFile(const char * name, FitsIOMode mode)
124{
125 // cout << " DBG - FitsInOutFile(char* name= " << name << ")" << endl;
126 fptr_ = NULL;
127 ownfptr = true;
128 SetDef_BinTable();
129 SetDef_StrColWidth();
130 Open(name, mode);
131}
132
133/*! \brief Copy constructor
134 \warning The fits file pointer is owned by the original FitsInOutFile object and
135 should not be closed as long as the new object is being used.
136*/
137FitsInOutFile::FitsInOutFile(FitsInOutFile const& fios)
138{
139 fptr_ = fios.fptr_;
140 fname_ = fios.fname_;
141 mode_ = fios.mode_;
142 ownfptr = false;
143 SetDef_BinTable();
144 SetDef_StrColWidth();
145}
146
147/* -- Fonction utilitaire pour verifier fichier ouvert (pointeur non null) -- */
148static inline void CheckFitsPtr(fitsfile* fptr) {
149 if (fptr == NULL) throw FitsIOException("FitsInOutFile/Error - NULL fitsfile pointer ");
150 return;
151}
152/* -- Fonction utilitaire pour verifier le code d'erreur fitsio -- */
153static inline bool FitsCheckStatus(int st, char * emsg = NULL) {
154 if (st) {
155 fits_report_error(stderr, st);
156 if (emsg) {
157 char buff[FLEN_ERRMSG];
158 fits_get_errstatus(st, buff);
159 string msg = emsg;
160 msg += buff;
161 throw FitsIOException(msg);
162 }
163 else return true;
164 }
165 else return false;
166}
167
168/*-- Methode --*/
169//! Destructor - Closes the fits file (if opened)
170FitsInOutFile::~FitsInOutFile()
171{
172 Close();
173}
174
175/*-- Methode --*/
176//! Opens the named fits file (see cfitsio routines fits_open_file and fits_create_file)
177void FitsInOutFile::Open(const char* name, FitsIOMode mode)
178{
179 if (fptr_ != NULL)
180 throw FitsIOException("FitsInOutFile::Open() /Error - file already opened ");
181 int status = 0;
182 fptr_ = NULL;
183 switch ( mode ) {
184 case Fits_RO :
185 fits_open_file(&fptr_, name, READONLY, &status);
186 break;
187 case Fits_RW :
188 fits_open_file(&fptr_, name, READWRITE, &status);
189 break;
190 case Fits_Create :
191 fits_create_file(&fptr_, name, &status);
192 break;
193 }
194 FitsCheckStatus(status, "FitsInOutFile::Open() Error: ");
195 fname_ = name;
196 mode_ = mode;
197 ownfptr = true;
198 return;
199}
200
201/*-- Methode --*/
202//! Opens the named fits file (see cfitsio routines fits_open_file and fits_create_file)
203void FitsInOutFile::Close()
204{
205 if (fptr_ == NULL) return;
206 if (ownfptr == false) {
207 fptr_ = NULL; return;
208 }
209 int status = 0;
210 if (mode_ == Fits_Create) {
211 status = 0;
212 int hdutyp;
213 fits_movabs_hdu(FitsPtr() , 1, &hdutyp, &status);
214 status = 0;
215 float sfv = Version();
216 fits_write_key(FitsPtr(), TFLOAT, "SOPHYAFV", &sfv,
217 "SOPHYA FitsIOServer module version", &status);
218 fits_write_date(FitsPtr(), &status);
219 status = 0;
220 fits_write_comment(FitsPtr(), "------------- SOPHYA (http://www.sophya.org) -------------", &status);
221 fits_write_comment(FitsPtr(), " (C) LAL/IN2P3-CNRS Orsay , (C) DAPNIA/CEA Saclay (FRANCE)", &status);
222 fits_write_comment(FitsPtr(), "-----------------------------------------------------------", &status);
223 }
224 MoveAbsToHDU(1);
225 status = 0;
226 if (fptr_) fits_close_file(fptr_, &status);
227 if (status) {
228 cerr << " FitsInOutFile::Close - Error closing fits file !" << endl;
229 fits_report_error(stderr, status);
230 }
231}
232
233/*! \brief Closes the current fits file and uses \b fios file for subsequent operations.
234 \warning The fits file pointer is owned by the original FitsInOutFile object and
235 should not be closed as long as the current object (this) is being used.
236*/
237
238void FitsInOutFile::ShareFitsPtr(FitsInOutFile const& fios)
239{
240 Close();
241 fptr_ = fios.fptr_;
242 fname_ = fios.fname_;
243 mode_ = fios.mode_;
244 ownfptr = false;
245}
246
247/*-- Methode --*/
248float FitsInOutFile::cfitsioVersion()
249{
250 float ver;
251 fits_get_version(&ver);
252 return ver;
253}
254
255/*-- Methode --*/
256int FitsInOutFile::NbHDUs() const
257{
258 int status = 0;
259 int nbhdu = 0;
260 fits_get_num_hdus(FitsPtr() , &nbhdu, &status);
261 FitsCheckStatus(status, "FitsInOutFile::NbHDUs() Error: ");
262 return nbhdu;
263}
264
265/*-- Methode --*/
266int FitsInOutFile::CurrentHDU() const
267{
268 int status = 0;
269 int curhdu = 0;
270 fits_get_hdu_num(FitsPtr() , &curhdu);
271 return curhdu;
272}
273
274/*-- Methode --*/
275int FitsInOutFile::CurrentHDUType() const
276{
277 int status = 0;
278 int hdutyp = 0;
279 fits_get_hdu_type(FitsPtr() , &hdutyp, &status);
280 FitsCheckStatus(status, "FitsInOutFile::CurrentHDUType() Error: ");
281 return hdutyp;
282}
283
284/*-- Methode --*/
285string FitsInOutFile::CurrentHDUTypeStr() const
286{
287 int status = 0;
288 int hdutyp = 0;
289 fits_get_hdu_type(FitsPtr() , &hdutyp, &status);
290 if ( FitsCheckStatus(status, "FitsInOutFile::CurrentHDUTypeStr() Error: ") )
291 return "Unknown";
292 else {
293 if (hdutyp == IMAGE_HDU) return "IMAGE_HDU";
294 else if (hdutyp == BINARY_TBL) return "BINARY_TBL";
295 else if (hdutyp == ASCII_TBL) return "ASCII_TBL";
296 else return "Unknown";
297 }
298}
299
300/*-- Methode --*/
301int FitsInOutFile::MoveAbsToHDU(int hdunum)
302{
303 int status = 0;
304 int hdutyp = 0;
305 fits_movabs_hdu(FitsPtr() , hdunum, &hdutyp, &status);
306 FitsCheckStatus(status, "FitsInOutFile::MoveAbsToHDU Error: ");
307 return hdutyp;
308}
309
310/*-- Methode --*/
311int FitsInOutFile::MoveRelToHDU(int hdunum)
312{
313 int status = 0;
314 int hdutyp = 0;
315 fits_movrel_hdu(FitsPtr() , hdunum, &hdutyp, &status);
316 FitsCheckStatus(status, "FitsInOutFile::MoveRelToHDU Error: ");
317 return hdutyp;
318}
319
320/*-- Methode --*/
321int FitsInOutFile::MoveToNextHDU()
322{
323 if (CurrentHDU() < NbHDUs())
324 return MoveRelToHDU(1);
325 else return -1;
326}
327
328/*-- Methode --*/
329/*!
330 Skip HDU 1 if NAXIS=0 (no data), on a file opened for reading.
331 return true if moved to HDU No 2
332*/
333bool FitsInOutFile::SkipEmptyFirstHDU()
334{
335 if (fptr_ == NULL) return false;
336 if (mode_ == Fits_Create) return false;
337 if (CurrentHDU() != 1) return false;
338 int naxis = 2;
339 LONGLONG naxes[2];
340 GetImageHDUInfo(naxis, naxes);
341 if ((naxis == 0) && (NbHDUs() > 1)) {
342 MoveRelToHDU(1);
343 return true;
344 }
345 return false;
346}
347
348/*-- Methode --*/
349void FitsInOutFile::CreateImageHDU(int bitpix, int naxis, LONGLONG* naxes)
350{
351 int status = 0;
352 fits_create_imgll(fptr_, bitpix, naxis, naxes, &status);
353 FitsCheckStatus(status,"FitsInOutFile::CreateImageHDU() Error: ");
354 return;
355}
356
357/*-- Methode --*/
358 /*!
359 See cfitsio function fits_get_img_param() for more information
360 naxis : input=max naxes dimension / out=image dimension
361 Rc : return the image type (bitpix)
362 */
363int FitsInOutFile::GetImageHDUInfo(int& naxis, LONGLONG* naxes) const
364{
365 int status = 0;
366 int maxdim = naxis;
367 int bitpix = 0;
368 fits_get_img_paramll(fptr_, maxdim, &bitpix, &naxis, naxes, &status);
369 FitsCheckStatus(status, "FitsInOutFile::GetImageHDUInfo() Error: ");
370 return bitpix;
371}
372/*-- Methode --*/
373 /*!
374 See cfitsio function fits_set_bscale() for more information
375 Changes the BSCALE/BZERO values for read/write operations on the
376 primary HDU, without changing the keyword values in the fits header
377 */
378void FitsInOutFile::SetBScaleBZero(double bscale, double bzero)
379{
380 int status = 0;
381 fits_set_bscale(fptr_, bscale, bzero, &status);
382 FitsCheckStatus(status, "FitsInOutFile::SetBScaleBZero() Error: ");
383}
384/*-- Methode --*/
385LONGLONG FitsInOutFile::GetNbRows() const
386{
387 int status = 0;
388 LONGLONG nbrow = 0;
389 fits_get_num_rowsll(FitsPtr() , &nbrow, &status);
390 FitsCheckStatus(status, "FitsInOutFile::GetNbRows() Error: " );
391 return nbrow;
392}
393
394/*-- Methode --*/
395int FitsInOutFile::GetNbCols() const
396{
397 int status = 0;
398 int nbcol = 0;
399 fits_get_num_cols(FitsPtr() , &nbcol, &status);
400 FitsCheckStatus(status, "FitsInOutFile::GetNbCols() Error: ");
401 return nbcol;
402}
403
404/*-- Methode --*/
405/*!
406 Create a binary or ascii table - See cfitsio routine fits_create_tbl for more information.
407 \param extname : extension name. NextExtensionName() will be used if extname == NULL or extname == "".
408 \param ncols : Number of columns
409 \param ttype : Column names
410 \param tform : Column data types J / V / K / E / D ...
411 \param tunit : Column units
412*/
413void FitsInOutFile::CreateTable(int tbltyp, const char * extname, int ncols,
414 char * ttype[], char * tform[],
415 char * tunit[], long ininr)
416{
417 int status = 0;
418
419 char * extn;
420 if ( (extname != NULL) && (extname[0] != '\0') ) extn = const_cast<char *>(extname);
421 else extn = const_cast<char *>(next_extname_.c_str());
422
423 fits_create_tbl(FitsPtr(), tbltyp, ininr, ncols, ttype,
424 tform, tunit, extn, &status);
425 next_extname_ = "";
426 FitsCheckStatus(status, "FitsInOutFile::CreateTable() Error: ");
427 return;
428}
429
430/*-- Methode --*/
431/*!
432 Create a binary or ascii table - See cfitsio routine fits_create_tbl for more information.
433 number of columns specified by colnames.size()
434 \param extname : extension name
435 \param colnames : Column names
436 \param tform : Column data types J / V / K / E / D ...
437 \param tunit : Column units
438*/
439void FitsInOutFile::CreateTable(int tbltyp, const string & extname,
440 const vector<string> & colnames,
441 const vector<string> & tform,
442 const vector<string> & tunit,
443 long ininr)
444{
445 if ( (colnames.size() != tform.size() ) ||
446 (colnames.size() != tunit.size() ) )
447 throw SzMismatchError("FitsInOutFile::CreateTable(): different sizes for colnames,tform,tunit");
448
449 // On utilise les SegDataBlock<T> pour eviter d'avoir a gerer les new/delete
450 // en plus avec les exceptions ...
451 size_t kk;
452 int ncols = colnames.size();
453
454 SegDataBlock<const char *> colnm(colnames.size(), 1);
455 for(kk=0; kk<colnames.size(); kk++) colnm[kk] = colnames[kk].c_str();
456 SegDataBlock<const char *> tfm(tform.size(), 1);
457 for(kk=0; kk<tform.size(); kk++) tfm[kk] = tform[kk].c_str();
458 SegDataBlock<const char *> tun(tunit.size(), 1);
459 for(kk=0; kk<tunit.size(); kk++) tun[kk] = tunit[kk].c_str();
460
461 CreateTable(tbltyp, const_cast<char *>(extname.c_str()), ncols,
462 const_cast<char **>(colnm.GetSegment(0)),
463 const_cast<char **>(tfm.GetSegment(0)),
464 const_cast<char **>(tun.GetSegment(0)),
465 ininr);
466}
467
468/*-- Methode --*/
469/*!
470 Return number of columns in table (See fits_get_colname and fits_get_coltype for more information)
471 \param colnames : Column names
472 \param coltypes : Column data types ( TSTRING / TSHORT / TFLOAT / ... )
473 \param repcnt : Repeat count (for columns with vector data)
474 \param width : The width (in bytes) of a single element in a column
475
476*/
477long FitsInOutFile::GetColInfo(vector<string> & colnames,
478 vector<int> & coltypes,
479 vector<LONGLONG> & repcnt,
480 vector<LONGLONG> & width)
481{
482
483 int status = 0;
484
485 colnames.clear();
486 coltypes.clear();
487 width.clear();
488 repcnt.clear();
489
490 int colnum, typecode;
491 LONGLONG repeat, colw; // $CHECK$ LONGLONG ???
492 int ncols = 0;
493 char colname[128]; // longueur max d'un nom de colonne
494
495 while (status != COL_NOT_FOUND) {
496 fits_get_colname(FitsPtr(), CASEINSEN, "*", colname, &colnum, &status);
497 if (status == COL_NOT_FOUND) break;
498 if ( (status != COL_NOT_UNIQUE) && (status != 0) ) {
499 char buff[32];
500 fits_get_errstatus(status, buff);
501 string msg = "FitsInOutFile::GetColInfo() Error(1): " ;
502 msg += buff;
503 throw FitsIOException(msg);
504 }
505 int sta2 = 0;
506 fits_get_coltypell(FitsPtr(), colnum, &typecode, &repeat, &colw, &sta2); // $CHECK$ LONGLONG ???fits_get_coltypell
507 FitsCheckStatus(sta2, "FitsInOutFile::GetColInfo() Error(2): ");
508
509 colnames.push_back(colname);
510 coltypes.push_back(typecode);
511 repcnt.push_back(repeat);
512 width.push_back(colw);
513 if (status == 0) break;
514 }
515 return colnames.size();
516}
517
518/*-- Methode --*/
519void FitsInOutFile::InsertColumn(int numcol, const char* colname, const char* fmt)
520{
521 int status = 0;
522 fits_insert_col(FitsPtr(), numcol, const_cast<char *>(colname),
523 const_cast<char *>(fmt), &status);
524 FitsCheckStatus(status, "FitsInOutFile::AddColumn() Error: ");
525
526 return;
527}
528
529/*-- Methode --*/
530/*!
531 Return the value associated to the keyword \b key in the header as a string.
532 If the keyword is not found in the fits header, an empty string is returned
533 and the \b nosk flag is set to true.
534*/
535string FitsInOutFile::KeyValue(string const & key, bool& nosk)
536{
537 nosk = false;
538 int status = 0;
539 char value[FLEN_VALUE], comm[FLEN_COMMENT];
540 fits_read_key(FitsPtr(), TSTRING, const_cast<char *>(key.c_str()), value, comm, &status);
541 if (status == KEY_NO_EXIST) {
542 nosk = true;
543 return "";
544 }
545 FitsCheckStatus(status, "FitsInOutFile::KeyValue() Error: ");
546 return value;
547}
548
549/*-- Methode --*/
550/*!
551 Read the current fits header information as pairs of '(keyword,value)' appended
552 to the DVList object \b dvl.
553 \param dvl : DVList object containing filled with (keyword,value) pairs.
554 \param stripkw : if true (default), remove leading and trailing spaces from keyword
555 \param keepstkey : if true , keep keys of type TYP_STRUC_KEY
556*/
557int FitsInOutFile::GetHeaderRecords(DVList& dvl, bool stripkw, bool keepstkey)
558{
559 int status = 0;
560 int nkeys = 0;
561 fits_get_hdrspace(FitsPtr(), &nkeys, NULL, &status);
562 FitsCheckStatus(status, "FitsInOutFile::GetHeaderRecords() Error(1): ");
563
564 char record[FLEN_CARD], value[FLEN_VALUE], comm[FLEN_COMMENT];
565 string comment;
566 int nok = 0;
567 for(int kk=1; kk<=nkeys; kk++) {
568 status = 0;
569 fits_read_record(FitsPtr(), kk, record, &status);
570 FitsCheckStatus(status, "FitsInOutFile::GetHeaderRecords() Error(2): ");
571 int kclas = fits_get_keyclass(record);
572 if ( (!keepstkey && (kclas == TYP_STRUC_KEY))
573 || (kclas == TYP_NULL_KEY) ) continue;
574 int len = 0;
575 status = 0;
576 fits_get_keyname(record, value, &len, &status);
577 if (status) continue;
578 if (stripkw) strip(value, 'B', ' ');
579 string keyname = value;
580 status = 0;
581 fits_parse_value(record, value, comm, &status);
582 if (status) continue;
583 if (kclas == TYP_COMM_KEY) {
584 if (comment.length() > 0) comment += '\n';
585 comment += value;
586 continue;
587 }
588 char ktyp;
589 status = 0;
590 fits_get_keytype(value, &ktyp, &status);
591 if (status) continue;
592 switch (ktyp) {
593 case 'C' :
594 case 'L' : // Il faudra traiter le cas des nb complexes
595 case 'X' : // idem pour les valeurs logiques
596 dvl.SetS(keyname, value);
597 break;
598 case 'I' :
599 dvl.SetI(keyname, atoi(value));
600 break;
601 case 'F' :
602 dvl.SetD(keyname, atof(value));
603 break;
604 }
605 if (strlen(comm) > 0) {
606 string scom = comm;
607 dvl.SetComment(keyname, scom);
608 }
609 nok++;
610 }
611 if (comment.length() > 0) dvl.Comment() = comment;
612 return nok;
613}
614
615/*-- Methode --*/
616void FitsInOutFile::WriteKey(const char * kname, MuTyV const & mtv,
617 const char *comment)
618{
619 CheckFitsPtr(FitsPtr());
620 char keyname[FLEN_KEYWORD], comm[FLEN_COMMENT], sval[FLEN_VALUE];
621 LONGLONG lval;
622 double dval;
623 string s;
624
625 keyname[0] = '\0';
626 strncpy(keyname, kname, FLEN_KEYWORD); keyname[FLEN_KEYWORD-1] = '\0';
627 comm[0] = '\0';
628 if (comm != NULL)
629 strncpy(comm, comment, FLEN_COMMENT); comm[FLEN_COMMENT-1] = '\0';
630 int status = 0;
631 switch (mtv.Type()) {
632 case MuTyV::MTVInteger :
633 lval = mtv.GetIntPart();
634 fits_write_key(FitsPtr(), TLONGLONG, keyname, &lval, comm, &status);
635 break;
636 case MuTyV::MTVFloat :
637 dval = mtv.GetRealPart();
638 fits_write_key(FitsPtr(), TDOUBLE, keyname, &dval, comm, &status);
639 break;
640 case MuTyV::MTVString :
641 strncpy(sval, mtv.GetStringPointer()->c_str(), FLEN_VALUE);
642 keyname[FLEN_VALUE-1] = '\0';
643 fits_write_key(FitsPtr(), TSTRING, keyname, sval, comm, &status);
644 break;
645 default :
646 s = (string)mtv;
647 strncpy(sval, s.c_str(), FLEN_VALUE);
648 keyname[FLEN_VALUE-1] = '\0';
649 fits_write_key(FitsPtr(), TSTRING, keyname, sval, comm, &status);
650 break;
651 }
652 FitsCheckStatus(status, "FitsInOutFile::WriteKey() Error: ");
653 return;
654}
655
656/*-- Methode --*/
657int FitsInOutFile::WriteHeaderRecords(DVList & dvl)
658{
659
660 CheckFitsPtr(FitsPtr());
661 int status = 0;
662 DVList::ValList::const_iterator it;
663 for(it = dvl.Begin(); it != dvl.End(); it++)
664 WriteKey( (*it).first, (*it).second.elval, (*it).second.elcomm);
665 // Ecriture commentaires
666 return 0;
667
668}
669
670/*-- Methode --*/
671void FitsInOutFile::Print(ostream& os, int lev) const
672{
673 string mode;
674 if (mode_ == Fits_Create) mode = "Create";
675 else if (mode_ == Fits_RO) mode = "ReadOnly";
676 else mode = "ReadWrite";
677 os << " FitsInOutFile(FileName= " << fname_ << " Mode="
678 << mode << ") fitsioVers= " << cfitsioVersion() << endl;
679 os << " TotalNumberHDU= " << NbHDUs() << " CurrentHDU: Num= "
680 << CurrentHDU() << " Type= " << CurrentHDUTypeStr() << endl;
681
682 return;
683}
684
685
Note: See TracBrowser for help on using the repository browser.