ifd_enumerate: Added tests.

- Refactored (IfdTagEntry).ValueBytes() to handle managed undefined
  values.
pull/3/head
Dustin Oprea 2018-04-22 02:35:33 -04:00
parent f1f23dca82
commit 50eafa98d6
7 changed files with 313 additions and 104 deletions

12
exif.go
View File

@ -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
}

View File

@ -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 {

View File

@ -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<TAG-ID=(0x%02x) IFD=[%s] VALUE=[%v]>", bt.tagId, bt.ifdName, bt.value)
return fmt.Sprintf("BuilderTag<TAG-ID=(0x%02x) IFD=[%s] VALUE=[%v]>", 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)

View File

@ -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)

View File

@ -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<TAG-IFD=[%s] TAG-ID=(0x%02x) TAG-TYPE=[%s] UNIT-COUNT=(%d)>", 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,

173
ifd_enumerate_test.go Normal file
View File

@ -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.")
}
}

View File

@ -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