Fawkes API Fawkes Development Version
fvfile.cpp
1
2/***************************************************************************
3 * fvfile.cpp - FireVision file
4 *
5 * Created: Fri Mar 28 11:45:47 2008
6 * Copyright 2008 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22 */
23
24#include <core/exceptions/system.h>
25#include <fvutils/fileformat/fvfile.h>
26#include <netinet/in.h>
27#include <sys/time.h>
28#include <utils/misc/strndup.h>
29
30#include <cerrno>
31#include <cstdio>
32#include <cstring>
33
34using namespace fawkes;
35
36namespace firevision {
37
38/** @class FireVisionDataFile <fvutils/fileformat/fvff.h>
39 * FireVision File Format for data files.
40 * The FireVision File Format (FVFF) defines a generic file layout that is used
41 * to store large chunks of data on the the disk drive in a byte efficient way.
42 *
43 * It is meant to serve as a skeleton which is used by subclasses to implement
44 * support for a concrete file format like colormaps or rectification information.
45 * It allows for arbitrary meta data to be added that is relevant to the format and
46 * it provides all the generic meta data that is needed to make the file format
47 * work and that is common to all formats.
48 *
49 * Each format has a two byte magic token. In general it is of the form FFNN, where
50 * FF stays literally (FireVision File) and NN is replaced with a number of the format.
51 * Currently assigned format numbers include:
52 * - FF01: colormaps
53 * - FF02: generic lookup tables
54 * - FF03: rectification information
55 * - FF04: histograms
56 *
57 * We assume large chunks of data that is saved most efficiently in a proprietary
58 * binary format that can be read and written quickly and mimics the layout of the
59 * file in the memory.
60 *
61 * The general layout is:
62 * @code
63 * 1. General header (file type, version, endianess, number of blocks, etc.)
64 * 2. Content type specific header (optional)
65 * 3. Data blocks
66 * @endcode
67 * Each of the data blocks itself is of the following form:
68 * @code
69 * 1. General block header (type, size)
70 * 2. Content type specific block header (optional)
71 * 3. Data chunk (raw byte stream, content-specific)
72 * @endcode
73 *
74 * @author Tim Niemueller
75 */
76
77/** @var void * FireVisionDataFile::_spec_header
78 * Content specific header.
79 * Create this buffer and set the size in _spec_header_size to get it written to
80 * the file.
81 */
82/** @var size_t FireVisionDataFile::_spec_header_size
83 * Size in bytes of _spec_header.
84 */
85
86/** Constructor.
87 * @param magic_token magic token for the concrete file type
88 * @param version file format version
89 */
90FireVisionDataFile::FireVisionDataFile(unsigned short int magic_token, unsigned short int version)
91{
92 header_ = (fvff_header_t *)calloc(1, sizeof(fvff_header_t));
93
94 magic_token_ = magic_token;
95 version_ = version;
96 comment_ = strdup("");
97
98 _spec_header = NULL;
100
101 owns_blocks_ = true;
102
104}
105
106/** Destructor. */
108{
110
111 free(header_);
112 free(comment_);
113 if (_spec_header) {
114 free(_spec_header);
115 }
116}
117
118/** Clear internal storage.
119 * All internal data is deleted.
120 */
121void
123{
124 if (owns_blocks_) {
125 for (bi_ = blocks_.begin(); bi_ != blocks_.end(); ++bi_) {
126 delete *bi_;
127 }
128 }
129
130 blocks_.clear();
131 memset(header_, 0, sizeof(fvff_header_t));
132
133 header_->magic_token = htons(magic_token_);
134 header_->version = version_;
135 header_->num_blocks = 0;
136#if BYTE_ORDER_ == BIG_ENDIAN_
137 header_->endianess = 1;
138#else
139 header_->endianess = 0;
140#endif
141 free(comment_);
142 comment_ = strdup("");
143}
144
145/** Get the magic token of the file.
146 * @return Magic token
147 */
148unsigned int
150{
151 return header_->magic_token;
152}
153
154/** Get the version of the file.
155 * @return version of the file (or the current supported version if no file was loaded)
156 */
157unsigned int
159{
160 return header_->version;
161}
162
163/** Check if data is encoded as big endian.
164 * @return true if data is encoded as big endian, false otherwise
165 */
166bool
168{
169 return (header_->endianess == 1);
170}
171
172/** Check if data is encoded as little endian.
173 * @return true if data is encoded as little endian, false otherwise
174 */
175bool
177{
178 return (header_->endianess == 0);
179}
180
181/** Get comment.
182 * @return comment of the file
183 */
184const char *
186{
187 return comment_;
188}
189
190/** Set comment.
191 * @param comment new comment to set
192 */
193void
195{
196 free(comment_);
197 comment_ = strndup(comment, FVFF_COMMENT_SIZE);
198 strncpy(header_->comment, comment, FVFF_COMMENT_SIZE - 1);
199}
200
201/** Lets the file take over the ownership and give up the ownership of the blocks,
202 * respectively. By default, the file is the owner of the blocks. If a file owns
203 * the blocks they will be deleted in the files destructor.
204 * @param owns_blocks if true file owns the blocks
205 */
206void
208{
209 owns_blocks_ = owns_blocks;
210}
211
212/** Get the number of available info blocks.
213 * @return number of available info blocks
214 */
215size_t
217{
218 return blocks_.size();
219}
220
221/** Add a block.
222 * @param block block to add
223 */
224void
226{
227 blocks_.push_back(block);
228}
229
230/** Get blocks.
231 * @return block list
232 */
235{
236 return blocks_;
237}
238
239/** Write file.
240 * @param file_name file to write to
241 */
242void
243FireVisionDataFile::write(const char *file_name)
244{
245 FILE *f = fopen(file_name, "w");
246 if (f == NULL) {
247 throw CouldNotOpenFileException(file_name,
248 errno,
249 "Could not open rectlut file "
250 "for writing");
251 }
252
253 header_->num_blocks = (unsigned int)blocks_.size();
254 timeval t;
255 gettimeofday(&t, NULL);
256 header_->created_sec = t.tv_sec;
257 header_->created_usec = t.tv_usec;
259
260 //printf("Writing %zu bytes for header\n", sizeof(fvff_header_t));
261 if (fwrite(header_, sizeof(fvff_header_t), 1, f) != 1) {
262 fclose(f);
263 throw FileWriteException(file_name, errno, "Writing fvff header failed");
264 }
265
266 if (_spec_header_size > 0) {
267 //printf("Writing %zu bytes for spec header\n", _spec_header_size);
268 if (fwrite(_spec_header, _spec_header_size, 1, f) != 1) {
269 fclose(f);
270 throw FileWriteException(file_name, errno, "Writing content specific header failed");
271 }
272 }
273
274 for (bi_ = blocks_.begin(); bi_ != blocks_.end(); ++bi_) {
275 // write this info block
276 //printf("Writing %zu bytes for block\n", (*bi_)->block_size());
277 if (fwrite((*bi_)->block_memptr(), (*bi_)->block_size(), 1, f) != 1) {
278 fclose(f);
279 throw FileWriteException(file_name, errno, "Failed to write info block");
280 }
281 }
282
283 fclose(f);
284}
285
286/** Read file.
287 * @param file_name file to read from
288 */
289void
290FireVisionDataFile::read(const char *file_name)
291{
292 FILE *f = fopen(file_name, "r");
293 if (f == NULL) {
294 throw CouldNotOpenFileException(file_name,
295 errno,
296 "Could not open rectlut file "
297 "for reading");
298 }
299
300 clear();
301
302 //printf("Reading %zu bytes for header\n", sizeof(fvff_header_t));
303 if (fread(header_, sizeof(fvff_header_t), 1, f) != 1) {
304 fclose(f);
305 throw FileReadException(file_name, errno, "Reading header failed");
306 }
307
308 if (header_->magic_token != htons(magic_token_)) {
309 fclose(f);
310 throw Exception("Unknown magic in fvff file (read: 0x%04x req: 0x%04x)",
311 header_->magic_token,
312 magic_token_);
313 }
314
315 if (header_->version != version_) {
316 fclose(f);
317 throw Exception("Unsupported version of fvff file (read: %u req: %u)",
318 header_->version,
319 version_);
320 }
321
322 if (header_->endianess ==
323#if BYTE_ORDER_ == BIG_ENDIAN_
324 0
325#else
326 1
327#endif
328 ) {
329 fclose(f);
330 throw Exception("FVFile header cannot be translated for endianess by now");
331 }
332
333 free(comment_);
334 comment_ = strndup(header_->comment, FVFF_COMMENT_SIZE);
335
336 if (_spec_header) {
337 free(_spec_header);
338 }
339 _spec_header = calloc(1, header_->spec_head_size);
340 if (!_spec_header) {
341 throw OutOfMemoryException("Cannot allocate memory for content specific header");
342 }
343
344 if (header_->spec_head_size > 0) {
345 //printf("Reading %u bytes for spec header\n", header_->spec_head_size);
346 if (fread(_spec_header, header_->spec_head_size, 1, f) != 1) {
347 fclose(f);
348 throw FileReadException(file_name, errno, "Reading content specific header failed");
349 }
350 }
351
352 //printf("Reading %u blocks\n", header_->num_blocks);
353 for (unsigned int b = 0; b < header_->num_blocks && !feof(f); ++b) {
355 //printf("Reading %zu bytes for block header\n", sizeof(bh));
356 if (fread(&bh, sizeof(bh), 1, f) != 1) {
357 fclose(f);
358 throw FileReadException(file_name,
359 errno,
360 "Could not read block info header while there should be one");
361 }
362 void *spec_header = NULL;
363
364 if (bh.spec_head_size > 0) {
365 // Read specific header
366 spec_header = malloc(bh.spec_head_size);
367 if (!spec_header) {
368 throw OutOfMemoryException("Could not allocate %u bytes for content specific header",
369 bh.spec_head_size);
370 }
371
372 //printf("Reading %u bytes for block spec header\n", bh.spec_head_size);
373 if (fread(spec_header, bh.spec_head_size, 1, f) != 1) {
374 fclose(f);
375 free(spec_header);
376 throw FileReadException(file_name, errno, "Could not read content specific block header");
377 }
378 }
379
381 new FireVisionDataFileBlock(bh.type, bh.size, spec_header, bh.spec_head_size);
382
383 free(spec_header);
384
385 //printf("Reading %u bytes for block data\n", bh.size);
386 if (bh.size && fread(block->data_ptr(), bh.size, 1, f) != 1) {
387 fclose(f);
388 delete block;
389 throw FileReadException(file_name, errno, "Could not read block data");
390 }
391
392 blocks_.push_back(block);
393 }
394
395 fclose(f);
396}
397
398/** Get magic token from file.
399 * @param filename name of file to read the magic token from
400 * @return magic token
401 */
402unsigned short int
404{
405 uint16_t magic_token = 0;
406
407 FILE *f;
408 f = fopen(filename, "r");
409 if (f != NULL) {
410 if (fread((char *)&magic_token, sizeof(magic_token), 1, f) != 1) {
411 fclose(f);
412 throw FileReadException(filename, errno, "Could not read magic token from file");
413 }
414 fclose(f);
415 } else {
416 throw FileReadException(filename, errno, "Could not read magic token from file");
417 }
418
419 return magic_token;
420}
421
422/** Check if file has a certain magic token.
423 * @param filename name of file to read the magic token from
424 * @param magic_token magic token to look for
425 * @return true if magic token was found, false otherwise
426 */
427bool
428FireVisionDataFile::has_magic_token(const char *filename, unsigned short int magic_token)
429{
430 uint16_t file_magic_token = read_magic_token(filename);
431 return (htons(magic_token) == file_magic_token);
432}
433
434} // end namespace firevision
File could not be opened.
Definition: system.h:53
Base class for exceptions in Fawkes.
Definition: exception.h:36
File could not be read.
Definition: system.h:62
Could not write to file.
Definition: system.h:69
System ran out of memory and desired operation could not be fulfilled.
Definition: system.h:32
FireVision File Format data block.
Definition: fvfile_block.h:34
void * data_ptr() const
Get data pointer.
unsigned int version()
Get the version of the file.
Definition: fvfile.cpp:158
virtual void read(const char *file_name)
Read file.
Definition: fvfile.cpp:290
void * _spec_header
Content specific header.
Definition: fvfile.h:66
unsigned int magic_token()
Get the magic token of the file.
Definition: fvfile.cpp:149
FireVisionDataFile(unsigned short int magic_token, unsigned short int version)
Constructor.
Definition: fvfile.cpp:90
virtual void clear()
Clear internal storage.
Definition: fvfile.cpp:122
size_t num_blocks()
Get the number of available info blocks.
Definition: fvfile.cpp:216
bool is_little_endian()
Check if data is encoded as little endian.
Definition: fvfile.cpp:176
size_t _spec_header_size
Size in bytes of _spec_header.
Definition: fvfile.h:67
static unsigned short int read_magic_token(const char *filename)
Get magic token from file.
Definition: fvfile.cpp:403
void set_comment(const char *comment)
Set comment.
Definition: fvfile.cpp:194
virtual void add_block(FireVisionDataFileBlock *block)
Add a block.
Definition: fvfile.cpp:225
std::list< FireVisionDataFileBlock * > BlockList
List of FireVision data file blocks.
Definition: fvfile.h:62
const char * get_comment() const
Get comment.
Definition: fvfile.cpp:185
static bool has_magic_token(const char *filename, unsigned short int magic_token)
Check if file has a certain magic token.
Definition: fvfile.cpp:428
bool is_big_endian()
Check if data is encoded as big endian.
Definition: fvfile.cpp:167
virtual void write(const char *file_name)
Write file.
Definition: fvfile.cpp:243
void set_owns_blocks(bool owns_blocks)
Lets the file take over the ownership and give up the ownership of the blocks, respectively.
Definition: fvfile.cpp:207
BlockList & blocks()
Get blocks.
Definition: fvfile.cpp:234
virtual ~FireVisionDataFile()
Destructor.
Definition: fvfile.cpp:107
Fawkes library namespace.
uint32_t type
The type of the block, content-specific.
Definition: fvff.h:75
uint32_t spec_head_size
the size of the following content specific block header
Definition: fvff.h:77
uint32_t size
size in bytes of this block, does not include any headers
Definition: fvff.h:76
Header for a FireVision file format file.
Definition: fvff.h:55
uint16_t num_blocks
number of rectification info blocks in this file
Definition: fvff.h:60
uint16_t version
version of the data file, this header defines version 1
Definition: fvff.h:57
uint64_t created_usec
creation unix timestamp, useconds
Definition: fvff.h:63
uint64_t created_sec
creation unix timestamp, seconds
Definition: fvff.h:62
uint16_t endianess
endianess of the file, 0 means little endian, 1 means big endian
Definition: fvff.h:58
uint32_t spec_head_size
data specific header size
Definition: fvff.h:61
uint16_t magic_token
magic token
Definition: fvff.h:56
char comment[FVFF_COMMENT_SIZE]
optional comment
Definition: fvff.h:64