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; } }