From 1ce5b771db9d78986cfd27f9dcd61aaaab0286fd Mon Sep 17 00:00:00 2001 From: Dustin Oprea Date: Fri, 8 Jun 2018 00:41:28 -0400 Subject: [PATCH] ifd_enumerate: Can now elect to not resolve tag value. - To support testing. --- exif.go | 4 ++-- ifd_builder_encode_test.go | 14 +++++++++++--- ifd_enumerate.go | 38 ++++++++++++++++++++------------------ tags_unknown_test.go | 2 +- 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/exif.go b/exif.go index 2b20d60..b2253c5 100644 --- a/exif.go +++ b/exif.go @@ -179,7 +179,7 @@ func Visit(exifData []byte, visitor TagVisitor) (eh ExifHeader, err error) { ie := NewIfdEnumerate(exifData, eh.ByteOrder) - err = ie.Scan(eh.FirstIfdOffset, visitor) + err = ie.Scan(eh.FirstIfdOffset, visitor, true) log.PanicIf(err) return eh, nil @@ -198,7 +198,7 @@ func Collect(exifData []byte) (eh ExifHeader, index IfdIndex, err error) { ie := NewIfdEnumerate(exifData, eh.ByteOrder) - index, err = ie.Collect(eh.FirstIfdOffset) + index, err = ie.Collect(eh.FirstIfdOffset, true) log.PanicIf(err) return eh, index, nil diff --git a/ifd_builder_encode_test.go b/ifd_builder_encode_test.go index 116b210..a6ca61d 100644 --- a/ifd_builder_encode_test.go +++ b/ifd_builder_encode_test.go @@ -375,7 +375,7 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) { t.Fatalf("Child IFD is not the right size: (%d)", len(childIfdBlock)) } - iteV, err := ParseOneTag(RootIi, TestDefaultByteOrder, tagBytes) + iteV, err := ParseOneTag(RootIi, TestDefaultByteOrder, tagBytes, false) log.PanicIf(err) if iteV.TagId != IfdExifId { @@ -398,7 +398,7 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) { // Validate the child's raw IFD bytes. - childNextIfdOffset, childEntries, err := ParseOneIfd(ExifIi, TestDefaultByteOrder, childIfdBlock, nil) + childNextIfdOffset, childEntries, err := ParseOneIfd(ExifIi, TestDefaultByteOrder, childIfdBlock, nil, false) log.PanicIf(err) if childNextIfdOffset != uint32(0) { @@ -429,6 +429,13 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) { } func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) { + defer func() { + if state := recover(); state != nil { + err := log.Wrap(state.(error)) + log.PrintErrorf(err, "Test failure.") + } + }() + // Encode the tag. Since we've actually provided an offset at which we can // allocate data, the child-IFD will automatically be encoded, allocated, // and installed into the allocated-data block (which will follow the IFD @@ -467,7 +474,8 @@ func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) { t.Fatalf("Child IFD not have been allocated.") } - ite, err := ParseOneTag(RootIi, TestDefaultByteOrder, tagBytes) + + ite, err := ParseOneTag(RootIi, TestDefaultByteOrder, tagBytes, false) log.PanicIf(err) if ite.TagId != 0x000b { diff --git a/ifd_enumerate.go b/ifd_enumerate.go index 6335ceb..b31a7e9 100644 --- a/ifd_enumerate.go +++ b/ifd_enumerate.go @@ -125,7 +125,7 @@ func (ie *IfdEnumerate) getTagEnumerator(ifdOffset uint32) (ite *IfdTagEnumerato return ite } -func (ie *IfdEnumerate) parseTag(ii IfdIdentity, tagIndex int, ite *IfdTagEnumerator) (tag *IfdTagEntry, err error) { +func (ie *IfdEnumerate) parseTag(ii IfdIdentity, tagIndex int, ite *IfdTagEnumerator, resolveValue bool) (tag *IfdTagEntry, err error) { defer func() { if state := recover(); state != nil { err = log.Wrap(state.(error)) @@ -154,11 +154,13 @@ func (ie *IfdEnumerate) parseTag(ii IfdIdentity, tagIndex int, ite *IfdTagEnumer RawValueOffset: rawValueOffset, } - value, isUnhandledUnknown, err := ie.resolveTagValue(tag) - log.PanicIf(err) + if resolveValue == true { + value, isUnhandledUnknown, err := ie.resolveTagValue(tag) + log.PanicIf(err) - tag.value = value - tag.isUnhandledUnknown = isUnhandledUnknown + tag.value = value + tag.isUnhandledUnknown = isUnhandledUnknown + } // If it's an IFD but not a standard one, it'll just be seen as a LONG // (the standard IFD tag type), later, unless we skip it because it's @@ -248,7 +250,7 @@ type TagVisitor func(ii IfdIdentity, ifdIndex int, tagId uint16, tagType TagType // ParseIfd decodes the IFD block that we're currently sitting on the first // byte of. -func (ie *IfdEnumerate) ParseIfd(ii IfdIdentity, ifdIndex int, ite *IfdTagEnumerator, visitor TagVisitor, doDescend bool) (nextIfdOffset uint32, entries []*IfdTagEntry, thumbnailData []byte, err error) { +func (ie *IfdEnumerate) ParseIfd(ii IfdIdentity, ifdIndex int, ite *IfdTagEnumerator, visitor TagVisitor, doDescend bool, resolveValues bool) (nextIfdOffset uint32, entries []*IfdTagEntry, thumbnailData []byte, err error) { defer func() { if state := recover(); state != nil { err = log.Wrap(state.(error)) @@ -266,7 +268,7 @@ func (ie *IfdEnumerate) ParseIfd(ii IfdIdentity, ifdIndex int, ite *IfdTagEnumer var iteThumbnailSize *IfdTagEntry for i := 0; i < int(tagCount); i++ { - tag, err := ie.parseTag(ii, i, ite) + tag, err := ie.parseTag(ii, i, ite, resolveValues) log.PanicIf(err) if tag.TagId == ThumbnailOffsetTagId { @@ -300,7 +302,7 @@ func (ie *IfdEnumerate) ParseIfd(ii IfdIdentity, ifdIndex int, ite *IfdTagEnumer childIi, _ := IfdIdOrFail(ii.IfdName, tag.ChildIfdName) - err := ie.scan(childIi, tag.ValueOffset, visitor) + err := ie.scan(childIi, tag.ValueOffset, visitor, resolveValues) log.PanicIf(err) } @@ -351,7 +353,7 @@ func (ie *IfdEnumerate) parseThumbnail(offsetIte, lengthIte *IfdTagEntry) (thumb } // Scan enumerates the different EXIF's IFD blocks. -func (ie *IfdEnumerate) scan(ii IfdIdentity, ifdOffset uint32, visitor TagVisitor) (err error) { +func (ie *IfdEnumerate) scan(ii IfdIdentity, ifdOffset uint32, visitor TagVisitor, resolveValues bool) (err error) { defer func() { if state := recover(); state != nil { err = log.Wrap(state.(error)) @@ -362,7 +364,7 @@ func (ie *IfdEnumerate) scan(ii IfdIdentity, ifdOffset uint32, visitor TagVisito ifdEnumerateLogger.Debugf(nil, "Parsing IFD [%s] (%d) at offset (%04x).", ii.IfdName, ifdIndex, ifdOffset) ite := ie.getTagEnumerator(ifdOffset) - nextIfdOffset, _, _, err := ie.ParseIfd(ii, ifdIndex, ite, visitor, true) + nextIfdOffset, _, _, err := ie.ParseIfd(ii, ifdIndex, ite, visitor, true, resolveValues) log.PanicIf(err) if nextIfdOffset == 0 { @@ -376,7 +378,7 @@ func (ie *IfdEnumerate) scan(ii IfdIdentity, ifdOffset uint32, visitor TagVisito } // Scan enumerates the different EXIF blocks (called IFDs). -func (ie *IfdEnumerate) Scan(ifdOffset uint32, visitor TagVisitor) (err error) { +func (ie *IfdEnumerate) Scan(ifdOffset uint32, visitor TagVisitor, resolveValue bool) (err error) { defer func() { if state := recover(); state != nil { err = log.Wrap(state.(error)) @@ -385,7 +387,7 @@ func (ie *IfdEnumerate) Scan(ifdOffset uint32, visitor TagVisitor) (err error) { ii, _ := IfdIdOrFail("", IfdStandard) - err = ie.scan(ii, ifdOffset, visitor) + err = ie.scan(ii, ifdOffset, visitor, resolveValue) log.PanicIf(err) return nil @@ -818,7 +820,7 @@ type IfdIndex struct { // Scan enumerates the different EXIF blocks (called IFDs). -func (ie *IfdEnumerate) Collect(rootIfdOffset uint32) (index IfdIndex, err error) { +func (ie *IfdEnumerate) Collect(rootIfdOffset uint32, resolveValues bool) (index IfdIndex, err error) { defer func() { if state := recover(); state != nil { err = log.Wrap(state.(error)) @@ -860,7 +862,7 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32) (index IfdIndex, err error ifdEnumerateLogger.Debugf(nil, "Parsing IFD [%s] (%d) at offset (%04x).", ii.IfdName, index, offset) ite := ie.getTagEnumerator(offset) - nextIfdOffset, entries, thumbnailData, err := ie.ParseIfd(ii, index, ite, nil, false) + nextIfdOffset, entries, thumbnailData, err := ie.ParseIfd(ii, index, ite, nil, false, resolveValues) log.PanicIf(err) id := len(ifds) @@ -979,7 +981,7 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32) (index IfdIndex, err error // ParseOneIfd is a hack to use an IE to parse a raw IFD block. Can be used for // testing. -func ParseOneIfd(ii IfdIdentity, byteOrder binary.ByteOrder, ifdBlock []byte, visitor TagVisitor) (nextIfdOffset uint32, entries []*IfdTagEntry, err error) { +func ParseOneIfd(ii IfdIdentity, byteOrder binary.ByteOrder, ifdBlock []byte, visitor TagVisitor, resolveValues bool) (nextIfdOffset uint32, entries []*IfdTagEntry, err error) { defer func() { if state := recover(); state != nil { err = log.Wrap(state.(error)) @@ -992,14 +994,14 @@ func ParseOneIfd(ii IfdIdentity, byteOrder binary.ByteOrder, ifdBlock []byte, vi ite := NewIfdTagEnumerator(ifdBlock, byteOrder, 0) - nextIfdOffset, entries, _, err = ie.ParseIfd(ii, 0, ite, visitor, true) + nextIfdOffset, entries, _, err = ie.ParseIfd(ii, 0, ite, visitor, true, resolveValues) log.PanicIf(err) return nextIfdOffset, entries, nil } // ParseOneTag is a hack to use an IE to parse a raw tag block. -func ParseOneTag(ii IfdIdentity, byteOrder binary.ByteOrder, tagBlock []byte) (tag *IfdTagEntry, err error) { +func ParseOneTag(ii IfdIdentity, byteOrder binary.ByteOrder, tagBlock []byte, resolveValue bool) (tag *IfdTagEntry, err error) { defer func() { if state := recover(); state != nil { err = log.Wrap(state.(error)) @@ -1012,7 +1014,7 @@ func ParseOneTag(ii IfdIdentity, byteOrder binary.ByteOrder, tagBlock []byte) (t ite := NewIfdTagEnumerator(tagBlock, byteOrder, 0) - tag, err = ie.parseTag(ii, 0, ite) + tag, err = ie.parseTag(ii, 0, ite, resolveValue) log.PanicIf(err) return tag, nil diff --git a/tags_unknown_test.go b/tags_unknown_test.go index 08915d8..397bfb0 100644 --- a/tags_unknown_test.go +++ b/tags_unknown_test.go @@ -60,7 +60,7 @@ func TestUndefinedValue_ExifVersion(t *testing.T) { t.Fatalf("Tag not encoded to the right number of bytes: (%d)", len(tagBytes)) } - ite, err := ParseOneTag(ii, byteOrder, tagBytes) + ite, err := ParseOneTag(ii, byteOrder, tagBytes, false) log.PanicIf(err) if ite.TagId != 0x9000 {