GammaLib 2.2.0.dev
Loading...
Searching...
No Matches
GHdf5.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GHdf5.cpp - HDF5 file handling class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2026 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * *
20 ***************************************************************************/
21/**
22 * @file GHdf5.hpp
23 * @brief HDF5 file handling class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <string>
32#include <cstring> // for std::memcpy, std::memmove, std::strncmp
33#include <typeinfo>
34#include "GHdf5.hpp"
35#include "GException.hpp"
36#include "GTools.hpp"
37
38/* __ Method name definitions ____________________________________________ */
39#define G_LOAD "GHdf5::load(GFilename&)"
40#define G_XML_HDF5_ENTRY "GHdf5::xml_hdf5_entry(std::string&)"
41#define G_READ_SUPERBLOCK "GHdf5::read_superblock(FILE*)"
42#define G_READ_SYMBOL_TABLE_NODE "GHdf5::read_symbol_table_node(FILE*, "\
43 "uint64_t&, uint64_t&, std::string&, GXmlElement*, int&)"
44#define G_READ_SYMBOL_TABLE_ENTRY "GHdf5::read_symbol_table_entry(FILE*, "\
45 "uint64_t&, GXmlElement*, int&)"
46#define G_READ_GROUP "GHdf5::read_group(FILE*, uint64_t&, uint64_t&, "\
47 "GXmlElement*, int&)"
48#define G_READ_BTREE_CHUNKED "GHdf5::read_btree(FILE*, "\
49 "uint64_t&, GXmlElement*, int& indent)"
50#define G_READ_OBJECT_HEADER "GHdf5::read_object_header(FILE*, "\
51 "uint64_t&, GXmlElement*, int&)"
52#define G_READ_OBJECT_HEADER_V1 "GHdf5::read_object_header_v1(FILE*, int&)"
53#define G_READ_OBJECT_HEADER_V2 "GHdf5::read_object_header_v2(FILE*, int&)"
54#define G_READ_OBJECT_HEADER_MESSAGE "GHdf5::read_object_header_message("\
55 "FILE*, int&, int&)"
56#define G_READ_MESSAGE_DATASPACE "GHdf5::read_message_dataspace(FILE*, "\
57 "GXmlElement*, std::string&)"
58#define G_READ_MESSAGE_DATATYPE "GHdf5::read_message_datatype(FILE*, "\
59 "GXmlElement*, std::string&)"
60#define G_READ_MESSAGE_LAYOUT "GHdf5::read_message_layout(FILE*, "\
61 "GXmlElement*, std::string&)"
62#define G_READ_MESSAGE_FILTER "GHdf5::read_message_filter(FILE*, "\
63 "GXmlElement*, std::string&)"
64#define G_READ_MESSAGE_ATTRIBUTE "GHdf5::read_message_attribute(FILE*, "\
65 "GXmlElement*, std::string&)"
66#define G_GLOBAL_HEAP_STRING "GHdf5::global_heap_string(FILE*, uint64_t&, "\
67 "int&, uint32_t&)"
68#define G_FREAD_DATA1 "GHdf5::fread_data(FILE*, int&)"
69#define G_FREAD_DATA2 "gammalib::hdf5::fread_data(FILE*, GXmlElement*, "\
70 "GXmlElement*, GXmlElement*, GXmlElement*)"
71#define G_FREAD_DATA_CHUNK "gammalib::hdf5::fread_data_chunk(FILE*, "\
72 "GXmlElement*, GXmlElement*, GXmlElement*, GXmlElement*, GXmlElement*)"
73#define G_FREAD_INT "gammalib::hdf5::fread_int(FILE*, int&)"
74#define G_FREAD_UINT32 "gammalib::hdf5::fread_uint32(FILE*, int&)"
75#define G_FREAD_UINT64 "gammalib::hdf5::fread_uint64(FILE*, int&)"
76#define G_FREAD_STRING "gammalib::hdf5::fread_string(FILE*, int&)"
77#define G_FREAD_DATA_AS_STRING "gammalib::hdf5::fread_data_as_string(FILE*, "\
78 "GXmlElement*)"
79#define G_FREAD_ZERO "gammalib::hdf5::fread_zero(FILE*, int&)"
80#define G_DATA_TO_INT "gammalib::hdf5::data_to_int(char*, GXmlElement*)"
81#define G_DATA_TO_DOUBLE "gammalib::hdf5::data_to_double(char*, "\
82 "GXmlElement*)"
83#define G_DATA_TO_STRING "gammalib::hdf5::data_to_string(char*, "\
84 "GXmlElement*)"
85#define G_DATA_FILTER "gammalib::hdf5::data_filter(std::string&, "\
86 "GXmlElement*)"
87#define G_DATA_FILTER_BITSHUFFLE \
88 "gammalib::hdf5::data_filter_bitshuffle(std::string&, GXmlElement*)"
89#define G_XML_MSG_TYPE "gammalib::hdf5::xml_msg_type(GXmlElement*, "\
90 "std::string& type, int&)"
91#define G_XML_MSG_ATTRIBUTE \
92 "gammalib::hdf5::xml_msg_attribute(GXmlElement*, std::string&)"
93#define G_DECOMPRESS_LZ4 "decompress_lz4(char*, char*, size_t&, size_t&)"
94#define G_READ_VARIABLE_LENGTH "read_variable_length(uint8_t**, uint8_t*, "\
95 "bool&)"
96#define G_MEMCPY_USING_OFFSET "memcpy_using_offset(uint8_t*, uint8_t*, "\
97 "uint8_t*, size_t&)"
98
99
100/* __ Macros _____________________________________________________________ */
101
102/* __ Coding definitions _________________________________________________ */
103
104/* __ Debug definitions __________________________________________________ */
105//#define G_HDF5_DEBUG //!< Debug HDF5 file decoding
106//#define G_BITSHUFFLE_DEBUG //!< Debug Bitshuffe filter
107
108/* __ Constants __________________________________________________________ */
109
110/* __ Prototypes for bitshuffle filter ___________________________________ */
111void bitshuffle_decompress(char* input,
112 char* output,
113 const size_t& elements,
114 const size_t& element_size,
115 size_t& block_size);
116uint64_t bitshuffle_read_uint64(const char* buffer);
117uint32_t bitshuffle_read_uint32(const char* buffer);
118void bitshuffle_elements(const char* input,
119 char* output,
120 const size_t& elements,
121 const size_t& element_size);
122int decompress_lz4(const char* src,
123 char* dst,
124 const size_t& srcSize,
125 const size_t& outputSize);
126size_t read_variable_length(const uint8_t** ip,
127 const uint8_t* ilimit,
128 const bool& initial_check);
129uint16_t read_uint16(const void* memPtr);
130void memcpy_using_offset(const uint8_t* srcPtr,
131 uint8_t* dstPtr,
132 uint8_t* dstEnd,
133 const size_t& offset);
134void memcpy_beyond8(const uint8_t* srcPtr,
135 uint8_t* dstPtr,
136 uint8_t* dstEnd);
137void memory_beyond32(const uint8_t* srcPtr,
138 uint8_t* dstPtr,
139 uint8_t* dstEnd);
140
141/* __ Using of namespaces ________________________________________________ */
142using namespace gammalib::hdf5;
143
144
145/*==========================================================================
146 = =
147 = Constructors/destructors =
148 = =
149 ==========================================================================*/
150
151/***********************************************************************//**
152 * @brief Void constructor
153 *
154 * Creates an empty instance of the HDF5 class.
155 ***************************************************************************/
157{
158 // Initialise members
159 init_members();
160
161 // Return
162 return;
163}
164
165
166/***********************************************************************//**
167 * @brief Load constructor
168 *
169 * @param[in] filename File name of HDF5 file.
170 *
171 * Create HDF5 instance by loading data from a HDF5 file.
172 ***************************************************************************/
173GHdf5::GHdf5(const GFilename& filename)
174{
175 // Initialise members
176 init_members();
177
178 // Load file
179 load(filename);
180
181 // Return
182 return;
183}
184
185
186/***********************************************************************//**
187 * @brief Copy constructor
188 *
189 * @param[in] file HDF5 file instance.
190 **************************************************************************/
191GHdf5::GHdf5(const GHdf5& file)
192{
193 // Initialise members
194 init_members();
195
196 // Copy members
197 copy_members(file);
198
199 // Return
200 return;
201}
202
203
204/***********************************************************************//**
205 * @brief Destructor
206 ***************************************************************************/
208{
209 // Free members
210 free_members();
211
212 // Return
213 return;
214}
215
216
217/*==========================================================================
218 = =
219 = Operators =
220 = =
221 ==========================================================================*/
222
223/***********************************************************************//**
224 * @brief Assignment operator
225 *
226 * @param[in] file HDF5 file instance.
227 * @return HDF5 file instance.
228 *
229 * Assign HDF5 file instance to this object. The assignment performs a deep
230 * copy of all information, hence the original object from which the
231 * assignment was made can be destroyed after this operation without any loss
232 * of information.
233 ***************************************************************************/
235{
236 // Execute only if object is not identical
237 if (this != &file) {
238
239 // Free members
240 free_members();
241
242 // Initialise members
243 init_members();
244
245 // Copy members
246 copy_members(file);
247
248 } // endif: object was not identical
249
250 // Return this object
251 return *this;
252}
253
254
255/*==========================================================================
256 = =
257 = Public methods =
258 = =
259 ==========================================================================*/
260
261/***********************************************************************//**
262 * @brief Clear instance
263 *
264 * Clears HDF5 file instance by resetting all class members to an initial
265 * state. Any information that was present before will be lost.
266 ***************************************************************************/
267void GHdf5::clear(void)
268{
269 // Free class members
270 free_members();
271
272 // Initialise members
273 init_members();
274
275 // Return
276 return;
277}
278
279
280/***********************************************************************//**
281 * @brief Clone instance
282 *
283 * @return Pointer to deep copy of HDF5 file instance.
284 ***************************************************************************/
285GHdf5* GHdf5::clone(void) const
286{
287 return new GHdf5(*this);
288}
289
290
291/***********************************************************************//**
292 * @brief Load data from HDF5 file into instance
293 *
294 * @param[in] filename File name of HDF5 file.
295 *
296 * @exception GException::file_error
297 * Unable to open specified file.
298 *
299 * Load data from HDF5 file into a HDF5 file.
300 ***************************************************************************/
301void GHdf5::load(const GFilename& filename)
302{
303 // Clear instance
304 clear();
305
306 // Store filename
307 m_filename = filename;
308
309 // Expand environment variables in filename
310 std::string fname = gammalib::expand_env(filename.url());
311
312 // Open HDF5 file (read-only)
313 FILE* fptr = std::fopen(fname.c_str(), "rb");
314 if (fptr == NULL) {
315 std::string msg = "Unable to open file \""+fname+"\" for read access. "
316 "Please specify a readable file.";
317 throw GException::file_error(G_LOAD, msg);
318 }
319
320 // Read file
321 read(fptr);
322
323 // Close file
324 std::fclose(fptr);
325
326 // Return
327 return;
328}
329
330
331/***********************************************************************//**
332 * @brief Read data from HDF5 file into instance
333 *
334 * @param[in] fptr File pointer to HDF5 file.
335 *
336 * Read data from HDF5 file into a HDF5 file.
337 ***************************************************************************/
338void GHdf5::read(FILE* fptr)
339{
340 // Clear instance
341 clear();
342
343 // Move file pointer to start of file
344 std::fseek(fptr, 0, SEEK_SET);
345
346 // Parse HDF5 file by reading its superblock
347 read_superblock(fptr);
348
349 // Return
350 return;
351}
352
353
354/***********************************************************************//**
355 * @brief Return XML element to entry tag
356 *
357 * @param[in] name Entry name.
358 * @return Pointer to XML element of given name.
359 *
360 * @exception GException::invalid_value
361 * No HDF5 metadata were loaded.
362 * No entry element with specified @p name found.
363 *
364 * Returns a XML pointer to an entry element with a given @p name.
365 *
366 * The method works recursevely down the entire XML structure of the HDF5
367 * file and stops once the first entry element with a "name" attribute equal
368 * to @p name was found. If no such element could be found, the method throws
369 * an exception.
370 ***************************************************************************/
371const GXmlElement* GHdf5::xml_hdf5_entry(const std::string& name) const
372{
373 // Throw an exception if XML instance is empty
374 if (m_xml.is_empty()) {
375 std::string msg = "No HDF5 metadata were loaded. Please first "
376 "load metadata from a HDF5 file.";
378 }
379
380 // Get ROOT element
381 const GXmlElement* root = m_xml.element(0);
382
383 // Search element
385 "entry",
386 "name",
387 name);
388
389 // Throw an exception if no entry was found
390 if (element == NULL) {
391 std::string msg = "No entry with attribute "+name+"=\""+name+
392 "\" found in HDF5 metadata.";
394 }
395
396 // Return element
397 return element;
398}
399
400
401/***********************************************************************//**
402 * @brief Print HDF5 file
403 *
404 * @param[in] chatter Chattiness.
405 * @return String containing HDF5 information.
406 ***************************************************************************/
407std::string GHdf5::print(const GChatter& chatter) const
408{
409 // Initialise result string
410 std::string result;
411
412 // Continue only if chatter is not silent
413 if (chatter != SILENT) {
414
415 // Append header
416 result.append("=== GHdf5 ===");
417
418 // Append information
419 result.append("\n"+gammalib::parformat("Filename")+m_filename);
420 result.append("\n"+gammalib::parformat("Size of Offsets")+gammalib::str(m_offset));
421 result.append("\n"+gammalib::parformat("Size of Lengths")+gammalib::str(m_length));
422
423 // If file name is not empty then append HDF5 metadata
424 if (m_filename.length() > 0) {
425
426 //TODO: Implement generic printing
427
428 } // endif: file name was not empty
429
430 } // endif: chatter was not silent
431
432 // Return result
433 return result;
434}
435
436
437/*==========================================================================
438 = =
439 = Private methods =
440 = =
441 ==========================================================================*/
442
443/***********************************************************************//**
444 * @brief Initialise class members
445 ***************************************************************************/
447{
448 // Initialise members
450 m_offset = 0;
451 m_length = 0;
452 m_xml.clear();
453
454 // Return
455 return;
456}
457
458
459/***********************************************************************//**
460 * @brief Copy class members
461 *
462 * @param[in] file HDF5 file instance.
463 ***************************************************************************/
464void GHdf5::copy_members(const GHdf5& file)
465{
466 // Copy members
467 m_filename = file.m_filename;
468 m_offset = file.m_offset;
469 m_length = file.m_length;
470 m_xml = file.m_xml;
471
472 // Return
473 return;
474}
475
476
477/***********************************************************************//**
478 * @brief Delete class members
479 ***************************************************************************/
481{
482 // Return
483 return;
484}
485
486
487/***********************************************************************//**
488 * @brief Read HDF5 file superblock
489 *
490 * @param[in] fptr File pointer.
491 *
492 * @exception GException::invalid_value
493 * File is not a HDF5 file
494 * Superblock version out of valid range
495 * Invalid offset and length values
496 *
497 * Reads the superblock of the HDF5 file and walks done the hierarchical HDF5
498 * file structure to extract all metadata. The information is stored in the
499 * XML file member m_xml that will echo the hierarchical information of
500 * the HDF5 file.
501 *
502 * The superblock may begin at certain predefined offsets within the HDF5
503 * file, allowing a block of unspecified content for users to place
504 * additional information at the beginning (and end) of the HDF5 file
505 * without limiting the HDF5 library's ability to manage the objects within
506 * the file itself.
507 *
508 * This method assumes that the @p fptr file pointer points to the
509 * superblock. If an offset is needed, the client needs to position the
510 * file pointer accordingly.
511 *
512 * This method fully supports superblock versions 0 and 1. For superblock
513 * versions 2 and 3, entering of the group graph still needs to be
514 * implemented.
515 ***************************************************************************/
517{
518 // Set HDF5 signature
519 const char hdf5_signature[] = {static_cast<char>(0x89), 0x48, 0x44, 0x46, 0x0d, 0x0a, 0x1a, 0x0a};
520
521 // Read signature
522 std::string signature = fread_string(fptr, 8);
523
524 // Check signature to verify that the file is indeed a HDF5 file
525 if (std::strncmp(signature.c_str(), &hdf5_signature[0], 8) != 0) {
526 std::string msg = "File does not contain a valid HDF5 signature. "
527 "Please specify a valid HDF5 file.";
529 }
530
531 // Read version
532 uint32_t version = fread_uint32(fptr, 1);
533
534 // Check version
535 if (version > 3) {
536 std::string msg = "Superblock version "+gammalib::str(version)+" is "
537 "not comprised between 0 and 3. Please specify a "
538 "valid HDF5 file.";
540 }
541
542 // Parse version 0 or 1
543 if (version < 2) {
544
545 // Read version fields
546 int version_free = fread_int(fptr, 1);
547 int version_root = fread_int(fptr, 1);
548 fread_zero(fptr, 1);
549 int version_shared = fread_int(fptr, 1);
550
551 // Read offset and length
552 m_offset = fread_int(fptr, 1);
553 m_length = fread_int(fptr, 1);
554
555 // Check offset and length
556 if (m_offset < 1) {
557 std::string msg = "Offset "+gammalib::str(m_offset)+" is smaller "
558 "than 1 Byte. Please specify a valid HDF5 file.";
560 }
561 if (m_offset > 8) {
562 std::string msg = "Offset "+gammalib::str(m_offset)+" is larger "
563 "than 8 Bytes. Please specify a valid HDF5 file.";
565 }
566 if (m_length < 1) {
567 std::string msg = "Length "+gammalib::str(m_offset)+" is smaller "
568 "than 1 Byte. Please specify a valid HDF5 file.";
570 }
571 if (m_length > 8) {
572 std::string msg = "Length "+gammalib::str(m_offset)+" is larger "
573 "than 8 Bytes. Please specify a valid HDF5 file.";
575 }
576
577 // Read further fields
578 fread_zero(fptr, 1); // Zero padding
579 int group_leaf_node = fread_int(fptr, 2); // Group Leaf Node K
580 int group_internal_node = fread_int(fptr, 2); // Group Internal Node K
581 int flags = fread_int(fptr, 4); // File Consistency Flags
582 int indexed_storage = 0;
583
584 // Read optional field
585 if (version == 1) {
586 indexed_storage = fread_int(fptr, 2);
587 fread_zero(fptr, 2);
588 }
589
590 // Read addresses
591 uint64_t address_base = fread_uint64(fptr, m_offset); // Base Address
592 uint64_t address_free = fread_uint64(fptr, m_offset); // Address of File Free Space Info
593 uint64_t address_eof = fread_uint64(fptr, m_offset); // End of File Address
594 uint64_t address_drv = fread_uint64(fptr, m_offset); // Driver Information Block Address
595
596 // Debugging: print superblock information
597 #if defined(G_HDF5_DEBUG)
598 std::string msg = "Superblock(version="+gammalib::str(version)+
599 ", offset="+gammalib::str(m_offset)+
600 ", length="+gammalib::str(m_length)+")";
601 debug_msg(msg, 0);
602 #endif
603
604 // Get current file pointer position as address of Root Group
605 // Symbol Table Entry
606 uint64_t pos = std::ftell(fptr);
607
608 // Create symbol table entry XML element and append it to XML file
609 GXmlElement* entry = m_xml.append("entry");
610
611 // Add attributes to "ROOT" entry
612 entry->attribute("version", gammalib::str(version));
613 entry->attribute("offset", gammalib::str(m_offset));
614 entry->attribute("length", gammalib::str(m_length));
615 entry->attribute("version_free_space_storage", gammalib::str(version_free));
616 entry->attribute("version_root_group_symbol_table", gammalib::str(version_root));
617 entry->attribute("version_shared_header_message", gammalib::str(version_shared));
618 entry->attribute("group_leaf_node", gammalib::str(group_leaf_node));
619 entry->attribute("group_internal_node", gammalib::str(group_internal_node));
620 entry->attribute("flags", gammalib::str(flags));
621 if (version == 1) {
622 entry->attribute("indexed_storage_internal_node", gammalib::str(indexed_storage));
623 }
624 entry->attribute("address_base", gammalib::str(address_base));
625 entry->attribute("address_free_space_storage", gammalib::str(address_free));
626 entry->attribute("address_eof", gammalib::str(address_eof));
627 entry->attribute("address_driver_info", gammalib::str(address_drv));
628
629 // Root Group Symbol Table Entry
630 read_symbol_table_entry(fptr, pos, 0, "ROOT", entry, 1);
631
632 } // endif: version 0 or 1
633
634 // Parse version 2 or 3
635 else {
636
637 // Read offset and length
638 m_offset = fread_int(fptr, 1);
639 m_length = fread_int(fptr, 1);
640
641 // Check offset and length
642 if (m_offset < 1) {
643 std::string msg = "Offset "+gammalib::str(m_offset)+" is smaller "
644 "than 1 Byte. Please specify a valid HDF5 file.";
646 }
647 if (m_offset > 8) {
648 std::string msg = "Offset "+gammalib::str(m_offset)+" is larger "
649 "than 8 Bytes. Please specify a valid HDF5 file.";
651 }
652 if (m_length < 1) {
653 std::string msg = "Length "+gammalib::str(m_offset)+" is smaller "
654 "than 1 Byte. Please specify a valid HDF5 file.";
656 }
657 if (m_length > 8) {
658 std::string msg = "Length "+gammalib::str(m_offset)+" is larger "
659 "than 8 Bytes. Please specify a valid HDF5 file.";
661 }
662
663 // Read further fields
664 int flags = fread_int(fptr, 1); // File Consistency Flags
665
666 // Read addresses
667 uint64_t address_base = fread_uint64(fptr, m_offset); // Base Address
668 uint64_t address_ext = fread_uint64(fptr, m_offset); // Superblock Extension Address
669 uint64_t address_eof = fread_uint64(fptr, m_offset); // End of File Address
670 uint64_t address_root = fread_uint64(fptr, m_offset); // Root Group Object Header Address
671
672 // Read further fields
673 uint32_t chksum = fread_uint32(fptr, 4); // Superblock Checksum
674
675 // Create symbol table entry XML element and append it to XML file
676 GXmlElement* entry = m_xml.append("entry");
677
678 // Add attributes to "ROOT" entry
679 entry->attribute("version", gammalib::str(version));
680 entry->attribute("offset", gammalib::str(m_offset));
681 entry->attribute("length", gammalib::str(m_length));
682 entry->attribute("flags", gammalib::str(flags));
683 entry->attribute("address_base", gammalib::str(address_base));
684 entry->attribute("address_superblock_extension", gammalib::str(address_ext));
685 entry->attribute("address_eof", gammalib::str(address_eof));
686 entry->attribute("address_root_group_object_header", gammalib::str(address_root));
687 entry->attribute("checksum", gammalib::str(chksum));
688
689 // Enter group graph
690 //TODO
691
692 } // endelse: version 2 or 3
693
694 // Return
695 return;
696}
697
698
699/***********************************************************************//**
700 * @brief Read HDF5 symbol table node
701 *
702 * @param[in] fptr File pointer.
703 * @param[in] address Address of symbol table node.
704 * @param[in] offset Byte offset in heap.
705 * @param[in] heap Heap.
706 * @param[in] table Pointer to XML element for table.
707 * @param[in] indent Indent for debugging messages.
708 *
709 * @exception GException::invalid_value
710 * Symbol table node signature not found
711 * Invalid symbol table node version
712 *
713 * This method reads a symbol table node from the file. The symbol table
714 * node is a leaf of a B-tree.
715 *
716 * Each symbol table node starts with the signature "SNOD" and contains an
717 * arbitrary number of symbols (group entries). All symbol table nodes
718 * have the same length of 2*m_offset+24.
719 ***************************************************************************/
721 const uint64_t& address,
722 const uint64_t& offset,
723 const std::string& heap,
724 GXmlElement* table,
725 const int& indent)
726{
727 // Set symbol table node signature
728 const char table_signature[] = {'S', 'N', 'O', 'D'};
729
730 // Move file pointer to symbol table node address
731 std::fseek(fptr, address, SEEK_SET);
732
733 // Read symbol table node signature
734 std::string signature = fread_string(fptr, 4);
735
736 // Check signature to verify that we point indeed to a symbol table node
737 if (std::strncmp(signature.c_str(), &table_signature[0], 4) != 0) {
738 std::string msg = "No \"SNOD\" signature found at address "+
739 hexaddress(address)+" in HDF5 file. "
740 "Please specify a valid HDF5 file.";
742 }
743
744 // Read version
745 uint32_t version = fread_uint32(fptr, 1);
746
747 // Check version
748 if (version != 1) {
749 std::string msg = "Symbol table node version "+gammalib::str(version)+
750 " is not 1. Please specify a valid HDF5 file.";
752 }
753
754 // Read fields
755 fread_zero(fptr, 1);
756 int symbols = fread_int(fptr, 2);
757
758 // Debugging: print symbol table node information
759 #if defined(G_HDF5_DEBUG)
760 std::string msg = "Symbol_table_node(address=" + hexaddress(address) +
761 ", version=" + gammalib::str(version) +
762 ", symbols=" + gammalib::str(symbols)+")";
763 debug_msg(msg, indent);
764 #endif
765
766 // Get current file pointer position as address of first symbol table entry
767 uint64_t pos = std::ftell(fptr);
768
769 // Loop over symbol table node entries
770 for (int i = 0; i < symbols; ++i) {
771
772 // Create entry XML element and append it to node
773 GXmlElement* entry = table->append("entry");
774
775 // Read symbol table entry
776 read_symbol_table_entry(fptr, pos, offset, heap, entry, indent+1);
777
778 // Increment pointer
779 pos += 2 * m_offset + 24;
780
781 } // endfor: looped over symbol table node entries
782
783 // Return
784 return;
785}
786
787
788/***********************************************************************//**
789 * @brief Read and handle HDF5 symbol table entry
790 *
791 * @param[in] fptr File pointer.
792 * @param[in] address Address of symbol table entry.
793 * @param[in] offset Byte offset in heap.
794 * @param[in] heap Heap.
795 * @param[in] entry Pointer to XML element for entry.
796 * @param[in] indent Indent for debugging messages.
797 *
798 * @exception GException::invalid_value
799 * Invalid cache type encountered
800 *
801 * Read and handle a symbol table entry. If the entry has a cache type of 1
802 * the method will read the corresponding group.
803 *
804 * Each symbol table entry in a symbol table node is designed to allow for
805 * very fast browsing of stored objects. Toward that design goal, the symbol
806 * table entries include space for caching certain constant metadata from the
807 * object header.
808 ***************************************************************************/
810 const uint64_t& address,
811 const uint64_t& offset,
812 const std::string& heap,
813 GXmlElement* entry,
814 const int& indent)
815{
816 // Initialise cache-type dependent information
817 uint64_t address_btree = 0;
818 uint64_t address_heap = 0;
819 uint32_t offset_link_value = 0;
820
821 // Move pointer to address
822 std::fseek(fptr, address, SEEK_SET);
823
824 // Read table entry
825 uint64_t link_name_offset = fread_uint64(fptr, m_offset);
826 uint64_t object_header_address = fread_uint64(fptr, m_offset);
827 uint32_t cache_type = fread_uint32(fptr, 4);
828 fread_zero(fptr, 4);
829
830 // Get link name
831 std::string link_name = extract(heap, offset+link_name_offset);
832
833 // Set link name as attribute of XML element
834 entry->attribute("name", link_name);
835
836 // Decode scratch pad according to cache type
837 switch (cache_type) {
838
839 // No data is cached in the scratch space
840 case 0:
841 break;
842
843 // Group object header metadata is cached in the scratch-pad space.
844 // This implies that the symbol table entry refers to another group.
845 case 1:
846 address_btree = fread_uint64(fptr, m_offset);
847 address_heap = fread_uint64(fptr, m_offset);
848 break;
849
850 // The entry is a symbolic link. The first four bytes of the scratch-pad
851 // space are the offset into the local heap for the link value. The object
852 // header address will be undefined.
853 case 2:
854 offset_link_value = fread_uint32(fptr, 4);
855 break;
856
857 // Invalid cache type
858 default:
859 std::string msg = "Invalid cache type "+gammalib::str(cache_type)+
860 " encountered in symbol table entry located at "
861 "address "+hexaddress(address)+" in HDF5 file. "
862 "Please specify a valid HDF5 file.";
864 break;
865 } // endswitch: decoded scratch pad
866
867 // Debugging: print symbol table entry information
868 #if defined(G_HDF5_DEBUG)
869 std::string msg = "Symbol_table_entry(address="+hexaddress(address)+
870 ", name="+link_name+
871 ", type="+gammalib::str(cache_type)+
872 ", header_address="+hexaddress(object_header_address);
873 if (cache_type == 1) {
874 msg += ", btree_address="+hexaddress(address_btree)+
875 ", heap_address="+hexaddress(address_heap);
876 }
877 else if (cache_type == 2) {
878 msg += "offset_link_value="+hexaddress(offset_link_value);
879 }
880 msg += ")";
881 debug_msg(msg, indent);
882 #endif
883
884 // Create symbol table header XML element and append it to entry
885 GXmlElement* header = entry->append("header");
886
887 // Read header
888 read_object_header(fptr, object_header_address, header, indent+1);
889
890 // If group metadata is cached then read group
891 if (cache_type == 1) {
892
893 // Create group XML element and append it to entry
894 GXmlElement* group = entry->append("group");
895
896 // Read group
897 read_group(fptr, address_btree, address_heap, group, indent+1);
898
899 } // endif: read group
900
901 // Return
902 return;
903}
904
905
906/***********************************************************************//**
907 * @brief Read and handle HDF5 group
908 *
909 * @param[in] fptr File pointer.
910 * @param[in] btree_address Address of B-tree.
911 * @param[in] heap_address Address of heap.
912 * @param[in] group Pointer to XML element for group.
913 * @param[in] indent Indent for debugging messages.
914 *
915 * @exception GException::invalid_value
916 * TREE or HEAP signatures not found
917 * Heap version is not zero
918 * B-tree node type is not 0 or 1
919 *
920 * This method only supports version 1 B-trees. Version 2 B-trees have the
921 * signature "BTHD" and need to be implemented if required.
922 ***************************************************************************/
923void GHdf5::read_group(FILE* fptr,
924 const uint64_t& address_btree,
925 const uint64_t& address_heap,
926 GXmlElement* group,
927 const int& indent)
928{
929 // Set TREE and HEAP signatures
930 const char tree_signature[] = {'T', 'R', 'E', 'E'};
931 const char heap_signature[] = {'H', 'E', 'A', 'P'};
932
933 // Debugging: on entry, print group information
934 #if defined(G_HDF5_DEBUG)
935 std::string msg = "Group(btree_address="+hexaddress(address_btree)+
936 ", heap_address="+hexaddress(address_heap)+")";
937 debug_msg(msg, indent);
938 #endif
939
940 // Move file pointer to heap address
941 std::fseek(fptr, address_heap, SEEK_SET);
942
943 // Read heap signature
944 std::string signature = fread_string(fptr, 4);
945
946 // Check signature to verify that we point indeed to a B-tree
947 if (std::strncmp(signature.c_str(), &heap_signature[0], 4) != 0) {
948 std::string msg = "No \"HEAP\" signature found at address "+
949 hexaddress(address_heap)+" in HDF5 file. "
950 "Please specify a valid HDF5 file.";
952 }
953
954 // Read heap version
955 int version = fread_int(fptr, 1);
956
957 // Check heap version
958 if (version != 0) {
959 std::string msg = "Heap version "+gammalib::str(version)+" is not 0."
960 " Please specify a valid HDF5 file.";
962 }
963
964 // Read heap fields
965 fread_zero(fptr, 3);
966 uint64_t heap_size = fread_uint64(fptr, m_length);
967 fread_uint64(fptr, m_length);
968 uint64_t heap_address = fread_uint64(fptr, m_offset);
969
970 // Move file pointer to heap data
971 std::fseek(fptr, heap_address, SEEK_SET);
972
973 // Read heap data
974 std::string heap = fread_data(fptr, heap_size);
975
976 // Debugging: print heap information
977 #if defined(G_HDF5_DEBUG)
978 msg = "Heap(address="+hexaddress(address_heap)+
979 ", data_address="+hexaddress(heap_address)+
980 ", size="+gammalib::str(heap_size)+")";
981 debug_msg(msg, indent+1);
982 #endif
983
984 // Move pointer to B-tree address
985 std::fseek(fptr, address_btree, SEEK_SET);
986
987 // Read B-tree signature
988 signature = fread_string(fptr, 4);
989
990 // Check signature to verify that we point indeed to a B-tree
991 if (std::strncmp(signature.c_str(), &tree_signature[0], 4) != 0) {
992 std::string msg = "No \"TREE\" signature found at address "+
993 hexaddress(address_btree)+" in HDF5 file. "
994 "Please specify a valid HDF5 file.";
996 }
997
998 // Read node type
999 int node_type = fread_int(fptr, 1);
1000
1001 // Check node type
1002 if (node_type < 0 || node_type > 1) {
1003 std::string msg = "B-tree node type "+gammalib::str(node_type)+" is not 0 "
1004 "or 1. Please specify a valid HDF5 file.";
1006 }
1007
1008 // Read fields
1009 int node_level = fread_int(fptr, 1);
1010 int entries = fread_int(fptr, 2);
1011 uint64_t address_left = fread_uint64(fptr, m_offset);
1012 uint64_t address_right = fread_uint64(fptr, m_offset);
1013
1014 // Debugging: print tree information
1015 #if defined(G_HDF5_DEBUG)
1016 msg = "B-tree(address="+hexaddress(address_btree)+
1017 ", target=";
1018 if (node_type == 0) {
1019 msg += "\"group nodes\"";
1020 }
1021 else {
1022 msg += "\"raw data chunk\"";
1023 }
1024 msg += ", entries="+gammalib::str(entries)+")";
1025 debug_msg(msg, indent+1);
1026 #endif
1027
1028 // Loop over entries
1029 for (int i = 0; i < entries; ++i) {
1030
1031 // Handle node type 0
1032 if (node_type == 0) {
1033
1034 // Get byte offset in heap and child address
1035 uint64_t offset = fread_uint64(fptr, m_length);
1036 uint64_t address_child = fread_uint64(fptr, m_offset);
1037
1038 // Create table XML element and append it to group
1039 GXmlElement* table = group->append("table");
1040
1041 // Read symbol table node
1042 read_symbol_table_node(fptr, address_child, offset, heap, table, indent+2);
1043
1044 } // endif: node type was 0
1045
1046 // Handle node type 1
1047 else {
1048
1049 } // endelse: node type was 1
1050
1051 } // endfor: looped over entries
1052
1053 // Return
1054 return;
1055}
1056
1057
1058/***********************************************************************//**
1059 * @brief Read HDF5 B-tree for chunked data
1060 *
1061 * @param[in] fptr File pointer.
1062 * @param[in] address Address of B-tree.
1063 * @param[in] dimensions Dataset dimensions + 1.
1064 * @param[in] btree Pointer to XML element for btree.
1065 *
1066 * @exception GException::invalid_value
1067 * TREE signature not found
1068 * B-tree node type is not 1
1069 *
1070 * This method only supports version 1 B-trees. Version 2 B-trees have the
1071 * signature "BTHD" and need to be implemented if required.
1072 ***************************************************************************/
1074 const uint64_t& address,
1075 const int& dimensions,
1076 GXmlElement* btree)
1077{
1078 // Set TREE signature
1079 const char tree_signature[] = {'T', 'R', 'E', 'E'};
1080
1081 // Move pointer to B-tree address
1082 std::fseek(fptr, address, SEEK_SET);
1083
1084 // Read B-tree signature
1085 std::string signature = fread_string(fptr, 4);
1086
1087 // Check signature to verify that we point indeed to a B-tree
1088 if (std::strncmp(signature.c_str(), &tree_signature[0], 4) != 0) {
1089 std::string msg = "No \"TREE\" signature found at address "+
1090 hexaddress(address)+" in HDF5 file. "
1091 "Please specify a valid HDF5 file.";
1093 }
1094
1095 // Read node type
1096 int node_type = fread_int(fptr, 1);
1097
1098 // Check node type
1099 if (node_type != 1) {
1100 std::string msg = "B-tree node type "+gammalib::str(node_type)+
1101 " for chunked data is not 1."
1102 "Please specify a valid HDF5 file.";
1104 }
1105
1106 // Read fields
1107 int node_level = fread_int(fptr, 1);
1108 int entries = fread_int(fptr, 2);
1109 uint64_t address_left = fread_uint64(fptr, m_offset);
1110 uint64_t address_right = fread_uint64(fptr, m_offset);
1111
1112 // Add attributes to XML element
1113 btree->attribute("type", gammalib::str(node_type));
1114 btree->attribute("level", gammalib::str(node_level));
1115 btree->attribute("entries", gammalib::str(entries));
1116 btree->attribute("dimensions", gammalib::str(dimensions));
1117
1118 // Loop over entries
1119 for (int i = 0; i < entries; ++i) {
1120
1121 // Read fields
1122 int chunk_size = fread_int(fptr, 4);
1123 int filter_mask = fread_int(fptr, 4);
1124
1125 // Create key XML element and append it to B-tree
1126 GXmlElement* key = btree->append("key");
1127
1128 // Add attributes to XML element
1129 key->attribute("size", gammalib::str(chunk_size));
1130 key->attribute("filter_mask", gammalib::str(filter_mask));
1131
1132 // Read keys
1133 for (int k = 0; k < dimensions; ++k) {
1134
1135 // Read fields
1136 uint64_t index = fread_uint64(fptr, 8);
1137
1138 // Add attribute to XML element
1139 if (k < dimensions-1) {
1140 key->attribute("index"+gammalib::str(k), gammalib::str(index));
1141 }
1142 else {
1143 key->attribute("offset", gammalib::str(index));
1144 }
1145
1146 } // endfor: looped over dimensions
1147
1148 // Read child address
1149 uint64_t address_child = fread_uint64(fptr, m_offset);
1150
1151 // Add attributes to XML element
1152 key->attribute("address", gammalib::str(address_child));
1153
1154 // If node level is not zero this nodes points to another B-tree, hence
1155 // recursively analyse this subtree
1156 if (node_level != 0) {
1157
1158 // Get current address
1159 uint64_t address = std::ftell(fptr);
1160
1161 // Create B-tree XML element and append it to key
1162 GXmlElement* subbtree = key->append("btree");
1163
1164 // Read B-tree
1165 read_btree_chunked(fptr, address_child, dimensions, subbtree);
1166
1167 // Restore current address for reading of next key
1168 std::fseek(fptr, address, SEEK_SET);
1169
1170 } // endif: node was not a leaf node
1171
1172 } // endfor: looped over entries
1173
1174 // Return
1175 return;
1176}
1177
1178
1179/***********************************************************************//**
1180 * @brief Read object header
1181 *
1182 * @param[in] fptr File pointer.
1183 * @param[in] address Address of header.
1184 * @param[in] header Pointer to XML element for header.
1185 * @param[in] indent Indent for debugging messages.
1186 *
1187 * @exception GException::invalid_value
1188 * Invalid object header version
1189 *
1190 * The header information of an object is designed to encompass all the
1191 * information about an object, except for the data itself. This information
1192 * includes the dataspace, datatype, information about how the data is stored
1193 * on disk (in external files, compressed, broken up in blocks, and so on),
1194 * as well as other information used by the library to speed up access to the
1195 * data objects or maintain a file’s integrity. Information stored by user
1196 * applications as attributes is also stored in the object’s header. The
1197 * header of each object is not necessarily located immediately prior to the
1198 * object’s data in the file and in fact may be located in any position in
1199 * the file. The order of the messages in an object header is not
1200 * significant.
1201 *
1202 * Object headers are composed of a prefix and a set of messages. The prefix
1203 * contains the information needed to interpret the messages and a small
1204 * amount of metadata about the object, and the messages contain the majority
1205 * of the metadata about the object.
1206 ***************************************************************************/
1208 const uint64_t& address,
1209 GXmlElement* header,
1210 const int& indent)
1211{
1212 // Move pointer to address
1213 std::fseek(fptr, address, SEEK_SET);
1214
1215 // Read version
1216 int version = fread_int(fptr, 1);
1217
1218 // Version dependent reading
1219 switch (version) {
1220 case 1:
1221 read_object_header_v1(fptr, header, indent);
1222 break;
1223 case 2:
1224 read_object_header_v2(fptr, header, indent);
1225 break;
1226 default:
1227 std::string msg = "Object header version "+gammalib::str(version)+" is "
1228 "not comprised between 1 and 2. Please specify a "
1229 "valid HDF5 file.";
1231 break;
1232 }
1233
1234 // Return
1235 return;
1236}
1237
1238
1239/***********************************************************************//**
1240 * @brief Read object header version 1
1241 *
1242 * @param[in] fptr File pointer.
1243 * @param[in] header Pointer to XML element for header.
1244 * @param[in] indent Indent for debugging messages.
1245 *
1246 * @exception GException::invalid_value
1247 * Invalid message type
1248 ***************************************************************************/
1250 GXmlElement* header,
1251 const int& indent)
1252{
1253 // Read header prefix fields
1254 fread_zero(fptr, 1);
1255 int messages = fread_int(fptr, 2);
1256 int ref_count = fread_int(fptr, 4);
1257 uint64_t size = fread_int(fptr, 4);
1258 fread_zero(fptr, 4);
1259
1260 // Initialise address of first message
1261 uint64_t address = std::ftell(fptr);
1262
1263 // Debugging: print header information
1264 #if defined(G_HDF5_DEBUG)
1265 std::string msg = "Object_header(address="+hexaddress(address)+
1266 ", version=1"
1267 ", messages="+gammalib::str(messages)+
1268 ", ref_count="+gammalib::str(ref_count)+
1269 ", size="+gammalib::str(size)+")";
1270 debug_msg(msg, indent);
1271 #endif
1272
1273 // Loop over all header messages
1274 for (int i = 0; i < messages; ++i) {
1275
1276 // Move pointer to message address
1277 std::fseek(fptr, address, SEEK_SET);
1278
1279 // Read message fields
1280 int msg_type = fread_int(fptr, 2);
1281 int msg_size = fread_int(fptr, 2);
1282 int msg_flags = fread_int(fptr, 1);
1283 fread_zero(fptr, 3);
1284
1285 // Check message type
1286 if (msg_type < 0 || msg_type > 23) {
1287 std::string msg = "Invalid message type "+hexaddress(msg_type)+
1288 " encountered at address "+hexaddress(address)+
1289 " in HDF5 file. Please specify a valid HDF5 file.";
1291 }
1292
1293 // Kludge: If message size is not a multiple of 8 this is an invalid
1294 // message. Set the message size to 8 Bytes and skip.
1295 if (msg_size % 8 != 0) {
1296 #if defined(G_HDF5_DEBUG)
1297 std::string msg = "*** invalid message size "+gammalib::str(msg_size)+
1298 " for message type "+gammalib::str(msg_type)+
1299 " with flags "+gammalib::str(msg_flags)+
1300 " at address "+hexaddress(address)+
1301 ". Skip message.";
1302 debug_msg(msg, indent+1);
1303 #endif
1304 msg_size = 8;
1305 address += msg_size + 8;
1306 continue;
1307 }
1308
1309 // Set address to next message
1310 address += msg_size + 8;
1311
1312 // Handle continuation message
1313 if (msg_type == 16) {
1314
1315 // Update address and size
1316 address = fread_uint64(fptr, m_offset);
1317 size = fread_uint64(fptr, m_length);
1318
1319 // Debugging: print continuation message
1320 #if defined(G_HDF5_DEBUG)
1321 std::string msg = "- message(address=" + hexaddress(address) +
1322 ", Continuation, size= " + gammalib::str(size) + ")";
1323 debug_msg(msg, indent+1);
1324 #endif
1325
1326 // Continue
1327 continue;
1328
1329 } // endif: handled continuation message
1330
1331 // Create message XML element and append it to header
1332 GXmlElement* message = header->append("message");
1333
1334 // Handle remaining messages
1335 read_object_header_message(fptr, msg_type, message, indent+1);
1336
1337 } // endfor: looped over messages
1338
1339 // Return
1340 return;
1341}
1342
1343
1344/***********************************************************************//**
1345 * @brief Read object header version 2
1346 *
1347 * @param[in] fptr File pointer.
1348 * @param[in] header Pointer to XML element for header.
1349 * @param[in] indent Indent for debugging messages.
1350 *
1351 * @exception GException::feature_not_implemented
1352 * Method not yet implemented.
1353 *
1354 * Method not yet implemented.
1355 ***************************************************************************/
1357 GXmlElement* header,
1358 const int& indent)
1359{
1360 // Throw exception
1361 std::string msg = "Decoding of header version 2 not yet implemented.";
1363
1364 // Return
1365 return;
1366}
1367
1368
1369/***********************************************************************//**
1370 * @brief Read one object header message
1371 *
1372 * @param[in] fptr File pointer.
1373 * @param[in] type Message type.
1374 * @param[in] message Pointer to XML element for message.
1375 * @param[in] indent Indent for debugging messages.
1376 *
1377 * @exception GException::invalid_value
1378 * Invalid message
1379 ***************************************************************************/
1381 const int& type,
1382 GXmlElement* message,
1383 const int& indent)
1384{
1385 // Debugging: initialise debug message
1386 #if defined(G_HDF5_DEBUG)
1387 std::string msg = "- message(address=" + hexaddress(std::ftell(fptr)) + ", ";
1388 #else
1389 std::string msg;
1390 #endif
1391
1392 // Handle messages according to type
1393 switch (type) {
1394
1395 // NIL message
1396 case 0: {
1397 // Debugging: add message name
1398 #if defined(G_HDF5_DEBUG)
1399 msg += "NIL";
1400 #endif
1401
1402 // Add message type to XML element
1403 message->attribute("type", "NIL");
1404 break;
1405 }
1406
1407 // Dataspace message
1408 case 1: {
1409 // Debugging: add message name
1410 #if defined(G_HDF5_DEBUG)
1411 msg += "Dataspace";
1412 #endif
1413
1414 // Add message type to XML element
1415 message->attribute("type", "Dataspace");
1416
1417 // Handle dataspace message
1418 read_message_dataspace(fptr, message, msg);
1419 break;
1420 }
1421
1422 // Link Info message
1423 case 2: {
1424 // Debugging: add message name
1425 #if defined(G_HDF5_DEBUG)
1426 msg += "Link Info - NOT DECODED!";
1427 #endif
1428
1429 // Add message type to XML element
1430 message->attribute("type", "LinkInfo");
1431 break;
1432 }
1433
1434 // Datatype message
1435 case 3: {
1436 // Debugging: add message name
1437 #if defined(G_HDF5_DEBUG)
1438 msg += "Datatype";
1439 #endif
1440
1441 // Add message type to XML element
1442 message->attribute("type", "Datatype");
1443
1444 // Handle datatype message
1445 read_message_datatype(fptr, message, msg);
1446 break;
1447 }
1448
1449 // Fill Value (old) message
1450 case 4: {
1451 // Debugging: add message name
1452 #if defined(G_HDF5_DEBUG)
1453 msg += "Fill Value (old) - NOT FULLY DECODED!";
1454 #endif
1455
1456 // Add message type to XML element
1457 message->attribute("type", "FillValueOld");
1458
1459 // Read fields
1460 int size = fread_int(fptr, 4);
1461
1462 // Read fill value
1463 //TODO
1464
1465 // Add attributes to XML element
1466 message->attribute("size", gammalib::str(size));
1467
1468 // Debugging: add dimensions and flags
1469 #if defined(G_HDF5_DEBUG)
1470 msg += ", size=" + gammalib::str(size);
1471 #endif
1472 break;
1473 }
1474
1475 // Fill Value message
1476 case 5: {
1477 // Debugging: add message name
1478 #if defined(G_HDF5_DEBUG)
1479 msg += "Fill Value - NOT DECODED!";
1480 #endif
1481
1482 // Add message type to XML element
1483 message->attribute("type", "FillValue");
1484 break;
1485 }
1486
1487 // Link message
1488 case 6: {
1489 // Debugging: add message name
1490 #if defined(G_HDF5_DEBUG)
1491 msg += "Link - NOT DECODED!";
1492 #endif
1493
1494 // Add message type to XML element
1495 message->attribute("type", "Link");
1496 break;
1497 }
1498
1499 // External Data Files message
1500 case 7: {
1501 // Debugging: add message name
1502 #if defined(G_HDF5_DEBUG)
1503 msg += "External Data Files - NOT DECODED!";
1504 #endif
1505
1506 // Add message type to XML element
1507 message->attribute("type", "ExternalDataFile");
1508 break;
1509 }
1510
1511 // Data Storage - Layout message
1512 case 8: {
1513 // Debugging: add message name
1514 #if defined(G_HDF5_DEBUG)
1515 msg += "Data Storage - Layout";
1516 #endif
1517
1518 // Add message type to XML element
1519 message->attribute("type", "DataStorageLayout");
1520
1521 // Handle message
1522 read_message_layout(fptr, message, msg);
1523 break;
1524 }
1525
1526 // Bogus message
1527 case 9: {
1528 // Debugging: add message name
1529 #if defined(G_HDF5_DEBUG)
1530 msg += "Bogus - NOT DECODED!";
1531 #endif
1532
1533 // Add message type to XML element
1534 message->attribute("type", "Bogus");
1535 break;
1536 }
1537
1538 // Group Info message
1539 case 10: {
1540 // Debugging: add message name
1541 #if defined(G_HDF5_DEBUG)
1542 msg += "Group Info - NOT DECODED!";
1543 #endif
1544
1545 // Add message type to XML element
1546 message->attribute("type", "GroupInfo");
1547 break;
1548 }
1549
1550 // Data Storage - Filter Pipeline message
1551 case 11: {
1552 // Debugging: add message name
1553 #if defined(G_HDF5_DEBUG)
1554 msg += "Data Storage - Filter Pipeline";
1555 #endif
1556
1557 // Add message type to XML element
1558 message->attribute("type", "DataStorageFilterPipeline");
1559
1560 // Handle message
1561 read_message_filter(fptr, message, msg);
1562 break;
1563 }
1564
1565 // Attribute message
1566 case 12: {
1567 // Debugging: add message name
1568 #if defined(G_HDF5_DEBUG)
1569 msg += "Attribute";
1570 #endif
1571
1572 // Add message type to XML element
1573 message->attribute("type", "Attribute");
1574
1575 // Handle message
1576 read_message_attribute(fptr, message, msg);
1577 break;
1578 }
1579
1580 // Object Comment message
1581 case 13: {
1582 // Debugging: add message name
1583 #if defined(G_HDF5_DEBUG)
1584 msg += "Object Comment - NOT DECODED!";
1585 #endif
1586
1587 // Add message type to XML element
1588 message->attribute("type", "ObjectComment");
1589 break;
1590 }
1591
1592 // Object Modification Time (Old) message
1593 case 14: {
1594 // Debugging: add message name
1595 #if defined(G_HDF5_DEBUG)
1596 msg += "Object Modification Time (Old) - NOT DECODED!";
1597 #endif
1598
1599 // Add message type to XML element
1600 message->attribute("type", "ObjectModificationTimeOld");
1601 break;
1602 }
1603
1604 // Shared Message Table message
1605 case 15: {
1606 // Debugging: add message name
1607 #if defined(G_HDF5_DEBUG)
1608 msg += "Shared Message Table - NOT DECODED!";
1609 #endif
1610
1611 // Add message type to XML element
1612 message->attribute("type", "SharedMessageTable");
1613 break;
1614 }
1615
1616 // Object Header Continuation message
1617 case 16: {
1618 // Debugging: add message name
1619 #if defined(G_HDF5_DEBUG)
1620 msg += "Continuation";
1621 #endif
1622
1623 // Add message type to XML element
1624 message->attribute("type", "Continuation");
1625 break;
1626 }
1627
1628 // Symbol Table Message message
1629 case 17: {
1630 // Debugging: add message name
1631 #if defined(G_HDF5_DEBUG)
1632 msg += "Symbol Table Message";
1633 #endif
1634
1635 // Add message type to XML element
1636 message->attribute("type", "SymbolTableMessage");
1637
1638 // Read fields
1639 uint64_t address_tree = fread_uint64(fptr, m_offset);
1640 uint64_t address_heap = fread_uint64(fptr, m_offset);
1641
1642 // Add attributes to XML element
1643 message->attribute("address_tree", gammalib::str(address_tree));
1644 message->attribute("address_heap", gammalib::str(address_heap));
1645
1646 // Debugging: add dimensions and flags
1647 #if defined(G_HDF5_DEBUG)
1648 msg += ", address_tree=" + hexaddress(address_tree) +
1649 ", address_heap=" + hexaddress(address_heap);
1650 #endif
1651 break;
1652 }
1653
1654 // Object Modification Time message
1655 case 18: {
1656 // Debugging: add message name
1657 #if defined(G_HDF5_DEBUG)
1658 msg += "Object Modification Time - NOT DECODED!";
1659 #endif
1660
1661 // Add message type to XML element
1662 message->attribute("type", "ObjectModificationTime");
1663 break;
1664 }
1665
1666 // B-tree K Values message
1667 case 19: {
1668 // Debugging: add message name
1669 #if defined(G_HDF5_DEBUG)
1670 msg += "B-tree K Values - NOT DECODED!";
1671 #endif
1672
1673 // Add message type to XML element
1674 message->attribute("type", "BtreeKValue");
1675 break;
1676 }
1677
1678 // Driver Info message
1679 case 20: {
1680 // Debugging: add message name
1681 #if defined(G_HDF5_DEBUG)
1682 msg += "Driver Info - NOT DECODED!";
1683 #endif
1684
1685 // Add message type to XML element
1686 message->attribute("type", "DriverInfo");
1687 break;
1688 }
1689
1690 // Attribute Info message
1691 case 21: {
1692 // Debugging: add message name
1693 #if defined(G_HDF5_DEBUG)
1694 msg += "Attribute Info - NOT DECODED!";
1695 #endif
1696
1697 // Add message type to XML element
1698 message->attribute("type", "AttributeInfo");
1699 break;
1700 }
1701
1702 // Object Reference Count message
1703 case 22: {
1704 // Debugging: add message name
1705 #if defined(G_HDF5_DEBUG)
1706 msg += "Object Reference Count - NOT DECODED!";
1707 #endif
1708
1709 // Add message type to XML element
1710 message->attribute("type", "ObjectReferenceCount");
1711 break;
1712 }
1713
1714 // File Space Info message
1715 case 23: {
1716 // Debugging: add message name
1717 #if defined(G_HDF5_DEBUG)
1718 msg += "File Space Info - NOT DECODED!";
1719 #endif
1720
1721 // Add message type to XML element
1722 message->attribute("type", "FileSpaceInfo");
1723 break;
1724 }
1725
1726 // Code should never arrive here
1727 default:
1728 break;
1729
1730 } // endwsitch
1731
1732 // Debugging: finalise debug message
1733 #if defined(G_HDF5_DEBUG)
1734 msg += ")";
1735 debug_msg(msg, indent);
1736 #endif
1737
1738 // Return
1739 return;
1740}
1741
1742
1743/***********************************************************************//**
1744 * @brief Read dataspace message
1745 *
1746 * @param[in] fptr File pointer.
1747 * @param[in] type Message type.
1748 * @param[in] msg String for debugging messages (not used if empty length).
1749 * @return Number of elements in dataspace.
1750 *
1751 * The dataspace message describes the number of dimensions (in other words,
1752 * "rank") and size of each dimension that the data object has. This message
1753 * is only used for datasets which have a simple, rectilinear, array-like
1754 * layout; datasets requiring a more complex layout are not yet supported.
1755 *
1756 * This method supports versions 1 and 2 of the dataspace message. If other
1757 * version numbers are encountered the validity flag is set to 0 and the
1758 * decoding is stopped.
1759 ***************************************************************************/
1761 GXmlElement* message,
1762 std::string& msg)
1763{
1764 // Initialise number of elements in dataspace
1765 uint64_t elements = 0;
1766
1767 // Read version
1768 int version = fread_int(fptr, 1);
1769
1770 // If version is not valid then just add version number to field and
1771 // set number of elements to 0. This is a kludge since the test file
1772 // contained an invalud version number of 24, and this version number
1773 // is hence filtered.
1774 if (version < 1 || version > 2) {
1775 message->attribute("version", gammalib::str(version));
1776 message->attribute("elements", "0");
1777 #if defined(G_HDF5_DEBUG)
1778 if (msg.length() > 0) {
1779 msg += ", version=" + gammalib::str(version) +
1780 ", elements=0";
1781 }
1782 #endif
1783 }
1784
1785 // ... otherwise handle dataspace
1786 else {
1787
1788 // Read fields
1789 int dimensions = fread_int(fptr, 1);
1790 int flags = fread_int(fptr, 1);
1791 int type = fread_int(fptr, 1); // Only exists in version 2
1792 fread_zero(fptr, 4);
1793
1794 // Add attributes to XML element
1795 message->attribute("version", gammalib::str(version));
1796 message->attribute("dimensions", gammalib::str(dimensions));
1797 message->attribute("flags", gammalib::str(flags));
1798 if (version == 2) {
1799 message->attribute("type", gammalib::str(type));
1800 }
1801
1802 // Debugging: add dimensions and flags
1803 #if defined(G_HDF5_DEBUG)
1804 if (msg.length() > 0) {
1805 msg += ", version=" + gammalib::str(version) +
1806 ", dimensions=" + gammalib::str(dimensions) +
1807 ", flags=" + gammalib::str(flags);
1808 if (version == 2) {
1809 msg += ", type=" + gammalib::str(type);
1810 }
1811 }
1812 #endif
1813
1814 // If there are no dimensions then set number of elements to
1815 // one
1816 if (dimensions == 0) {
1817 elements = 1;
1818 }
1819
1820 // ... otherwise loop over dimensions to extract sizes and compute
1821 // the number of elements
1822 else {
1823
1824 // Loop over dimensions
1825 for (int i = 0; i < dimensions; ++i) {
1826
1827 // Read dimension size
1828 uint64_t size = fread_uint64(fptr, m_length);
1829
1830 // Compute number of elements
1831 if (i == 0) {
1832 elements = int(size);
1833 }
1834 else {
1835 elements *= int(size);
1836 }
1837
1838 // Add size to XML element
1839 message->attribute("size"+gammalib::str(i), gammalib::str(size));
1840
1841 // Debugging: add size
1842 #if defined(G_HDF5_DEBUG)
1843 if (msg.length() > 0) {
1844 msg += ", size"+gammalib::str(i)+"=" + gammalib::str(size);
1845 }
1846 #endif
1847
1848 } // endfor: looped over dimensions
1849
1850 } // endelse: there were dimensions
1851
1852 // Optionally extract maximum sizes
1853 if ((flags & 1) == 1) {
1854
1855 // Loop over dimensions to extract maximum sizes
1856 for (int i = 0; i < dimensions; ++i) {
1857
1858 // Read dimension size
1859 uint64_t size = fread_uint64(fptr, m_length);
1860
1861 // Add maximum size to XML element
1862 message->attribute("max_size"+gammalib::str(i), gammalib::str(size));
1863
1864 // Debugging: add maximum size
1865 #if defined(G_HDF5_DEBUG)
1866 if (msg.length() > 0) {
1867 msg += ", max_size"+gammalib::str(i)+"=" + gammalib::str(size);
1868 }
1869 #endif
1870
1871 } // endfor: looped over dimensions
1872
1873 } // endif: maximum sizes were present
1874
1875 // Optionally extract permutation index
1876 if ((version == 1) && ((flags & 2) == 2)) {
1877
1878 // Loop over dimensions to extract permutation index
1879 for (int i = 0; i < dimensions; ++i) {
1880
1881 // Read dimension size
1882 uint64_t size = fread_uint64(fptr, m_length);
1883
1884 // Add permutation to XML element
1885 message->attribute("permutation"+gammalib::str(i), gammalib::str(size));
1886
1887 // Debugging: add permutation
1888 #if defined(G_HDF5_DEBUG)
1889 if (msg.length() > 0) {
1890 msg += ", permutation"+gammalib::str(i)+"=" + gammalib::str(size);
1891 }
1892 #endif
1893
1894 } // endfor: looped over dimensions
1895
1896 } // endif: permutation indices were present
1897
1898 // Add elements to XML element
1899 message->attribute("elements", gammalib::str(elements));
1900
1901 // Debugging: add elements
1902 #if defined(G_HDF5_DEBUG)
1903 if (msg.length() > 0) {
1904 msg += ", elements=" + gammalib::str(elements);
1905 }
1906 #endif
1907
1908 } // endelse: version was valid
1909
1910 // Return
1911 return;
1912}
1913
1914
1915/***********************************************************************//**
1916 * @brief Read datatype message
1917 *
1918 * @param[in] fptr File pointer.
1919 * @param[in] message Pointer to XML element.
1920 * @param[in] msg String for debugging messages (not used if empty length).
1921 * @return Size of datatype elements in Bytes.
1922 *
1923 * @exception GException::invalid_value
1924 * Invalid datatype version or class
1925 *
1926 * The datatype message defines the datatype for each element of a dataset
1927 * or a common datatype for sharing between multiple datasets. A datatype
1928 * can describe an atomic type like a fixed- or floating-point type or more
1929 * complex types like a C struct (compound datatype), array (array datatype)
1930 * or C++ vector (variable-length datatype).
1931 *
1932 * Datatype messages that are part of a dataset object do not describe how
1933 * elements are related to one another; the dataspace message is used for
1934 * that purpose. Datatype messages that are part of a committed datatype
1935 * (formerly named datatype) message describe a common datatype that can be
1936 * shared by multiple datasets in the file.
1937 ***************************************************************************/
1939 GXmlElement* message,
1940 std::string& msg)
1941{
1942 // Read fields
1943 int class_version = fread_int(fptr, 1);
1944 int bits1 = fread_int(fptr, 1);
1945 int bits2 = fread_int(fptr, 1);
1946 int bits3 = fread_int(fptr, 1);
1947 int size = fread_int(fptr, 4); // Size of datatype elements in Bytes
1948
1949 // Extract version and class
1950 int version = class_version / 16;
1951 int cls = class_version & 15;
1952
1953 // Check version
1954 if (version < 1 || version > 5) {
1955 std::string msg = "Datatype version "+gammalib::str(version)+
1956 " is not between 1 and 5."
1957 " Please specify a valid HDF5 file.";
1959 }
1960
1961 // Check class
1962 if (cls < 0 || cls > 11) {
1963 std::string msg = "Datatype class "+gammalib::str(cls)+
1964 " is not between 0 and 11."
1965 " Please specify a valid HDF5 file.";
1967 }
1968
1969 // Get classname
1970 std::string clsname = gammalib::hdf5::classname(cls);
1971
1972 // Add version, class and size to XML element
1973 message->attribute("version", gammalib::str(version));
1974 message->attribute("class", gammalib::str(cls));
1975 message->attribute("classname", clsname);
1976 message->attribute("size", gammalib::str(size));
1977
1978 // Debugging: add version, class and size
1979 #if defined(G_HDF5_DEBUG)
1980 if (msg.length() > 0) {
1981 msg += ", version=" + gammalib::str(version) +
1982 ", class=" + gammalib::str(cls) +
1983 ", classname=\"" + clsname + "\"" +
1984 ", size=" + gammalib::str(size);
1985 }
1986 #endif
1987
1988 // Handle class specific information
1989 switch (cls) {
1990
1991 // Fixed point
1992 case 0: {
1993 // Decode Bit fields
1994 int order = bits1 & 1; // 0=Little-endian, 1=Big-endian
1995 int lopad = (bits1 & 2) / 2; // Lo-pad
1996 int hipad = (bits1 & 4) / 4; // High-pad
1997 int sign = (bits1 & 8) / 8; // 0=Unsigned, 1=Signed
1998
1999 // Read properties
2000 int offset = fread_int(fptr, 2);
2001 int precision = fread_int(fptr, 2);
2002
2003 // Add XML attributes
2004 message->attribute("order", gammalib::str(order));
2005 if (order == 0) {
2006 message->attribute("ordername", "little-endian");
2007 }
2008 else {
2009 message->attribute("ordername", "big-endian");
2010 }
2011 message->attribute("signed", gammalib::str(sign));
2012 message->attribute("offset", gammalib::str(offset));
2013 message->attribute("precision", gammalib::str(precision));
2014 message->attribute("lopad", gammalib::str(lopad));
2015 message->attribute("hipad", gammalib::str(hipad));
2016 break;
2017 }
2018
2019 // Floating point
2020 case 1: {
2021 break;
2022 }
2023
2024 // Time
2025 case 2: {
2026 break;
2027 }
2028
2029 // String
2030 case 3: {
2031 break;
2032 }
2033
2034 // Bit field
2035 case 4: {
2036 break;
2037 }
2038
2039 // Opaque
2040 case 5: {
2041 break;
2042 }
2043
2044 // Compound
2045 case 6: {
2046 break;
2047 }
2048
2049 // Reference
2050 case 7: {
2051 break;
2052 }
2053
2054 // Enumerated
2055 case 8: {
2056 // Decode Bit fields
2057 int number = bits1 + bits2 * 256;
2058
2059 // Add XML attributes
2060 message->attribute("number", gammalib::str(number));
2061
2062 // Debugging: add attributes
2063 #if defined(G_HDF5_DEBUG)
2064 if (msg.length() > 0) {
2065 msg += ", number=" + gammalib::str(number);
2066 }
2067 #endif
2068
2069 // Version 1 or 2
2070 if ((version == 1) || (version == 2)) {
2071
2072 // Read base type datatype
2073 GXmlElement* basetype = message->append("basetype");
2074 std::string empty;
2075 read_message_datatype(fptr, basetype, empty);
2076
2077 // Allocate string vectors for name and values
2078 std::vector<std::string> names;
2079 std::vector<std::string> values;
2080
2081 // Read names
2082 for (int i = 0; i < number; ++i) {
2083
2084 // Read multiples of 8 Bytes until a NULL character is
2085 // encountered
2086 std::string name;
2087 bool looping = true;
2088 while (looping) {
2089
2090 // Read next 8 Bytes
2091 std::string segment = fread_data(fptr, 8);
2092
2093 // Search for termination NULL
2094 for (int k = 0; k < 8; ++k) {
2095 if (segment[k] == '\0') { // found
2096 if (k > 0) { // string is not empty
2097 name += segment.substr(0,k); // then add substring
2098 }
2099 looping = false; // stop looping
2100 break; // exit loop
2101 }
2102 }
2103
2104 // If we are still looping no termination NULL was found.
2105 // We hence add the entire segment
2106 if (looping) {
2107 name += segment;
2108 }
2109
2110 } // endwhile: looping over 8 Byte junks
2111
2112 // Append name
2113 names.push_back(name);
2114
2115 } // endfor: looped over names
2116
2117 // Read values
2118 for (int i = 0; i < number; ++i) {
2119
2120 // Read value
2121 std::string value = fread_data_as_string(fptr, basetype);
2122
2123 // Append value
2124 values.push_back(value);
2125
2126 } // endfor: looped over values
2127
2128 // Create XML elements for all name/value pairs
2129 for (int i = 0; i < number; ++i) {
2130
2131 // Create name XML element
2132 GXmlElement* enumeration = message->append("enumeration");
2133
2134 // Set name and value
2135 enumeration->attribute("name", names[i]);
2136 enumeration->attribute("value", values[i]);
2137
2138 } // endfor: looped over name/value pairs
2139
2140 } // endif: version 1 or 2
2141 break;
2142 }
2143
2144 // Variable-Length
2145 case 9: {
2146 // Decode Bit fields
2147 int type = bits1 & 15; // 0=Sequence, 1=String
2148 int padding = bits1 / 16; // 0=Null terminated, 1=Null pad, 2=Space pad
2149 int charset = bits2 & 15; // 0=ASCII, 1=UTF-8
2150
2151 // Read parent type datatype (not used for string)
2152 GXmlElement* parenttype = message->append("parenttype");
2153 std::string empty;
2154 read_message_datatype(fptr, parenttype, empty);
2155
2156 // Add XML attributes
2157 message->attribute("type", gammalib::str(type));
2158 message->attribute("padding", gammalib::str(padding));
2159 message->attribute("charset", gammalib::str(charset));
2160
2161 // Debugging: add version, class and size
2162 #if defined(G_HDF5_DEBUG)
2163 if (msg.length() > 0) {
2164 msg += ", type=" + gammalib::str(type) +
2165 ", padding=" + gammalib::str(padding) +
2166 ", charset=" + gammalib::str(charset);
2167 }
2168 #endif
2169 break;
2170 }
2171
2172 // Array
2173 case 10: {
2174 break;
2175 }
2176
2177 // Complex
2178 case 11: {
2179 break;
2180 }
2181
2182 // This should never be reacked
2183 default:
2184 break;
2185
2186 } // endwsitch: Handled class specific information
2187
2188 // Return
2189 return;
2190}
2191
2192
2193/***********************************************************************//**
2194 * @brief Read Data Storage - Layout message
2195 *
2196 * @param[in] fptr File pointer.
2197 * @param[in] message Pointer to XML element.
2198 * @param[in] msg String for debugging messages.
2199 *
2200 * @exception GException::invalid_value
2201 * Invalid data storage layout version or class
2202 ***************************************************************************/
2204 GXmlElement* message,
2205 std::string& msg)
2206{
2207 // Read version
2208 int version = fread_int(fptr, 1);
2209
2210 // Version dependent treatment
2211 switch (version) {
2212
2213 // Version 1 or 2
2214 case 1:
2215 case 2: {
2216 break;
2217 }
2218
2219 case 3: {
2220 // Read layout class
2221 int cls = fread_int(fptr, 1);
2222
2223 // Add attribute to XML element
2224 message->attribute("class", gammalib::str(cls));
2225
2226 // Debugging: add class
2227 #if defined(G_HDF5_DEBUG)
2228 msg += ", class=" + gammalib::str(cls);
2229 #endif
2230
2231 // Class dependent treatment
2232 switch (cls) {
2233
2234 // Compact layout
2235 case 0: {
2236 // Add attribute to XML element
2237 message->attribute("classname", "compact");
2238
2239 // Debugging: add layout class
2240 #if defined(G_HDF5_DEBUG)
2241 msg += ", compact";
2242 #endif
2243 break;
2244 }
2245
2246 // Contiguous layout
2247 case 1: {
2248 // Add attribute to XML element
2249 message->attribute("classname", "contiguous");
2250
2251 // Debugging: add layout class
2252 #if defined(G_HDF5_DEBUG)
2253 msg += ", contiguous";
2254 #endif
2255
2256 // Read fields
2257 uint64_t address = fread_uint64(fptr, m_offset);
2258 uint64_t size = fread_uint64(fptr, m_length);
2259
2260 // Add attributes to XML element
2261 message->attribute("address", gammalib::str(address));
2262 message->attribute("size", gammalib::str(size));
2263
2264 // Debugging: add address and size
2265 #if defined(G_HDF5_DEBUG)
2266 msg += ", address=" + hexaddress(address) +
2267 ", size=" + gammalib::str(size);
2268 #endif
2269 break;
2270 }
2271
2272 // Chunked layout
2273 case 2: {
2274 // Add attribute to XML element
2275 message->attribute("classname", "chunked");
2276
2277 // Debugging: add layout class
2278 #if defined(G_HDF5_DEBUG)
2279 msg += ", chunked";
2280 #endif
2281
2282 // Read fields
2283 int dimensions = fread_int(fptr, 1);
2284 uint64_t address = fread_uint64(fptr, m_offset);
2285
2286 // Add attributes to XML element
2287 message->attribute("address", gammalib::str(address));
2288 message->attribute("dimensions", gammalib::str(dimensions));
2289
2290 // Debugging: add address and dimension
2291 #if defined(G_HDF5_DEBUG)
2292 msg += ", address=" + hexaddress(address) +
2293 ", dimensions=" + gammalib::str(dimensions);
2294 #endif
2295
2296 // Initialise number of elements
2297 int elements = 0;
2298
2299 // Loop over dimensions
2300 for (int i = 0; i < dimensions; ++i) {
2301
2302 // Read size
2303 int size = fread_int(fptr, 4);
2304
2305 // Update number of elements
2306 if (i == 0) {
2307 elements = size;
2308 }
2309 else {
2310 elements *= size;
2311 }
2312
2313 // Add attribute to XML element
2314 message->attribute("size"+gammalib::str(i), gammalib::str(size));
2315
2316 // Debugging: add size
2317 #if defined(G_HDF5_DEBUG)
2318 msg += ", size" + gammalib::str(i) +
2319 "=" + gammalib::str(size);
2320 #endif
2321
2322 } // endfor: looped over dimensions
2323
2324 // Add attributes to XML element
2325 message->attribute("elements", gammalib::str(elements));
2326
2327 // Debugging: add elements
2328 #if defined(G_HDF5_DEBUG)
2329 msg += ", elements=" + gammalib::str(elements);
2330 #endif
2331
2332 // Create XML element for B-tree that holds addresses of chunked
2333 // data
2334 GXmlElement* btree = message->append("btree");
2335
2336 // Read B-tree
2337 read_btree_chunked(fptr, address, dimensions, btree);
2338 break;
2339 }
2340
2341 // Invalid layout class
2342 default: {
2343 std::string msg = "Data storage layout class "+gammalib::str(cls)+
2344 " is not between 0 and 2."
2345 " Please specify a valid HDF5 file.";
2347 break;
2348 }
2349 } // endswitch: class
2350 break;
2351 }
2352
2353 // Invalid version
2354 default: {
2355 std::string msg = "Data storage layout version "+gammalib::str(version)+
2356 " is not between 1 and 3."
2357 " Please specify a valid HDF5 file.";
2359 break;
2360 }
2361 } // endswitch: version
2362
2363 // Return
2364 return;
2365}
2366
2367
2368/***********************************************************************//**
2369 * @brief Read Data Storage - Filter pipeline message
2370 *
2371 * @param[in] fptr File pointer.
2372 * @param[in] type Message type.
2373 * @param[in] msg String for debugging messages.
2374 *
2375 * @exception GException::invalid_value
2376 * Invalid data filter pipeline message version
2377 ***************************************************************************/
2379 GXmlElement* message,
2380 std::string& msg)
2381{
2382 // Read version
2383 int version = fread_int(fptr, 1);
2384
2385 // Version dependent treatment
2386 switch (version) {
2387
2388 // Version 1
2389 case 1: {
2390
2391 // Read fields
2392 int filters = fread_int(fptr, 1);
2393 fread_zero(fptr, 6);
2394
2395 // Add attribute to XML element
2396 message->attribute("filters", gammalib::str(filters));
2397
2398 // Debugging: add filters
2399 #if defined(G_HDF5_DEBUG)
2400 msg += ", filters=" + gammalib::str(filters);
2401 #endif
2402
2403 // Loop over filter descriptions
2404 for (int i = 0; i < filters; ++i) {
2405
2406 // Add filter XML element
2407 GXmlElement* filter = message->append("filter");
2408
2409 // Read fields
2410 int id = fread_int(fptr, 2);
2411 int name_length = fread_int(fptr, 2);
2412 int flags = fread_int(fptr, 2);
2413 int number_of_values = fread_int(fptr, 2);
2414
2415 // Read filter name
2416 std::string name;
2417 if (name_length > 0) {
2418 name = fread_string(fptr, name_length);
2419 }
2420
2421 // Add attributes to XML element
2422 filter->attribute("name", name);
2423 filter->attribute("id", gammalib::str(id));
2424 filter->attribute("flags", gammalib::str(flags));
2425
2426 // Loop over client data values
2427 for (int k = 0; k < number_of_values; ++k) {
2428
2429 // Read client data
2430 int client_data = fread_int(fptr, 4);
2431
2432 // Create XML element to homd client data
2433 GXmlElement* data = filter->append("data");
2434
2435 // Create XML text node
2436 GXmlText text(gammalib::str(client_data));
2437
2438 // Append text node
2439 data->append(text);
2440
2441 } // endfor: looped over client data
2442
2443 } // endfor: looped over filters
2444 break;
2445 }
2446
2447 // Version 2
2448 case 2: {
2449 break;
2450 }
2451
2452 // Invalid version
2453 default: {
2454 std::string msg = "Data storage filter pipeline version " +
2455 gammalib::str(version) + " is not one of 1 or 2."
2456 " Please specify a valid HDF5 file.";
2458 break;
2459 }
2460 } // endswitch: version
2461
2462 // Return
2463 return;
2464}
2465
2466
2467/***********************************************************************//**
2468 * @brief Read Attribute message
2469 *
2470 * @param[in] fptr File pointer.
2471 * @param[in] type Message type.
2472 * @param[in] msg String for debugging messages.
2473 *
2474 * @exception GException::invalid_value
2475 * Invalid attribute version
2476 *
2477 * The Attribute message is used to store objects in the HDF5 file which are
2478 * used as attributes, or "metadata" about the current object. An attribute
2479 * is a small dataset; it has a name, a datatype, a dataspace, and raw data.
2480 *
2481 * Since attributes are stored in the object header, they should be
2482 * relatively small (in other words, less than 64KB). They can be associated
2483 * with any type of object which has an object header (groups, datasets, or
2484 * committed (named) datatypes).
2485 *
2486 * Note: Attributes on an object must have unique names: the HDF5 Library
2487 * currently enforces this by causing the creation of an attribute with a
2488 * duplicate name to fail. Attributes on different objects may have the same
2489 * name, however.
2490 ***************************************************************************/
2492 GXmlElement* message,
2493 std::string& msg)
2494{
2495 // Read version
2496 int version = fread_int(fptr, 1);
2497
2498 // Version dependent treatment
2499 switch (version) {
2500
2501 // Version 1
2502 case 1: {
2503 // Read fields
2504 fread_zero(fptr, 1);
2505 int name_size = pad2eight(fread_int(fptr, 2));
2506 int datatype_size = pad2eight(fread_int(fptr, 2));
2507 int dataspace_size = pad2eight(fread_int(fptr, 2));
2508
2509 // Read attribute name
2510 std::string name = fread_string(fptr, name_size);
2511
2512 // Add attributes to XML element
2513 message->attribute("name", name);
2514
2515 // Debugging: add message name
2516 #if defined(G_HDF5_DEBUG)
2517 msg += ", name=" + name;
2518 #endif
2519
2520 // Read datatype
2521 uint64_t address = std::ftell(fptr);
2522 GXmlElement* datatype = message->append("datatype");
2523 read_message_datatype(fptr, datatype, msg);
2524 std::fseek(fptr, address+datatype_size, SEEK_SET);
2525
2526 // Read dataspace
2527 address = std::ftell(fptr);
2528 GXmlElement* dataspace = message->append("dataspace");
2529 read_message_dataspace(fptr, dataspace, msg);
2530 std::fseek(fptr, address+dataspace_size, SEEK_SET);
2531
2532 // Optionally read message data
2533 if (datatype->has_attribute("size") && dataspace->has_attribute("elements")) {
2534
2535 // Extract data element size and number of elements
2536 int size = gammalib::toint(datatype->attribute("size"));
2537 int cls = gammalib::toint(datatype->attribute("class"));
2538 int sign = gammalib::toint(datatype->attribute("signed"));
2539 int elements = gammalib::toint(dataspace->attribute("elements"));
2540
2541 // Special handling for variable-length data
2542 if (cls == 9) {
2543
2544 // Get variable-length type
2545 int type = gammalib::toint(datatype->attribute("type"));
2546
2547 // Read fields (sequence length, collection address, object index)
2548 uint32_t sequence_length = fread_uint32(fptr, 4);
2549 uint64_t collection_address = fread_uint64(fptr, m_offset);
2550 int object_index = fread_int(fptr, 4);
2551
2552 // Add attributes to XML element
2553 message->attribute("sequence_length", gammalib::str(sequence_length));
2554 message->attribute("collection_address", gammalib::str(collection_address));
2555 message->attribute("object_index", gammalib::str(object_index));
2556
2557 // Debugging: add attributes
2558 #if defined(G_HDF5_DEBUG)
2559 msg += ", sequence_length="+gammalib::str(sequence_length) +
2560 ", collection_address="+hexaddress(collection_address) +
2561 ", object_index="+gammalib::str(object_index);
2562 #endif
2563
2564 // If type is string then get attribute string from global heap
2565 if (type == 1) {
2566
2567 // Get attribute string
2568 std::string value = global_heap_string(fptr,
2569 collection_address,
2570 object_index,
2571 sequence_length);
2572
2573 // Add value to XML element
2574 message->attribute("value", value);
2575
2576 // Debugging: add value
2577 #if defined(G_HDF5_DEBUG)
2578 msg += ", value=\""+value+"\"";
2579 #endif
2580
2581 } // endif: type was string
2582 break;
2583
2584 } // endif: handled variable-length data
2585
2586 // ... otherwise handle remaining classes
2587 else {
2588
2589 // Compute data size
2590 int data_size = size * elements;
2591
2592 // If we have data that decode it
2593 if (data_size > 0) {
2594
2595 // If there is a single element then set it as value attribute
2596 if (elements == 1) {
2597
2598 // Read value as string
2599 std::string value = fread_data_as_string(fptr, datatype);
2600
2601 // Set attribute
2602 message->attribute("value", value);
2603
2604 } // endif: there was a single attribute
2605
2606 // ... otherwise add value tags
2607 else {
2608
2609 // Loop over elements
2610 for (int i = 0; i < elements; ++i) {
2611
2612 // Create value XML element
2613 GXmlElement* value = message->append("value");
2614
2615 // Read value as string
2616 std::string string = fread_data_as_string(fptr, datatype);
2617
2618 // Create XML text node
2619 GXmlText text(string);
2620
2621 // Append text node
2622 value->append(text);
2623
2624 } // endfor: looped over elements
2625
2626 } // endelse: added value tags
2627
2628 } // endif: there were data
2629
2630 } // endelse: handle remaining classes
2631
2632 } // endif: relevant attributes present
2633 break;
2634 }
2635
2636 // Version 2
2637 case 2: {
2638 break;
2639 }
2640
2641 // Version 3
2642 case 3: {
2643 break;
2644 }
2645
2646 // Invalid version
2647 default: {
2648 std::string msg = "Attribute version "+gammalib::str(version)+
2649 " is not between 1 and 3."
2650 " Please specify a valid HDF5 file.";
2652 break;
2653 }
2654
2655 } // endswitch: version
2656
2657 // Return
2658 return;
2659}
2660
2661
2662/***********************************************************************//**
2663 * @brief Get string from global heap
2664 *
2665 * @param[in] fptr File pointer.
2666 * @param[in] address Collection address (address of global heap).
2667 * @param[in] id Heap object index.
2668 * @param[in] length Length of string.
2669 * @return String from global heap.
2670 *
2671 * @exception GException::invalid_value
2672 * Invalid group heap signature
2673 * Invalid group heap version
2674 * Object index not found in global heap collection
2675 * Length of string does not correspond to length of object
2676 *
2677 * Get string from the global heap using it's collection address @p address
2678 * and the heap object index @p id.
2679 *
2680 * If the requested global heap does not yet exist in the XML object it is
2681 * read from the file and stored into a "gobal_heap" element. Multiple global
2682 * heap elements may exist and are identified by their file address.
2683 ***************************************************************************/
2684std::string GHdf5::global_heap_string(FILE* fptr,
2685 const uint64_t& address,
2686 const int& id,
2687 const uint32_t& length)
2688{
2689 // Set global heap signature
2690 const char global_heap_signature[] = {'G', 'C', 'O', 'L'};
2691
2692 // Initialise string
2693 std::string string;
2694
2695 // Convert address into string
2696 std::string str_address = gammalib::str(address);
2697
2698 // Get "ROOT" entry in file
2699 GXmlElement* root = m_xml.element("entry");
2700
2701 // Initialise pointer to group heap
2702 GXmlElement* global_heap = NULL;
2703
2704 // Search all global heaps for the one with the appropriate address
2705 int elements = root->elements("global_heap");
2706 for (int i = 0; i < elements; ++i) {
2707 if (root->element("global_heap", i)->attribute("address") == str_address) {
2708 global_heap = root->element("global_heap", i);
2709 }
2710 }
2711
2712 // If no group heap with appropriate address was found then create one
2713 // and read collection information from file
2714 if (global_heap == NULL) {
2715
2716 // Create group heap
2717 global_heap = root->append("global_heap");
2718
2719 // Store address as attribute
2720 global_heap->attribute("address", str_address);
2721
2722 // Get current file pointer position
2723 uint64_t current_pos = std::ftell(fptr);
2724
2725 // Move file pointer position to group heap
2726 std::fseek(fptr, address, SEEK_SET);
2727
2728 // Read group heap signature
2729 std::string signature = fread_string(fptr, 4);
2730
2731 // Check signature to verify that we point indeed to a group heap
2732 if (std::strncmp(signature.c_str(), &global_heap_signature[0], 4) != 0) {
2733 std::string msg = "No \"GCOL\" signature found at address "+
2734 hexaddress(address)+" in HDF5 file. "
2735 "Please specify a valid HDF5 file.";
2737 }
2738
2739 // Read version
2740 uint32_t version = fread_uint32(fptr, 1);
2741
2742 // Check version
2743 if (version != 1) {
2744 std::string msg = "Global heap version "+gammalib::str(version)+
2745 " is not 1. Please specify a valid HDF5 file.";
2747 }
2748
2749 // Read fields
2750 fread_zero(fptr, 3);
2751 uint64_t size = fread_uint64(fptr, m_length);
2752
2753 // Store attributes
2754 global_heap->attribute("version", gammalib::str(version));
2755 global_heap->attribute("size", gammalib::str(size));
2756
2757 // Set object header size
2758 int object_header_size = 8 + m_length;
2759
2760 // Loop over global heap collection without knowing a priori how many
2761 // objects are present in the heap
2762 int read = 0;
2763 while (true) {
2764
2765 // Compute remaining Bytes
2766 int remaining = size - read;
2767
2768 // If there is not enough space for an object header then
2769 // break
2770 if (remaining < object_header_size) {
2771 break;
2772 }
2773
2774 // Read object header
2775 int index = fread_int(fptr, 2);
2776 int ref_count = fread_int(fptr, 2);
2777 fread_zero(fptr, 4);
2778 uint64_t object_size = fread_uint64(fptr, m_length);
2779 read += object_header_size;
2780
2781 // If the object header index is zero we reached the end
2782 // and break
2783 if (index == 0) {
2784 break;
2785 }
2786
2787 // Read object data as string
2788 std::string value = fread_string(fptr, object_size);
2789 read += object_size;
2790
2791 // Read additional storage space to round up to 8 bytes
2792 int padded = pad2eight(object_size) - object_size;
2793 if (padded > 0) {
2794 fread_data(fptr, padded);
2795 read += padded;
2796 }
2797
2798 // Create object element
2799 GXmlElement* object = global_heap->append("object");
2800
2801 // Store attributes
2802 object->attribute("index", gammalib::str(index));
2803 object->attribute("ref_count", gammalib::str(ref_count));
2804 object->attribute("object_size", gammalib::str(object_size));
2805 object->attribute("value", value);
2806
2807 } // endwhile: looped over global heap collection
2808
2809 // Recover file pointer position prior to reading group heap
2810 std::fseek(fptr, current_pos, SEEK_SET);
2811
2812 } // endif: created global heap and filled it with collection information
2813
2814 // Get number of objects in global heap
2815 int objects = global_heap->elements("object");
2816
2817 // Initialise found flag
2818 bool found = false;
2819
2820 // Loop over objects
2821 for (int i = 0; i < objects; ++i) {
2822
2823 // Get pointer to object
2824 GXmlElement* object = global_heap->element("object", i);
2825
2826 // If the heap object index was found then return string
2827 if (gammalib::toint(object->attribute("index")) == id) {
2828
2829 // Check that length is consistent
2830 int object_length = gammalib::toint(object->attribute("object_size"));
2831 if (object_length != length) {
2832 std::string msg = "Length "+object->attribute("object_size")+
2833 " of object with index "+gammalib::str(id)+
2834 " in global heap at address "+
2835 hexaddress(address)+" in HDF5 file does "
2836 "not correspond to the expected length "+
2837 gammalib::str(length)+". "
2838 "Please specify a valid HDF5 file.";
2840 }
2841
2842 // Extract string
2843 string = object->attribute("value");
2844
2845 // Signal that string was found
2846 found = true;
2847
2848 // Exit search loop
2849 break;
2850 }
2851
2852 } // endfor: looped over collection objects
2853
2854 // If object index was not found than throw an exception
2855 if (!found) {
2856 std::string msg = "No object with index "+gammalib::str(id)+
2857 " found in global heap at address "+
2858 hexaddress(address)+" in HDF5 file. "
2859 "Please specify a valid HDF5 file.";
2861 }
2862
2863 // Return string
2864 return string;
2865}
2866
2867
2868/***********************************************************************//**
2869 * @brief Show debug message
2870 *
2871 * @param[in] msg Debug message.
2872 * @param[in] indent Number of spaces to indent
2873 ***************************************************************************/
2874void GHdf5::debug_msg(const std::string& msg, const int& indent)
2875{
2876 // Indent
2877 for (int i = 0; i < indent; ++i) {
2878 std::cout << " ";
2879 }
2880
2881 // Print message
2882 std::cout << msg << std::endl;
2883
2884 // Return
2885 return;
2886}
2887
2888
2889/***********************************************************************//**
2890 * @brief Format address for debugging
2891 *
2892 * @param[in] address Address.
2893 * @return String with address hexadecimal format.
2894 *
2895 * Returns a string with the @p address in hexadecimal format.
2896 ***************************************************************************/
2897std::string GHdf5::hexaddress(const uint64_t& address)
2898{
2899 // Set address string
2900 std::string string = "0x" + gammalib::str(address, "%x");
2901
2902 // Return string
2903 return string;
2904}
2905
2906
2907/***********************************************************************//**
2908 * @brief Extract string from position until next null termination
2909 *
2910 * @param[in] string String.
2911 * @param[in] pos Start position in string.
2912 * @return Extracted string.
2913 *
2914 * Returns extracted string.
2915 ***************************************************************************/
2916std::string GHdf5::extract(const std::string& string, const int& pos)
2917{
2918 // Initialise result
2919 std::string result = "";
2920
2921 // Get maximum string position
2922 int n = string.length();
2923
2924 // Loop over string until either a \0 or the end of the string is reached
2925 for (int i = pos; i < n; ++i) {
2926 if (string[i] != '\0') {
2927 result += string[i];
2928 }
2929 else {
2930 break;
2931 }
2932 }
2933
2934 // Return result
2935 return result;
2936}
2937
2938
2939/***********************************************************************//**
2940 * @brief Pad number of Bytes to 8 Bytes
2941 *
2942 * @param[in] nbytes Number of Bytes.
2943 * @return Padded number of Bytes to 8 Bytes.
2944 *
2945 * Returns a padded number of Bytes so that @p nbytes becomes a multiple of
2946 * 8 Bytes.
2947 ***************************************************************************/
2948int GHdf5::pad2eight(const int& nbytes)
2949{
2950 // Initialise result
2951 int result = nbytes;
2952
2953 // If nbytes is not a multiple of 8 then pad it to a multiple of 8
2954 if (result % 8 != 0) {
2955 result = ((result / 8) + 1) * 8;
2956 }
2957
2958 // Return result
2959 return result;
2960}
2961
2962
2963/*==========================================================================
2964 = =
2965 = Public HDF5 support functions =
2966 = =
2967 ==========================================================================*/
2968
2969/***********************************************************************//**
2970 * @brief Read data from HDF5 file
2971 *
2972 * @param[in] fptr File pointer.
2973 * @param[in] nbytes Number of Bytes to read (>0).
2974 * @returns String holding the data that was read.
2975 *
2976 * @exception GException::invalid_argument
2977 * Number of Bytes not positive
2978 * @exception GException::runtime_error
2979 * Attempt to read beyond end of file
2980 *
2981 * Reads @p nbytes from the current position of the file pointer @p fptr into
2982 * a string.
2983 ***************************************************************************/
2984std::string gammalib::hdf5::fread_data(FILE* fptr, const int& nbytes)
2985{
2986 // Check that nbytes is not zero
2987 if (nbytes < 1) {
2988 std::string msg = "Non positive number "+gammalib::str(nbytes)+
2989 " of Bytes specified. Please specify a number "
2990 "larger than 0.";
2992 }
2993
2994 // Initialise string
2995 std::string string;
2996
2997 // Allocate string space
2998 string.resize(nbytes);
2999
3000 // Read Bytes from file
3001 const std::size_t n = std::fread(&string[0], 1, nbytes, fptr);
3002
3003 // Check number of Bytes read
3004 if (n != nbytes) {
3005 std::string msg = "Attempt to read beyond the end of file. Read "
3006 "only "+gammalib::str(n)+" of "+gammalib::str(nbytes)+
3007 " Bytes from file.";
3009 }
3010
3011 // Return string
3012 return (string);
3013}
3014
3015
3016/***********************************************************************//**
3017 * @brief Read data
3018 *
3019 * @param[in] fptr File pointer.
3020 * @param[in] dataspace Pointer to "Dataspace" message XML element.
3021 * @param[in] datatype Pointer to "Datatype" message XML element.
3022 * @param[in] datalayout Pointer to "DataStorageLayout" message XML element.
3023 * @param[in] datafilter Pointer to "DataStorageFilterPipeline" message XML element.
3024 * @return String holding the data.
3025 *
3026 * @exception GException::invalid_argument
3027 * No "elements" attribute in dataspace
3028 * No "size" attribute in datatype
3029 * No "address" attribute in datalayout
3030 * No "class" attribute in datalayout
3031 * @excaption GException::runtime_error
3032 * Attempt to read beyond end of file
3033 *
3034 * Reads entire data structure and stores the Bytes into a string.
3035 *
3036 * The address from where to read the data is extracted from @p datalayout.
3037 * The current position of the file pointer @p fptr is not modified by the
3038 * function. The number of Bytes to read is extracted from @p dataspace and
3039 * @p datatype.
3040 *
3041 * If @p datafilter is not NULL, a data filter is applied to the data before
3042 * returning them to the client.
3043 ***************************************************************************/
3044std::string gammalib::hdf5::fread_data(FILE* fptr,
3045 const GXmlElement* dataspace,
3046 const GXmlElement* datatype,
3047 const GXmlElement* datalayout,
3048 const GXmlElement* datafilter)
3049{
3050 // Initialise string
3051 std::string string;
3052
3053 // Check for required attributes
3054 if (!dataspace->has_attribute("elements")) {
3055 std::string msg = "\"Dataspace\" message is missing \"elements\""
3056 " attribute";
3058 }
3059 if (!datatype->has_attribute("size")) {
3060 std::string msg = "\"Datatype\" message is missing \"size\""
3061 " attribute";
3063 }
3064 if (!datalayout->has_attribute("address")) {
3065 std::string msg = "\"DataStorageLayout\" message is missing \"address\""
3066 " attribute";
3068 }
3069 if (!datalayout->has_attribute("class")) {
3070 std::string msg = "\"DataStorageLayout\" message is missing \"class\""
3071 " attribute";
3073 }
3074
3075 // Handle chunked data layout
3076 if (datalayout->attribute("class") == "2") {
3077
3078 //TODO: Implement reading of chunked data
3079
3080 }
3081
3082 // ... handle other layouts
3083 else {
3084
3085 // Get number of elements in dataspace
3086 int elements = gammalib::toint(dataspace->attribute("elements"));
3087
3088 // Continue only if there are elements to read
3089 if (elements > 0) {
3090
3091 // Get size of each element in Bytes
3092 int size = gammalib::toint(datatype->attribute("size"));
3093
3094 // Continue only if the size if positive
3095 if (size > 0) {
3096
3097 // Get address from where data should be read
3098 uint64_t address = gammalib::toulonglong(datalayout->attribute("address"));
3099
3100 // Determine number of Bytes to read
3101 int nbytes = elements * size;
3102
3103 // Allocate string space
3104 string.resize(nbytes);
3105
3106 // Get current file pointer address
3107 uint64_t current_address = std::ftell(fptr);
3108
3109 // Move file pointer to address
3110 std::fseek(fptr, address, SEEK_SET);
3111
3112 // Read Bytes from file
3113 const std::size_t n = std::fread(&string[0], 1, nbytes, fptr);
3114
3115 // Check number of Bytes read
3116 if (n != nbytes) {
3117 std::string msg = "Attempt to read beyond the end of file. Read "
3118 "only "+gammalib::str(n)+" of "+gammalib::str(nbytes)+
3119 " Bytes from file.";
3121 }
3122
3123 // Restore file pointer to initial address
3124 std::fseek(fptr, current_address, SEEK_SET);
3125
3126 } // endif: element size was positive
3127
3128 } // endif: there were elements to read
3129
3130 // Optionally apply data filter
3131 if (datafilter != NULL) {
3132 string = data_filter(string, datafilter);
3133 }
3134
3135 } // endelse: handles non-chunked layouts
3136
3137 // Return string
3138 return string;
3139}
3140
3141
3142/***********************************************************************//**
3143 * @brief Read data chunk
3144 *
3145 * @param[in] fptr File pointer.
3146 * @param[in] chunk Pointer to "key" XML element.
3147 * @param[in] dataspace Pointer to "Dataspace" message XML element.
3148 * @param[in] datatype Pointer to "Datatype" message XML element.
3149 * @param[in] datalayout Pointer to "DataStorageLayout" message XML element.
3150 * @param[in] datafilter Pointer to "DataStorageFilterPipeline" message XML element.
3151 * @return String holding the data chunk.
3152 *
3153 * @exception GException::invalid_argument
3154 * No "address" attribute in chunk key
3155 * No "size" attribute in chunk key
3156 * No "class" attribute in datalayout
3157 * "DataStorageLayout" is not chunked
3158 * @exception GException::runtime_error
3159 * Attempt to read beyond end of file
3160 *
3161 * Reads a data chunk and stores the Bytes into a string.
3162 *
3163 * The address from where to read the data and the number of Bytes to read
3164 * is extracted from @p chunk.
3165 *
3166 * The current position of the file pointer @p fptr is not modified by the
3167 * function.
3168 *
3169 * If @p datafilter is not NULL, a data filter is applied to the data before
3170 * returning them to the client.
3171 ***************************************************************************/
3173 const GXmlElement* chunk,
3174 const GXmlElement* dataspace,
3175 const GXmlElement* datatype,
3176 const GXmlElement* datalayout,
3177 const GXmlElement* datafilter)
3178{
3179 // Initialise string
3180 std::string string;
3181
3182 // Check for required attributes
3183 if (!chunk->has_attribute("address")) {
3184 std::string msg = "Chunk key message is missing \"address\""
3185 " attribute";
3187 }
3188 if (!chunk->has_attribute("size")) {
3189 std::string msg = "Chunk key message is missing \"size\""
3190 " attribute";
3192 }
3193 if (!datalayout->has_attribute("class")) {
3194 std::string msg = "\"DataStorageLayout\" message is missing \"class\""
3195 " attribute";
3197 }
3198
3199 // Check that ataStorageLayout is chunked
3200 if (datalayout->attribute("class") != "2") {
3201 std::string msg = "\"DataStorageLayout\" is " +
3202 datalayout->attribute("class") + " which is not "
3203 "chunked. Please specify a chunked layout.";
3205 }
3206
3207 // Get address and size
3208 uint64_t address = gammalib::toulonglong(chunk->attribute("address"));
3209 int size = gammalib::toint(chunk->attribute("size"));
3210
3211 // Allocate string space
3212 string.resize(size);
3213
3214 // Get current file pointer address
3215 uint64_t current_address = std::ftell(fptr);
3216
3217 // Move file pointer to address
3218 std::fseek(fptr, address, SEEK_SET);
3219
3220 // Read Bytes from file
3221 const std::size_t n = std::fread(&string[0], 1, size, fptr);
3222
3223 // Check number of Bytes read
3224 if (n != size) {
3225 std::string msg = "Attempt to read beyond the end of file. Read "
3226 "only "+gammalib::str(n)+" of "+gammalib::str(size)+
3227 " Bytes from file.";
3229 }
3230
3231 // Restore file pointer to initial address
3232 std::fseek(fptr, current_address, SEEK_SET);
3233
3234 // Optionally apply data filter
3235 if (datafilter != NULL) {
3236 string = data_filter(string, datafilter);
3237 }
3238
3239 // Return string
3240 return string;
3241}
3242
3243
3244/***********************************************************************//**
3245 * @brief Read data as integer from HDF5 file
3246 *
3247 * @param[in] fptr File pointer.
3248 * @param[in] nbytes Number of Bytes to read (1...4).
3249 * @returns Integer.
3250 *
3251 * @exception GException::out_of_range
3252 * Number of Bytes not in valid range
3253 * GException::runtime_error
3254 * Attempt to read beyond end of file
3255 ***************************************************************************/
3256int gammalib::hdf5::fread_int(FILE* fptr, const int& nbytes)
3257{
3258 // Initialise buffer for reading
3259 char buffer[4];
3260
3261 // Check that nbytes is in valid range
3262 if (nbytes < 1 || nbytes > 4) {
3263 throw GException::out_of_range(G_FREAD_INT, "Number of bytes", nbytes, 4);
3264 }
3265
3266 // Read Bytes from file
3267 const std::size_t n = std::fread(&buffer[0], 1, nbytes, fptr);
3268
3269 // Check number of Bytes read
3270 if (n != nbytes) {
3271 std::string msg = "Attempt to read beyond the end of file; read "
3272 "only "+gammalib::str(n)+" of "+gammalib::str(nbytes)+
3273 " Bytes from file.";
3275 }
3276
3277 // Initialise integer
3278 int integer = 0;
3279
3280 // Convert buffer into integer
3281 for (int i = 0, shift = 0; i < nbytes; ++i, shift += 8) {
3282 integer += (unsigned char)buffer[i] << shift;
3283 }
3284
3285 // Return integer
3286 return (integer);
3287}
3288
3289
3290/***********************************************************************//**
3291 * @brief Read data as unsiged 32 Bit integer from HDF5 file
3292 *
3293 * @param[in] fptr File pointer.
3294 * @param[in] nbytes Number of Bytes to read (1...4).
3295 * @returns Unsiged 32 Bit integer.
3296 *
3297 * @exception GException::out_of_range
3298 * Number of Bytes not in valid range
3299 * GException::runtime_error
3300 * Attempt to read beyond end of file
3301 ***************************************************************************/
3302uint32_t gammalib::hdf5::fread_uint32(FILE* fptr, const int& nbytes)
3303{
3304 // Initialise buffer for reading
3305 char buffer[4];
3306
3307 // Check that nbytes is in valid range
3308 if (nbytes < 1 || nbytes > 4) {
3309 throw GException::out_of_range(G_FREAD_UINT32, "Number of bytes", nbytes, 8);
3310 }
3311
3312 // Read Bytes from file
3313 const std::size_t n = std::fread(&buffer[0], 1, nbytes, fptr);
3314
3315 // Check number of Bytes read
3316 if (n != nbytes) {
3317 std::string msg = "Attempt to read beyond the end of file; read "
3318 "only "+gammalib::str(n)+" of "+gammalib::str(nbytes)+
3319 " Bytes from file.";
3321 }
3322
3323 // Initialise unsigned 32 Bit integer
3324 uint32_t integer = 0;
3325
3326 // Convert buffer into unsigned 32 Bit integer
3327 for (int i = 0, shift = 0; i < nbytes; ++i, shift += 8) {
3328 integer += (unsigned char)buffer[i] << shift;
3329 }
3330
3331 // Return unsigned 32 Bit integer
3332 return (integer);
3333}
3334
3335
3336/***********************************************************************//**
3337 * @brief Read data as unsiged 64 Bit integer from HDF5 file
3338 *
3339 * @param[in] fptr File pointer.
3340 * @param[in] nbytes Number of Bytes to read (1...8).
3341 * @returns Unsiged 64 Bit integer.
3342 *
3343 * @exception GException::out_of_range
3344 * Number of Bytes not in valid range
3345 * GException::runtime_error
3346 * Attempt to read beyond end of file
3347 ***************************************************************************/
3348uint64_t gammalib::hdf5::fread_uint64(FILE* fptr, const int& nbytes)
3349{
3350 // Initialise buffer for reading
3351 char buffer[8];
3352
3353 // Check that nbytes is in valid range
3354 if (nbytes < 1 || nbytes > 8) {
3355 throw GException::out_of_range(G_FREAD_UINT64, "Number of bytes", nbytes, 8);
3356 }
3357
3358 // Read Bytes from file
3359 const std::size_t n = std::fread(&buffer[0], 1, nbytes, fptr);
3360
3361 // Check number of Bytes read
3362 if (n != nbytes) {
3363 std::string msg = "Attempt to read beyond the end of file; read "
3364 "only "+gammalib::str(n)+" of "+gammalib::str(nbytes)+
3365 " Bytes from file.";
3367 }
3368
3369 // Initialise unsigned 64 Bit integer
3370 uint64_t integer = 0;
3371
3372 // Convert buffer into unsigned 64 Bit integer
3373 for (int i = 0, shift = 0; i < nbytes; ++i, shift += 8) {
3374 integer += (unsigned char)buffer[i] << shift;
3375 }
3376
3377 // Return unsigned 64 Bit integer
3378 return (integer);
3379}
3380
3381
3382/***********************************************************************//**
3383 * @brief Read string data from HDF5 file
3384 *
3385 * @param[in] fptr File pointer.
3386 * @param[in] nbytes Number of Bytes to read (>0).
3387 * @returns String.
3388 *
3389 * @exception GException::invalid_argument
3390 * Number of Bytes not positive
3391 * @exception GException::runtime_error
3392 * Attempt to read beyond end of file
3393 *
3394 * Reads a string from the current position of the file pointer @p fptr into
3395 * a string. The method always reads @p nbytes from the file and advances
3396 * the file pointer by that amount. If a NULL termination character is
3397 * encountered the string is truncated to the segement before that character.
3398 ***************************************************************************/
3399std::string gammalib::hdf5::fread_string(FILE* fptr, const int& nbytes)
3400{
3401 // Check that nbytes is not zero
3402 if (nbytes < 1) {
3403 std::string msg = "Non positive number "+gammalib::str(nbytes)+
3404 " of Bytes specified. Please specify a number "
3405 "larger than 0.";
3407 }
3408
3409 // Initialise string
3410 std::string string;
3411
3412 // Allocate string space
3413 string.resize(nbytes);
3414
3415 // Read Bytes from file
3416 const std::size_t n = std::fread(&string[0], 1, nbytes, fptr);
3417
3418 // Check number of Bytes read
3419 if (n != nbytes) {
3420 std::string msg = "Attempt to read beyond the end of file; read "
3421 "only "+gammalib::str(n)+" of "+gammalib::str(nbytes)+
3422 " Bytes from file.";
3424 }
3425
3426 // Truncate string at termination character
3427 for (int i = 0; i < string.length(); ++i) {
3428 if (string[i] == '\0') { // found
3429 if (i > 0) { // string is not empty
3430 string = string.substr(0,i); // truncate string
3431 }
3432 else {
3433 string.clear(); // clear string
3434 }
3435 break; // exit loop
3436 }
3437 } // endfor: looped over bytes
3438
3439 // Return string
3440 return (string);
3441}
3442
3443
3444/***********************************************************************//**
3445 * @brief Read data with any data type as a string
3446 *
3447 * @param[in] fptr File pointer.
3448 * @param[in] datatype Datatype.
3449 * @return Data converted into a string.
3450 *
3451 * @exception GException::runtime_error
3452 * Attempt reading beyond end of file
3453 *
3454 * Reads one element of any datatype and return it as a string.
3455 ***************************************************************************/
3456std::string gammalib::hdf5::fread_data_as_string(FILE* fptr, const GXmlElement* datatype)
3457{
3458 // Initialise string
3459 std::string string;
3460
3461 // Get datatype size and class
3462 int size = gammalib::toint(datatype->attribute("size"));
3463 int cls = gammalib::toint(datatype->attribute("class"));
3464
3465 // Allocate string space
3466 string.resize(size);
3467
3468 // Read Bytes from file
3469 const std::size_t n = std::fread(&string[0], 1, size, fptr);
3470
3471 // Check number of Bytes read
3472 if (n != size) {
3473 std::string msg = "Attempt to read beyond the end of file; read "
3474 "only "+gammalib::str(n)+" of "+gammalib::str(size)+
3475 " Bytes from file.";
3477 }
3478
3479 // Convert buffer into string
3480 string = data_to_string(string.c_str(), datatype);
3481
3482 // Return string
3483 return string;
3484}
3485
3486
3487/***********************************************************************//**
3488 * @brief Read zero data from HDF5 file
3489 *
3490 * @param[in] fptr File pointer.
3491 * @param[in] nbytes Number of Bytes to read (>0).
3492 *
3493 * @exception GException::out_of_range
3494 * Number of Bytes not positive
3495 * GException::runtime_error
3496 * Attempt to read beyond end of file
3497 ***************************************************************************/
3498void gammalib::hdf5::fread_zero(FILE* fptr, const int& nbytes)
3499{
3500 // Check that nbytes is not zero
3501 if (nbytes < 1) {
3502 std::string msg = "Non positive number "+gammalib::str(nbytes)+
3503 " of Bytes specified. Please specify a number "
3504 "larger than 0.";
3506 }
3507
3508 // Initialise buffer for reading
3509 char* buffer = new char(nbytes);
3510
3511 // Get current file pointer position
3512 uint64_t pos = std::ftell(fptr);
3513
3514 // Read Bytes from file
3515 const std::size_t n = std::fread(&buffer[0], 1, nbytes, fptr);
3516
3517 // Check number of Bytes read
3518 if (n != nbytes) {
3519 std::string msg = "Attempt to read beyond the end of file; read "
3520 "only "+gammalib::str(n)+" of "+gammalib::str(nbytes)+
3521 " Bytes from file.";
3523 }
3524
3525 // Check that all Bytes are zero
3526 for (int i = 0; i < nbytes; ++i) {
3527 if ((unsigned char)buffer[i] != 0) {
3528 std::string msg = "Non-zero Byte "+gammalib::str((int)buffer[i])+" encountered "
3529 "at position "+gammalib::str(pos+i)+" in file.";
3531 }
3532 }
3533
3534 // Free buffer
3535 delete buffer;
3536
3537 // Return
3538 return;
3539}
3540
3541
3542/***********************************************************************//**
3543 * @brief Convert data into integer value
3544 *
3545 * @param[in] data Pointer to data.
3546 * @param[in] datatype Pointer to datatype XML element.
3547 * @return Data converted into integer value.
3548 *
3549 * @exception GException::feature_not_implemented
3550 * Conversion of specified datatype not yet supported
3551 * GException::invalid_value
3552 * Conversion of datatype not supported
3553 *
3554 * Converts one @p data element of given @p datatype into an integer value.
3555 * The method does not check for overflow. Fixed-point data are assumed to
3556 * be stored in little endian order.
3557 ***************************************************************************/
3558int gammalib::hdf5::data_to_int(const char* data,
3559 const GXmlElement* datatype)
3560{
3561 // Initialise integer value
3562 int value = 0;
3563
3564 // Get datatype class
3565 int size = gammalib::toint(datatype->attribute("size"));
3566 int cls = gammalib::toint(datatype->attribute("class"));
3567
3568 // Convert data according to class
3569 switch (cls) {
3570
3571 // Fixed point
3572 case 0: {
3573 // Get order
3574 int order = gammalib::toint(datatype->attribute("order"));
3575
3576 // Handle little-endian
3577 if (order == 0) {
3578 for (int i = 0, shift = 0; i < size; ++i, shift += 8) {
3579 value += (int)((unsigned char)data[i] << shift);
3580 }
3581 }
3582
3583 // Handle big-endian
3584 else {
3585 for (int i = 0, shift = 0; i < size; ++i, shift += 8) {
3586 value += (int)((unsigned char)data[size-i-1] << shift);
3587 }
3588 }
3589 break;
3590 }
3591
3592 // Floating point
3593 case 1: {
3594 if (size == 4) {
3595 value = (int)(*((const float*)data));
3596 }
3597 else if (size == 8) {
3598 value = (int)(*((const double*)data));
3599 }
3600 else {
3601 std::string msg = "Conversion of floating point value of "
3602 "size "+gammalib::str(size)+" to integer "
3603 "value is not supported.";
3605 }
3606 break;
3607 }
3608
3609 // Other cases
3610 default: {
3611 std::string msg = "Conversion of \""+classname(cls)+"\" to integer "
3612 "value is not yet implemented.";
3614 break;
3615 }
3616
3617 } // endswitch: handle type dependent data
3618
3619 // Return value
3620 return value;
3621}
3622
3623
3624/***********************************************************************//**
3625 * @brief Convert data into double precision floating point value
3626 *
3627 * @param[in] data Pointer to data.
3628 * @param[in] datatype Pointer to datatype XML element.
3629 * @return Data converted into double precision floating point value.
3630 *
3631 * @exception GException::feature_not_implemented
3632 * Conversion of specified datatype not yet supported
3633 * GException::invalid_value
3634 * Conversion of datatype not supported
3635 *
3636 * Converts one @p data element of given @p datatype into a double precision
3637 * floating point value.
3638 ***************************************************************************/
3639double gammalib::hdf5::data_to_double(const char* data,
3640 const GXmlElement* datatype)
3641{
3642 // Initialise double precision floating point value
3643 double value = 0.0;
3644
3645 // Get datatype class
3646 int size = gammalib::toint(datatype->attribute("size"));
3647 int cls = gammalib::toint(datatype->attribute("class"));
3648
3649 // Convert data according to class
3650 switch (cls) {
3651
3652 // Fixed point
3653 case 0: {
3654 // Get order
3655 int order = gammalib::toint(datatype->attribute("order"));
3656
3657 // Handle little-endian
3658 if (order == 0) {
3659 for (int i = 0, shift = 0; i < size; ++i, shift += 8) {
3660 value += (double)((unsigned char)data[i] << shift);
3661 }
3662 }
3663
3664 // Handle big-endian
3665 else {
3666 for (int i = 0, shift = 0; i < size; ++i, shift += 8) {
3667 value += (double)((unsigned char)data[size-i-1] << shift);
3668 }
3669 }
3670 break;
3671 }
3672
3673 // Floating point
3674 case 1: {
3675 if (size == 4) {
3676 value = (double)(*((const float*)data));
3677 }
3678 else if (size == 8) {
3679 value = *((const double*)data);
3680 }
3681 else {
3682 std::string msg = "Conversion of floating point value of "
3683 "size "+gammalib::str(size)+" to double "
3684 "precision value is not supported.";
3686 }
3687 break;
3688 }
3689
3690 // Other cases
3691 default: {
3692 std::string msg = "Conversion of \""+classname(cls)+"\" to double "
3693 "precision value is not yet implemented.";
3695 break;
3696 }
3697
3698 } // endswitch: handle type dependent data
3699
3700 // Return value
3701 return value;
3702}
3703
3704
3705/***********************************************************************//**
3706 * @brief Convert data into string
3707 *
3708 * @param[in] data Pointer to data.
3709 * @param[in] datatype Pointer to datatype XML element.
3710 * @return Data converted into string.
3711 *
3712 * @exception GException::feature_not_implemented
3713 * Conversion of specified datatype not yet supported
3714 *
3715 * Converts one @p data element of given @p datatype into a character string.
3716 ***************************************************************************/
3717std::string gammalib::hdf5::data_to_string(const char* data,
3718 const GXmlElement* datatype)
3719{
3720 // Initialise string
3721 std::string string;
3722
3723 // Get datatype class
3724 int size = gammalib::toint(datatype->attribute("size"));
3725 int cls = gammalib::toint(datatype->attribute("class"));
3726
3727 // Convert data according to class
3728 switch (cls) {
3729
3730 // Fixed point
3731 case 0: {
3732
3733 // Get class specific attributes
3734 int sign = gammalib::toint(datatype->attribute("signed"));
3735
3736 // Handle signed case
3737 if (sign == 1) {
3738
3739 // Initialise signed 64 Bit integer
3740 int64_t value = 0;
3741
3742 // Convert buffer into signed 64 Bit integer (assumes little-endian)
3743 for (int i = 0, shift = 0; i < size; ++i, shift += 8) {
3744 value += (unsigned char)data[i] << shift;
3745 }
3746
3747 // Set string
3748 string = gammalib::str(value);
3749
3750 } // endif: fixed point was signed
3751
3752 // Handle unsigned case
3753 else {
3754
3755 // Initialise unsigned 64 Bit integer
3756 uint64_t value = 0;
3757
3758 // Convert buffer into unsigned 64 Bit integer (assumes little-endian)
3759 for (int i = 0, shift = 0; i < size; ++i, shift += 8) {
3760 value += (unsigned char)data[i] << shift;
3761 }
3762
3763 // Set string
3764 string = gammalib::str(value);
3765
3766 } // endelse: fixed point was unsigned
3767 break;
3768 }
3769
3770 // Floating point
3771 /*
3772 case 1: {
3773 break;
3774 }
3775 */
3776
3777 // Enumerated
3778 case 8: {
3779
3780 // Get class specific attributes
3781 int number = gammalib::toint(datatype->attribute("number"));
3782
3783 // Get pointer to basetype
3784 const GXmlElement* basetype = datatype->element("basetype");
3785
3786 // Convert buffer into string
3787 string = data_to_string(data, basetype);
3788 break;
3789 }
3790
3791 // Other cases
3792 default: {
3793 std::string msg = "Conversion of \""+classname(cls)+"\" to string "
3794 "not yet implemented.";
3796 break;
3797 }
3798
3799 } // endswitch: handle type dependent data
3800
3801 // Return string
3802 return string;
3803}
3804
3805
3806/***********************************************************************//**
3807 * @brief Filter data
3808 *
3809 * @param[in] data Data string.
3810 * @param[in] datafilter Pointer to datafilter XML element.
3811 * @return Filtered data string.
3812 *
3813 * @exception GException::invalid_argument
3814 * No "filters" attribute in @p datafilter
3815 * @exception GException::invalid_value
3816 * Unxpected number of "filter" elements
3817 * @exception GException::feature_not_implemented
3818 * Requested filter is not yet implemented
3819 *
3820 * Filter data according to specified @p datafilter.
3821 ***************************************************************************/
3822std::string gammalib::hdf5::data_filter(const std::string& data,
3823 const GXmlElement* datafilter)
3824{
3825 // Initialise string
3826 std::string string;
3827
3828 // Check for required attributes
3829 if (!datafilter->has_attribute("filters")) {
3830 std::string msg = "\"DataStorageFilterPipeline\" message is missing "
3831 "\"filters\" attribute";
3833 }
3834
3835 // Get number of filters
3836 int filters = gammalib::toint(datafilter->attribute("filters"));
3837
3838 // Check for corresponding number of filter elements
3839 if (datafilter->elements("filter") != filters) {
3840 std::string msg = gammalib::str(datafilter->elements("filter"))+
3841 "filters found in \"DataStorageFilterPipeline\" "
3842 "but attribute \"filters\"="+gammalib::str(filters)+
3843 ". Please specify a valid HDF5 file.";
3845 }
3846
3847 // Loop over number of filters
3848 for (int i = 0; i < filters; ++i) {
3849
3850 // Get filter XML element
3851 const GXmlElement* filter = datafilter->element("filter");
3852
3853 // Check for required attributes
3854 if (!filter->has_attribute("id")) {
3855 std::string msg = "Filter element "+gammalib::str(i)+" is "
3856 "missing \"id\" attribute";
3858 }
3859
3860 // Get identifier
3861 int id = gammalib::toint(filter->attribute("id"));
3862
3863 // Apply filter according to ID
3864 switch (id) {
3865 // Bitshuffle
3866 case 32008: {
3867 string = data_filter_bitshuffle(data, filter);
3868 break;
3869 }
3870 default: {
3871 std::string msg = "Requested data filter with id="+
3872 gammalib::str(id)+" is not yet implemented.";
3874 break;
3875 }
3876 }
3877
3878 } // endfor: looped over data filters
3879
3880 // Return string
3881 return string;
3882}
3883
3884
3885/***********************************************************************//**
3886 * @brief Filter data according to Bitshuffle algorithm
3887 *
3888 * @param[in] data Data string.
3889 * @param[in] filter Pointer to bitshuffle filter XML element.
3890 * @return Filtered data string.
3891 *
3892 * @exception GException::invalid_argument
3893 * Invalid number of client data values found in @p filter
3894 * @exception GException::feature_not_implemented
3895 * Unsupported Bitshuffle algorithm specified in @p filter
3896 *
3897 * Filter data according to Bitshuffle algorithm with parameters specified
3898 * by @p filter.
3899 *
3900 * The method was inspired by https://github.com/kiyo-masui/bitshuffle and
3901 * specifically the bshuf_h5_filter() function in the file bshuf_h5filter.c.
3902 ***************************************************************************/
3903std::string gammalib::hdf5::data_filter_bitshuffle(const std::string& data,
3904 const GXmlElement* filter)
3905{
3906 // Initialise string
3907 std::string string;
3908
3909 // Debug bitshuffle code
3910 #if defined(G_BITSHUFFLE_DEBUG)
3911 std::cout << "data_filter_bitshuffle" << std::endl;
3912 std::cout << "======================" << std::endl;
3913 #endif
3914
3915 // Get client data values
3916 int client_values = filter->elements("data");
3917
3918 // Check client data values
3919 if (client_values < 3) {
3920 std::string msg = "Only "+gammalib::str(client_values)+
3921 " client data values found in filter, but at least "
3922 "3 values are required for the bitshuffle filter. "
3923 "Please specify a valid HDF5 file.";
3925 }
3926
3927 // Extract element size of typed data
3928 size_t element_size = filter->element("data", 2)->integer();
3929
3930 // Optionally extract block size
3931 size_t block_size = (client_values > 3) ? filter->element("data", 3)->integer() : 0;
3932
3933 // If block size is zero then use default block size
3934 if (block_size == 0) {
3935 block_size = 8192 / element_size; // Target a block size of 8192
3936 block_size = (block_size / 8) * 8; // Block size must be a multiple of 8
3937 block_size = (block_size > 128) ? block_size : 128; // Block size should be at least 128
3938 }
3939
3940 // Optionally extract compression algorithm
3941 int compression = (client_values > 4) ? filter->element("data", 4)->integer() : 0;
3942
3943 // Check compression algorithm
3944 if (compression != 2) {
3945 std::string msg = "Unsupported bitshuffle compression algorithm "+
3946 gammalib::str(compression)+" encountered. "
3947 "Only algorithm=2 (LZ4 compression) is so far supported.";
3949 }
3950
3951 // Set pointer to input buffer
3952 char* input = (char*)data.c_str();
3953
3954 // Handle dependent on compression type
3955 switch(compression) {
3956
3957 // No compression
3958 case 0: {
3959 //
3960 size_t nbytes_uncompressed = data.length();
3961 size_t buf_size_out = data.length();
3962 size_t size = nbytes_uncompressed / element_size;
3963
3964 // Allocate string space for uncompressed data
3965 string.resize(buf_size_out);
3966
3967 // Set pointer to output buffer
3968 char* output = (char*)string.c_str();
3969
3970 // Bit unshuffle.
3971 //err = bshuf_bitunshuffle(input, output, size, element_size, block_size);
3972 break;
3973 }
3974
3975 // LZ4 compression
3976 case 2: {
3977 // Read number of uncompressed Bytes and block size from data
3978 size_t nbytes_uncompressed = bitshuffle_read_uint64(input);
3979 size_t block_size = bitshuffle_read_uint32((const char*)input + 8) / element_size;
3980 input += 12;
3981
3982 // Compute number of elements
3983 size_t elements = nbytes_uncompressed / element_size;
3984
3985 // Allocate string space for uncompressed data
3986 string.resize(nbytes_uncompressed);
3987
3988 // Set pointer to output buffer
3989 char* output = (char*)string.c_str();
3990
3991 // Debug bitshuffle code
3992 #if defined(G_BITSHUFFLE_DEBUG)
3993 std::cout << "LZ4 compression:";
3994 std::cout << " nbytes_uncompressed=" << nbytes_uncompressed;
3995 std::cout << ", block_size=" << block_size;
3996 std::cout << ", elements=" << elements;
3997 std::cout << ", element_size=" << element_size << std::endl;
3998 #endif
3999
4000 // Decompress and unshuffle
4001 bitshuffle_decompress(input, output, elements, element_size, block_size);
4002 break;
4003 }
4004
4005 } // endswitch: handled according to compression type
4006
4007 // Return string
4008 return string;
4009}
4010
4011
4012/***********************************************************************//**
4013 * @brief Return specific occurence of header message of given type
4014 *
4015 * @param[in] header Pointer to XML header element.
4016 * @param[in] type Message type.
4017 * @param[in] number Occurence of message.
4018 * @return Pointer to XML element of specific occurence of message type.
4019 *
4020 * GException::invalid_value
4021 * No @p type message found in header.
4022 *
4023 * Returns a XML pointer to the ocurrence @p number of a message of specified
4024 * @p type.
4025 ***************************************************************************/
4027 const std::string& type,
4028 const int& number)
4029{
4030 // Initialise result element
4031 const GXmlElement* element = NULL;
4032
4033 // Get number of messages
4034 int messages = header->elements("message");
4035
4036 // Initialise occurences
4037 int occurences = 0;
4038
4039 // Loop over messages
4040 for (int i = 0; i < messages; ++i) {
4041
4042 // Get message element
4043 const GXmlElement* message = header->element("message", i);
4044
4045 // Search the element for requested type
4046 if (message->has_attribute("type")) {
4047 if (message->attribute("type") == type) {
4048 if (occurences == number) {
4049 element = message;
4050 break;
4051 }
4052 else {
4053 occurences++;
4054 }
4055 }
4056 }
4057
4058 } // endfor: looped over messages
4059
4060 // Throw an exception if no entry was found
4061 if (element == NULL) {
4062 if (number == 0) {
4063 std::string msg = "No \""+type+"\" message found in HDF5 object header.";
4065 }
4066 else {
4067 std::string msg = gammalib::order(number)+" occurence of \""+
4068 type+"\" message not found in HDF5 object header.";
4070 }
4071 }
4072
4073 // Return element
4074 return element;
4075}
4076
4077
4078/***********************************************************************//**
4079 * @brief Checks if specific occurence of header message of given type exists
4080 *
4081 * @param[in] header Pointer to XML header element.
4082 * @param[in] type Message type.
4083 * @param[in] number Occurence of message.
4084 * @return True if ith occurence of message exists, false otherwise.
4085 *
4086 * Returns true if the occurence @p number of header message of @p type
4087 * exists.
4088 ***************************************************************************/
4090 const std::string& type,
4091 const int& number)
4092{
4093 // Initialise result element
4094 const GXmlElement* element = NULL;
4095
4096 // Get number of messages
4097 int messages = header->elements("message");
4098
4099 // Initialise occurences
4100 int occurences = 0;
4101
4102 // Loop over messages
4103 for (int i = 0; i < messages; ++i) {
4104
4105 // Get message element
4106 const GXmlElement* message = header->element("message", i);
4107
4108 // Search the element for with specified type
4109 if (message->has_attribute("type")) {
4110 if (message->attribute("type") == type) {
4111 if (occurences == number) {
4112 element = message;
4113 break;
4114 }
4115 else {
4116 occurences++;
4117 }
4118 }
4119 }
4120
4121 } // endfor: looped over messages
4122
4123 // Return existence
4124 return (element != NULL);
4125}
4126
4127/***********************************************************************//**
4128 * @brief Return number of "Attribute" messages in header
4129 *
4130 * @param[in] header Pointer to XML header element.
4131 * @param[in] name Name of "Attribute" message.
4132 * @return Number of attributes in message header.
4133 *
4134 * Returns the number of message elements of type "Attribute" in the specified
4135 * header element. If @p name is not empty, the method will only count the
4136 * attributes of which the "name" attribute equals to @p name.
4137 ***************************************************************************/
4139 const std::string& name)
4140{
4141 // Initialise number of attributes
4142 int number = 0;
4143
4144 // Get number of messages
4145 int messages = header->elements("message");
4146
4147 // Signal that name should be checked
4148 bool check_name = (name.length() > 0);
4149
4150 // Loop over messages
4151 for (int i = 0; i < messages; ++i) {
4152
4153 // Get message element
4154 const GXmlElement* message = header->element("message", i);
4155
4156 // Count number of "Attribute" types
4157 if (message->has_attribute("type")) {
4158 if (message->attribute("type") == "Attribute") {
4159 if (check_name) {
4160 if (message->has_attribute("name")) {
4161 if (message->attribute("name") == name) {
4162 number++;
4163 }
4164 }
4165 }
4166 else {
4167 number++;
4168 }
4169 }
4170 }
4171
4172 } // endfor: looped over messages
4173
4174 // Return number of attributes
4175 return number;
4176}
4177
4178
4179/***********************************************************************//**
4180 * @brief Return "Attribute" message XML element with specified name
4181 *
4182 * @param[in] header Pointer to XML header element.
4183 * @param[in] name Name of "Attribute" message.
4184 * @param[in] number Number of occurences to return (0=return first occurence).
4185 * @return Pointer to "Attribute" message XML element with specified @p name.
4186 *
4187 * Returns a XML pointer to a message element of type "Attribute" and with
4188 * the specified @p name.
4189 *
4190 * If several "Attribute" messages have the same @p name, the first of these
4191 * messages is returned.
4192 ***************************************************************************/
4194 const std::string& name,
4195 const int& number)
4196{
4197 // Initialise result element
4198 const GXmlElement* element = NULL;
4199
4200 // Get number of messages
4201 int messages = header->elements("message");
4202
4203 // Initialise occurences
4204 int occurences = 0;
4205
4206 // Loop over messages
4207 for (int i = 0; i < messages; ++i) {
4208
4209 // Get message element
4210 const GXmlElement* message = header->element("message", i);
4211
4212 // Search the element for "Attribute" with specified name
4213 if (message->has_attribute("type")) {
4214 if (message->attribute("type") == "Attribute") {
4215 if (message->has_attribute("name")) {
4216 if (message->attribute("name") == name) {
4217 if (occurences == number) {
4218 element = message;
4219 break;
4220 }
4221 else {
4222 occurences++;
4223 }
4224 }
4225 }
4226 }
4227 }
4228
4229 } // endfor: looped over messages
4230
4231 // Throw an exception if no entry was found
4232 if (element == NULL) {
4233 if (number == 0) {
4234 std::string msg = "No \"Attribute\" message with attribute name=\""+
4235 name+"\" found in HDF5 metadata.";
4237 }
4238 else {
4239 std::string msg = gammalib::order(number)+" occurence of "
4240 "\"Attribute\" message with attribute name=\""+
4241 name+"\" not found in HDF5 metadata.";
4243 }
4244 }
4245
4246 // Return element
4247 return element;
4248}
4249
4250
4251/***********************************************************************//**
4252 * @brief Checks if "Attribute" message XML element with specified name exists
4253 *
4254 * @param[in] header Pointer to XML header element.
4255 * @param[in] name Name of "Attribute" message.
4256 * @param[in] number Number of occurences to return (0=return first occurence).
4257 * @return True if message exists, false otherwise.
4258 *
4259 * Returns true if an "Attribute" message with @p name exists.
4260 ***************************************************************************/
4262 const std::string& name,
4263 const int& number)
4264{
4265 // Initialise result element
4266 const GXmlElement* element = NULL;
4267
4268 // Get number of messages
4269 int messages = header->elements("message");
4270
4271 // Initialise occurences
4272 int occurences = 0;
4273
4274 // Loop over messages
4275 for (int i = 0; i < messages; ++i) {
4276
4277 // Get message element
4278 const GXmlElement* message = header->element("message", i);
4279
4280 // Search the element for "Attribute" with specified name
4281 if (message->has_attribute("type")) {
4282 if (message->attribute("type") == "Attribute") {
4283 if (message->has_attribute("name")) {
4284 if (message->attribute("name") == name) {
4285 if (occurences == number) {
4286 element = message;
4287 break;
4288 }
4289 else {
4290 occurences++;
4291 }
4292 }
4293 }
4294 }
4295 }
4296
4297 } // endfor: looped over messages
4298
4299 // Return existence
4300 return (element != NULL);
4301}
4302
4303
4304/***********************************************************************//**
4305 * @brief Return "Attribute" message key value from attribute with specified name
4306 *
4307 * @param[in] header Pointer to XML header element.
4308 * @param[in] name Name of "Attribute" message.
4309 * @param[in] key Key of "Attribute" message.
4310 * @return String with value of @p key in "Attribute" message with @p name.
4311 *
4312 * Returns the value of an attribute @p key in an "Attribute" message with
4313 * the specified @p name as a string. If the attribute or the key was not
4314 * found then return an empty string.
4315 *
4316 * If several "Attribute" messages have the same @p name and p@ key, the
4317 * first corresponding value is returned.
4318 ***************************************************************************/
4320 const std::string& name,
4321 const std::string& key)
4322{
4323 // Initialise value string
4324 std::string value;
4325
4326 // Get number of messages
4327 int messages = header->elements("message");
4328
4329 // Loop over messages
4330 for (int i = 0; i < messages; ++i) {
4331
4332 // Get message element
4333 const GXmlElement* message = header->element("message", i);
4334
4335 // Search the element for "Attribute" with specified name and
4336 // specified key and return it's value
4337 if (message->has_attribute("type")) {
4338 if (message->attribute("type") == "Attribute") {
4339 if (message->has_attribute("name")) {
4340 if (message->attribute("name") == name) {
4341 if (message->has_attribute(key)) {
4342 value = message->attribute(key);
4343 break;
4344 }
4345 }
4346 }
4347 }
4348 }
4349
4350 } // endfor: looped over all messages
4351
4352 // Return value
4353 return value;
4354}
4355
4356
4357/***********************************************************************//**
4358 * @brief Convert datatype class into classname
4359 *
4360 * @param[in] cls Datatype class.
4361 * @return Classname.
4362 *
4363 * Return class name from datatype class.
4364 ***************************************************************************/
4365std::string gammalib::hdf5::classname(const int& cls)
4366{
4367 // Initialise classname
4368 std::string classname;
4369
4370 // Convert datatype class into string
4371 switch (cls) {
4372 case 0:
4373 classname = "Fixed point";
4374 break;
4375 case 1:
4376 classname = "Floating point";
4377 break;
4378 case 2:
4379 classname = "Time";
4380 break;
4381 case 3:
4382 classname = "String";
4383 break;
4384 case 4:
4385 classname = "Bit field";
4386 break;
4387 case 5:
4388 classname = "Opaque";
4389 break;
4390 case 6:
4391 classname = "Compound";
4392 break;
4393 case 7:
4394 classname = "Reference";
4395 break;
4396 case 8:
4397 classname = "Enumerated";
4398 break;
4399 case 9:
4400 classname = "Variable-Length";
4401 break;
4402 case 10:
4403 classname = "Array";
4404 break;
4405 case 11:
4406 classname = "Complex";
4407 break;
4408 default:
4409 break;
4410 }
4411
4412 // Return classname
4413 return classname;
4414}
4415
4416
4417/*==========================================================================
4418 = =
4419 = Private HDF5 support functions =
4420 = =
4421 ==========================================================================*/
4422
4423
4424/***********************************************************************//**
4425 * @brief Decompress and bitshuffle data
4426 *
4427 * @param[in] input Pointer to input buffer.
4428 * @param[out] out Pointer to output buffer (@p elements * @p element_size bytes).
4429 * @param[in] elements Number of elements in input.
4430 * @param[in] element_size Element size of typed data.
4431 * @param[in] block_size Process in blocks of this many elements.
4432 *
4433 * The method was inspired by https://github.com/kiyo-masui/bitshuffle and
4434 * specifically the bshuf_decompress_lz4() and bshuf_decompress_lz4_block()
4435 * functions in the bitshuffle.c file and the bshuf_blocked_wrap_fun()
4436 * function in the bitshuffle_core.c file.
4437 ***************************************************************************/
4438void bitshuffle_decompress(char* input,
4439 char* output,
4440 const size_t& elements,
4441 const size_t& element_size,
4442 size_t& block_size)
4443{
4444 // Initialise cumulative count
4445 uint64_t cum_count = 0;
4446
4447 // Determine number of blocks
4448 int nblocks = elements / block_size;
4449
4450 // Debug bitshuffle code
4451 #if defined(G_BITSHUFFLE_DEBUG)
4452 std::cout << "bitshuffle_decompress" << std::endl;
4453 std::cout << "=====================" << std::endl;
4454 std::cout << "nblocks=" << nblocks << std::endl;
4455 #endif
4456
4457 // Loop over blocks, including the last block
4458 for (int i = 0; i < nblocks+1; ++i) {
4459
4460 // Determine size of this block, where each block except of the
4461 // last block have the same user specified size
4462 size_t this_block_size = block_size;
4463 if (i == nblocks) {
4464 this_block_size = elements % block_size;
4465 this_block_size = this_block_size - this_block_size % 8;
4466 }
4467
4468 // Continue only if size of this block is non-zero
4469 if (this_block_size != 0) {
4470
4471 // Read number of Bytes to decompress from header
4472 uint32_t nbytes_from_header = bitshuffle_read_uint32(input);
4473
4474 // Set buffer size
4475 int buffer_size = this_block_size * element_size;
4476
4477 // Allocate temporary memory
4478 char* buffer = new char[buffer_size];
4479
4480 // LZ4 decompression
4481 int nbytes = decompress_lz4((const char*)input + 4,
4482 buffer,
4483 nbytes_from_header,
4484 buffer_size);
4485
4486 // Debug bitshuffle code
4487 #if defined(G_BITSHUFFLE_DEBUG)
4488 std::cout << "block=" << i;
4489 std::cout << ", nbytes_from_header=" << nbytes_from_header;
4490 std::cout << ", block_size=" << this_block_size;
4491 std::cout << ", buffer_size=" << buffer_size;
4492 std::cout << ", nbytes=" << nbytes;
4493 std::cout << std::endl;
4494 #endif
4495
4496 // Check number of decompressed Bytes
4497 if (nbytes != buffer_size) {
4498 std::string msg = "Invalid number of "+gammalib::str(nbytes)+
4499 " decompressed Bytes, expected "+
4500 gammalib::str(buffer_size)+" Bytes.";
4502 }
4503
4504 // Unshuffle elements
4505 bitshuffle_elements(buffer, output, this_block_size, element_size);
4506
4507 // Increment input and output pointers
4508 input += nbytes_from_header + 4;
4509 output += this_block_size * element_size;
4510
4511 // Cumulate counts
4512 cum_count += nbytes_from_header + 4;
4513
4514 // Free buffer
4515 delete [] buffer;
4516
4517 } // endif: size of this block was not zero
4518
4519 } // endfor: looped over blocks
4520
4521 // Compute number of leftover Bytes
4522 size_t leftover_bytes = elements % 8 * element_size;
4523
4524 // Debug bitshuffle code
4525 #if defined(G_BITSHUFFLE_DEBUG)
4526 std::cout << "leftover_bytes=" << leftover_bytes;
4527 std::cout << std::endl;
4528 #endif
4529
4530 // Copy over leftover Bytes
4531 //memcpy(output, input, leftover_bytes);
4532 for (int i = 0; i < leftover_bytes; ++i) {
4533 *output++ = *input++;
4534 }
4535
4536 // Cumulate counts
4537 cum_count += leftover_bytes;
4538
4539 // Debug bitshuffle code
4540 #if defined(G_BITSHUFFLE_DEBUG)
4541 std::cout << "cum_count=" << cum_count;
4542 std::cout << std::endl;
4543 #endif
4544
4545 // Return
4546 return;
4547
4548}
4549
4550
4551/***********************************************************************//**
4552 * @brief Read a 64 bit unsigned integer from a buffer big endian order
4553 *
4554 * @param[in] buffer Buffer.
4555 * @return 64 bit unsigned integer.
4556 *
4557 * Reads a 64 bit unsigned integer stored in big endian order from a Byte
4558 * buffer.
4559 *
4560 * The method was inspired by https://github.com/kiyo-masui/bitshuffle and
4561 * specifically the bshuf_read_uint64_BE() function in the bitshuffle.c file.
4562 ***************************************************************************/
4563uint64_t bitshuffle_read_uint64(const char* buffer)
4564{
4565 // Set constants
4566 const uint64_t pow28 = 256;
4567
4568 // Cast buffer to unsigned Byte
4569 uint8_t* b = (uint8_t*)buffer;
4570
4571 // Initialise conversion
4572 uint64_t num = 0;
4573 uint64_t cp = 1;
4574
4575 // Loop over 8 Bytes backwards
4576 for (int i = 7; i >= 0; i--) {
4577 num += b[i] * cp;
4578 cp *= pow28;
4579 }
4580
4581 // Returns result
4582 return num;
4583}
4584
4585
4586/***********************************************************************//**
4587 * @brief Read a 32 bit unsigned integer from a buffer big endian order
4588 *
4589 * @param[in] buffer Buffer.
4590 * @return 32 bit unsigned integer.
4591 *
4592 * Reads a 32 bit unsigned integer stored in big endian order from a Byte
4593 * buffer.
4594 *
4595 * The method was inspired by https://github.com/kiyo-masui/bitshuffle and
4596 * specifically the bshuf_read_uint32_BE() function in the bitshuffle.c file.
4597 ***************************************************************************/
4598uint32_t bitshuffle_read_uint32(const char* buffer)
4599{
4600 // Set constants
4601 const uint32_t pow28 = 256;
4602
4603 // Cast buffer to unsigned Byte
4604 uint8_t* b = (uint8_t*)buffer;
4605
4606 // Initialise conversion
4607 uint32_t num = 0;
4608 uint32_t cp = 1;
4609
4610 // Loop over 4 Bytes backwards
4611 for (int i = 3; i >= 0; i--) {
4612 num += b[i] * cp;
4613 cp *= pow28;
4614 }
4615
4616 // Return result
4617 return num;
4618}
4619
4620
4621/***********************************************************************//**
4622 * @brief Untranspose bits within elements
4623 *
4624 * @param[in] input Pointer to input buffer.
4625 * @param[out] output Pointer to output buffer (@p elements * @p element_size bytes).
4626 * @param[in] elements Number of elements in input.
4627 * @param[in] element_size Element size of typed data.
4628 *
4629 * The method was inspired by https://github.com/kiyo-masui/bitshuffle and
4630 * specifically the bshuf_untrans_bit_elem_scal() function in the file
4631 * bitshuffle_core.c.
4632 ***************************************************************************/
4633void bitshuffle_elements(const char* input,
4634 char* output,
4635 const size_t& elements,
4636 const size_t& element_size)
4637{
4638 // Compute number of Bytes on output
4639 int nbytes = elements * element_size;
4640
4641 // Allocate temporary buffer
4642 char* buffer = new char[nbytes];
4643
4644 // Compute number of Bytes in row
4645 int nbyte_row = elements / 8;
4646
4647 // For data organized into a row for each bit (8 * element_size rows),
4648 // transpose the bytes
4649 for (int i = 0; i < element_size; ++i) {
4650 int i8 = i * 8;
4651 for (int j = 0; j < nbyte_row; ++j) {
4652 int joffset = j * 8 * element_size + i8;
4653 for (int k = 0; k < 8; ++k) {
4654 buffer[joffset + k] = input[(i8 + k) * nbyte_row + j];
4655 }
4656 }
4657 }
4658
4659 // Shuffle bits within the bytes of eight element blocks. The shuffling
4660 // depends on the storage order. First handle little endian...
4662 for (int i = 0; i < 8 * element_size; i += 8) {
4663 for (int j = 0; j + 8 * element_size - 1 < nbytes; j += 8 * element_size) {
4664 uint64_t x = *((uint64_t*)&buffer[j + i]);
4665 uint64_t t = (x ^ (x >> 7)) & 0x00AA00AA00AA00AALL;
4666 x = x ^ t ^ (t << 7);
4667 t = (x ^ (x >> 14)) & 0x0000CCCC0000CCCCLL;
4668 x = x ^ t ^ (t << 14);
4669 t = (x ^ (x >> 28)) & 0x00000000F0F0F0F0LL;
4670 x = x ^ t ^ (t << 28);
4671 for (int k = 0; k < 8; ++k) {
4672 *((uint8_t*)&output[j + i / 8 + k * element_size]) = x;
4673 x = x >> 8;
4674 }
4675 }
4676 }
4677 } // endif: integers are stored little endian
4678
4679 // ... otherwise handle big endian
4680 else {
4681 for (int i = 0; i < 8 * element_size; i += 8) {
4682 for (int j = 0; j + 8 * element_size - 1 < nbytes; j += 8 * element_size) {
4683 uint64_t x = *((uint64_t*)&buffer[j + i]);
4684 uint64_t t = (x ^ (x >> 9)) & 0x0055005500550055LL;
4685 x = x ^ t ^ (t << 9);
4686 t = (x ^ (x >> 18)) & 0x0000333300003333LL;
4687 x = x ^ t ^ (t << 18);
4688 t = (x ^ (x >> 36)) & 0x000000000F0F0F0FLL;
4689 x = x ^ t ^ (t << 36);
4690 for (int k = 0; k < 8; ++k) {
4691 *((uint8_t*)&output[j + i / 8 + (7-k) * element_size]) = x;
4692 x = x >> 8;
4693 }
4694 }
4695 }
4696 } // endelse: integers are stored big endian
4697
4698 // Free temporary buffer
4699 delete [] buffer;
4700
4701 // Return
4702 return;
4703}
4704
4705
4706/***********************************************************************//**
4707 * @brief Decompress data using the LZ4 algorithm
4708 *
4709 * @param[in] src Pointer to compressed data.
4710 * @param[out] dest Pointer to decompressed data (must be already allocated).
4711 * @param[in] srcSize Size of compressed data.
4712 * @param[in] outputSize Maximum size of allocated decompressed data.
4713 * @returns Number of decompressed Bytes.
4714 *
4715 * Decompress data using the LZ4 algorithm.
4716 *
4717 * The method was inspired by https://github.com/kiyo-masui/bitshuffle and
4718 * specifically the LZ4_decompress_safe() function in the file lz4.c.
4719 ***************************************************************************/
4720int decompress_lz4(const char* src,
4721 char* dst,
4722 const size_t& srcSize,
4723 const size_t& outputSize)
4724{
4725 // Set constants
4726 const int minmatch = 4;
4727 const int wildcopylength = 8;
4728 const int lastliterals = 5;
4729 const int mflimit = 12;
4730 const int match_safeguard_distance = ((2*wildcopylength) - minmatch);
4731 const int fastloop_safe_distance = 64;
4732 const int ml_bits = 4;
4733 const int ml_mask = ((1U<<ml_bits)-1);
4734 const int run_bits = (8-ml_bits);
4735 const int run_mask = ((1U<<run_bits)-1);
4736 const unsigned inc32table[8] = {0, 1, 2, 1, 0, 4, 4, 4};
4737 const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3};
4738
4739 // Derive variables from arguments
4740 const uint8_t* lowPrefix = (uint8_t*)dst;
4741
4742 // Set start and end Byte pointers to compressed data
4743 const uint8_t* ip = (const uint8_t*)src;
4744 const uint8_t* iend = ip + srcSize;
4745
4746 // Set start and end Byte pointers to uncompressed data
4747 uint8_t* op = (uint8_t*)dst;
4748 uint8_t* oend = op + outputSize;
4749 uint8_t* cpy;
4750
4751 // Set up the "end" pointers for the shortcut
4752 const uint8_t* shortiend = iend - 14 /*maxLL*/ - 2 /*offset*/;
4753 const uint8_t* shortoend = oend - 14 /*maxLL*/ - 18 /*maxML*/;
4754
4755 // Allocate working variables
4756 const uint8_t* match;
4757 size_t offset;
4758 unsigned token;
4759 size_t length;
4760
4761 // Use fast loop
4762 if ((oend - op) >= fastloop_safe_distance) {
4763
4764 // Decode sequences as long as output < oend-fastloop_safe_distance
4765 while (true) {
4766
4767 // Main fastloop assertion: We can always wildcopy fastloop_safe_distance
4768 //assert(oend - op >= fastloop_safe_distance);
4769 //assert(ip < iend);
4770
4771 // Get next token and literal length
4772 token = *ip++;
4773 length = token >> ml_bits;
4774
4775 // Decode literal length
4776 if (length == run_mask) {
4777
4778 // Add length
4779 length += read_variable_length(&ip, iend-run_mask, true);
4780
4781 // Check for overflow
4782 if (((uintptr_t)(op)+length < (uintptr_t)(op)) ||
4783 ((uintptr_t)(ip)+length < (uintptr_t)(ip))) {
4784 std::string msg = "Overflow detection.";
4786 }
4787
4788 // If we're close to the end of the buffers then use safe literal
4789 // copy
4790 //LZ4_STATIC_ASSERT(mflimit >= wildcopylength);
4791 if ((op+length > oend-32) || (ip+length > iend-32)) {
4792 goto safe_literal_copy;
4793 }
4794
4795 // ... otherwise copy literals
4796 memory_beyond32(ip, op, op+length);
4797
4798 // Increment pointers
4799 ip += length;
4800 op += length;
4801
4802 } // endif: decoded literal
4803
4804 // ... otherwise if at least 16 Bytes remain in input buffer then
4805 // copy 16-Bytes stripe. We don't need to check oend, since we check
4806 // it once for each loop below.
4807 else if (ip <= iend-(16 + 1)) {
4808
4809 // Copy 16-Byte stripe
4810 std::memcpy(op, ip, 16);
4811
4812 // Increment pointers
4813 ip += length;
4814 op += length;
4815
4816 } // endif: copied 16-Byte stripe
4817
4818 // ... otherwise use safe literal copy
4819 else {
4820 goto safe_literal_copy;
4821 }
4822
4823 // Get offset
4824 offset = read_uint16(ip);
4825 ip += 2;
4826 match = op - offset;
4827 //assert(match <= op); /* overflow check */
4828
4829 // Get matchlength
4830 length = token & ml_mask;
4831
4832 //
4833 if (length == ml_mask) {
4834
4835 // Add length
4836 length += read_variable_length(&ip, iend - lastliterals + 1, false);
4837 length += minmatch;
4838
4839 // Check for overflow
4840 if ((uintptr_t)(op)+length < (uintptr_t)(op)) {
4841 std::string msg = "Overflow detection.";
4843 }
4844
4845 //
4846 if (op + length >= oend - fastloop_safe_distance) {
4847 goto safe_match_copy;
4848 }
4849
4850 } // endif
4851
4852 // ...
4853 else {
4854 length += minmatch;
4855 if (op + length >= oend - fastloop_safe_distance) {
4856 //DEBUGLOG(7, "moving to safe_match_copy (ml==%u)", (unsigned)length);
4857 goto safe_match_copy;
4858 }
4859
4860 /* Fastpath check: skip memory_beyond32 when true */
4861 if ((match >= lowPrefix)) {
4862 if (offset >= 8) {
4863 //assert(match >= lowPrefix);
4864 //assert(match <= op);
4865 //assert(op + 18 <= oend);
4866 std::memcpy(op, match, 8);
4867 std::memcpy(op+8, match+8, 8);
4868 std::memcpy(op+16, match+16, 2);
4869 op += length;
4870 continue;
4871 }
4872 }
4873
4874 } // endelse
4875
4876 // ...
4877 if (match < lowPrefix) {
4878 std::string msg = "Position outside buffers.";
4880 }
4881
4882 // Copy match within block
4883 cpy = op + length;
4884
4885 //assert((op <= oend) && (oend-op >= 32));
4886 if (offset < 16) {
4887 memcpy_using_offset(match, op, cpy, offset);
4888 }
4889 else {
4890 memory_beyond32(match, op, cpy);
4891 }
4892
4893 // Adopt wildcopy correction
4894 op = cpy;
4895
4896 } // endwhile
4897
4898 } // endif: used fast loop
4899
4900 // Main loop that decompresses the remaining sequence where
4901 // output < fastloop_safe_distance
4902 while (true) {
4903
4904 // Check
4905 //assert(ip < iend);
4906
4907 // Get literal length token
4908 token = *ip++;
4909 length = token >> ml_bits;
4910
4911 // Two-stage shortcut for the most common case:
4912 // 1) If the literal length is 0..14, and there is enough space,
4913 // enter the shortcut and copy 16 bytes on behalf of the literals
4914 // (in the fast mode, only 8 bytes can be safely copied this way).
4915 // 2) Further if the match length is 4..18, copy 18 bytes in a similar
4916 // manner; but we ensure that there's enough space in the output for
4917 // those 18 bytes earlier, upon entering the shortcut (in other words,
4918 // there is a combined check for both stages).
4919 if ((length != run_mask) && (ip < shortiend) & (op <= shortoend)) {
4920
4921 // Copy the literals
4922 std::memcpy(op, ip, 16);
4923 op += length;
4924 ip += length;
4925
4926 // Second stage: prepare for match copying, decode full info. If it
4927 // doesn't work out, the info won't be wasted.
4928 length = token & ml_mask;
4929 offset = read_uint16(ip);
4930 ip += 2;
4931 match = op - offset;
4932 //assert(match <= op); /* check overflow */
4933
4934 // Do not deal with overlapping matches
4935 if ((length != ml_mask) && (offset >= 8) && (match >= lowPrefix)) {
4936 std::memcpy(op + 0, match + 0, 8);
4937 std::memcpy(op + 8, match + 8, 8);
4938 std::memcpy(op +16, match +16, 2);
4939 op += length + minmatch;
4940 // Both stages worked, load the next token
4941 continue;
4942 }
4943
4944 // The second stage didn't work out, but the info is ready. Propel
4945 // it right to the point of match copying.
4946 goto _copy_match;
4947
4948 } // endif: Two-stage shortcut
4949
4950 // Decode literal length. Check for overflow.
4951 if (length == run_mask) {
4952 length += read_variable_length(&ip, iend-run_mask, true);
4953 if (((uintptr_t)(op)+length < (uintptr_t)(op)) ||
4954 ((uintptr_t)(ip)+length < (uintptr_t)(ip))) {
4955 std::string msg = "Overflow detection.";
4957 }
4958 }
4959
4960safe_literal_copy:
4961 /* copy literals */
4962 cpy = op+length;
4963
4964 //LZ4_STATIC_ASSERT(mflimit >= wildcopylength);
4965 if ((cpy>oend-mflimit) || (ip+length>iend-(2+1+lastliterals))) {
4966 /* We've either hit the input parsing restriction or the output parsing restriction.
4967 * In the normal scenario, decoding a full block, it must be the last sequence,
4968 * otherwise it's an error (invalid input or dimensions).
4969 * In partialDecoding scenario, it's necessary to ensure there is no buffer overflow.
4970 */
4971 /* We must be on the last sequence (or invalid) because of the parsing limitations
4972 * so check that we exactly consume the input and don't overrun the output buffer.
4973 */
4974 if ((ip+length != iend) || (cpy > oend)) {
4975 std::string msg = "Overrun output buffer.";
4977 }
4978
4979 std::memmove(op, ip, length);
4980 ip += length;
4981 op += length;
4982 /* Necessarily EOF when !partialDecoding.
4983 * When partialDecoding, it is EOF if we've either
4984 * filled the output buffer or
4985 * can't proceed with reading an offset for following match.
4986 */
4987 if ((cpy == oend) || (ip >= (iend-2))) {
4988 break;
4989 }
4990 }
4991 else {
4992 memcpy_beyond8(ip, op, cpy);
4993 ip += length;
4994 op = cpy;
4995 }
4996
4997 // Get offset
4998 offset = read_uint16(ip);
4999 ip += 2;
5000 match = op - offset;
5001
5002 // Get matchlength
5003 length = token & ml_mask;
5004
5005_copy_match:
5006 if (length == ml_mask) {
5007
5008 // Add variable length
5009 length += read_variable_length(&ip, iend - lastliterals + 1, false);
5010
5011 // Check for overflow
5012 if ((uintptr_t)(op)+length < (uintptr_t)(op)) {
5013 std::string msg = "Overflow detection.";
5015 }
5016
5017 }
5018 length += minmatch;
5019
5020safe_match_copy:
5021 // Check if offset is outside buffers
5022 if (match < lowPrefix) {
5023 std::string msg = "Offset outside buffers.";
5025 }
5026
5027 // Copy match within block
5028 cpy = op + length;
5029
5030 //
5031 if (offset < 8) {
5032 *(uint32_t*)op = 0;
5033 op[0] = match[0];
5034 op[1] = match[1];
5035 op[2] = match[2];
5036 op[3] = match[3];
5037 match += inc32table[offset];
5038 std::memcpy(op+4, match, 4);
5039 match -= dec64table[offset];
5040 }
5041 else {
5042 std::memcpy(op, match, 8);
5043 match += 8;
5044 }
5045 op += 8;
5046
5047 // ...
5048 if (cpy > oend-match_safeguard_distance) {
5049
5050 // Get ...
5051 uint8_t* oCopyLimit = oend - (wildcopylength-1);
5052
5053 // Check ...
5054 if (cpy > oend-lastliterals) {
5055 std::string msg = "Last 5 Bytes were not uncompressed literals.";
5057 }
5058
5059 //
5060 if (op < oCopyLimit) {
5061 memcpy_beyond8(match, op, oCopyLimit);
5062 match += oCopyLimit - op;
5063 op = oCopyLimit;
5064 }
5065 while (op < cpy) {
5066 *op++ = *match++;
5067 }
5068
5069 } // endif
5070
5071 else {
5072 std::memcpy(op, match, 8);
5073 if (length > 16) {
5074 memcpy_beyond8(match+8, op+8, cpy);
5075 }
5076 } // endelse
5077
5078 // Apply wildcopy correction
5079 op = cpy;
5080
5081 } // endwhile
5082
5083 // Return number of decompressed Bytes
5084 return (int)(((char*)op)-dst);
5085}
5086
5087
5088/***********************************************************************//**
5089 * @brief Read the variable-length literal or match length
5090 *
5091 * @param[in] ip Input pointer.
5092 * @param[in] ilimit Limiting position.
5093 * @param[in] initial_check Performs initial check.
5094 * @return Length literal or match length.
5095 *
5096 * @exception GException::invalid_argument
5097 * Initial check revealed that read limit was reached
5098 * @exception GException::invalid_value
5099 * Read limit was reached or accumulator overflow was detected
5100 *
5101 * @p ilimit specifies the position after which, if length is not decoded,
5102 * the input is necessarily corrupted. In this case an exception is thrown.
5103 *
5104 * If @p initial_check is true then a check @p ip < @p ilimit is performed,
5105 * and if the check is false, an exception is thrown.
5106 *
5107 * The method was inspired by https://github.com/kiyo-masui/bitshuffle and
5108 * specifically the read_variable_length() function in the file lz4.c.
5109 ***************************************************************************/
5110size_t read_variable_length(const uint8_t** ip,
5111 const uint8_t* ilimit,
5112 const bool& initial_check)
5113{
5114 // Initialise length
5115 size_t length = 0;
5116
5117 // If initial check is requested then throw an exception if the read
5118 // limit was reached
5119 if (initial_check && (*ip) >= ilimit) {
5120 std::string msg = "Initial check revealed that read limit was reached.";
5122 }
5123
5124 // ... otherwise determine length
5125 else {
5126
5127 // Allocate size
5128 size_t s;
5129
5130 // Loop until size is no longer 255
5131 do {
5132 // Get size, add it to length and increment input pointer
5133 s = **ip;
5134 length += s;
5135 (*ip)++;
5136
5137 // Throw an exception if read limit was reached
5138 if ((*ip) > ilimit) {
5139 std::string msg = "Read limit was reached.";
5141 }
5142
5143 // Stop with error if accumulator overflow detected
5144 if ((sizeof(length) < 8) && length > ((size_t)(-1)/2)) {
5145 std::string msg = "Accumulator overflow detected.";
5147 }
5148
5149 } while (s == 255);
5150
5151 } // endelse: determined length
5152
5153 // Return
5154 return length;
5155}
5156
5157
5158/***********************************************************************//**
5159* @brief Read unsigned 16 Bit integer stored as little endian
5160*
5161* @param[in] memPtr Input pointer.
5162* @return Unsigned 16 Bit integer.
5163*
5164* Reads an unsigend 16 Bit integer from the current memory location that is
5165* stored in little endian order. The code handles both little and big endian
5166* architectures.
5167***************************************************************************/
5168uint16_t read_uint16(const void* memPtr)
5169{
5170 // Allocate result
5171 uint16_t result;
5172
5173 // If architecture is little endian then just store value in memory
5174 // location
5176 result = *(const uint16_t*)(memPtr);
5177 }
5178
5179 // ... otherwise switch the Byte order
5180 else {
5181 const uint8_t* p = (const uint8_t*)memPtr;
5182 result = (uint16_t)((uint16_t)p[0] | (p[1]<<8));
5183 }
5184
5185 // Return result
5186 return result;
5187}
5188
5189
5190/***********************************************************************//**
5191 * @brief Memory copy
5192 *
5193 * @param[in] srcPtr Input pointer.
5194 * @param[in] dstPtr Pointer to start of output.
5195 * @param[in] dstEnd Pointer to end of output
5196 * @param[in] offset .
5197 *
5198 * @exception
5199 *
5200 * The method was inspired by https://github.com/kiyo-masui/bitshuffle and
5201 * specifically the LZ4_memcpy_using_offset() function in the file lz4.c.
5202 ***************************************************************************/
5203void memcpy_using_offset(const uint8_t* srcPtr,
5204 uint8_t* dstPtr,
5205 uint8_t* dstEnd,
5206 const size_t& offset)
5207{
5208 // Check that destination end pointer is at least 4 Bytes behind start
5209 // pointer
5210 if (dstEnd < dstPtr + 4) {
5211 std::string msg = "Destination end pointer "+
5212 gammalib::str((uint64_t)dstPtr)+
5213 " is not at least 4 Bytes behind start pointer "+
5214 gammalib::str((uint64_t)srcPtr)+".";
5216 }
5217
5218 // Buffer
5219 uint8_t v[8];
5220
5221 switch (offset) {
5222 case 1:
5223 std::memset(v, *srcPtr, 8);
5224 break;
5225 case 2:
5226 std::memcpy(v, srcPtr, 2);
5227 std::memcpy(&v[2], srcPtr, 2);
5228 std::memcpy(&v[4], v, 4);
5229 break;
5230 case 4:
5231 std::memcpy(v, srcPtr, 4);
5232 std::memcpy(&v[4], srcPtr, 4);
5233 break;
5234 default: {
5235 static const unsigned inc32table[8] = {0, 1, 2, 1, 0, 4, 4, 4};
5236 static const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3};
5237 //assert(srcPtr + offset == dstPtr);
5238 if (offset < 8) {
5239 *(uint32_t*)dstPtr = 0;
5240 dstPtr[0] = srcPtr[0];
5241 dstPtr[1] = srcPtr[1];
5242 dstPtr[2] = srcPtr[2];
5243 dstPtr[3] = srcPtr[3];
5244 srcPtr += inc32table[offset];
5245 std::memcpy(dstPtr+4, srcPtr, 4);
5246 srcPtr -= dec64table[offset];
5247 dstPtr += 8;
5248 } else {
5249 std::memcpy(dstPtr, srcPtr, 8);
5250 dstPtr += 8;
5251 srcPtr += 8;
5252 }
5253
5254 memcpy_beyond8(srcPtr, dstPtr, dstEnd);
5255
5256 return;
5257 }
5258 }
5259
5260 std::memcpy(dstPtr, v, 8);
5261 dstPtr += 8;
5262 while (dstPtr < dstEnd) {
5263 std::memcpy(dstPtr, v, 8);
5264 dstPtr += 8;
5265 }
5266
5267 // Return
5268 return;
5269}
5270
5271
5272/***********************************************************************//**
5273 * @brief Memory copy allowing to overwrite up to 8 Bytes beyond the end
5274 *
5275 * @param[in] srcPtr Pointer to start of source.
5276 * @param[in] dstPtr Pointer to start of destination.
5277 * @param[in] dstEnd Pointer to end of destination.
5278 *
5279 * This method is a customised variant of memcpy, which can overwrite up
5280 * to 8 Bytes beyond @p dstEnd. This method copies 8 Bytes a time using
5281 * the std::memcpy() function.
5282 *
5283 * The method was inspired by https://github.com/kiyo-masui/bitshuffle and
5284 * specifically the LZ4_wildCopy8() function in the file lz4.c.
5285 ***************************************************************************/
5286void memcpy_beyond8(const uint8_t* srcPtr,
5287 uint8_t* dstPtr,
5288 uint8_t* dstEnd)
5289{
5290 // Perform memory copy
5291 do {
5292 std::memcpy(dstPtr, srcPtr, 8);
5293 dstPtr += 8;
5294 srcPtr += 8;
5295 } while (dstPtr < dstEnd);
5296
5297 // Return
5298 return;
5299}
5300
5301
5302/***********************************************************************//**
5303 * @brief Memory copy allowing to overwrite up to 32 Bytes beyond the end
5304 *
5305 * @param[in] srcPtr Pointer to start of source.
5306 * @param[in] dstPtr Pointer to start of destination.
5307 * @param[in] dstEnd Pointer to end of destination.
5308 *
5309 * This method is a customised variant of memcpy, which can overwrite up
5310 * to 32 Bytes beyond @p dstEnd. This method copies 16 Bytes a time using
5311 * the std::memcpy() function.
5312 *
5313 * The method was inspired by https://github.com/kiyo-masui/bitshuffle and
5314 * specifically the LZ4_wildCopy8() function in the file lz4.c.
5315 ***************************************************************************/
5316void memory_beyond32(const uint8_t* srcPtr, uint8_t* dstPtr, uint8_t* dstEnd)
5317{
5318 // Perform memory copy (in chunks of 16 Bytes)
5319 do {
5320 std::memcpy(dstPtr, srcPtr, 16);
5321 dstPtr += 16;
5322 srcPtr += 16;
5323 std::memcpy(dstPtr, srcPtr, 16);
5324 dstPtr += 16;
5325 srcPtr += 16;
5326 } while (dstPtr < dstEnd);
5327
5328 // Return
5329 return;
5330}
Exception handler interface definition.
#define G_READ_MESSAGE_ATTRIBUTE
Definition GHdf5.cpp:64
#define G_READ_GROUP
Definition GHdf5.cpp:46
#define G_FREAD_UINT64
Definition GHdf5.cpp:75
#define G_READ_SUPERBLOCK
Definition GHdf5.cpp:41
#define G_MEMCPY_USING_OFFSET
Definition GHdf5.cpp:96
void bitshuffle_decompress(char *input, char *output, const size_t &elements, const size_t &element_size, size_t &block_size)
Decompress and bitshuffle data.
Definition GHdf5.cpp:4438
#define G_DATA_TO_STRING
Definition GHdf5.cpp:83
#define G_READ_MESSAGE_LAYOUT
Definition GHdf5.cpp:60
#define G_FREAD_INT
Definition GHdf5.cpp:73
uint16_t read_uint16(const void *memPtr)
Read unsigned 16 Bit integer stored as little endian.
Definition GHdf5.cpp:5168
#define G_DATA_TO_INT
Definition GHdf5.cpp:80
#define G_FREAD_DATA1
Definition GHdf5.cpp:68
#define G_FREAD_DATA2
Definition GHdf5.cpp:69
#define G_READ_MESSAGE_DATATYPE
Definition GHdf5.cpp:58
uint32_t bitshuffle_read_uint32(const char *buffer)
Read a 32 bit unsigned integer from a buffer big endian order.
Definition GHdf5.cpp:4598
#define G_DECOMPRESS_LZ4
Definition GHdf5.cpp:93
#define G_DATA_FILTER_BITSHUFFLE
Definition GHdf5.cpp:87
void memory_beyond32(const uint8_t *srcPtr, uint8_t *dstPtr, uint8_t *dstEnd)
Memory copy allowing to overwrite up to 32 Bytes beyond the end.
Definition GHdf5.cpp:5316
void memcpy_using_offset(const uint8_t *srcPtr, uint8_t *dstPtr, uint8_t *dstEnd, const size_t &offset)
Memory copy.
Definition GHdf5.cpp:5203
#define G_XML_MSG_ATTRIBUTE
Definition GHdf5.cpp:91
void memcpy_beyond8(const uint8_t *srcPtr, uint8_t *dstPtr, uint8_t *dstEnd)
Memory copy allowing to overwrite up to 8 Bytes beyond the end.
Definition GHdf5.cpp:5286
#define G_READ_BTREE_CHUNKED
Definition GHdf5.cpp:48
#define G_FREAD_DATA_CHUNK
Definition GHdf5.cpp:71
size_t read_variable_length(const uint8_t **ip, const uint8_t *ilimit, const bool &initial_check)
Read the variable-length literal or match length.
Definition GHdf5.cpp:5110
#define G_READ_OBJECT_HEADER
Definition GHdf5.cpp:50
#define G_FREAD_ZERO
Definition GHdf5.cpp:79
#define G_READ_SYMBOL_TABLE_ENTRY
Definition GHdf5.cpp:44
#define G_GLOBAL_HEAP_STRING
Definition GHdf5.cpp:66
int decompress_lz4(const char *src, char *dst, const size_t &srcSize, const size_t &outputSize)
Decompress data using the LZ4 algorithm.
Definition GHdf5.cpp:4720
#define G_FREAD_STRING
Definition GHdf5.cpp:76
uint64_t bitshuffle_read_uint64(const char *buffer)
Read a 64 bit unsigned integer from a buffer big endian order.
Definition GHdf5.cpp:4563
#define G_READ_SYMBOL_TABLE_NODE
Definition GHdf5.cpp:42
#define G_FREAD_DATA_AS_STRING
Definition GHdf5.cpp:77
#define G_READ_OBJECT_HEADER_V2
Definition GHdf5.cpp:53
#define G_READ_MESSAGE_FILTER
Definition GHdf5.cpp:62
#define G_READ_VARIABLE_LENGTH
Definition GHdf5.cpp:94
void bitshuffle_elements(const char *input, char *output, const size_t &elements, const size_t &element_size)
Untranspose bits within elements.
Definition GHdf5.cpp:4633
#define G_READ_OBJECT_HEADER_V1
Definition GHdf5.cpp:52
#define G_DATA_TO_DOUBLE
Definition GHdf5.cpp:81
#define G_FREAD_UINT32
Definition GHdf5.cpp:74
#define G_XML_MSG_TYPE
Definition GHdf5.cpp:89
#define G_DATA_FILTER
Definition GHdf5.cpp:85
#define G_XML_HDF5_ENTRY
Definition GHdf5.cpp:40
HDF5 file handling class definition.
#define G_LOAD
GNdarray sign(const GNdarray &array)
Computes sign of array elements.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
Filename class.
Definition GFilename.hpp:62
int length(void) const
Return length of filename.
std::string url(void) const
Return Uniform Resource Locator (URL)
void clear(void)
Clear file name.
COSI instrument response function class.
Definition GHdf5.hpp:107
GHdf5 * clone(void) const
Clone instance.
Definition GHdf5.cpp:285
GHdf5 & operator=(const GHdf5 &file)
Assignment operator.
Definition GHdf5.cpp:234
void read_group(FILE *fptr, const uint64_t &address_btree, const uint64_t &address_heap, GXmlElement *group, const int &indent)
Read and handle HDF5 group.
Definition GHdf5.cpp:923
void read_object_header_v2(FILE *fptr, GXmlElement *header, const int &indent)
Read object header version 2.
Definition GHdf5.cpp:1356
void read_object_header_message(FILE *fptr, const int &type, GXmlElement *message, const int &indent)
Read one object header message.
Definition GHdf5.cpp:1380
GXml m_xml
Definition GHdf5.hpp:203
std::string print(const GChatter &chatter=NORMAL) const
Print HDF5 file.
Definition GHdf5.cpp:407
std::string global_heap_string(FILE *fptr, const uint64_t &address, const int &id, const uint32_t &length)
Get string from global heap.
Definition GHdf5.cpp:2684
void debug_msg(const std::string &msg, const int &indent)
Show debug message.
Definition GHdf5.cpp:2874
const GXmlElement * xml_hdf5_entry(const std::string &name) const
Return XML element to entry tag.
Definition GHdf5.cpp:371
void read_message_attribute(FILE *fptr, GXmlElement *message, std::string &msg)
Read Attribute message.
Definition GHdf5.cpp:2491
void read_symbol_table_node(FILE *fptr, const uint64_t &address, const uint64_t &offset, const std::string &heap, GXmlElement *table, const int &indent)
Read HDF5 symbol table node.
Definition GHdf5.cpp:720
GHdf5(void)
Void constructor.
Definition GHdf5.cpp:156
void read_symbol_table_entry(FILE *fptr, const uint64_t &address, const uint64_t &offset, const std::string &heap, GXmlElement *entry, const int &indent)
Read and handle HDF5 symbol table entry.
Definition GHdf5.cpp:809
void read_message_datatype(FILE *fptr, GXmlElement *message, std::string &msg)
Read datatype message.
Definition GHdf5.cpp:1938
int m_length
Definition GHdf5.hpp:202
std::string extract(const std::string &string, const int &pos)
Extract string from position until next null termination.
Definition GHdf5.cpp:2916
void read_message_layout(FILE *fptr, GXmlElement *message, std::string &msg)
Read Data Storage - Layout message.
Definition GHdf5.cpp:2203
int pad2eight(const int &nbytes)
Pad number of Bytes to 8 Bytes.
Definition GHdf5.cpp:2948
GFilename m_filename
Definition GHdf5.hpp:200
void load(const GFilename &filename)
Load data from HDF5 file into instance.
Definition GHdf5.cpp:301
void read_message_filter(FILE *fptr, GXmlElement *message, std::string &msg)
Read Data Storage - Filter pipeline message.
Definition GHdf5.cpp:2378
void read_object_header_v1(FILE *fptr, GXmlElement *header, const int &indent)
Read object header version 1.
Definition GHdf5.cpp:1249
int m_offset
Definition GHdf5.hpp:201
void copy_members(const GHdf5 &file)
Copy class members.
Definition GHdf5.cpp:464
void clear(void)
Clear instance.
Definition GHdf5.cpp:267
void read(FILE *fptr)
Read data from HDF5 file into instance.
Definition GHdf5.cpp:338
void read_object_header(FILE *fptr, const uint64_t &address, GXmlElement *header, const int &indent)
Read object header.
Definition GHdf5.cpp:1207
void read_btree_chunked(FILE *fptr, const uint64_t &address, const int &dimensions, GXmlElement *btree)
Read HDF5 B-tree for chunked data.
Definition GHdf5.cpp:1073
virtual ~GHdf5(void)
Destructor.
Definition GHdf5.cpp:207
void read_superblock(FILE *fptr)
Read HDF5 file superblock.
Definition GHdf5.cpp:516
std::string hexaddress(const uint64_t &address)
Format address for debugging.
Definition GHdf5.cpp:2897
void free_members(void)
Delete class members.
Definition GHdf5.cpp:480
void init_members(void)
Initialise class members.
Definition GHdf5.cpp:446
void read_message_dataspace(FILE *fptr, GXmlElement *message, std::string &msg)
Read dataspace message.
Definition GHdf5.cpp:1760
XML element node class.
const GXmlAttribute * attribute(const int &index) const
Return attribute.
int integer(void) const
Return integer value.
bool has_attribute(const std::string &name) const
Check if element has a given attribute.
virtual GXmlNode * append(const GXmlNode &node)
Append XML child node.
Definition GXmlNode.cpp:287
virtual GXmlElement * element(const int &index)
Return pointer to GXMLElement child.
Definition GXmlNode.cpp:640
virtual int elements(void) const
Return number of GXMLElement children of node.
Definition GXmlNode.cpp:586
XML text node class.
Definition GXmlText.hpp:43
void clear(void)
Clear XML object.
Definition GXml.cpp:232
GXmlElement * element(const int &index)
Return pointer to child element.
Definition GXml.cpp:419
GXmlNode * append(const GXmlNode &node)
Append child node to XML document root.
Definition GXml.cpp:279
bool is_empty(void) const
Signals if document has no child nodes.
Definition GXml.hpp:279
std::string data_filter_bitshuffle(const std::string &data, const GXmlElement *filter)
Filter data according to Bitshuffle algorithm.
Definition GHdf5.cpp:3903
const GXmlElement * xml_msg_type(const GXmlElement *header, const std::string &type, const int &number=0)
Return specific occurence of header message of given type.
Definition GHdf5.cpp:4026
std::string fread_data_chunk(FILE *fptr, const GXmlElement *chunk, const GXmlElement *dataspace, const GXmlElement *datatype, const GXmlElement *datalayout, const GXmlElement *datafilter=NULL)
Read data chunk.
Definition GHdf5.cpp:3172
int data_to_int(const char *data, const GXmlElement *datatype)
Convert data into integer value.
Definition GHdf5.cpp:3558
std::string fread_data(FILE *fptr, const int &nbytes)
Read data from HDF5 file.
Definition GHdf5.cpp:2984
int fread_int(FILE *fptr, const int &nbytes)
Read data as integer from HDF5 file.
Definition GHdf5.cpp:3256
int xml_msg_attributes(const GXmlElement *header, const std::string &name="")
Return number of "Attribute" messages in header.
Definition GHdf5.cpp:4138
void fread_zero(FILE *fptr, const int &nbytes)
Read zero data from HDF5 file.
Definition GHdf5.cpp:3498
double data_to_double(const char *data, const GXmlElement *datatype)
Convert data into double precision floating point value.
Definition GHdf5.cpp:3639
bool xml_has_msg_type(const GXmlElement *header, const std::string &type, const int &number=0)
Checks if specific occurence of header message of given type exists.
Definition GHdf5.cpp:4089
std::string classname(const int &cls)
Convert datatype class into classname.
Definition GHdf5.cpp:4365
std::string data_to_string(const char *data, const GXmlElement *datatype)
Convert data into string.
Definition GHdf5.cpp:3717
std::string data_filter(const std::string &data, const GXmlElement *datafilter)
Filter data.
Definition GHdf5.cpp:3822
std::string fread_string(FILE *fptr, const int &nbytes)
Read string data from HDF5 file.
Definition GHdf5.cpp:3399
const GXmlElement * xml_msg_attribute(const GXmlElement *header, const std::string &name, const int &number=0)
Return "Attribute" message XML element with specified name.
Definition GHdf5.cpp:4193
uint32_t fread_uint32(FILE *fptr, const int &nbytes)
Read data as unsiged 32 Bit integer from HDF5 file.
Definition GHdf5.cpp:3302
bool xml_has_msg_attribute(const GXmlElement *header, const std::string &name, const int &number=0)
Checks if "Attribute" message XML element with specified name exists.
Definition GHdf5.cpp:4261
uint64_t fread_uint64(FILE *fptr, const int &nbytes)
Read data as unsiged 64 Bit integer from HDF5 file.
Definition GHdf5.cpp:3348
std::string fread_data_as_string(FILE *fptr, const GXmlElement *datatype)
Read data with any data type as a string.
Definition GHdf5.cpp:3456
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1136
std::string number(const std::string &noun, const int &number)
Convert singular noun into number noun.
Definition GTools.cpp:1160
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:508
std::string order(const int &number)
Convert number into order noun.
Definition GTools.cpp:1185
bool little_endian(void)
Signal if architecture stores integers as little endian.
Definition GTools.hpp:232
unsigned long long toulonglong(const std::string &arg)
Convert string into unsigned long long value.
Definition GTools.cpp:889
int toint(const std::string &arg)
Convert string into integer value.
Definition GTools.cpp:814
std::string expand_env(const std::string &arg)
Expand environment variables in string.
Definition GTools.cpp:233
const GXmlElement * xml_get_element_by_attribute(const GXmlElement *element, const std::string &tag, const std::string &name, const std::string &value)
Return XML element for a given tag and name/value attribute.
Definition GTools.cpp:2088