HDF5DotNet and string in compound data type

Thanks Gerd for the comments and code. I went through your code and I am no more enlightened as to what may be going wrong with my code. You are correct that I am using fixed length string of 10 characters including the terminating null. As a side note there does not seem to be a way of setting the character encoding, i.e. set_cset(...)? For practical purposes and in most situations its not going to matter I guess whether its ASCII or UTF-8. To your comment on initialization, I believe the following statement is ok:tsa[i].char1 = barr2;I have confirmed this in the debugger. I have even looked at the contents of each of the tsa[i].char arrays and mapped to the ASCII table and all is in order. Lonnie

···

----------------------------------------------------------------------

Message: 1
Date: Mon, 8 Jun 2015 12:37:42 +0100
From: Lonnie Hamm <lonniehamm@hotmail.com>
To: "hdf-forum@lists.hdfgroup.org" <hdf-forum@lists.hdfgroup.org>
Subject: [Hdf-forum] HDF5DotNet and string in compound data type
Message-ID: <DUB114-W12806A51A4C4C191E9882E6C9BF0@phx.gbl>
Content-Type: text/plain; charset="iso-8859-1"

I know this question (or related to) has been asked a few times but the answers don't seem to be of any help to me. Below is my code. I am simply trying to write out a compound data type with one element being a string. All the numbers, i.e. int1, double1, and double2 in the structure are correct when I view the resulting file in HDFView but the string is garbage. Any suggestions?

using System;
using HDF5DotNet;
using System.Runtime.InteropServices;
using System.IO;

namespace TestCompound
{
    class Program
    {
        const int N_RECORDS = 5; // number of records in the table
        const int N_FIELDS = 4; // number of fields
        const int RANK = 1;
        const string TABLE_NAME = "Test";
        const string FILE_NAME = "test_file2.h5";

        [StructLayout(LayoutKind.Explicit)]
        public struct testStruct2
        {
            [FieldOffset(0)]
            public int int1;
            [FieldOffset(4)]
            public byte[] char1; // assuming 9 characters + null termination
            [FieldOffset(14)]
            public double double1;
            [FieldOffset(22)]
            public double double2;
        }
        
        static void Main(string[] args)
        {
            try
            {

                // initialize the data
                testStruct2[] tsa = new testStruct2[N_RECORDS];
                for (int i = 0; i< N_RECORDS; i++)
                {
                    tsa[i].int1 = i;
                    byte[] barr1 = System.Text.Encoding.ASCII.GetBytes("testline" + i.ToString());
                    byte[] barr2 = new byte[10];
                    System.Buffer.BlockCopy(barr1, 0, barr2, 0, 9);
                    barr2[9] = 0; // null termination
                    tsa[i].char1 = barr2;
                    tsa[i].double1 = i * (i + 0.25);
                    tsa[i].double2 = 1 / (i + 1.25);
                }

                // create the file
                H5FileId fileId = H5F.create(FILE_NAME, H5F.CreateMode.ACC_TRUNC);

                // create the data space
                long[] dims = new long[1] { N_RECORDS };
                H5DataSpaceId spaceId = H5S.create_simple(RANK, dims);

                // create the memory data type
                int structSize = Marshal.SizeOf(typeof(testStruct2));
                H5DataTypeId typeId = H5T.create(H5T.CreateClass.COMPOUND, structSize);

                // insert members
                string[] field_names = { "a", "b", "c", "d" };
                H5T.insert(typeId, field_names[0], Marshal.OffsetOf(typeof(testStruct2), "int1").ToInt32(), H5T.H5Type.NATIVE_INT);
                H5DataTypeId stDtId = H5T.copy(H5T.H5Type.C_S1);
                H5T.setSize(stDtId, 10);
                H5T.insert(typeId, field_names[1], Marshal.OffsetOf(typeof(testStruct2), "char1").ToInt32(), stDtId);
                H5T.insert(typeId, field_names[2], Marshal.OffsetOf(typeof(testStruct2), "double1").ToInt32(), H5T.H5Type.NATIVE_DOUBLE);
                H5T.insert(typeId, field_names[3], Marshal.OffsetOf(typeof(testStruct2), "double2").ToInt32(), H5T.H5Type.NATIVE_DOUBLE);

                 // create the dataset
                H5DataSetId dsetId = H5D.create(fileId, TABLE_NAME, typeId, spaceId);

                // Write the dataset.
                H5D.write<testStruct2>(dsetId, typeId, spaceId, spaceId, new H5PropertyListId(H5P.Template.DEFAULT), new H5Array<testStruct2>(tsa));
                // Close resources.
                H5D.close(dsetId);
                H5S.close(spaceId);
                H5T.close(typeId);
                H5F.close(fileId);
            }
            catch (HDFException anyHDF5E)
            {
                Console.WriteLine(anyHDF5E.Message);
            }
            catch (System.Exception sysE)
            {
                Console.WriteLine(sysE.TargetSite);
                Console.WriteLine(sysE.Message);
            }
        }
    }
}

Lonnie
                 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.hdfgroup.org/pipermail/hdf-forum_lists.hdfgroup.org/attachments/20150608/82edf667/attachment-0001.html>

------------------------------

Message: 2
Date: Mon, 8 Jun 2015 13:18:58 +0000
From: Gerd Heber <gheber@hdfgroup.org>
To: HDF Users Discussion List <hdf-forum@lists.hdfgroup.org>
Subject: Re: [Hdf-forum] HDF5DotNet and string in compound data type
Message-ID:
  <BLUPR0701MB197145AE0B1B8A9E35250A6DA4BF0@BLUPR0701MB1971.namprd07.prod.outlook.com>
  
Content-Type: text/plain; charset="us-ascii"

Lonnie, how are you? I'm sure you are aware of the difference between
fixed-length and variable-length strings, and how the (C-) library deals with them.
Attached is an IronPython example similar to yours, but with a variable-length string
member. I believe your example is intended to use a fixed-length (10) member.
The problem might be your assignment

tsa[i].char1 = barr2;

which doesn't really initialize the 10 bytes you set aside for the string in tsa[i].

G.

From: Hdf-forum [mailto:hdf-forum-bounces@lists.hdfgroup.org] On Behalf Of Lonnie Hamm
Sent: Monday, June 8, 2015 6:38 AM
To: hdf-forum@lists.hdfgroup.org
Subject: [Hdf-forum] HDF5DotNet and string in compound data type

I know this question (or related to) has been asked a few times but the answers don't seem to be of any help to me. Below is my code. I am simply trying to write out a compound data type with one element being a string. All the numbers, i.e. int1, double1, and double2 in the structure are correct when I view the resulting file in HDFView but the string is garbage. Any suggestions?

using System;
using HDF5DotNet;
using System.Runtime.InteropServices;
using System.IO;

namespace TestCompound
{
    class Program
    {
        const int N_RECORDS = 5; // number of records in the table
        const int N_FIELDS = 4; // number of fields
        const int RANK = 1;
        const string TABLE_NAME = "Test";
        const string FILE_NAME = "test_file2.h5";

        [StructLayout(LayoutKind.Explicit)]
        public struct testStruct2
        {
            [FieldOffset(0)]
            public int int1;
            [FieldOffset(4)]
            public byte[] char1; // assuming 9 characters + null termination
            [FieldOffset(14)]
            public double double1;
            [FieldOffset(22)]
            public double double2;
        }

        static void Main(string[] args)
        {
            try
            {

                // initialize the data
                testStruct2[] tsa = new testStruct2[N_RECORDS];
                for (int i = 0; i< N_RECORDS; i++)
                {
                    tsa[i].int1 = i;
                    byte[] barr1 = System.Text.Encoding.ASCII.GetBytes("testline" + i.ToString());
                    byte[] barr2 = new byte[10];
                    System.Buffer.BlockCopy(barr1, 0, barr2, 0, 9);
                    barr2[9] = 0; // null termination
                    tsa[i].char1 = barr2;
                    tsa[i].double1 = i * (i + 0.25);
                    tsa[i].double2 = 1 / (i + 1.25);
                }

                // create the file
                H5FileId fileId = H5F.create(FILE_NAME, H5F.CreateMode.ACC_TRUNC);

                // create the data space
                long[] dims = new long[1] { N_RECORDS };
                H5DataSpaceId spaceId = H5S.create_simple(RANK, dims);

                // create the memory data type
                int structSize = Marshal.SizeOf(typeof(testStruct2));
                H5DataTypeId typeId = H5T.create(H5T.CreateClass.COMPOUND, structSize);

                // insert members
                string[] field_names = { "a", "b", "c", "d" };
                H5T.insert(typeId, field_names[0], Marshal.OffsetOf(typeof(testStruct2), "int1").ToInt32(), H5T.H5Type.NATIVE_INT);
                H5DataTypeId stDtId = H5T.copy(H5T.H5Type.C_S1);
                H5T.setSize(stDtId, 10);
                H5T.insert(typeId, field_names[1], Marshal.OffsetOf(typeof(testStruct2), "char1").ToInt32(), stDtId);
                H5T.insert(typeId, field_names[2], Marshal.OffsetOf(typeof(testStruct2), "double1").ToInt32(), H5T.H5Type.NATIVE_DOUBLE);
                H5T.insert(typeId, field_names[3], Marshal.OffsetOf(typeof(testStruct2), "double2").ToInt32(), H5T.H5Type.NATIVE_DOUBLE);

                 // create the dataset
                H5DataSetId dsetId = H5D.create(fileId, TABLE_NAME, typeId, spaceId);

                // Write the dataset.
                H5D.write<testStruct2>(dsetId, typeId, spaceId, spaceId, new H5PropertyListId(H5P.Template.DEFAULT), new H5Array<testStruct2>(tsa));
                // Close resources.
                H5D.close(dsetId);
                H5S.close(spaceId);
                H5T.close(typeId);
                H5F.close(fileId);
            }
            catch (HDFException anyHDF5E)
            {
                Console.WriteLine(anyHDF5E.Message);
            }
            catch (System.Exception sysE)
            {
                Console.WriteLine(sysE.TargetSite);
                Console.WriteLine(sysE.Message);
            }
        }
    }
}

Lonnie
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.hdfgroup.org/pipermail/hdf-forum_lists.hdfgroup.org/attachments/20150608/a863b46a/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: h5_cmpd.py
Type: application/octet-stream
Size: 5525 bytes
Desc: h5_cmpd.py
URL: <http://lists.hdfgroup.org/pipermail/hdf-forum_lists.hdfgroup.org/attachments/20150608/a863b46a/attachment.obj>

------------------------------

Subject: Digest Footer

_______________________________________________
Hdf-forum is for HDF software users discussion.
Hdf-forum@lists.hdfgroup.org
http://lists.hdfgroup.org/mailman/listinfo/hdf-forum_lists.hdfgroup.org

------------------------------

End of Hdf-forum Digest, Vol 72, Issue 19
*****************************************

Lonnie, arrays are reference types in .NET (I believe), i.e.,
the assignment "tsap[i].char1 = barr2;" will change a reference
and NOT copy the bytes in the array referred to by barr2
over the 10 bytes between the int1 and double1 fields, which is
what the underlying unmanaged code expects to find in memory.
It finds the (contiguous) bytes between int1 and double1,
which is NOT what you initialize with the assignment. (except for the reference part)
Maybe I'm wrong...

Best, G.

···

From: Hdf-forum [mailto:hdf-forum-bounces@lists.hdfgroup.org] On Behalf Of Lonnie Hamm
Sent: Wednesday, June 10, 2015 10:53 AM
To: hdf-forum@lists.hdfgroup.org
Subject: Re: [Hdf-forum] HDF5DotNet and string in compound data type

Thanks Gerd for the comments and code. I went through your code and I am no more enlightened as to what may be going wrong with my code. You are correct that I am using fixed length string of 10 characters including the terminating null. As a side note there does not seem to be a way of setting the character encoding, i.e. set_cset(...)? For practical purposes and in most situations its not going to matter I guess whether its ASCII or UTF-8.

To your comment on initialization, I believe the following statement is ok:
tsa[i].char1 = barr2;
I have confirmed this in the debugger. I have even looked at the contents of each of the tsa[i].char arrays and mapped to the ASCII table and all is in order.

Lonnie

----------------------------------------------------------------------

Message: 1
Date: Mon, 8 Jun 2015 12:37:42 +0100
From: Lonnie Hamm <lonniehamm@hotmail.com<mailto:lonniehamm@hotmail.com>>
To: "hdf-forum@lists.hdfgroup.org<mailto:hdf-forum@lists.hdfgroup.org>" <hdf-forum@lists.hdfgroup.org<mailto:hdf-forum@lists.hdfgroup.org>>
Subject: [Hdf-forum] HDF5DotNet and string in compound data type
Message-ID: <DUB114-W12806A51A4C4C191E9882E6C9BF0@phx.gbl<mailto:DUB114-W12806A51A4C4C191E9882E6C9BF0@phx.gbl>>
Content-Type: text/plain; charset="iso-8859-1"

I know this question (or related to) has been asked a few times but the answers don't seem to be of any help to me. Below is my code. I am simply trying to write out a compound data type with one element being a string. All the numbers, i.e. int1, double1, and double2 in the structure are correct when I view the resulting file in HDFView but the string is garbage. Any suggestions?

using System;
using HDF5DotNet;
using System.Runtime.InteropServices;
using System.IO;

namespace TestCompound
{
class Program
{
const int N_RECORDS = 5; // number of records in the table
const int N_FIELDS = 4; // number of fields
const int RANK = 1;
const string TABLE_NAME = "Test";
const string FILE_NAME = "test_file2.h5";

[StructLayout(LayoutKind.Explicit)]
public struct testStruct2
{
[FieldOffset(0)]
public int int1;
[FieldOffset(4)]
public byte[] char1; // assuming 9 characters + null termination
[FieldOffset(14)]
public double double1;
[FieldOffset(22)]
public double double2;
}

static void Main(string[] args)
{
try
{

// initialize the data
testStruct2[] tsa = new testStruct2[N_RECORDS];
for (int i = 0; i< N_RECORDS; i++)
{
tsa[i].int1 = i;
byte[] barr1 = System.Text.Encoding.ASCII.GetBytes("testline" + i.ToString());
byte[] barr2 = new byte[10];
System.Buffer.BlockCopy(barr1, 0, barr2, 0, 9);
barr2[9] = 0; // null termination
tsa[i].char1 = barr2;
tsa[i].double1 = i * (i + 0.25);
tsa[i].double2 = 1 / (i + 1.25);
}

// create the file
H5FileId fileId = H5F.create(FILE_NAME, H5F.CreateMode.ACC_TRUNC);

// create the data space
long[] dims = new long[1] { N_RECORDS };
H5DataSpaceId spaceId = H5S.create_simple(RANK, dims);

// create the memory data type
int structSize = Marshal.SizeOf(typeof(testStruct2));
H5DataTypeId typeId = H5T.create(H5T.CreateClass.COMPOUND, structSize);

// insert members
string[] field_names = { "a", "b", "c", "d" };
H5T.insert(typeId, field_names[0], Marshal.OffsetOf(typeof(testStruct2), "int1").ToInt32(), H5T.H5Type.NATIVE_INT);
H5DataTypeId stDtId = H5T.copy(H5T.H5Type.C_S1);
H5T.setSize(stDtId, 10);
H5T.insert(typeId, field_names[1], Marshal.OffsetOf(typeof(testStruct2), "char1").ToInt32(), stDtId);
H5T.insert(typeId, field_names[2], Marshal.OffsetOf(typeof(testStruct2), "double1").ToInt32(), H5T.H5Type.NATIVE_DOUBLE);
H5T.insert(typeId, field_names[3], Marshal.OffsetOf(typeof(testStruct2), "double2").ToInt32(), H5T.H5Type.NATIVE_DOUBLE);

// create the dataset
H5DataSetId dsetId = H5D.create(fileId, TABLE_NAME, typeId, spaceId);

// Write the dataset.
H5D.write<testStruct2>(dsetId, typeId, spaceId, spaceId, new H5PropertyListId(H5P.Template.DEFAULT), new H5Array<testStruct2>(tsa));
// Close resources.
H5D.close(dsetId);
H5S.close(spaceId);
H5T.close(typeId);
H5F.close(fileId);
}
catch (HDFException anyHDF5E)
{
Console.WriteLine(anyHDF5E.Message);
}
catch (System.Exception sysE)
{
Console.WriteLine(sysE.TargetSite);
Console.WriteLine(sysE.Message);
}
}
}
}

Lonnie

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.hdfgroup.org/pipermail/hdf-forum_lists.hdfgroup.org/attachments/20150608/82edf667/attachment-0001.html>

------------------------------

Message: 2
Date: Mon, 8 Jun 2015 13:18:58 +0000
From: Gerd Heber <gheber@hdfgroup.org<mailto:gheber@hdfgroup.org>>
To: HDF Users Discussion List <hdf-forum@lists.hdfgroup.org<mailto:hdf-forum@lists.hdfgroup.org>>
Subject: Re: [Hdf-forum] HDF5DotNet and string in compound data type
Message-ID:
<BLUPR0701MB197145AE0B1B8A9E35250A6DA4BF0@BLUPR0701MB1971.namprd07.prod.outlook.com<mailto:BLUPR0701MB197145AE0B1B8A9E35250A6DA4BF0@BLUPR0701MB1971.namprd07.prod.outlook.com>>

Content-Type: text/plain; charset="us-ascii"

Lonnie, how are you? I'm sure you are aware of the difference between
fixed-length and variable-length strings, and how the (C-) library deals with them.
Attached is an IronPython example similar to yours, but with a variable-length string
member. I believe your example is intended to use a fixed-length (10) member.
The problem might be your assignment

tsa[i].char1 = barr2;

which doesn't really initialize the 10 bytes you set aside for the string in tsa[i].

G.

From: Hdf-forum [mailto:hdf-forum-bounces@lists.hdfgroup.org] On Behalf Of Lonnie Hamm
Sent: Monday, June 8, 2015 6:38 AM
To: hdf-forum@lists.hdfgroup.org<mailto:hdf-forum@lists.hdfgroup.org>
Subject: [Hdf-forum] HDF5DotNet and string in compound data type

I know this question (or related to) has been asked a few times but the answers don't seem to be of any help to me. Below is my code. I am simply trying to write out a compound data type with one element being a string. All the numbers, i.e. int1, double1, and double2 in the structure are correct when I view the resulting file in HDFView but the string is garbage. Any suggestions?

using System;
using HDF5DotNet;
using System.Runtime.InteropServices;
using System.IO;

namespace TestCompound
{
class Program
{
const int N_RECORDS = 5; // number of records in the table
const int N_FIELDS = 4; // number of fields
const int RANK = 1;
const string TABLE_NAME = "Test";
const string FILE_NAME = "test_file2.h5";

[StructLayout(LayoutKind.Explicit)]
public struct testStruct2
{
[FieldOffset(0)]
public int int1;
[FieldOffset(4)]
public byte[] char1; // assuming 9 characters + null termination
[FieldOffset(14)]
public double double1;
[FieldOffset(22)]
public double double2;
}

static void Main(string[] args)
{
try
{

// initialize the data
testStruct2[] tsa = new testStruct2[N_RECORDS];
for (int i = 0; i< N_RECORDS; i++)
{
tsa[i].int1 = i;
byte[] barr1 = System.Text.Encoding.ASCII.GetBytes("testline" + i.ToString());
byte[] barr2 = new byte[10];
System.Buffer.BlockCopy(barr1, 0, barr2, 0, 9);
barr2[9] = 0; // null termination
tsa[i].char1 = barr2;
tsa[i].double1 = i * (i + 0.25);
tsa[i].double2 = 1 / (i + 1.25);
}

// create the file
H5FileId fileId = H5F.create(FILE_NAME, H5F.CreateMode.ACC_TRUNC);

// create the data space
long[] dims = new long[1] { N_RECORDS };
H5DataSpaceId spaceId = H5S.create_simple(RANK, dims);

// create the memory data type
int structSize = Marshal.SizeOf(typeof(testStruct2));
H5DataTypeId typeId = H5T.create(H5T.CreateClass.COMPOUND, structSize);

// insert members
string[] field_names = { "a", "b", "c", "d" };
H5T.insert(typeId, field_names[0], Marshal.OffsetOf(typeof(testStruct2), "int1").ToInt32(), H5T.H5Type.NATIVE_INT);
H5DataTypeId stDtId = H5T.copy(H5T.H5Type.C_S1);
H5T.setSize(stDtId, 10);
H5T.insert(typeId, field_names[1], Marshal.OffsetOf(typeof(testStruct2), "char1").ToInt32(), stDtId);
H5T.insert(typeId, field_names[2], Marshal.OffsetOf(typeof(testStruct2), "double1").ToInt32(), H5T.H5Type.NATIVE_DOUBLE);
H5T.insert(typeId, field_names[3], Marshal.OffsetOf(typeof(testStruct2), "double2").ToInt32(), H5T.H5Type.NATIVE_DOUBLE);

// create the dataset
H5DataSetId dsetId = H5D.create(fileId, TABLE_NAME, typeId, spaceId);

// Write the dataset.
H5D.write<testStruct2>(dsetId, typeId, spaceId, spaceId, new H5PropertyListId(H5P.Template.DEFAULT), new H5Array<testStruct2>(tsa));
// Close resources.
H5D.close(dsetId);
H5S.close(spaceId);
H5T.close(typeId);
H5F.close(fileId);
}
catch (HDFException anyHDF5E)
{
Console.WriteLine(anyHDF5E.Message);
}
catch (System.Exception sysE)
{
Console.WriteLine(sysE.TargetSite);
Console.WriteLine(sysE.Message);
}
}
}
}

Lonnie
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.hdfgroup.org/pipermail/hdf-forum_lists.hdfgroup.org/attachments/20150608/a863b46a/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: h5_cmpd.py
Type: application/octet-stream
Size: 5525 bytes
Desc: h5_cmpd.py
URL: <http://lists.hdfgroup.org/pipermail/hdf-forum_lists.hdfgroup.org/attachments/20150608/a863b46a/attachment.obj>

------------------------------

Subject: Digest Footer

_______________________________________________
Hdf-forum is for HDF software users discussion.
Hdf-forum@lists.hdfgroup.org<mailto:Hdf-forum@lists.hdfgroup.org>
http://lists.hdfgroup.org/mailman/listinfo/hdf-forum_lists.hdfgroup.org

------------------------------

End of Hdf-forum Digest, Vol 72, Issue 19
*****************************************