title: How to read HDF5 variable length string attributes in C# .NET
body: <p>Using the <a href="https://github.com/HDFGroup/HDF.PInvoke" rel="nofollow noreferrer">HDF.PInvoke</a> library in C#, how do you read from a variable length string, <code>H5T_VARIABLE</code>, attribute?</p>
  
  <p>The HDF5 file looks like:</p>
  
  <pre><code>GROUP "/" {
     ATTRIBUTE "foo" {
        DATATYPE  H5T_STRING {
           STRSIZE H5T_VARIABLE;
           STRPAD H5T_STR_NULLTERM;
           CSET H5T_CSET_ASCII;
           CTYPE H5T_C_S1;
        }
        DATASPACE  SCALAR
        DATA {
        (0): "bar"
        }
     }
  }
  </code></pre>
  
  <p>Trying to read the attribute <code>foo</code> like this:</p>
  
  <pre><code>long fileId = H5F.open("my-file.h5", H5F.ACC_RDWR);
  long attrId = H5A.open(fileId, "foo");
  long typeId = H5A.get_type(attrId);
  H5A.info_t attrInfo = new H5A.info_t();
  var info_result = H5A.get_info(attrId, ref attrInfo);
  
  // Note sure if this `size` is useful.
  // Docs say: For variable-length string datatypes, the returned value is
  //           the size of the pointer to the actual string, or sizeof(char *). 
  //           This function does not return the size of actual variable-length
  //           string data.
  // @See: https://support.hdfgroup.org/HDF5/doc/RM/RM_H5T.html#Datatype-GetSize
  int size = H5T.get_size(typeId).ToInt32();
  
  // Docs say: `data_size` indicates the size, in the number of characters,
  //           of the attribute.
  // @See: https://support.hdfgroup.org/HDF5/doc/RM/RM_H5A.html#Annot-GetInfo
  int data_size = (int)attrInfo.data_size;
  
  // Docs say: In a C environment, variable-length strings will always be
  //           NULL-terminated, so the buffer to hold such a string must be
  //           one byte larger than the string itself to accommodate the NULL
  //           terminator.
  // @See: https://support.hdfgroup.org/HDF5/doc/RM/RM_H5T.html#CreateVLString
  IntPtr iPtr = Marshal.AllocHGlobal(data_size + 1); // Add one to fit NULL-terminator.
  
  int read_result = H5A.read(attrId, typeId, iPtr);
  if (H5T.is_variable_str(typeId) &gt; 0)
  {
    Console.WriteLine("attribute value = {0}", Marshal.PtrToStringAnsi(iPtr));
  }
  </code></pre>
  
  <p>The console outputs random data:</p>
  
  <pre><code>attribute value = @Ñ&gt;←
  </code></pre>