Read compound datatype array in attribute

Hello all,

I'm having some issues reading a compound datatype array that is an
attribute.The compound datatype has the fields:

"Name" variable length string
"NumericValue" 64-bit floating point
"StringValue" variable length string
"Units" variable length string

I'm trying to read it in using the HDF5 v1.8 .NET wrappers. However, there
are some problems with reading the data. The first problem is it appears
the endian order of the double value is wrong. Also the member field data
starts to get mixed up between elements of the array. If the compound
dataset only contains variable length strings, I can read it fine. The
problem arises when the double value is added. I attached the HDF5 file I'm
trying to read as a reference.

Any and all help is appreciated.

On a related note, is it possible to read just a single field at a time on
the attributes? For example, if the array is 4 elements long, is there a
way to read the value of "NumericValue" from element 3 only, i.e. what is
the best way to retrieve the dataspace for a field of a compound datatype
that is part of an array.

Regards,

Jesse

This is the program output.

variableStringattribute.zip (6.54 KB)

···

-----------------------------------------------
Successfully opened file
The dataset test exists
COMPOUND
Member Name: Name; Class: STRING; Length: 4
Member Name: NumericValue; Class: FLOAT; Length: 8
Member Name: StringValue; Class: STRING; Length: 4
Member Name: Units; Class: STRING; Length: 4

Condition 0
-------------------
Name: Power
Numeric Value: 8.35708918785685E-275
String Value: dB
Units: Voltage

Condition 1
-------------------
Name:
Numeric Value: 8.35753006037801E-275
String Value: StringValue
Units:

Condition 2
-------------------
Name:
Numeric Value: 8.35686897845336E-275
String Value:
Units:

Condition 3
-------------------
Name: Current
Numeric Value: 0
String Value:
Units:
-----------------------------------------------------------------

Here's my complete program:
----------------------------------------
class Program
    {
        public struct ConditionStruct
        {
            //public Chararray ConditionName;
            //public Chararray ConditionValue;
            //public Chararray ConditionUnits;

            public Chararray Name;
            public double NumericValue;
            public Chararray StringValue;
            public Chararray Units;
        }

        //this defines the struct used to read in the string data
        //since it is unsafe we need to use the layout to define the struct
        [StructLayout(LayoutKind.Sequential)]
        public unsafe struct Chararray
        {
            private char* recordedText;

            //an initializer to get and set the char* since it is unsafe
            public char* RecordedText
            {
                get
                {
                    return recordedText;
                }
                set
                {
                    recordedText = value;
                }
            }

            public override string ToString()
            {
                string s;
                //the HDF5 STRING is not a string but in fact a char *
                //since it is we need to translate the return into a pointer
address

                IntPtr ipp = (IntPtr)this.recordedText;

                //This call is used to transform the pointer into the value
of the pointer.
                //NOTE: this only works with null-terminated strings.
                s =
System.Runtime.InteropServices.Marshal.PtrToStringAnsi(ipp);

                // FREE THE MEMORY TO THE POINTER??
                //System.Runtime.InteropServices.Marshal.FreeHGlobal(ipp);

                return s;
            }
        }

        static void Main(string[] args)
        {
            bool isReadEnabled = true;
            string fileName;
            string datasetName;

            // FILENAME:
            fileName = @"C:\WORK\HDF5\variableStringattribute.h5";

            H5FileId fileId = H5F.open(fileName, H5F.OpenMode.ACC_RDONLY);
            Console.WriteLine("Successfully opened file");

            // DATASET NAME:
            datasetName = "test";

            H5ObjectInfo objectInfo = H5O.getInfoByName(fileId,
datasetName);

            if (objectInfo.objectType == H5ObjectType.DATASET)
            {
                Console.WriteLine(String.Format("The dataset {0} exists",
datasetName));

                H5AttributeId attributeId = null;
                H5DataTypeId dataTypeId = null;

                try
                {
                    attributeId = H5A.openByName(fileId, datasetName,
"Conditions");
                    dataTypeId = H5A.getType(attributeId);

                    // Determine the dataset rank to determine the number of
conditions
                    H5DataSpaceId dataSpaceId = H5A.getSpace(attributeId);
                    int rank = H5S.getSimpleExtentNDims(dataSpaceId);

                    ulong[] dims = H5S.getSimpleExtentDims(dataSpaceId);
                    int numConditions = (int)dims[0];

                    H5S.close(dataSpaceId);

                    // Verify that the dataset is a COMPOUND type
                    H5T.H5TClass dataClass = H5T.getClass(dataTypeId);
                    Console.WriteLine(dataClass.ToString());
                    if (dataClass != H5T.H5TClass.COMPOUND)
                    {
                        // ERROR
                    }

                    // Validate the number of fields of the compound type

                    // Get the number of fields of the struct
                    int numFields = H5T.getNMembers(dataTypeId);

                    // Look at each of the member fields
                    for (uint i = 0; i < numFields; i++)
                    {
                        H5T.H5TClass memberClass =
H5T.getMemberClass(dataTypeId, i);

                        string memberName = H5T.getMemberName(dataTypeId,
i);
                        H5DataTypeId memberDataTypeId =
H5T.getMemberType(dataTypeId, i);
                        uint offset = H5T.getMemberOffset(dataTypeId, i);

                        int length = (int)H5T.getSize(memberDataTypeId);
                        bool isVariableLength =
H5T.isVariableString(memberDataTypeId);

                        Console.WriteLine(String.Format("Member Name: {0};
Class: {1}; Length: {2}", memberName, memberClass.ToString(),
length.ToString()));

                        H5T.close(memberDataTypeId);
                    }

                    if (isReadEnabled)
                    {
                        ConditionStruct[] read_data4 = new
ConditionStruct[numConditions];

                        H5A.read(attributeId, dataTypeId, new
H5Array<ConditionStruct>(read_data4));

                        // Write the read values to the command window
                        Console.WriteLine("");
                        for (int i = 0; i < numConditions; i++)
                        {
                            Console.WriteLine(String.Format("Condition
{0}\n-------------------", i));
                            Console.WriteLine(String.Format("Name:
{0}\nNumeric Value: {1}\nString Value: {2}\nUnits: {3}",
read_data4[i].Name.ToString(), read_data4[i].NumericValue.ToString(),
read_data4[i].StringValue.ToString(), read_data4[i].Units.ToString()));
                            Console.WriteLine("");
                        }
                    }
                }
                catch (H5AopenByNameException)
                {
                    // Attribute does not exist
                }
                catch (H5AreadException)
                {
                    // Could not read the attribute correctly
                }
                finally
                {
                    if (dataTypeId != null)
                    {
                        H5T.close(dataTypeId);
                    }
                    if (attributeId != null)
                    {
                        H5A.close(attributeId);
                    }
                }
            }

            H5F.close(fileId);
            Console.ReadLine();
        }
    }