mirror of https://github.com/dsoprea/go-exif.git
Empower ITEs to resolve values and raw bytes directly
They'll also now embed all of the information they need to know since it is all known where the ITEs are created. This prevents the user from having to be involved in it. This makes it much more straightforward and enjoyable to use. - ifd_tag_entry.go - newIfdTagEntry now takes and embeds `addressableBytes` and `byteOrder`. - We've dumped the `value` member that let the caller preload a parsed value (or bytes?). It's no longer necessary since this led to inconsistencies and the ITE can produce these values directly, now. - `Value()` obviously no longer takes `addressableValue` and `byteOrder` since now embedded. - `Value()` will now see and return ErrUnhandledUnknownTypedTag directly (not wrapping it, since this is a handled case). - common/type.go: FormatFromType now uses Stringer as a fallback if possible. All undefined-tag wrapper types implement it, so the same function can handle both undefined and non-undefined values, and the individual types can control the strings presented in simple listing. - Dropped "resolveValue" parameters from all of the collect, visit, and parsing functions. Resolution is now a later step performed by the caller on the ITEs, directly. - This parameter was protection against undefined-type values disrupting simple enumeration, but now the user can simply produce the list of tags and can either choose to decode their value or not, directly. If they do, they, as of earlier, recent commits, also have the ability to properly manage unhandled undefined-values so they don't crash. - The ITEs can now create ValueContext structs directly (GetValueContext()), though it might not be necessary now that the ITEs can produce the values and encodings directly. - This also allowed us to dump several other GetValueContext() implementations elsewhere since it is now self-reliant on this type and those methods were essentially kludges for the lack of this. - Dump a bunch of "Value" methods from ITEs which just weren't useful or simple enough. Replaced by the above. - Fixed `(Ifd).String()` to have a pointer receiver.for/master
parent
e7e1e89ffb
commit
1bdfa9b10e
|
@ -139,7 +139,10 @@ type SignedRational struct {
|
|||
}
|
||||
|
||||
// Format returns a stringified value for the given encoding. Automatically
|
||||
// parses. Automatically calculates count based on type size.
|
||||
// parses. Automatically calculates count based on type size. This function
|
||||
// also supports undefined-type values (the ones that we support, anyway) by
|
||||
// way of the String() method that they all require. We can't be more specific
|
||||
// because we're a base package and we can't refer to it.
|
||||
func FormatFromType(value interface{}, justFirst bool) (phrase string, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -247,6 +250,9 @@ func FormatFromType(value interface{}, justFirst bool) (phrase string, err error
|
|||
}
|
||||
|
||||
return fmt.Sprintf("%v", parts), nil
|
||||
case fmt.Stringer:
|
||||
// An undefined value that is documented (or that we otherwise support).
|
||||
return t.String(), nil
|
||||
default:
|
||||
// Affects only "unknown" values, in general.
|
||||
log.Panicf("type can not be formatted into string: %v", reflect.TypeOf(value).Name())
|
||||
|
|
|
@ -189,7 +189,7 @@ func Visit(rootIfdName string, ifdMapping *IfdMapping, tagIndex *TagIndex, exifD
|
|||
|
||||
ie := NewIfdEnumerate(ifdMapping, tagIndex, exifData, eh.ByteOrder)
|
||||
|
||||
err = ie.Scan(rootIfdName, eh.FirstIfdOffset, visitor, true)
|
||||
err = ie.Scan(rootIfdName, eh.FirstIfdOffset, visitor)
|
||||
log.PanicIf(err)
|
||||
|
||||
return eh, nil
|
||||
|
@ -208,7 +208,7 @@ func Collect(ifdMapping *IfdMapping, tagIndex *TagIndex, exifData []byte) (eh Ex
|
|||
|
||||
ie := NewIfdEnumerate(ifdMapping, tagIndex, exifData, eh.ByteOrder)
|
||||
|
||||
index, err = ie.Collect(eh.FirstIfdOffset, true)
|
||||
index, err = ie.Collect(eh.FirstIfdOffset)
|
||||
log.PanicIf(err)
|
||||
|
||||
return eh, index, nil
|
||||
|
|
|
@ -315,19 +315,19 @@ func TestCollect(t *testing.T) {
|
|||
foundExif := 0
|
||||
foundGps := 0
|
||||
for _, ite := range lookup[exifcommon.IfdPathStandard][0].Entries {
|
||||
if ite.ChildIfdPath == exifcommon.IfdPathStandardExif {
|
||||
if ite.ChildIfdPath() == exifcommon.IfdPathStandardExif {
|
||||
foundExif++
|
||||
|
||||
if ite.TagId != exifcommon.IfdExifId {
|
||||
t.Fatalf("EXIF IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId, exifcommon.IfdExifId)
|
||||
if ite.TagId() != exifcommon.IfdExifId {
|
||||
t.Fatalf("EXIF IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId(), exifcommon.IfdExifId)
|
||||
}
|
||||
}
|
||||
|
||||
if ite.ChildIfdPath == exifcommon.IfdPathStandardGps {
|
||||
if ite.ChildIfdPath() == exifcommon.IfdPathStandardGps {
|
||||
foundGps++
|
||||
|
||||
if ite.TagId != exifcommon.IfdGpsId {
|
||||
t.Fatalf("GPS IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId, exifcommon.IfdGpsId)
|
||||
if ite.TagId() != exifcommon.IfdGpsId {
|
||||
t.Fatalf("GPS IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId(), exifcommon.IfdGpsId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -340,11 +340,11 @@ func TestCollect(t *testing.T) {
|
|||
|
||||
foundIop := 0
|
||||
for _, ite := range lookup[exifcommon.IfdPathStandardExif][0].Entries {
|
||||
if ite.ChildIfdPath == exifcommon.IfdPathStandardExifIop {
|
||||
if ite.ChildIfdPath() == exifcommon.IfdPathStandardExifIop {
|
||||
foundIop++
|
||||
|
||||
if ite.TagId != exifcommon.IfdIopId {
|
||||
t.Fatalf("IOP IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId, exifcommon.IfdIopId)
|
||||
if ite.TagId() != exifcommon.IfdIopId {
|
||||
t.Fatalf("IOP IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId(), exifcommon.IfdIopId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1042,7 +1042,7 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, includeTagIds []uint16, excl
|
|||
}
|
||||
|
||||
for i, ite := range ifd.Entries {
|
||||
if ite.TagId == ThumbnailOffsetTagId || ite.TagId == ThumbnailSizeTagId {
|
||||
if ite.TagId() == ThumbnailOffsetTagId || ite.TagId() == ThumbnailSizeTagId {
|
||||
// These will be added on-the-fly when we encode.
|
||||
continue
|
||||
}
|
||||
|
@ -1050,7 +1050,7 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, includeTagIds []uint16, excl
|
|||
if excludeTagIds != nil && len(excludeTagIds) > 0 {
|
||||
found := false
|
||||
for _, excludedTagId := range excludeTagIds {
|
||||
if excludedTagId == ite.TagId {
|
||||
if excludedTagId == ite.TagId() {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
@ -1066,7 +1066,7 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, includeTagIds []uint16, excl
|
|||
|
||||
found := false
|
||||
for _, includedTagId := range includeTagIds {
|
||||
if includedTagId == ite.TagId {
|
||||
if includedTagId == ite.TagId() {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
@ -1079,7 +1079,7 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, includeTagIds []uint16, excl
|
|||
|
||||
var bt *BuilderTag
|
||||
|
||||
if ite.ChildIfdPath != "" {
|
||||
if ite.ChildIfdPath() != "" {
|
||||
// If we want to add an IFD tag, we'll have to build it first and
|
||||
// *then* add it via a different method.
|
||||
|
||||
|
@ -1090,7 +1090,7 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, includeTagIds []uint16, excl
|
|||
for _, thisChildIfd := range ifd.Children {
|
||||
if thisChildIfd.ParentTagIndex != i {
|
||||
continue
|
||||
} else if thisChildIfd.TagId != 0xffff && thisChildIfd.TagId != ite.TagId {
|
||||
} 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)
|
||||
}
|
||||
|
||||
|
@ -1104,7 +1104,7 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, includeTagIds []uint16, excl
|
|||
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)
|
||||
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)
|
||||
|
@ -1112,11 +1112,11 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, includeTagIds []uint16, excl
|
|||
} else {
|
||||
// Non-IFD tag.
|
||||
|
||||
valueContext := ifd.GetValueContext(ite)
|
||||
valueContext := ite.GetValueContext()
|
||||
|
||||
var rawBytes []byte
|
||||
|
||||
if ite.TagType == exifcommon.TypeUndefined {
|
||||
if ite.TagType() == exifcommon.TypeUndefined {
|
||||
// It's an undefined-type value. Try to process (or skip if
|
||||
// we don't know how to), and encode back to bytes. This is the
|
||||
// cleanest way of using what we already have to both determine
|
||||
|
@ -1149,8 +1149,8 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, includeTagIds []uint16, excl
|
|||
|
||||
bt = NewBuilderTag(
|
||||
ifd.IfdPath,
|
||||
ite.TagId,
|
||||
ite.TagType,
|
||||
ite.TagId(),
|
||||
ite.TagType(),
|
||||
value,
|
||||
ib.byteOrder)
|
||||
}
|
||||
|
|
|
@ -422,30 +422,28 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) {
|
|||
t.Fatalf("Child IFD is not the right size: (%d)", len(childIfdBlock))
|
||||
}
|
||||
|
||||
iteV, err := ParseOneTag(im, ti, fmt.Sprintf("%s%d", exifcommon.IfdPathStandard, 0), exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder, tagBytes, false)
|
||||
iteV, err := ParseOneTag(im, ti, fmt.Sprintf("%s%d", exifcommon.IfdPathStandard, 0), exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder, tagBytes)
|
||||
log.PanicIf(err)
|
||||
|
||||
if iteV.TagId != exifcommon.IfdExifId {
|
||||
t.Fatalf("IFD first tag-ID not correct: (0x%02x)", iteV.TagId)
|
||||
} else if iteV.TagIndex != 0 {
|
||||
t.Fatalf("IFD first tag index not correct: (%d)", iteV.TagIndex)
|
||||
} else if iteV.TagType != exifcommon.TypeLong {
|
||||
t.Fatalf("IFD first tag type not correct: (%d)", iteV.TagType)
|
||||
} else if iteV.UnitCount != 1 {
|
||||
t.Fatalf("IFD first tag unit-count not correct: (%d)", iteV.UnitCount)
|
||||
} else if iteV.ValueOffset != nextIfdOffsetToWrite {
|
||||
t.Fatalf("IFD's child-IFD offset (as offset) is not correct: (%d) != (%d)", iteV.ValueOffset, nextIfdOffsetToWrite)
|
||||
} else if bytes.Compare(iteV.RawValueOffset, []byte{0x0, 0x0, 0x07, 0xd0}) != 0 {
|
||||
t.Fatalf("IFD's child-IFD offset (as raw bytes) is not correct: [%x]", iteV.RawValueOffset)
|
||||
} else if iteV.ChildIfdPath != exifcommon.IfdPathStandardExif {
|
||||
t.Fatalf("IFD first tag IFD-name name not correct: [%s]", iteV.ChildIfdPath)
|
||||
} else if iteV.IfdPath != exifcommon.IfdPathStandard {
|
||||
t.Fatalf("IFD first tag parent IFD not correct: %v", iteV.IfdPath)
|
||||
if iteV.TagId() != exifcommon.IfdExifId {
|
||||
t.Fatalf("IFD first tag-ID not correct: (0x%02x)", iteV.TagId())
|
||||
} else if iteV.tagIndex != 0 {
|
||||
t.Fatalf("IFD first tag index not correct: (%d)", iteV.tagIndex)
|
||||
} else if iteV.TagType() != exifcommon.TypeLong {
|
||||
t.Fatalf("IFD first tag type not correct: (%d)", iteV.TagType())
|
||||
} else if iteV.UnitCount() != 1 {
|
||||
t.Fatalf("IFD first tag unit-count not correct: (%d)", iteV.UnitCount())
|
||||
} else if iteV.valueOffset_() != nextIfdOffsetToWrite {
|
||||
t.Fatalf("IFD's child-IFD offset (as offset) is not correct: (%d) != (%d)", iteV.valueOffset_(), nextIfdOffsetToWrite)
|
||||
} else if iteV.ChildIfdPath() != exifcommon.IfdPathStandardExif {
|
||||
t.Fatalf("IFD first tag IFD-name name not correct: [%s]", iteV.ChildIfdPath())
|
||||
} else if iteV.IfdPath() != exifcommon.IfdPathStandard {
|
||||
t.Fatalf("IFD first tag parent IFD not correct: %v", iteV.IfdPath())
|
||||
}
|
||||
|
||||
// Validate the child's raw IFD bytes.
|
||||
|
||||
childNextIfdOffset, childEntries, err := ParseOneIfd(im, ti, "IFD0/Exif0", "IFD/Exif", exifcommon.TestDefaultByteOrder, childIfdBlock, nil, false)
|
||||
childNextIfdOffset, childEntries, err := ParseOneIfd(im, ti, "IFD0/Exif0", "IFD/Exif", exifcommon.TestDefaultByteOrder, childIfdBlock, nil)
|
||||
log.PanicIf(err)
|
||||
|
||||
if childNextIfdOffset != uint32(0) {
|
||||
|
@ -456,22 +454,18 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) {
|
|||
|
||||
ite := childEntries[0]
|
||||
|
||||
if ite.TagId != 0x8822 {
|
||||
t.Fatalf("Child IFD first tag-ID not correct: (0x%02x)", ite.TagId)
|
||||
} else if ite.TagIndex != 0 {
|
||||
t.Fatalf("Child IFD first tag index not correct: (%d)", ite.TagIndex)
|
||||
} else if ite.TagType != exifcommon.TypeShort {
|
||||
t.Fatalf("Child IFD first tag type not correct: (%d)", ite.TagType)
|
||||
} else if ite.UnitCount != 1 {
|
||||
t.Fatalf("Child IFD first tag unit-count not correct: (%d)", ite.UnitCount)
|
||||
} else if ite.ValueOffset != 0x12340000 {
|
||||
t.Fatalf("Child IFD first tag value value (as offset) not correct: (0x%02x)", ite.ValueOffset)
|
||||
} else if bytes.Compare(ite.RawValueOffset, []byte{0x12, 0x34, 0x0, 0x0}) != 0 {
|
||||
t.Fatalf("Child IFD first tag value value (as raw bytes) not correct: [%v]", ite.RawValueOffset)
|
||||
} else if ite.ChildIfdPath != "" {
|
||||
t.Fatalf("Child IFD first tag IFD-name name not empty: [%s]", ite.ChildIfdPath)
|
||||
} else if ite.IfdPath != exifcommon.IfdPathStandardExif {
|
||||
t.Fatalf("Child IFD first tag parent IFD not correct: %v", ite.IfdPath)
|
||||
if ite.TagId() != 0x8822 {
|
||||
t.Fatalf("Child IFD first tag-ID not correct: (0x%02x)", ite.TagId())
|
||||
} else if ite.tagIndex != 0 {
|
||||
t.Fatalf("Child IFD first tag index not correct: (%d)", ite.tagIndex)
|
||||
} else if ite.TagType() != exifcommon.TypeShort {
|
||||
t.Fatalf("Child IFD first tag type not correct: (%d)", ite.TagType())
|
||||
} else if ite.UnitCount() != 1 {
|
||||
t.Fatalf("Child IFD first tag unit-count not correct: (%d)", ite.UnitCount())
|
||||
} else if ite.ChildIfdPath() != "" {
|
||||
t.Fatalf("Child IFD first tag IFD-name name not empty: [%s]", ite.ChildIfdPath())
|
||||
} else if ite.IfdPath() != exifcommon.IfdPathStandardExif {
|
||||
t.Fatalf("Child IFD first tag parent IFD not correct: %v", ite.IfdPath())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -531,25 +525,21 @@ func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) {
|
|||
t.Fatalf("Child IFD not have been allocated.")
|
||||
}
|
||||
|
||||
ite, err := ParseOneTag(im, ti, fmt.Sprintf("%s%d", exifcommon.IfdPathStandard, 0), exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder, tagBytes, false)
|
||||
ite, err := ParseOneTag(im, ti, fmt.Sprintf("%s%d", exifcommon.IfdPathStandard, 0), exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder, tagBytes)
|
||||
log.PanicIf(err)
|
||||
|
||||
if ite.TagId != 0x000b {
|
||||
t.Fatalf("Tag-ID not correct: (0x%02x)", ite.TagId)
|
||||
} else if ite.TagIndex != 0 {
|
||||
t.Fatalf("Tag index not correct: (%d)", ite.TagIndex)
|
||||
} else if ite.TagType != exifcommon.TypeAscii {
|
||||
t.Fatalf("Tag type not correct: (%d)", ite.TagType)
|
||||
} else if ite.UnitCount != (uint32(len(valueString) + 1)) {
|
||||
t.Fatalf("Tag unit-count not correct: (%d)", ite.UnitCount)
|
||||
} else if ite.ValueOffset != addressableOffset {
|
||||
t.Fatalf("Tag's value (as offset) is not correct: (%d) != (%d)", ite.ValueOffset, addressableOffset)
|
||||
} else if bytes.Compare(ite.RawValueOffset, []byte{0x0, 0x0, 0x12, 0x34}) != 0 {
|
||||
t.Fatalf("Tag's value (as raw bytes) is not correct: [%x]", ite.RawValueOffset)
|
||||
} else if ite.ChildIfdPath != "" {
|
||||
t.Fatalf("Tag's IFD-name should be empty: [%s]", ite.ChildIfdPath)
|
||||
} else if ite.IfdPath != exifcommon.IfdPathStandard {
|
||||
t.Fatalf("Tag's parent IFD is not correct: %v", ite.IfdPath)
|
||||
if ite.TagId() != 0x000b {
|
||||
t.Fatalf("Tag-ID not correct: (0x%02x)", ite.TagId())
|
||||
} else if ite.tagIndex != 0 {
|
||||
t.Fatalf("Tag index not correct: (%d)", ite.tagIndex)
|
||||
} else if ite.TagType() != exifcommon.TypeAscii {
|
||||
t.Fatalf("Tag type not correct: (%d)", ite.TagType())
|
||||
} else if ite.UnitCount() != (uint32(len(valueString) + 1)) {
|
||||
t.Fatalf("Tag unit-count not correct: (%d)", ite.UnitCount())
|
||||
} else if ite.ChildIfdPath() != "" {
|
||||
t.Fatalf("Tag's IFD-name should be empty: [%s]", ite.ChildIfdPath())
|
||||
} else if ite.IfdPath() != exifcommon.IfdPathStandard {
|
||||
t.Fatalf("Tag's parent IFD is not correct: %v", ite.IfdPath())
|
||||
}
|
||||
|
||||
expectedBuffer := bytes.NewBufferString(valueString)
|
||||
|
@ -886,15 +876,11 @@ func ExampleIfdByteEncoder_EncodeToExif() {
|
|||
_, index, err := Collect(im, ti, exifData)
|
||||
log.PanicIf(err)
|
||||
|
||||
// addressableData is the byte-slice where the allocated data can be
|
||||
// resolved (where position 0x0 will correlate with offset 0x0).
|
||||
addressableData := exifData[ExifAddressableAreaStart:]
|
||||
|
||||
for i, e := range index.RootIfd.Entries {
|
||||
value, err := e.Value(addressableData, exifcommon.TestDefaultByteOrder)
|
||||
for i, ite := range index.RootIfd.Entries {
|
||||
value, err := ite.Value()
|
||||
log.PanicIf(err)
|
||||
|
||||
fmt.Printf("%d: %s [%v]\n", i, e, value)
|
||||
fmt.Printf("%d: %s [%v]\n", i, ite, value)
|
||||
}
|
||||
|
||||
// Output:
|
||||
|
|
|
@ -1435,15 +1435,15 @@ func TestIfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
|||
|
||||
originalIfdTags := make([][2]interface{}, 0)
|
||||
for _, ite := range originalTags {
|
||||
if ite.ChildIfdPath != "" {
|
||||
originalIfdTags = append(originalIfdTags, [2]interface{}{ite.IfdPath, ite.TagId})
|
||||
if ite.ChildIfdPath() != "" {
|
||||
originalIfdTags = append(originalIfdTags, [2]interface{}{ite.IfdPath(), ite.TagId()})
|
||||
}
|
||||
}
|
||||
|
||||
recoveredIfdTags := make([][2]interface{}, 0)
|
||||
for _, ite := range recoveredTags {
|
||||
if ite.ChildIfdPath != "" {
|
||||
recoveredIfdTags = append(recoveredIfdTags, [2]interface{}{ite.IfdPath, ite.TagId})
|
||||
if ite.ChildIfdPath() != "" {
|
||||
recoveredIfdTags = append(recoveredIfdTags, [2]interface{}{ite.IfdPath(), ite.TagId()})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1474,64 +1474,53 @@ func TestIfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
|||
}
|
||||
|
||||
for i, recoveredIte := range recoveredTags {
|
||||
if recoveredIte.ChildIfdPath != "" {
|
||||
if recoveredIte.ChildIfdPath() != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
originalIte := originalTags[i]
|
||||
|
||||
if recoveredIte.IfdPath != originalIte.IfdPath {
|
||||
t.Fatalf("IfdIdentity not as expected: %s != %s ITE=%s", recoveredIte.IfdPath, originalIte.IfdPath, recoveredIte)
|
||||
} else if recoveredIte.TagId != originalIte.TagId {
|
||||
t.Fatalf("Tag-ID not as expected: %d != %d ITE=%s", recoveredIte.TagId, originalIte.TagId, recoveredIte)
|
||||
} else if recoveredIte.TagType != originalIte.TagType {
|
||||
t.Fatalf("Tag-type not as expected: %d != %d ITE=%s", recoveredIte.TagType, originalIte.TagType, recoveredIte)
|
||||
if recoveredIte.IfdPath() != originalIte.IfdPath() {
|
||||
t.Fatalf("IfdIdentity not as expected: %s != %s ITE=%s", recoveredIte.IfdPath(), originalIte.IfdPath(), recoveredIte)
|
||||
} else if recoveredIte.TagId() != originalIte.TagId() {
|
||||
t.Fatalf("Tag-ID not as expected: %d != %d ITE=%s", recoveredIte.TagId(), originalIte.TagId(), recoveredIte)
|
||||
} else if recoveredIte.TagType() != originalIte.TagType() {
|
||||
t.Fatalf("Tag-type not as expected: %d != %d ITE=%s", recoveredIte.TagType(), originalIte.TagType(), recoveredIte)
|
||||
}
|
||||
|
||||
var originalValueBytes []byte
|
||||
|
||||
if originalIte.TagType == exifcommon.TypeUndefined {
|
||||
if originalIte.TagType() == exifcommon.TypeUndefined {
|
||||
valueContext := originalIte.GetValueContext()
|
||||
|
||||
var err error
|
||||
|
||||
valueContext :=
|
||||
newValueContextFromTag(
|
||||
originalIte,
|
||||
originalIndex.RootIfd.addressableData,
|
||||
originalIndex.RootIfd.ByteOrder)
|
||||
|
||||
value, err := exifundefined.Decode(valueContext)
|
||||
|
||||
log.PanicIf(err)
|
||||
|
||||
originalValueBytes, _, err = exifundefined.Encode(value, originalIndex.RootIfd.ByteOrder)
|
||||
} else {
|
||||
var err error
|
||||
|
||||
// TODO(dustin): We're always accessing the addressable-data using the root-IFD. It shouldn't matter, but we'd rather access it from our specific IFD.
|
||||
originalValueBytes, err = originalIte.ValueBytes(originalIndex.RootIfd.addressableData, originalIndex.RootIfd.ByteOrder)
|
||||
originalValueBytes, err = originalIte.RawBytes()
|
||||
log.PanicIf(err)
|
||||
}
|
||||
|
||||
var recoveredValueBytes []byte
|
||||
|
||||
if recoveredIte.TagType == exifcommon.TypeUndefined {
|
||||
if recoveredIte.TagType() == exifcommon.TypeUndefined {
|
||||
valueContext := recoveredIte.GetValueContext()
|
||||
|
||||
var err error
|
||||
|
||||
valueContext :=
|
||||
newValueContextFromTag(
|
||||
recoveredIte,
|
||||
recoveredIndex.RootIfd.addressableData,
|
||||
recoveredIndex.RootIfd.ByteOrder)
|
||||
|
||||
value, err := exifundefined.Decode(valueContext)
|
||||
|
||||
log.PanicIf(err)
|
||||
|
||||
recoveredValueBytes, _, err = exifundefined.Encode(value, recoveredIndex.RootIfd.ByteOrder)
|
||||
} else {
|
||||
var err error
|
||||
|
||||
recoveredValueBytes, err = recoveredIte.ValueBytes(recoveredIndex.RootIfd.addressableData, recoveredIndex.RootIfd.ByteOrder)
|
||||
recoveredValueBytes, err = recoveredIte.RawBytes()
|
||||
log.PanicIf(err)
|
||||
}
|
||||
|
||||
|
@ -1610,15 +1599,15 @@ func TestIfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
|||
|
||||
// originalIfdTags := make([][2]interface{}, 0)
|
||||
// for _, ite := range originalTags {
|
||||
// if ite.ChildIfdPath != "" {
|
||||
// originalIfdTags = append(originalIfdTags, [2]interface{}{ite.IfdPath, ite.TagId})
|
||||
// if ite.ChildIfdPath() != "" {
|
||||
// originalIfdTags = append(originalIfdTags, [2]interface{}{ite.IfdPath(), ite.TagId()})
|
||||
// }
|
||||
// }
|
||||
|
||||
// recoveredIfdTags := make([][2]interface{}, 0)
|
||||
// for _, ite := range recoveredTags {
|
||||
// if ite.ChildIfdPath != "" {
|
||||
// recoveredIfdTags = append(recoveredIfdTags, [2]interface{}{ite.IfdPath, ite.TagId})
|
||||
// if ite.ChildIfdPath() != "" {
|
||||
// recoveredIfdTags = append(recoveredIfdTags, [2]interface{}{ite.IfdPath(), ite.TagId()})
|
||||
// }
|
||||
// }
|
||||
|
||||
|
@ -1649,18 +1638,18 @@ func TestIfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
|||
// }
|
||||
|
||||
// for i, recoveredIte := range recoveredTags {
|
||||
// if recoveredIte.ChildIfdPath != "" {
|
||||
// if recoveredIte.ChildIfdPath() != "" {
|
||||
// continue
|
||||
// }
|
||||
|
||||
// originalIte := originalTags[i]
|
||||
|
||||
// if recoveredIte.IfdPath != originalIte.IfdPath {
|
||||
// t.Fatalf("IfdIdentity not as expected: %s != %s ITE=%s", recoveredIte.IfdPath, originalIte.IfdPath, recoveredIte)
|
||||
// } else if recoveredIte.TagId != originalIte.TagId {
|
||||
// t.Fatalf("Tag-ID not as expected: %d != %d ITE=%s", recoveredIte.TagId, originalIte.TagId, recoveredIte)
|
||||
// } else if recoveredIte.TagType != originalIte.TagType {
|
||||
// t.Fatalf("Tag-type not as expected: %d != %d ITE=%s", recoveredIte.TagType, originalIte.TagType, recoveredIte)
|
||||
// if recoveredIte.IfdPath() != originalIte.IfdPath() {
|
||||
// t.Fatalf("IfdIdentity not as expected: %s != %s ITE=%s", recoveredIte.IfdPath(), originalIte.IfdPath(), recoveredIte)
|
||||
// } else if recoveredIte.TagId() != originalIte.TagId() {
|
||||
// t.Fatalf("Tag-ID not as expected: %d != %d ITE=%s", recoveredIte.TagId(), originalIte.TagId(), recoveredIte)
|
||||
// } else if recoveredIte.TagType() != originalIte.TagType() {
|
||||
// t.Fatalf("Tag-type not as expected: %d != %d ITE=%s", recoveredIte.TagType(), originalIte.TagType(), recoveredIte)
|
||||
// }
|
||||
|
||||
// originalValueBytes, err := originalIte.ValueBytes(originalIndex.RootIfd.addressableData, originalIndex.RootIfd.ByteOrder)
|
||||
|
@ -1669,7 +1658,7 @@ func TestIfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
|
|||
// recoveredValueBytes, err := recoveredIte.ValueBytes(recoveredIndex.RootIfd.addressableData, recoveredIndex.RootIfd.ByteOrder)
|
||||
// log.PanicIf(err)
|
||||
|
||||
// if recoveredIte.TagId == 0x9286 {
|
||||
// if recoveredIte.TagId() == 0x9286 {
|
||||
// expectedValueBytes := make([]byte, 0)
|
||||
|
||||
// expectedValueBytes = append(expectedValueBytes, []byte{'A', 'S', 'C', 'I', 'I', 0, 0, 0}...)
|
||||
|
@ -1822,10 +1811,12 @@ func ExampleIfdBuilder_SetStandardWithName() {
|
|||
log.PanicIf(err)
|
||||
|
||||
for _, ite := range results {
|
||||
value, err := childIfd.TagValue(ite)
|
||||
valueContext := ite.GetValueContext()
|
||||
|
||||
valueRaw, err := valueContext.Values()
|
||||
log.PanicIf(err)
|
||||
|
||||
stringValue := value.(string)
|
||||
stringValue := valueRaw.(string)
|
||||
fmt.Println(stringValue)
|
||||
}
|
||||
|
||||
|
|
|
@ -58,14 +58,14 @@ type IfdTagEnumerator struct {
|
|||
buffer *bytes.Buffer
|
||||
}
|
||||
|
||||
func NewIfdTagEnumerator(addressableData []byte, byteOrder binary.ByteOrder, ifdOffset uint32) (ite *IfdTagEnumerator) {
|
||||
ite = &IfdTagEnumerator{
|
||||
func NewIfdTagEnumerator(addressableData []byte, byteOrder binary.ByteOrder, ifdOffset uint32) (enumerator *IfdTagEnumerator) {
|
||||
enumerator = &IfdTagEnumerator{
|
||||
addressableData: addressableData,
|
||||
byteOrder: byteOrder,
|
||||
buffer: bytes.NewBuffer(addressableData[ifdOffset:]),
|
||||
}
|
||||
|
||||
return ite
|
||||
return enumerator
|
||||
}
|
||||
|
||||
// getUint16 reads a uint16 and advances both our current and our current
|
||||
|
@ -139,16 +139,16 @@ func NewIfdEnumerate(ifdMapping *IfdMapping, tagIndex *TagIndex, exifData []byte
|
|||
}
|
||||
}
|
||||
|
||||
func (ie *IfdEnumerate) getTagEnumerator(ifdOffset uint32) (ite *IfdTagEnumerator) {
|
||||
ite = NewIfdTagEnumerator(
|
||||
func (ie *IfdEnumerate) getTagEnumerator(ifdOffset uint32) (enumerator *IfdTagEnumerator) {
|
||||
enumerator = NewIfdTagEnumerator(
|
||||
ie.exifData[ExifAddressableAreaStart:],
|
||||
ie.byteOrder,
|
||||
ifdOffset)
|
||||
|
||||
return ite
|
||||
return enumerator
|
||||
}
|
||||
|
||||
func (ie *IfdEnumerate) parseTag(fqIfdPath string, tagPosition int, enumerator *IfdTagEnumerator, resolveValue bool) (ite *IfdTagEntry, err error) {
|
||||
func (ie *IfdEnumerate) parseTag(fqIfdPath string, tagPosition int, enumerator *IfdTagEnumerator) (ite *IfdTagEntry, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
|
@ -176,51 +176,26 @@ func (ie *IfdEnumerate) parseTag(fqIfdPath string, tagPosition int, enumerator *
|
|||
ifdPath, err := ie.ifdMapping.StripPathPhraseIndices(fqIfdPath)
|
||||
log.PanicIf(err)
|
||||
|
||||
ite = &IfdTagEntry{
|
||||
IfdPath: ifdPath,
|
||||
TagId: tagId,
|
||||
TagIndex: tagPosition,
|
||||
TagType: tagType,
|
||||
UnitCount: unitCount,
|
||||
ValueOffset: valueOffset,
|
||||
RawValueOffset: rawValueOffset,
|
||||
}
|
||||
|
||||
if resolveValue == true {
|
||||
valueContext := ie.GetValueContext(ite)
|
||||
|
||||
if ite.TagType == exifcommon.TypeUndefined {
|
||||
value, err := exifundefined.Decode(valueContext)
|
||||
if err != nil {
|
||||
if err == exifcommon.ErrUnhandledUnknownTypedTag {
|
||||
ite.isUnhandledUnknown = true
|
||||
} else {
|
||||
log.Panic(err)
|
||||
}
|
||||
} else {
|
||||
encodeable := value.(exifundefined.EncodeableValue)
|
||||
|
||||
var err error
|
||||
|
||||
ite.value, _, err = exifundefined.Encode(encodeable, ie.byteOrder)
|
||||
log.PanicIf(err)
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
|
||||
ite.value, err = valueContext.ReadRawEncoded()
|
||||
log.PanicIf(err)
|
||||
}
|
||||
}
|
||||
ite = newIfdTagEntry(
|
||||
ifdPath,
|
||||
tagId,
|
||||
tagPosition,
|
||||
tagType,
|
||||
unitCount,
|
||||
valueOffset,
|
||||
rawValueOffset,
|
||||
ie.exifData[ExifAddressableAreaStart:],
|
||||
ie.byteOrder)
|
||||
|
||||
// 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
|
||||
// [likely] not even in the standard list of known tags.
|
||||
mi, err := ie.ifdMapping.GetChild(ifdPath, tagId)
|
||||
if err == nil {
|
||||
ite.ChildIfdName = mi.Name
|
||||
ite.ChildIfdPath = mi.PathPhrase()
|
||||
ite.ChildFqIfdPath = fmt.Sprintf("%s/%s", fqIfdPath, mi.Name)
|
||||
ite.SetChildIfd(
|
||||
fmt.Sprintf("%s/%s", fqIfdPath, mi.Name),
|
||||
mi.PathPhrase(),
|
||||
mi.Name)
|
||||
|
||||
// We also need to set `tag.ChildFqIfdPath` but can't do it here
|
||||
// because we don't have the IFD index.
|
||||
|
@ -231,18 +206,6 @@ func (ie *IfdEnumerate) parseTag(fqIfdPath string, tagPosition int, enumerator *
|
|||
return ite, nil
|
||||
}
|
||||
|
||||
func (ie *IfdEnumerate) GetValueContext(ite *IfdTagEntry) *exifcommon.ValueContext {
|
||||
|
||||
// TODO(dustin): Add test
|
||||
|
||||
addressableData := ie.exifData[ExifAddressableAreaStart:]
|
||||
|
||||
return newValueContextFromTag(
|
||||
ite,
|
||||
addressableData,
|
||||
ie.byteOrder)
|
||||
}
|
||||
|
||||
// RawTagWalk is an optional callback that can get hit for every tag we parse
|
||||
// through. `addressableData` is the byte array startign after the EXIF header
|
||||
// (where the offsets of all IFDs and values are calculated from).
|
||||
|
@ -255,25 +218,25 @@ type RawTagWalk interface {
|
|||
|
||||
// ParseIfd decodes the IFD block that we're currently sitting on the first
|
||||
// byte of.
|
||||
func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, ite *IfdTagEnumerator, visitor RawTagWalk, doDescend bool, resolveValues bool) (nextIfdOffset uint32, entries []*IfdTagEntry, thumbnailData []byte, err error) {
|
||||
func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, enumerator *IfdTagEnumerator, visitor RawTagWalk, doDescend bool) (nextIfdOffset uint32, entries []*IfdTagEntry, thumbnailData []byte, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
tagCount, _, err := ite.getUint16()
|
||||
tagCount, _, err := enumerator.getUint16()
|
||||
log.PanicIf(err)
|
||||
|
||||
ifdEnumerateLogger.Debugf(nil, "Current IFD tag-count: (%d)", tagCount)
|
||||
|
||||
entries = make([]*IfdTagEntry, 0)
|
||||
|
||||
var iteThumbnailOffset *IfdTagEntry
|
||||
var iteThumbnailSize *IfdTagEntry
|
||||
var enumeratorThumbnailOffset *IfdTagEntry
|
||||
var enumeratorThumbnailSize *IfdTagEntry
|
||||
|
||||
for i := 0; i < int(tagCount); i++ {
|
||||
tag, err := ie.parseTag(fqIfdPath, i, ite, resolveValues)
|
||||
ite, err := ie.parseTag(fqIfdPath, i, enumerator)
|
||||
if err != nil {
|
||||
if log.Is(err, ErrTagTypeNotValid) == true {
|
||||
ifdEnumerateLogger.Warningf(nil, "Tag in IFD [%s] at position (%d) has invalid type and will be skipped.", fqIfdPath, i)
|
||||
|
@ -283,43 +246,44 @@ func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, ite *IfdTagEnum
|
|||
log.Panic(err)
|
||||
}
|
||||
|
||||
if tag.TagId == ThumbnailOffsetTagId {
|
||||
iteThumbnailOffset = tag
|
||||
tagId := ite.TagId()
|
||||
if tagId == ThumbnailOffsetTagId {
|
||||
enumeratorThumbnailOffset = ite
|
||||
|
||||
continue
|
||||
} else if tag.TagId == ThumbnailSizeTagId {
|
||||
iteThumbnailSize = tag
|
||||
} else if tagId == ThumbnailSizeTagId {
|
||||
enumeratorThumbnailSize = ite
|
||||
continue
|
||||
}
|
||||
|
||||
if visitor != nil {
|
||||
valueContext := ie.GetValueContext(tag)
|
||||
valueContext := ite.GetValueContext()
|
||||
|
||||
err := visitor.Visit(fqIfdPath, ifdIndex, tag.TagId, tag.TagType, valueContext)
|
||||
err := visitor.Visit(fqIfdPath, ifdIndex, ite.TagId(), ite.TagType(), valueContext)
|
||||
log.PanicIf(err)
|
||||
}
|
||||
|
||||
// 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
|
||||
// [likely] not even in the standard list of known tags.
|
||||
if tag.ChildIfdPath != "" {
|
||||
if ite.ChildIfdPath() != "" {
|
||||
if doDescend == true {
|
||||
ifdEnumerateLogger.Debugf(nil, "Descending to IFD [%s].", tag.ChildIfdPath)
|
||||
ifdEnumerateLogger.Debugf(nil, "Descending to IFD [%s].", ite.ChildIfdPath())
|
||||
|
||||
err := ie.scan(tag.ChildFqIfdPath, tag.ValueOffset, visitor, resolveValues)
|
||||
err := ie.scan(ite.ChildFqIfdPath(), ite.valueOffset_(), visitor)
|
||||
log.PanicIf(err)
|
||||
}
|
||||
}
|
||||
|
||||
entries = append(entries, tag)
|
||||
entries = append(entries, ite)
|
||||
}
|
||||
|
||||
if iteThumbnailOffset != nil && iteThumbnailSize != nil {
|
||||
thumbnailData, err = ie.parseThumbnail(iteThumbnailOffset, iteThumbnailSize)
|
||||
if enumeratorThumbnailOffset != nil && enumeratorThumbnailSize != nil {
|
||||
thumbnailData, err = ie.parseThumbnail(enumeratorThumbnailOffset, enumeratorThumbnailSize)
|
||||
log.PanicIf(err)
|
||||
}
|
||||
|
||||
nextIfdOffset, _, err = ite.getUint32()
|
||||
nextIfdOffset, _, err = enumerator.getUint32()
|
||||
log.PanicIf(err)
|
||||
|
||||
ifdEnumerateLogger.Debugf(nil, "Next IFD at offset: (%08x)", nextIfdOffset)
|
||||
|
@ -334,9 +298,7 @@ func (ie *IfdEnumerate) parseThumbnail(offsetIte, lengthIte *IfdTagEntry) (thumb
|
|||
}
|
||||
}()
|
||||
|
||||
addressableData := ie.exifData[ExifAddressableAreaStart:]
|
||||
|
||||
vRaw, err := lengthIte.Value(addressableData, ie.byteOrder)
|
||||
vRaw, err := lengthIte.Value()
|
||||
log.PanicIf(err)
|
||||
|
||||
vList := vRaw.([]uint32)
|
||||
|
@ -347,17 +309,17 @@ func (ie *IfdEnumerate) parseThumbnail(offsetIte, lengthIte *IfdTagEntry) (thumb
|
|||
length := vList[0]
|
||||
|
||||
// The tag is official a LONG type, but it's actually an offset to a blob of bytes.
|
||||
offsetIte.TagType = exifcommon.TypeByte
|
||||
offsetIte.UnitCount = length
|
||||
offsetIte.updateTagType(exifcommon.TypeByte)
|
||||
offsetIte.updateUnitCount(length)
|
||||
|
||||
thumbnailData, err = offsetIte.ValueBytes(addressableData, ie.byteOrder)
|
||||
thumbnailData, err = offsetIte.RawBytes()
|
||||
log.PanicIf(err)
|
||||
|
||||
return thumbnailData, nil
|
||||
}
|
||||
|
||||
// Scan enumerates the different EXIF's IFD blocks.
|
||||
func (ie *IfdEnumerate) scan(fqIfdName string, ifdOffset uint32, visitor RawTagWalk, resolveValues bool) (err error) {
|
||||
func (ie *IfdEnumerate) scan(fqIfdName string, ifdOffset uint32, visitor RawTagWalk) (err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
|
@ -366,9 +328,9 @@ func (ie *IfdEnumerate) scan(fqIfdName string, ifdOffset uint32, visitor RawTagW
|
|||
|
||||
for ifdIndex := 0; ; ifdIndex++ {
|
||||
ifdEnumerateLogger.Debugf(nil, "Parsing IFD [%s] (%d) at offset (%04x).", fqIfdName, ifdIndex, ifdOffset)
|
||||
ite := ie.getTagEnumerator(ifdOffset)
|
||||
enumerator := ie.getTagEnumerator(ifdOffset)
|
||||
|
||||
nextIfdOffset, _, _, err := ie.ParseIfd(fqIfdName, ifdIndex, ite, visitor, true, resolveValues)
|
||||
nextIfdOffset, _, _, err := ie.ParseIfd(fqIfdName, ifdIndex, enumerator, visitor, true)
|
||||
log.PanicIf(err)
|
||||
|
||||
if nextIfdOffset == 0 {
|
||||
|
@ -383,14 +345,14 @@ func (ie *IfdEnumerate) scan(fqIfdName string, ifdOffset uint32, visitor RawTagW
|
|||
|
||||
// Scan enumerates the different EXIF blocks (called IFDs). `rootIfdName` will
|
||||
// be "IFD" in the TIFF standard.
|
||||
func (ie *IfdEnumerate) Scan(rootIfdName string, ifdOffset uint32, visitor RawTagWalk, resolveValue bool) (err error) {
|
||||
func (ie *IfdEnumerate) Scan(rootIfdName string, ifdOffset uint32, visitor RawTagWalk) (err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
err = ie.scan(rootIfdName, ifdOffset, visitor, resolveValue)
|
||||
err = ie.scan(rootIfdName, ifdOffset, visitor)
|
||||
log.PanicIf(err)
|
||||
|
||||
return nil
|
||||
|
@ -399,7 +361,8 @@ func (ie *IfdEnumerate) Scan(rootIfdName string, ifdOffset uint32, visitor RawTa
|
|||
// Ifd represents a single parsed IFD.
|
||||
type Ifd struct {
|
||||
|
||||
// TODO(dustin): !! Why are all of these public? Privatize them and then add NextIfd().
|
||||
// TODO(dustin): !! Why are all of these exported? Stop doing this in the next release.
|
||||
// TODO(dustin): Add NextIfd().
|
||||
|
||||
// This is just for convenience, just so that we can easily get the values
|
||||
// and not involve other projects in semantics that they won't otherwise
|
||||
|
@ -467,32 +430,6 @@ func (ifd *Ifd) ChildWithIfdPath(ifdPath string) (childIfd *Ifd, err error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (ifd *Ifd) TagValue(ite *IfdTagEntry) (value interface{}, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
value, err = ite.Value(ifd.addressableData, ifd.ByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (ifd *Ifd) TagValueBytes(ite *IfdTagEntry) (value []byte, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
value, err = ite.ValueBytes(ifd.addressableData, ifd.ByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// FindTagWithId returns a list of tags (usually just zero or one) that match
|
||||
// the given tag ID. This is efficient.
|
||||
func (ifd *Ifd) FindTagWithId(tagId uint16) (results []*IfdTagEntry, err error) {
|
||||
|
@ -528,7 +465,7 @@ func (ifd *Ifd) FindTagWithName(tagName string) (results []*IfdTagEntry, err err
|
|||
|
||||
results = make([]*IfdTagEntry, 0)
|
||||
for _, ite := range ifd.Entries {
|
||||
if ite.TagId == it.Id {
|
||||
if ite.TagId() == it.Id {
|
||||
results = append(results, ite)
|
||||
}
|
||||
}
|
||||
|
@ -540,7 +477,7 @@ func (ifd *Ifd) FindTagWithName(tagName string) (results []*IfdTagEntry, err err
|
|||
return results, nil
|
||||
}
|
||||
|
||||
func (ifd Ifd) String() string {
|
||||
func (ifd *Ifd) String() string {
|
||||
parentOffset := uint32(0)
|
||||
if ifd.ParentIfd != nil {
|
||||
parentOffset = ifd.ParentIfd.Offset
|
||||
|
@ -563,6 +500,7 @@ func (ifd *Ifd) Thumbnail() (data []byte, err error) {
|
|||
return ifd.thumbnailData, nil
|
||||
}
|
||||
|
||||
// dumpTags recursively builds a list of tags from an IFD.
|
||||
func (ifd *Ifd) dumpTags(tags []*IfdTagEntry) []*IfdTagEntry {
|
||||
if tags == nil {
|
||||
tags = make([]*IfdTagEntry, 0)
|
||||
|
@ -572,15 +510,16 @@ func (ifd *Ifd) dumpTags(tags []*IfdTagEntry) []*IfdTagEntry {
|
|||
|
||||
ifdsFoundCount := 0
|
||||
|
||||
for _, tag := range ifd.Entries {
|
||||
tags = append(tags, tag)
|
||||
for _, ite := range ifd.Entries {
|
||||
tags = append(tags, ite)
|
||||
|
||||
if tag.ChildIfdPath != "" {
|
||||
childIfdPath := ite.ChildIfdPath()
|
||||
if childIfdPath != "" {
|
||||
ifdsFoundCount++
|
||||
|
||||
childIfd, found := ifd.ChildIfdIndex[tag.ChildIfdPath]
|
||||
childIfd, found := ifd.ChildIfdIndex[childIfdPath]
|
||||
if found != true {
|
||||
log.Panicf("alien child IFD referenced by a tag: [%s]", tag.ChildIfdPath)
|
||||
log.Panicf("alien child IFD referenced by a tag: [%s]", childIfdPath)
|
||||
}
|
||||
|
||||
tags = childIfd.dumpTags(tags)
|
||||
|
@ -603,6 +542,50 @@ func (ifd *Ifd) DumpTags() []*IfdTagEntry {
|
|||
return ifd.dumpTags(nil)
|
||||
}
|
||||
|
||||
// FormatValue returns a stringified value for any well-defined tag value as
|
||||
// well as supported undefined-tag values.
|
||||
func (ifd *Ifd) FormatValue(ite *IfdTagEntry) (valuePhrase string, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
value, err := ite.Value()
|
||||
if err != nil {
|
||||
if err == exifcommon.ErrUnhandledUnknownTypedTag {
|
||||
return exifundefined.UnparseableUnknownTagValuePlaceholder, nil
|
||||
}
|
||||
|
||||
log.Panic(err)
|
||||
}
|
||||
|
||||
valuePhrase, err = exifcommon.FormatFromType(value, false)
|
||||
log.PanicIf(err)
|
||||
|
||||
return valuePhrase, nil
|
||||
}
|
||||
|
||||
// Value returns the value for the given tag.
|
||||
func (ifd *Ifd) Value(ite *IfdTagEntry) (value interface{}, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
value, err = ite.Value()
|
||||
if err != nil {
|
||||
if err == exifcommon.ErrUnhandledUnknownTypedTag {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Panic(err)
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (ifd *Ifd) printTagTree(populateValues bool, index, level int, nextLink bool) {
|
||||
indent := strings.Repeat(" ", level*2)
|
||||
|
||||
|
@ -617,40 +600,37 @@ func (ifd *Ifd) printTagTree(populateValues bool, index, level int, nextLink boo
|
|||
|
||||
ifdsFoundCount := 0
|
||||
|
||||
for _, tag := range ifd.Entries {
|
||||
if tag.ChildIfdPath != "" {
|
||||
fmt.Printf("%s - TAG: %s\n", indent, tag)
|
||||
for _, ite := range ifd.Entries {
|
||||
if ite.ChildIfdPath() != "" {
|
||||
fmt.Printf("%s - TAG: %s\n", indent, ite)
|
||||
} else {
|
||||
it, err := ifd.tagIndex.Get(ifd.IfdPath, tag.TagId)
|
||||
it, err := ifd.tagIndex.Get(ifd.IfdPath, ite.TagId())
|
||||
|
||||
tagName := ""
|
||||
if err == nil {
|
||||
tagName = it.Name
|
||||
}
|
||||
|
||||
var value interface{}
|
||||
var valuePhrase string
|
||||
if populateValues == true {
|
||||
var err error
|
||||
|
||||
value, err = ifd.TagValue(tag)
|
||||
if err != nil {
|
||||
if err == exifcommon.ErrUnhandledUnknownTypedTag {
|
||||
value = exifundefined.UnparseableUnknownTagValuePlaceholder
|
||||
} else {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
valuePhrase, err = ifd.FormatValue(ite)
|
||||
log.PanicIf(err)
|
||||
} else {
|
||||
valuePhrase = "!UNRESOLVED"
|
||||
}
|
||||
|
||||
fmt.Printf("%s - TAG: %s NAME=[%s] VALUE=[%v]\n", indent, tag, tagName, value)
|
||||
fmt.Printf("%s - TAG: %s NAME=[%s] VALUE=[%v]\n", indent, ite, tagName, valuePhrase)
|
||||
}
|
||||
|
||||
if tag.ChildIfdPath != "" {
|
||||
childIfdPath := ite.ChildIfdPath()
|
||||
if childIfdPath != "" {
|
||||
ifdsFoundCount++
|
||||
|
||||
childIfd, found := ifd.ChildIfdIndex[tag.ChildIfdPath]
|
||||
childIfd, found := ifd.ChildIfdIndex[childIfdPath]
|
||||
if found != true {
|
||||
log.Panicf("alien child IFD referenced by a tag: [%s]", tag.ChildIfdPath)
|
||||
log.Panicf("alien child IFD referenced by a tag: [%s]", childIfdPath)
|
||||
}
|
||||
|
||||
childIfd.printTagTree(populateValues, 0, level+1, false)
|
||||
|
@ -685,13 +665,14 @@ func (ifd *Ifd) printIfdTree(level int, nextLink bool) {
|
|||
|
||||
ifdsFoundCount := 0
|
||||
|
||||
for _, tag := range ifd.Entries {
|
||||
if tag.ChildIfdPath != "" {
|
||||
for _, ite := range ifd.Entries {
|
||||
childIfdPath := ite.ChildIfdPath()
|
||||
if childIfdPath != "" {
|
||||
ifdsFoundCount++
|
||||
|
||||
childIfd, found := ifd.ChildIfdIndex[tag.ChildIfdPath]
|
||||
childIfd, found := ifd.ChildIfdIndex[childIfdPath]
|
||||
if found != true {
|
||||
log.Panicf("alien child IFD referenced by a tag: [%s]", tag.ChildIfdPath)
|
||||
log.Panicf("alien child IFD referenced by a tag: [%s]", childIfdPath)
|
||||
}
|
||||
|
||||
childIfd.printIfdTree(level+1, false)
|
||||
|
@ -730,15 +711,16 @@ func (ifd *Ifd) dumpTree(tagsDump []string, level int) []string {
|
|||
tagsDump = append(tagsDump, startBlurb)
|
||||
|
||||
ifdsFoundCount := 0
|
||||
for _, tag := range ifd.Entries {
|
||||
tagsDump = append(tagsDump, fmt.Sprintf("%s - (0x%04x)", indent, tag.TagId))
|
||||
for _, ite := range ifd.Entries {
|
||||
tagsDump = append(tagsDump, fmt.Sprintf("%s - (0x%04x)", indent, ite.TagId()))
|
||||
|
||||
if tag.ChildIfdPath != "" {
|
||||
childIfdPath := ite.ChildIfdPath()
|
||||
if childIfdPath != "" {
|
||||
ifdsFoundCount++
|
||||
|
||||
childIfd, found := ifd.ChildIfdIndex[tag.ChildIfdPath]
|
||||
childIfd, found := ifd.ChildIfdIndex[childIfdPath]
|
||||
if found != true {
|
||||
log.Panicf("alien child IFD referenced by a tag: [%s]", tag.ChildIfdPath)
|
||||
log.Panicf("alien child IFD referenced by a tag: [%s]", childIfdPath)
|
||||
}
|
||||
|
||||
tagsDump = childIfd.dumpTree(tagsDump, level+1)
|
||||
|
@ -784,21 +766,24 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
|
|||
log.Panicf("GPS can only be read on GPS IFD: [%s] != [%s]", ifd.IfdPath, exifcommon.IfdPathStandardGps)
|
||||
}
|
||||
|
||||
if tags, found := ifd.EntriesByTagId[TagVersionId]; found == false {
|
||||
if tags, found := ifd.EntriesByTagId[TagGpsVersionId]; found == false {
|
||||
// We've seen this. We'll just have to default to assuming we're in a
|
||||
// 2.2.0.0 format.
|
||||
ifdEnumerateLogger.Warningf(nil, "No GPS version tag (0x%04x) found.", TagVersionId)
|
||||
ifdEnumerateLogger.Warningf(nil, "No GPS version tag (0x%04x) found.", TagGpsVersionId)
|
||||
} else {
|
||||
versionBytes, err := tags[0].RawBytes()
|
||||
log.PanicIf(err)
|
||||
|
||||
hit := false
|
||||
for _, acceptedGpsVersion := range ValidGpsVersions {
|
||||
if bytes.Compare(tags[0].value, acceptedGpsVersion[:]) == 0 {
|
||||
if bytes.Compare(versionBytes, acceptedGpsVersion[:]) == 0 {
|
||||
hit = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if hit != true {
|
||||
ifdEnumerateLogger.Warningf(nil, "GPS version not supported: %v", tags[0].value)
|
||||
ifdEnumerateLogger.Warningf(nil, "GPS version not supported: %v", versionBytes)
|
||||
log.Panic(ErrNoGpsTags)
|
||||
}
|
||||
}
|
||||
|
@ -809,7 +794,7 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
|
|||
log.Panic(ErrNoGpsTags)
|
||||
}
|
||||
|
||||
latitudeValue, err := ifd.TagValue(tags[0])
|
||||
latitudeValue, err := ifd.Value(tags[0])
|
||||
log.PanicIf(err)
|
||||
|
||||
// Look for whether North or South.
|
||||
|
@ -819,7 +804,7 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
|
|||
log.Panic(ErrNoGpsTags)
|
||||
}
|
||||
|
||||
latitudeRefValue, err := ifd.TagValue(tags[0])
|
||||
latitudeRefValue, err := ifd.Value(tags[0])
|
||||
log.PanicIf(err)
|
||||
|
||||
tags, found = ifd.EntriesByTagId[TagLongitudeId]
|
||||
|
@ -828,7 +813,7 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
|
|||
log.Panic(ErrNoGpsTags)
|
||||
}
|
||||
|
||||
longitudeValue, err := ifd.TagValue(tags[0])
|
||||
longitudeValue, err := ifd.Value(tags[0])
|
||||
log.PanicIf(err)
|
||||
|
||||
// Look for whether West or East.
|
||||
|
@ -838,7 +823,7 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
|
|||
log.Panic(ErrNoGpsTags)
|
||||
}
|
||||
|
||||
longitudeRefValue, err := ifd.TagValue(tags[0])
|
||||
longitudeRefValue, err := ifd.Value(tags[0])
|
||||
log.PanicIf(err)
|
||||
|
||||
// Parse location.
|
||||
|
@ -867,10 +852,10 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
|
|||
altitudeRefTags, foundAltitudeRef := ifd.EntriesByTagId[TagAltitudeRefId]
|
||||
|
||||
if foundAltitude == true && foundAltitudeRef == true {
|
||||
altitudeValue, err := ifd.TagValue(altitudeTags[0])
|
||||
altitudeValue, err := ifd.Value(altitudeTags[0])
|
||||
log.PanicIf(err)
|
||||
|
||||
altitudeRefValue, err := ifd.TagValue(altitudeRefTags[0])
|
||||
altitudeRefValue, err := ifd.Value(altitudeRefTags[0])
|
||||
log.PanicIf(err)
|
||||
|
||||
altitudeRaw := altitudeValue.([]exifcommon.Rational)
|
||||
|
@ -888,7 +873,7 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
|
|||
datestampTags, foundDatestamp := ifd.EntriesByTagId[TagDatestampId]
|
||||
|
||||
if foundTimestamp == true && foundDatestamp == true {
|
||||
datestampValue, err := ifd.TagValue(datestampTags[0])
|
||||
datestampValue, err := ifd.Value(datestampTags[0])
|
||||
log.PanicIf(err)
|
||||
|
||||
dateParts := strings.Split(datestampValue.(string), ":")
|
||||
|
@ -898,7 +883,7 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
|
|||
day, err3 := strconv.ParseUint(dateParts[2], 10, 8)
|
||||
|
||||
if err1 == nil && err2 == nil && err3 == nil {
|
||||
timestampValue, err := ifd.TagValue(timestampTags[0])
|
||||
timestampValue, err := ifd.Value(timestampTags[0])
|
||||
log.PanicIf(err)
|
||||
|
||||
timestampRaw := timestampValue.([]exifcommon.Rational)
|
||||
|
@ -925,8 +910,9 @@ func (ifd *Ifd) EnumerateTagsRecursively(visitor ParsedTagVisitor) (err error) {
|
|||
|
||||
for ptr := ifd; ptr != nil; ptr = ptr.NextIfd {
|
||||
for _, ite := range ifd.Entries {
|
||||
if ite.ChildIfdPath != "" {
|
||||
childIfd := ifd.ChildIfdIndex[ite.ChildIfdPath]
|
||||
childIfdPath := ite.ChildIfdPath()
|
||||
if childIfdPath != "" {
|
||||
childIfd := ifd.ChildIfdIndex[childIfdPath]
|
||||
|
||||
err := childIfd.EnumerateTagsRecursively(visitor)
|
||||
log.PanicIf(err)
|
||||
|
@ -940,13 +926,6 @@ func (ifd *Ifd) EnumerateTagsRecursively(visitor ParsedTagVisitor) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (ifd *Ifd) GetValueContext(ite *IfdTagEntry) *exifcommon.ValueContext {
|
||||
return newValueContextFromTag(
|
||||
ite,
|
||||
ifd.addressableData,
|
||||
ifd.ByteOrder)
|
||||
}
|
||||
|
||||
type QueuedIfd struct {
|
||||
Name string
|
||||
IfdPath string
|
||||
|
@ -972,7 +951,7 @@ type IfdIndex struct {
|
|||
}
|
||||
|
||||
// Scan enumerates the different EXIF blocks (called IFDs).
|
||||
func (ie *IfdEnumerate) Collect(rootIfdOffset uint32, resolveValues bool) (index IfdIndex, err error) {
|
||||
func (ie *IfdEnumerate) Collect(rootIfdOffset uint32) (index IfdIndex, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
|
@ -1016,21 +995,23 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32, resolveValues bool) (index
|
|||
queue = queue[1:]
|
||||
|
||||
ifdEnumerateLogger.Debugf(nil, "Parsing IFD [%s] (%d) at offset (%04x).", ifdPath, index, offset)
|
||||
ite := ie.getTagEnumerator(offset)
|
||||
enumerator := ie.getTagEnumerator(offset)
|
||||
|
||||
nextIfdOffset, entries, thumbnailData, err := ie.ParseIfd(fqIfdPath, index, ite, nil, false, resolveValues)
|
||||
nextIfdOffset, entries, thumbnailData, err := ie.ParseIfd(fqIfdPath, index, enumerator, nil, false)
|
||||
log.PanicIf(err)
|
||||
|
||||
id := len(ifds)
|
||||
|
||||
entriesByTagId := make(map[uint16][]*IfdTagEntry)
|
||||
for _, tag := range entries {
|
||||
tags, found := entriesByTagId[tag.TagId]
|
||||
for _, ite := range entries {
|
||||
tagId := ite.TagId()
|
||||
|
||||
tags, found := entriesByTagId[tagId]
|
||||
if found == false {
|
||||
tags = make([]*IfdTagEntry, 0)
|
||||
}
|
||||
|
||||
entriesByTagId[tag.TagId] = append(tags, tag)
|
||||
entriesByTagId[tagId] = append(tags, ite)
|
||||
}
|
||||
|
||||
ifd := &Ifd{
|
||||
|
@ -1093,19 +1074,19 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32, resolveValues bool) (index
|
|||
}
|
||||
|
||||
// Determine if any of our entries is a child IFD and queue it.
|
||||
for i, entry := range entries {
|
||||
if entry.ChildIfdPath == "" {
|
||||
for i, ite := range entries {
|
||||
if ite.ChildIfdPath() == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
qi := QueuedIfd{
|
||||
Name: entry.ChildIfdName,
|
||||
IfdPath: entry.ChildIfdPath,
|
||||
FqIfdPath: entry.ChildFqIfdPath,
|
||||
TagId: entry.TagId,
|
||||
Name: ite.ChildIfdName(),
|
||||
IfdPath: ite.ChildIfdPath(),
|
||||
FqIfdPath: ite.ChildFqIfdPath(),
|
||||
TagId: ite.TagId(),
|
||||
|
||||
Index: 0,
|
||||
Offset: entry.ValueOffset,
|
||||
Offset: ite.valueOffset_(),
|
||||
Parent: ifd,
|
||||
ParentTagIndex: i,
|
||||
}
|
||||
|
@ -1175,7 +1156,7 @@ func (ie *IfdEnumerate) setChildrenIndex(ifd *Ifd) (err error) {
|
|||
|
||||
// ParseOneIfd is a hack to use an IE to parse a raw IFD block. Can be used for
|
||||
// testing.
|
||||
func ParseOneIfd(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath, ifdPath string, byteOrder binary.ByteOrder, ifdBlock []byte, visitor RawTagWalk, resolveValues bool) (nextIfdOffset uint32, entries []*IfdTagEntry, err error) {
|
||||
func ParseOneIfd(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath, ifdPath string, byteOrder binary.ByteOrder, ifdBlock []byte, visitor RawTagWalk) (nextIfdOffset uint32, entries []*IfdTagEntry, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
|
@ -1183,16 +1164,16 @@ func ParseOneIfd(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath, ifdPath
|
|||
}()
|
||||
|
||||
ie := NewIfdEnumerate(ifdMapping, tagIndex, make([]byte, 0), byteOrder)
|
||||
ite := NewIfdTagEnumerator(ifdBlock, byteOrder, 0)
|
||||
enumerator := NewIfdTagEnumerator(ifdBlock, byteOrder, 0)
|
||||
|
||||
nextIfdOffset, entries, _, err = ie.ParseIfd(fqIfdPath, 0, ite, visitor, true, resolveValues)
|
||||
nextIfdOffset, entries, _, err = ie.ParseIfd(fqIfdPath, 0, enumerator, visitor, true)
|
||||
log.PanicIf(err)
|
||||
|
||||
return nextIfdOffset, entries, nil
|
||||
}
|
||||
|
||||
// ParseOneTag is a hack to use an IE to parse a raw tag block.
|
||||
func ParseOneTag(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath, ifdPath string, byteOrder binary.ByteOrder, tagBlock []byte, resolveValue bool) (tag *IfdTagEntry, err error) {
|
||||
func ParseOneTag(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath, ifdPath string, byteOrder binary.ByteOrder, tagBlock []byte) (tag *IfdTagEntry, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
|
@ -1200,9 +1181,9 @@ func ParseOneTag(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath, ifdPath
|
|||
}()
|
||||
|
||||
ie := NewIfdEnumerate(ifdMapping, tagIndex, make([]byte, 0), byteOrder)
|
||||
ite := NewIfdTagEnumerator(tagBlock, byteOrder, 0)
|
||||
enumerator := NewIfdTagEnumerator(tagBlock, byteOrder, 0)
|
||||
|
||||
tag, err = ie.parseTag(fqIfdPath, 0, ite, resolveValue)
|
||||
tag, err = ie.parseTag(fqIfdPath, 0, enumerator)
|
||||
log.PanicIf(err)
|
||||
|
||||
return tag, nil
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
@ -15,34 +14,7 @@ import (
|
|||
"github.com/dsoprea/go-exif/v2/common"
|
||||
)
|
||||
|
||||
func TestIfdTagEntry_ValueBytes(t *testing.T) {
|
||||
byteOrder := binary.BigEndian
|
||||
ve := exifcommon.NewValueEncoder(byteOrder)
|
||||
|
||||
original := []byte("original text")
|
||||
|
||||
ed, err := ve.Encode(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: exifcommon.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) {
|
||||
func TestIfdTagEntry_RawBytes_RealData(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
|
@ -60,12 +32,12 @@ func TestIfdTagEntry_ValueBytes_RealData(t *testing.T) {
|
|||
|
||||
ti := NewTagIndex()
|
||||
|
||||
eh, index, err := Collect(im, ti, rawExif)
|
||||
_, index, err := Collect(im, ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
var ite *IfdTagEntry
|
||||
for _, thisIte := range index.RootIfd.Entries {
|
||||
if thisIte.TagId == 0x0110 {
|
||||
if thisIte.TagId() == 0x0110 {
|
||||
ite = thisIte
|
||||
break
|
||||
}
|
||||
|
@ -75,14 +47,13 @@ func TestIfdTagEntry_ValueBytes_RealData(t *testing.T) {
|
|||
t.Fatalf("Tag not found.")
|
||||
}
|
||||
|
||||
addressableData := rawExif[ExifAddressableAreaStart:]
|
||||
decodedBytes, err := ite.ValueBytes(addressableData, eh.ByteOrder)
|
||||
decodedBytes, err := ite.RawBytes()
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := []byte("Canon EOS 5D Mark III")
|
||||
expected = append(expected, 0)
|
||||
|
||||
if len(decodedBytes) != int(ite.UnitCount) {
|
||||
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.")
|
||||
|
@ -108,7 +79,7 @@ func TestIfd_FindTagWithId_Hit(t *testing.T) {
|
|||
|
||||
if len(results) != 1 {
|
||||
t.Fatalf("Exactly one result was not found: (%d)", len(results))
|
||||
} else if results[0].TagId != 0x011b {
|
||||
} else if results[0].TagId() != 0x011b {
|
||||
t.Fatalf("The result was not expected: %v", results[0])
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +127,7 @@ func TestIfd_FindTagWithName_Hit(t *testing.T) {
|
|||
|
||||
if len(results) != 1 {
|
||||
t.Fatalf("Exactly one result was not found: (%d)", len(results))
|
||||
} else if results[0].TagId != 0x011b {
|
||||
} else if results[0].TagId() != 0x011b {
|
||||
t.Fatalf("The result was not expected: %v", results[0])
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +275,7 @@ func TestIfd_EnumerateTagsRecursively(t *testing.T) {
|
|||
cb := func(ifd *Ifd, ite *IfdTagEntry) error {
|
||||
item := [2]interface{}{
|
||||
ifd.IfdPath,
|
||||
int(ite.TagId),
|
||||
int(ite.TagId()),
|
||||
}
|
||||
|
||||
collected = append(collected, item)
|
||||
|
@ -512,8 +483,10 @@ func ExampleIfd_FindTagWithName() {
|
|||
|
||||
tagName := "Model"
|
||||
|
||||
rootIfd := index.RootIfd
|
||||
|
||||
// We know the tag we want is on IFD0 (the first/root IFD).
|
||||
results, err := index.RootIfd.FindTagWithName(tagName)
|
||||
results, err := rootIfd.FindTagWithName(tagName)
|
||||
log.PanicIf(err)
|
||||
|
||||
// This should never happen.
|
||||
|
@ -522,8 +495,9 @@ func ExampleIfd_FindTagWithName() {
|
|||
}
|
||||
|
||||
ite := results[0]
|
||||
valueContext := ite.GetValueContext()
|
||||
|
||||
valueRaw, err := index.RootIfd.TagValue(ite)
|
||||
valueRaw, err := valueContext.Values()
|
||||
log.PanicIf(err)
|
||||
|
||||
value := valueRaw.(string)
|
||||
|
|
|
@ -15,141 +15,144 @@ var (
|
|||
iteLogger = log.NewLogger("exif.ifd_tag_entry")
|
||||
)
|
||||
|
||||
// IfdTagEntry refers to a tag in the loaded EXIF block.
|
||||
type IfdTagEntry struct {
|
||||
TagId uint16
|
||||
TagIndex int
|
||||
TagType exifcommon.TagTypePrimitive
|
||||
UnitCount uint32
|
||||
ValueOffset uint32
|
||||
RawValueOffset []byte
|
||||
tagId uint16
|
||||
tagIndex int
|
||||
tagType exifcommon.TagTypePrimitive
|
||||
unitCount uint32
|
||||
valueOffset uint32
|
||||
rawValueOffset []byte
|
||||
|
||||
// ChildIfdName is the right most atom in the IFD-path. We need this to
|
||||
// childIfdName is the right most atom in the IFD-path. We need this to
|
||||
// construct the fully-qualified IFD-path.
|
||||
ChildIfdName string
|
||||
childIfdName string
|
||||
|
||||
// ChildIfdPath is the IFD-path of the child if this tag represents a child
|
||||
// childIfdPath is the IFD-path of the child if this tag represents a child
|
||||
// IFD.
|
||||
ChildIfdPath string
|
||||
childIfdPath string
|
||||
|
||||
// ChildFqIfdPath is the IFD-path of the child if this tag represents a
|
||||
// childFqIfdPath is the IFD-path of the child if this tag represents a
|
||||
// child IFD. Includes indices.
|
||||
ChildFqIfdPath string
|
||||
childFqIfdPath string
|
||||
|
||||
// TODO(dustin): !! IB's host the child-IBs directly in the tag, but that's not the case here. Refactor to accomodate it for a consistent experience.
|
||||
|
||||
// IfdPath is the IFD that this tag belongs to.
|
||||
IfdPath string
|
||||
// ifdPath is the IFD that this tag belongs to.
|
||||
ifdPath string
|
||||
|
||||
// TODO(dustin): !! We now parse and read the value immediately. Update the rest of the logic to use this and get rid of all of the staggered and different resolution mechanisms.
|
||||
value []byte
|
||||
isUnhandledUnknown bool
|
||||
|
||||
addressableData []byte
|
||||
byteOrder binary.ByteOrder
|
||||
}
|
||||
|
||||
func (ite *IfdTagEntry) String() string {
|
||||
return fmt.Sprintf("IfdTagEntry<TAG-IFD-PATH=[%s] TAG-ID=(0x%04x) TAG-TYPE=[%s] UNIT-COUNT=(%d)>", ite.IfdPath, ite.TagId, ite.TagType.String(), ite.UnitCount)
|
||||
}
|
||||
|
||||
// TODO(dustin): TODO(dustin): Stop exporting IfdPath and TagId.
|
||||
//
|
||||
// func (ite *IfdTagEntry) IfdPath() string {
|
||||
// return ite.IfdPath
|
||||
// }
|
||||
|
||||
// TODO(dustin): TODO(dustin): Stop exporting IfdPath and TagId.
|
||||
//
|
||||
// func (ite *IfdTagEntry) TagId() uint16 {
|
||||
// return ite.TagId
|
||||
// }
|
||||
|
||||
// ValueString renders a string from whatever the value in this tag is.
|
||||
func (ite *IfdTagEntry) ValueString(addressableData []byte, byteOrder binary.ByteOrder) (phrase string, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
valueContext :=
|
||||
newValueContextFromTag(
|
||||
ite,
|
||||
addressableData,
|
||||
byteOrder)
|
||||
|
||||
if ite.TagType == exifcommon.TypeUndefined {
|
||||
var err error
|
||||
|
||||
value, err := exifundefined.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
|
||||
s := value.(fmt.Stringer)
|
||||
|
||||
phrase = s.String()
|
||||
} else {
|
||||
var err error
|
||||
|
||||
phrase, err = valueContext.Format()
|
||||
log.PanicIf(err)
|
||||
func newIfdTagEntry(ifdPath string, tagId uint16, tagIndex int, tagType exifcommon.TagTypePrimitive, unitCount uint32, valueOffset uint32, rawValueOffset []byte, addressableData []byte, byteOrder binary.ByteOrder) *IfdTagEntry {
|
||||
return &IfdTagEntry{
|
||||
ifdPath: ifdPath,
|
||||
tagId: tagId,
|
||||
tagIndex: tagIndex,
|
||||
tagType: tagType,
|
||||
unitCount: unitCount,
|
||||
valueOffset: valueOffset,
|
||||
rawValueOffset: rawValueOffset,
|
||||
addressableData: addressableData,
|
||||
byteOrder: byteOrder,
|
||||
}
|
||||
|
||||
return phrase, nil
|
||||
}
|
||||
|
||||
// ValueBytes renders a specific list of bytes from the value in this tag.
|
||||
func (ite *IfdTagEntry) ValueBytes(addressableData []byte, byteOrder binary.ByteOrder) (value []byte, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
// String returns a stringified representation of the struct.
|
||||
func (ite *IfdTagEntry) String() string {
|
||||
return fmt.Sprintf("IfdTagEntry<TAG-IFD-PATH=[%s] TAG-ID=(0x%04x) TAG-TYPE=[%s] UNIT-COUNT=(%d)>", ite.ifdPath, ite.tagId, ite.tagType.String(), ite.unitCount)
|
||||
}
|
||||
|
||||
valueContext :=
|
||||
newValueContextFromTag(
|
||||
ite,
|
||||
addressableData,
|
||||
byteOrder)
|
||||
// IfdPath returns the path of the IFD that owns this tag.
|
||||
func (ite *IfdTagEntry) IfdPath() string {
|
||||
return ite.ifdPath
|
||||
}
|
||||
|
||||
// Return the exact bytes of the unknown-type value. Returning a string
|
||||
// (`ValueString`) is easy because we can just pass everything to
|
||||
// `Sprintf()`. Returning the raw, typed value (`Value`) is easy
|
||||
// (obviously). However, here, in order to produce the list of bytes, we
|
||||
// need to coerce whatever `Undefined()` returns.
|
||||
if ite.TagType == exifcommon.TypeUndefined {
|
||||
// TagId returns the ID of the tag that we represent. The combination of
|
||||
// (IfdPath(), TagId()) is unique.
|
||||
func (ite *IfdTagEntry) TagId() uint16 {
|
||||
return ite.tagId
|
||||
}
|
||||
|
||||
// TagType is the type of value for this tag.
|
||||
func (ite *IfdTagEntry) TagType() exifcommon.TagTypePrimitive {
|
||||
return ite.tagType
|
||||
}
|
||||
|
||||
// updateTagType sets an alternatively interpreted tag-type.
|
||||
func (ite *IfdTagEntry) updateTagType(tagType exifcommon.TagTypePrimitive) {
|
||||
ite.tagType = tagType
|
||||
}
|
||||
|
||||
// UnitCount returns the unit-count of the tag's value.
|
||||
func (ite *IfdTagEntry) UnitCount() uint32 {
|
||||
return ite.unitCount
|
||||
}
|
||||
|
||||
// updateUnitCount sets an alternatively interpreted unit-count.
|
||||
func (ite *IfdTagEntry) updateUnitCount(unitCount uint32) {
|
||||
ite.unitCount = unitCount
|
||||
}
|
||||
|
||||
// valueOffset_ is the four-byte offset converted to an integer to point to the
|
||||
// location of its value in the EXIF block.
|
||||
func (ite *IfdTagEntry) valueOffset_() uint32 {
|
||||
return ite.valueOffset
|
||||
}
|
||||
|
||||
// RawBytes renders a specific list of bytes from the value in this tag.
|
||||
func (ite *IfdTagEntry) RawBytes() (rawBytes []byte, err error) {
|
||||
valueContext := ite.GetValueContext()
|
||||
|
||||
if ite.TagType() == exifcommon.TypeUndefined {
|
||||
value, err := exifundefined.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
if err != nil {
|
||||
if err == exifcommon.ErrUnhandledUnknownTypedTag {
|
||||
ite.setIsUnhandledUnknown(true)
|
||||
} else {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
ve := exifcommon.NewValueEncoder(byteOrder)
|
||||
// Encode it back, in order to get the raw bytes. This is the best,
|
||||
// general way to do it with an undefined tag.
|
||||
|
||||
ed, err := ve.Encode(value)
|
||||
log.PanicIf(err)
|
||||
|
||||
return ed.Encoded, nil
|
||||
} else {
|
||||
rawBytes, err := valueContext.ReadRawEncoded()
|
||||
rawBytes, _, err := exifundefined.Encode(value, ite.byteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
return rawBytes, nil
|
||||
}
|
||||
|
||||
rawBytes, err = valueContext.ReadRawEncoded()
|
||||
log.PanicIf(err)
|
||||
|
||||
return rawBytes, nil
|
||||
}
|
||||
|
||||
// Value returns the specific, parsed, typed value from the tag.
|
||||
func (ite *IfdTagEntry) Value(addressableData []byte, byteOrder binary.ByteOrder) (value interface{}, err error) {
|
||||
func (ite *IfdTagEntry) Value() (value interface{}, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
valueContext :=
|
||||
newValueContextFromTag(
|
||||
ite,
|
||||
addressableData,
|
||||
byteOrder)
|
||||
valueContext := ite.GetValueContext()
|
||||
|
||||
if ite.TagType == exifcommon.TypeUndefined {
|
||||
if ite.tagType == exifcommon.TypeUndefined {
|
||||
var err error
|
||||
|
||||
value, err = exifundefined.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
if err != nil {
|
||||
if err == exifcommon.ErrUnhandledUnknownTypedTag {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Panic(err)
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
|
||||
|
@ -159,3 +162,38 @@ func (ite *IfdTagEntry) Value(addressableData []byte, byteOrder binary.ByteOrder
|
|||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (ite *IfdTagEntry) setIsUnhandledUnknown(isUnhandledUnknown bool) {
|
||||
ite.isUnhandledUnknown = isUnhandledUnknown
|
||||
}
|
||||
|
||||
// SetChildIfd sets child-IFD information (if we represent a child IFD).
|
||||
func (ite *IfdTagEntry) SetChildIfd(childFqIfdPath, childIfdPath, childIfdName string) {
|
||||
ite.childFqIfdPath = childFqIfdPath
|
||||
ite.childIfdPath = childIfdPath
|
||||
ite.childIfdName = childIfdName
|
||||
}
|
||||
|
||||
func (ite *IfdTagEntry) ChildIfdName() string {
|
||||
return ite.childIfdName
|
||||
}
|
||||
|
||||
func (ite *IfdTagEntry) ChildIfdPath() string {
|
||||
return ite.childIfdPath
|
||||
}
|
||||
|
||||
func (ite *IfdTagEntry) ChildFqIfdPath() string {
|
||||
return ite.childFqIfdPath
|
||||
}
|
||||
|
||||
func (ite *IfdTagEntry) GetValueContext() *exifcommon.ValueContext {
|
||||
return exifcommon.NewValueContext(
|
||||
ite.ifdPath,
|
||||
ite.tagId,
|
||||
ite.unitCount,
|
||||
ite.valueOffset,
|
||||
ite.rawValueOffset,
|
||||
ite.addressableData,
|
||||
ite.tagType,
|
||||
ite.byteOrder)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package exif
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
@ -10,51 +9,31 @@ import (
|
|||
"github.com/dsoprea/go-exif/v2/common"
|
||||
)
|
||||
|
||||
func TestIfdTagEntry_ValueString_Allocated(t *testing.T) {
|
||||
ite := IfdTagEntry{
|
||||
TagId: 0x1,
|
||||
TagIndex: 0,
|
||||
TagType: exifcommon.TypeByte,
|
||||
UnitCount: 6,
|
||||
ValueOffset: 0x0,
|
||||
RawValueOffset: []byte{0x0, 0x0, 0x0, 0x0},
|
||||
IfdPath: exifcommon.IfdPathStandard,
|
||||
}
|
||||
|
||||
func TestIfdTagEntry_RawBytes_Allocated(t *testing.T) {
|
||||
data := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
|
||||
|
||||
value, err := ite.ValueString(data, exifcommon.TestDefaultByteOrder)
|
||||
addressableBytes := data
|
||||
|
||||
ite := newIfdTagEntry(
|
||||
exifcommon.IfdPathStandard,
|
||||
0x1,
|
||||
0,
|
||||
exifcommon.TypeByte,
|
||||
6,
|
||||
0,
|
||||
nil,
|
||||
addressableBytes,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
value, err := ite.RawBytes()
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := "11 22 33 44 55 66"
|
||||
if value != expected {
|
||||
t.Fatalf("Value not expected: [%s] != [%s]", value, expected)
|
||||
if bytes.Compare(value, data) != 0 {
|
||||
t.Fatalf("Value not expected: [%s] != [%s]", value, data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagEntry_ValueString_Embedded(t *testing.T) {
|
||||
data := []byte{0x11, 0x22, 0x33, 0x44}
|
||||
|
||||
ite := IfdTagEntry{
|
||||
TagId: 0x1,
|
||||
TagIndex: 0,
|
||||
TagType: exifcommon.TypeByte,
|
||||
UnitCount: 4,
|
||||
ValueOffset: 0,
|
||||
RawValueOffset: data,
|
||||
IfdPath: exifcommon.IfdPathStandard,
|
||||
}
|
||||
|
||||
value, err := ite.ValueString(nil, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := "11 22 33 44"
|
||||
if value != expected {
|
||||
t.Fatalf("Value not expected: [%s] != [%s]", value, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagEntry_ValueString_Undefined(t *testing.T) {
|
||||
func TestIfdTagEntry_RawBytes_Embedded(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
|
@ -64,124 +43,38 @@ func TestIfdTagEntry_ValueString_Undefined(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
data := []uint8{'0', '2', '3', '0'}
|
||||
data := []byte{0x11, 0x22, 0x33, 0x44}
|
||||
|
||||
ite := IfdTagEntry{
|
||||
TagId: 0x9000,
|
||||
TagIndex: 0,
|
||||
TagType: exifcommon.TypeUndefined,
|
||||
UnitCount: 4,
|
||||
ValueOffset: 0x0,
|
||||
RawValueOffset: data,
|
||||
IfdPath: exifcommon.IfdPathStandardExif,
|
||||
}
|
||||
ite := newIfdTagEntry(
|
||||
exifcommon.IfdPathStandard,
|
||||
0x1,
|
||||
0,
|
||||
exifcommon.TypeByte,
|
||||
4,
|
||||
0,
|
||||
data,
|
||||
nil,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
value, err := ite.ValueString(nil, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := "0230"
|
||||
if value != expected {
|
||||
t.Fatalf("Value not expected: [%s] != [%s]", value, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagEntry_ValueBytes_Allocated(t *testing.T) {
|
||||
ite := IfdTagEntry{
|
||||
TagId: 0x1,
|
||||
TagIndex: 0,
|
||||
TagType: exifcommon.TypeByte,
|
||||
UnitCount: 6,
|
||||
ValueOffset: 0x0,
|
||||
RawValueOffset: []byte{0x0, 0x0, 0x0, 0x0},
|
||||
IfdPath: exifcommon.IfdPathStandard,
|
||||
}
|
||||
|
||||
data := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
|
||||
|
||||
value, err := ite.ValueBytes(data, exifcommon.TestDefaultByteOrder)
|
||||
value, err := ite.RawBytes()
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(value, data) != 0 {
|
||||
t.Fatalf("Value not expected: [%s] != [%s]", value, data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagEntry_ValueBytes_Embedded(t *testing.T) {
|
||||
data := []byte{0x11, 0x22, 0x33, 0x44}
|
||||
|
||||
ite := IfdTagEntry{
|
||||
TagId: 0x1,
|
||||
TagIndex: 0,
|
||||
TagType: exifcommon.TypeByte,
|
||||
UnitCount: 4,
|
||||
ValueOffset: 0x0,
|
||||
RawValueOffset: data,
|
||||
IfdPath: exifcommon.IfdPathStandard,
|
||||
}
|
||||
|
||||
value, err := ite.ValueBytes(nil, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(value, data) != 0 {
|
||||
t.Fatalf("Value not expected: [%s] != [%s]", value, data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagEntry_Value_Normal(t *testing.T) {
|
||||
data := []byte{0x11, 0x22, 0x33, 0x44}
|
||||
|
||||
ite := IfdTagEntry{
|
||||
TagId: 0x1,
|
||||
TagIndex: 0,
|
||||
TagType: exifcommon.TypeByte,
|
||||
UnitCount: 4,
|
||||
ValueOffset: 0x0,
|
||||
RawValueOffset: data,
|
||||
IfdPath: exifcommon.IfdPathStandard,
|
||||
}
|
||||
|
||||
value, err := ite.Value(nil, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(value.([]byte), data) != 0 {
|
||||
t.Fatalf("Value not expected: [%s] != [%s]", value, data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagEntry_Value_Undefined(t *testing.T) {
|
||||
data := []uint8{'0', '2', '3', '0'}
|
||||
|
||||
ite := IfdTagEntry{
|
||||
TagId: 0x9000,
|
||||
TagIndex: 0,
|
||||
TagType: exifcommon.TypeUndefined,
|
||||
UnitCount: 4,
|
||||
ValueOffset: 0x0,
|
||||
RawValueOffset: data,
|
||||
IfdPath: exifcommon.IfdPathStandardExif,
|
||||
}
|
||||
|
||||
value, err := ite.Value(nil, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
s := value.(fmt.Stringer)
|
||||
recovered := []byte(s.String())
|
||||
|
||||
if bytes.Compare(recovered, data) != 0 {
|
||||
t.Fatalf("Value not expected: [%s] != [%s]", recovered, data)
|
||||
t.Fatalf("Value not expected: %v != %v", value, data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfdTagEntry_String(t *testing.T) {
|
||||
ite := IfdTagEntry{
|
||||
TagId: 0x1,
|
||||
TagIndex: 0,
|
||||
TagType: exifcommon.TypeByte,
|
||||
UnitCount: 6,
|
||||
ValueOffset: 0x0,
|
||||
RawValueOffset: []byte{0x0, 0x0, 0x0, 0x0},
|
||||
IfdPath: exifcommon.IfdPathStandard,
|
||||
}
|
||||
ite := newIfdTagEntry(
|
||||
exifcommon.IfdPathStandard,
|
||||
0x1,
|
||||
0,
|
||||
exifcommon.TypeByte,
|
||||
6,
|
||||
0,
|
||||
nil,
|
||||
nil,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
expected := "IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x0001) TAG-TYPE=[BYTE] UNIT-COUNT=(6)>"
|
||||
if ite.String() != expected {
|
||||
|
|
|
@ -17,7 +17,7 @@ const (
|
|||
|
||||
// Exif
|
||||
|
||||
TagVersionId = 0x0000
|
||||
TagGpsVersionId = 0x0000
|
||||
|
||||
TagLatitudeId = 0x0002
|
||||
TagLatitudeRefId = 0x0001
|
||||
|
|
|
@ -135,8 +135,6 @@ func validateExifSimpleTestIb(exifData []byte, t *testing.T) {
|
|||
|
||||
// Verify the values by using the actual, orginal types (this is awesome).
|
||||
|
||||
addressableData := exifData[ExifAddressableAreaStart:]
|
||||
|
||||
expected := []struct {
|
||||
tagId uint16
|
||||
value interface{}
|
||||
|
@ -147,12 +145,12 @@ func validateExifSimpleTestIb(exifData []byte, t *testing.T) {
|
|||
{tagId: 0x013e, value: []exifcommon.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)
|
||||
for i, ite := range ifd.Entries {
|
||||
if ite.TagId() != expected[i].tagId {
|
||||
t.Fatalf("Tag-ID for entry (%d) not correct: (0x%02x) != (0x%02x)", i, ite.TagId(), expected[i].tagId)
|
||||
}
|
||||
|
||||
value, err := e.Value(addressableData, exifcommon.TestDefaultByteOrder)
|
||||
value, err := ite.Value()
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, expected[i].value) != true {
|
||||
|
|
|
@ -116,7 +116,7 @@ func GetFlatExifData(exifData []byte) (exifTags []ExifTag, err error) {
|
|||
for _, ite := range ifd.Entries {
|
||||
tagName := ""
|
||||
|
||||
it, err := ti.Get(ifd.IfdPath, ite.TagId)
|
||||
it, err := ti.Get(ifd.IfdPath, ite.TagId())
|
||||
if err != nil {
|
||||
// If it's a non-standard tag, just leave the name blank.
|
||||
if log.Is(err, ErrTagNotFound) != true {
|
||||
|
@ -126,7 +126,12 @@ func GetFlatExifData(exifData []byte) (exifTags []ExifTag, err error) {
|
|||
tagName = it.Name
|
||||
}
|
||||
|
||||
value, err := ifd.TagValue(ite)
|
||||
valueContext := ite.GetValueContext()
|
||||
|
||||
valueBytes, err := valueContext.ReadRawEncoded()
|
||||
log.PanicIf(err)
|
||||
|
||||
value, err := ite.Value()
|
||||
if err != nil {
|
||||
if err == exifcommon.ErrUnhandledUnknownTypedTag {
|
||||
value = exifundefined.UnparseableUnknownTagValuePlaceholder
|
||||
|
@ -135,20 +140,17 @@ func GetFlatExifData(exifData []byte) (exifTags []ExifTag, err error) {
|
|||
}
|
||||
}
|
||||
|
||||
valueBytes, err := ifd.TagValueBytes(ite)
|
||||
if err != nil && err != exifcommon.ErrUnhandledUnknownTypedTag {
|
||||
log.Panic(err)
|
||||
}
|
||||
tagType := ite.TagType()
|
||||
|
||||
et := ExifTag{
|
||||
IfdPath: ifd.IfdPath,
|
||||
TagId: ite.TagId,
|
||||
TagId: ite.TagId(),
|
||||
TagName: tagName,
|
||||
TagTypeId: ite.TagType,
|
||||
TagTypeName: ite.TagType.String(),
|
||||
TagTypeId: tagType,
|
||||
TagTypeName: tagType.String(),
|
||||
Value: value,
|
||||
ValueBytes: valueBytes,
|
||||
ChildIfdPath: ite.ChildIfdPath,
|
||||
ChildIfdPath: ite.ChildIfdPath(),
|
||||
}
|
||||
|
||||
exifTags = append(exifTags, et)
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
package exif
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-exif/v2/common"
|
||||
)
|
||||
|
||||
func newValueContextFromTag(ite *IfdTagEntry, addressableData []byte, byteOrder binary.ByteOrder) *exifcommon.ValueContext {
|
||||
return exifcommon.NewValueContext(
|
||||
ite.IfdPath,
|
||||
ite.TagId,
|
||||
ite.UnitCount,
|
||||
ite.ValueOffset,
|
||||
ite.RawValueOffset,
|
||||
addressableData,
|
||||
ite.TagType,
|
||||
byteOrder)
|
||||
}
|
Loading…
Reference in New Issue