Visit interface now just gets the ITE struct

That, rather than just a couple of values from it. Primarily because we
want to not have callers involve themselves with the value context
unless they want to.

- ifd_tag_entry.go: ITEs now provide `Format()` and `FormatFirst()`
  methods.

- We dumped several spots of code that could just reuse functions to
  format, decode, or get raw bytes rather than dealing with undefined
  vs not undefined logic themselves.

  - This is now possible due to prior change.

- ifd_tag_entry.go: No longer exports GetValueContext(). Users shouldn't
  usually have to touch it, now.

- Added some commenting.

This commit almost represents everything we have been trying to achieve,
now made possible by the last several commits.
for/master
Dustin Oprea 2020-01-11 02:20:38 -05:00
parent 1bdfa9b10e
commit 173d686dd9
7 changed files with 73 additions and 105 deletions

View File

@ -13,17 +13,16 @@ import (
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
"github.com/dsoprea/go-exif/v2/undefined"
)
type innerVisitorCall func(fqIfdPath string, ifdIndex int, tagId uint16, tagType exifcommon.TagTypePrimitive, valueContext *exifcommon.ValueContext) (err error)
type innerVisitorCall func(fqIfdPath string, ifdIndex int, ite *IfdTagEntry) (err error)
type visitorWrapper struct {
f innerVisitorCall
}
func (vw *visitorWrapper) Visit(fqIfdPath string, ifdIndex int, tagId uint16, tagType exifcommon.TagTypePrimitive, valueContext *exifcommon.ValueContext) (err error) {
return vw.f(fqIfdPath, ifdIndex, tagId, tagType, valueContext)
func (vw *visitorWrapper) Visit(fqIfdPath string, ifdIndex int, ite *IfdTagEntry) (err error) {
return vw.f(fqIfdPath, ifdIndex, ite)
}
func TestVisit(t *testing.T) {
@ -71,7 +70,7 @@ func TestVisit(t *testing.T) {
tags := make([]string, 0)
visitor := func(fqIfdPath string, ifdIndex int, tagId uint16, tagType exifcommon.TagTypePrimitive, valueContext *exifcommon.ValueContext) (err error) {
visitor := func(fqIfdPath string, ifdIndex int, ite *IfdTagEntry) (err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
@ -79,6 +78,9 @@ func TestVisit(t *testing.T) {
}
}()
tagId := ite.TagId()
tagType := ite.TagType()
ifdPath, err := im.StripPathPhraseIndices(fqIfdPath)
log.PanicIf(err)
@ -92,26 +94,10 @@ func TestVisit(t *testing.T) {
}
}
valueString := ""
if tagType == exifcommon.TypeUndefined {
value, err := exifundefined.Decode(valueContext)
if err != nil {
if err == exifcommon.ErrUnhandledUnknownTypedTag {
valueString = "!UNDEFINED!"
} else {
log.Panic(err)
}
}
valueString, err := ite.FormatFirst()
log.PanicIf(err)
valueString = fmt.Sprintf("%v", value)
} else {
var err error
valueString, err = valueContext.FormatFirst()
log.PanicIf(err)
}
description := fmt.Sprintf("IFD-PATH=[%s] ID=(0x%04x) NAME=[%s] COUNT=(%d) TYPE=[%s] VALUE=[%s]", ifdPath, tagId, it.Name, valueContext.UnitCount(), tagType.String(), valueString)
description := fmt.Sprintf("IFD-PATH=[%s] ID=(0x%04x) NAME=[%s] COUNT=(%d) TYPE=[%s] VALUE=[%s]", ifdPath, tagId, it.Name, ite.UnitCount(), tagType.String(), valueString)
tags = append(tags, description)
return nil

View File

@ -1112,38 +1112,8 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, includeTagIds []uint16, excl
} else {
// Non-IFD tag.
valueContext := ite.GetValueContext()
var rawBytes []byte
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
// if we support this tag and producing the bytes for it.
value, err := exifundefined.Decode(valueContext)
if err != nil {
if err == exifcommon.ErrUnhandledUnknownTypedTag {
// It's an undefined-type tag that we don't handle. If
// we don't know how to handle it, we can't know how
// many bytes it is and we must skip it.
continue
}
log.Panic(err)
}
rawBytes, _, err = exifundefined.Encode(value, ib.byteOrder)
log.PanicIf(err)
} else {
// It's a value with a standard type.
var err error
rawBytes, err = valueContext.ReadRawEncoded()
log.PanicIf(err)
}
rawBytes, err := ite.RawBytes()
log.PanicIf(err)
value := NewIfdBuilderTagValueFromBytes(rawBytes)

View File

@ -1488,41 +1488,11 @@ func TestIfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
t.Fatalf("Tag-type not as expected: %d != %d ITE=%s", recoveredIte.TagType(), originalIte.TagType(), recoveredIte)
}
var originalValueBytes []byte
originalValueBytes, err := originalIte.RawBytes()
log.PanicIf(err)
if originalIte.TagType() == exifcommon.TypeUndefined {
valueContext := originalIte.GetValueContext()
var err error
value, err := exifundefined.Decode(valueContext)
log.PanicIf(err)
originalValueBytes, _, err = exifundefined.Encode(value, originalIndex.RootIfd.ByteOrder)
} else {
var err error
originalValueBytes, err = originalIte.RawBytes()
log.PanicIf(err)
}
var recoveredValueBytes []byte
if recoveredIte.TagType() == exifcommon.TypeUndefined {
valueContext := recoveredIte.GetValueContext()
var err error
value, err := exifundefined.Decode(valueContext)
log.PanicIf(err)
recoveredValueBytes, _, err = exifundefined.Encode(value, recoveredIndex.RootIfd.ByteOrder)
} else {
var err error
recoveredValueBytes, err = recoveredIte.RawBytes()
log.PanicIf(err)
}
recoveredValueBytes, err := recoveredIte.RawBytes()
log.PanicIf(err)
if bytes.Compare(recoveredValueBytes, originalValueBytes) != 0 {
fmt.Printf("ACTUAL: %s\n", originalIte)
@ -1811,9 +1781,7 @@ func ExampleIfdBuilder_SetStandardWithName() {
log.PanicIf(err)
for _, ite := range results {
valueContext := ite.GetValueContext()
valueRaw, err := valueContext.Values()
valueRaw, err := ite.Value()
log.PanicIf(err)
stringValue := valueRaw.(string)

View File

@ -213,7 +213,7 @@ func (ie *IfdEnumerate) parseTag(fqIfdPath string, tagPosition int, enumerator *
// This was reimplemented as an interface to allow for simpler change management
// in the future.
type RawTagWalk interface {
Visit(fqIfdPath string, ifdIndex int, tagId uint16, tagType exifcommon.TagTypePrimitive, valueContext *exifcommon.ValueContext) (err error)
Visit(fqIfdPath string, ifdIndex int, ite *IfdTagEntry) (err error)
}
// ParseIfd decodes the IFD block that we're currently sitting on the first
@ -257,9 +257,7 @@ func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, enumerator *Ifd
}
if visitor != nil {
valueContext := ite.GetValueContext()
err := visitor.Visit(fqIfdPath, ifdIndex, ite.TagId(), ite.TagType(), valueContext)
err := visitor.Visit(fqIfdPath, ifdIndex, ite)
log.PanicIf(err)
}

View File

@ -495,9 +495,8 @@ func ExampleIfd_FindTagWithName() {
}
ite := results[0]
valueContext := ite.GetValueContext()
valueRaw, err := valueContext.Values()
valueRaw, err := ite.Value()
log.PanicIf(err)
value := valueRaw.(string)

View File

@ -105,7 +105,7 @@ func (ite *IfdTagEntry) valueOffset_() uint32 {
// RawBytes renders a specific list of bytes from the value in this tag.
func (ite *IfdTagEntry) RawBytes() (rawBytes []byte, err error) {
valueContext := ite.GetValueContext()
valueContext := ite.getValueContext()
if ite.TagType() == exifcommon.TypeUndefined {
value, err := exifundefined.Decode(valueContext)
@ -140,7 +140,7 @@ func (ite *IfdTagEntry) Value() (value interface{}, err error) {
}
}()
valueContext := ite.GetValueContext()
valueContext := ite.getValueContext()
if ite.tagType == exifcommon.TypeUndefined {
var err error
@ -163,6 +163,52 @@ func (ite *IfdTagEntry) Value() (value interface{}, err error) {
return value, nil
}
// Format returns the tag's value as a string.
func (ite *IfdTagEntry) Format() (phrase 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)
}
phrase, err = exifcommon.FormatFromType(value, false)
log.PanicIf(err)
return phrase, nil
}
// FormatFirst returns the same as Format() but only the first item.
func (ite *IfdTagEntry) FormatFirst() (phrase 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)
}
phrase, err = exifcommon.FormatFromType(value, true)
log.PanicIf(err)
return phrase, nil
}
func (ite *IfdTagEntry) setIsUnhandledUnknown(isUnhandledUnknown bool) {
ite.isUnhandledUnknown = isUnhandledUnknown
}
@ -174,19 +220,22 @@ func (ite *IfdTagEntry) SetChildIfd(childFqIfdPath, childIfdPath, childIfdName s
ite.childIfdName = childIfdName
}
// ChildIfdName returns the name of the child IFD
func (ite *IfdTagEntry) ChildIfdName() string {
return ite.childIfdName
}
// ChildIfdPath returns the path of the child IFD.
func (ite *IfdTagEntry) ChildIfdPath() string {
return ite.childIfdPath
}
// ChildFqIfdPath returns the complete path of the child IFD.
func (ite *IfdTagEntry) ChildFqIfdPath() string {
return ite.childFqIfdPath
}
func (ite *IfdTagEntry) GetValueContext() *exifcommon.ValueContext {
func (ite *IfdTagEntry) getValueContext() *exifcommon.ValueContext {
return exifcommon.NewValueContext(
ite.ifdPath,
ite.tagId,

View File

@ -126,9 +126,7 @@ func GetFlatExifData(exifData []byte) (exifTags []ExifTag, err error) {
tagName = it.Name
}
valueContext := ite.GetValueContext()
valueBytes, err := valueContext.ReadRawEncoded()
valueBytes, err := ite.RawBytes()
log.PanicIf(err)
value, err := ite.Value()