diff --git a/v2/exif_test.go b/v2/exif_test.go index c91b5e4..a3edf93 100644 --- a/v2/exif_test.go +++ b/v2/exif_test.go @@ -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 diff --git a/v2/ifd_builder.go b/v2/ifd_builder.go index de027a9..c5f2429 100644 --- a/v2/ifd_builder.go +++ b/v2/ifd_builder.go @@ -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) diff --git a/v2/ifd_builder_test.go b/v2/ifd_builder_test.go index 1cd4412..e2766cf 100644 --- a/v2/ifd_builder_test.go +++ b/v2/ifd_builder_test.go @@ -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) diff --git a/v2/ifd_enumerate.go b/v2/ifd_enumerate.go index 0b358ce..1a11086 100644 --- a/v2/ifd_enumerate.go +++ b/v2/ifd_enumerate.go @@ -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) } diff --git a/v2/ifd_enumerate_test.go b/v2/ifd_enumerate_test.go index 61228ce..0c19e73 100644 --- a/v2/ifd_enumerate_test.go +++ b/v2/ifd_enumerate_test.go @@ -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) diff --git a/v2/ifd_tag_entry.go b/v2/ifd_tag_entry.go index b396296..2146ef2 100644 --- a/v2/ifd_tag_entry.go +++ b/v2/ifd_tag_entry.go @@ -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, diff --git a/v2/utility.go b/v2/utility.go index a6d9ba7..04b7361 100644 --- a/v2/utility.go +++ b/v2/utility.go @@ -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()