SPECtrum Processing Routines Data Format 3/4/88: C++11/STL parsing library

Specpr records are fixed format, 1536 bytes/record. Record number counting starts at 0. Binary data are in IEEE format real numbers and non-byte swapped integers (compatiible with all Sun Microsystems, and Hewlett Packard workstations (Intel and some DEC machines are byte swapped relative to Suns and HPs). Each record may contain different information according to the following scheme.

You can get some library of spectra from ftp://ftpext.cr.usgs.gov/pub/cr/co/denver/speclab/pub/spectral.library/splib06.library/

File extension

spec

KS implementation details

License: Unlicense

This page hosts a formal specification of SPECtrum Processing Routines Data Format 3/4/88 using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

Runtime library

All parsing code for C++11/STL generated by Kaitai Struct depends on the C++/STL runtime library. You have to install it before you can parse data.

For C++, the easiest way is to clone the runtime library sources and build them along with your project.

Code

Using Kaitai Struct in C++/STL usually consists of 3 steps.

  1. We need to create an STL input stream (std::istream). One can open local file for that, or use existing std::string or char* buffer.
    #include <fstream>
    
    std::ifstream is("path/to/local/file.spec", std::ifstream::binary);
    
    #include <sstream>
    
    std::istringstream is(str);
    
    #include <sstream>
    
    const char buf[] = { ... };
    std::string str(buf, sizeof buf);
    std::istringstream is(str);
    
  2. We need to wrap our input stream into Kaitai stream:
    #include "kaitai/kaitaistream.h"
    
    kaitai::kstream ks(&is);
    
  3. And finally, we can invoke the parsing:
    specpr_t data(&ks);
    

After that, one can get various attributes from the structure by invoking getter methods like:

data.records() // => get records

C++11/STL source code to parse SPECtrum Processing Routines Data Format 3/4/88

specpr.h

#pragma once

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "kaitai/kaitaistruct.h"
#include <stdint.h>
#include <memory>
#include <vector>

#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif

/**
 * Specpr records are fixed format, 1536 bytes/record. Record number
 * counting starts at 0. Binary data are in IEEE format real numbers
 * and non-byte swapped integers (compatiible with all Sun
 * Microsystems, and Hewlett Packard workstations (Intel and some DEC
 * machines are byte swapped relative to Suns and HPs). Each record may
 * contain different information according to the following scheme.
 * 
 * You can get some library of spectra from
 * ftp://ftpext.cr.usgs.gov/pub/cr/co/denver/speclab/pub/spectral.library/splib06.library/
 */

class specpr_t : public kaitai::kstruct {

public:
    class data_initial_t;
    class coarse_timestamp_t;
    class icflag_t;
    class data_continuation_t;
    class identifiers_t;
    class illum_angle_t;
    class text_initial_t;
    class record_t;
    class text_continuation_t;

    enum record_type_t {
        RECORD_TYPE_DATA_INITIAL = 0,
        RECORD_TYPE_TEXT_INITIAL = 1,
        RECORD_TYPE_DATA_CONTINUATION = 2,
        RECORD_TYPE_TEXT_CONTINUATION = 3
    };

    specpr_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, specpr_t* p__root = nullptr);

private:
    void _read();
    void _clean_up();

public:
    ~specpr_t();

    class data_initial_t : public kaitai::kstruct {

    public:

        data_initial_t(kaitai::kstream* p__io, specpr_t::record_t* p__parent = nullptr, specpr_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~data_initial_t();

    private:
        bool f_phase_angle_arcsec;
        double m_phase_angle_arcsec;

    public:

        /**
         * The phase angle between iangl and eangl in seconds
         */
        double phase_angle_arcsec();

    private:
        std::unique_ptr<identifiers_t> m_ids;
        std::unique_ptr<coarse_timestamp_t> m_iscta;
        std::unique_ptr<coarse_timestamp_t> m_isctb;
        int32_t m_jdatea;
        int32_t m_jdateb;
        std::unique_ptr<coarse_timestamp_t> m_istb;
        int32_t m_isra;
        int32_t m_isdec;
        int32_t m_itchan;
        int32_t m_irmas;
        int32_t m_revs;
        std::unique_ptr<std::vector<int32_t>> m_iband;
        int32_t m_irwav;
        int32_t m_irespt;
        int32_t m_irecno;
        int32_t m_itpntr;
        std::string m_ihist;
        std::unique_ptr<std::vector<std::string>> m_mhist;
        int32_t m_nruns;
        std::unique_ptr<illum_angle_t> m_siangl;
        std::unique_ptr<illum_angle_t> m_seangl;
        int32_t m_sphase;
        int32_t m_iwtrns;
        int32_t m_itimch;
        float m_xnrm;
        float m_scatim;
        float m_timint;
        float m_tempd;
        std::unique_ptr<std::vector<float>> m_data;
        specpr_t* m__root;
        specpr_t::record_t* m__parent;

    public:
        identifiers_t* ids() const { return m_ids.get(); }

        /**
         * Civil or Universal time when data was last processed
         */
        coarse_timestamp_t* iscta() const { return m_iscta.get(); }

        /**
         * Civil or Universal time at the start of the spectral run
         */
        coarse_timestamp_t* isctb() const { return m_isctb.get(); }

        /**
         * Date when data was last processed. Stored as integer*4 Julian Day number *10
         */
        int32_t jdatea() const { return m_jdatea; }

        /**
         * Date when the spectral run began. Stored as integer*4 Julian Day number *10
         */
        int32_t jdateb() const { return m_jdateb; }

        /**
         * Siderial time when the spectral run started. See flag #05.
         */
        coarse_timestamp_t* istb() const { return m_istb.get(); }

        /**
         * Right ascension coordinates of an astronomical  object, or longitude on a planetary surface (integer*4 numbers in seconds *1000) (RA in RA seconds, Longitude in arc-seconds) See flag #06.
         */
        int32_t isra() const { return m_isra; }

        /**
         * Declination coordinates of an astronomical object, or latitude on a planetary surface (integer*4 number in arc-seconds *1000). See flag #06.
         */
        int32_t isdec() const { return m_isdec; }

        /**
         * Total number of channels in the spectrum (integer*4 value from 1 to 4852)
         */
        int32_t itchan() const { return m_itchan; }

        /**
         * The equivalent atmospheric thickness through which the observation was obtained (=1.0 overhead scaled: airmass*1000; integer*4).
         */
        int32_t irmas() const { return m_irmas; }

        /**
         * The number of independent spectral scans which were added to make the spectrum (integer*4 number).
         */
        int32_t revs() const { return m_revs; }

        /**
         * The channel numbers which define the band normalization (scaling to unity). (integers*4).
         */
        std::vector<int32_t>* iband() const { return m_iband.get(); }

        /**
         * The record number within the file where the wavelengths are found (integer*4).
         */
        int32_t irwav() const { return m_irwav; }

        /**
         * The record pointer to where the resolution can be found (or horizontal error bar) (integer*4).
         */
        int32_t irespt() const { return m_irespt; }

        /**
         * The record number within the file where the data is located (integer*4 number).
         */
        int32_t irecno() const { return m_irecno; }

        /**
         * Text data record pointer. This pointer points to a data record where additional text describing the data may be found.  (32 bit integer)
         */
        int32_t itpntr() const { return m_itpntr; }

        /**
         * The program automatic 60 character history.
         */
        std::string ihist() const { return m_ihist; }

        /**
         * Manual history. Program automatic for large history requirements.
         */
        std::vector<std::string>* mhist() const { return m_mhist.get(); }

        /**
         * The number of independent spectral runs which were summed or averaged to make this spectrum (integer*4).
         */
        int32_t nruns() const { return m_nruns; }

        /**
         * The angle of incidence of illuminating radiation
         *       integrating sphere = 2000000000
         *       Geometric albedo   = 2000000001
         */
        illum_angle_t* siangl() const { return m_siangl.get(); }

        /**
         * The angle of emission of illuminating radiation
         *       integrating sphere = 2000000000
         *       Geometric albedo   = 2000000001
         */
        illum_angle_t* seangl() const { return m_seangl.get(); }

        /**
         * The phase angle between iangl and eangl (Integer*4 number, in arc-seconds*1500). (180 degrees=972000000; -180 deg <= phase <= 180 deg)
         *       integrating sphere = 2000000000
         */
        int32_t sphase() const { return m_sphase; }

        /**
         * Weighted number of runs (the number of runs of the spectrum with the minimum runs which was used in processing this spectrum, integer*4).
         */
        int32_t iwtrns() const { return m_iwtrns; }

        /**
         * The time observed in the sample beam for each half chop in milliseconds (for chopping spectrometers only). (integer*4)
         */
        int32_t itimch() const { return m_itimch; }

        /**
         * The band normalization factor. For data scaled to 1.0, multiply by this number to recover photometric level (32 bit real number).
         */
        float xnrm() const { return m_xnrm; }

        /**
         * The time it takes to make one scan of the entire spectrum in seconds (32 bit real number).
         */
        float scatim() const { return m_scatim; }

        /**
         * Total integration time (usually=scatime * nruns) (32 bit real number).
         */
        float timint() const { return m_timint; }

        /**
         * Temperature in degrees Kelvin (32 bit real number).
         */
        float tempd() const { return m_tempd; }

        /**
         * The spectral data (256 channels of 32 bit real data numbers).
         */
        std::vector<float>* data() const { return m_data.get(); }
        specpr_t* _root() const { return m__root; }
        specpr_t::record_t* _parent() const { return m__parent; }
    };

    class coarse_timestamp_t : public kaitai::kstruct {

    public:

        coarse_timestamp_t(kaitai::kstream* p__io, specpr_t::data_initial_t* p__parent = nullptr, specpr_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~coarse_timestamp_t();

    private:
        bool f_seconds;
        double m_seconds;

    public:
        double seconds();

    private:
        int32_t m_scaled_seconds;
        specpr_t* m__root;
        specpr_t::data_initial_t* m__parent;

    public:
        int32_t scaled_seconds() const { return m_scaled_seconds; }
        specpr_t* _root() const { return m__root; }
        specpr_t::data_initial_t* _parent() const { return m__parent; }
    };

    /**
     * it is big endian
     */

    class icflag_t : public kaitai::kstruct {

    public:

        icflag_t(kaitai::kstream* p__io, specpr_t::record_t* p__parent = nullptr, specpr_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~icflag_t();

    private:
        bool f_type;
        record_type_t m_type;

    public:
        record_type_t type();

    private:
        uint64_t m_reserved;
        bool m_isctb_type;
        bool m_iscta_type;
        bool m_coordinate_mode;
        bool m_errors;
        bool m_text;
        bool m_continuation;
        specpr_t* m__root;
        specpr_t::record_t* m__parent;

    public:
        uint64_t reserved() const { return m_reserved; }

        /**
         * =0 ctb is civil time
         * =1 ctb is universal time
         */
        bool isctb_type() const { return m_isctb_type; }

        /**
         * =0 cta is civil time
         * =1 cta is universal time
         */
        bool iscta_type() const { return m_iscta_type; }

        /**
         * RA, Dec / Long., Lat flag
         * =0 the array "ira" and "idec" corresponds to the right ascension and declination of an astronomical object.
         * =1 the array "ira" and "idec" correspond to the longitude and latitude of a spot on a planetary surface.
         */
        bool coordinate_mode() const { return m_coordinate_mode; }

        /**
         * flag to indicate whether or not the data for the error bar (1 sigma standard deviation of the mean) is in the next record set. =0: no errors, =1: errors in next record set.
         */
        bool errors() const { return m_errors; }

        /**
         * =0 the data in the array "data" is data
         * =1 the data in the array "data" is ascii text as is most of the header info.
         */
        bool text() const { return m_text; }

        /**
         * =0 first record of a spectrum consists of: header then 256 data channels
         * =1 continuation data record consisting of:
         *   # bit flags followed by 1532 bytes of
         *   # real data (bit 1=0) (383 channels)
         *   # or 1532 bytes of text (bit 1=1).
         *   # A maximum of 12 continuation records
         *   # are allowed for a total of 4852
         *   # channels (limited by arrays of 4864)
         *   # or 19860 characters of text (bit 1=1).
         */
        bool continuation() const { return m_continuation; }
        specpr_t* _root() const { return m__root; }
        specpr_t::record_t* _parent() const { return m__parent; }
    };

    class data_continuation_t : public kaitai::kstruct {

    public:

        data_continuation_t(kaitai::kstream* p__io, specpr_t::record_t* p__parent = nullptr, specpr_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~data_continuation_t();

    private:
        std::unique_ptr<std::vector<float>> m_cdata;
        specpr_t* m__root;
        specpr_t::record_t* m__parent;

    public:

        /**
         * The continuation of the data values (383 channels of 32 bit real numbers).
         */
        std::vector<float>* cdata() const { return m_cdata.get(); }
        specpr_t* _root() const { return m__root; }
        specpr_t::record_t* _parent() const { return m__parent; }
    };

    class identifiers_t : public kaitai::kstruct {

    public:

        identifiers_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, specpr_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~identifiers_t();

    private:
        std::string m_ititle;
        std::string m_usernm;
        specpr_t* m__root;
        kaitai::kstruct* m__parent;

    public:

        /**
         * Title which describes the data
         */
        std::string ititle() const { return m_ititle; }

        /**
         * The name of the user who created the data record
         */
        std::string usernm() const { return m_usernm; }
        specpr_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };

    class illum_angle_t : public kaitai::kstruct {

    public:

        illum_angle_t(kaitai::kstream* p__io, specpr_t::data_initial_t* p__parent = nullptr, specpr_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~illum_angle_t();

    private:
        bool f_seconds_total;
        int32_t m_seconds_total;

    public:
        int32_t seconds_total();

    private:
        bool f_minutes_total;
        int32_t m_minutes_total;

    public:
        int32_t minutes_total();

    private:
        bool f_degrees_total;
        int32_t m_degrees_total;

    public:
        int32_t degrees_total();

    private:
        int32_t m_angl;
        specpr_t* m__root;
        specpr_t::data_initial_t* m__parent;

    public:

        /**
         * (Integer*4 number, in arc-seconds*6000). (90 degrees=1944000000; -90 deg <= angle <= 90 deg)
         */
        int32_t angl() const { return m_angl; }
        specpr_t* _root() const { return m__root; }
        specpr_t::data_initial_t* _parent() const { return m__parent; }
    };

    class text_initial_t : public kaitai::kstruct {

    public:

        text_initial_t(kaitai::kstream* p__io, specpr_t::record_t* p__parent = nullptr, specpr_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~text_initial_t();

    private:
        std::unique_ptr<identifiers_t> m_ids;
        uint32_t m_itxtpt;
        int32_t m_itxtch;
        std::string m_itext;
        specpr_t* m__root;
        specpr_t::record_t* m__parent;

    public:
        identifiers_t* ids() const { return m_ids.get(); }

        /**
         * Text data record pointer. This pointer points  to a data record where additional text may be may be found.
         */
        uint32_t itxtpt() const { return m_itxtpt; }

        /**
         * The number of text characters (maximum= 19860).
         */
        int32_t itxtch() const { return m_itxtch; }

        /**
         * 1476 characters of text.  Text has embedded newlines so the number of lines available is limited only by the number of characters available.
         */
        std::string itext() const { return m_itext; }
        specpr_t* _root() const { return m__root; }
        specpr_t::record_t* _parent() const { return m__parent; }
    };

    class record_t : public kaitai::kstruct {

    public:

        record_t(kaitai::kstream* p__io, specpr_t* p__parent = nullptr, specpr_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~record_t();

    private:
        std::unique_ptr<icflag_t> m_icflag;
        std::unique_ptr<kaitai::kstruct> m_content;
        bool n_content;

    public:
        bool _is_null_content() { content(); return n_content; };

    private:
        specpr_t* m__root;
        specpr_t* m__parent;
        std::string m__raw_content;
        std::unique_ptr<kaitai::kstream> m__io__raw_content;

    public:

        /**
         * Total number of bytes comprising the document.
         */
        icflag_t* icflag() const { return m_icflag.get(); }
        kaitai::kstruct* content() const { return m_content.get(); }
        specpr_t* _root() const { return m__root; }
        specpr_t* _parent() const { return m__parent; }
        std::string _raw_content() const { return m__raw_content; }
        kaitai::kstream* _io__raw_content() const { return m__io__raw_content.get(); }
    };

    class text_continuation_t : public kaitai::kstruct {

    public:

        text_continuation_t(kaitai::kstream* p__io, specpr_t::record_t* p__parent = nullptr, specpr_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~text_continuation_t();

    private:
        std::string m_tdata;
        specpr_t* m__root;
        specpr_t::record_t* m__parent;

    public:

        /**
         * 1532 characters of text.
         */
        std::string tdata() const { return m_tdata; }
        specpr_t* _root() const { return m__root; }
        specpr_t::record_t* _parent() const { return m__parent; }
    };

private:
    std::unique_ptr<std::vector<std::unique_ptr<record_t>>> m_records;
    specpr_t* m__root;
    kaitai::kstruct* m__parent;

public:
    std::vector<std::unique_ptr<record_t>>* records() const { return m_records.get(); }
    specpr_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

specpr.cpp

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "specpr.h"

specpr_t::specpr_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, specpr_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_records = nullptr;
    _read();
}

void specpr_t::_read() {
    m_records = std::unique_ptr<std::vector<std::unique_ptr<record_t>>>(new std::vector<std::unique_ptr<record_t>>());
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_records->push_back(std::move(std::unique_ptr<record_t>(new record_t(m__io, this, m__root))));
            i++;
        }
    }
}

specpr_t::~specpr_t() {
    _clean_up();
}

void specpr_t::_clean_up() {
}

specpr_t::data_initial_t::data_initial_t(kaitai::kstream* p__io, specpr_t::record_t* p__parent, specpr_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_ids = nullptr;
    m_iscta = nullptr;
    m_isctb = nullptr;
    m_istb = nullptr;
    m_iband = nullptr;
    m_mhist = nullptr;
    m_siangl = nullptr;
    m_seangl = nullptr;
    m_data = nullptr;
    f_phase_angle_arcsec = false;
    _read();
}

void specpr_t::data_initial_t::_read() {
    m_ids = std::unique_ptr<identifiers_t>(new identifiers_t(m__io, this, m__root));
    m_iscta = std::unique_ptr<coarse_timestamp_t>(new coarse_timestamp_t(m__io, this, m__root));
    m_isctb = std::unique_ptr<coarse_timestamp_t>(new coarse_timestamp_t(m__io, this, m__root));
    m_jdatea = m__io->read_s4be();
    m_jdateb = m__io->read_s4be();
    m_istb = std::unique_ptr<coarse_timestamp_t>(new coarse_timestamp_t(m__io, this, m__root));
    m_isra = m__io->read_s4be();
    m_isdec = m__io->read_s4be();
    m_itchan = m__io->read_s4be();
    m_irmas = m__io->read_s4be();
    m_revs = m__io->read_s4be();
    m_iband = std::unique_ptr<std::vector<int32_t>>(new std::vector<int32_t>());
    const int l_iband = 2;
    for (int i = 0; i < l_iband; i++) {
        m_iband->push_back(std::move(m__io->read_s4be()));
    }
    m_irwav = m__io->read_s4be();
    m_irespt = m__io->read_s4be();
    m_irecno = m__io->read_s4be();
    m_itpntr = m__io->read_s4be();
    m_ihist = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_strip_right(m__io->read_bytes(60), 32), std::string("ascii"));
    m_mhist = std::unique_ptr<std::vector<std::string>>(new std::vector<std::string>());
    const int l_mhist = 4;
    for (int i = 0; i < l_mhist; i++) {
        m_mhist->push_back(std::move(kaitai::kstream::bytes_to_str(m__io->read_bytes(74), std::string("ascii"))));
    }
    m_nruns = m__io->read_s4be();
    m_siangl = std::unique_ptr<illum_angle_t>(new illum_angle_t(m__io, this, m__root));
    m_seangl = std::unique_ptr<illum_angle_t>(new illum_angle_t(m__io, this, m__root));
    m_sphase = m__io->read_s4be();
    m_iwtrns = m__io->read_s4be();
    m_itimch = m__io->read_s4be();
    m_xnrm = m__io->read_f4be();
    m_scatim = m__io->read_f4be();
    m_timint = m__io->read_f4be();
    m_tempd = m__io->read_f4be();
    m_data = std::unique_ptr<std::vector<float>>(new std::vector<float>());
    const int l_data = 256;
    for (int i = 0; i < l_data; i++) {
        m_data->push_back(std::move(m__io->read_f4be()));
    }
}

specpr_t::data_initial_t::~data_initial_t() {
    _clean_up();
}

void specpr_t::data_initial_t::_clean_up() {
}

double specpr_t::data_initial_t::phase_angle_arcsec() {
    if (f_phase_angle_arcsec)
        return m_phase_angle_arcsec;
    m_phase_angle_arcsec = (sphase() / 1500);
    f_phase_angle_arcsec = true;
    return m_phase_angle_arcsec;
}

specpr_t::coarse_timestamp_t::coarse_timestamp_t(kaitai::kstream* p__io, specpr_t::data_initial_t* p__parent, specpr_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_seconds = false;
    _read();
}

void specpr_t::coarse_timestamp_t::_read() {
    m_scaled_seconds = m__io->read_s4be();
}

specpr_t::coarse_timestamp_t::~coarse_timestamp_t() {
    _clean_up();
}

void specpr_t::coarse_timestamp_t::_clean_up() {
}

double specpr_t::coarse_timestamp_t::seconds() {
    if (f_seconds)
        return m_seconds;
    m_seconds = (scaled_seconds() * 24000);
    f_seconds = true;
    return m_seconds;
}

specpr_t::icflag_t::icflag_t(kaitai::kstream* p__io, specpr_t::record_t* p__parent, specpr_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_type = false;
    _read();
}

void specpr_t::icflag_t::_read() {
    m_reserved = m__io->read_bits_int_be(26);
    m_isctb_type = m__io->read_bits_int_be(1);
    m_iscta_type = m__io->read_bits_int_be(1);
    m_coordinate_mode = m__io->read_bits_int_be(1);
    m_errors = m__io->read_bits_int_be(1);
    m_text = m__io->read_bits_int_be(1);
    m_continuation = m__io->read_bits_int_be(1);
}

specpr_t::icflag_t::~icflag_t() {
    _clean_up();
}

void specpr_t::icflag_t::_clean_up() {
}

specpr_t::record_type_t specpr_t::icflag_t::type() {
    if (f_type)
        return m_type;
    m_type = static_cast<specpr_t::record_type_t>(((((text()) ? 1 : 0) * 1) + (((continuation()) ? 1 : 0) * 2)));
    f_type = true;
    return m_type;
}

specpr_t::data_continuation_t::data_continuation_t(kaitai::kstream* p__io, specpr_t::record_t* p__parent, specpr_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_cdata = nullptr;
    _read();
}

void specpr_t::data_continuation_t::_read() {
    m_cdata = std::unique_ptr<std::vector<float>>(new std::vector<float>());
    const int l_cdata = 383;
    for (int i = 0; i < l_cdata; i++) {
        m_cdata->push_back(std::move(m__io->read_f4be()));
    }
}

specpr_t::data_continuation_t::~data_continuation_t() {
    _clean_up();
}

void specpr_t::data_continuation_t::_clean_up() {
}

specpr_t::identifiers_t::identifiers_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, specpr_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void specpr_t::identifiers_t::_read() {
    m_ititle = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_strip_right(m__io->read_bytes(40), 32), std::string("ascii"));
    m_usernm = kaitai::kstream::bytes_to_str(m__io->read_bytes(8), std::string("ascii"));
}

specpr_t::identifiers_t::~identifiers_t() {
    _clean_up();
}

void specpr_t::identifiers_t::_clean_up() {
}

specpr_t::illum_angle_t::illum_angle_t(kaitai::kstream* p__io, specpr_t::data_initial_t* p__parent, specpr_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_seconds_total = false;
    f_minutes_total = false;
    f_degrees_total = false;
    _read();
}

void specpr_t::illum_angle_t::_read() {
    m_angl = m__io->read_s4be();
}

specpr_t::illum_angle_t::~illum_angle_t() {
    _clean_up();
}

void specpr_t::illum_angle_t::_clean_up() {
}

int32_t specpr_t::illum_angle_t::seconds_total() {
    if (f_seconds_total)
        return m_seconds_total;
    m_seconds_total = (angl() / 6000);
    f_seconds_total = true;
    return m_seconds_total;
}

int32_t specpr_t::illum_angle_t::minutes_total() {
    if (f_minutes_total)
        return m_minutes_total;
    m_minutes_total = (seconds_total() / 60);
    f_minutes_total = true;
    return m_minutes_total;
}

int32_t specpr_t::illum_angle_t::degrees_total() {
    if (f_degrees_total)
        return m_degrees_total;
    m_degrees_total = (minutes_total() / 60);
    f_degrees_total = true;
    return m_degrees_total;
}

specpr_t::text_initial_t::text_initial_t(kaitai::kstream* p__io, specpr_t::record_t* p__parent, specpr_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_ids = nullptr;
    _read();
}

void specpr_t::text_initial_t::_read() {
    m_ids = std::unique_ptr<identifiers_t>(new identifiers_t(m__io, this, m__root));
    m_itxtpt = m__io->read_u4be();
    m_itxtch = m__io->read_s4be();
    m_itext = kaitai::kstream::bytes_to_str(m__io->read_bytes(1476), std::string("ascii"));
}

specpr_t::text_initial_t::~text_initial_t() {
    _clean_up();
}

void specpr_t::text_initial_t::_clean_up() {
}

specpr_t::record_t::record_t(kaitai::kstream* p__io, specpr_t* p__parent, specpr_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_icflag = nullptr;
    m__io__raw_content = nullptr;
    _read();
}

void specpr_t::record_t::_read() {
    m_icflag = std::unique_ptr<icflag_t>(new icflag_t(m__io, this, m__root));
    n_content = true;
    switch (icflag()->type()) {
    case specpr_t::RECORD_TYPE_DATA_INITIAL: {
        n_content = false;
        m__raw_content = m__io->read_bytes((1536 - 4));
        m__io__raw_content = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_content));
        m_content = std::unique_ptr<data_initial_t>(new data_initial_t(m__io__raw_content.get(), this, m__root));
        break;
    }
    case specpr_t::RECORD_TYPE_DATA_CONTINUATION: {
        n_content = false;
        m__raw_content = m__io->read_bytes((1536 - 4));
        m__io__raw_content = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_content));
        m_content = std::unique_ptr<data_continuation_t>(new data_continuation_t(m__io__raw_content.get(), this, m__root));
        break;
    }
    case specpr_t::RECORD_TYPE_TEXT_CONTINUATION: {
        n_content = false;
        m__raw_content = m__io->read_bytes((1536 - 4));
        m__io__raw_content = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_content));
        m_content = std::unique_ptr<text_continuation_t>(new text_continuation_t(m__io__raw_content.get(), this, m__root));
        break;
    }
    case specpr_t::RECORD_TYPE_TEXT_INITIAL: {
        n_content = false;
        m__raw_content = m__io->read_bytes((1536 - 4));
        m__io__raw_content = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_content));
        m_content = std::unique_ptr<text_initial_t>(new text_initial_t(m__io__raw_content.get(), this, m__root));
        break;
    }
    default: {
        m__raw_content = m__io->read_bytes((1536 - 4));
        break;
    }
    }
}

specpr_t::record_t::~record_t() {
    _clean_up();
}

void specpr_t::record_t::_clean_up() {
    if (!n_content) {
    }
}

specpr_t::text_continuation_t::text_continuation_t(kaitai::kstream* p__io, specpr_t::record_t* p__parent, specpr_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void specpr_t::text_continuation_t::_read() {
    m_tdata = kaitai::kstream::bytes_to_str(m__io->read_bytes(1532), std::string("ascii"));
}

specpr_t::text_continuation_t::~text_continuation_t() {
    _clean_up();
}

void specpr_t::text_continuation_t::_clean_up() {
}