kaitai-io / kaitai_struct_formats

Kaitai Struct: library of binary file formats (.ksy)
http://formats.kaitai.io
708 stars 204 forks source link

Exif struct broken for Go #622

Open insomniacslk opened 2 years ago

insomniacslk commented 2 years ago

Hi, I noticed that image/exif.ksy is broken for Go, the generated files yield the following errors:

./exif.go:164:28: this._parent._is_le undefined (type interface {} is interface with no methods)
./exif.go:853:24: invalid operation: this.Length * tmp27 (mismatched types uint32 and int8)

The type of Exif_ExifBody_Ifd._parent is interface{}, hence the instruction this._is_le = this._parent._is_le fails because it is generated as AnyType instead of being converted to Exif_ExifBody_Ifd.

This happens with both Go 1.17 and Go 1.18.

The issue can be reproduced with the following commands:

curl https://raw.githubusercontent.com/kaitai-io/kaitai_struct_formats/master/image/exif.ksy -o exif.ksy`
ksc -t go --go-package=main exif.ksy
cd main
go mod init test
go mod tidy
go build

I don't have experience with Scala, or I'd have submitted a PR, let me know if I should provide more information.

Thanks!

insomniacslk commented 2 years ago

I just realized that the compiler cannot infer the right type, because parent could be more than one type (that is, either Exif_ExifBody or Exif_ExifBody_Ifd), so interface{} is the most appropriate here, then it requires runtime type casting to read _is_le properly

insomniacslk commented 2 years ago

Another (ugly) option is to use reflection. If the type is unknown, the attribute can be resolved at runtime like this:

    // Using reflection to read this._parent._is_le, because this._parent could
    // be one of Exif_ExifBody or Exif_ExifBody_Ifd .
    // Elem() is called two more times, first to resolve the interface, and then to resolve the pointer.
    this._is_le = int(reflect.ValueOf(&this._parent).Elem().Elem().Elem().FieldByName("_is_le").Int())

but I hope there's a better option