-
Notifications
You must be signed in to change notification settings - Fork 0
/
DataFile.cpp
executable file
·451 lines (386 loc) · 10.2 KB
/
DataFile.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
/**
* @file DataFile.cpp
* @ingroup DataManagement
* @author Dominique Vaufreydaz, Grenoble Alpes University, Inria
* @copyright All right reserved.
*/
#include "DataFile.h"
#include <sys/stat.h>
#include <stdlib.h>
#include <algorithm>
using namespace MobileRGBD;
// static
bool DataFile::OpenCompressedVersionFirst = false; /*!< Say that we want to try to open compressed version first. Useful when data are over the network. Default, false. */
char DataFile::DropBuffer[DataFile::DropBufferSize]; /*!< Share 1 Mib buffer to drop data when seeking forward in pipes */
#if defined WIN32 || defined WIN64
// use 64 bits versions of ftell and fseek, make them POSIX compliant
#define ftello _ftelli64
#define fseeko _fseeki64
#else
// Check that we will use 64 bits of ftell and fseek
#if !defined _FILE_OFFSET_BITS || _FILE_OFFSET_BITS < 64
#error You must compile using a _FILE_OFFSET_BITS defined to 64 (-D _FILE_OFFSET_BITS=64)
#endif
#endif
/** @brief Check if a file exists
*
* @param FileName [in] File name.
* @return true if file actually exists
*/
bool DataFile::FileOrFolderExists( const char * FileName )
{
struct stat FileStat;
if ( FileName == nullptr )
{
return false;
}
if ( stat(FileName, &FileStat) == 0 )
{
// exists
return true;
}
return false;
}
/** @brief constructor. Set LogLevel and ShowInfos and call Init().
*/
DataFile::DataFile()
{
// By default, we have no pipe
IsPipe = false;
Pos = -1;
}
/** @brief Virtual destructor, always.
*/
DataFile::~DataFile()
{
Close();
}
/** @brief Open a file *always in binary mode*.
*
* @param Filename [in] The file name.
* @param eMode [in] The width of the video stream.
* @return true if the file version is opened.
*/
bool DataFile::InternalOpen( const char * Filename, int eMode /* = READ_MODE */ )
{
const char * ModeRead = "rb";
const char * ModeWrite = "wb";
// ( InternalFile == nullptr ) has been check in ::Open. We do not do it again here
// try to open file the usual way
if ( eMode == READ_MODE )
{
InternalFile = fopen(Filename, ModeRead);
}
else if ( eMode == WRITE_MODE )
{
InternalFile = fopen(Filename, ModeWrite);
}
else
{
Pos = -1;
return false;
}
if ( InternalFile != nullptr )
{
Pos = 0;
return true;
}
return false;
}
/** @brief Open a 7z version file *always in binary mode*.
*
* @param Filename [in] The file name (without .7z extension)
* @param eMode [in] The width of the video stream.
* @return true if the 7zip is opened.
*/
bool DataFile::InternalOpenCompressedVersion( const char * Filename, int eMode /* = READ_MODE */ )
{
// Initial conditions have been tested in ::Open (public function)
// InternalFile == nullptr
// Filename != nullptr
// Values have been set to:
// IsPipe = false
// Here, we can not manage to open file for writing, we do not try it compressed
if ( eMode != READ_MODE )
{
// TODO: add support for output compression
Pos = -1;
return false;
}
// Generate new file name with '.7z' extension
char NewFileName[1024];
sprintf( NewFileName, "%s.7z", Filename );
return InternalOpenCompressed( NewFileName, eMode );
}
/** @brief Open a 7z file *always in binary mode*.
*
* @param Filename [in] The 7zip file name.
* @param eMode [in] The width of the video stream.
* @return true if the 7zip is opened.
*/
bool DataFile::InternalOpenCompressed( const char * Filename, int eMode /* = READ_MODE */ )
{
// Initial conditions have been tested in ::Open (public function)
// InternalFile == nullptr
// Filename != nullptr
// Values have been set to:
// IsPipe = false
Pos = -1;
// Here, we can not manage to open file for writing, we do not try it compressed
if ( eMode != READ_MODE )
{
// TODO: add support for output compression
return false;
}
// Try to open a 7z compressed version of the file
char _7zPipedCommand[1024];
// If there is a 7zip version of the file,
// generate a pipe command to open it
#if defined WIN32 || defined WIN64
if ( FileOrFolderExists( Filename ) == false )
{
return false;
}
sprintf( _7zPipedCommand, "7z e -so \"%s\" 2> %s", Filename, NULL_OUTPUT );
#else
char resolved_path[1024];
realpath( Filename, resolved_path);
if ( FileOrFolderExists( resolved_path ) == false )
{
return false;
}
sprintf( _7zPipedCommand, "7z e -so \"%s\"", resolved_path );
#endif
// Store pipe command to reopen it if we want to rewind
CompressedFileName = Filename;
// Try to the open the pipe
if ( Pipe::Open( _7zPipedCommand, Pipe::READ_MODE ) == true )
{
IsPipe = true;
Pos = 0;
return true;
}
// Could not open file
return false;
}
/** @brief Open a file *always in binary mode* (why convertir \r\n as \n is enough, even on Windows (not in
* some strange app anyway). If reading is asked and the file could not be opened,
* try to open a 7zip version of the file using 7z.
*
* @param Filename [in] The file name.
* @param eMode [in] The width of the video stream.
* @return true if the file or its 7z version is opened.
*/
bool DataFile::Open( const char *Filename, int eMode /* = READ_MODE */ )
{
// prior checks
if ( InternalFile != nullptr )
{
fprintf( stderr, "Could not reopen file, please call DataFile::Close() before.\n" );
return false;
}
if ( Filename == nullptr )
{
fprintf( stderr, "File name is null.\n" );
return false;
}
// By default it is not a pipe
IsPipe = false;
if ( OpenCompressedVersionFirst == true )
{
// Ok, try to open first the compressed version
if ( InternalOpenCompressedVersion( Filename, eMode ) == true )
{
return true;
}
// ok, open it usualy
return InternalOpen( Filename, eMode );
}
// Here, we try first usual file
if ( InternalOpen( Filename, eMode ) == true )
{
return true;
}
// ok, try to open it in its compressed version
return InternalOpenCompressedVersion( Filename, eMode );
}
/** @brief Read bytes from a the file (or pipe). Identical to fread.
*
* @param ptr [in,out] Pointer to buffer.
* @param size [in] Size of element to read.
* @param nmemb [in] Number ot element to read.
* @return Number of element read.
*/
size_t DataFile::Read( void *ptr, size_t size, size_t nmemb )
{
size_t RetCode = (size_t)0;
if ( InternalFile != nullptr )
{
RetCode = fread( ptr, size, nmemb, InternalFile );
// Compile new pos value
Pos += (int64_t)size*(int64_t)RetCode;
// DWORD err = GetLastError();
}
return RetCode;
}
/** @brief Write bytes to a the file (or pipe). Identical to fwrite.
*
* @param ptr [in] Pointer to buffer.
* @param size [in] Size of element to read.
* @param nmemb [in] Number ot element to write.
* @return Number of elements written.
*/
size_t DataFile::Write(const void *ptr, size_t size, size_t nmemb )
{
size_t RetCode = (size_t)0;
if ( InternalFile != nullptr )
{
RetCode = fwrite( ptr, size, nmemb, InternalFile );
// Compile new pos value
Pos += (int64_t)size*(int64_t)RetCode;
}
return (size_t)0;
}
/** @brief Close file (or pipe). Identical to fclose/pclose.
*
*/
int DataFile::Close()
{
int RetCode = 0;
if ( InternalFile != nullptr )
{
if ( IsPipe == false )
{
// Usual file
RetCode = fclose(InternalFile);
InternalFile = nullptr;
}
else
{
Pipe::Close();
}
IsPipe = false;
}
return RetCode;
}
/** @brief Write bytes to a the file (or pipe). Identical to fseek.
*
* @param offset [in] Number of offset bytes.
* @param whence [in] Origine of the offset (see fseek).
* @return error code, same as fseek.
*/
int DataFile::Seek(int64_t offset, int whence)
{
if ( InternalFile == nullptr )
{
// Could not seek
return -1;
}
// Specific case for Pipe
if ( IsPipe == false )
{
// usual case, usual file, call the seek function
return fseeko( InternalFile, offset, whence );
}
// Here, we are using a pipe
switch(whence)
{
case SEEK_CUR:
// Compute position from here
offset += Pos;
// Continue in the SEEK_SET condition
case SEEK_SET:
if ( offset < Pos )
{
// Could not seek backward in pipe
return EBADF;
}
// Loop to greedily eat data coming from the pipe as we can not seek
while( Pos < offset )
{
// Read at max DropBufferSize
int NbToRead = std::min( (int)DropBufferSize, (int)(offset-Pos) );
// Can we read?
int NbRead = (int)fread( DropBuffer, NbToRead, 1, InternalFile );
if ( NbRead == 0 )
{
// Could not seek
return EBADF;
}
// Yes, increase Pos
Pos += (int64_t)NbRead*(int64_t)NbToRead;
}
return 0;
case SEEK_END: // Could not seek from end with pipe
return EBADF;
default:
return EINVAL;
}
}
/** @brief Get position in the current file/pipe.
*
*/
int64_t DataFile::Tell()
{
if ( InternalFile == nullptr )
{
// Could not tell
return -1;
}
// Return current pos file
return Pos;
}
/** @brief Restart file at beginning.
*
*/
void DataFile::Rewind()
{
if ( InternalFile == nullptr )
{
// Could not ftell
return;
}
// In case of a pipe
if ( IsPipe == true )
{
// Close the pipe
Close();
if ( CompressedFileName.length() == 0 )
{
// impossible to rewind
return;
}
// Reopen the pipe
InternalOpenCompressed( CompressedFileName.c_str() );
return;
}
return rewind(InternalFile);
}
/** @brief Retrieve current position in a file/pipe as a fpos_t_ structure (identical to fgetpos).
*
* @param pos [in,out] pointer to a fpos_t structure to fill.
* @return error code, same as fgetpos.
*/
int DataFile::GetPos(fpos_t *pos)
{
if ( InternalFile == nullptr )
{
// Could not fgetpos
return -1;
}
return fgetpos(InternalFile, pos);
}
/** @brief Retrieve current position in a file/pipe as a fpos_t_ structure (identical to fsetpos).
*
* @param pos [in] pointer to a fpos_t structure to use to set current pos in file/pipe.
* @return error code, same as fsetpos.
*/
int DataFile::SetPos(fpos_t *pos)
{
if ( InternalFile == nullptr || IsPipe == true )
{
// Could not fsetpos
return -1;
}
return fsetpos( InternalFile, pos );
}