Changeset 17687 for fact/tools/pyscripts


Ignore:
Timestamp:
04/24/14 15:58:56 (11 years ago)
Author:
dneise
Message:
differs from Mars/mcore only in special python accessors like GetPy_KeyKeys and similar.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • fact/tools/pyscripts/pyfact/fits.h

    r13504 r17687  
    66#include <map>
    77#include <string>
     8#include <fstream>
    89#include <sstream>
    910#include <algorithm>
    10 
    11 #ifdef __EXCEPTIONS
    1211#include <stdexcept>
    13 #endif
    14 
    15 #ifdef __CINT__
     12
     13#define GCC_VERSION (__GNUC__ * 10000  + __GNUC_MINOR__ * 100  + __GNUC_PATCHLEVEL__)
     14
     15#ifndef __CINT__
     16#include <unordered_map>
     17#else
    1618#define off_t size_t
     19namespace std
     20{
     21    template<class T, class S> class unordered_map<T, S>;
     22}
    1723#endif
    1824
     
    2127#include <iomanip>
    2228#include <iostream>
    23 #define gLog cerr
    24 #define ___err___ ""
    25 #define ___all___ ""
     29#ifndef gLog
     30#define gLog std::cerr
     31#define ___err___   ""
     32#define ___warn___  ""
     33#define ___all___   ""
     34#endif
    2635#else
    2736#include "MLog.h"
    2837#include "MLogManip.h"
    29 #define ___err___ err
    30 #define ___all___ all
     38#define ___err___   err
     39#define ___warn___  warn
     40#define ___all___   all
    3141#endif
    3242
    3343#define HAVE_ZLIB
    34 #ifdef HAVE_ZLIB
    35 #include "izstream.h"
     44#if defined(HAVE_ZLIB) || defined(__CINT__)
     45#include "extern_Mars_mcore/izstream.h"
    3646#else
    3747#include <fstream>
    3848#define izstream ifstream
    39 //#warning Support for zipped FITS files disabled.
    40 #endif
    41 
    42 #warning This file is considered DEPRICATED. Please use pyfits.h instead
    43 
    44 namespace std
    45 {
     49#warning Support for zipped FITS files disabled.
     50#endif
     51
     52#include "extern_Mars_mcore/checksum.h"
    4653
    4754class fits : public izstream
    4855{
    4956public:
     57    //I know I know, you're going to yiell that this does not belong here.
     58    //It will belong in the global scope eventually, and it makes the coding of zfits much simpler this way.
     59    enum Compression_t
     60    {
     61        kCompUnknown,
     62        kCompFACT
     63    };
     64
    5065    struct Entry
    5166    {
    52         char   type;
    53         string value;
    54         string comment;
     67        char        type;
     68        std::string value;
     69        std::string comment;
     70        std::string fitsString;
    5571
    5672        template<typename T>
     
    5975            T t;
    6076
    61             istringstream str(value);
     77            std::istringstream str(value);
    6278            str >> t;
    6379
     
    7086        off_t offset;
    7187
    72         string name;
     88        bool is_compressed;
     89
     90        std::string name;
    7391        size_t bytes_per_row;
    7492        size_t num_rows;
    7593        size_t num_cols;
     94        size_t total_bytes; // NAXIS1*NAXIS2
    7695
    7796        struct Column
     
    8099            size_t num;
    81100            size_t size;
     101            size_t bytes;  // num*size
    82102            char   type;
    83             string unit;
     103            std::string unit;
     104            Compression_t comp;
    84105        };
    85106
    86         typedef map<string, Entry>  Keys;
    87         typedef map<string, Column> Columns;
     107        typedef std::map<std::string, Entry>  Keys;
     108        typedef std::map<std::string, Column> Columns;
     109        typedef std::vector<Column> SortedColumns;
    88110
    89111        Columns cols;
     112        SortedColumns sorted_cols;
    90113        Keys    keys;
    91 
    92         string Trim(const string &str, char c=' ') const
     114       
     115        //------------ vectors containing the same info as cols and keys------
     116        // They are filled at the end of the contstuctor
     117        // They are used py python, for retrieving the contents of the maps
     118        // I did not find out how to return a map of <string, struct> via ROOT to python
     119        // So I use this ugly hack. I guess its no problem, its just ugly
     120        //
     121        // btw: The way these variables are named, is imho as ugly as possible,
     122        // but I will stick to it.
     123        // usually a std::map contains key-value pairs
     124        // that means the e.g. map<string, Entry> contains keys of type string
     125        // and values of type Entry.
     126        // but now the map itself was called 'keys', which means one should say:
     127        // the keys of 'keys' are of type string
     128        // and
     129        // the value of 'keys' are of type Entry.
     130        // not to forget that:
     131        // one field of a value of 'keys' is named 'value'
     132       
     133        // vectors for Keys keys;
     134        vector<string> Py_KeyKeys;
     135        vector<string> Py_KeyValues;
     136        vector<string> Py_KeyComments;
     137        vector<char>   Py_KeyTypes;
     138       
     139        // vectors for Columns cols;
     140        vector<string> Py_ColumnKeys;
     141        vector<size_t> Py_ColumnOffsets;
     142        vector<size_t> Py_ColumnNums;
     143        vector<size_t> Py_ColumnSizes;
     144        vector<char>   Py_ColumnTypes;
     145        vector<string> Py_ColumnUnits;
     146        //-end of----- vectors containing the same info as cols and keys------
     147       
     148
     149        int64_t datasum;
     150
     151        std::string Trim(const std::string &str, char c=' ') const
    93152        {
    94153            // Trim Both leading and trailing spaces
     
    97156
    98157            // if all spaces or empty return an empty string
    99             if (string::npos==pstart || string::npos==pend)
    100                 return string();
     158            if (std::string::npos==pstart || std::string::npos==pend)
     159                return std::string();
    101160
    102161            return str.substr(pstart, pend-pstart+1);
    103162        }
    104163
    105         bool Check(const string &key, char type, const string &value="") const
     164        bool Check(const std::string &key, char type, const std::string &value="") const
    106165        {
    107166            const Keys::const_iterator it = keys.find(key);
    108167            if (it==keys.end())
    109168            {
    110                 ostringstream str;
     169                std::ostringstream str;
    111170                str << "Key '" << key << "' not found.";
    112171#ifdef __EXCEPTIONS
    113                 throw runtime_error(str.str());
    114 #else
    115                 gLog << ___err___ << "ERROR - " << str.str() << endl;
     172                throw std::runtime_error(str.str());
     173#else
     174                gLog << ___err___ << "ERROR - " << str.str() << std::endl;
    116175                return false;
    117176#endif
     
    120179            if (it->second.type!=type)
    121180            {
    122                 ostringstream str;
     181                std::ostringstream str;
    123182                str << "Wrong type for key '" << key << "': expected " << type << ", found " << it->second.type << ".";
    124183#ifdef __EXCEPTIONS
    125                 throw runtime_error(str.str());
    126 #else
    127                 gLog << ___err___ << "ERROR - " << str.str() << endl;
     184                throw std::runtime_error(str.str());
     185#else
     186                gLog << ___err___ << "ERROR - " << str.str() << std::endl;
    128187                return false;
    129188#endif
     
    132191            if (!value.empty() && it->second.value!=value)
    133192            {
    134                 ostringstream str;
     193                std::ostringstream str;
    135194                str << "Wrong value for key '" << key << "': expected " << value << ", found " << it->second.value << ".";
    136195#ifdef __EXCEPTIONS
    137                 throw runtime_error(str.str());
    138 #else
    139                 gLog << ___err___ << "ERROR - " << str.str() << endl;
     196                throw std::runtime_error(str.str());
     197#else
     198                gLog << ___err___ << "ERROR - " << str.str() << std::endl;
    140199                return false;
    141200#endif
     
    145204        }
    146205
    147         Keys ParseBlock(const vector<string> &vec) const
    148         {
    149             map<string,Entry> rc;
     206        Keys ParseBlock(const std::vector<std::string> &vec) const
     207        {
     208            std::map<std::string,Entry> rc;
    150209
    151210            for (unsigned int i=0; i<vec.size(); i++)
    152211            {
    153                 const string key = Trim(vec[i].substr(0,8));
     212                const std::string key = Trim(vec[i].substr(0,8));
    154213                // Keywords without a value, like COMMENT / HISTORY
    155214                if (vec[i].substr(8,2)!="= ")
     
    158217                char type = 0;
    159218
    160                 string com;
    161                 string val = Trim(vec[i].substr(10));
     219                std::string com;
     220                std::string val = Trim(vec[i].substr(10));
     221
    162222                if (val[0]=='\'')
    163223                {
     
    167227                    {
    168228                        const size_t pp = val.find_first_of('\'', p);
    169                         if (pp==string::npos)
     229                        if (pp==std::string::npos)
    170230                            break;
    171231
     
    177237
    178238                    // Set value, comment and type
    179                     com  = ppp==string::npos ? "" : Trim(val.substr(ppp+1));
     239                    // comments could be just spaces. take care of this.
     240                    if (ppp!=std::string::npos && val.size() != ppp+1)
     241                        com = Trim(val.substr(ppp+1));
     242
    180243                    val  = Trim(val.substr(1, p-2));
    181244                    type = 'T';
     
    185248                    const size_t p = val.find_first_of('/');
    186249
    187                     com = Trim(val.substr(p+2));
     250                    if (val.size() != p+1)
     251                        com = Trim(val.substr(p+2));
     252
    188253                    val = Trim(val.substr(0, p));
    189254
    190                     if (val.empty() || val.find_first_of('T')!=string::npos || val.find_first_of('F')!=string::npos)
     255                    if (val.empty() || val.find_first_of('T')!=std::string::npos || val.find_first_of('F')!=std::string::npos)
    191256                        type = 'B';
    192257                    else
    193                         type = val.find_last_of('.')==string::npos ? 'I' : 'F';
     258                        type = val.find_last_of('.')==std::string::npos ? 'I' : 'F';
    194259                }
    195260
    196                 const Entry e = { type, val, com };
     261                const Entry e = { type, val, com, vec[i] };
     262
    197263                rc[key] = e;
    198264            }
     
    201267        }
    202268
    203         Table() : offset(0) { }
    204         Table(const vector<string> &vec, off_t off) :
    205             offset(off), keys(ParseBlock(vec))
    206         {
     269        Table() : offset(0), is_compressed(false) { }
     270        Table(const std::vector<std::string> &vec, off_t off) : offset(off),
     271            keys(ParseBlock(vec))
     272        {
     273            is_compressed = HasKey("ZTABLE") && Check("ZTABLE", 'B', "T");
     274
    207275            if (!Check("XTENSION", 'T', "BINTABLE") ||
    208276                !Check("NAXIS",    'I', "2")        ||
    209277                !Check("BITPIX",   'I', "8")        ||
    210                 !Check("PCOUNT",   'I', "0")        ||
    211278                !Check("GCOUNT",   'I', "1")        ||
    212279                !Check("EXTNAME",  'T')             ||
     
    216283                return;
    217284
    218             bytes_per_row = Get<size_t>("NAXIS1");
    219             num_rows      = Get<size_t>("NAXIS2");
     285            if (is_compressed)
     286            {
     287                if (!Check("ZNAXIS1", 'I') ||
     288                    !Check("ZNAXIS2", 'I') ||
     289                    !Check("ZPCOUNT", 'I', "0"))
     290                    return;
     291            }
     292            else
     293            {
     294                if (!Check("PCOUNT", 'I', "0"))
     295                    return;
     296            }
     297
     298            total_bytes   = Get<size_t>("NAXIS1")*Get<size_t>("NAXIS2");
     299            bytes_per_row = is_compressed ? Get<size_t>("ZNAXIS1") : Get<size_t>("NAXIS1");
     300            num_rows      = is_compressed ? Get<size_t>("ZNAXIS2") : Get<size_t>("NAXIS2");
    220301            num_cols      = Get<size_t>("TFIELDS");
    221 
     302            datasum       = is_compressed ? Get<int64_t>("DATASUM", -1) : Get<int64_t>("DATASUM", -1);
     303//cout << "IS COMPRESSED =-========= " << is_compressed << " " << Get<size_t>("NAXIS1") << endl;
    222304            size_t bytes = 0;
    223             for (size_t i=1; i<=num_cols; i++)
    224             {
    225                 ostringstream num;
    226                 num << i;
    227 
    228                 if (!Check("TTYPE"+num.str(), 'T') ||
    229                     !Check("TFORM"+num.str(), 'T'))
     305
     306            const std::string tFormName = is_compressed ? "ZFORM" : "TFORM";
     307            for (long long unsigned int i=1; i<=num_cols; i++)
     308            {
     309                const std::string num(std::to_string(i));
     310
     311                if (!Check("TTYPE"+num, 'T') ||
     312                    !Check(tFormName+num, 'T'))
    230313                    return;
    231314
    232                 const string id   = Get<string>("TTYPE"+num.str());
    233                 const string fmt  = Get<string>("TFORM"+num.str());
    234                 const string unit = Get<string>("TUNIT"+num.str(), "");
    235 
    236                 istringstream sin(fmt);
     315                const std::string id   = Get<std::string>("TTYPE"+num);
     316                const std::string fmt  = Get<std::string>(tFormName+num);
     317                const std::string unit = Get<std::string>("TUNIT"+num, "");
     318                const std::string comp = Get<std::string>("ZCTYP"+num, "");
     319
     320                Compression_t compress = kCompUnknown;
     321                if (comp == "FACT")
     322                    compress = kCompFACT;
     323
     324                std::istringstream sin(fmt);
    237325                int n = 0;
    238326                sin >> n;
     
    247335                    // We could use negative values to mark floats
    248336                    // otheriwse we could just cast them to int64_t?
    249                 case 'L': size = 1; break; // logical
    250                 // case 'X': size = n; break; // bits (n=number of bytes needed to contain all bits)
     337                case 'L':                 // logical
     338                case 'A':                  // char
    251339                case 'B': size = 1; break; // byte
    252340                case 'I': size = 2; break; // short
     
    255343                case 'E': size = 4; break; // float
    256344                case 'D': size = 8; break; // double
     345                // case 'X': size =  n; break; // bits (n=number of bytes needed to contain all bits)
    257346                // case 'C': size =  8; break; // complex float
    258347                // case 'M': size = 16; break; // complex double
     
    261350                default:
    262351                    {
    263                         ostringstream str;
     352                        std::ostringstream str;
    264353                        str << "FITS format TFORM='" << fmt << "' not yet supported.";
    265354#ifdef __EXCEPTIONS
    266                         throw runtime_error(str.str());
    267 #else
    268                         gLog << ___err___ << "ERROR - " << str.str() << endl;
     355                        throw std::runtime_error(str.str());
     356#else
     357                        gLog << ___err___ << "ERROR - " << str.str() << std::endl;
    269358                        return;
    270359#endif
     
    272361                }
    273362
    274                 const Table::Column col = { bytes, n, size, type, unit };
     363                const Table::Column col = { bytes, n, size, n*size, type, unit, compress};
    275364
    276365                cols[id] = col;
     366                sorted_cols.push_back(col);
    277367                bytes  += n*size;
    278368            }
     
    281371            {
    282372#ifdef __EXCEPTIONS
    283                 throw runtime_error("Column size mismatch");
    284 #else
    285                 gLog << ___err___ << "ERROR - Column size mismatch" << endl;
     373                throw std::runtime_error("Column size mismatch");
     374#else
     375                gLog << ___err___ << "ERROR - Column size mismatch" << std::endl;
    286376                return;
    287377#endif
    288378            }
    289379
    290             name = Get<string>("EXTNAME");
     380            name = Get<std::string>("EXTNAME");
     381           
     382            Fill_Py_Vectors();
     383        }
     384       
     385        void Fill_Py_Vectors(void)
     386        {
     387            // Fill the Py_ vectors see line: 90ff
     388            // vectors for Keys keys;
     389            for (Keys::const_iterator it=keys.begin(); it!=keys.end(); it++)
     390            {
     391                Py_KeyKeys.push_back(it->first);
     392                Py_KeyValues.push_back(it->second.value);
     393                Py_KeyComments.push_back(it->second.comment);
     394                Py_KeyTypes.push_back(it->second.type);
     395            }
     396
     397            // vectors for Columns cols;
     398            for (Columns::const_iterator it=cols.begin(); it!=cols.end(); it++)
     399            {
     400                Py_ColumnKeys.push_back(it->first);
     401                Py_ColumnTypes.push_back(it->second.type);
     402                Py_ColumnOffsets.push_back(it->second.offset);
     403                Py_ColumnNums.push_back(it->second.num);
     404                Py_ColumnSizes.push_back(it->second.size);
     405                Py_ColumnUnits.push_back(it->second.unit);
     406            }
    291407        }
    292408
    293409        void PrintKeys(bool display_all=false) const
    294410        {
    295             for (Keys::const_iterator it=keys.begin(); it!=keys.end(); it++)
     411            for (Keys::const_iterator it=keys.cbegin(); it!=keys.cend(); it++)
    296412            {
    297413                if (!display_all &&
     
    308424                    continue;
    309425
    310                 gLog << ___all___ << setw(2) << it->second.type << '|' << it->first << '=' << it->second.value << '/' << it->second.comment << '|' << endl;
     426                gLog << ___all___ << std::setw(2) << it->second.type << '|' << it->first << '=' << it->second.value << '/' << it->second.comment << '|' << std::endl;
    311427            }}
    312428
    313429        void PrintColumns() const
    314430        {
    315             typedef map<pair<size_t, string>, Column> Sorted;
     431            typedef std::map<std::pair<size_t, std::string>, Column> Sorted;
    316432
    317433            Sorted sorted;
    318434
    319             for (Columns::const_iterator it=cols.begin(); it!=cols.end(); it++)
    320                 sorted[make_pair(it->second.offset, it->first)] = it->second;
    321 
    322             for (Sorted::const_iterator it=sorted.begin(); it!=sorted.end(); it++)
    323             {
    324                 gLog << ___all___ << setw(6) << it->second.offset << "| ";
     435            for (Columns::const_iterator it=cols.cbegin(); it!=cols.cend(); it++)
     436                sorted[std::make_pair(it->second.offset, it->first)] = it->second;
     437
     438            for (Sorted::const_iterator it=sorted.cbegin(); it!=sorted.cend(); it++)
     439            {
     440                gLog << ___all___ << std::setw(6) << it->second.offset << "| ";
    325441                gLog << it->second.num << 'x';
    326442                switch (it->second.type)
    327443                {
     444                case 'A': gLog << "char(8)";    break;
    328445                case 'L': gLog << "bool(8)";    break;
    329446                case 'B': gLog << "byte(8)";    break;
     
    334451                case 'D': gLog << "double(64)"; break;
    335452                }
    336                 gLog << ": " << it->first.second << " [" << it->second.unit << "]" << endl;
     453                gLog << ": " << it->first.second << " [" << it->second.unit << "]" << std::endl;
    337454            }
    338455        }
     
    340457        operator bool() const { return !name.empty(); }
    341458
    342         bool HasKey(const string &key) const
     459        bool HasKey(const std::string &key) const
    343460        {
    344461            return keys.find(key)!=keys.end();
    345462        }
    346463
    347             // Values of keys are always signed
     464        bool HasColumn(const std::string& col) const
     465        {
     466            return cols.find(col)!=cols.end();
     467        }
     468
     469        const Columns &GetColumns() const
     470        {
     471            return cols;
     472        }
     473
     474        const Keys &GetKeys() const
     475        {
     476            return keys;
     477        }
     478
     479        // Values of keys are always signed
    348480        template<typename T>
    349             T Get(const string &key) const
    350         {
    351             const map<string,Entry>::const_iterator it = keys.find(key);
     481            T Get(const std::string &key) const
     482        {
     483            const std::map<std::string,Entry>::const_iterator it = keys.find(key);
    352484            if (it==keys.end())
    353485            {
    354                 ostringstream str;
    355                 str << "Key '" << key << "' not found." << endl;
    356 #ifdef __EXCEPTIONS
    357                 throw runtime_error(str.str());
    358 #else
    359                 gLog << ___err___ << "ERROR - " << str.str() << endl;
     486                std::ostringstream str;
     487                str << "Key '" << key << "' not found.";
     488#ifdef __EXCEPTIONS
     489                throw std::runtime_error(str.str());
     490#else
     491                gLog << ___err___ << "ERROR - " << str.str() << std::endl;
     492                return T();
     493#endif
     494            }
     495            return it->second.Get<T>();
     496        }
     497
     498        // Values of keys are always signed
     499        template<typename T>
     500            T Get(const std::string &key, const T &deflt) const
     501        {
     502            const std::map<std::string,Entry>::const_iterator it = keys.find(key);
     503            return it==keys.end() ? deflt :it->second.Get<T>();
     504        }
     505
     506        size_t GetN(const std::string &key) const
     507        {
     508            const Columns::const_iterator it = cols.find(key);
     509            return it==cols.end() ? 0 : it->second.num;
     510        }
     511       
     512
     513
     514        // There may be a gap between the main table and the start of the heap:
     515        // this computes the offset
     516        streamoff GetHeapShift() const
     517        {
     518            if (!HasKey("ZHEAPPTR"))
    360519                return 0;
    361 #endif
    362             }
    363             return it->second.Get<T>();
    364         }
    365 
    366             // Values of keys are always signed
    367         template<typename T>
    368             T Get(const string &key, const string &deflt) const
    369         {
    370             const map<string,Entry>::const_iterator it = keys.find(key);
    371             return it==keys.end() ? deflt :it->second.Get<T>();
    372         }
    373 
    374         size_t GetN(const string &key) const
    375         {
    376             const Columns::const_iterator it = cols.find(key);
    377             if (it==cols.end()){
    378                 ostringstream str;
    379                 str << "Key '" << key << "' not found." << endl;
    380                 str << "Possible keys are:" << endl;
    381                 for ( Columns::const_iterator it=cols.begin() ; it != cols.end(); ++it){
    382                     str << it->first << endl;
    383                 }
    384 #ifdef __EXCEPTIONS
    385                 throw runtime_error(str.str());
    386 #else
    387                 gLog << ___err___ << "ERROR - " << str.str() << endl;
    388                 return 0;
    389 #endif
    390             }
    391             return it==cols.end() ? 0 : it->second.num;
     520
     521            const size_t shift = Get<size_t>("ZHEAPPTR");
     522            return shift <= total_bytes ? 0 : shift - total_bytes;
     523        }
     524
     525        // return total number of bytes 'all inclusive'
     526        streamoff GetTotalBytes() const
     527        {
     528            //get offset of special data area from start of main table
     529            const streamoff shift = GetHeapShift();
     530
     531            //and special data area size
     532            const streamoff size  = HasKey("PCOUNT") ? Get<streamoff>("PCOUNT") : 0;
     533
     534            // Get the total size
     535            const streamoff total = total_bytes + size + shift;
     536
     537            // check for padding
     538            if (total%2880==0)
     539                return total;
     540
     541            // padding necessary
     542            return total + (2880 - (total%2880));
    392543        }
    393544    };
    394545
    395 private:
     546protected:
     547    std::ofstream fCopy;
     548    std::vector<std::string> fListOfTables; // List of skipped tables. Last table is open table
     549
    396550    Table fTable;
    397551
    398     typedef pair<void*, Table::Column> Address;
    399     typedef vector<Address> Addresses;
     552    typedef std::pair<void*, Table::Column> Address;
     553    typedef std::vector<Address> Addresses;
    400554    //map<void*, Table::Column> fAddresses;
    401555    Addresses fAddresses;
    402556
    403     vector<char> fBufferRow;
    404     vector<char> fBufferDat;
     557    typedef std::unordered_map<std::string, void*> Pointers;
     558    Pointers fPointers;
     559
     560    std::vector<std::vector<char>> fGarbage;
     561
     562    std::vector<char> fBufferRow;
     563    std::vector<char> fBufferDat;
    405564
    406565    size_t fRow;
    407566
    408     vector<string> ReadBlock(vector<string> &vec)
    409     {
    410         bool endtag = false;
     567    Checksum fChkHeader;
     568    Checksum fChkData;
     569
     570    bool ReadBlock(std::vector<std::string> &vec)
     571    {
     572        int endtag = 0;
    411573        for (int i=0; i<36; i++)
    412574        {
     
    417579                break;
    418580
    419             if (c[0]==0)
    420                 return vector<string>();
    421 
    422             string str(c);
     581            fChkHeader.add(c, 80);
     582
     583//            if (c[0]==0)
     584//                return vector<string>();
     585
     586            std::string str(c);
    423587
    424588//            if (!str.empty())
    425589//                cout << setw(2) << i << "|" << str << "|" << (endtag?'-':'+') << endl;
    426590
    427             if (str=="END                                                                             ")
    428             {
    429                 endtag = true;
    430 
    431                 // Make sure that no empty vector is returned
    432                 if (vec.size()%36==0)
    433                     vec.push_back(string("END     = '' / "));
    434             }
    435 
    436             if (endtag)
     591            if (endtag==2 || str=="END                                                                             ")
     592            {
     593                endtag = 2; // valid END tag found
    437594                continue;
     595            }
     596
     597            if (endtag==1 || str=="                                                                                ")
     598            {
     599                endtag = 1; // end tag not found, but expected to be there
     600                continue;
     601            }
    438602
    439603            vec.push_back(str);
    440604        }
    441605
    442         return vec;
    443     }
    444 
    445     string Compile(const string &key, int16_t i=-1)
    446     {
    447         if (i<0)
    448             return key;
    449 
    450         ostringstream str;
    451         str << key << i;
    452         return str.str();
    453     }
    454 
    455 public:
    456     fits(const string &fname) : izstream(fname.c_str())
     606        // Make sure that no empty vector is returned
     607        if (endtag && vec.size()%36==0)
     608            vec.emplace_back("END     = '' / ");
     609
     610        return endtag==2;
     611    }
     612
     613    std::string Compile(const std::string &key, int16_t i=-1) const
     614    {
     615#if GCC_VERSION < 40603
     616        return i<0 ? key : key+std::to_string((long long int)(i));
     617#else
     618        return i<0 ? key : key+std::to_string(i);
     619#endif
     620    }
     621
     622    void Constructor(const std::string &fname, std::string fout="", const std::string& tableName="", bool force=false)
    457623    {
    458624        char simple[10];
     
    463629        if (memcmp(simple, "SIMPLE  = ", 10))
    464630        {
    465             clear(rdstate()|ios::badbit);
    466 #ifdef __EXCEPTIONS
    467             throw runtime_error("File is not a FITS file.");
    468 #else
    469             gLog << ___err___ << "ERROR - File is not a FITS file." << endl;
     631            clear(rdstate()|std::ios::badbit);
     632#ifdef __EXCEPTIONS
     633            throw std::runtime_error("File is not a FITS file.");
     634#else
     635            gLog << ___err___ << "ERROR - File is not a FITS file." << std::endl;
    470636            return;
    471637#endif
     
    476642        while (good())
    477643        {
    478             vector<string> block;
     644            std::vector<std::string> block;
    479645            while (1)
    480646            {
     647                // If we search for a table, we implicitly assume that
     648                // not finding the table is not an error. The user
     649                // can easily check that by eof() && !bad()
     650                peek();
     651                if (eof() && !bad() && !tableName.empty())
     652                {
     653                    break;
     654                }
    481655                // FIXME: Set limit on memory consumption
    482                 ReadBlock(block);
     656                const int rc = ReadBlock(block);
    483657                if (!good())
    484658                {
    485                     clear(rdstate()|ios::badbit);
    486 #ifdef __EXCEPTIONS
    487                     throw runtime_error("FITS file corrupted.");
    488 #else
    489                     gLog << ___err___ << "ERROR - FITS file corrupted." << endl;
     659                    clear(rdstate()|std::ios::badbit);
     660#ifdef __EXCEPTIONS
     661                    throw std::runtime_error("FITS file corrupted.");
     662#else
     663                    gLog << ___err___ << "ERROR - FITS file corrupted." << std::endl;
    490664                    return;
    491665#endif
     
    493667
    494668                if (block.size()%36)
     669                {
     670                    if (!rc && !force)
     671                    {
     672                        clear(rdstate()|std::ios::badbit);
     673#ifdef __EXCEPTIONS
     674                        throw std::runtime_error("END keyword missing in FITS header.");
     675#else
     676                        gLog << ___err___ << "ERROR - END keyword missing in FITS file... file might be corrupted." << std::endl;
     677                        return;
     678#endif
     679                    }
    495680                    break;
    496             }
    497 
    498             if (block.size()==0)
     681                }
     682            }
     683
     684            if (block.empty())
    499685                break;
    500686
    501687            if (block[0].substr(0, 9)=="SIMPLE  =")
     688            {
     689                fChkHeader.reset();
    502690                continue;
     691            }
    503692
    504693            if (block[0].substr(0, 9)=="XTENSION=")
    505694            {
    506                 // FIXME: Check for table name
    507 
    508695                fTable = Table(block, tellg());
    509696                fRow   = (size_t)-1;
    510697
    511                 //fTable.PrintKeys();
    512 
    513698                if (!fTable)
    514699                {
    515                     clear(rdstate()|ios::badbit);
     700                    clear(rdstate()|std::ios::badbit);
    516701                    return;
    517702                }
    518703
    519                 fBufferRow.resize(fTable.bytes_per_row);
     704                const std::string &tname = fTable.Get<std::string>("EXTNAME");
     705
     706                fListOfTables.emplace_back(tname);
     707
     708                // Check for table name. Skip until eof or requested table are found.
     709                // skip the current table?
     710                if ((!tableName.empty() && tableName!=tname) || (tableName.empty() && "ZDrsCellOffsets"==tname))
     711                {
     712                    const streamoff skip = fTable.GetTotalBytes();
     713                    seekg(skip, std::ios_base::cur);
     714
     715                    fChkHeader.reset();
     716
     717                    continue;
     718                }
     719
     720                fBufferRow.resize(fTable.bytes_per_row + 8-fTable.bytes_per_row%4);
    520721                fBufferDat.resize(fTable.bytes_per_row);
    521722
    522                 /*
    523                  // Next table should start at:
    524                  const size_t size = fTable.bytes_per_row*fTable.num_rows;
    525                  const size_t blks = size/(36*80);
    526                  const size_t rest = size%(36*80);
    527 
    528                 seekg((blks+(rest>0?1:0))*(36*80), ios::cur);
    529                 if (!good())
    530                      gLog << ___err___ << "File seems to be incomplete (less data than expected from header)." << endl;
    531 
    532                 fRow   = fTable.num_rows;
    533                  */
    534 
    535723                break;
    536724            }
    537725        }
    538     }
    539 
    540     void ReadRow(size_t row)
     726
     727        if (fout.empty())
     728            return;
     729
     730        if (*fout.rbegin()=='/')
     731        {
     732            const size_t p = fname.find_last_of('/');
     733            fout.append(fname.substr(p+1));
     734        }
     735
     736        fCopy.open(fout);
     737        if (!fCopy)
     738        {
     739            clear(rdstate()|std::ios::badbit);
     740#ifdef __EXCEPTIONS
     741            throw std::runtime_error("Could not open output file.");
     742#else
     743            gLog << ___err___ << "ERROR - Failed to open output file." << std::endl;
     744            return;
     745#endif
     746        }
     747
     748        const streampos p = tellg();
     749        seekg(0);
     750
     751        std::vector<char> buf(p);
     752        read(buf.data(), p);
     753
     754        fCopy.write(buf.data(), p);
     755        if (!fCopy)
     756            clear(rdstate()|std::ios::badbit);
     757    }
     758
     759public:
     760    fits(const std::string &fname, const std::string& tableName="", bool force=false) : izstream(fname.c_str())
     761    {
     762        Constructor(fname, "", tableName, force);
     763        if ((fTable.is_compressed ||fTable.name=="ZDrsCellOffsets") && !force)
     764        {
     765#ifdef __EXCEPTIONS
     766            throw std::runtime_error("You are trying to read a compressed fits with the base fits class. Please use factfits instead.");
     767#else
     768            gLog << ___err___ << "ERROR - You are trying to read a compressed fits with the base fits class. Please use factfits instead." << std::endl;
     769#endif
     770            clear(rdstate()|std::ios::badbit);
     771        }
     772    }
     773
     774    fits(const std::string &fname, const std::string &fout, const std::string& tableName, bool force=false) : izstream(fname.c_str())
     775    {
     776        Constructor(fname, fout, tableName, force);
     777        if ((fTable.is_compressed || fTable.name=="ZDrsCellOffsets") && !force)
     778        {
     779#ifdef __EXCEPTIONS
     780            throw std::runtime_error("You are trying to read a compressed fits with the base fits class. Please use factfits instead.");
     781#else
     782            gLog << ___err___ << "ERROR - You are trying to read a compressed fits with the base fits class. Please use factfits instead." << std::endl;
     783#endif
     784            clear(rdstate()|std::ios::badbit);
     785        }
     786    }
     787
     788    fits() : izstream()
     789    {
     790
     791    }
     792
     793    ~fits()
     794    {
     795        std::copy(std::istreambuf_iterator<char>(*this),
     796                  std::istreambuf_iterator<char>(),
     797                  std::ostreambuf_iterator<char>(fCopy));
     798    }
     799
     800    virtual void StageRow(size_t row, char* dest)
    541801    {
    542802        // if (row!=fRow+1) // Fast seeking is ensured by izstream
    543803        seekg(fTable.offset+row*fTable.bytes_per_row);
     804        read(dest, fTable.bytes_per_row);
     805        //fin.clear(fin.rdstate()&~ios::eofbit);
     806    }
     807
     808    virtual void WriteRowToCopyFile(size_t row)
     809    {
     810        if (row==fRow+1)
     811        {
     812            const uint8_t offset = (row*fTable.bytes_per_row)%4;
     813
     814            fChkData.add(fBufferRow);
     815            if (fCopy.is_open() && fCopy.good())
     816                fCopy.write(fBufferRow.data()+offset, fTable.bytes_per_row);
     817            if (!fCopy)
     818                clear(rdstate()|std::ios::badbit);
     819        }
     820        else
     821            if (fCopy.is_open())
     822                clear(rdstate()|std::ios::badbit);
     823    }
     824
     825    void ZeroBufferForChecksum(std::vector<char>& vec, const uint64_t extraZeros=0)
     826    {
     827        auto ib = vec.begin();
     828        auto ie = vec.end();
     829
     830        *ib++ = 0;
     831        *ib++ = 0;
     832        *ib++ = 0;
     833        *ib   = 0;
     834
     835        for (uint64_t i=0;i<extraZeros+8;i++)
     836            *--ie = 0;
     837    }
     838
     839    uint8_t ReadRow(size_t row)
     840    {
     841        // For the checksum we need everything to be correctly aligned
     842        const uint8_t offset = (row*fTable.bytes_per_row)%4;
     843
     844        ZeroBufferForChecksum(fBufferRow);
     845
     846        StageRow(row, fBufferRow.data()+offset);
     847
     848        WriteRowToCopyFile(row);
    544849
    545850        fRow = row;
    546851
    547         read(fBufferRow.data(), fBufferRow.size());
    548         //fin.clear(fin.rdstate()&~ios::eofbit);
     852        return offset;
    549853    }
    550854
    551855    template<size_t N>
    552         void revcpy(char *dest, const char *src, int num)
     856        void revcpy(char *dest, const char *src, const int &num)
    553857    {
    554858        const char *pend = src + num*N;
    555859        for (const char *ptr = src; ptr<pend; ptr+=N, dest+=N)
    556             reverse_copy(ptr, ptr+N, dest);
    557     }
    558 
    559     bool GetRow(size_t row)
    560     {
    561         ReadRow(row);
     860            std::reverse_copy(ptr, ptr+N, dest);
     861    }
     862
     863    virtual void MoveColumnDataToUserSpace(char *dest, const char *src, const Table::Column& c)
     864    {
     865        // Let the compiler do some optimization by
     866        // knowing that we only have 1, 2, 4 and 8
     867        switch (c.size)
     868        {
     869        case 1: memcpy   (dest, src, c.bytes); break;
     870        case 2: revcpy<2>(dest, src, c.num);   break;
     871        case 4: revcpy<4>(dest, src, c.num);   break;
     872        case 8: revcpy<8>(dest, src, c.num);   break;
     873        }
     874    }
     875
     876    virtual bool GetRow(size_t row, bool check=true)
     877    {
     878        if (check && row>=fTable.num_rows)
     879            return false;
     880
     881        const uint8_t offset = ReadRow(row);
    562882        if (!good())
    563883            return good();
    564884
    565         for (Addresses::const_iterator it=fAddresses.begin(); it!=fAddresses.end(); it++)
     885        const char *ptr = fBufferRow.data() + offset;
     886
     887        for (Addresses::const_iterator it=fAddresses.cbegin(); it!=fAddresses.cend(); it++)
    566888        {
    567889            const Table::Column &c = it->second;
    568890
    569             const char *src = fBufferRow.data() + c.offset;
     891            const char *src = ptr + c.offset;
    570892            char *dest = reinterpret_cast<char*>(it->first);
    571893
    572             // Let the compiler do some optimization by
    573             // knowing the we only have 1, 2, 4 and 8
    574             switch (c.size)
    575             {
    576             case 1: memcpy   (dest, src, c.num*c.size); break;
    577             case 2: revcpy<2>(dest, src, c.num);        break;
    578             case 4: revcpy<4>(dest, src, c.num);        break;
    579             case 8: revcpy<8>(dest, src, c.num);        break;
    580             }
     894            MoveColumnDataToUserSpace(dest, src, c);
    581895        }
    582896
     
    584898    }
    585899
    586     bool GetNextRow()
    587     {
    588         return GetRow(fRow+1);
    589     }
    590 
    591     bool SkipNextRow()
     900    bool GetNextRow(bool check=true)
     901    {
     902        return GetRow(fRow+1, check);
     903    }
     904
     905    virtual bool SkipNextRow()
    592906    {
    593907        seekg(fTable.offset+(++fRow)*fTable.bytes_per_row);
     
    600914    }
    601915
     916    template<class T, class S>
     917    const T &GetAs(const std::string &name)
     918    {
     919        return *reinterpret_cast<S*>(fPointers[name]);
     920    }
     921
     922    void *SetPtrAddress(const std::string &name)
     923    {
     924        if (fTable.cols.count(name)==0)
     925        {
     926            std::ostringstream str;
     927            str << "SetPtrAddress('" << name << "') - Column not found.";
     928#ifdef __EXCEPTIONS
     929            throw std::runtime_error(str.str());
     930#else
     931            gLog << ___err___ << "ERROR - " << str.str() << std::endl;
     932            return NULL;
     933#endif
     934        }
     935
     936        Pointers::const_iterator it = fPointers.find(name);
     937        if (it!=fPointers.end())
     938            return it->second;
     939
     940        fGarbage.emplace_back(fTable.cols[name].bytes);
     941
     942        void *ptr = fGarbage.back().data();
     943
     944        fPointers[name] = ptr;
     945        fAddresses.emplace_back(ptr, fTable.cols[name]);
     946        sort(fAddresses.begin(), fAddresses.end(), Compare);
     947        return ptr;
     948    }
     949
    602950    template<typename T>
    603     bool SetPtrAddress(const string &name, T *ptr, size_t cnt)
     951    bool SetPtrAddress(const std::string &name, T *ptr, size_t cnt)
    604952    {
    605953        if (fTable.cols.count(name)==0)
    606954        {
    607             ostringstream str;
    608             str <<"SetPtrAddress('" << name << "') - Column not found." << endl;
    609 #ifdef __EXCEPTIONS
    610             throw runtime_error(str.str());
    611 #else
    612             gLog << ___err___ << "ERROR - " << str.str() << endl;
     955            std::ostringstream str;
     956            str << "SetPtrAddress('" << name << "') - Column not found.";
     957#ifdef __EXCEPTIONS
     958            throw std::runtime_error(str.str());
     959#else
     960            gLog << ___err___ << "ERROR - " << str.str() << std::endl;
    613961            return false;
    614962#endif
     
    617965        if (sizeof(T)!=fTable.cols[name].size)
    618966        {
    619             ostringstream str;
     967            std::ostringstream str;
    620968            str << "SetPtrAddress('" << name << "') - Element size mismatch: expected "
    621                 << fTable.cols[name].size << " from header, got " << sizeof(T) << endl;
    622 #ifdef __EXCEPTIONS
    623             throw runtime_error(str.str());
    624 #else
    625             gLog << ___err___ << "ERROR - " << str.str() << endl;
     969                << fTable.cols[name].size << " from header, got " << sizeof(T);
     970#ifdef __EXCEPTIONS
     971            throw std::runtime_error(str.str());
     972#else
     973            gLog << ___err___ << "ERROR - " << str.str() << std::endl;
    626974            return false;
    627975#endif
     
    630978        if (cnt!=fTable.cols[name].num)
    631979        {
    632             ostringstream str;
     980            std::ostringstream str;
    633981            str << "SetPtrAddress('" << name << "') - Element count mismatch: expected "
    634                 << fTable.cols[name].num << " from header, got " << cnt << endl;
    635 #ifdef __EXCEPTIONS
    636             throw runtime_error(str.str());
    637 #else
    638             gLog << ___err___ << "ERROR - " << str.str() << endl;
     982                << fTable.cols[name].num << " from header, got " << cnt;
     983#ifdef __EXCEPTIONS
     984            throw std::runtime_error(str.str());
     985#else
     986            gLog << ___err___ << "ERROR - " << str.str() << std::endl;
    639987            return false;
    640988#endif
     
    645993
    646994        //fAddresses[ptr] = fTable.cols[name];
    647         fAddresses.push_back(make_pair(ptr, fTable.cols[name]));
     995        fPointers[name] = ptr;
     996        fAddresses.emplace_back(ptr, fTable.cols[name]);
    648997        sort(fAddresses.begin(), fAddresses.end(), Compare);
    649998        return true;
     
    6511000
    6521001    template<class T>
    653     bool SetRefAddress(const string &name, T &ptr)
     1002    bool SetRefAddress(const std::string &name, T &ptr)
    6541003    {
    6551004        return SetPtrAddress(name, &ptr, sizeof(ptr)/sizeof(T));
     
    6571006
    6581007    template<typename T>
    659     bool SetVecAddress(const string &name, vector<T> &vec)
     1008    bool SetVecAddress(const std::string &name, std::vector<T> &vec)
    6601009    {
    6611010        return SetPtrAddress(name, vec.data(), vec.size());
     
    6631012
    6641013    template<typename T>
    665         T Get(const string &key) const
     1014        T Get(const std::string &key) const
    6661015    {
    6671016        return fTable.Get<T>(key);
     
    6691018
    6701019    template<typename T>
    671         T Get(const string &key, const string &deflt) const
     1020        T Get(const std::string &key, const std::string &deflt) const
    6721021    {
    6731022        return fTable.Get<T>(key, deflt);
    6741023    }
    6751024
    676     bool SetPtrAddress(const string &name, void *ptr)
     1025    bool SetPtrAddress(const std::string &name, void *ptr, size_t cnt=0)
    6771026    {
    6781027        if (fTable.cols.count(name)==0)
    6791028        {
    680             ostringstream str;
    681             str <<"SetPtrAddress('" << name << "') - Column not found." << endl;
    682 #ifdef __EXCEPTIONS
    683             throw runtime_error(str.str());
    684 #else
    685             gLog << ___err___ << "ERROR - " << str.str() << endl;
     1029            std::ostringstream str;
     1030            str <<"SetPtrAddress('" << name << "') - Column not found.";
     1031#ifdef __EXCEPTIONS
     1032            throw std::runtime_error(str.str());
     1033#else
     1034            gLog << ___err___ << "ERROR - " << str.str() << std::endl;
     1035            return false;
     1036#endif
     1037        }
     1038
     1039        if (cnt && cnt!=fTable.cols[name].num)
     1040        {
     1041            std::ostringstream str;
     1042            str << "SetPtrAddress('" << name << "') - Element count mismatch: expected "
     1043                << fTable.cols[name].num << " from header, got " << cnt;
     1044#ifdef __EXCEPTIONS
     1045            throw std::runtime_error(str.str());
     1046#else
     1047            gLog << ___err___ << "ERROR - " << str.str() << std::endl;
    6861048            return false;
    6871049#endif
     
    6921054
    6931055        //fAddresses[ptr] = fTable.cols[name];
    694         fAddresses.push_back(make_pair(ptr, fTable.cols[name]));
     1056        fPointers[name] = ptr;
     1057        fAddresses.emplace_back(ptr, fTable.cols[name]);
    6951058        sort(fAddresses.begin(), fAddresses.end(), Compare);
    6961059        return true;
    6971060    }
    6981061
    699     bool     HasKey(const string &key) const { return fTable.HasKey(key); }
    700     int64_t  GetInt(const string &key) const { return fTable.Get<int64_t>(key); }
    701     uint64_t GetUInt(const string &key) const { return fTable.Get<uint64_t>(key); }
    702     double   GetFloat(const string &key) const { return fTable.Get<double>(key); }
    703     string   GetStr(const string &key) const { return fTable.Get<string>(key); }
    704 
    705     size_t GetN(const string &key) const
     1062    bool     HasKey(const std::string &key) const { return fTable.HasKey(key); }
     1063    bool     HasColumn(const std::string& col) const { return fTable.HasColumn(col);}
     1064    const Table::Columns &GetColumns() const { return fTable.GetColumns();}
     1065    const Table::SortedColumns& GetSortedColumns() const { return fTable.sorted_cols;}
     1066    const Table::Keys &GetKeys() const { return fTable.GetKeys();}
     1067
     1068    int64_t     GetInt(const std::string &key) const { return fTable.Get<int64_t>(key); }
     1069    uint64_t    GetUInt(const std::string &key) const { return fTable.Get<uint64_t>(key); }
     1070    double      GetFloat(const std::string &key) const { return fTable.Get<double>(key); }
     1071    std::string GetStr(const std::string &key) const { return fTable.Get<std::string>(key); }
     1072
     1073    size_t GetN(const std::string &key) const
    7061074    {
    7071075        return fTable.GetN(key);
    7081076    }
    7091077
    710     size_t GetNumRows() const { return fTable.num_rows; }
    711     size_t GetRow() const { return fRow; }
     1078//    size_t GetNumRows() const { return fTable.num_rows; }
     1079    size_t GetRow() const { return fRow==(size_t)-1 ? 0 : fRow; }
    7121080
    7131081    operator bool() const { return fTable && fTable.offset!=0; }
     
    7151083    void PrintKeys() const { fTable.PrintKeys(); }
    7161084    void PrintColumns() const { fTable.PrintColumns(); }
     1085   
     1086    // 'Wrappers' for the Table's Getters of the Py Vectors
     1087    vector<string> GetPy_KeyKeys()       {return fTable.Py_KeyKeys; }
     1088    vector<string> GetPy_KeyValues()     {return fTable.Py_KeyValues; }
     1089    vector<string> GetPy_KeyComments()   {return fTable.Py_KeyComments; }
     1090    vector<char>   GetPy_KeyTypes()      {return fTable.Py_KeyTypes; }
     1091   
     1092    vector<string> GetPy_ColumnKeys()    {return fTable.Py_ColumnKeys; }
     1093    vector<size_t> GetPy_ColumnOffsets() {return fTable.Py_ColumnOffsets; }
     1094    vector<size_t> GetPy_ColumnNums()    {return fTable.Py_ColumnNums; }
     1095    vector<size_t> GetPy_ColumnSizes()   {return fTable.Py_ColumnSizes;}
     1096    vector<char>   GetPy_ColumnTypes()   {return fTable.Py_ColumnTypes;}
     1097    vector<string> GetPy_ColumnUnits()   {return fTable.Py_ColumnUnits;}
     1098
     1099    bool IsHeaderOk() const { return fTable.datasum<0?false:(fChkHeader+Checksum(fTable.datasum)).valid(); }
     1100    virtual bool IsFileOk() const { return (fChkHeader+fChkData).valid(); }
     1101
     1102    bool IsCompressedFITS() const { return fTable.is_compressed;}
     1103
     1104    virtual size_t GetNumRows() const
     1105    {
     1106        return fTable.Get<size_t>("NAXIS2");
     1107    }
     1108
     1109    virtual size_t GetBytesPerRow() const
     1110    {
     1111        return fTable.Get<size_t>("NAXIS1");
     1112    }
     1113
     1114    const std::vector<std::string> &GetTables() const
     1115    {
     1116        return fListOfTables;
     1117    }
    7171118};
    7181119
    719 };
    720 #endif
     1120#endif
Note: See TracChangeset for help on using the changeset viewer.