Browse Source

first commit

Patrik Kovacs 6 years ago
parent
commit
b77da98806

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+.idea
+build
+cmake-build*

+ 51 - 0
CMakeLists.txt

@@ -0,0 +1,51 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(HDF4CPP)
+
+list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
+
+
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+find_package(HDF4)
+add_library(hdf4cpp
+        lib/HdfFile.cpp
+        lib/HdfItem.cpp
+        lib/HdfAttribute.cpp)
+
+target_include_directories(hdf4cpp
+        PUBLIC
+        include/
+        ${HDF4_INCLUDE_DIRS}
+        )
+
+target_link_libraries(hdf4cpp
+        ${HDF4_LIBRARIES}
+        )
+
+enable_testing()
+find_package(GTest REQUIRED)
+find_package(Threads REQUIRED)
+
+add_executable(hdf4cpp-tests
+        tests/HdfFileTest.cpp)
+
+target_include_directories(hdf4cpp-tests
+        PRIVATE
+        ${GTEST_INCLUDE_DIRS}
+        ${hdf4cpp_INCLUDE_DIRS}
+        )
+target_link_libraries(hdf4cpp-tests
+        ${GTEST_BOTH_LIBRARIES}
+        ${CMAKE_THREAD_LIBS_INIT}
+        hdf4cpp
+        )
+
+if (NOT DEFINED TEST_DATA_PATH)
+    set(TEST_DATA_PATH "${PROJECT_SOURCE_DIR}/tests/test_data/")
+    message(STATUS "No path to test data defined, using ${TEST_DATA_PATH} as default")
+endif ()
+target_compile_definitions(hdf4cpp-tests PRIVATE
+        "TEST_DATA_PATH=\"${TEST_DATA_PATH}\"")

+ 35 - 0
cmake/FindHDF4.cmake

@@ -0,0 +1,35 @@
+# - Find the HDF4 library together with dependencies...
+# This module defines the following variables:
+#  HDF4_INCLUDE_DIRS - include directories for HDF4
+#  HDF4_LIBRARIES - libraries to link against HDF4
+#  HDF4_FOUND - true if HDF4 has been found and can be used
+
+find_path(HDF4_INCLUDE_DIR hdf.h PATH_SUFFIXES hdf)
+find_library(MFHDF_LIB NAMES mfhdf mfhdfalt)
+find_library(DF_LIB NAMES df dfalt)
+
+# dependencies for the static library version of hdf4
+find_package(JPEG)
+find_package(ZLIB)
+
+set(HDF4_INCLUDE_DIRS ${HDF4_INCLUDE_DIR})
+set(HDF4_LIBRARIES
+  ${MFHDF_LIB}
+  ${DF_LIB}
+  ${JPEG_LIBRARIES}
+  ${ZLIB_LIBRARIES}
+  )
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(HDF4
+	FOUND_VAR HDF4_FOUND
+	REQUIRED_VARS MFHDF_LIB DF_LIB HDF4_INCLUDE_DIR JPEG_LIBRARIES ZLIB_LIBRARIES) 
+
+if(HDF4_FOUND)
+	message(-- " HDF4 include path: ${HDF4_INCLUDE_DIRS}")
+	message(-- " HDF4 libs:  ${HDF4_LIBRARIES}")
+else()
+	message(WARNING "HDF4 not found")	
+endif()
+
+mark_as_advanced(HDF4_INCLUDE_DIR MFHDF_LIB DF_LIB)

+ 101 - 0
include/hdf4cpp/HdfAttribute.h

@@ -0,0 +1,101 @@
+//
+// Created by patrik on 11.08.17.
+//
+
+#ifndef HDF4CPP_HDFATTRIBUTE_H
+#define HDF4CPP_HDFATTRIBUTE_H
+
+#include <hdf/hdf.h>
+#include <hdf/mfhdf.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <memory>
+
+class HdfAttributeBase {
+public:
+    HdfAttributeBase(int32 id, int32 index) : id(id), index(index) {}
+    virtual ~HdfAttributeBase() {}
+    virtual bool isValid() const { return index != FAIL; }
+    virtual Type getType() const = 0;
+
+    virtual intn size() const = 0;
+
+    template <class T> bool get(std::vector<T> &dest) {
+        intn length = size();
+        if(length != FAIL) {
+            auto it = typeSizeMap.find(getDataType());
+            if(it != typeSizeMap.end()) {
+                if(it->second != sizeof(T)) {
+                    throw std::runtime_error("HDF4CPP: type size missmatch");
+                }
+            } else {
+                throw std::runtime_error("HDF4CPP: hdf data set type not supported");
+            }
+            dest.resize(length);
+            return get(dest.data());
+        } else {
+            return false;
+        }
+    }
+
+protected:
+    int32 id;
+    int32 index;
+
+    virtual bool get(void *dest) = 0;
+    virtual int32 getDataType() const = 0;
+};
+
+class HdfDatasetAttribute : public HdfAttributeBase {
+public:
+    HdfDatasetAttribute(int32 id, const std::string& name);
+    Type getType() const;
+
+    intn size() const;
+
+private:
+    intn _size;
+    int32 dataType;
+
+    bool get(void *dest);
+    int32 getDataType() const;
+};
+
+class HdfGroupAttribute : public HdfAttributeBase {
+public:
+    HdfGroupAttribute(int32 id, const std::string& name);
+    Type getType() const;
+
+    intn size() const;
+
+private:
+    intn _size;
+    int32 dataType;
+
+    bool get(void *dest);
+    int32 getDataType() const;
+};
+
+class HdfAttribute {
+public:
+    HdfAttribute(HdfAttributeBase *attribute) : attribute(attribute) {}
+    HdfAttribute(const HdfAttribute&) = delete;
+    HdfAttribute(HdfAttribute&& attribute);
+    bool isValid() const;
+    Type getType() const;
+
+    intn size() const;
+    template <class T> bool get(std::vector<T> &dest) {
+        if(isValid()) {
+            return attribute->get(dest);
+        } else {
+            return false;
+        }
+    }
+
+private:
+    std::unique_ptr<HdfAttributeBase> attribute;
+};
+
+#endif //HDF4CPP_HDFATTRIBUTE_H

+ 36 - 0
include/hdf4cpp/HdfDefines.h

@@ -0,0 +1,36 @@
+//
+// Created by patrik on 11.08.17.
+//
+
+#ifndef HDF4CPP_HDFDEFINES_H
+#define HDF4CPP_HDFDEFINES_H
+
+#include <map>
+#include <hdf/mfhdf.h>
+
+#define MAX_DIMENSION 32
+#define MAX_NAME_LENGTH 100
+
+enum Type {DATASET, GROUP, NONE};
+
+const std::multimap<int32, int32> typeSizeMap = {
+        {DFNT_CHAR, SIZE_CHAR},
+        {DFNT_CHAR8, SIZE_CHAR8},
+        {DFNT_CHAR16, SIZE_CHAR16},
+        {DFNT_FLOAT32, SIZE_FLOAT32},
+        {DFNT_FLOAT64, SIZE_FLOAT64},
+        {DFNT_FLOAT128, SIZE_FLOAT128},
+        {DFNT_INT8, SIZE_INT8},
+        {DFNT_INT16, SIZE_INT16},
+        {DFNT_INT32, SIZE_INT32},
+        {DFNT_INT64, SIZE_INT64},
+        {DFNT_UINT8, SIZE_UINT8},
+        {DFNT_UINT16, SIZE_UINT16},
+        {DFNT_UINT32, SIZE_UINT32},
+        {DFNT_UINT64, SIZE_UINT64},
+        {DFNT_UCHAR, SIZE_UCHAR},
+        {DFNT_UCHAR8, SIZE_UCHAR8},
+        {DFNT_UCHAR16, SIZE_UCHAR16},
+};
+
+#endif //HDF4CPP_HDFDEFINES_H

+ 40 - 0
include/hdf4cpp/HdfFile.h

@@ -0,0 +1,40 @@
+//
+// Created by patrik on 10.08.17.
+//
+
+#ifndef GRASP_SEGMENTER_HDFFILE_H
+#define GRASP_SEGMENTER_HDFFILE_H
+
+#include <string>
+#include <vector>
+
+#include <hdf4cpp/HdfItem.h>
+
+class HdfFile {
+  public:
+    HdfFile(const std::string& path);
+    ~HdfFile();
+    bool isValid();
+
+    HdfItem get(const std::string& name);
+    std::vector<HdfItem> getAll(const std::string& name);
+
+    HdfAttribute getAttribute(const std::string& name);
+
+    class Iterator;
+
+    HdfItem::Iterator begin() const;
+    HdfItem::Iterator end() const;
+
+  private:
+    int32 getDatasetId(const std::string& name);
+    int32 getGroupId(const std::string& name);
+
+    std::vector<int32> getDatasetIds(const std::string& name);
+    std::vector<int32> getGroupIds(const std::string& name);
+
+    int32 sId;
+    int32 vId;
+};
+
+#endif //GRASP_SEGMENTER_HDFFILE_H

+ 183 - 0
include/hdf4cpp/HdfItem.h

@@ -0,0 +1,183 @@
+//
+// Created by patrik on 11.08.17.
+//
+
+#ifndef HDF4CPP_HDFITEM_H
+#define HDF4CPP_HDFITEM_H
+
+#include <hdf4cpp/HdfDefines.h>
+#include <hdf4cpp/HdfAttribute.h>
+#include <iostream>
+#include <map>
+#include <memory>
+#include <vector>
+#include <hdf/hdf.h>
+
+class HdfItemBase {
+public:
+
+    HdfItemBase(int32 id) : id(id) {}
+    virtual ~HdfItemBase() {}
+    virtual bool isValid() const { return id != FAIL; }
+
+    virtual Type getType() const = 0;
+    virtual int32 getId() const = 0;
+    virtual std::string getName() const = 0;
+    virtual std::vector<int32> getDims() = 0;
+    virtual intn size() const = 0;
+
+    template <class T> bool read(std::vector<T> &dest) {
+        intn length = size();
+        if(length != FAIL) {
+            auto it = typeSizeMap.find(getDataType());
+            if(it != typeSizeMap.end()) {
+                if(it->second != sizeof(T)) {
+                    throw std::runtime_error("HDF4CPP: type size missmatch");
+                }
+            } else {
+                throw std::runtime_error("HDF4CPP: hdf data set type not supported");
+            }
+            dest.resize(length);
+            return read(dest.data());
+        } else {
+            return false;
+        }
+    }
+
+    virtual HdfAttribute getAttribute(const std::string& name) = 0;
+
+protected:
+    int32 id;
+
+    virtual bool read(void *dest) = 0;
+    virtual int32 getDataType() const = 0;
+};
+
+class HdfDatasetItem : public HdfItemBase {
+public:
+    HdfDatasetItem(int32 id);
+    ~HdfDatasetItem();
+
+    Type getType() const;
+    int32 getId() const;
+    std::string getName() const;
+    std::vector<int32> getDims();
+    intn size() const;
+    HdfAttribute getAttribute(const std::string& name);
+
+private:
+    intn _size;
+    int32 dataType;
+    std::string name;
+
+    bool read(void *dest);
+    int32 getDataType() const;
+};
+
+class HdfGroupItem : public HdfItemBase {
+public:
+    HdfGroupItem(int32 id);
+    ~HdfGroupItem();
+
+    Type getType() const;
+    int32 getId() const;
+    std::string getName() const;
+    std::vector<int32> getDims();
+    intn size() const;
+
+    HdfAttribute getAttribute(const std::string& name);
+
+private:
+    std::string name;
+
+    bool read(void *dest);
+    int32 getDataType() const;
+};
+
+class HdfItem {
+public:
+    HdfItem(HdfItemBase *item, int32 sId, int32 vId) : item(item), sId(sId), vId(vId) {}
+    HdfItem(const HdfItem& item) = delete;
+    HdfItem(HdfItem&& item);
+    bool isValid() const;
+
+    Type getType() const;
+    std::string getName() const;
+    std::vector<int32> getDims();
+    intn size() const;
+    HdfAttribute getAttribute(const std::string& name);
+
+    template <class T> bool read(std::vector<T> &dest) {
+        if(isValid()) {
+            return item->read(dest);
+        } else {
+            return false;
+        }
+    }
+
+    class Iterator;
+
+    Iterator begin() const;
+    Iterator end() const;
+
+private:
+    std::unique_ptr<HdfItemBase> item;
+    int32 sId;
+    int32 vId;
+};
+
+class HdfItem::Iterator : public std::iterator<std::bidirectional_iterator_tag, HdfItem> {
+public:
+    Iterator(int32 sId, int32 vId, int32 key, int32 index) : sId(sId), vId(vId), key(key), index(index) {}
+
+    bool operator!=(const Iterator& it) { return index != it.index; }
+    bool operator==(const Iterator& it) { return index == it.index; }
+//    bool operator<(const Iterator& it) { return index < it.index; }
+//    bool operator>(const Iterator& it) { return index > it.index; }
+//    bool operator>=(const Iterator& it) { return index >= it.index; }
+//    bool operator<=(const Iterator& it) { return index <= it.index; }
+
+    Iterator& operator++() {
+        ++index;
+        return *this;
+    }
+    Iterator operator++(int) {
+        Iterator it(*this);
+        ++index;
+        return it;
+    }
+    Iterator& operator--() {
+        --index;
+        return *this;
+    }
+    Iterator operator--(int) {
+        Iterator it(*this);
+        --index;
+        return it;
+    }
+
+    HdfItem operator*() {
+        int32 tag, ref;
+        if(Vgettagref(key, index, &tag, &ref) == FAIL) {
+            throw std::runtime_error("HDF4CPP: cannot access invalid item");
+        }
+        if(Visvs(key, ref)) {
+            throw std::runtime_error("HDF4CPP: vdata not supported yet");
+        } else if(Visvg(key, ref)) {
+            int32 id = Vattach(vId, ref, "r");
+            return HdfItem(new HdfGroupItem(id), sId, vId);
+        } else {
+            int32 id = SDselect(sId, SDreftoindex(sId, ref));
+            return HdfItem(new HdfDatasetItem(id), sId, vId);
+        }
+    }
+
+private:
+    int32 sId;
+    int32 vId;
+    int32 key;
+
+    int32 index;
+};
+
+#endif //HDF4CPP_HDFITEM_H

+ 87 - 0
lib/HdfAttribute.cpp

@@ -0,0 +1,87 @@
+//
+// Created by patrik on 11.08.17.
+//
+
+#include <hdf4cpp/HdfDefines.h>
+#include <hdf4cpp/HdfAttribute.h>
+#include <stdexcept>
+
+HdfDatasetAttribute::HdfDatasetAttribute(int32 id, const std::string& name) : HdfAttributeBase(id, SDfindattr(id, name.c_str())) {
+    if(index != FAIL) {
+        int32 nrValues;
+        char nameRet[MAX_NAME_LENGTH];
+        SDattrinfo(id, index, nameRet, &dataType, &_size);
+    } else {
+        dataType = 0;
+        _size = FAIL;
+    }
+}
+Type HdfDatasetAttribute::getType() const {
+    return DATASET;
+}
+intn HdfDatasetAttribute::size() const {
+    return _size;
+}
+int32 HdfDatasetAttribute::getDataType() const {
+    return dataType;
+}
+bool HdfDatasetAttribute::get(void *dest) {
+    if(!isValid()) {
+        return false;
+    }
+
+    int32 nrValues;
+    char nameRet[MAX_NAME_LENGTH];
+    int32 status = SDattrinfo(id, index, nameRet, &dataType, &nrValues);
+    if(status == FAIL) {
+        return false;
+    }
+
+    return SDreadattr(id, index, dest) != FAIL;
+}
+HdfGroupAttribute::HdfGroupAttribute(int32 id, const std::string& name) : HdfAttributeBase(id, -1), _size(FAIL) {
+    int32 nrAtts = Vnattrs2(id);
+    for(intn i = 0; i < nrAtts; ++i) {
+        char names[MAX_NAME_LENGTH];
+        int32 type, count, size, nFields;
+        uint16 refNum;
+        Vattrinfo2(id, i, names, &type, &count, &size, &nFields, &refNum);
+        if(name == std::string(names)) {
+            index = i;
+            _size = count;
+            dataType = type;
+            break;
+        }
+    }
+}
+Type HdfGroupAttribute::getType() const {
+    return GROUP;
+}
+intn HdfGroupAttribute::size() const {
+    return _size;
+}
+int32 HdfGroupAttribute::getDataType() const {
+    return dataType;
+}
+bool HdfGroupAttribute::get(void *dest) {
+    return Vgetattr2(id, index, dest) != FAIL;
+}
+HdfAttribute::HdfAttribute(HdfAttribute &&other) : attribute(std::move(other.attribute)) {
+}
+bool HdfAttribute::isValid() const {
+    return attribute && attribute->isValid();
+}
+Type HdfAttribute::getType() const {
+    if(isValid()) {
+        return attribute->getType();
+    } else {
+        return NONE;
+    }
+}
+intn HdfAttribute::size() const {
+    if(isValid()) {
+        return attribute->size();
+    } else {
+        return FAIL;
+    }
+}

+ 104 - 0
lib/HdfFile.cpp

@@ -0,0 +1,104 @@
+//
+// Created by patrik on 10.08.17.
+//
+
+#include <hdf/mfhdf.h>
+#include <stdexcept>
+
+#include <hdf4cpp/HdfDefines.h>
+#include <hdf4cpp/HdfFile.h>
+
+
+
+HdfFile::HdfFile(const std::string& path) {
+    sId = SDstart(path.c_str(), DFACC_READ);
+    vId = Hopen(path.c_str(), DFACC_READ, 0);
+    Vstart(vId);
+}
+HdfFile::~HdfFile() {
+    SDend(sId);
+    Vend(vId);
+    Hclose(vId);
+}
+int32 HdfFile::getDatasetId(const std::string &name) {
+    int32 index = SDnametoindex(sId, name.c_str());
+    return (index == FAIL) ? (FAIL) : (SDselect(sId, index));
+}
+int32 HdfFile::getGroupId(const std::string &name) {
+    int32 ref = Vfind(vId, name.c_str());
+    return (!ref) ? (FAIL) : (Vattach(vId, ref, "r"));
+}
+HdfItem HdfFile::get(const std::string& name) {
+    int32 id = getDatasetId(name);
+    if(id == FAIL) {
+        id = getGroupId(name);
+        if(id == FAIL) {
+            return HdfItem(nullptr, sId, vId);
+        }
+        return HdfItem(new HdfGroupItem(id), sId, vId);
+    }
+    return HdfItem(new HdfDatasetItem(id), sId, vId);
+}
+std::vector<int32> HdfFile::getDatasetIds(const std::string &name) {
+    std::vector<int32> ids;
+    char nameDataset[MAX_NAME_LENGTH];
+    int32 datasets, attrs;
+    SDfileinfo(sId, &datasets, &attrs);
+    for(int32 i = 0; i < datasets; ++i) {
+        int32 id = SDselect(sId, i);
+        int32 rank, dimSize, nt, nAttr;
+        SDgetinfo(id, nameDataset, &rank, &dimSize, &nt, &nAttr);
+        if(name == std::string(nameDataset)) {
+            ids.push_back(id);
+        } else {
+            SDendaccess(id);
+        }
+    }
+    return ids;
+}
+std::vector<int32> HdfFile::getGroupIds(const std::string &name) {
+    std::vector<int32> ids;
+    char nameGroup[MAX_NAME_LENGTH];
+    int32 ref = Vgetid(vId, -1);
+    while(ref != FAIL) {
+        int32 id = Vattach(vId, ref, "r");
+        Vgetname(id, nameGroup);
+        if(Visvg(id, ref) && name == std::string(nameGroup)) {
+            ids.push_back(id);
+        } else {
+            Vdetach(id);
+        }
+        ref = Vgetid(vId, ref);
+    }
+    return ids;
+}
+std::vector<HdfItem> HdfFile::getAll(const std::string& name) {
+    std::vector<HdfItem> items;
+    std::vector<int32> ids;
+    ids = getDatasetIds(name);
+    for(const auto& id : ids) {
+        items.push_back(HdfItem(new HdfDatasetItem(id), sId, vId));
+    }
+    ids = getGroupIds(name);
+    for(const auto& id : ids) {
+        items.push_back(HdfItem(new HdfGroupItem(id), sId, vId));
+    }
+    return std::move(items);
+}
+HdfAttribute HdfFile::getAttribute(const std::string &name) {
+    return HdfAttribute(new HdfDatasetAttribute(sId, name));
+}
+bool HdfFile::isValid() {
+    return sId != FAIL || vId != FAIL;
+}
+HdfItem::Iterator HdfFile::begin() const {
+    return HdfItem::Iterator(sId, vId, vId, 0);
+}
+HdfItem::Iterator HdfFile::end() const {
+    // FIXME get the number of items in the root
+    int32 size = Vntagrefs(vId);
+    if(size == FAIL) {
+        size = 0;
+    }
+    return HdfItem::Iterator(sId, vId, vId, size);
+}

+ 137 - 0
lib/HdfItem.cpp

@@ -0,0 +1,137 @@
+//
+// Created by patrik on 11.08.17.
+//
+
+#include <hdf4cpp/HdfItem.h>
+#include <hdf/mfhdf.h>
+#include <algorithm>
+#include <iostream>
+
+HdfDatasetItem::HdfDatasetItem(int32 id) : HdfItemBase(id) {
+    std::vector<int32> dims = getDims();
+    _size = 1;
+    std::for_each(dims.begin(), dims.end(), [this](const int32& t) {
+        _size *= t;
+    });
+    int32 dim[MAX_DIMENSION];
+    int32 size, nrAtt;
+    char _name[MAX_NAME_LENGTH];
+    SDgetinfo(id, _name, &size, dim, &dataType, &nrAtt);
+    name = std::string(_name);
+}
+std::vector<int32> HdfDatasetItem::getDims() {
+    int32 dims[MAX_DIMENSION];
+    int32 size, dataType, nrAtt;
+    char name[MAX_NAME_LENGTH];
+    SDgetinfo(id, name, &size, dims, &dataType, &nrAtt);
+    return std::vector<int32>(dims, dims + size);
+}
+bool HdfDatasetItem::read(void *dest) {
+    std::vector<int32> end = getDims();
+    std::vector<int32> start(end.size(), 0);
+    return SDreaddata(id, start.data(), nullptr, end.data(), dest) != FAIL;
+}
+HdfAttribute HdfDatasetItem::getAttribute(const std::string &name) {
+    return HdfAttribute(new HdfDatasetAttribute(id, name));
+}
+Type HdfDatasetItem::getType() const {
+    return DATASET;
+}
+std::string HdfDatasetItem::getName() const {
+    return name;
+}
+int32 HdfDatasetItem::getId() const {
+    return id;
+}
+int32 HdfDatasetItem::getDataType() const {
+    return dataType;
+}
+HdfDatasetItem::~HdfDatasetItem() {
+    if(isValid()) {
+        SDendaccess(id);
+    }
+}
+intn HdfDatasetItem::size() const {
+    return _size;
+}
+HdfGroupItem::HdfGroupItem(int32 id) : HdfItemBase(id) {
+    char _name[MAX_NAME_LENGTH];
+    Vgetname(id, _name);
+    name = std::string(_name);
+}
+std::vector<int32> HdfGroupItem::getDims() {
+    throw std::runtime_error("HDF4CPP: getDims not defined for HdfGroupItem");
+}
+bool HdfGroupItem::read(void *) {
+    throw std::runtime_error("HDF4CPP: read not defined for HdfGroupItem");
+}
+HdfAttribute HdfGroupItem::getAttribute(const std::string &name) {
+    return HdfAttribute(new HdfGroupAttribute(id, name));
+}
+Type HdfGroupItem::getType() const {
+    return GROUP;
+}
+std::string HdfGroupItem::getName() const {
+    return name;
+}
+int32 HdfGroupItem::getId() const {
+    return id;
+}
+HdfGroupItem::~HdfGroupItem() {
+    if(isValid()) {
+        Vdetach(id);
+    }
+}
+intn HdfGroupItem::size() const {
+    throw std::runtime_error("HdfFile: read not defined for HdfGroupItem");
+}
+int32 HdfGroupItem::getDataType() const {
+    throw std::runtime_error("HDF4CPP: no data type for HdfGroup");
+}
+HdfItem::HdfItem(HdfItem&& other) : item(std::move(other.item)), sId(other.sId), vId(other.vId) {
+}
+std::vector<int32> HdfItem::getDims() {
+    if(isValid()) {
+        return item->getDims();
+    } else {
+        return std::vector<int32>();
+    }
+}
+HdfAttribute HdfItem::getAttribute(const std::string &name) {
+    return item->getAttribute(name);
+}
+Type HdfItem::getType() const {
+    if(isValid()) {
+        return item->getType();
+    } else {
+        return NONE;
+    }
+}
+std::string HdfItem::getName() const {
+    if(isValid()) {
+        return item->getName();
+    } else {
+        return std::string();
+    }
+}
+bool HdfItem::isValid() const {
+    return item && item->isValid();
+}
+intn HdfItem::size() const {
+    if(isValid()) {
+        return item->size();
+    } else {
+        return FAIL;
+    }
+}
+HdfItem::Iterator HdfItem::begin() const {
+    return Iterator(sId, vId, item->getId(), 0);
+}
+HdfItem::Iterator HdfItem::end() const {
+    int32 size = Vntagrefs(item->getId());
+    if(size == FAIL) {
+        return Iterator(sId, vId, item->getId(), 0);
+    } else {
+        return Iterator(sId, vId, item->getId(), size);
+    }
+}

+ 161 - 0
tests/HdfFileTest.cpp

@@ -0,0 +1,161 @@
+//
+// Created by patrik on 10.08.17.
+//
+
+#include <gtest/gtest.h>
+#include <hdf4cpp/HdfFile.h>
+
+class HdfFileTest : public ::testing::Test {
+protected:
+    HdfFileTest() : file(std::string(TEST_DATA_PATH) + "small_test.hdf") {}
+
+    HdfFile file;
+};
+
+TEST_F(HdfFileTest, FileValidity) {
+    ASSERT_TRUE(file.isValid());
+}
+
+TEST_F(HdfFileTest, DatasetValidity) {
+    ASSERT_TRUE(file.get("Data").isValid());
+}
+
+TEST_F(HdfFileTest, GroupValidity) {
+    ASSERT_TRUE(file.get("Group").isValid());
+}
+
+TEST_F(HdfFileTest, InvalidItem) {
+    ASSERT_FALSE(file.get("InvalidKey").isValid());
+}
+
+TEST_F(HdfFileTest, ReadData1) {
+    HdfItem item = file.get("Data");
+    std::vector<int32> vec;
+    item.read(vec);
+    ASSERT_EQ(vec, std::vector<int32>({1, 2, 3, 4, 5, 6, 7, 8, 9}));
+}
+
+TEST_F(HdfFileTest, ReadData2) {
+    HdfItem item = file.get("DataWithAttributes");
+    std::vector<float32> vec;
+    item.read(vec);
+    ASSERT_EQ(vec, std::vector<float32>({0.0, 0.1, 0.2, 1.0, 1.1, 1.2, 2.0, 2.1, 2.2}));
+}
+
+TEST_F(HdfFileTest, ReadDatasetAttributes) {
+    HdfItem item = file.get("DataWithAttributes");
+
+    HdfAttribute attribute1 = item.getAttribute("Integer");
+    std::vector<int32> integer;
+    attribute1.get(integer);
+    ASSERT_EQ(integer, std::vector<int32>({12345}));
+
+    HdfAttribute attribute2 = item.getAttribute("Integers");
+    std::vector<int32> integers;
+    attribute2.get(integers);
+    ASSERT_EQ(integers, std::vector<int32>({1, 12, 123, 1234, 12345}));
+}
+
+TEST_F(HdfFileTest, ReadGroupAttributes) {
+    HdfItem item = file.get("GroupWithOnlyAttribute");
+
+    {
+        HdfAttribute attribute = item.getAttribute("Egy");
+        std::vector<int8> egy;
+        attribute.get(egy);
+        ASSERT_EQ(egy, std::vector<int8>({1}));
+    }
+
+    {
+        HdfAttribute attribute = item.getAttribute("One");
+        std::vector<int16> one;
+        attribute.get(one);
+        ASSERT_EQ(one, std::vector<int16>({1}));
+    }
+
+    {
+        HdfAttribute attribute = item.getAttribute("Ein");
+        std::vector<int32> ein;
+        attribute.get(ein);
+        ASSERT_EQ(ein, std::vector<int32>({1}));
+    }
+}
+
+TEST_F(HdfFileTest, ReadInvalidData) {
+    HdfItem item = file.get("InvalidKey");
+    std::vector<int32> vec;
+    ASSERT_FALSE(item.read(vec));
+}
+
+TEST_F(HdfFileTest, ReadInvalidDatasetAttribute) {
+    HdfItem item = file.get("Data");
+    ASSERT_TRUE(item.isValid());
+    HdfAttribute attribute = item.getAttribute("Attribute");
+    ASSERT_FALSE(attribute.isValid());
+    std::vector<int32> vec;
+    ASSERT_FALSE(attribute.get(vec));
+}
+
+TEST_F(HdfFileTest, ReadInvalidGroupAttribute) {
+    HdfItem item = file.get("Group");
+    ASSERT_TRUE(item.isValid());
+    HdfAttribute attribute = item.getAttribute("Attribute");
+    ASSERT_FALSE(attribute.isValid());
+    std::vector<int32> vec;
+    ASSERT_FALSE(attribute.get(vec));
+}
+
+TEST_F(HdfFileTest, MovingItems) {
+    HdfItem item1 = file.get("Data");
+    HdfItem item2 = std::move(item1);
+    ASSERT_FALSE(item1.isValid());
+    std::vector<int32> vec;
+    item2.read(vec);
+    ASSERT_EQ(vec, std::vector<int32>({1, 2, 3, 4, 5, 6, 7, 8, 9}));
+}
+
+TEST_F(HdfFileTest, GetAllDatsetsWithTheSameName) {
+    std::vector<HdfItem> items = file.getAll("DoubleDataset");
+    ASSERT_EQ(items.size(), 2);
+    std::vector<int32> vec;
+    items[0].read(vec);
+    ASSERT_EQ(vec, std::vector<int32>({0}));
+    items[1].read(vec);
+    ASSERT_EQ(vec, std::vector<int32>({0, 1}));
+}
+
+TEST_F(HdfFileTest, DatasetTypeIncompatibility) {
+    std::vector<std::string> vec;
+    HdfItem item = file.get("Data");
+    ASSERT_ANY_THROW(item.read(vec));
+}
+
+TEST_F(HdfFileTest, DatasetAttributeTypeIncompatibility) {
+    std::vector<std::string> vec;
+    HdfItem item = file.get("DataWithAttributes");
+    HdfAttribute attribute = item.getAttribute("Integer");
+    ASSERT_ANY_THROW(attribute.get(vec));
+}
+
+TEST_F(HdfFileTest, GroupAttributeTypeIncompatibility) {
+    std::vector<std::string> vec;
+    HdfItem item = file.get("GroupWithOnlyAttribute");
+    HdfAttribute attribute = item.getAttribute("Egy");
+    ASSERT_ANY_THROW(attribute.get(vec));
+}
+
+TEST_F(HdfFileTest, GlobalAttribute) {
+    std::vector<int8> vec;
+    HdfAttribute attribute = file.getAttribute("GlobalAttribute");
+    ASSERT_TRUE(attribute.isValid());
+    attribute.get(vec);
+    ASSERT_EQ(vec, std::vector<int8>({11, 22}));
+}
+
+TEST_F(HdfFileTest, ItemIterator1) {
+    std::ostringstream out;
+    for(auto it : file) {
+        out << it.getName() << '*';
+    }
+    ASSERT_EQ(out.str(), std::string("Group*GroupWithOnlyAttributes*DoubleDataset*DoubleDataset*"));
+}

BIN
tests/test_data/small_test.hdf