Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Variable length string Read not working #6

Open
tclarke opened this issue Jan 17, 2014 · 2 comments
Open

Variable length string Read not working #6

tclarke opened this issue Jan 17, 2014 · 2 comments
Assignees

Comments

@tclarke
Copy link
Contributor

tclarke commented Jan 17, 2014

Read() of scalar variable length string data does not appear to work.

var buf string
dset.Read(buf, hdf5.T_GO_STRING)

will error with:
panic: reflect.Value.UnsafeAddr of unaddressable value [recovered]
panic: reflect.Value.UnsafeAddr of unaddressable value

using dset.Read(&buf, hdf5.T_GO_STRING) works with uint, etc. but not with string. There is not error but buf will be empty.

@ghost ghost assigned sbinet Jan 20, 2014
@naegelejd
Copy link

I can reproduce this issue. I create a datset with a simple 1-D dataspace, with datatype hdf5.T_GO_STRING, then write a string slice containing only my single string to the dataset (errors ignored for simplicity):

dataspace, _ := hdf5.CreateSimpleDataspace([]uint{1}, nil)
dataset, _ := file.CreateDataset("group/xml", hdf5.T_GO_STRING, dataspace)
wrapper := []string{xml}
dataset.Write(&wrapper)

This works great! However, when I want to read my string back from the dataset I get an empty string:

dataset, _ := file.OpenDataset("group/xml")
wrapper := make([]string, 1)
dataset.Read(&wrapper)
fmt.Println(wrapper[0])

@naegelejd
Copy link

In fact, the strings in the s1Type in your example here are not properly read back into memory after being written to the HDF5 file. If you check the output printed here, you'll see that each struct's string member e is "empty". Also, each array member's last item is not read properly (it remains the zero value). You can see the difference between what is written and what is read in the output of your example:

:: data: [{0 0 1 [0 0 0] --0--} {1 1 0.5 [1 2 3] --1--} {2 4 0.3333333333333333 [2 4 6] --2--} {3 9 0.25 [3 6 9] --3--} {4 16 0.2 [4 8 12] --4--} {5 25 0.16666666666666666 [5 10 15] --5--} {6 36 0.14285714285714285 [6 12 18] --6--} {7 49 0.125 [7 14 21] --7--} {8 64 0.1111111111111111 [8 16 24] --8--} {9 81 0.1 [9 18 27] --9--}]
:: file [SDScompound.h5] created (id=16777216)
:: dset (id=83886080)
:: dset.Write...
:: dset.Write... [ok]
:: data: [{0 0 1 [0 0 0] } {1 1 0.5 [1 2 0] } {2 4 0.3333333333333333 [2 4 0] } {3 9 0.25 [3 6 0] } {4 16 0.2 [4 8 0] } {5 25 0.16666666666666666 [5 10 0] } {6 36 0.14285714285714285 [6 12 0] } {7 49 0.125 [7 14 0] } {8 64 0.1111111111111111 [8 16 0] } {9 81 0.1 [9 18 0] }]

I'm not positive, but, at least for strings and string slices, I don't think you can just call H5Dread to fill a string's StringHeader.Data field without updating its StringHeader.Len field. If I manually update this field in your Dataset.Read after the call to H5Dread, the string looks valid... but this is super hacky and just to demonstrate my point:

diff --git a/h5d.go b/h5d.go
index a3fa9d9..f22059e 100644
--- a/h5d.go
+++ b/h5d.go
@@ -149,6 +149,20 @@ func (s *Dataset) WriteSubset(data interface{}, memspace, filespace *Dataspace)
                filespace_id = filespace.id
        }
        rc := C.H5Dwrite(s.id, dtype.id, memspace_id, filespace_id, 0, addr)
+
+       // only checking for string slices
+       sp, ok := data.(*[]string)
+       if ok {
+               // show that the string was actually read from the file
+               fmt.Print("C.puts(...): ")
+               C.puts(*(**C.char)(addr))
+
+               // make Go believe it's a string of len > 0
+               head := (*reflect.SliceHeader)(unsafe.Pointer(&(*sp)[0]))
+               head.Len = int(C.strlen((*C.char)(unsafe.Pointer(head.Data))))
+               fmt.Println("s[0]: ", (*sp)[0])
+       }
+
        err = h5err(rc)
        return err
 }

This doesn't work, for example, with a struct containing strings, as in your example

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants