#include "io/hdf5/hdf5_primitives.h" #include #include #include #include #include #include #include namespace fesa::hdf5_internal { Status OutputFailure(const std::string& code, const std::string& message) { return Status::Failure(FailureCategory::kOutput, {{Severity::kError, code, {}, "", "", message}}); } bool IsValidUtf8(const std::string& value) { const auto* bytes = reinterpret_cast(value.data()); std::size_t index = 0U; while (index < value.size()) { const unsigned char first = bytes[index]; if (first <= 0x7fU) { ++index; continue; } std::size_t continuation_count = 0U; std::uint32_t code_point = 0U; if (first >= 0xc2U && first <= 0xdfU) { continuation_count = 1U; code_point = first & 0x1fU; } else if (first >= 0xe0U && first <= 0xefU) { continuation_count = 2U; code_point = first & 0x0fU; } else if (first >= 0xf0U && first <= 0xf4U) { continuation_count = 3U; code_point = first & 0x07U; } else { return false; } if (index + continuation_count >= value.size()) { return false; } for (std::size_t offset = 1U; offset <= continuation_count; ++offset) { const unsigned char next = bytes[index + offset]; if ((next & 0xc0U) != 0x80U) { return false; } code_point = (code_point << 6U) | (next & 0x3fU); } if ((continuation_count == 2U && code_point < 0x800U) || (continuation_count == 3U && code_point < 0x10000U) || (code_point >= 0xd800U && code_point <= 0xdfffU) || code_point > 0x10ffffU) { return false; } index += continuation_count + 1U; } return true; } bool SameIdentity(const SourceEntityId& left, const SourceEntityId& right) { return left.instance_name == right.instance_name && left.source_label == right.source_label && left.source_label_text == right.source_label_text; } bool IsShellDomain(const Domain& domain) noexcept { return !domain.ShellElements().Empty(); } const char* ShellSourceTypeName(const ShellSourceElementType type) { return type == ShellSourceElementType::kS4 ? "S4" : "S4R"; } bool SizeProductFits(const std::size_t left, const std::size_t right, std::size_t& product) { if (right != 0U && left > (std::numeric_limits::max)() / right) { return false; } product = left * right; return true; } std::string NormalizedPathString(const std::filesystem::path& path) { if (path.empty()) { return {}; } return std::filesystem::absolute(path).lexically_normal().generic_u8string(); } std::string SourceInputIdentity(const Domain& domain) { return "path=" + NormalizedPathString(domain.SourcePath()) + ";content_identity=" + domain.SourceContentIdentity(); } Hdf5Handle MakeUtf8StringType() { Hdf5Handle type{ RequireHdf5Id(H5Tcopy(H5T_C_S1), "Unable to copy an HDF5 string type."), H5Tclose}; RequireHdf5(H5Tset_size(type.Get(), H5T_VARIABLE), "Unable to configure a variable-length HDF5 string."); RequireHdf5(H5Tset_cset(type.Get(), H5T_CSET_UTF8), "Unable to configure UTF-8 HDF5 strings."); RequireHdf5(H5Tset_strpad(type.Get(), H5T_STR_NULLTERM), "Unable to configure HDF5 string padding."); return type; } void WriteStringAttribute(const hid_t object, const char* name, const std::string& value) { auto type = MakeUtf8StringType(); Hdf5Handle space{RequireHdf5Id(H5Screate(H5S_SCALAR), "Unable to create an attribute space."), H5Sclose}; Hdf5Handle attribute{ RequireHdf5Id(H5Acreate2(object, name, type.Get(), space.Get(), H5P_DEFAULT, H5P_DEFAULT), "Unable to create an HDF5 string attribute."), H5Aclose}; const char* raw = value.c_str(); RequireHdf5(H5Awrite(attribute.Get(), type.Get(), &raw), "Unable to write an HDF5 string attribute."); } void WriteUint64Attribute(const hid_t object, const char* name, const std::uint64_t value) { Hdf5Handle space{RequireHdf5Id(H5Screate(H5S_SCALAR), "Unable to create an attribute space."), H5Sclose}; Hdf5Handle attribute{ RequireHdf5Id(H5Acreate2(object, name, H5T_STD_U64LE, space.Get(), H5P_DEFAULT, H5P_DEFAULT), "Unable to create an HDF5 integer attribute."), H5Aclose}; RequireHdf5(H5Awrite(attribute.Get(), H5T_NATIVE_UINT64, &value), "Unable to write an HDF5 integer attribute."); } void WriteUint8Attribute(const hid_t object, const char* name, const std::uint8_t value) { Hdf5Handle space{RequireHdf5Id(H5Screate(H5S_SCALAR), "Unable to create an attribute space."), H5Sclose}; Hdf5Handle attribute{ RequireHdf5Id(H5Acreate2(object, name, H5T_STD_U8LE, space.Get(), H5P_DEFAULT, H5P_DEFAULT), "Unable to create an HDF5 uint8 attribute."), H5Aclose}; RequireHdf5(H5Awrite(attribute.Get(), H5T_NATIVE_UINT8, &value), "Unable to write an HDF5 uint8 attribute."); } void WriteDoubleAttribute(const hid_t object, const char* name, const double value) { Hdf5Handle space{RequireHdf5Id(H5Screate(H5S_SCALAR), "Unable to create an attribute space."), H5Sclose}; Hdf5Handle attribute{ RequireHdf5Id(H5Acreate2(object, name, H5T_IEEE_F64LE, space.Get(), H5P_DEFAULT, H5P_DEFAULT), "Unable to create an HDF5 float64 attribute."), H5Aclose}; RequireHdf5(H5Awrite(attribute.Get(), H5T_NATIVE_DOUBLE, &value), "Unable to write an HDF5 float64 attribute."); } Hdf5Handle CreateGroup(const hid_t file, const char* path) { Hdf5Handle link_properties{RequireHdf5Id(H5Pcreate(H5P_LINK_CREATE), "Unable to create link properties."), H5Pclose}; RequireHdf5(H5Pset_create_intermediate_group(link_properties.Get(), 1U), "Unable to enable intermediate HDF5 groups."); return Hdf5Handle{RequireHdf5Id(H5Gcreate2(file, path, link_properties.Get(), H5P_DEFAULT, H5P_DEFAULT), "Unable to create an HDF5 group."), H5Gclose}; } Hdf5Handle CreateDatasetSpace(const std::vector& dimensions) { return Hdf5Handle{ RequireHdf5Id(H5Screate_simple(static_cast(dimensions.size()), dimensions.data(), nullptr), "Unable to create an HDF5 dataset space."), H5Sclose}; } void WriteResultAttributes(const hid_t dataset, const std::string& component_names, const std::string& component_units, const std::string& coordinate_system, const std::string& location) { WriteStringAttribute(dataset, "component_names", component_names); WriteStringAttribute(dataset, "component_unit_dimensions", component_units); WriteStringAttribute(dataset, "coordinate_system", coordinate_system); WriteStringAttribute(dataset, "location", location); WriteStringAttribute(dataset, "step_name", kStepName); WriteUint64Attribute(dataset, "frame_index", 0U); } Hdf5Handle WriteDoubleValues(const hid_t file, const std::string& path, const std::vector& dimensions, const double* values, const std::size_t value_count) { auto space = CreateDatasetSpace(dimensions); Hdf5Handle dataset{ RequireHdf5Id(H5Dcreate2(file, path.c_str(), H5T_IEEE_F64LE, space.Get(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT), "Unable to create a floating-point HDF5 dataset."), H5Dclose}; if (value_count != 0U) { RequireHdf5(H5Dwrite(dataset.Get(), H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, values), "Unable to write a floating-point HDF5 dataset."); } return dataset; } void WriteDoubleDataset(const hid_t file, const std::string& path, const std::vector& dimensions, const double* values, const std::size_t value_count, const std::string& component_names, const std::string& component_units, const std::string& coordinate_system, const std::string& location) { auto dataset = WriteDoubleValues(file, path, dimensions, values, value_count); WriteResultAttributes(dataset.Get(), component_names, component_units, coordinate_system, location); } void WriteModelDoubleDataset(const hid_t file, const std::string& path, const std::vector& dimensions, const double* values, const std::size_t value_count, const std::string& component_names, const std::string& component_units, const std::string& coordinate_system, const std::string& location) { auto dataset = WriteDoubleValues(file, path, dimensions, values, value_count); WriteStringAttribute(dataset.Get(), "component_names", component_names); WriteStringAttribute(dataset.Get(), "component_unit_dimensions", component_units); WriteStringAttribute(dataset.Get(), "coordinate_system", coordinate_system); WriteStringAttribute(dataset.Get(), "location", location); } void WriteUint8Dataset(const hid_t file, const std::string& path, const std::vector& dimensions, const std::uint8_t* values, const std::size_t value_count) { auto space = CreateDatasetSpace(dimensions); Hdf5Handle dataset{ RequireHdf5Id(H5Dcreate2(file, path.c_str(), H5T_STD_U8LE, space.Get(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT), "Unable to create a uint8 HDF5 dataset."), H5Dclose}; if (value_count != 0U) { RequireHdf5(H5Dwrite(dataset.Get(), H5T_NATIVE_UINT8, H5S_ALL, H5S_ALL, H5P_DEFAULT, values), "Unable to write a uint8 HDF5 dataset."); } WriteStringAttribute(dataset.Get(), "component_names", "UX,UY,UZ,URX,URY,URZ"); WriteStringAttribute(dataset.Get(), "value_meaning", "0=free,1=constrained"); } Hdf5Handle WriteCompoundDataset(const hid_t file, const char* path, const std::size_t row_count, const hid_t file_type, const hid_t memory_type, const void* rows) { const std::vector dimensions = {static_cast(row_count)}; auto space = CreateDatasetSpace(dimensions); Hdf5Handle dataset{ RequireHdf5Id(H5Dcreate2(file, path, file_type, space.Get(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT), "Unable to create a compound HDF5 dataset."), H5Dclose}; if (row_count != 0U) { RequireHdf5(H5Dwrite(dataset.Get(), memory_type, H5S_ALL, H5S_ALL, H5P_DEFAULT, rows), "Unable to write a compound HDF5 dataset."); } return dataset; } } // namespace fesa::hdf5_internal