GCC Code Coverage Report


Directory: ./
File: lib/geogram/basic/geofile.h
Date: 2026-09-07 02:36:43
Exec Total Coverage
Lines: 50 90 55.6%
Functions: 12 37 32.4%
Branches: 24 72 33.3%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #ifndef GEOGRAM_BASIC_GEOFILE
41 #define GEOGRAM_BASIC_GEOFILE
42
43 #include <geogram/basic/common.h>
44 #include <geogram/basic/numeric.h>
45 #include <geogram/basic/memory.h>
46 #include <geogram/basic/string.h>
47 #ifdef GEOGRAM_USE_BUILTIN_DEPS
48 #include <geogram/third_party/zlib/zlib.h>
49 #else
50 #include <zlib.h>
51 #endif
52
53 #include <stdexcept>
54 #include <fstream>
55 #include <map>
56
57
58 /**
59 * \file geogram/basic/geofile.h
60 * \brief Functions to read and write structured files
61 */
62
63 namespace GEO {
64
65 /**
66 * \brief GeoFile exception.
67 * \details This exception is thrown by GeoFile functions
68 * whenever a file cannot be written or read.
69 */
70 class GEOGRAM_API GeoFileException : public std::logic_error {
71 public:
72 /**
73 * \brief GeoFileException constructor
74 * \param[in] s a const reference to the message to be
75 * memorized in the exception.
76 */
77 GeoFileException(const std::string& s) : logic_error(s) {
78 }
79
80 /**
81 * \brief GeoFileException copy constructor.
82 * \param[in] rhs a const reference to the GeoFileException to be
83 * copied.
84 */
85 GeoFileException(const GeoFileException& rhs) : logic_error(rhs) {
86 }
87
88 /**
89 * \brief GeoFileException destructor.
90 */
91 ~GeoFileException() GEO_NOEXCEPT override;
92 };
93
94 /**************************************************************/
95
96 /**
97 * \brief Reads an ASCII attribute from a file.
98 * \param[in] file the input file, obtained through fopen()
99 * \param[out] base_addr an array with sufficient space for
100 * storing nb_elements of type \p T
101 * \param[in] nb_elements the number of elements to be read
102 * \retval true on success
103 * \retval false otherwise
104 * \tparam T the type of the elements to be read
105 */
106 8 template <class T> inline bool read_ascii_attribute(
107 FILE* file, Memory::pointer base_addr, index_t nb_elements
108 ) {
109 8 T* attrib = reinterpret_cast<T*>(base_addr);
110
3/4
✓ Branch 1 taken 276 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 276 times.
✓ Branch 4 taken 4 times.
1112 for(index_t i=0; i<nb_elements; ++i) {
111 552 std::string buff;
112 int res;
113
3/4
✓ Branch 1 taken 1147 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 871 times.
✓ Branch 4 taken 276 times.
2294 while(char(res = fgetc(file)) != '\n') {
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 871 times.
1742 if(res == EOF) {
115 return false;
116 }
117
1/2
✓ Branch 1 taken 871 times.
✗ Branch 2 not taken.
1742 buff.push_back(char(res));
118 }
119
1/4
✗ Branch 2 not taken.
✓ Branch 3 taken 276 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
552 if(!String::from_string(buff.c_str(),attrib[i])) {
120 return false;
121 }
122 }
123 8 return true;
124 }
125
126 /**
127 * \brief Writes an ASCII attribute to a file.
128 * \param[in] file the output file, obtained through fopen()
129 * \param[in] base_addr an array with nb_elements of type \p T
130 * \param[in] nb_elements the number of elements to be written
131 * \retval true on success
132 * \retval false otherwise
133 * \tparam T the type of the elements to be written
134 */
135 8 template <class T> inline bool write_ascii_attribute(
136 FILE* file, Memory::const_pointer base_addr, index_t nb_elements
137 ) {
138 8 const T* attrib = reinterpret_cast<const T*>(base_addr);
139
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 4 times.
560 for(index_t i=0; i<nb_elements; ++i) {
140 552 if(
141
1/2
✓ Branch 2 taken 276 times.
✗ Branch 3 not taken.
552 fprintf(
142
2/4
✓ Branch 1 taken 276 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 276 times.
1104 file, "%s\n", String::to_string(attrib[i]).c_str()
143 552 ) == 0
144 ) {
145 return false;
146 }
147 }
148 8 return true;
149 }
150
151 /**
152 * \brief Reads an ASCII attribute from a file.
153 * \details Template specialization for char, needed because we
154 * want chars to appear as integers in ASCII files.
155 * \param[in] file the input file, obtained through fopen()
156 * \param[out] base_addr an array with sufficient space for
157 * storing nb_elements of type char
158 * \param[in] nb_elements the number of elements to be read
159 * \retval true on success
160 * \retval false otherwise
161 */
162 template <> inline bool read_ascii_attribute<char>(
163 FILE* file, Memory::pointer base_addr, index_t nb_elements
164 ) {
165 char* attrib = reinterpret_cast<char*>(base_addr);
166 for(index_t i=0; i<nb_elements; ++i) {
167 int val;
168 if(fscanf(file, "%d", &val) == 0) {
169 return false;
170 }
171 attrib[i] = char(val);
172 }
173 return true;
174 }
175
176 /**
177 * \brief Writes an ASCII attribute to a file.
178 * \details Template specialization for char, needed because we
179 * want chars to appear as integers in ASCII files.
180 * \param[in] file the output file, obtained through fopen()
181 * \param[in] base_addr an array with nb_elements of type char
182 * \param[in] nb_elements the number of elements to be written
183 * \retval true on success
184 * \retval false otherwise
185 */
186 template <> inline bool write_ascii_attribute<char>(
187 FILE* file, Memory::const_pointer base_addr, index_t nb_elements
188 ) {
189 const char* attrib = reinterpret_cast<const char*>(base_addr);
190 for(index_t i=0; i<nb_elements; ++i) {
191 if(fprintf(file, "%d\n", int(attrib[i])) == 0) {
192 return false;
193 }
194 }
195 return true;
196 }
197
198 /**
199 * \brief Reads an ASCII attribute from a file.
200 * \details Template specialization for bool.
201 * \param[in] file the input file, obtained through fopen()
202 * \param[out] base_addr an array with sufficient space for
203 * storing nb_elements of type bool (1 byte per element)
204 * \param[in] nb_elements the number of elements to be read
205 * \retval true on success
206 * \retval false otherwise
207 */
208 template <> inline bool read_ascii_attribute<bool>(
209 FILE* file, Memory::pointer base_addr, index_t nb_elements
210 ) {
211 char* attrib = reinterpret_cast<char*>(base_addr);
212 for(index_t i=0; i<nb_elements; ++i) {
213 int val;
214 if(fscanf(file, "%d", &val) == 0) {
215 return false;
216 }
217 attrib[i] = char(val);
218 }
219 return true;
220 }
221
222 /**
223 * \brief Writes an ASCII attribute to a file.
224 * \details Template specialization for bool.
225 * \param[in] file the output file, obtained through fopen()
226 * \param[in] base_addr an array with nb_elements of type bool
227 * (1 byte per element)
228 * \param[in] nb_elements the number of elements to be written
229 * \retval true on success
230 * \retval false otherwise
231 */
232 template <> inline bool write_ascii_attribute<bool>(
233 FILE* file, Memory::const_pointer base_addr, index_t nb_elements
234 ) {
235 const char* attrib = reinterpret_cast<const char*>(base_addr);
236 for(index_t i=0; i<nb_elements; ++i) {
237 if(fprintf(file, "%d\n", int(attrib[i])) == 0) {
238 return false;
239 }
240 }
241 return true;
242 }
243
244 /**************************************************************/
245
246 /**
247 * \brief Base class for reading or writing Geogram structured binary
248 * files.
249 * \details Geogram structured binary files are organized into "chunks",
250 * in a way inspired by the Interchange File Format (IFF), with
251 * several differences (GeoFile uses little endian and does not use
252 * the standard IFF chunks). Like in IFF, each chunk starts with a
253 * four characters code (FourCC) and its size in bytes, stored in
254 * a 4 bytes unsigned integer. This makes it possible to easily skip
255 * the chunks that are not needed / not understood by the software.
256 * In addition, structured binary files are (optionally)
257 * compressed, using ZLib. Structured files can also be saved/loaded in
258 * ASCII, human-readable form. Natively, GeoFile uses the following chunks:
259 * - CMNT (Comment): contains a string
260 * - CMDL (Command Line): contains a vector of string
261 * - EOFL (End of file): an end of file marker. Can be used to
262 * indicate the boundaries of multiple objects stored in the
263 * same file
264 * - HEAD (Geofile header): contains the string GEOGRAM and a
265 * version string
266 * - PSET (Property Set): a set of properties. For instance, in
267 * a mesh, each mesh element type (vertices, edges, facets...)
268 * corresponds to a property set.
269 * - PROP (Property): a property attached to Property Set.
270 * - SPTR (Separator): marks the boundaries between multiple objects
271 * stored in the same GeoFile
272 */
273 class GEOGRAM_API GeoFile {
274 public:
275
276 /**
277 * \brief The function pointer type for reading and writing attributes
278 * in ASCII files.
279 */
280 typedef bool (*AsciiAttributeReadSerializer)(
281 FILE* file, Memory::pointer base_address, index_t nb_elements
282 );
283
284 typedef bool (*AsciiAttributeWriteSerializer)(
285 FILE* file, Memory::const_pointer base_address, index_t nb_elements
286 );
287
288 /**
289 * \brief Declares a new attribute type that can be read from
290 * and written to ascii files.
291 * \param[in] type_name the C++ type name of the attribute
292 * \param[in] read the function pointer for reading an attribute
293 * \param[in] write the function pointer for writing an attribute
294 */
295 static void register_ascii_attribute_serializer(
296 const std::string& type_name,
297 AsciiAttributeReadSerializer read,
298 AsciiAttributeWriteSerializer write
299 );
300
301 /**
302 * \brief GeoFile constructor.
303 * \param[in] filename a const reference to the file name.
304 */
305 GeoFile(const std::string& filename);
306
307 /**
308 * \brief GeoFile destructor.
309 */
310 ~GeoFile();
311
312 /**
313 * \brief Tests whether this GeoFile is ascii.
314 * \details GeoFile can be ascii or binary. If file name
315 * ends with "_ascii", then GeoFile is ascii.
316 * \retval true if this GeoFile is ascii
317 * \retval false otherwise
318 */
319 bool is_ascii() const {
320 return ascii_;
321 }
322
323 /**
324 * \brief Tests whether this GeoFile is in GARGANTUA mode.
325 * \details In GARGANTUA mode, index_t is 64 bits wide, else it is 32 bits.
326 * geogram can be compiled in standard or GARGANTUA mode. When loading a
327 * GARGANTUA file in standard mode, each time an index_t is read, it is
328 * checked whether it fits in 32 bits. An exception is thrown if it is not
329 * the case.
330 * \retval true if this file is in GARGANTUA mode
331 * \retval false otherwise
332 */
333 bool gargantua_mode() const {
334 return gargantua_mode_;
335 }
336
337 /**
338 * \brief Gets the current chunk class.
339 * \return the current chunk class
340 */
341 const std::string& current_chunk_class() const {
342 return current_chunk_class_;
343 }
344
345 /**
346 * \brief Gets the size of the current chunk.
347 * \return the size of the current chunk, in bytes
348 */
349 size_t current_chunk_size() const {
350 return current_chunk_size_;
351 }
352
353 /**
354 * \brief Internal representation of attributes.
355 */
356 struct AttributeInfo {
357
358 /**
359 * \brief AttributeInfo constructor.
360 */
361 AttributeInfo() : element_size(0), dimension(0) {
362 }
363
364 /**
365 * \brief AttributeInfo constructor.
366 * \param[in] name_in name of the attribute
367 * \param[in] element_type_in C++ type of the elements, as a string
368 * \param[in] element_size_in size in bytes of an element
369 * \param[in] dimension_in number of elements per item
370 */
371 146 AttributeInfo(
372 const std::string& name_in,
373 const std::string& element_type_in,
374 size_t element_size_in,
375 index_t dimension_in
376 146 ) :
377 146 name(name_in),
378
1/2
✓ Branch 1 taken 146 times.
✗ Branch 2 not taken.
146 element_type(element_type_in),
379 146 element_size(element_size_in),
380 146 dimension(dimension_in) {
381 146 }
382
383
384 /**
385 * \brief Name of the attribute.
386 */
387 std::string name;
388
389 /**
390 * \brief A string with the name fo the C++ type
391 * of the elements.
392 */
393 std::string element_type;
394
395 /**
396 * \brief The size in bytes of each element.
397 */
398 size_t element_size;
399
400 /**
401 * \brief The number of elements per item.
402 */
403 index_t dimension;
404 };
405
406 /**
407 * \brief Internal representation of an attribute set.
408 */
409 struct AttributeSetInfo {
410
411 /**
412 * \brief AttributeSetInfo constructor.
413 */
414 142 AttributeSetInfo() : nb_items(0), skip(false) {
415 142 }
416
417 /**
418 * \brief AttributeSetInfo constructor.
419 * \param[in] name_in name of the attribute set
420 * \param[in] nb_items_in number of items in each attribute of the
421 * set
422 */
423 142 AttributeSetInfo(
424 const std::string& name_in,
425 index_t nb_items_in
426 142 ) :
427 142 name(name_in),
428 142 nb_items(nb_items_in),
429 142 skip(false) {
430 142 }
431
432 /**
433 * \brief Finds an AttributeInfo by name.
434 * \param[in] name_in a const reference to the name of the
435 * attribute
436 * \return a const pointer to the AttributeInfo or nullptr if there
437 * is no such attribute.
438 */
439 const AttributeInfo* find_attribute(
440 const std::string& name_in
441 ) const {
442 for(index_t i=0; i<attributes.size(); ++i) {
443 if(attributes[i].name == name_in) {
444 return &(attributes[i]);
445 }
446 }
447 return nullptr;
448 }
449
450 /**
451 * \brief Finds an AttributeInfo by name.
452 * \param[in] name_in a const reference to the name of the
453 * attribute
454 * \return a pointer to the AttributeInfo or nullptr if there
455 * is no such attribute.
456 */
457 155 AttributeInfo* find_attribute(const std::string& name_in) {
458
2/2
✓ Branch 1 taken 59 times.
✓ Branch 2 taken 146 times.
205 for(index_t i=0; i<attributes.size(); ++i) {
459
2/2
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 50 times.
59 if(attributes[i].name == name_in) {
460 9 return &(attributes[i]);
461 }
462 }
463 146 return nullptr;
464 }
465
466 /**
467 * \brief name of the attribute set.
468 */
469 std::string name;
470
471 /**
472 * \brief number of items in each attribute of the set.
473 */
474 index_t nb_items;
475
476 /**
477 * \brief the attributes of the set.
478 */
479 vector<AttributeInfo> attributes;
480
481 /**
482 * \brief if set, all attributes in the set are
483 * skipped when reading the file.
484 */
485 bool skip;
486 };
487
488 /**
489 * \brief Finds an attribute set by name.
490 * \param[in] name a const reference to the name of the attribute set
491 * \return a pointer to the AttributeSetInfo or nullptr if there is
492 * no such attribute set.
493 */
494 295 AttributeSetInfo* find_attribute_set(const std::string& name) {
495
1/2
✓ Branch 1 taken 295 times.
✗ Branch 2 not taken.
295 auto it = attribute_sets_.find(name);
496
2/2
✓ Branch 2 taken 142 times.
✓ Branch 3 taken 153 times.
295 if(it == attribute_sets_.end()) {
497 142 return nullptr;
498 }
499 153 return &(it->second);
500 }
501
502 /**
503 * \brief Finds an attribute set by name.
504 * \param[in] name a const reference to the name of the attribute set
505 * \return a const pointer to the AttributeSetInfo or nullptr if there is
506 * no such attribute set.
507 */
508 const AttributeSetInfo* find_attribute_set(
509 const std::string& name
510 ) const {
511 auto it = attribute_sets_.find(name);
512 if(it == attribute_sets_.end()) {
513 return nullptr;
514 }
515 return &(it->second);
516 }
517
518 /**
519 * \brief Reads an integer from the file.
520 * \details Checks that I/O was completed and throws a
521 * GeoFileException if the file is truncated. Reads
522 * 32 or 64 bits depending on whether geogram file is
523 * in GARGANTUA mode, and truncates or expands depending
524 * on current GARGANTUA mode. If file is in GARGANTUA mode
525 * and not current mode, check whether read integer fits in
526 * 32 bits and throws an exception if it is not the case.
527 * \return the read integer
528 */
529 index_t read_index_t();
530
531 /**
532 * \brief Writes an integer into the file.
533 * \details Checks that I/O was completed and throws a
534 * GeoFileException if the file is truncated. In Standard
535 * mode a 32-bits integer is written. In Gargantua
536 * mode a 64-bits integer is written.
537 * \param[in] x the integer
538 * \param[in] comment an optional comment string, written to
539 * ASCII geofiles
540 */
541 void write_index_t(index_t x, const char* comment = nullptr);
542
543 /**
544 * \brief Reads a 32-bit integer from the file.
545 * \details Checks that I/O was completed and throws a
546 * GeoFileException if the file is truncated.
547 * \return the read integer converted to index_t
548 */
549 index_t read_index_t_32();
550
551 /**
552 * \brief Writes a 32-bit integer into the file.
553 * \details Checks that I/O was completed and throws a
554 * GeoFileException if the file is truncated.
555 * \param[in] x the integer
556 * \param[in] comment an optional comment string, written to
557 * ASCII geofiles
558 */
559 void write_index_t_32(index_t x, const char* comment = nullptr);
560
561 /**
562 * \brief Reads a string from the file.
563 * \details Checks that I/O was completed and throws a
564 * GeoFileException if the file is truncated.
565 * \return the read string
566 */
567 std::string read_string();
568
569 /**
570 * \brief Writes a string into the file.
571 * \details Checks that I/O was completed and throws a
572 * GeoFileException if the file is truncated.
573 * \param[in] s a const reference to the string
574 * \param[in] comment an optional comment string, written to
575 * ASCII geofiles
576 */
577 void write_string(const std::string& s, const char* comment = nullptr);
578
579 /**
580 * \brief Reads an unsigned 64 bits integer from the file.
581 * \details Checks that I/O was completed and throws a
582 * GeoFileException if the file is truncated.
583 * \return the read integer
584 */
585 size_t read_size_t();
586
587 /**
588 * \brief Writes an unsigned 64 bits integer into the file.
589 * \details Checks that I/O was completed and throws a
590 * GeoFileException if the file is truncated.
591 * \param[in] x the integer
592 */
593 void write_size_t(size_t x);
594
595 /**
596 * \brief Reads a chunk class from the file.
597 * \details A chunk class is a 4 characters string.
598 * The function checks that I/O was completed and throws a
599 * GeoFileException if the file is truncated.
600 * \return A 4 characters string with the chunk class.
601 */
602 std::string read_chunk_class();
603
604 /**
605 * \brief Writes a chunk class into the file.
606 * \details A chunk class is a 4 characters string.
607 * The function checks that I/O was completed and throws a
608 * GeoFileException if the file is truncated.
609 * \param[in] chunk_class A 4 characters string with the chunk class.
610 * \pre chunk_class.length() == 4
611 */
612 void write_chunk_class(const std::string& chunk_class);
613
614 /**
615 * \brief Writes a string array into the file.
616 * \param[in] strings the string array, as a const reference to
617 * a vector of strings.
618 */
619 void write_string_array(const std::vector<std::string>& strings);
620
621 /**
622 * \brief Reads a string array from the file.
623 * \param[out] strings the read string array, as a reference to
624 * a vector of strings.
625 */
626 void read_string_array(std::vector<std::string>& strings);
627
628
629 /**
630 * \brief Gets the size in bytes used by a given string in
631 * the file.
632 * \details The file stored the length of the string in a 32
633 * bits integer plus all the characters of the string
634 * \return the size in bytes used to store the string in the
635 * file.
636 */
637 1975 size_t string_size(const std::string& s) const {
638 1975 return sizeof(Numeric::uint32) + s.length();
639 }
640
641 /**
642 * \brief Gets the size in bytes used by a given string array in
643 * the file.
644 * \return the size in bytes used to store the string array in the
645 * file.
646 */
647 size_t string_array_size(
648 const std::vector<std::string>& strings
649 ) const ;
650
651 /**
652 * \brief Reads a chunk header from the file.
653 */
654 void read_chunk_header();
655
656 /**
657 * \brief Writes a chunk header into the file.
658 * \param[in] chunk_class the chunk class
659 * \param[in] size the size in bytes of the data
660 * attached to the chunk.
661 * \details When reading the file, to skip the chunk,
662 * one calls fseek(file_, size, SEEK_CUR)
663 */
664 void write_chunk_header(
665 const std::string& chunk_class, size_t size
666 );
667
668 /**
669 * \brief Checks that the actual chunk size corresponds
670 * to the specified chunk size.
671 */
672 void check_chunk_size();
673
674 /**
675 * \brief Compares the zlib version declared in the header
676 * file with the zlib version obtained from the runtime,
677 * and outputs an error message if they differ.
678 */
679 void check_zlib_version();
680
681 /**
682 * \brief Clears all memorized information about attributes
683 * and attribute sets.
684 * \details This function is called whenever a separator is read.
685 */
686 void clear_attribute_maps();
687
688 protected:
689 std::string filename_;
690 gzFile file_;
691 bool ascii_;
692 FILE* ascii_file_;
693 std::string current_chunk_class_;
694 size_t current_chunk_size_;
695 size_t current_chunk_file_pos_;
696 std::map<std::string, AttributeSetInfo> attribute_sets_;
697
698 static std::map<std::string, AsciiAttributeReadSerializer>
699 ascii_attribute_read_;
700
701 static std::map<std::string, AsciiAttributeWriteSerializer>
702 ascii_attribute_write_;
703
704 /**
705 * \brief True if current file is in GARGANTUA mode
706 * \details In GARGANTUA mode, index_t has 64 bits
707 */
708 bool gargantua_mode_;
709
710 /** \brief True if reading a standard file in GARGANTUA mode */
711 bool convert_32_to_64_;
712
713 /** \brief True if reading a GARGANTUA file in standard mode */
714 bool convert_64_to_32_;
715 };
716
717 /**************************************************************/
718
719 /**
720 * \brief Used to read a structured binary file.
721 */
722 class GEOGRAM_API InputGeoFile : public GeoFile {
723 public:
724 /**
725 * \brief InputGeoFile constructor.
726 * \param[in] filename a const reference to the file name.
727 */
728 InputGeoFile(const std::string& filename);
729
730 /**
731 * \brief Advances to the next chunk.
732 * \return The read chunk class.
733 */
734 const std::string& next_chunk();
735
736 /**
737 * \brief Reads the latest attribute.
738 * \details This function can be only called right after next_chunk(),
739 * if it returned ATTRIBUTE.
740 */
741 void read_attribute(void* addr);
742
743
744 /**
745 * \brief Indicates that all the attributes attached to the
746 * latest attribute set should be skipped.
747 * \details This function can be only called right after next_chunk(),
748 * if it returned ATTRIBUTE_SET.
749 */
750 void skip_attribute_set();
751
752
753 /**
754 * \brief Gets the current attribute set.
755 * \return a const reference to the AttributeSetInfo that
756 * represents the current attribute set
757 * \pre current chunk class is either "ATTR" (ATTRIBUTE) or
758 * ATTS (ATTRIBUTE_SET)
759 */
760 23 const AttributeSetInfo& current_attribute_set() const {
761
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
23 geo_assert(current_attribute_set_ != nullptr);
762 23 return *current_attribute_set_;
763 }
764
765 /**
766 * \brief Gets the current attribute.
767 * \return a const reference to the AttributeInfo that
768 * represents the current attribute
769 * \pre current chunk class is "ATTR" (ATTRIBUTE)
770 */
771 29 const AttributeInfo& current_attribute() const {
772
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
29 geo_assert(current_attribute_ != nullptr);
773 29 return *current_attribute_;
774 }
775
776 /*
777 * \brief Gets the current user comment.
778 * \return a const reference to the current user comment
779 * \pre current chunk class is "CMNT" (COMMENT)
780 */
781 const std::string& current_comment() const {
782 geo_assert(current_chunk_class_ == "CMNT");
783 return current_comment_;
784 }
785
786
787 /**
788 * \brief Reads the command line from the file.
789 * \details It is useful to save the command line arguments in
790 * each file, so that one can retrieve the parameters of each
791 * experiments when doing algorithm test.
792 * \param[out] args the command line, as a vector of strings
793 * \pre current_chunk_class() == "CMDL"
794 */
795 void read_command_line(std::vector<std::string>& args);
796
797 protected:
798 /**
799 * \brief Skips the latest chunk.
800 * \details This function can only be called right
801 * after next_chunk().
802 */
803 void skip_chunk();
804
805 /**
806 * \brief Reads an array of index_t, possibly with different
807 * GARGANTUA mode, and adapts it to current GARGANTUA mode.
808 * \param[out] addr buffer where to store the result
809 * \param[in] nb_elements number of elements to read
810 * \param[in] element_size size of an element (index_t), 4 or 8
811 */
812 void read_and_convert_index_t_array(
813 index_t* addr, size_t nb_elements, size_t element_size
814 );
815
816 AttributeSetInfo* current_attribute_set_;
817 AttributeInfo* current_attribute_;
818 std::string current_comment_;
819
820 private:
821 /**
822 * \brief Forbids copy.
823 */
824 InputGeoFile(const InputGeoFile& rhs);
825
826 /**
827 * \brief Forbids copy.
828 */
829 InputGeoFile& operator=(const InputGeoFile& rhs);
830 };
831
832 /**************************************************************/
833
834 /**
835 * \brief Used to write a structured binary file.
836 */
837 class GEOGRAM_API OutputGeoFile : public GeoFile {
838 public:
839 /**
840 * \brief OutputGeoFile constructor.
841 * \param[in] filename a const reference to the file name.
842 * \param[in] compression_level optional compression level, use
843 * 0 for uncompressed and 6 for maximum compression.
844 */
845 OutputGeoFile(const std::string& filename, index_t compression_level=3);
846
847 /**
848 * \brief Writes a new attribute set to the file.
849 * \param[in] name a const reference to the name of
850 * the attribute set
851 * \param[in] nb_items number of items in the attribute set
852 */
853 void write_attribute_set(
854 const std::string& name, index_t nb_items
855 );
856
857 /**
858 * \brief Writes a new attribute to the file.
859 * \param[in] attribute_set_name a const reference to the name of
860 * an attribute set
861 * \param[in] attribute_name a const reference to the name of the
862 * attribute
863 * \param[in] element_type a const reference to the C++ name of the
864 * element type
865 * \param[in] element_size size in bytes of an element
866 * \param[in] dimension number of elements per item
867 * \param[in] data a const pointer to the data of the attribute, as
868 * a contiguous array of bytes in memory.
869 */
870 void write_attribute(
871 const std::string& attribute_set_name,
872 const std::string& attribute_name,
873 const std::string& element_type,
874 size_t element_size,
875 index_t dimension,
876 const void* data
877 );
878
879
880 /**
881 * \brief Writes a new comment to the file.
882 * \param[in] comment a const reference to the comment.
883 */
884 void write_comment(const std::string& comment);
885
886 /**
887 * \brief Writes the command line to the file.
888 * \details It is useful to save the command line arguments in
889 * each file, so that one can retrieve the parameters of each
890 * experiments when doing algorithm test.
891 * \param[in] args the command line, as a vector of strings
892 */
893 void write_command_line(const std::vector<std::string>& args);
894
895
896 /**
897 * \brief Writes a separator into the file.
898 * \details Separators are used to mark the boundaries between
899 * multiple objects saved in the same GeoFile.
900 */
901 void write_separator();
902
903 private:
904 /**
905 * \brief Forbids copy.
906 */
907 OutputGeoFile(const InputGeoFile& rhs);
908
909 /**
910 * \brief Forbids copy.
911 */
912 OutputGeoFile& operator=(const InputGeoFile& rhs);
913 };
914
915 /**************************************************************/
916 }
917
918 #endif
919