Search code examples
chdf5

Determine length of fixed-length string attribute from HDF5 file in C


I have an HDF5 file with the following contents:

$ h5dump foo.h5 
HDF5 "foo.h5" {
GROUP "/" {
   ATTRIBUTE "Version" {
      DATATYPE  H5T_STRING {
         STRSIZE 5;
         STRPAD H5T_STR_NULLTERM;
         CSET H5T_CSET_ASCII;
         CTYPE H5T_C_S1;
      }
      DATASPACE  SIMPLE { ( 1 ) / ( 1 ) }
      DATA {
      (0): "1.2.0"
      }
   }
...

How do I extract the STRSIZE (in this case 5) from the attribute? I can currently extract the entire string by allocating more memory than I think I need:

char version_string[] = "hello_hello_hello";
hid_t attr = H5Aopen(file_id, "Version", H5P_DEFAULT);
hid_t atype = H5Tcopy(H5T_C_S1);
H5Tset_size(atype, 17);
herr_t err = H5Aread(attr, atype, version_string);
H5Aclose(attr);
H5Tclose(atype);

However, I cannot figure out how to find allocate the right about of memory for the string.


Solution

  • (Disclaimer: I'm not a HDF5 user)

    From looking at the documentation, I think you need to use H5Aget_storage_size to determine the size of the buffer to use with H5Aread.

        hid_t versionAttr = H5Aopen( file_id, "Version", H5P_DEFAULT );
        if( versionAttr < 0 ) goto cleanup1;
    
        size_t versionAttrSize = 0;
        {
            hsize_t size = H5Aget_storage_size( versionAttr );
            if( size == 0 ) {
                // get_storage_size failed for some reason but the documentation isn't helpful. Grrrr.
                // TODO: Show an error message here, I guess.
                goto cleanup2;
            }
            else if( size > SIZE_MAX ) {
                // The data on-disk is larger than can be represented in C on your platform.
                // TODO: Show an error message here, I guess.
                goto cleanup2;
            }
            else {
                versionAttrSize = (size_t)size;
            }
        }
    
        char* versionAttrBuffer = malloc( versionAttrSize );
        if( !versionAttrBuffer ) {
            // Computer broken.
            goto cleanup2;
        }
    
        herr_t versionAttrBufferReadError = H5Aread( versionAttr, H5T_C_S1, versionAttrBuffer );
        if( versionAttrBufferReadError < 0 ) {
            goto cleanup3;
        }
    
        // Do stuff with `versionAttrBuffer` here.
        printf( "String attribute length: %d\n", versionAttrSize );
        printf( "String attribute data: \"%s\"", versionAttrBuffer );
    
    cleanup3:
        free( versionAttrBuffer );
    
    cleanup2:
        herr_t cleanupErr = H5Aclose( versionAttr );
        if( cleanupErr < 0 ) { die( "This should never happen." ); };
    
    cleanup1:
        // TODO: Close file?