Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include "MantidKernel/HDFDescriptor.h"
#include "MantidKernel/Exception.h"
#include <nexus/NeXusFile.hpp>
#include <nexus/NeXusException.hpp>
#include <Poco/File.h>
#include <Poco/Path.h>
#include <cstring>
namespace Mantid
{
namespace Kernel
{
//---------------------------------------------------------------------------------------------------------------------------
// static HDFDescriptor constants
//---------------------------------------------------------------------------------------------------------------------------
/// Size of HDF magic number
const size_t HDFDescriptor::HDFMagicSize = 4;
/// HDF cookie that is stored in the first 4 bytes of the file.
const unsigned char HDFDescriptor::HDFMagic[4] = {'\016','\003','\023','\001'}; // From HDF4::hfile.h
/// Size of HDF5 signature
size_t HDFDescriptor::HDF5SignatureSize = 8;
/// signature identifying a HDF5 file.
const unsigned char HDFDescriptor::HDF5Signature[8] = { 137, 'H', 'D', 'F', '\r', '\n', '\032', '\n' };
namespace
{
//---------------------------------------------------------------------------------------------------------------------------
// Anonymous helper methods to use isHDF methods to use an open file handle
//---------------------------------------------------------------------------------------------------------------------------
/**
* Currently simply checks for the HDF signatures and returns true if one of them is found
* @param fileHandle A file handled opened and pointing at the start of the file. On return the
* fileHandle is left at the start of the file
* @param version One of the HDFDescriptor::Version enumerations specifying the required version
* @return True if the file is considered hierarchical, false otherwise
*/
bool isHDFHandle(FILE *fileHandle, HDFDescriptor::Version version)
{
if(!fileHandle) throw std::invalid_argument("HierarchicalFileDescriptor::isHierarchical - Invalid file handle");
bool result(false);
// HDF4 check requires 4 bytes, HDF5 check requires 8 bytes
// Use same buffer and waste a few bytes if only checking HDF4
unsigned char buffer[8] = {'0','0','0','0','0','0','0','0'};
std::fread(static_cast<void*>(&buffer), sizeof(unsigned char), HDFDescriptor::HDF5SignatureSize, fileHandle);
// Number of bytes read doesn't matter as if it is not enough then the memory simply won't match
// as the buffer has been "zeroed"
if(version == HDFDescriptor::Version5 || version == HDFDescriptor::AnyVersion )
{
result = (std::memcmp(&buffer, &HDFDescriptor::HDF5Signature, HDFDescriptor::HDF5SignatureSize) == 0);
}
if(!result && (version == HDFDescriptor::Version4 || version == HDFDescriptor::AnyVersion) )
{
result = (std::memcmp(&buffer, &HDFDescriptor::HDFMagic, HDFDescriptor::HDFMagicSize) == 0);
}
// Return file stream to start of file
std::rewind(fileHandle);
return result;
}
}
//---------------------------------------------------------------------------------------------------------------------------
// static HDFDescriptor methods
//---------------------------------------------------------------------------------------------------------------------------
/**
* Checks for the HDF signatures and returns true if one of them is found
* @param filename A string filename to check
* @param version One of the HDFDescriptor::Version enumerations specifying the required version
* @return True if the file is considered hierarchical, false otherwise
*/
bool HDFDescriptor::isHDF(const std::string & filename, const Version version)
{
FILE *fd = fopen(filename.c_str(), "rb");
if(!fd)
{
throw std::invalid_argument("HierarchicalFileDescriptor::isHierarchical - Unable to open file '" + filename + "'");
}
const bool result = isHDFHandle(fd, version); // use anonymous helper
fclose(fd);
return result;
}
//---------------------------------------------------------------------------------------------------------------------------
// HDFDescriptor public methods
//---------------------------------------------------------------------------------------------------------------------------
/**
* Constructs the wrapper
* @param filename A string pointing to an existing file
* @throws std::invalid_argument if the file is not identified to be hierarchical. This currently
* involves simply checking for the signature if a HDF file at the start of the file
*/
HDFDescriptor::HDFDescriptor(const std::string & filename)
: m_filename(), m_extension()
{
if(filename.empty())
{
throw std::invalid_argument("HDFDescriptor() - Empty filename '" + filename + "'");
}
if(!Poco::File(filename).exists())
{
throw std::invalid_argument("HDFDescriptor() - File '" + filename + "' does not exist");
}
initialize(filename);
}
/**
* @param path A string giving a path using UNIX-style path separators (/), e.g. /raw_data_1, /entry/bank1
* @return True if the path exists in the file, false otherwise
*/
bool HDFDescriptor::pathExists(const std::string& path) const
{
return true;
}
//---------------------------------------------------------------------------------------------------------------------------
// HDFDescriptor private methods
//---------------------------------------------------------------------------------------------------------------------------
/**
* Creates the internal cached structure of the file as a tree of nodes
*/
void HDFDescriptor::initialize(const std::string& filename)
{
m_filename = filename;
m_extension = "." + Poco::Path(filename).getExtension();
try
{
::NeXus::File file(this->filename());
}
catch(::NeXus::Exception &)
{
throw std::invalid_argument("HDFDescriptor::initialize - File '" + filename + "' does not look like a HDF file.");
}
// // Root node has no type and is named "/"
// m_root->name = "/";
//
// addChildren(file, "/", m_root);
//
// auto rootEntries = file.getEntries();
// for(auto it = rootEntries.begin(); rootEntries.end(); ++it)
// {
// auto node = boost::make_shared<Node>();
// node->name = it->first;
// node->type = it->second;
// m_roots.insert(std::make_pair(it->first, node));
// }
}
} // namespace Kernel
} // namespace Mantid