From 50eafa98d68dda296f20714c92fe928967894d1e Mon Sep 17 00:00:00 2001 From: Dustin Oprea Date: Sun, 22 Apr 2018 02:35:33 -0400 Subject: [PATCH] ifd_enumerate: Added tests. - Refactored (IfdTagEntry).ValueBytes() to handle managed undefined values. --- exif.go | 12 +-- exif_test.go | 10 +-- ifd_builder.go | 31 ++++---- ifd_builder_test.go | 148 ++++++++++++++++++------------------ ifd_enumerate.go | 41 +++++++++- ifd_enumerate_test.go | 173 ++++++++++++++++++++++++++++++++++++++++++ type_decode.go | 2 + 7 files changed, 313 insertions(+), 104 deletions(-) create mode 100644 ifd_enumerate_test.go diff --git a/exif.go b/exif.go index bdd3fea..f702c02 100644 --- a/exif.go +++ b/exif.go @@ -135,14 +135,14 @@ func (e *Exif) ParseExifHeader(data []byte) (eh ExifHeader, err error) { return eh, nil } -func (e *Exif) Visit(exifData []byte, visitor TagVisitor) (err error) { +func (e *Exif) Visit(exifData []byte, visitor TagVisitor) (eh ExifHeader, err error) { defer func() { if state := recover(); state != nil { err = log.Wrap(state.(error)) } }() - eh, err := e.ParseExifHeader(exifData) + eh, err = e.ParseExifHeader(exifData) log.PanicIf(err) ie := NewIfdEnumerate(exifData, eh.ByteOrder) @@ -150,17 +150,17 @@ func (e *Exif) Visit(exifData []byte, visitor TagVisitor) (err error) { err = ie.Scan(IfdStandard, eh.FirstIfdOffset, visitor) log.PanicIf(err) - return nil + return eh, nil } -func (e *Exif) Collect(exifData []byte) (index IfdIndex, err error) { +func (e *Exif) Collect(exifData []byte) (eh ExifHeader, index IfdIndex, err error) { defer func() { if state := recover(); state != nil { err = log.Wrap(state.(error)) } }() - eh, err := e.ParseExifHeader(exifData) + eh, err = e.ParseExifHeader(exifData) log.PanicIf(err) ie := NewIfdEnumerate(exifData, eh.ByteOrder) @@ -168,5 +168,5 @@ func (e *Exif) Collect(exifData []byte) (index IfdIndex, err error) { index, err = ie.Collect(eh.FirstIfdOffset) log.PanicIf(err) - return index, nil + return eh, index, nil } diff --git a/exif_test.go b/exif_test.go index d53fb6c..22cf46b 100644 --- a/exif_test.go +++ b/exif_test.go @@ -109,7 +109,7 @@ func TestVisit(t *testing.T) { return nil } - err = e.Visit(data[foundAt:], visitor) + _, err = e.Visit(data[foundAt:], visitor) log.PanicIf(err) // for _, line := range tags { @@ -198,7 +198,7 @@ func TestCollect(t *testing.T) { rawExif, err := e.SearchAndExtractExif(filepath) log.PanicIf(err) - index, err := e.Collect(rawExif) + _, index, err := e.Collect(rawExif) log.PanicIf(err) rootIfd := index.RootIfd @@ -257,7 +257,7 @@ func TestCollect(t *testing.T) { foundExif := 0 foundGps := 0 for _, ite := range lookup[IfdStandard][0].Entries { - if ite.IfdName == IfdExif { + if ite.ChildIfdName == IfdExif { foundExif++ if IfdTagNames[ite.TagId] != IfdExif { @@ -265,7 +265,7 @@ func TestCollect(t *testing.T) { } } - if ite.IfdName == IfdGps { + if ite.ChildIfdName == IfdGps { foundGps++ if IfdTagNames[ite.TagId] != IfdGps { @@ -282,7 +282,7 @@ func TestCollect(t *testing.T) { foundIop := 0 for _, ite := range lookup[IfdExif][0].Entries { - if ite.IfdName == IfdIop { + if ite.ChildIfdName == IfdIop { foundIop++ if IfdTagNames[ite.TagId] != IfdIop { diff --git a/ifd_builder.go b/ifd_builder.go index ffe5ad8..54ce9eb 100644 --- a/ifd_builder.go +++ b/ifd_builder.go @@ -29,11 +29,11 @@ type builderTag struct { // value is either a value that can be encoded, an IfdBuilder instance (for // child IFDs), or an IfdTagEntry instance representing an existing, // previously-stored tag. - value interface{} + valueBytes interface{} } func (bt builderTag) String() string { - return fmt.Sprintf("BuilderTag", bt.tagId, bt.ifdName, bt.value) + return fmt.Sprintf("BuilderTag", bt.tagId, bt.ifdName, bt.valueBytes) } @@ -463,7 +463,7 @@ func (ib *IfdBuilder) AddChildIfd(childIfd *IfdBuilder) (err error) { bt := builderTag{ ifdName: childIfd.ifdName, tagId: childIfd.ifdTagId, - value: childIfd, + valueBytes: childIfd, } ib.Add(bt) @@ -474,7 +474,7 @@ func (ib *IfdBuilder) AddChildIfd(childIfd *IfdBuilder) (err error) { // AddTagsFromExisting does a verbatim copy of the entries in `ifd` to this // builder. It excludes child IFDs. This must be added explicitly via // `AddChildIfd()`. -func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, includeTagIds []uint16, excludeTagIds []uint16) (err error) { +func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResolver, includeTagIds []uint16, excludeTagIds []uint16) (err error) { defer func() { if state := recover(); state != nil { err = log.Wrap(state.(error)) @@ -498,22 +498,17 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, includeTagIds []uint16, excl // an IfdEnumerator and then be read and re-read (like an IEnumerable vs IList). -// TODO(dustin): !! Finish. - // itevr := NewIfdTagEntryValueResolver(rawExif []byte, ib.byteOrder) - // itevr.ValueBytes(ite *IfdTagEntry) (value []byte, err error) - - - for _, tag := range ifd.Entries { + for _, ite := range ifd.Entries { // If we want to add an IFD tag, we'll have to build it first and *then* // add it via a different method. - if tag.IfdName != "" { + if ite.ChildIfdName != "" { continue } if excludeTagIds != nil && len(excludeTagIds) > 0 { found := false for _, excludedTagId := range excludeTagIds { - if excludedTagId == tag.TagId { + if excludedTagId == ite.TagId { found = true } } @@ -529,7 +524,7 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, includeTagIds []uint16, excl found := false for _, includedTagId := range includeTagIds { - if includedTagId == tag.TagId { + if includedTagId == ite.TagId { found = true break } @@ -541,10 +536,14 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, includeTagIds []uint16, excl } bt := builderTag{ - tagId: tag.TagId, + tagId: ite.TagId, + } -// TODO(dustin): !! For right now, a IfdTagEntry instance will mean that the value will have to be inherited/copied from an existing offset. - value: tag, + if itevr != nil { + var err error + + bt.valueBytes, err = itevr.ValueBytes(&ite) + log.PanicIf(err) } err := ib.Add(bt) diff --git a/ifd_builder_test.go b/ifd_builder_test.go index 925e1d1..0ddeb0e 100644 --- a/ifd_builder_test.go +++ b/ifd_builder_test.go @@ -18,21 +18,21 @@ func TestAdd(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string2", + valueBytes: "test string2", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string3", + valueBytes: "test string3", } ib.Add(bt) @@ -41,7 +41,7 @@ func TestAdd(t *testing.T) { bt = builderTag{ tagId: 0x44, - value: originalShorts, + valueBytes: originalShorts, } ib.Add(bt) @@ -64,25 +64,25 @@ func TestAdd(t *testing.T) { if tags[0].tagId != 0x11 { t.Fatalf("tag (0) tag-ID not correct") - } else if tags[0].value != "test string" { + } else if tags[0].valueBytes != "test string" { t.Fatalf("tag (0) value not correct") } if tags[1].tagId != 0x22 { t.Fatalf("tag (1) tag-ID not correct") - } else if tags[1].value != "test string2" { + } else if tags[1].valueBytes != "test string2" { t.Fatalf("tag (1) value not correct") } if tags[2].tagId != 0x33 { t.Fatalf("tag (2) tag-ID not correct") - } else if tags[2].value != "test string3" { + } else if tags[2].valueBytes != "test string3" { t.Fatalf("tag (2) value not correct") } if tags[3].tagId != 0x44 { t.Fatalf("tag (3) tag-ID not correct") - } else if reflect.DeepEqual(tags[3].value.([]uint16), originalShorts) != true { + } else if reflect.DeepEqual(tags[3].valueBytes.([]uint16), originalShorts) != true { t.Fatalf("tag (3) value not correct") } } @@ -111,7 +111,7 @@ func TestAddChildIfd(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) @@ -122,7 +122,7 @@ func TestAddChildIfd(t *testing.T) { bt = builderTag{ tagId: 0x22, - value: "test string", + valueBytes: "test string", } ib.Add(bt) @@ -131,7 +131,7 @@ func TestAddChildIfd(t *testing.T) { t.Fatalf("first tag not correct") } else if ib.tags[1].tagId != ibChild.ifdTagId { t.Fatalf("second tag ID does not match child-IFD tag-ID") - } else if ib.tags[1].value != ibChild { + } else if ib.tags[1].valueBytes != ibChild { t.Fatalf("second tagvalue does not match child-IFD") } else if ib.tags[2].tagId != 0x22 { t.Fatalf("third tag not correct") @@ -149,7 +149,7 @@ func TestAddTagsFromExisting(t *testing.T) { entries[1] = IfdTagEntry{ TagId: 0x22, - IfdName: "some ifd", + ChildIfdName: "some ifd", } entries[2] = IfdTagEntry{ @@ -160,7 +160,7 @@ func TestAddTagsFromExisting(t *testing.T) { Entries: entries, } - err := ib.AddTagsFromExisting(ifd, nil, nil) + err := ib.AddTagsFromExisting(ifd, nil, nil, nil) log.PanicIf(err) if ib.tags[0].tagId != 0x11 { @@ -183,7 +183,7 @@ func TestAddTagsFromExisting__Includes(t *testing.T) { entries[1] = IfdTagEntry{ TagId: 0x22, - IfdName: "some ifd", + ChildIfdName: "some ifd", } entries[2] = IfdTagEntry{ @@ -194,7 +194,7 @@ func TestAddTagsFromExisting__Includes(t *testing.T) { Entries: entries, } - err := ib.AddTagsFromExisting(ifd, []uint16 { 0x33 }, nil) + err := ib.AddTagsFromExisting(ifd, nil, []uint16 { 0x33 }, nil) log.PanicIf(err) if ib.tags[0].tagId != 0x33 { @@ -215,7 +215,7 @@ func TestAddTagsFromExisting__Excludes(t *testing.T) { entries[1] = IfdTagEntry{ TagId: 0x22, - IfdName: "some ifd", + ChildIfdName: "some ifd", } entries[2] = IfdTagEntry{ @@ -226,7 +226,7 @@ func TestAddTagsFromExisting__Excludes(t *testing.T) { Entries: entries, } - err := ib.AddTagsFromExisting(ifd, nil, []uint16 { 0x11 }) + err := ib.AddTagsFromExisting(ifd, nil, nil, []uint16 { 0x11 }) log.PanicIf(err) if ib.tags[0].tagId != 0x33 { @@ -241,21 +241,21 @@ func TestFindN_First_1(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string2", + valueBytes: "test string2", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string3", + valueBytes: "test string3", } ib.Add(bt) @@ -282,21 +282,21 @@ func TestFindN_First_2_1Returned(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string2", + valueBytes: "test string2", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string3", + valueBytes: "test string3", } ib.Add(bt) @@ -323,35 +323,35 @@ func TestFindN_First_2_2Returned(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string2", + valueBytes: "test string2", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string3", + valueBytes: "test string3", } ib.Add(bt) bt = builderTag{ tagId: 0x11, - value: "test string4", + valueBytes: "test string4", } ib.Add(bt) bt = builderTag{ tagId: 0x11, - value: "test string5", + valueBytes: "test string5", } ib.Add(bt) @@ -370,13 +370,13 @@ func TestFindN_First_2_2Returned(t *testing.T) { tags := ib.Tags() bt = tags[found[0]] - if bt.tagId != 0x11 || bt.value != "test string" { - log.Panicf("Found entry 0 is not correct: (0x%02x) [%s]", bt.tagId, bt.value) + if bt.tagId != 0x11 || bt.valueBytes != "test string" { + log.Panicf("Found entry 0 is not correct: (0x%02x) [%s]", bt.tagId, bt.valueBytes) } bt = tags[found[1]] - if bt.tagId != 0x11 || bt.value != "test string4" { - log.Panicf("Found entry 1 is not correct: (0x%02x) [%s]", bt.tagId, bt.value) + if bt.tagId != 0x11 || bt.valueBytes != "test string4" { + log.Panicf("Found entry 1 is not correct: (0x%02x) [%s]", bt.tagId, bt.valueBytes) } } @@ -385,42 +385,42 @@ func TestFindN_Middle_WithDuplicates(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string2", + valueBytes: "test string2", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string3", + valueBytes: "test string3", } ib.Add(bt) bt = builderTag{ tagId: 0x11, - value: "test string4", + valueBytes: "test string4", } ib.Add(bt) bt = builderTag{ tagId: 0x11, - value: "test string5", + valueBytes: "test string5", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string6", + valueBytes: "test string6", } ib.Add(bt) @@ -447,28 +447,28 @@ func TestFindN_Middle_NoDuplicates(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string2", + valueBytes: "test string2", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string3", + valueBytes: "test string3", } ib.Add(bt) bt = builderTag{ tagId: 0x11, - value: "test string4", + valueBytes: "test string4", } ib.Add(bt) @@ -506,28 +506,28 @@ func TestFind_Hit(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string2", + valueBytes: "test string2", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string3", + valueBytes: "test string3", } ib.Add(bt) bt = builderTag{ tagId: 0x11, - value: "test string4", + valueBytes: "test string4", } ib.Add(bt) @@ -552,28 +552,28 @@ func TestFind_Miss(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string2", + valueBytes: "test string2", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string3", + valueBytes: "test string3", } ib.Add(bt) bt = builderTag{ tagId: 0x11, - value: "test string4", + valueBytes: "test string4", } ib.Add(bt) @@ -591,21 +591,21 @@ func TestReplace(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string2", + valueBytes: "test string2", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string3", + valueBytes: "test string3", } ib.Add(bt) @@ -621,7 +621,7 @@ func TestReplace(t *testing.T) { bt = builderTag{ tagId: 0x99, - value: "test string4", + valueBytes: "test string4", } err := ib.Replace(0x22, bt) @@ -642,21 +642,21 @@ func TestReplaceN(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string2", + valueBytes: "test string2", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string3", + valueBytes: "test string3", } ib.Add(bt) @@ -672,7 +672,7 @@ func TestReplaceN(t *testing.T) { bt = builderTag{ tagId: 0xA9, - value: "test string4", + valueBytes: "test string4", } err := ib.ReplaceAt(1, bt) @@ -693,28 +693,28 @@ func TestDeleteFirst(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string2", + valueBytes: "test string2", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string3", + valueBytes: "test string3", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string4", + valueBytes: "test string4", } ib.Add(bt) @@ -781,28 +781,28 @@ func TestDeleteN(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string2", + valueBytes: "test string2", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string3", + valueBytes: "test string3", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string4", + valueBytes: "test string4", } ib.Add(bt) @@ -869,28 +869,28 @@ func TestDeleteN_Two(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string2", + valueBytes: "test string2", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string3", + valueBytes: "test string3", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string4", + valueBytes: "test string4", } ib.Add(bt) @@ -940,28 +940,28 @@ func TestDeleteAll(t *testing.T) { bt := builderTag{ tagId: 0x11, - value: "test string", + valueBytes: "test string", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string2", + valueBytes: "test string2", } ib.Add(bt) bt = builderTag{ tagId: 0x22, - value: "test string3", + valueBytes: "test string3", } ib.Add(bt) bt = builderTag{ tagId: 0x33, - value: "test string4", + valueBytes: "test string4", } ib.Add(bt) diff --git a/ifd_enumerate.go b/ifd_enumerate.go index e7a2bc3..a9397f5 100644 --- a/ifd_enumerate.go +++ b/ifd_enumerate.go @@ -137,9 +137,18 @@ type IfdTagEntry struct { UnitCount uint32 ValueOffset uint32 RawValueOffset []byte + + // ChildIfdName is a name if this tag represents a child IFD. + ChildIfdName string + + // IfdName is the IFD that this tag belongs to. IfdName string } +func (ite IfdTagEntry) String() string { + return fmt.Sprintf("IfdTagEntry", ite.ChildIfdName, ite.TagId, TypeNames[ite.TagType], ite.UnitCount) +} + func (ite IfdTagEntry) ValueBytes(addressableData []byte, byteOrder binary.ByteOrder) (value []byte, err error) { defer func() { if state := recover(); state != nil { @@ -147,6 +156,28 @@ func (ite IfdTagEntry) ValueBytes(addressableData []byte, byteOrder binary.ByteO } }() + if ite.TagType == TypeUndefined { + valueContext := ValueContext{ + UnitCount: ite.UnitCount, + ValueOffset: ite.ValueOffset, + RawValueOffset: ite.RawValueOffset, + AddressableData: addressableData, + } + + value, err := UndefinedValue(ite.IfdName, ite.TagId, valueContext, byteOrder) + log.PanicIf(err) + + switch value.(type) { + case []byte: + return value.([]byte), nil + case string: + return []byte(value.(string)), nil + default: +// TODO(dustin): !! Finish translating the rest of the types (make reusable and replace into other similar implementations?) + log.Panicf("can not produce bytes for unknown-type tag (0x%02x)", ite.TagId) + } + } + originalType := NewTagType(ite.TagType, byteOrder) byteCount := uint32(originalType.Size()) * ite.UnitCount @@ -260,6 +291,7 @@ func (ie *IfdEnumerate) ParseIfd(ifdName string, ifdIndex int, ifdOffset uint32, } tag := IfdTagEntry{ + IfdName: ifdName, TagId: tagId, TagIndex: int(i), TagType: tagType, @@ -270,7 +302,7 @@ func (ie *IfdEnumerate) ParseIfd(ifdName string, ifdIndex int, ifdOffset uint32, childIfdName, isIfd := IsIfdTag(tagId) if isIfd == true { - tag.IfdName = childIfdName + tag.ChildIfdName = childIfdName if doDescend == true { ifdEnumerateLogger.Debugf(nil, "Descending to IFD [%s].", childIfdName) @@ -320,7 +352,10 @@ type Ifd struct { Name string Index int Offset uint32 + +// TODO(dustin): !! Add a find method. Entries []IfdTagEntry + Children []*Ifd NextIfdOffset uint32 NextIfd *Ifd @@ -455,12 +490,12 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32) (index IfdIndex, err error // Determine if any of our entries is a child IFD and queue it. for _, entry := range entries { - if entry.IfdName == "" { + if entry.ChildIfdName == "" { continue } qi := QueuedIfd { - Name: entry.IfdName, + Name: entry.ChildIfdName, Index: 0, Offset: entry.ValueOffset, Parent: &ifd, diff --git a/ifd_enumerate_test.go b/ifd_enumerate_test.go new file mode 100644 index 0000000..8f8ee9a --- /dev/null +++ b/ifd_enumerate_test.go @@ -0,0 +1,173 @@ +package exif + +import ( + "path" + "testing" + "bytes" + + "encoding/binary" + + "github.com/dsoprea/go-logging" +) + +func TestIfdTagEntry_ValueBytes(t *testing.T) { + byteOrder := binary.BigEndian + ve := NewValueEncoder(byteOrder) + + original := []byte("original text") + + ed, err := ve.encodeBytes(original) + log.PanicIf(err) + + // Now, pass the raw encoded value as if it was the entire addressable area + // and provide an offset of 0 as if it was a real block of data and this + // value happened to be recorded at the beginning. + + ite := IfdTagEntry{ + TagType: TypeByte, + UnitCount: uint32(len(original)), + ValueOffset: 0, + } + + decodedBytes, err := ite.ValueBytes(ed.Encoded, byteOrder) + log.PanicIf(err) + + if bytes.Compare(decodedBytes, original) != 0 { + t.Fatalf("Bytes not decoded correctly.") + } +} + +func TestIfdTagEntry_ValueBytes_RealData(t *testing.T) { + defer func() { + if state := recover(); state != nil { + err := log.Wrap(state.(error)) + log.PrintErrorf(err, "Test failure.") + } + }() + + e := NewExif() + + filepath := path.Join(assetsPath, "NDM_8901.jpg") + + rawExif, err := e.SearchAndExtractExif(filepath) + log.PanicIf(err) + + eh, index, err := e.Collect(rawExif) + log.PanicIf(err) + + var ite *IfdTagEntry + for _, thisIte := range index.RootIfd.Entries { + if thisIte.TagId == 0x0110 { + ite = &thisIte + break + } + } + + if ite == nil { + t.Fatalf("Tag not found.") + } + + addressableData := rawExif[ExifAddressableAreaStart:] + decodedBytes, err := ite.ValueBytes(addressableData, eh.ByteOrder) + log.PanicIf(err) + + expected := []byte("Canon EOS 5D Mark III") + expected = append(expected, 0) + + if len(decodedBytes) != int(ite.UnitCount) { + t.Fatalf("Decoded bytes not the right count.") + } else if bytes.Compare(decodedBytes, expected) != 0 { + t.Fatalf("Decoded bytes not correct.") + } +} + +func TestIfdTagEntry_Resolver_ValueBytes(t *testing.T) { + defer func() { + if state := recover(); state != nil { + err := log.Wrap(state.(error)) + log.PrintErrorf(err, "Test failure.") + } + }() + + e := NewExif() + + filepath := path.Join(assetsPath, "NDM_8901.jpg") + + rawExif, err := e.SearchAndExtractExif(filepath) + log.PanicIf(err) + + eh, index, err := e.Collect(rawExif) + log.PanicIf(err) + + var ite *IfdTagEntry + for _, thisIte := range index.RootIfd.Entries { + if thisIte.TagId == 0x0110 { + ite = &thisIte + break + } + } + + if ite == nil { + t.Fatalf("Tag not found.") + } + + itevr := NewIfdTagEntryValueResolver(rawExif, eh.ByteOrder) + + decodedBytes, err := itevr.ValueBytes(ite) + log.PanicIf(err) + + expected := []byte("Canon EOS 5D Mark III") + expected = append(expected, 0) + + if len(decodedBytes) != int(ite.UnitCount) { + t.Fatalf("Decoded bytes not the right count.") + } else if bytes.Compare(decodedBytes, expected) != 0 { + t.Fatalf("Decoded bytes not correct.") + } +} + +func TestIfdTagEntry_Resolver_ValueBytes__Unknown_Field_And_Nonroot_Ifd(t *testing.T) { + defer func() { + if state := recover(); state != nil { + err := log.Wrap(state.(error)) + log.PrintErrorf(err, "Test failure.") + } + }() + + e := NewExif() + + filepath := path.Join(assetsPath, "NDM_8901.jpg") + + rawExif, err := e.SearchAndExtractExif(filepath) + log.PanicIf(err) + + eh, index, err := e.Collect(rawExif) + log.PanicIf(err) + + ifdExif := index.Lookup[IfdExif][0] + + var ite *IfdTagEntry + for _, thisIte := range ifdExif.Entries { + if thisIte.TagId == 0x9000 { + ite = &thisIte + break + } + } + + if ite == nil { + t.Fatalf("Tag not found.") + } + + itevr := NewIfdTagEntryValueResolver(rawExif, eh.ByteOrder) + + decodedBytes, err := itevr.ValueBytes(ite) + log.PanicIf(err) + + expected := []byte { '0', '2', '3', '0' } + + if len(decodedBytes) != int(ite.UnitCount) { + t.Fatalf("Decoded bytes not the right count.") + } else if bytes.Compare(decodedBytes, expected) != 0 { + t.Fatalf("Recovered unknown value is not correct.") + } +} diff --git a/type_decode.go b/type_decode.go index 0208f9d..b0fe7bd 100644 --- a/type_decode.go +++ b/type_decode.go @@ -601,6 +601,8 @@ func UndefinedValue(indexedIfdName string, tagId uint16, valueContext ValueConte } }() + typeDecodeLogger.Debugf(nil, "UndefinedValue: IFD=[%s] TAG-ID=(0x%02x)", indexedIfdName, tagId) + if indexedIfdName == IfdName(IfdExif, 0) { if tagId == 0x9000 { // ExifVersion