using PureHDF;
using PureHDF.Selections;
namespace GeoVLog.Core.Hdf5;
internal static class H5Extensions
{
///
/// Creates a group at the specified path if it does not exist, or opens it if it already exists.
/// All intermediate groups in the path are created as needed.
///
public static H5Group CreateOrOpenGroup(this H5File file, string path)
{
if (string.IsNullOrWhiteSpace(path) || path == "/")
{
// Root or empty path: return the root group (file itself)
return file;
}
string normalizedPath = path.Trim('/');
string[] parts = normalizedPath.Split('/', StringSplitOptions.RemoveEmptyEntries);
H5Group current = file;
foreach (string part in parts)
{
IH5Object? item;
try
{
// Try to get an existing child object with this name
item = ((IH5Group)current).Get(part);
}
catch
{
item = null;
}
if (item is H5Group subgroup)
{
// If a subgroup exists, descend into it
current = subgroup;
}
else if (item is null)
{
// Create a new subgroup if none exists at this path segment
var newGroup = new H5Group();
current[part] = newGroup;
current = newGroup;
}
else
{
throw new InvalidOperationException(
$"Cannot create group \"{part}\" in path \"{path}\" because an object with that name already exists and is not a group.");
}
}
return current;
}
///
/// Creates a variable-length UTF-8 string dataset at the specified path if it does not exist, or opens it if it exists.
/// The dataset is one-dimensional, chunked, and can grow without bound (unlimited dimension).
///
public static H5Dataset CreateOrOpenVLStringDataset(this H5File file, string path)
{
// Ensure parent group exists first
int lastSlashIndex = path.LastIndexOf('/');
if (lastSlashIndex > 0)
{
string parentPath = path[..lastSlashIndex];
file.CreateOrOpenGroup(parentPath);
}
// Check if an object already exists at the target path
IH5Object? existing;
try
{
existing = ((IH5Group)file).Get(path.TrimStart('/'));
}
catch
{
existing = null;
}
if (existing is H5Dataset dataset)
{
// Dataset already exists, return it
return dataset;
}
if (existing is not null)
{
throw new InvalidOperationException(
$"Cannot create dataset at \"{path}\" because a different object already exists at that path.");
}
// Define a new 1D dataset of variable-length strings, initially empty (0 length).
ulong[] dims = { 0 }; // Initial dimension size is 0 (no entries yet).
// Note: We omit maxDims because PureHDF 2.1.1 no longer requires it –
// unlimited growth is handled by using chunked storage and extending on write:contentReference[oaicite:3]{index=3}.
ulong[] chunkDims = { 1024 }; // Use chunking (chunks of 1024 elements) to allow resizing.
uint[] chunkDims32 = Array.ConvertAll(chunkDims, x => (uint)x);
// Create the new dataset with the specified initial dims and chunk layout.
// PureHDF 2.1.1: H5Dataset constructor takes fileDims and chunks, but no maxDims:contentReference[oaicite:4]{index=4}.
var newDataset = new H5Dataset(fileDims: dims, chunks: chunkDims32);
// Attach the new dataset to the file structure at the specified path.
string datasetName = (lastSlashIndex >= 0) ? path[(lastSlashIndex + 1)..] : path;
H5Group parentGroup = file;
if (lastSlashIndex > 0)
{
string parentGroupPath = path[..lastSlashIndex];
parentGroup = file.CreateOrOpenGroup(parentGroupPath);
}
parentGroup[datasetName] = newDataset;
return newDataset;
}
}