From 4a1124a91108de1ef069d54639d13f529be61b67 Mon Sep 17 00:00:00 2001 From: Henri Date: Fri, 12 May 2023 22:34:05 -0400 Subject: [PATCH 1/2] Add support for PrintIM tag --- v3/undefined/exif_C4A5_printim.go | 123 +++++++++++++++++++++++++ v3/undefined/exif_C4A5_printim_test.go | 99 ++++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 v3/undefined/exif_C4A5_printim.go create mode 100644 v3/undefined/exif_C4A5_printim_test.go diff --git a/v3/undefined/exif_C4A5_printim.go b/v3/undefined/exif_C4A5_printim.go new file mode 100644 index 0000000..119b94c --- /dev/null +++ b/v3/undefined/exif_C4A5_printim.go @@ -0,0 +1,123 @@ +package exifundefined + +import ( + "fmt" + + "encoding/binary" + + log "github.com/dsoprea/go-logging" + + exifcommon "github.com/dsoprea/go-exif/v3/common" +) + +type PrintIMKeyValue struct { + key uint16 + value uint32 +} +type TagExifC4A5PrintIM struct { + version string + values []PrintIMKeyValue +} + +func (TagExifC4A5PrintIM) EncoderName() string { + return "CodecExifC4A5PrintIM" +} + +func (af TagExifC4A5PrintIM) String() string { + return fmt.Sprintf("Version: %s", af.version) +} + +const () + +type CodecExifC4A5PrintIM struct { +} + +func (CodecExifC4A5PrintIM) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) { + defer func() { + if state := recover(); state != nil { + err = log.Wrap(state.(error)) + } + }() + + p, ok := value.(TagExifC4A5PrintIM) + if !ok { + log.Panicf("can only encode a TagExifC4A5PrintIM") + } + + size := 16 + 6*len(p.values) + e := make([]byte, size) + + copy(e, "PrintIM") + if len(p.version) > 4 { + log.PanicIf("version can't be more than 4 bytes") + } + copy(e[8:], p.version) + + byteOrder.PutUint16(e[14:], uint16(len(p.values))) + + for i, kv := range p.values { + byteOrder.PutUint16(e[16+6*i:], kv.key) + byteOrder.PutUint32(e[16+6*i+2:], kv.value) + } + + return e, uint32(size), nil +} + +func (CodecExifC4A5PrintIM) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) { + defer func() { + if state := recover(); state != nil { + err = log.Wrap(state.(error)) + } + }() + + valueContext.SetUndefinedValueType(exifcommon.TypeByte) + + // From what I understand, this is the structure: + // 0..7: "PrintIM" followed by a 0 byte + // 8..11: 4 byte string version number + // 12..13: ? (two null bytes) + // 14..15: number of chunks, as uint16 + // 16.... num_chunks times + // 0..1 uint16: key + // 2..5 uint32: value + + b, err := valueContext.ReadBytes() + log.PanicIf(err) + + if len(b) < 16 { + log.Panic("PrintIM Tag too short") + } + + if string(b[0:7]) != "PrintIM" || b[7] != 0 { + log.Panic(fmt.Errorf("PrintIM Tag not starting with \"PrintIM\"")) + } + + tag := TagExifC4A5PrintIM{ + version: string(b[8:12]), + } + + numChunks := valueContext.ByteOrder().Uint16(b[14:]) + if int(numChunks*6+16) > len(b) { + log.Panic("Size mismatch in PrintIM Tag") + } + + for i := 0; i < int(numChunks); i++ { + offset := i*6 + 16 + tag.values = append(tag.values, PrintIMKeyValue{ + key: valueContext.ByteOrder().Uint16(b[offset:]), + value: valueContext.ByteOrder().Uint32(b[offset+2:]), + }) + } + return tag, nil +} + +func init() { + registerEncoder( + TagExifC4A5PrintIM{}, + CodecExifC4A5PrintIM{}) + + registerDecoder( + exifcommon.IfdStandardIfdIdentity.UnindexedString(), + 0xc4a5, + CodecExifC4A5PrintIM{}) +} diff --git a/v3/undefined/exif_C4A5_printim_test.go b/v3/undefined/exif_C4A5_printim_test.go new file mode 100644 index 0000000..a140ff1 --- /dev/null +++ b/v3/undefined/exif_C4A5_printim_test.go @@ -0,0 +1,99 @@ +package exifundefined + +import ( + "bytes" + "reflect" + "testing" + + log "github.com/dsoprea/go-logging" + rifs "github.com/dsoprea/go-utility/v2/filesystem" + + exifcommon "github.com/dsoprea/go-exif/v3/common" +) + +func TestTagExifC4A5PrintIM_String(t *testing.T) { + ut := TagExifA301SceneType(0x1234) + + s := ut.String() + if s != "0x00001234" { + t.Fatalf("String not correct: [%s]", s) + } +} + +func TestCodecExifC4A5PrintIM_Encode(t *testing.T) { + ut := TagExifC4A5PrintIM{ + version: "1234", + values: []PrintIMKeyValue{ + { + key: 0x1, + value: 0x12345678, + }, + { + key: 0x4212, + value: 0x90ABCDEF, + }, + }, + } + + codec := CodecExifC4A5PrintIM{} + + encoded, unitCount, err := codec.Encode(ut, exifcommon.TestDefaultByteOrder) + log.PanicIf(err) + + expectedEncoded := []byte{ + 0x50, 0x72, 0x69, 0x6E, 0x74, 0x49, 0x4D, 0x00, // "PrintIM" + null byte + 0x31, 0x32, 0x33, 0x34, 0x00, 0x00, 0x00, 0x02, // "1234" version, 2 null bytes, and num_chunks (big endian for tests) + 0x00, 0x01, 0x12, 0x34, 0x56, 0x78, // First chunk + 0x42, 0x12, 0x90, 0xAB, 0xCD, 0xEF, // Second chunk + } + if !bytes.Equal(encoded, expectedEncoded) { + exifcommon.DumpBytesClause(encoded) + t.Fatalf("Encoding not correct.") + } else if unitCount != uint32(len(expectedEncoded)) { + t.Fatalf("Unit-count not correct: (%d)", unitCount) + } +} + +func TestCodecExifC4A5PrintIM_Decode(t *testing.T) { + expectedUt := TagExifC4A5PrintIM{ + version: "1234", + values: []PrintIMKeyValue{ + { + key: 0x1, + value: 0x12345678, + }, + { + key: 0x4212, + value: 0x90ABCDEF, + }, + }, + } + + encoded := []byte{ + 0x50, 0x72, 0x69, 0x6E, 0x74, 0x49, 0x4D, 0x00, // "PrintIM" + null byte + 0x31, 0x32, 0x33, 0x34, 0x00, 0x00, 0x00, 0x02, // "1234" version, 2 null bytes, and num_chunks (big endian for tests) + 0x00, 0x01, 0x12, 0x34, 0x56, 0x78, // First chunk + 0x42, 0x12, 0x90, 0xAB, 0xCD, 0xEF, // Second chunk + } + + sb := rifs.NewSeekableBufferWithBytes(encoded) + + valueContext := exifcommon.NewValueContext( + "", + 0, + uint32(len(encoded)), + 0, + nil, + sb, + exifcommon.TypeUndefined, + exifcommon.TestDefaultByteOrder) + + codec := CodecExifC4A5PrintIM{} + + decoded, err := codec.Decode(valueContext) + log.PanicIf(err) + + if reflect.DeepEqual(decoded, expectedUt) != true { + t.Fatalf("Decoded struct not correct.") + } +} From 75f94522a43d8634e7a16041c741ce76305429c2 Mon Sep 17 00:00:00 2001 From: Henri Date: Fri, 12 May 2023 22:34:24 -0400 Subject: [PATCH 2/2] mod tidy --- v3/go.mod | 3 --- v3/go.sum | 6 ++++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/v3/go.mod b/v3/go.mod index e5a18f0..43d94b6 100644 --- a/v3/go.mod +++ b/v3/go.mod @@ -9,10 +9,7 @@ go 1.12 require ( github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 - github.com/go-errors/errors v1.4.2 // indirect github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 github.com/jessevdk/go-flags v1.5.0 - golang.org/x/net v0.0.0-20221002022538-bcab6841153b // indirect - golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect gopkg.in/yaml.v2 v2.4.0 ) diff --git a/v3/go.sum b/v3/go.sum index f69540e..4791437 100644 --- a/v3/go.sum +++ b/v3/go.sum @@ -1,11 +1,17 @@ github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E= github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8= +github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk= +github.com/dsoprea/go-exif/v3 v3.0.0-20221003160559-cf5cd88aa559/go.mod h1:rW6DMEv25U9zCtE5ukC7ttBRllXj7g7TAHl7tQrT5No= +github.com/dsoprea/go-exif/v3 v3.0.0-20221003171958-de6cb6e380a8/go.mod h1:akyZEJZ/k5bmbC9gA612ZLQkcED8enS9vuTiuAkENr0= github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA= github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8= github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd h1:l+vLbuxptsC6VQyQsfD7NnEC8BZuFpz45PgY+pH8YTg= github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8= github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf h1:/w4QxepU4AHh3AuO6/g8y/YIIHH5+aKP3Bj8sg5cqhU= github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8= +github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU= +github.com/dsoprea/go-utility/v2 v2.0.0-20221003142440-7a1927d49d9d/go.mod h1:LVjRU0RNUuMDqkPTxcALio0LWPFPXxxFCvVGVAwEpFc= +github.com/dsoprea/go-utility/v2 v2.0.0-20221003160719-7bc88537c05e/go.mod h1:VZ7cB0pTjm1ADBWhJUOHESu4ZYy9JN+ZPqjfiW09EPU= github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 h1:DilThiXje0z+3UQ5YjYiSRRzVdtamFpvBQXKwMglWqw= github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349/go.mod h1:4GC5sXji84i/p+irqghpPFZBF8tRN/Q7+700G0/DLe8= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=