private Span <byte> GetBuffer <T>(out T[] result) where T : struct { // first, get byte size var byteSize = H5Utils.CalculateSize(this.Dataspace.DimensionSizes, this.Dataspace.Type) * this.Datatype.Size; // second, convert file type (e.g. 2 bytes) to T (e.g. 4 bytes) var arraySize = byteSize / (ulong)Unsafe.SizeOf <T>(); // finally, create buffer result = new T[arraySize]; var buffer = MemoryMarshal.AsBytes(result.AsSpan()); return(buffer); }
public AttributeMessage(H5BinaryReader reader, Superblock superblock) : base(reader) { //var a = reader.ReadBytes(200); // version this.Version = reader.ReadByte(); if (this.Version == 1) { reader.ReadByte(); } else { this.Flags = (AttributeMessageFlags)reader.ReadByte(); } // name size var nameSize = reader.ReadUInt16(); // datatype size var datatypeSize = reader.ReadUInt16(); // dataspace size var dataspaceSize = reader.ReadUInt16(); // name character set encoding if (this.Version == 3) { _nameEncoding = (CharacterSetEncoding)reader.ReadByte(); } // name if (this.Version == 1) { this.Name = H5Utils.ReadNullTerminatedString(reader, pad: true, encoding: _nameEncoding); } else { this.Name = H5Utils.ReadNullTerminatedString(reader, pad: false, encoding: _nameEncoding); } // datatype this.Datatype = new DatatypeMessage(reader); if (this.Version == 1) { var paddedSize = (int)(Math.Ceiling(datatypeSize / 8.0) * 8); var remainingSize = paddedSize - datatypeSize; reader.ReadBytes(remainingSize); } // dataspace this.Dataspace = new DataspaceMessage(reader, superblock); if (this.Version == 1) { var paddedSize = (int)(Math.Ceiling(dataspaceSize / 8.0) * 8); var remainingSize = paddedSize - dataspaceSize; this.Reader.Seek(remainingSize, SeekOrigin.Current); } // data var byteSize = H5Utils.CalculateSize(this.Dataspace.DimensionSizes, this.Dataspace.Type) * this.Datatype.Size; this.Data = reader.ReadBytes((int)byteSize); }
public static unsafe T[] ReadCompound <T>( DatatypeMessage datatype, DataspaceMessage dataspace, Superblock superblock, Span <byte> data, Func <FieldInfo, string> getName) where T : struct { if (datatype.Class != DatatypeMessageClass.Compound) { throw new Exception($"This method can only be used for data type class '{DatatypeMessageClass.Compound}'."); } var type = typeof(T); var fieldInfoMap = new Dictionary <string, FieldProperties>(); foreach (var fieldInfo in type.GetFields()) { var name = getName(fieldInfo); var isNotSupported = H5Utils.IsReferenceOrContainsReferences(fieldInfo.FieldType) && fieldInfo.FieldType != typeof(string); if (isNotSupported) { throw new Exception("Nested nullable fields are not supported."); } fieldInfoMap[name] = new FieldProperties() { FieldInfo = fieldInfo, Offset = Marshal.OffsetOf(type, fieldInfo.Name) }; } var properties = datatype.Properties .Cast <CompoundPropertyDescription>() .ToList(); var sourceOffset = 0UL; var sourceRawBytes = data; var sourceElementSize = datatype.Size; var targetArraySize = H5Utils.CalculateSize(dataspace.DimensionSizes, dataspace.Type); var targetArray = new T[targetArraySize]; var targetElementSize = Marshal.SizeOf <T>(); for (int i = 0; i < targetArray.Length; i++) { var targetRawBytes = new byte[targetElementSize]; var stringMap = new Dictionary <FieldProperties, string>(); foreach (var property in properties) { if (!fieldInfoMap.TryGetValue(property.Name, out var fieldInfo)) { throw new Exception($"The property named '{property.Name}' in the HDF5 data type does not exist in the provided structure of type '{typeof(T)}'."); } var fieldSize = (int)property.MemberTypeMessage.Size; // strings if (fieldInfo.FieldInfo.FieldType == typeof(string)) { var sourceIndex = (int)(sourceOffset + property.MemberByteOffset); var sourceIndexEnd = sourceIndex + fieldSize; var targetIndex = fieldInfo.Offset.ToInt64(); var value = H5Utils.ReadString(property.MemberTypeMessage, sourceRawBytes[sourceIndex..sourceIndexEnd], superblock);
private T[] ReadChunked <T>() where T : struct { var buffer = this.GetBuffer <T>(out var result); if (this.DataLayout is DataLayoutMessage12 layout12) { if (this.Context.Superblock.IsUndefinedAddress(layout12.DataAddress)) { if (this.FillValue.IsDefined) { buffer.Fill(this.FillValue.Value); } } else { var chunkSize = H5Utils.CalculateSize(layout12.DimensionSizes); this.Context.Reader.Seek((int)layout12.DataAddress, SeekOrigin.Begin); this.ReadChunkedBTree1(buffer, layout12.Rank, chunkSize); } } else if (this.DataLayout is DataLayoutMessage4 layout4) { var chunked4 = (ChunkedStoragePropertyDescription4)layout4.Properties; var chunkSize = H5Utils.CalculateSize(chunked4.DimensionSizes); if (this.Context.Superblock.IsUndefinedAddress(chunked4.Address)) { if (this.FillValue.IsDefined) { buffer.Fill(this.FillValue.Value); } } else { this.Context.Reader.Seek((int)chunked4.Address, SeekOrigin.Begin); switch (chunked4.ChunkIndexingType) { // the current, maximum, and chunk dimension sizes are all the same case ChunkIndexingType.SingleChunk: var singleChunkInfo = (SingleChunkIndexingInformation)chunked4.IndexingTypeInformation; this.ReadChunk(buffer, chunkSize); break; // fixed maximum dimension sizes // no filter applied to the dataset // the timing for the space allocation of the dataset chunks is H5P_ALLOC_TIME_EARLY case ChunkIndexingType.Implicit: var @implicitInfo = (ImplicitIndexingInformation)chunked4.IndexingTypeInformation; this.Context.Reader.Read(buffer); break; // fixed maximum dimension sizes case ChunkIndexingType.FixedArray: var fixedArrayInfo = (FixedArrayIndexingInformation)chunked4.IndexingTypeInformation; this.ReadFixedArray(buffer, chunkSize); break; // only one dimension of unlimited extent case ChunkIndexingType.ExtensibleArray: var extensibleArrayInfo = (ExtensibleArrayIndexingInformation)chunked4.IndexingTypeInformation; this.ReadExtensibleArray(buffer, chunkSize); break; // more than one dimension of unlimited extent case ChunkIndexingType.BTree2: var btree2Info = (BTree2IndexingInformation)chunked4.IndexingTypeInformation; this.ReadChunkedBTree2(buffer, (byte)(chunked4.Rank - 1), chunkSize); break; default: break; } } } else if (this.DataLayout is DataLayoutMessage3 layout3) { var chunked3 = (ChunkedStoragePropertyDescription3)layout3.Properties; if (this.Context.Superblock.IsUndefinedAddress(chunked3.Address)) { if (this.FillValue.IsDefined) { buffer.Fill(this.FillValue.Value); } } else { var chunkSize = H5Utils.CalculateSize(chunked3.DimensionSizes); this.Context.Reader.Seek((int)chunked3.Address, SeekOrigin.Begin); this.ReadChunkedBTree1(buffer, (byte)(chunked3.Rank - 1), chunkSize); } } else { throw new Exception($"Data layout message type '{this.DataLayout.GetType().Name}' is not supported."); } this.EnsureEndianness(buffer); return(result); }
public AttributeMessage(H5Context context, ObjectHeader objectHeader) : base(context.Reader) { _context = context; // version this.Version = context.Reader.ReadByte(); if (this.Version == 1) { context.Reader.ReadByte(); } else { this.Flags = (AttributeMessageFlags)context.Reader.ReadByte(); } // name size var nameSize = context.Reader.ReadUInt16(); // datatype size var datatypeSize = context.Reader.ReadUInt16(); // dataspace size var dataspaceSize = context.Reader.ReadUInt16(); // name character set encoding if (this.Version == 3) { _nameEncoding = (CharacterSetEncoding)context.Reader.ReadByte(); } // name if (this.Version == 1) { this.Name = H5Utils.ReadNullTerminatedString(context.Reader, pad: true, encoding: _nameEncoding); } else { this.Name = H5Utils.ReadNullTerminatedString(context.Reader, pad: false, encoding: _nameEncoding); } // datatype var flags1 = this.Flags.HasFlag(AttributeMessageFlags.SharedDatatype) ? MessageFlags.Shared : MessageFlags.NoFlags; this.Datatype = objectHeader.DecodeMessage(flags1, () => new DatatypeMessage(context.Reader)); if (this.Version == 1) { var paddedSize = (int)(Math.Ceiling(datatypeSize / 8.0) * 8); var remainingSize = paddedSize - datatypeSize; context.Reader.ReadBytes(remainingSize); } // dataspace var flags2 = this.Flags.HasFlag(AttributeMessageFlags.SharedDataspace) ? MessageFlags.Shared : MessageFlags.NoFlags; this.Dataspace = objectHeader.DecodeMessage(flags2, () => new DataspaceMessage(context.Reader, context.Superblock)); if (this.Version == 1) { var paddedSize = (int)(Math.Ceiling(dataspaceSize / 8.0) * 8); var remainingSize = paddedSize - dataspaceSize; this.Reader.Seek(remainingSize, SeekOrigin.Current); } // data var byteSize = H5Utils.CalculateSize(this.Dataspace.DimensionSizes, this.Dataspace.Type) * this.Datatype.Size; this.Data = context.Reader.ReadBytes((int)byteSize); }