13 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 16 #include <unordered_map> 21 template<
class T,
class S>
class unordered_map<T, S>;
25 #if defined(__MARS__) || defined(__CINT__) 27 #include "MLogManip.h" 29 #define ___warn___ warn 36 #define gLog std::cerr 43 #if defined(HAVE_ZLIB) || defined(__CINT__) 47 #define izstream ifstream 48 #warning Support for zipped FITS files disabled. 82 std::istringstream
str(value);
112 typedef std::map<std::string, Entry>
Keys;
113 typedef std::map<std::string, Column>
Columns;
122 std::string
Trim(
const std::string &
str,
char c=
' ')
const 125 const size_t pstart = str.find_first_not_of(c);
126 const size_t pend = str.find_last_not_of(c);
129 if (std::string::npos==pstart || std::string::npos==pend)
130 return std::string();
132 return str.substr(pstart, pend-pstart+1);
135 bool Check(
const std::string &key,
char type,
const std::string &value=
"")
const 137 const Keys::const_iterator it = keys.find(key);
140 std::ostringstream
str;
141 str <<
"Key '" << key <<
"' not found.";
143 throw std::runtime_error(str.str());
150 if (it->second.type!=type)
152 std::ostringstream
str;
153 str <<
"Wrong type for key '" << key <<
"': expected " << type <<
", found " << it->second.type <<
".";
155 throw std::runtime_error(str.str());
162 if (!value.empty() && it->second.value!=value)
164 std::ostringstream
str;
165 str <<
"Wrong value for key '" << key <<
"': expected " << value <<
", found " << it->second.value <<
".";
167 throw std::runtime_error(str.str());
181 for (
unsigned int i=0;
i<vec.size();
i++)
183 const std::string key =
Trim(vec[
i].substr(0,8));
185 if (vec[
i].substr(8,2)!=
"= ")
191 std::string val =
Trim(vec[
i].substr(10));
199 const size_t pp = val.find_first_of(
'\'', p);
200 if (pp==std::string::npos)
203 p = val[pp+1]==
'\'' ? pp+2 : pp+1;
207 const size_t ppp = val.find_first_of(
'/', p);
211 if (ppp!=std::string::npos && val.size()!=ppp+1)
212 com =
Trim(val.substr(ppp+1));
214 val =
Trim(val.substr(1, p-2));
219 const size_t p = val.find_first_of(
'/');
221 if (p!=std::string::npos && val.size()!=p+1)
222 com =
Trim(val.substr(p+2));
224 val =
Trim(val.substr(0, p));
226 if (val.empty() || val.find_first_of(
'T')!=std::string::npos || val.find_first_of(
'F')!=std::string::npos)
229 type = val.find_last_of(
'.')==std::string::npos ?
'I' :
'F';
240 Table() : offset(0), is_compressed(false) { }
241 Table(
const std::vector<std::string> &vec, off_t off) : offset(off),
242 keys(ParseBlock(vec))
244 is_compressed = HasKey(
"ZTABLE") && Check(
"ZTABLE",
'B',
"T");
246 if (!Check(
"XTENSION",
'T',
"BINTABLE") ||
247 !Check(
"NAXIS",
'I',
"2") ||
248 !Check(
"BITPIX",
'I',
"8") ||
249 !Check(
"GCOUNT",
'I',
"1") ||
250 !Check(
"EXTNAME",
'T') ||
251 !Check(
"NAXIS1",
'I') ||
252 !Check(
"NAXIS2",
'I') ||
253 !Check(
"TFIELDS",
'I'))
258 if (!Check(
"ZNAXIS1",
'I') ||
259 !Check(
"ZNAXIS2",
'I') ||
260 !Check(
"ZPCOUNT",
'I',
"0"))
265 if (!Check(
"PCOUNT",
'I',
"0"))
269 total_bytes = Get<size_t>(
"NAXIS1")*Get<size_t>(
"NAXIS2");
270 bytes_per_row = is_compressed ? Get<size_t>(
"ZNAXIS1") : Get<size_t>(
"NAXIS1");
271 num_rows = is_compressed ? Get<size_t>(
"ZNAXIS2") : Get<size_t>(
"NAXIS2");
272 num_cols = Get<size_t>(
"TFIELDS");
273 datasum = Get<int64_t>(
"DATASUM", -1);
276 const std::string tFormName = is_compressed ?
"ZFORM" :
"TFORM";
277 for (
long long unsigned int i=1;
i<=num_cols;
i++)
279 const std::string num(std::to_string(
i));
281 if (!Check(
"TTYPE"+num,
'T') ||
282 !Check(tFormName+num,
'T'))
285 const std::string
id = Get<std::string>(
"TTYPE"+num);
286 const std::string fmt = Get<std::string>(tFormName+num);
287 const std::string unit = Get<std::string>(
"TUNIT"+num,
"");
288 const std::string comp = Get<std::string>(
"ZCTYP"+num,
"");
292 compress = kCompFACT;
294 std::istringstream sin(fmt);
300 const char type = fmt[fmt.length()-1];
309 case 'B': size = 1;
break;
310 case 'I': size = 2;
break;
311 case 'J': size = 4;
break;
312 case 'K': size = 8;
break;
313 case 'E': size = 4;
break;
314 case 'D': size = 8;
break;
322 std::ostringstream
str;
323 str <<
"FITS format TFORM='" << fmt <<
"' not yet supported.";
325 throw std::runtime_error(str.str());
336 sorted_cols.emplace_back(col);
340 if (bytes!=bytes_per_row)
342 std::ostringstream
str;
343 str <<
"Sum of bytes in columns [" << bytes <<
"] does not match (Z)NAXIS2 [" << bytes_per_row <<
"].";
346 throw std::runtime_error(str.str());
353 name = Get<std::string>(
"EXTNAME");
358 for (Keys::const_iterator it=keys.cbegin(); it!=keys.cend(); it++)
363 gLog <<
___all___ << std::setw(2) << it->second.type <<
'|' << it->first <<
'=' << it->second.value <<
'/' << it->second.comment <<
'|' << std::endl;
369 typedef std::map<std::pair<size_t, std::string>,
Column> Sorted;
373 for (Columns::const_iterator it=cols.cbegin(); it!=cols.cend(); it++)
374 sorted[std::make_pair(it->second.offset, it->first)] = it->second;
376 for (Sorted::const_iterator it=sorted.cbegin(); it!=sorted.cend(); it++)
378 gLog <<
___all___ << std::setw(6) << it->second.offset <<
"| ";
379 gLog << it->second.num <<
'x';
380 switch (it->second.type)
382 case 'A':
gLog <<
"char(8)";
break;
383 case 'L':
gLog <<
"bool(8)";
break;
384 case 'B':
gLog <<
"byte(8)";
break;
385 case 'I':
gLog <<
"short(16)";
break;
386 case 'J':
gLog <<
"int(32)";
break;
387 case 'K':
gLog <<
"int(64)";
break;
388 case 'E':
gLog <<
"float(32)";
break;
389 case 'D':
gLog <<
"double(64)";
break;
391 gLog <<
": " << it->first.second <<
" [" << it->second.unit <<
"]" << std::endl;
395 operator bool()
const {
return !name.empty(); }
397 bool HasKey(
const std::string &key)
const 399 return keys.find(key)!=keys.end();
404 return cols.find(col)!=cols.end();
419 T
Get(
const std::string &key)
const 421 const Keys::const_iterator it = keys.find(key);
424 std::ostringstream
str;
425 str <<
"Key '" << key <<
"' not found.";
427 throw std::runtime_error(str.str());
433 return it->second.Get<T>();
438 T
Get(
const std::string &key,
const T &deflt)
const 440 const Keys::const_iterator it = keys.find(key);
441 return it==keys.end() ? deflt :it->second.Get<T>();
444 size_t GetN(
const std::string &key)
const 446 const Columns::const_iterator it = cols.find(key);
447 return it==cols.end() ? 0 : it->second.num;
456 if (!HasKey(
"ZHEAPPTR"))
459 const size_t shift = Get<size_t>(
"ZHEAPPTR");
460 return shift <= total_bytes ? 0 : shift - total_bytes;
467 const streamoff shift = GetHeapShift();
470 const streamoff
size = HasKey(
"PCOUNT") ? Get<streamoff>(
"PCOUNT") : 0;
473 const streamoff total = total_bytes + size + shift;
480 return total + (2880 - (total%2880));
487 if (exceptions()&throwbit)
488 throw std::runtime_error(txt);
494 typedef std::pair<void*, Table::Column>
Address;
496 typedef std::unordered_map<std::string, void*>
Pointers;
522 for (
int i=0;
i<36;
i++)
530 fChkHeader.
add(c, 80);
540 if (endtag==2 || str==
"END ")
546 if (endtag==1 || str==
" ")
552 vec.emplace_back(str);
556 if (endtag && vec.size()%36==0)
557 vec.emplace_back(
"END = '' / ");
562 std::string
Compile(
const std::string &key, int16_t
i=-1)
const 564 #if GCC_VERSION < 40603 565 return i<0 ? key : key+std::to_string((
long long int)(
i));
567 return i<0 ? key : key+std::to_string(
i);
571 void Constructor(
const std::string &fname, std::string fout=
"",
const std::string& tableName=
"",
bool force=
false)
578 EnableAddressExceptions();
580 if (memcmp(simple,
"SIMPLE = ", 10))
582 clear(rdstate()|std::ios::badbit);
584 throw std::runtime_error(
"File is not a FITS file.");
586 gLog <<
___err___ <<
"ERROR - File is not a FITS file." << std::endl;
595 std::vector<std::string> block;
602 if (eof() && !bad() && !tableName.empty())
607 const int rc = ReadBlock(block);
610 clear(rdstate()|std::ios::badbit);
612 throw std::runtime_error(
"FITS file corrupted.");
614 gLog <<
___err___ <<
"ERROR - FITS file corrupted." << std::endl;
623 clear(rdstate()|std::ios::badbit);
625 throw std::runtime_error(
"END keyword missing in FITS header.");
627 gLog <<
___err___ <<
"ERROR - END keyword missing in FITS file... file might be corrupted." << std::endl;
638 if (block[0].substr(0, 9)==
"SIMPLE =")
644 if (block[0].substr(0, 9)==
"XTENSION=")
646 fTable =
Table(block, tellg());
651 clear(rdstate()|std::ios::badbit);
655 const std::string &tname = fTable.
Get<std::string>(
"EXTNAME");
657 fListOfTables.emplace_back(tname);
661 if ((!tableName.empty() && tableName!=tname) || (tableName.empty() &&
"ZDrsCellOffsets"==tname))
664 seekg(skip, std::ios_base::cur);
681 if (*fout.rbegin()==
'/')
683 const size_t p = fname.find_last_of(
'/');
684 fout.append(fname.substr(p+1));
690 clear(rdstate()|std::ios::badbit);
692 throw std::runtime_error(
"Could not open output file.");
694 gLog <<
___err___ <<
"ERROR - Failed to open output file." << std::endl;
699 const streampos p = tellg();
702 std::vector<char> buf(p);
705 fCopy.write(buf.data(), p);
707 clear(rdstate()|std::ios::badbit);
711 fits(
const std::string &fname,
const std::string& tableName=
"",
bool force=
false) :
izstream(fname.c_str())
713 Constructor(fname,
"", tableName, force);
717 throw std::runtime_error(
"Trying to read a compressed fits with the base fits class. Use factfits instead.");
719 gLog <<
___err___ <<
"ERROR - Trying to read a compressed fits with the base fits class. Use factfits instead." << std::endl;
721 clear(rdstate()|std::ios::badbit);
725 fits(
const std::string &fname,
const std::string &fout,
const std::string& tableName,
bool force=
false) :
izstream(fname.c_str())
727 Constructor(fname, fout, tableName, force);
731 throw std::runtime_error(
"Trying to read a compressed fits with the base fits class. Use factfits instead.");
733 gLog <<
___err___ <<
"ERROR - Trying to read a compressed fits with the base fits class. Use factfits instead." << std::endl;
735 clear(rdstate()|std::ios::badbit);
746 std::copy(std::istreambuf_iterator<char>(*
this),
747 std::istreambuf_iterator<char>(),
748 std::ostreambuf_iterator<char>(fCopy));
765 fChkData.
add(fBufferRow);
766 if (fCopy.is_open() && fCopy.good())
769 clear(rdstate()|std::ios::badbit);
773 clear(rdstate()|std::ios::badbit);
778 auto ib = vec.begin();
786 for (uint64_t
i=0;
i<extraZeros+8;
i++)
795 ZeroBufferForChecksum(fBufferRow);
797 StageRow(row, fBufferRow.data()+offset);
799 WriteRowToCopyFile(row);
807 void revcpy(
char *dest,
const char *src,
const int &num)
809 const char *pend = src + num*N;
810 for (
const char *ptr = src; ptr<pend; ptr+=N, dest+=N)
811 std::reverse_copy(ptr, ptr+N, dest);
820 case 1: memcpy (dest, src, c.
bytes);
break;
821 case 2: revcpy<2>(dest, src, c.
num);
break;
822 case 4: revcpy<4>(dest, src, c.
num);
break;
823 case 8: revcpy<8>(dest, src, c.
num);
break;
827 virtual bool GetRow(
size_t row,
bool check=
true)
832 const uint8_t offset = ReadRow(row);
836 const char *ptr = fBufferRow.data() + offset;
838 for (Addresses::const_iterator it=fAddresses.cbegin(); it!=fAddresses.cend(); it++)
842 const char *src = ptr + c.
offset;
843 char *dest =
reinterpret_cast<char*
>(it->first);
845 MoveColumnDataToUserSpace(dest, src, c);
853 return GetRow(fRow+1, check);
862 static bool Compare(
const Address &p1,
const Address &p2)
864 return p1.first>p2.first;
867 template<
class T,
class S>
868 const T &
GetAs(
const std::string &name)
870 return *
reinterpret_cast<S*
>(fPointers[name]);
876 exceptions(iostate(throwbit));
878 exceptions(iostate(exceptions()&~throwbit));
883 EnableAddressExceptions(
false);
888 if (fTable.
cols.count(name)==0)
890 std::ostringstream
str;
891 str <<
"SetPtrAddress('" << name <<
"') - Column not found.";
892 Exception(str.str());
896 Pointers::const_iterator it = fPointers.find(name);
897 if (it!=fPointers.end())
900 fGarbage.emplace_back(fTable.
cols[name].bytes);
902 void *ptr = fGarbage.back().data();
904 fPointers[name] = ptr;
905 fAddresses.emplace_back(ptr, fTable.
cols[name]);
906 sort(fAddresses.begin(), fAddresses.end(), Compare);
913 if (fTable.
cols.count(name)==0)
915 std::ostringstream
str;
916 str <<
"SetPtrAddress('" << name <<
"') - Column not found.";
917 Exception(str.str());
921 if (
sizeof(T)!=fTable.
cols[name].size)
923 std::ostringstream
str;
924 str <<
"SetPtrAddress('" << name <<
"') - Element size mismatch: expected " 925 << fTable.
cols[name].size <<
" from header, got " <<
sizeof(T);
926 Exception(str.str());
930 if (cnt!=fTable.
cols[name].num)
932 std::ostringstream
str;
933 str <<
"SetPtrAddress('" << name <<
"') - Element count mismatch: expected " 934 << fTable.
cols[name].num <<
" from header, got " << cnt;
935 Exception(str.str());
943 fPointers[name] = ptr;
944 fAddresses.emplace_back(ptr, fTable.
cols[name]);
945 sort(fAddresses.begin(), fAddresses.end(), Compare);
952 return SetPtrAddress(name, &ptr,
sizeof(ptr)/
sizeof(T));
958 return SetPtrAddress(name, vec.data(), vec.size());
962 T
Get(
const std::string &key)
const 964 return fTable.
Get<T>(key);
968 T
Get(
const std::string &key,
const std::string &deflt)
const 970 return fTable.
Get<T>(key, deflt);
975 if (fTable.
cols.count(name)==0)
977 std::ostringstream
str;
978 str <<
"SetPtrAddress('" << name <<
"') - Column not found.";
979 Exception(str.str());
983 if (cnt && cnt!=fTable.
cols[name].num)
985 std::ostringstream
str;
986 str <<
"SetPtrAddress('" << name <<
"') - Element count mismatch: expected " 987 << fTable.
cols[name].num <<
" from header, got " << cnt;
988 Exception(str.str());
996 fPointers[name] = ptr;
997 fAddresses.emplace_back(ptr, fTable.
cols[name]);
998 sort(fAddresses.begin(), fAddresses.end(), Compare);
1008 int64_t
GetInt(
const std::string &key)
const {
return fTable.
Get<int64_t>(key); }
1009 uint64_t
GetUInt(
const std::string &key)
const {
return fTable.
Get<uint64_t>(key); }
1010 double GetFloat(
const std::string &key)
const {
return fTable.
Get<
double>(key); }
1011 std::string
GetStr(
const std::string &key)
const {
return fTable.
Get<std::string>(key); }
1013 size_t GetN(
const std::string &key)
const 1015 return fTable.
GetN(key);
1019 size_t GetRow()
const {
return fRow==(size_t)-1 ? 0 : fRow; }
1021 operator bool()
const {
return fTable && fTable.
offset!=0; }
1027 virtual bool IsFileOk()
const {
return (fChkHeader+fChkData).valid(); }
1033 return fTable.
Get<
size_t>(
"NAXIS2");
1038 return fTable.
Get<
size_t>(
"NAXIS1");
1043 return fListOfTables;
std::string Compile(const std::string &key, int16_t i=-1) const
static bool IsReservedKeyWord(const std::string &key)
std::vector< Column > SortedColumns
virtual void MoveColumnDataToUserSpace(char *dest, const char *src, const Table::Column &c)
bool HasKey(const std::string &key) const
std::vector< Address > Addresses
std::string GetStr(const std::string &key) const
void * SetPtrAddress(const std::string &name)
bool IsCompressedFITS() const
std::map< std::string, Column > Columns
uint64_t GetUInt(const std::string &key) const
bool HasColumn(const std::string &col) const
std::vector< char > fBufferDat
void PrintKeys(bool display_all=false) const
fits(const std::string &fname, const std::string &tableName="", bool force=false)
T Get(const std::string &key, const std::string &deflt) const
void PrintColumns() const
const T & GetAs(const std::string &name)
std::unordered_map< std::string, void * > Pointers
bool SetPtrAddress(const std::string &name, void *ptr, size_t cnt=0)
void ZeroBufferForChecksum(std::vector< char > &vec, const uint64_t extraZeros=0)
virtual size_t GetBytesPerRow() const
virtual size_t GetNumRows() const
bool Check(const std::string &key, char type, const std::string &value="") const
SortedColumns sorted_cols
virtual void WriteRowToCopyFile(size_t row)
bool SetVecAddress(const std::string &name, std::vector< T > &vec)
size_t GetN(const std::string &key) const
static bool Compare(const Address &p1, const Address &p2)
void EnableAddressExceptions(bool b=true)
bool ReadBlock(std::vector< std::string > &vec)
bool GetNextRow(bool check=true)
streamoff GetTotalBytes() const
T Get(const std::string &key) const
void PrintKeys(bool all_keys=false) const
const Table::Keys & GetKeys() const
const Keys & GetKeys() const
size_t GetN(const std::string &key) const
double GetFloat(const std::string &key) const
const Columns & GetColumns() const
std::map< std::string, Entry > Keys
virtual bool SkipNextRow()
T Get(const std::string &key, const T &deflt) const
int64_t GetInt(const std::string &key) const
streamoff GetHeapShift() const
void revcpy(char *dest, const char *src, const int &num)
std::vector< char > fBufferRow
std::vector< std::string > fListOfTables
virtual void StageRow(size_t row, char *dest)
void DisableAddressExceptions()
bool HasColumn(const std::string &col) const
const std::vector< std::string > & GetTables() const
void PrintColumns() const
std::string Trim(const std::string &str, char c=' ') const
const Table::SortedColumns & GetSortedColumns() const
std::vector< std::vector< char > > fGarbage
void Exception(const std::string &txt)
virtual bool IsFileOk() const
fits(const std::string &fname, const std::string &fout, const std::string &tableName, bool force=false)
const Table::Columns & GetColumns() const
bool SetPtrAddress(const std::string &name, T *ptr, size_t cnt)
std::pair< void *, Table::Column > Address
bool add(const char *buf, size_t len, bool big_endian=true)
Keys ParseBlock(const std::vector< std::string > &vec) const
bool HasKey(const std::string &key) const
bool SetRefAddress(const std::string &name, T &ptr)
void Constructor(const std::string &fname, std::string fout="", const std::string &tableName="", bool force=false)
T Get(const std::string &key) const
uint8_t ReadRow(size_t row)
virtual bool GetRow(size_t row, bool check=true)
Table(const std::vector< std::string > &vec, off_t off)