Careful disposal

This commit is contained in:
Alexander Luzgarev 2019-03-12 21:15:12 +01:00
parent 99558d96c4
commit 82f43a7e5d

View File

@ -9,6 +9,83 @@ using HDF.PInvoke;
namespace MatFileHandler namespace MatFileHandler
{ {
public struct Dataset : IDisposable
{
public long Id { get; private set; }
public Dataset(long groupId, string name)
{
Id = H5D.open(groupId, name);
}
public void Dispose()
{
if (Id != -1)
{
H5D.close(Id);
Id = -1;
}
}
}
public struct Group : IDisposable
{
public long Id { get; private set; }
public Group(long groupId, string name)
{
Id = H5G.open(groupId, name);
}
public void Dispose()
{
if (Id != -1)
{
H5G.close(Id);
Id = -1;
}
}
}
public struct Attribute : IDisposable
{
public long Id { get; private set; }
public Attribute(long locationId, string name)
{
Id = H5A.open_by_name(locationId, ".", name);
}
public void Dispose()
{
if (Id != -1)
{
H5A.close(Id);
Id = -1;
}
}
}
sealed class MemoryHandle : IDisposable
{
internal MemoryHandle(int sizeInBytes)
{
Handle = Marshal.AllocHGlobal(sizeInBytes);
}
internal IntPtr Handle { get; private set; }
/// <inheritdoc/>
public void Dispose()
{
if (Handle != IntPtr.Zero)
{
Marshal.FreeHGlobal(Handle);
Handle = IntPtr.Zero;
}
}
}
internal enum HdfMatlabClass internal enum HdfMatlabClass
{ {
MEmpty, MEmpty,
@ -385,18 +462,22 @@ namespace MatFileHandler
switch (object_info.type) switch (object_info.type)
{ {
case H5O.type_t.DATASET: case H5O.type_t.DATASET:
var datasetId = H5D.open(group, variableName); using (var dataset = new Dataset(group, variableName))
var value = ReadDataset(datasetId); {
variables.Add(new MatVariable(value, variableName, false)); var value = ReadDataset(dataset.Id);
variables.Add(new MatVariable(value, variableName, false));
}
break; break;
case H5O.type_t.GROUP: case H5O.type_t.GROUP:
if (variableName == "#refs#") if (variableName == "#refs#")
{ {
return 0; return 0;
} }
var groupId = H5G.open(group, variableName); using (var subGroup = new Group(group, variableName))
var groupValue = ReadGroup(groupId); {
variables.Add(new MatVariable(groupValue, variableName, false)); var groupValue = ReadGroup(subGroup.Id);
variables.Add(new MatVariable(groupValue, variableName, false));
}
break; break;
default: default:
throw new NotImplementedException(); throw new NotImplementedException();
@ -406,23 +487,26 @@ namespace MatFileHandler
private static string GetMatlabClassOfDataset(long datasetId) private static string GetMatlabClassOfDataset(long datasetId)
{ {
var attributeId = H5A.open_by_name(datasetId, ".", "MATLAB_class"); using (var attribute = new Attribute(datasetId, "MATLAB_class"))
var typeId = H5A.get_type(attributeId);
var cl = H5T.get_class(typeId);
if (cl != H5T.class_t.STRING)
{ {
throw new NotImplementedException(); var typeId = H5A.get_type(attribute.Id);
var cl = H5T.get_class(typeId);
if (cl != H5T.class_t.STRING)
{
throw new NotImplementedException();
}
var classId = H5T.copy(H5T.C_S1);
var typeIdSize = (int)H5T.get_size(typeId);
H5T.set_size(classId, (IntPtr)typeIdSize);
var matlabClassNameBytes = new byte[typeIdSize];
using (var buf = new MemoryHandle(typeIdSize))
{
H5A.read(attribute.Id, classId, buf.Handle);
Marshal.Copy(buf.Handle, matlabClassNameBytes, 0, typeIdSize);
}
return Encoding.ASCII.GetString(matlabClassNameBytes);
} }
var classId = H5T.copy(H5T.C_S1);
var typeIdSize = H5T.get_size(typeId);
H5T.set_size(classId, typeIdSize);
var buf = Marshal.AllocHGlobal(typeIdSize);
H5A.read(attributeId, classId, buf);
var matlabClassNameBytes = new byte[(int)typeIdSize];
Marshal.Copy(buf, matlabClassNameBytes, 0, (int)typeIdSize);
Marshal.FreeHGlobal(buf);
return Encoding.ASCII.GetString(matlabClassNameBytes);
} }
private static int[] GetDimensionsOfDataset(long datasetId) private static int[] GetDimensionsOfDataset(long datasetId)
@ -492,36 +576,39 @@ namespace MatFileHandler
private static string[] ReadFieldNames(long groupId) private static string[] ReadFieldNames(long groupId)
{ {
// Try to read fields from MATLAB_fields. // Try to read fields from MATLAB_fields.
var attrId = H5A.open_by_name(groupId, ".", "MATLAB_fields"); using (var attr = new Attribute(groupId, "MATLAB_fields"))
if (attrId == 0)
{ {
throw new NotImplementedException(); if (attr.Id == 0)
{
throw new NotImplementedException();
}
var spaceId = H5A.get_space(attr.Id);
var rank = H5S.get_simple_extent_ndims(spaceId);
var dims = new ulong[rank];
H5S.get_simple_extent_dims(spaceId, dims, null);
Array.Reverse(dims);
var dimensions = dims.Select(x => (int)x).ToArray();
var numberOfFields = dimensions.NumberOfElements();
var field_id = H5A.get_type(attr.Id);
var fieldNamePointersSizeInBytes = numberOfFields * Marshal.SizeOf(default(H5T.hvl_t));
var fieldNamePointers = new IntPtr[numberOfFields * 2];
using (var fieldNamesBuf = new MemoryHandle(fieldNamePointersSizeInBytes))
{
H5A.read(attr.Id, field_id, fieldNamesBuf.Handle);
Marshal.Copy(fieldNamesBuf.Handle, fieldNamePointers, 0, numberOfFields * 2);
}
var fieldNames = new string[numberOfFields];
for (var i = 0; i < numberOfFields; i++)
{
var stringLength = fieldNamePointers[i * 2];
var stringPointer = fieldNamePointers[(i * 2) + 1];
fieldNames[i] = Marshal.PtrToStringAnsi(stringPointer, (int)stringLength);
}
return fieldNames;
} }
var spaceId = H5A.get_space(attrId);
var rank = H5S.get_simple_extent_ndims(spaceId);
var dims = new ulong[rank];
H5S.get_simple_extent_dims(spaceId, dims, null);
Array.Reverse(dims);
var dimensions = dims.Select(x => (int)x).ToArray();
var numberOfFields = dimensions.NumberOfElements();
var field_id = H5A.get_type(attrId);
var fieldNamePointersSizeInBytes = numberOfFields * Marshal.SizeOf(default(H5T.hvl_t));
var fieldNamesBuf = Marshal.AllocHGlobal(fieldNamePointersSizeInBytes);
H5A.read(attrId, field_id, fieldNamesBuf);
var fieldNamePointers = new IntPtr[numberOfFields * 2];
Marshal.Copy(fieldNamesBuf, fieldNamePointers, 0, numberOfFields * 2);
Marshal.FreeHGlobal(fieldNamesBuf);
var fieldNames = new string[numberOfFields];
for (var i = 0; i < numberOfFields; i++)
{
var stringLength = fieldNamePointers[i * 2];
var stringPointer = fieldNamePointers[i * 2 + 1];
fieldNames[i] = Marshal.PtrToStringAnsi(stringPointer, (int)stringLength);
}
return fieldNames;
} }
private static H5O.type_t GetObjectType(long groupId, string fieldName) private static H5O.type_t GetObjectType(long groupId, string fieldName)
@ -537,51 +624,57 @@ namespace MatFileHandler
var firstObjectType = GetObjectType(groupId, fieldNames[0]); var firstObjectType = GetObjectType(groupId, fieldNames[0]);
if (firstObjectType == H5O.type_t.DATASET) if (firstObjectType == H5O.type_t.DATASET)
{ {
var firstFieldId = H5D.open(groupId, fieldNames[0]); using (var firstField = new Dataset(groupId, fieldNames[0]))
var firstFieldTypeId = H5D.get_type(firstFieldId);
if (H5T.get_class(firstFieldTypeId) == H5T.class_t.REFERENCE)
{ {
if (H5A.exists_by_name(firstFieldId, ".", "MATLAB_class") != 0) var firstFieldTypeId = H5D.get_type(firstField.Id);
if (H5T.get_class(firstFieldTypeId) == H5T.class_t.REFERENCE)
{ {
throw new NotImplementedException(); if (H5A.exists_by_name(firstField.Id, ".", "MATLAB_class") != 0)
{
throw new NotImplementedException();
}
else
{
var dimensions = GetDimensionsOfDataset(firstField.Id);
var numberOfElements = dimensions.NumberOfElements();
var dictionary = new Dictionary<string, List<IArray>>();
foreach (var fieldName in fieldNames)
{
var fieldType = GetObjectType(groupId, fieldName);
dictionary[fieldName] = new List<IArray>();
switch (fieldType)
{
case H5O.type_t.DATASET:
using (var field = new Dataset(groupId, fieldName))
{
using (var buf = new MemoryHandle(Marshal.SizeOf(default(IntPtr)) * numberOfElements))
{
H5D.read(field.Id, H5T.STD_REF_OBJ, H5S.ALL, H5S.ALL, H5P.DEFAULT, buf.Handle);
for (var i = 0; i < numberOfElements; i++)
{
var fieldDataSet = H5R.dereference(
field.Id,
H5P.DEFAULT,
H5R.type_t.OBJECT,
buf.Handle + (i * Marshal.SizeOf(default(IntPtr))));
var dataset = ReadDataset(fieldDataSet);
dictionary[fieldName].Add(dataset);
}
}
}
break;
default:
throw new NotImplementedException();
}
}
return new HdfStructureArray(dimensions, dictionary);
}
} }
else else
{ {
var dimensions = GetDimensionsOfDataset(firstFieldId); throw new NotImplementedException();
var numberOfElements = dimensions.NumberOfElements();
var dictionary = new Dictionary<string, List<IArray>>();
foreach (var fieldName in fieldNames)
{
var fieldType = GetObjectType(groupId, fieldName);
dictionary[fieldName] = new List<IArray>();
switch (fieldType)
{
case H5O.type_t.DATASET:
var fieldId = H5D.open(groupId, fieldName);
var buf = Marshal.AllocHGlobal(Marshal.SizeOf(default(IntPtr)) * numberOfElements);
H5D.read(fieldId, H5T.STD_REF_OBJ, H5S.ALL, H5S.ALL, H5P.DEFAULT, buf);
for (var i = 0; i < numberOfElements; i++)
{
var fieldDataSet = H5R.dereference(
fieldId,
H5P.DEFAULT,
H5R.type_t.OBJECT,
buf + (i * Marshal.SizeOf(default(IntPtr))));
var dataset = ReadDataset(fieldDataSet);
dictionary[fieldName].Add(dataset);
}
break;
default:
throw new NotImplementedException();
}
}
return new HdfStructureArray(dimensions, dictionary);
} }
} }
else
{
throw new NotImplementedException();
}
} }
else else
{ {
@ -634,18 +727,21 @@ namespace MatFileHandler
private static IArray ReadCellArray(long datasetId, int[] dims) private static IArray ReadCellArray(long datasetId, int[] dims)
{ {
var numberOfElements = dims.NumberOfElements(); var numberOfElements = dims.NumberOfElements();
var buf = Marshal.AllocHGlobal(Marshal.SizeOf(default(IntPtr)) * numberOfElements);
H5D.read(datasetId, H5T.STD_REF_OBJ, H5S.ALL, H5S.ALL, H5P.DEFAULT, buf);
var elements = new IArray[numberOfElements]; var elements = new IArray[numberOfElements];
for (var i = 0; i < numberOfElements; i++) using (var buf = new MemoryHandle(Marshal.SizeOf(default(IntPtr)) * numberOfElements))
{ {
var fieldDataSet = H5R.dereference( H5D.read(datasetId, H5T.STD_REF_OBJ, H5S.ALL, H5S.ALL, H5P.DEFAULT, buf.Handle);
datasetId, for (var i = 0; i < numberOfElements; i++)
H5P.DEFAULT, {
H5R.type_t.OBJECT, var fieldDataSet =
buf + (i * Marshal.SizeOf(default(IntPtr)))); H5R.dereference(
var dataset = ReadDataset(fieldDataSet); datasetId,
elements[i] = dataset; H5P.DEFAULT,
H5R.type_t.OBJECT,
buf.Handle + (i * Marshal.SizeOf(default(IntPtr))));
var dataset = ReadDataset(fieldDataSet);
elements[i] = dataset;
}
} }
return new HdfCellArray(dims, elements); return new HdfCellArray(dims, elements);
} }
@ -715,11 +811,12 @@ namespace MatFileHandler
private static byte[] ReadDataset(long datasetId, long elementType, int dataSize) private static byte[] ReadDataset(long datasetId, long elementType, int dataSize)
{ {
var dataBuffer = Marshal.AllocHGlobal(dataSize);
H5D.read(datasetId, elementType, H5S.ALL, H5S.ALL, H5P.DEFAULT, dataBuffer);
var data = new byte[dataSize]; var data = new byte[dataSize];
Marshal.Copy(dataBuffer, data, 0, dataSize); using (var dataBuffer = new MemoryHandle(dataSize))
Marshal.FreeHGlobal(dataBuffer); {
H5D.read(datasetId, elementType, H5S.ALL, H5S.ALL, H5P.DEFAULT, dataBuffer.Handle);
Marshal.Copy(dataBuffer.Handle, data, 0, dataSize);
}
return data; return data;
} }