mirror of https://github.com/dsoprea/go-exif.git
ifd_enumerate: Added tests.
- Refactored (IfdTagEntry).ValueBytes() to handle managed undefined values.pull/3/head
parent
f1f23dca82
commit
50eafa98d6
12
exif.go
12
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
|
||||
}
|
||||
|
|
10
exif_test.go
10
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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.")
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue