|
|
|
@ -1,19 +1,39 @@ |
|
|
|
|
#ifndef MATLAB_IO_HPP_ |
|
|
|
|
#define MATLAB_IO_HPP_ |
|
|
|
|
|
|
|
|
|
#include <sstream> |
|
|
|
|
#include <fstream> |
|
|
|
|
#include <zlib.h> |
|
|
|
|
#include <opencv2/core.hpp> |
|
|
|
|
#include <opencv2/core/persistence.hpp> |
|
|
|
|
#include "primitives.hpp" |
|
|
|
|
#include "bridge.hpp" |
|
|
|
|
#include "mxarray.hpp" |
|
|
|
|
#include "map.hpp" |
|
|
|
|
|
|
|
|
|
namespace Matlab { |
|
|
|
|
namespace IO { |
|
|
|
|
static const int VERSION_5 = 5; |
|
|
|
|
static const int VERSION_73 = 73; |
|
|
|
|
class RandomAccessRead {}; |
|
|
|
|
class SequentialWrite {}; |
|
|
|
|
static const int Version5 = 5; |
|
|
|
|
static const int Version73 = 73; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class Index { |
|
|
|
|
private: |
|
|
|
|
// predeclarations
|
|
|
|
|
class IONode; |
|
|
|
|
class IONodeIterator; |
|
|
|
|
class MatlabIO; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// FILE AS A DATA STRUCTURE
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
class IONode { |
|
|
|
|
protected: |
|
|
|
|
//! the name of the field (if associative container)
|
|
|
|
|
std::string name_; |
|
|
|
|
//! the size of the field
|
|
|
|
|
std::vector<size_t> size_; |
|
|
|
|
//! beginning of the data field in the file
|
|
|
|
|
size_t begin_; |
|
|
|
|
//! address after the last data field
|
|
|
|
@ -26,36 +46,126 @@ private: |
|
|
|
|
bool compressed_; |
|
|
|
|
//! are the descendents associative (mappings)
|
|
|
|
|
bool associative_; |
|
|
|
|
//! the descendents of this node
|
|
|
|
|
union { |
|
|
|
|
//! valid if the container is a sequence (list)
|
|
|
|
|
std::vector<Index> sequence_; |
|
|
|
|
//! valid if the container is a mapping (associative)
|
|
|
|
|
Map<std::string, Index> mapping_; |
|
|
|
|
}; |
|
|
|
|
//! is this a leaf node containing data, or an interior node
|
|
|
|
|
bool leaf_; |
|
|
|
|
//! the data stream from which the file was indexed
|
|
|
|
|
cv::Ptr<std::istream> stream_; |
|
|
|
|
//! valid if the container is a sequence (list)
|
|
|
|
|
std::vector<IONode> sequence_; |
|
|
|
|
//! valid if the container is a mapping (associative)
|
|
|
|
|
Map<std::string, IONode> mapping_; |
|
|
|
|
IONode(const std::string& name, const std::Vector<size_t>& size, size_t begin, size_t end,
|
|
|
|
|
int stored_type, int type, bool compressed, bool associative, bool leaf, istream& stream) : |
|
|
|
|
name_(name), size_(size), begin_(begin), end_(end), stored_type_(stored_type), type_(type), |
|
|
|
|
compressed_(compressed), associative_(associative), leaf_(leaf), stream_(stream) {} |
|
|
|
|
public: |
|
|
|
|
std::string name() const { return name_; } |
|
|
|
|
std::vector<size_t> size() const { return size_; } |
|
|
|
|
size_t begin() const { return begin_; } |
|
|
|
|
size_t end() const { return end_; } |
|
|
|
|
int stored_type() const { return stored_type_; } |
|
|
|
|
int type() const { return type_; } |
|
|
|
|
bool compressed() const { return compressed_; } |
|
|
|
|
bool associative() const { return associative_; } |
|
|
|
|
bool leaf() const { return leaf_; } |
|
|
|
|
IONode() : begin_(0), end_(0), stored_type_(0), type_(0), leaf_(true) {} |
|
|
|
|
|
|
|
|
|
#if __cplusplus >= 201103L |
|
|
|
|
// conversion operators
|
|
|
|
|
template <typename T> void operator=(const T& obj) { static_assert(0, "Unimplemented specialization for given type"); } |
|
|
|
|
template <typename T> operator T() { static_assert(0, "Unimplemented specialization for given type"); } |
|
|
|
|
#else |
|
|
|
|
// conversion operators
|
|
|
|
|
template <typename T> void operator=(const T& obj) { T::unimplemented_specialization; } |
|
|
|
|
template <typename T> operator T() { T::unimplemented_specialization; } |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
void swap(const IONode& other) { |
|
|
|
|
using std::swap; |
|
|
|
|
swap(name_, other.name_); |
|
|
|
|
swap(size_, other.size_); |
|
|
|
|
swap(begin_, other.begin_); |
|
|
|
|
swap(end_, other.end_); |
|
|
|
|
swap(stored_type_, other.stored_type_); |
|
|
|
|
swap(type_, other.type_); |
|
|
|
|
swap(compressed_, other.compressed_); |
|
|
|
|
swap(associative_, other.associative_); |
|
|
|
|
swap(leaf_, other.leaf_); |
|
|
|
|
swap(stream_, other.stream_); |
|
|
|
|
swap(sequence_, other.sequence_); |
|
|
|
|
swap(mapping_, other.mapping_); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class SequenceIONode : public IONode { |
|
|
|
|
public: |
|
|
|
|
std::vector<IONode>& sequence() { return sequence_; } |
|
|
|
|
SequenceIONode(const std::string& name, const std::Vector<size_t>& size, size_t begin, size_t end,
|
|
|
|
|
int stored_type, int type, const std::istream& stream) :
|
|
|
|
|
IONode(name, size, begin, end, stored_type, type, false, false, false, stream) {} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class MappingIONode : public IONode { |
|
|
|
|
public: |
|
|
|
|
Map<std::string, IONode>& mapping() { return mapping_; } |
|
|
|
|
MappingIONode(const std::string& name, const std::Vector<size_t>& size, size_t begin, size_t end,
|
|
|
|
|
int stored_type, int type, const std::istream& stream) :
|
|
|
|
|
IONode(name, size, begin, end, stored_type, type, false, true, false, stream) {} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class LeafIONode : public IONode { |
|
|
|
|
LeafIONode(const std::string& name, const std::Vector<size_t>& size, size_t begin, size_t end,
|
|
|
|
|
int stored_type, int type, const std::istream& stream) :
|
|
|
|
|
IONode(name, size, begin, end, stored_type, type, false, false, true, stream) {} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class MatlabIONode { |
|
|
|
|
class CompressedIONode : public IONode { |
|
|
|
|
private: |
|
|
|
|
std::istringstream uncompressed_stream_; |
|
|
|
|
std::vector<char> data_; |
|
|
|
|
public: |
|
|
|
|
CompressedIONode(const std::string& name, const std::Vector<size_t>& size, size_t begin, size_t end,
|
|
|
|
|
int stored_type, int type, const std::stream& stream) :
|
|
|
|
|
IONode(name, size, begin, end, stored_type, type, true, false, false, stream) {} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class Header : public IONode { |
|
|
|
|
Header(const std::string& name, const std::Vector<size_t>& size, size_t begin, size_t end,
|
|
|
|
|
int stored_type, int type, const std::stream& stream) :
|
|
|
|
|
IONode(name, size, begin, end, stored_type, type, true, false, false, stream) {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// FILE NODE
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
class IONodeIterator : public std::iterator<std::random_access_iterator_tag, MatlabIONode> { |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// MATLABIO
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
class MatlabIO { |
|
|
|
|
private: |
|
|
|
|
// member variables
|
|
|
|
|
static const int HEADER_LENGTH = 116; |
|
|
|
|
static const int SUBSYS_LENGTH = 8; |
|
|
|
|
static const int ENDIAN_LENGTH = 2; |
|
|
|
|
char header_[HEADER_LENGTH+1]; |
|
|
|
|
char subsys_[SUBSYS_LENGTH+1]; |
|
|
|
|
char endian_[ENDIAN_LENGTH+1]; |
|
|
|
|
std::string header_; |
|
|
|
|
std::string subsys_; |
|
|
|
|
std::string endian_; |
|
|
|
|
int version_; |
|
|
|
|
bool byte_swap_; |
|
|
|
|
std::string filename_; |
|
|
|
|
// uses a custom stream buffer for fast memory-mapped access and endian swapping
|
|
|
|
|
std::fstream stream_; |
|
|
|
|
std::ifstream::pos_type stream_pos_; |
|
|
|
|
//! the main file index. The top-level index must be associative
|
|
|
|
|
Index index_; |
|
|
|
|
IONode index_; |
|
|
|
|
|
|
|
|
|
// internal methods
|
|
|
|
|
void getFileHeader(); |
|
|
|
@ -64,18 +174,31 @@ private: |
|
|
|
|
void getHeader(); |
|
|
|
|
void setHeader(); |
|
|
|
|
|
|
|
|
|
CompressedIONode uncompress(const IONode& node); |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
// construct/destruct
|
|
|
|
|
MatlabIO() {} |
|
|
|
|
MatlabIO() : header_(HEADER_LENGTH+1, '\0'), subsys_(SUBSYS_LENGTH+1, '\0'),
|
|
|
|
|
endian_(ENDIAN_LENGTH+1, '\0'), byte_swap(false), stream_pos_(0) {} |
|
|
|
|
~MatlabIO {} |
|
|
|
|
|
|
|
|
|
// global read and write routines
|
|
|
|
|
std::string filename(void); |
|
|
|
|
bool open(const std::string& filename, const std::string& mode); |
|
|
|
|
bool open(const std::string& filename, std::ios_base::openmode mode); |
|
|
|
|
bool isOpen() const; |
|
|
|
|
void close();
|
|
|
|
|
void clear(); |
|
|
|
|
|
|
|
|
|
// index the contents of the file
|
|
|
|
|
void index(); |
|
|
|
|
|
|
|
|
|
// print all of the top-level variables in the file
|
|
|
|
|
} |
|
|
|
|
void printRootIndex() const; |
|
|
|
|
void printFullIndex() const; |
|
|
|
|
|
|
|
|
|
// FileNode operations
|
|
|
|
|
IONode root() const; |
|
|
|
|
IONode operator[](const String& nodename) const; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
|