Pottu
TDRFile.hpp
Go to the documentation of this file.
1 
7 #ifndef H_POTTU_TDRFILE
8 #define H_POTTU_TDRFILE
9 
10 
11 #include "ebyedataheader.hpp"
12 #include "dataitem.hpp"
13 
14 #include "GZFile.hpp"
15 
16 #include <zlib.h>
17 
18 #include <fmt/format.h>
19 
20 #include <string>
21 #include <cstdint>
22 #include <vector>
23 #include <cstdio>
24 
25 
26 namespace pottu {
27 
31  class TDRFile {
32  public:
33 
39  TDRFile( const std::string &path ) : _path(path) {}
40 
49  void open() {
50  if( _f.isOpen() )
51  return;
52  // Finding first the real file size
53  {
54  FILE *ftmp = fopen( _path.c_str(), "rb" );
55  if( !ftmp ) {
56  std::string errmsg = fmt::format( "TDRFile::open(): Couldn't open \'{}\'. Reason: {}",
57  _path, std::strerror(errno) );
58  throw std::runtime_error( errmsg );
59  }
60  off_t p = fseek( ftmp, 0, SEEK_END );
61  if( p < 0 ) {
62  std::string errmsg( std::strerror(errno) );
63  fclose( ftmp );
64  throw std::runtime_error( errmsg );
65  }
66  _filesize = ftell( ftmp );
67  fclose( ftmp );
68  }
69  _f.open( _path, "rb" );
70  _gzipped = _f.isZipped();
71  _findWordOrderingAndBlocksize();
72  _currentblock = 0;
73  }
74 
81  void close() {
82  _f.close();
83  }
84 
85 
91  size_t readBlock( uint8_t *buf ) {
92  /*
93  if( !_f.isOpen() )
94  throw std::runtime_error( "Cannot read. File is not open." );
95  if( _f.isEof() )
96  return 0;
97  int ret = _f.read( (char *)_blockbuf.data(), _blockbuf.size() );
98  if( ret != int(_blockbuf.size()) && ret != 0 )
99  throw std::runtime_error( "Immature end of file or failure in reading" );
100  else {
101  ++_currentblock;
102  _lastheader = ebyedataheader_t::createFromMemory( (const char *)_blockbuf.data() );
103  if( _lastheader.dataLen )
104  std::memcpy( buf, _blockbuf.data()+24, _lastheader.dataLen );
105  return _lastheader.dataLen;
106  }
107  */
108  if( !_f.isOpen() )
109  throw std::runtime_error( "Cannot read. File is not open." );
110  if( _f.isEof() )
111  return 0;
112  int ret = _f.read( (char *)buf, _blocksize );
113  if( ret == 0 && _f.isEof() )
114  return 0;
115  else if( ret == int(_blocksize) ) {
116  ++_currentblock;
117  _lastheader = ebyedataheader_t::createFromMemory( (const char *)buf );
118  return _lastheader.dataLen;
119  } else
120  throw std::runtime_error( "Immature end of file or failure in reading" );
121  }
122 
123  const GZFile &getGZFile() const noexcept { return _f; }
124 
125  bool isOpen() const noexcept { return _f.isOpen(); }
126  bool isEof() const noexcept { return _f.isEof(); }
127 
128  bool isZipped() const noexcept { return _gzipped; }
129  bool isWordSwapRequired() const noexcept { return _wordSwapRequired; }
130  uint32_t getBlocksize() const noexcept { return _blocksize; }
131  int64_t getFilesize() const noexcept { return _filesize; }
132 
133  const std::string &getPath() const noexcept { return _path; }
134 
135  const ebyedataheader_t &getLastHeader() const noexcept { return _lastheader; }
136 
137  private:
138 
139 
140  void _findWordOrderingAndBlocksize() {
141  // Assumes that we are at the beginning of the file
142  char buf[24];
143  int readCount = _f.read( buf, 24 );
144  if( readCount != 24 )
145  throw std::runtime_error( "Failed to read the header." );
146  ebyedataheader_t header0 = ebyedataheader_t::createFromMemory( buf );
147  if( !header0.isValid() ) {
148  std::cerr << header0 << "\n";
149  throw std::runtime_error( "Header is not valid" );
150  }
151 
152  std::vector<dataitem_t> tmpdata;
153  tmpdata.resize( header0.dataLen / 8 ); // Resize to fit all the data in the first block here.
154  int bytesToRead = (header0.dataLen / 8) * 8;
155  readCount = _f.read( (char *)tmpdata.data(), bytesToRead );
156  if( readCount != bytesToRead )
157  throw std::runtime_error( "Failed to read the first block of data." );
158 
159  // Iterating through the data and counting the number of
160  // different recordtypes for both non swapped and swapped
161  // words.
162  unsigned noswap_rectypes[4] = {0};
163  unsigned swap_rectypes[4] = {0};
164  for( const auto &item : tmpdata ) {
165  ++noswap_rectypes[ static_cast<uint32_t>( item.getType() ) ];
166  ++swap_rectypes[ static_cast<uint32_t>( item.asSwapped().getType() ) ];
167  }
168  // The bits 60 & 61 defines the record type and are both
169  // zero only for tracedata. The bits 30 & 31 are zero for
170  // all items. Therefore, for wrong word order there should
171  // be only "tracedata" items in this block. I.e. The
172  // correct word ordering is with that one giving more
173  // other than tracedata items.
174  _wordSwapRequired = swap_rectypes[2] + swap_rectypes[3] > noswap_rectypes[2] + noswap_rectypes[3];
175 
176  uint32_t testblocksize = 1024;
177  while( testblocksize < (1<<20) ) {
178  testblocksize *= 2;
179  if( testblocksize < header0.dataLen )
180  // Blocksize cannot be smaller than the size of the data in first block...
181  continue;
182 
183  _f.seek( testblocksize );
184  // Reading the header
185  readCount = _f.read( buf, 24 );
186  if( readCount != 24 )
187  throw std::runtime_error( "Failed to read the header while guessing the blocksize." );
188  ebyedataheader_t h = ebyedataheader_t::createFromMemory( buf );
189 
190  // Did We found the next header?
191  if( h.isValid() )
192  break;
193  }
194  if( testblocksize >= (1<<20) )
195  throw std::runtime_error( "Failed to find the blocksize." );
196 
197  _blocksize = testblocksize;
198 
199  // Seeking back to beginning
200  _f.seek( 0 );
201 
202  _blockbuf.resize( _blocksize );
203  }
204 
205 
206  std::string _path;
207  uint32_t _blocksize{0};
208  int64_t _filesize{-1};
209  bool _gzipped;
210  bool _wordSwapRequired{false};
211  GZFile _f;
212  uint32_t _currentblock{0};
213 
214  ebyedataheader_t _lastheader;
215  std::vector<uint8_t> _blockbuf;
216  };
217 
218 
219 }
220 
221 
222 #endif
Definition: GZFile.hpp:21
int read(char *buf, unsigned int size)
Reads data from the file to a buffer.
Definition: GZFile.hpp:87
bool isOpen() const noexcept
Checks if file is open.
Definition: GZFile.hpp:112
void seek(size_t position)
Seeks the file position.
Definition: GZFile.hpp:102
bool isZipped() const noexcept
Tells whether the file is zipped.
Definition: GZFile.hpp:118
Readonly access to a tdr file with some helpers.
Definition: TDRFile.hpp:31
void close()
Closes the file.
Definition: TDRFile.hpp:81
void open()
Opens the file and sets file information.
Definition: TDRFile.hpp:49
size_t readBlock(uint8_t *buf)
Reads next block.
Definition: TDRFile.hpp:91
TDRFile(const std::string &path)
Sets the filename.
Definition: TDRFile.hpp:39
Defines the raw low level dataitems used in tdr datastreams and files.
Definition: mainpage.dox:6
static ebyedataheader_t createFromMemory(const char *p) noexcept
Creates ebyedataheader_t from a memory buffer.
Definition: ebyedataheader.hpp:40