mirror of https://github.com/dsoprea/go-exif.git
ifd_builder.go: No longer use ITEVRs
This was an early way of resolving tag values that is now obsolete. `ValueContext` structs should be used, and these, in many cases, should be able to be constructed from the current context without passing additional arguments. - ifd_builder_test.go: Refactors to several tests due to loss of ITEVR support. - ifd_builder_encode_test.go: Moved test-IB populate to testing_common.go . - ifd_builder.go: Fixed test naming (in most cases, omitted type name).pull/28/head
parent
9946007f05
commit
88612c1cf8
143
ifd_builder.go
143
ifd_builder.go
|
@ -222,8 +222,8 @@ type IfdBuilder struct {
|
|||
byteOrder binary.ByteOrder
|
||||
|
||||
// Includes both normal tags and IFD tags (which point to child IFDs).
|
||||
// TODO(dustin): Keep a separate list of children like with IFd.
|
||||
// TODO(dustin): Either rename this or `Entries` in Ifd to be the same thing.
|
||||
// TODO(dustin): Keep a separate list of children like with `Ifd`.
|
||||
// TODO(dustin): Either rename this or `Entries` in `Ifd` to be the same thing.
|
||||
tags []*BuilderTag
|
||||
|
||||
// existingOffset will be the offset that this IFD is currently found at if
|
||||
|
@ -312,7 +312,7 @@ func NewIfdBuilderWithExistingIfd(ifd *Ifd) (ib *IfdBuilder) {
|
|||
// NewIfdBuilderFromExistingChain creates a chain of IB instances from an
|
||||
// IFD chain generated from real data.
|
||||
func NewIfdBuilderFromExistingChain(rootIfd *Ifd, itevr *IfdTagEntryValueResolver) (firstIb *IfdBuilder) {
|
||||
// TODO(dustin): !! When we actually write the code to flatten the IB to bytes, make sure to skip the tags that have a nil value (which will happen when we add-from-exsting without a resolver instance).
|
||||
// OBSOLETE(dustin): Support for `itevr` is now obsolete. This parameter will be removed in the future.
|
||||
|
||||
var lastIb *IfdBuilder
|
||||
i := 0
|
||||
|
@ -324,7 +324,7 @@ func NewIfdBuilderFromExistingChain(rootIfd *Ifd, itevr *IfdTagEntryValueResolve
|
|||
lastIb.SetNextIb(newIb)
|
||||
}
|
||||
|
||||
err := newIb.AddTagsFromExisting(thisExistingIfd, itevr, nil, nil)
|
||||
err := newIb.AddTagsFromExisting(thisExistingIfd, nil, nil, nil)
|
||||
log.PanicIf(err)
|
||||
|
||||
lastIb = newIb
|
||||
|
@ -1028,6 +1028,8 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResol
|
|||
}
|
||||
}()
|
||||
|
||||
// OBSOLETE(dustin): Support for `itevr` is now obsolete. This parameter will be removed in the future.
|
||||
|
||||
thumbnailData, err := ifd.Thumbnail()
|
||||
if err == nil {
|
||||
err = ib.SetThumbnail(thumbnailData)
|
||||
|
@ -1078,105 +1080,76 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResol
|
|||
// If we want to add an IFD tag, we'll have to build it first and
|
||||
// *then* add it via a different method.
|
||||
|
||||
if itevr == nil {
|
||||
// We don't have any ability to resolve the structure of the
|
||||
// child-IFD. Just install it as a normal tag rather than a
|
||||
// fully-structured child-IFD. We're going to blank the value,
|
||||
// though, since its original offset will no longer be valid
|
||||
// (nor does it matter since this is just a temporary
|
||||
// placeholder, in this situation).
|
||||
value := NewIfdBuilderTagValueFromBytes([]byte{0, 0, 0, 0})
|
||||
bt = NewBuilderTag(
|
||||
ite.IfdPath,
|
||||
ite.TagId,
|
||||
ite.TagType,
|
||||
value,
|
||||
ib.byteOrder)
|
||||
} else {
|
||||
// Figure out which of the child-IFDs that are associated with
|
||||
// this IFD represents this specific child IFD.
|
||||
// Figure out which of the child-IFDs that are associated with
|
||||
// this IFD represents this specific child IFD.
|
||||
|
||||
var childIfd *Ifd
|
||||
for _, thisChildIfd := range ifd.Children {
|
||||
if thisChildIfd.ParentTagIndex != i {
|
||||
continue
|
||||
} else if thisChildIfd.TagId != 0xffff && thisChildIfd.TagId != ite.TagId {
|
||||
log.Panicf("child-IFD tag is not correct: TAG-POSITION=(%d) ITE=%s CHILD-IFD=%s", thisChildIfd.ParentTagIndex, ite, thisChildIfd)
|
||||
}
|
||||
|
||||
childIfd = thisChildIfd
|
||||
break
|
||||
var childIfd *Ifd
|
||||
for _, thisChildIfd := range ifd.Children {
|
||||
if thisChildIfd.ParentTagIndex != i {
|
||||
continue
|
||||
} else if thisChildIfd.TagId != 0xffff && thisChildIfd.TagId != ite.TagId {
|
||||
log.Panicf("child-IFD tag is not correct: TAG-POSITION=(%d) ITE=%s CHILD-IFD=%s", thisChildIfd.ParentTagIndex, ite, thisChildIfd)
|
||||
}
|
||||
|
||||
if childIfd == nil {
|
||||
childTagIds := make([]string, len(ifd.Children))
|
||||
for j, childIfd := range ifd.Children {
|
||||
childTagIds[j] = fmt.Sprintf("0x%04x (parent tag-position %d)", childIfd.TagId, childIfd.ParentTagIndex)
|
||||
}
|
||||
|
||||
log.Panicf("could not find child IFD for child ITE: IFD-PATH=[%s] TAG-ID=(0x%04x) CURRENT-TAG-POSITION=(%d) CHILDREN=%v", ite.IfdPath, ite.TagId, i, childTagIds)
|
||||
}
|
||||
|
||||
childIb := NewIfdBuilderFromExistingChain(childIfd, itevr)
|
||||
bt = ib.NewBuilderTagFromBuilder(childIb)
|
||||
childIfd = thisChildIfd
|
||||
break
|
||||
}
|
||||
|
||||
if childIfd == nil {
|
||||
childTagIds := make([]string, len(ifd.Children))
|
||||
for j, childIfd := range ifd.Children {
|
||||
childTagIds[j] = fmt.Sprintf("0x%04x (parent tag-position %d)", childIfd.TagId, childIfd.ParentTagIndex)
|
||||
}
|
||||
|
||||
log.Panicf("could not find child IFD for child ITE: IFD-PATH=[%s] TAG-ID=(0x%04x) CURRENT-TAG-POSITION=(%d) CHILDREN=%v", ite.IfdPath, ite.TagId, i, childTagIds)
|
||||
}
|
||||
|
||||
childIb := NewIfdBuilderFromExistingChain(childIfd, nil)
|
||||
bt = ib.NewBuilderTagFromBuilder(childIb)
|
||||
} else {
|
||||
// Non-IFD tag.
|
||||
|
||||
var value *IfdBuilderTagValue
|
||||
|
||||
// TODO(dustin): !! We should be able to dump (i.e. deimplement) the concept of itevr's and exclusively use ValueContext, now.
|
||||
valueContext := newValueContextFromTag(
|
||||
ite,
|
||||
ifd.addressableData,
|
||||
ifd.ByteOrder)
|
||||
|
||||
if itevr == nil {
|
||||
// TODO(dustin): !! This might not make sense. The undefined-type data will just likely now have invalid value.
|
||||
var rawBytes []byte
|
||||
|
||||
// rawValueOffsetCopy is our own private copy of the original data.
|
||||
// It should always be four-bytes, but just copy whatever there is.
|
||||
rawValueOffsetCopy := make([]byte, len(ite.RawValueOffset))
|
||||
copy(rawValueOffsetCopy, ite.RawValueOffset)
|
||||
if ite.TagType == TypeUndefined {
|
||||
// It's an undefined-type value. Try to process, or skip if
|
||||
// we don't know how to.
|
||||
|
||||
value = NewIfdBuilderTagValueFromBytes(rawValueOffsetCopy)
|
||||
} else {
|
||||
valueContext := newValueContextFromTag(
|
||||
ite,
|
||||
ifd.addressableData,
|
||||
ifd.ByteOrder)
|
||||
x, err := valueContext.Undefined()
|
||||
log.PanicIf(err)
|
||||
|
||||
var rawBytes []byte
|
||||
// TODO(dustin): !! Add test for this.
|
||||
_, isUnknownUndefined := x.(TagUnknownType_UnknownValue)
|
||||
|
||||
if ite.TagType == TypeUndefined {
|
||||
// It's an undefined-type value. Try to process, or skip if
|
||||
// we don't know how to.
|
||||
|
||||
x, err := valueContext.Undefined()
|
||||
log.PanicIf(err)
|
||||
|
||||
// TODO(dustin): !! Add test for this.
|
||||
_, isUnknownUndefined := x.(TagUnknownType_UnknownValue)
|
||||
|
||||
if isUnknownUndefined == true {
|
||||
continue
|
||||
}
|
||||
|
||||
undefined, ok := x.(UnknownTagValue)
|
||||
if ok != true {
|
||||
log.Panicf("unexpected value returned from undefined-value processor")
|
||||
}
|
||||
|
||||
rawBytes, err = undefined.ValueBytes()
|
||||
log.PanicIf(err)
|
||||
} else {
|
||||
// It's a value with a standard type.
|
||||
|
||||
var err error
|
||||
|
||||
rawBytes, err = valueContext.readRawEncoded()
|
||||
log.PanicIf(err)
|
||||
if isUnknownUndefined == true {
|
||||
continue
|
||||
}
|
||||
|
||||
value = NewIfdBuilderTagValueFromBytes(rawBytes)
|
||||
undefined, ok := x.(UnknownTagValue)
|
||||
if ok != true {
|
||||
log.Panicf("unexpected value returned from undefined-value processor")
|
||||
}
|
||||
|
||||
rawBytes, err = undefined.ValueBytes()
|
||||
log.PanicIf(err)
|
||||
} else {
|
||||
// It's a value with a standard type.
|
||||
|
||||
var err error
|
||||
|
||||
rawBytes, err = valueContext.readRawEncoded()
|
||||
log.PanicIf(err)
|
||||
}
|
||||
|
||||
value = NewIfdBuilderTagValueFromBytes(rawBytes)
|
||||
|
||||
bt = NewBuilderTag(
|
||||
ifd.IfdPath,
|
||||
ite.TagId,
|
||||
|
|
|
@ -3,7 +3,6 @@ package exif
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
@ -562,97 +561,6 @@ func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func getExifSimpleTestIb() *IfdBuilder {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
log.PanicIf(err)
|
||||
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
||||
|
||||
err = ib.AddStandard(0x000b, "asciivalue")
|
||||
log.PanicIf(err)
|
||||
|
||||
err = ib.AddStandard(0x00ff, []uint16{0x1122})
|
||||
log.PanicIf(err)
|
||||
|
||||
err = ib.AddStandard(0x0100, []uint32{0x33445566})
|
||||
log.PanicIf(err)
|
||||
|
||||
err = ib.AddStandard(0x013e, []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}})
|
||||
log.PanicIf(err)
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func validateExifSimpleTestIb(exifData []byte, t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
log.PanicIf(err)
|
||||
|
||||
ti := NewTagIndex()
|
||||
|
||||
eh, index, err := Collect(im, ti, exifData)
|
||||
log.PanicIf(err)
|
||||
|
||||
if eh.ByteOrder != TestDefaultByteOrder {
|
||||
t.Fatalf("EXIF byte-order is not correct: %v", eh.ByteOrder)
|
||||
} else if eh.FirstIfdOffset != ExifDefaultFirstIfdOffset {
|
||||
t.Fatalf("EXIF first IFD-offset not correct: (0x%02x)", eh.FirstIfdOffset)
|
||||
}
|
||||
|
||||
if len(index.Ifds) != 1 {
|
||||
t.Fatalf("There wasn't exactly one IFD decoded: (%d)", len(index.Ifds))
|
||||
}
|
||||
|
||||
ifd := index.RootIfd
|
||||
|
||||
if ifd.ByteOrder != TestDefaultByteOrder {
|
||||
t.Fatalf("IFD byte-order not correct.")
|
||||
} else if ifd.IfdPath != IfdStandard {
|
||||
t.Fatalf("IFD name not correct.")
|
||||
} else if ifd.Index != 0 {
|
||||
t.Fatalf("IFD index not zero: (%d)", ifd.Index)
|
||||
} else if ifd.Offset != uint32(0x0008) {
|
||||
t.Fatalf("IFD offset not correct.")
|
||||
} else if len(ifd.Entries) != 4 {
|
||||
t.Fatalf("IFD number of entries not correct: (%d)", len(ifd.Entries))
|
||||
} else if ifd.NextIfdOffset != uint32(0) {
|
||||
t.Fatalf("Next-IFD offset is non-zero.")
|
||||
} else if ifd.NextIfd != nil {
|
||||
t.Fatalf("Next-IFD pointer is non-nil.")
|
||||
}
|
||||
|
||||
// Verify the values by using the actual, orginal types (this is awesome).
|
||||
|
||||
addressableData := exifData[ExifAddressableAreaStart:]
|
||||
|
||||
expected := []struct {
|
||||
tagId uint16
|
||||
value interface{}
|
||||
}{
|
||||
{tagId: 0x000b, value: "asciivalue"},
|
||||
{tagId: 0x00ff, value: []uint16{0x1122}},
|
||||
{tagId: 0x0100, value: []uint32{0x33445566}},
|
||||
{tagId: 0x013e, value: []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}},
|
||||
}
|
||||
|
||||
for i, e := range ifd.Entries {
|
||||
if e.TagId != expected[i].tagId {
|
||||
t.Fatalf("Tag-ID for entry (%d) not correct: (0x%02x) != (0x%02x)", i, e.TagId, expected[i].tagId)
|
||||
}
|
||||
|
||||
value, err := e.Value(addressableData, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, expected[i].value) != true {
|
||||
t.Fatalf("Value for entry (%d) not correct: [%v] != [%v]", i, value, expected[i].value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_IfdByteEncoder_encodeIfdToBytes_simple(t *testing.T) {
|
||||
ib := getExifSimpleTestIb()
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
func TestIfdBuilder_Add(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -103,7 +103,7 @@ func TestAdd(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSetNextIb(t *testing.T) {
|
||||
func TestIfdBuilder_SetNextIb(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -128,7 +128,7 @@ func TestSetNextIb(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAddChildIb(t *testing.T) {
|
||||
func TestIfdBuilder_AddChildIb(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -172,160 +172,120 @@ func TestAddChildIb(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAddTagsFromExisting(t *testing.T) {
|
||||
func TestIfdBuilder_AddTagsFromExisting(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Test failure.")
|
||||
log.PrintError(err)
|
||||
|
||||
t.Fatalf("Test failure.")
|
||||
}
|
||||
}()
|
||||
|
||||
exifData := getExifSimpleTestIbBytes()
|
||||
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
log.PanicIf(err)
|
||||
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
||||
|
||||
entries := make([]*IfdTagEntry, 3)
|
||||
|
||||
entries[0] = &IfdTagEntry{
|
||||
IfdPath: IfdPathStandardExif,
|
||||
TagId: 0x11,
|
||||
TagType: TypeByte,
|
||||
UnitCount: 4,
|
||||
RawValueOffset: []byte{0x12, 0, 0, 0},
|
||||
}
|
||||
|
||||
entries[1] = &IfdTagEntry{
|
||||
IfdPath: IfdPathStandardExif,
|
||||
TagId: 0x22,
|
||||
TagType: TypeLong,
|
||||
ChildIfdPath: "some ifd",
|
||||
}
|
||||
|
||||
entries[2] = &IfdTagEntry{
|
||||
IfdPath: IfdPathStandardExif,
|
||||
TagId: 0x33,
|
||||
TagType: TypeByte,
|
||||
UnitCount: 4,
|
||||
RawValueOffset: []byte{0x34, 0, 0, 0},
|
||||
}
|
||||
|
||||
ifd := &Ifd{
|
||||
IfdPath: IfdPathStandard,
|
||||
Entries: entries,
|
||||
tagIndex: ti,
|
||||
}
|
||||
|
||||
err = ib.AddTagsFromExisting(ifd, nil, nil, nil)
|
||||
_, index, err := Collect(im, ti, exifData)
|
||||
log.PanicIf(err)
|
||||
|
||||
if ib.tags[0].tagId != 0x11 {
|
||||
t.Fatalf("tag (0) not correct")
|
||||
} else if ib.tags[1].tagId != 0x22 {
|
||||
t.Fatalf("tag (1) not correct")
|
||||
} else if ib.tags[2].tagId != 0x33 {
|
||||
t.Fatalf("tag (2) not correct")
|
||||
} else if len(ib.tags) != 3 {
|
||||
t.Fatalf("tag count not correct")
|
||||
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
||||
|
||||
err = ib.AddTagsFromExisting(index.RootIfd, nil, nil, nil)
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := []uint16{
|
||||
0x000b,
|
||||
0x00ff,
|
||||
0x0100,
|
||||
0x013e,
|
||||
}
|
||||
|
||||
if len(ib.tags) != len(expected) {
|
||||
t.Fatalf("Tag count not correct: (%d) != (%d)", len(ib.tags), len(expected))
|
||||
}
|
||||
|
||||
for i, tag := range ib.tags {
|
||||
if tag.tagId != expected[i] {
|
||||
t.Fatalf("Tag (%d) not correct: (0x%04x) != (0x%04x)", i, tag.tagId, expected[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddTagsFromExisting__Includes(t *testing.T) {
|
||||
func TestIfdBuilder_AddTagsFromExisting__Includes(t *testing.T) {
|
||||
exifData := getExifSimpleTestIbBytes()
|
||||
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
log.PanicIf(err)
|
||||
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
||||
|
||||
entries := make([]*IfdTagEntry, 3)
|
||||
|
||||
entries[0] = &IfdTagEntry{
|
||||
IfdPath: IfdPathStandard,
|
||||
TagType: TypeByte,
|
||||
TagId: 0x11,
|
||||
}
|
||||
|
||||
entries[1] = &IfdTagEntry{
|
||||
IfdPath: IfdPathStandard,
|
||||
TagType: TypeByte,
|
||||
TagId: 0x22,
|
||||
ChildIfdPath: "some ifd",
|
||||
}
|
||||
|
||||
entries[2] = &IfdTagEntry{
|
||||
IfdPath: IfdPathStandard,
|
||||
TagType: TypeByte,
|
||||
TagId: 0x33,
|
||||
}
|
||||
|
||||
ifd := &Ifd{
|
||||
IfdPath: IfdPathStandard,
|
||||
Entries: entries,
|
||||
tagIndex: ti,
|
||||
}
|
||||
|
||||
err = ib.AddTagsFromExisting(ifd, nil, []uint16{0x33}, nil)
|
||||
_, index, err := Collect(im, ti, exifData)
|
||||
log.PanicIf(err)
|
||||
|
||||
if ib.tags[0].tagId != 0x33 {
|
||||
t.Fatalf("tag (1) not correct")
|
||||
} else if len(ib.tags) != 1 {
|
||||
t.Fatalf("tag count not correct")
|
||||
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
||||
|
||||
err = ib.AddTagsFromExisting(index.RootIfd, nil, []uint16{0x00ff}, nil)
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := []uint16{
|
||||
0x00ff,
|
||||
}
|
||||
|
||||
if len(ib.tags) != len(expected) {
|
||||
t.Fatalf("Tag count not correct: (%d) != (%d)", len(ib.tags), len(expected))
|
||||
}
|
||||
|
||||
for i, tag := range ib.tags {
|
||||
if tag.tagId != expected[i] {
|
||||
t.Fatalf("Tag (%d) not correct: (0x%04x) != (0x%04x)", i, tag.tagId, expected[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddTagsFromExisting__Excludes(t *testing.T) {
|
||||
func TestIfdBuilder_AddTagsFromExisting__Excludes(t *testing.T) {
|
||||
exifData := getExifSimpleTestIbBytes()
|
||||
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
log.PanicIf(err)
|
||||
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
||||
|
||||
entries := make([]*IfdTagEntry, 3)
|
||||
|
||||
entries[0] = &IfdTagEntry{
|
||||
IfdPath: IfdPathStandard,
|
||||
TagType: TypeByte,
|
||||
TagId: 0x11,
|
||||
}
|
||||
|
||||
entries[1] = &IfdTagEntry{
|
||||
IfdPath: IfdPathStandard,
|
||||
TagType: TypeByte,
|
||||
TagId: 0x22,
|
||||
ChildIfdPath: "some ifd",
|
||||
}
|
||||
|
||||
entries[2] = &IfdTagEntry{
|
||||
IfdPath: IfdPathStandard,
|
||||
TagType: TypeByte,
|
||||
TagId: 0x33,
|
||||
}
|
||||
|
||||
ifd := &Ifd{
|
||||
IfdPath: IfdPathStandard,
|
||||
Entries: entries,
|
||||
tagIndex: ti,
|
||||
}
|
||||
|
||||
err = ib.AddTagsFromExisting(ifd, nil, nil, []uint16{0x11})
|
||||
_, index, err := Collect(im, ti, exifData)
|
||||
log.PanicIf(err)
|
||||
|
||||
if ib.tags[0].tagId != 0x22 {
|
||||
t.Fatalf("tag not correct")
|
||||
} else if len(ib.tags) != 2 {
|
||||
t.Fatalf("tag count not correct")
|
||||
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
||||
|
||||
err = ib.AddTagsFromExisting(index.RootIfd, nil, nil, []uint16{0xff})
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := []uint16{
|
||||
0x000b,
|
||||
0x0100,
|
||||
0x013e,
|
||||
}
|
||||
|
||||
if len(ib.tags) != len(expected) {
|
||||
t.Fatalf("Tag count not correct: (%d) != (%d)", len(ib.tags), len(expected))
|
||||
}
|
||||
|
||||
for i, tag := range ib.tags {
|
||||
if tag.tagId != expected[i] {
|
||||
t.Fatalf("Tag (%d) not correct: (0x%04x) != (0x%04x)", i, tag.tagId, expected[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindN_First_1(t *testing.T) {
|
||||
func TestIfdBuilder_FindN__First_1(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -381,7 +341,7 @@ func TestFindN_First_1(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestFindN_First_2_1Returned(t *testing.T) {
|
||||
func TestIfdBuilder_FindN__First_2_1Returned(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -437,7 +397,7 @@ func TestFindN_First_2_1Returned(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestFindN_First_2_2Returned(t *testing.T) {
|
||||
func TestIfdBuilder_FindN__First_2_2Returned(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -520,7 +480,7 @@ func TestFindN_First_2_2Returned(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestFindN_Middle_WithDuplicates(t *testing.T) {
|
||||
func TestIfdBuilder_FindN__Middle_WithDuplicates(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -606,7 +566,7 @@ func TestFindN_Middle_WithDuplicates(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestFindN_Middle_NoDuplicates(t *testing.T) {
|
||||
func TestIfdBuilder_FindN__Middle_NoDuplicates(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -672,7 +632,7 @@ func TestFindN_Middle_NoDuplicates(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestFindN_Miss(t *testing.T) {
|
||||
func TestIfdBuilder_FindN__Miss(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -689,7 +649,7 @@ func TestFindN_Miss(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestFind_Hit(t *testing.T) {
|
||||
func TestIfdBuilder_Find__Hit(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -753,7 +713,7 @@ func TestFind_Hit(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestFind_Miss(t *testing.T) {
|
||||
func TestIfdBuilder_Find__Miss(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -810,7 +770,7 @@ func TestFind_Miss(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestReplace(t *testing.T) {
|
||||
func TestIfdBuilder_Replace(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -878,7 +838,7 @@ func TestReplace(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestReplaceN(t *testing.T) {
|
||||
func TestIfdBuilder_ReplaceN(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -946,7 +906,7 @@ func TestReplaceN(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDeleteFirst(t *testing.T) {
|
||||
func TestIfdBuilder_DeleteFirst(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -1048,7 +1008,7 @@ func TestDeleteFirst(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDeleteN(t *testing.T) {
|
||||
func TestIfdBuilder_DeleteN(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -1150,7 +1110,7 @@ func TestDeleteN(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDeleteN_Two(t *testing.T) {
|
||||
func TestIfdBuilder_DeleteN_Two(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -1236,7 +1196,7 @@ func TestDeleteN_Two(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDeleteAll(t *testing.T) {
|
||||
func TestIfdBuilder_DeleteAll(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -1324,7 +1284,7 @@ func TestDeleteAll(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_IfdBuilder_CreateIfdBuilderFromExistingChain(t *testing.T) {
|
||||
func TestIfdBuilder_CreateIfdBuilderFromExistingChain(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
|
@ -1427,7 +1387,7 @@ func Test_IfdBuilder_CreateIfdBuilderFromExistingChain(t *testing.T) {
|
|||
|
||||
// TODO(dustin): !! Test with an actual GPS-attached image.
|
||||
|
||||
func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
||||
func TestIfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
|
@ -1546,7 +1506,7 @@ func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData_WithUpdate(t *testing.T) {
|
||||
// func TestIfdBuilder_CreateIfdBuilderFromExistingChain_RealData_WithUpdate(t *testing.T) {
|
||||
// filepath := path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
// rawExif, err := SearchFileAndExtractExif(filepath)
|
||||
|
@ -1843,7 +1803,7 @@ func ExampleIfdBuilder_SetStandardWithName() {
|
|||
// alternative software
|
||||
}
|
||||
|
||||
func Test_IfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) {
|
||||
func TestIfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) {
|
||||
ti := NewTagIndex()
|
||||
|
||||
im := NewIfdMapping()
|
||||
|
@ -1884,7 +1844,7 @@ func Test_IfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNewStandardBuilderTag_OneUnit(t *testing.T) {
|
||||
func TestNewStandardBuilderTag__OneUnit(t *testing.T) {
|
||||
ti := NewTagIndex()
|
||||
|
||||
it, err := ti.Get(IfdPathStandardExif, uint16(0x8833))
|
||||
|
@ -1901,7 +1861,7 @@ func TestNewStandardBuilderTag_OneUnit(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNewStandardBuilderTag_TwoUnits(t *testing.T) {
|
||||
func TestNewStandardBuilderTag__TwoUnits(t *testing.T) {
|
||||
ti := NewTagIndex()
|
||||
|
||||
it, err := ti.Get(IfdPathStandardExif, uint16(0x8833))
|
||||
|
@ -1920,7 +1880,7 @@ func TestNewStandardBuilderTag_TwoUnits(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAddStandardWithName(t *testing.T) {
|
||||
func TestIfdBuilder_AddStandardWithName(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -1951,7 +1911,7 @@ func TestAddStandardWithName(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetOrCreateIbFromRootIb_Noop(t *testing.T) {
|
||||
func TestGetOrCreateIbFromRootIb__Noop(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -1972,7 +1932,7 @@ func TestGetOrCreateIbFromRootIb_Noop(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetOrCreateIbFromRootIb_FqNoop(t *testing.T) {
|
||||
func TestGetOrCreateIbFromRootIb__FqNoop(t *testing.T) {
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
|
@ -2010,7 +1970,7 @@ func TestGetOrCreateIbFromRootIb_InvalidChild(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetOrCreateIbFromRootIb_Child(t *testing.T) {
|
||||
func TestGetOrCreateIbFromRootIb__Child(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
package exif
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
func getExifSimpleTestIb() *IfdBuilder {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.Panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
log.PanicIf(err)
|
||||
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
||||
|
||||
err = ib.AddStandard(0x000b, "asciivalue")
|
||||
log.PanicIf(err)
|
||||
|
||||
err = ib.AddStandard(0x00ff, []uint16{0x1122})
|
||||
log.PanicIf(err)
|
||||
|
||||
err = ib.AddStandard(0x0100, []uint32{0x33445566})
|
||||
log.PanicIf(err)
|
||||
|
||||
err = ib.AddStandard(0x013e, []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}})
|
||||
log.PanicIf(err)
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func getExifSimpleTestIbBytes() []byte {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.Panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
log.PanicIf(err)
|
||||
|
||||
ti := NewTagIndex()
|
||||
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
|
||||
|
||||
err = ib.AddStandard(0x000b, "asciivalue")
|
||||
log.PanicIf(err)
|
||||
|
||||
err = ib.AddStandard(0x00ff, []uint16{0x1122})
|
||||
log.PanicIf(err)
|
||||
|
||||
err = ib.AddStandard(0x0100, []uint32{0x33445566})
|
||||
log.PanicIf(err)
|
||||
|
||||
err = ib.AddStandard(0x013e, []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}})
|
||||
log.PanicIf(err)
|
||||
|
||||
ibe := NewIfdByteEncoder()
|
||||
|
||||
exifData, err := ibe.EncodeToExif(ib)
|
||||
log.PanicIf(err)
|
||||
|
||||
return exifData
|
||||
}
|
||||
|
||||
func validateExifSimpleTestIb(exifData []byte, t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.Panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
im := NewIfdMapping()
|
||||
|
||||
err := LoadStandardIfds(im)
|
||||
log.PanicIf(err)
|
||||
|
||||
ti := NewTagIndex()
|
||||
|
||||
eh, index, err := Collect(im, ti, exifData)
|
||||
log.PanicIf(err)
|
||||
|
||||
if eh.ByteOrder != TestDefaultByteOrder {
|
||||
t.Fatalf("EXIF byte-order is not correct: %v", eh.ByteOrder)
|
||||
} else if eh.FirstIfdOffset != ExifDefaultFirstIfdOffset {
|
||||
t.Fatalf("EXIF first IFD-offset not correct: (0x%02x)", eh.FirstIfdOffset)
|
||||
}
|
||||
|
||||
if len(index.Ifds) != 1 {
|
||||
t.Fatalf("There wasn't exactly one IFD decoded: (%d)", len(index.Ifds))
|
||||
}
|
||||
|
||||
ifd := index.RootIfd
|
||||
|
||||
if ifd.ByteOrder != TestDefaultByteOrder {
|
||||
t.Fatalf("IFD byte-order not correct.")
|
||||
} else if ifd.IfdPath != IfdStandard {
|
||||
t.Fatalf("IFD name not correct.")
|
||||
} else if ifd.Index != 0 {
|
||||
t.Fatalf("IFD index not zero: (%d)", ifd.Index)
|
||||
} else if ifd.Offset != uint32(0x0008) {
|
||||
t.Fatalf("IFD offset not correct.")
|
||||
} else if len(ifd.Entries) != 4 {
|
||||
t.Fatalf("IFD number of entries not correct: (%d)", len(ifd.Entries))
|
||||
} else if ifd.NextIfdOffset != uint32(0) {
|
||||
t.Fatalf("Next-IFD offset is non-zero.")
|
||||
} else if ifd.NextIfd != nil {
|
||||
t.Fatalf("Next-IFD pointer is non-nil.")
|
||||
}
|
||||
|
||||
// Verify the values by using the actual, orginal types (this is awesome).
|
||||
|
||||
addressableData := exifData[ExifAddressableAreaStart:]
|
||||
|
||||
expected := []struct {
|
||||
tagId uint16
|
||||
value interface{}
|
||||
}{
|
||||
{tagId: 0x000b, value: "asciivalue"},
|
||||
{tagId: 0x00ff, value: []uint16{0x1122}},
|
||||
{tagId: 0x0100, value: []uint32{0x33445566}},
|
||||
{tagId: 0x013e, value: []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}},
|
||||
}
|
||||
|
||||
for i, e := range ifd.Entries {
|
||||
if e.TagId != expected[i].tagId {
|
||||
t.Fatalf("Tag-ID for entry (%d) not correct: (0x%02x) != (0x%02x)", i, e.TagId, expected[i].tagId)
|
||||
}
|
||||
|
||||
value, err := e.Value(addressableData, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, expected[i].value) != true {
|
||||
t.Fatalf("Value for entry (%d) not correct: [%v] != [%v]", i, value, expected[i].value)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue