#ifndef TDM_RIPPER #define TDM_RIPPER #include #include #include #include #include #include #include #include #include #include "../pugixml/pugixml.hpp" class tdm_ripper { // .tdm and .tdx filenames std::string tdmfile_; std::string tdxfile_; // endianness (true = little, false = big) bool endianness_, machine_endianness_; // number/names/ids of channels, channelgroups and channels's assignment to groups int num_channels_, num_groups_; std::vector channel_id_, inc_id_, units_, channel_name_; std::vector group_id_, group_name_; std::vector num_channels_group_; std::vector channels_group_; std::vector channel_ext_; // evtl. get group time_stamp of .tdm file in the unix format, i.e. #seconds since 01.01.0000 with average year having 365+97/400 = 365.2425 days // minimum/maximum value in particular channel (is provided in .tdm file as float) std::vector> minmax_; // use xpointers and ids to assign channels to byteoffsets std::map xml_local_columns_, xml_values_, xml_double_sequence_; // byteoffset, length and datatype of channels std::vector byteoffset_; std::vector length_; std::vector type_; std::vector external_id_; // mapping of NI datatype to size (in bytes) of type std::map datatypes_; // xml parser pugi::xml_document xml_doc_; pugi::xml_parse_result xml_result_; // binary data container std::vector tdxbuf_; public: tdm_ripper(std::string tdmfile, std::string tdxfile = ""); void parse_structure(); void list_channels(std::ostream& gout = std::cout, int width = 15, int maxshow = 50); void list_groups(std::ostream& gout = std::cout, int width = 15, int maxshow = 50); void show_structure(); // count number of occurences of substring in string int count_occ_string(std::string s, std::string sub) { int num_occs = 0; std::string::size_type pos = 0; while ( ( pos = s.find(sub,pos) ) != std::string::npos ) { num_occs++; pos += sub.length(); } return num_occs; } // obtain substring of 'entirestr' in between starting and stopping delimiter std::string get_str_between(std::string entirestr, std::string startlim, std::string stoplim) { std::size_t apos = entirestr.find(startlim); std::size_t bpos = entirestr.find_last_of(stoplim); assert( apos != std::string::npos && bpos != std::string::npos ); return entirestr.substr(apos+startlim.length(),bpos-(apos+startlim.length())); } void print_hash_local(const char* filename, int width = 20) { std::ofstream fout(filename); std::map::iterator it; int count = 0; for ( it = xml_local_columns_.begin(); it != xml_local_columns_.end(); it++ ) { count++; fout<first; fout<second; fout<<"\n"; } fout.close(); } void print_hash_values(const char* filename, int width = 20) { std::ofstream fout(filename); std::map::iterator it; int count = 0; for ( it = xml_values_.begin(); it != xml_values_.end(); it++ ) { count++; fout<first; fout<second; fout<<"\n"; } fout.close(); } void print_hash_double(const char* filename, int width = 20) { std::ofstream fout(filename); std::map::iterator it; int count = 0; for ( it = xml_double_sequence_.begin(); it != xml_double_sequence_.end(); it++ ) { count++; fout<first; fout<second; fout<<"\n"; } fout.close(); } // provide number of channels and group const int& num_channels() { return num_channels_; } const int& num_groups() { return num_groups_; } // get number of channels in specific group const int& no_channels(int groupid) { assert( groupid > 0 && groupid <= num_groups_ ); return num_channels_group_[groupid-1]; } const std::string& channel_name(int channelid) { assert( channelid > 0 && channelid <= num_channels_ ); return channel_name_[channelid-1]; } // obtain overall channel id from combined group and group-specific channel id int obtain_channel_id(int groupid, int channelid) { assert( groupid > 0 && groupid <= num_groups_ ); assert( channelid > 0 && channelid <= num_channels_group_[groupid-1] ); // find cummulative number of channels int numsum = 0; for ( int i = 0; i < groupid-1; i++ ) { numsum += num_channels_group_[i]; } assert( (numsum + channelid) > 0 && (numsum + channelid) <= num_channels_ ); return numsum+channelid; } const std::string& channel_name(int groupid, int channelid) { return channel_name_[obtain_channel_id(groupid,channelid)-1]; } const std::string& group_name(int groupid) { assert( groupid > 0 && groupid <= num_channels_ ); return group_name_[groupid-1]; } const std::string& channel_unit(int groupid, int channelid) { return units_[obtain_channel_id(groupid,channelid)-1]; } void list_datatypes(); // convert array of chars to single integer or floating point double int convert_int(std::vector bych); double convert_double(std::vector bych); // disassemble single integer or double into array of chars std::vector convert_int(int number); std::vector convert_double(double number); // convert entire channel, i.e. expert of .tdx binary file // std::vector convert_channel(int byteoffset, int length, int typesize); std::vector convert_channel(int channelid); // obtain channel from overall channel id... std::vector get_channel(int channelid); // ...or from group id and group-specific channel id std::vector channel(int groupid, int channelid) { return get_channel(obtain_channel_id(groupid,channelid)); } void print_channel(int channelid, const char* filename, int width = 15); // TODO add elements/methods to build .tdm and write .tdx files for your own data // by constructing xml document tree and write data to binary .tdx // void set_channels(std::vector channels); // void set_groups(std::vector groups); // void set_assigment(std::vector assignment); // void set_channel(int i, std::vector data); }; #endif