New integration of common/ and undefined/ subpackages

- common/type.go: Add FormatFromType() .
- Renamed common/type_encode.go to common/value_encoder.go .
This commit is contained in:
Dustin Oprea 2020-01-04 19:22:04 -05:00
parent 5c7dc45079
commit 32a5d88770
42 changed files with 1094 additions and 780 deletions

View File

@ -3,6 +3,7 @@ package exifcommon
import ( import (
"errors" "errors"
"fmt" "fmt"
"reflect"
"strconv" "strconv"
"strings" "strings"
@ -93,6 +94,22 @@ func (tagType TagTypePrimitive) Size() int {
} }
} }
// IsValid returns true if tagType is a valid type.
func (tagType TagTypePrimitive) IsValid() bool {
// TODO(dustin): Add test
return tagType == TypeByte ||
tagType == TypeAscii ||
tagType == TypeAsciiNoNul ||
tagType == TypeShort ||
tagType == TypeLong ||
tagType == TypeRational ||
tagType == TypeSignedLong ||
tagType == TypeSignedRational ||
tagType == TypeUndefined
}
var ( var (
// TODO(dustin): Rename TypeNames() to typeNames() and add getter. // TODO(dustin): Rename TypeNames() to typeNames() and add getter.
TypeNames = map[TagTypePrimitive]string{ TypeNames = map[TagTypePrimitive]string{
@ -108,7 +125,7 @@ var (
TypeAsciiNoNul: "_ASCII_NO_NUL", TypeAsciiNoNul: "_ASCII_NO_NUL",
} }
TypeNamesR = map[string]TagTypePrimitive{} typeNamesR = map[string]TagTypePrimitive{}
) )
type Rational struct { type Rational struct {
@ -123,14 +140,134 @@ type SignedRational struct {
// Format returns a stringified value for the given encoding. Automatically // 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.
func Format(rawBytes []byte, tagType TagTypePrimitive, justFirst bool, byteOrder binary.ByteOrder) (value string, err error) { func FormatFromType(value interface{}, justFirst bool) (phrase string, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
} }
}() }()
// TODO(dustin): !! Add tests // TODO(dustin): !! Add test
switch t := value.(type) {
case []byte:
return DumpBytesToString(t), nil
case string:
return t, nil
case []uint16:
if len(t) == 0 {
return "", nil
}
if justFirst == true {
var valueSuffix string
if len(t) > 1 {
valueSuffix = "..."
}
return fmt.Sprintf("%v%s", t[0], valueSuffix), nil
}
return fmt.Sprintf("%v", t), nil
case []uint32:
if len(t) == 0 {
return "", nil
}
if justFirst == true {
var valueSuffix string
if len(t) > 1 {
valueSuffix = "..."
}
return fmt.Sprintf("%v%s", t[0], valueSuffix), nil
}
return fmt.Sprintf("%v", t), nil
case []Rational:
if len(t) == 0 {
return "", nil
}
parts := make([]string, len(t))
for i, r := range t {
parts[i] = fmt.Sprintf("%d/%d", r.Numerator, r.Denominator)
if justFirst == true {
break
}
}
if justFirst == true {
var valueSuffix string
if len(t) > 1 {
valueSuffix = "..."
}
return fmt.Sprintf("%v%s", parts[0], valueSuffix), nil
}
return fmt.Sprintf("%v", parts), nil
case []int32:
if len(t) == 0 {
return "", nil
}
if justFirst == true {
var valueSuffix string
if len(t) > 1 {
valueSuffix = "..."
}
return fmt.Sprintf("%v%s", t[0], valueSuffix), nil
}
return fmt.Sprintf("%v", t), nil
case []SignedRational:
if len(t) == 0 {
return "", nil
}
parts := make([]string, len(t))
for i, r := range t {
parts[i] = fmt.Sprintf("%d/%d", r.Numerator, r.Denominator)
if justFirst == true {
break
}
}
if justFirst == true {
var valueSuffix string
if len(t) > 1 {
valueSuffix = "..."
}
return fmt.Sprintf("%v%s", parts[0], valueSuffix), nil
}
return fmt.Sprintf("%v", parts), nil
default:
// Affects only "unknown" values, in general.
log.Panicf("type can not be formatted into string: %v", reflect.TypeOf(value).Name())
// Never called.
return "", nil
}
}
// TODO(dustin): Rename Format() to FormatFromBytes()
// Format returns a stringified value for the given encoding. Automatically
// parses. Automatically calculates count based on type size.
func Format(rawBytes []byte, tagType TagTypePrimitive, justFirst bool, byteOrder binary.ByteOrder) (phrase string, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
// TODO(dustin): !! Add test
typeSize := tagType.Size() typeSize := tagType.Size()
@ -144,109 +281,61 @@ func Format(rawBytes []byte, tagType TagTypePrimitive, justFirst bool, byteOrder
// Truncate the items if it's not bytes or a string and we just want the first. // Truncate the items if it's not bytes or a string and we just want the first.
valueSuffix := "" var value interface{}
if justFirst == true && unitCount > 1 && tagType != TypeByte && tagType != TypeAscii && tagType != TypeAsciiNoNul {
unitCount = 1
valueSuffix = "..."
}
if tagType == TypeByte { switch tagType {
items, err := parser.ParseBytes(rawBytes, unitCount) case TypeByte:
var err error
value, err = parser.ParseBytes(rawBytes, unitCount)
log.PanicIf(err) log.PanicIf(err)
case TypeAscii:
var err error
return DumpBytesToString(items), nil value, err = parser.ParseAscii(rawBytes, unitCount)
} else if tagType == TypeAscii {
phrase, err := parser.ParseAscii(rawBytes, unitCount)
log.PanicIf(err) log.PanicIf(err)
case TypeAsciiNoNul:
var err error
return phrase, nil value, err = parser.ParseAsciiNoNul(rawBytes, unitCount)
} else if tagType == TypeAsciiNoNul {
phrase, err := parser.ParseAsciiNoNul(rawBytes, unitCount)
log.PanicIf(err) log.PanicIf(err)
case TypeShort:
var err error
return phrase, nil value, err = parser.ParseShorts(rawBytes, unitCount, byteOrder)
} else if tagType == TypeShort {
items, err := parser.ParseShorts(rawBytes, unitCount, byteOrder)
log.PanicIf(err) log.PanicIf(err)
case TypeLong:
var err error
if len(items) > 0 { value, err = parser.ParseLongs(rawBytes, unitCount, byteOrder)
if justFirst == true {
return fmt.Sprintf("%v%s", items[0], valueSuffix), nil
} else {
return fmt.Sprintf("%v", items), nil
}
} else {
return "", nil
}
} else if tagType == TypeLong {
items, err := parser.ParseLongs(rawBytes, unitCount, byteOrder)
log.PanicIf(err) log.PanicIf(err)
case TypeRational:
var err error
if len(items) > 0 { value, err = parser.ParseRationals(rawBytes, unitCount, byteOrder)
if justFirst == true {
return fmt.Sprintf("%v%s", items[0], valueSuffix), nil
} else {
return fmt.Sprintf("%v", items), nil
}
} else {
return "", nil
}
} else if tagType == TypeRational {
items, err := parser.ParseRationals(rawBytes, unitCount, byteOrder)
log.PanicIf(err) log.PanicIf(err)
case TypeSignedLong:
var err error
if len(items) > 0 { value, err = parser.ParseSignedLongs(rawBytes, unitCount, byteOrder)
parts := make([]string, len(items))
for i, r := range items {
parts[i] = fmt.Sprintf("%d/%d", r.Numerator, r.Denominator)
}
if justFirst == true {
return fmt.Sprintf("%v%s", parts[0], valueSuffix), nil
} else {
return fmt.Sprintf("%v", parts), nil
}
} else {
return "", nil
}
} else if tagType == TypeSignedLong {
items, err := parser.ParseSignedLongs(rawBytes, unitCount, byteOrder)
log.PanicIf(err) log.PanicIf(err)
case TypeSignedRational:
var err error
if len(items) > 0 { value, err = parser.ParseSignedRationals(rawBytes, unitCount, byteOrder)
if justFirst == true {
return fmt.Sprintf("%v%s", items[0], valueSuffix), nil
} else {
return fmt.Sprintf("%v", items), nil
}
} else {
return "", nil
}
} else if tagType == TypeSignedRational {
items, err := parser.ParseSignedRationals(rawBytes, unitCount, byteOrder)
log.PanicIf(err) log.PanicIf(err)
default:
parts := make([]string, len(items))
for i, r := range items {
parts[i] = fmt.Sprintf("%d/%d", r.Numerator, r.Denominator)
}
if len(items) > 0 {
if justFirst == true {
return fmt.Sprintf("%v%s", parts[0], valueSuffix), nil
} else {
return fmt.Sprintf("%v", parts), nil
}
} else {
return "", nil
}
} else {
// Affects only "unknown" values, in general. // Affects only "unknown" values, in general.
log.Panicf("value of type [%s] can not be formatted into string", tagType.String()) log.Panicf("value of type [%s] can not be formatted into string", tagType.String())
// Never called. // Never called.
return "", nil return "", nil
} }
phrase, err = FormatFromType(value, justFirst)
log.PanicIf(err)
return phrase, nil
} }
// TranslateStringToType converts user-provided strings to properly-typed // TranslateStringToType converts user-provided strings to properly-typed
@ -323,8 +412,15 @@ func TranslateStringToType(tagType TagTypePrimitive, valueString string) (value
return nil, nil return nil, nil
} }
// GetTypeByName returns the `TagTypePrimitive` for the given type name.
// Returns (0) if not valid.
func GetTypeByName(typeName string) (tagType TagTypePrimitive, found bool) {
tagType, found = typeNamesR[typeName]
return tagType, found
}
func init() { func init() {
for typeId, typeName := range TypeNames { for typeId, typeName := range TypeNames {
TypeNamesR[typeName] = typeId typeNamesR[typeName] = typeId
} }
} }

View File

@ -7,6 +7,7 @@ import (
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
) )
// DumpBytes prints a list of hex-encoded bytes.
func DumpBytes(data []byte) { func DumpBytes(data []byte) {
fmt.Printf("DUMP: ") fmt.Printf("DUMP: ")
for _, x := range data { for _, x := range data {
@ -16,6 +17,8 @@ func DumpBytes(data []byte) {
fmt.Printf("\n") fmt.Printf("\n")
} }
// DumpBytesClause prints a list like DumpBytes(), but encapsulated in
// "[]byte { ... }".
func DumpBytesClause(data []byte) { func DumpBytesClause(data []byte) {
fmt.Printf("DUMP: ") fmt.Printf("DUMP: ")
@ -32,6 +35,7 @@ func DumpBytesClause(data []byte) {
fmt.Printf(" }\n") fmt.Printf(" }\n")
} }
// DumpBytesToString returns a stringified list of hex-encoded bytes.
func DumpBytesToString(data []byte) string { func DumpBytesToString(data []byte) string {
b := new(bytes.Buffer) b := new(bytes.Buffer)
@ -48,6 +52,7 @@ func DumpBytesToString(data []byte) string {
return b.String() return b.String()
} }
// DumpBytesClauseToString returns a comma-separated list of hex-encoded bytes.
func DumpBytesClauseToString(data []byte) string { func DumpBytesClauseToString(data []byte) string {
b := new(bytes.Buffer) b := new(bytes.Buffer)

28
v2/common/utility_test.go Normal file
View File

@ -0,0 +1,28 @@
package exifcommon
import (
"testing"
// "github.com/dsoprea/go-logging"
)
func TestDumpBytes(t *testing.T) {
DumpBytes([]byte{1, 2, 3, 4})
}
func TestDumpBytesClause(t *testing.T) {
DumpBytesClause([]byte{1, 2, 3, 4})
}
func TestDumpBytesToString(t *testing.T) {
s := DumpBytesToString([]byte{1, 2, 3, 4})
if s != "01 02 03 04" {
t.Fatalf("String not correct: [%s]", s)
}
}
func TestDumpBytesClauseToString(t *testing.T) {
s := DumpBytesClauseToString([]byte{1, 2, 3, 4})
if s != "0x01, 0x02, 0x03, 0x04" {
t.Fatalf("Stringified clause is not correct: [%s]", s)
}
}

View File

@ -32,7 +32,7 @@ type ValueContext struct {
// TODO(dustin): We can update newValueContext() to derive `valueOffset` itself (from `rawValueOffset`). // TODO(dustin): We can update newValueContext() to derive `valueOffset` itself (from `rawValueOffset`).
// newValueContext returns a new ValueContext struct. // newValueContext returns a new ValueContext struct.
func newValueContext(ifdPath string, tagId uint16, unitCount, valueOffset uint32, rawValueOffset, addressableData []byte, tagType TagTypePrimitive, byteOrder binary.ByteOrder) *ValueContext { func NewValueContext(ifdPath string, tagId uint16, unitCount, valueOffset uint32, rawValueOffset, addressableData []byte, tagType TagTypePrimitive, byteOrder binary.ByteOrder) *ValueContext {
return &ValueContext{ return &ValueContext{
unitCount: unitCount, unitCount: unitCount,
valueOffset: valueOffset, valueOffset: valueOffset,
@ -138,6 +138,14 @@ func (vc *ValueContext) readRawEncoded() (rawBytes []byte, err error) {
} }
} }
// ReadRawEncoded returns the encoded bytes for the value that we represent.
func (vc *ValueContext) ReadRawEncoded() (rawBytes []byte, err error) {
// TODO(dustin): Remove this method and rename readRawEncoded in its place.
return vc.readRawEncoded()
}
// Format returns a string representation for the value. // Format returns a string representation for the value.
// //
// Where the type is not ASCII, `justFirst` indicates whether to just stringify // Where the type is not ASCII, `justFirst` indicates whether to just stringify

View File

@ -11,7 +11,7 @@ import (
func TestNewValueContext(t *testing.T) { func TestNewValueContext(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := newValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder)
if vc.ifdPath != "aa/bb" { if vc.ifdPath != "aa/bb" {
t.Fatalf("ifdPath not correct: [%s]", vc.ifdPath) t.Fatalf("ifdPath not correct: [%s]", vc.ifdPath)
@ -48,7 +48,7 @@ func TestValueContext_SetUndefinedValueType__ErrorWhenNotUndefined(t *testing.T)
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := newValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder)
vc.SetUndefinedValueType(TypeLong) vc.SetUndefinedValueType(TypeLong)
} }
@ -56,7 +56,7 @@ func TestValueContext_SetUndefinedValueType__ErrorWhenNotUndefined(t *testing.T)
func TestValueContext_SetUndefinedValueType__Ok(t *testing.T) { func TestValueContext_SetUndefinedValueType__Ok(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := newValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
vc.SetUndefinedValueType(TypeLong) vc.SetUndefinedValueType(TypeLong)
@ -72,7 +72,7 @@ func TestValueContext_SetUndefinedValueType__Ok(t *testing.T) {
func TestValueContext_effectiveValueType(t *testing.T) { func TestValueContext_effectiveValueType(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := newValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
vc.SetUndefinedValueType(TypeLong) vc.SetUndefinedValueType(TypeLong)
@ -88,7 +88,7 @@ func TestValueContext_effectiveValueType(t *testing.T) {
func TestValueContext_UnitCount(t *testing.T) { func TestValueContext_UnitCount(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := newValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
if vc.UnitCount() != 11 { if vc.UnitCount() != 11 {
t.Fatalf("UnitCount() not correct: (%d)", vc.UnitCount()) t.Fatalf("UnitCount() not correct: (%d)", vc.UnitCount())
@ -98,7 +98,7 @@ func TestValueContext_UnitCount(t *testing.T) {
func TestValueContext_ValueOffset(t *testing.T) { func TestValueContext_ValueOffset(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := newValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
if vc.ValueOffset() != 22 { if vc.ValueOffset() != 22 {
t.Fatalf("ValueOffset() not correct: (%d)", vc.ValueOffset()) t.Fatalf("ValueOffset() not correct: (%d)", vc.ValueOffset())
@ -108,7 +108,7 @@ func TestValueContext_ValueOffset(t *testing.T) {
func TestValueContext_RawValueOffset(t *testing.T) { func TestValueContext_RawValueOffset(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := newValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
if bytes.Equal(vc.RawValueOffset(), rawValueOffset) != true { if bytes.Equal(vc.RawValueOffset(), rawValueOffset) != true {
t.Fatalf("RawValueOffset() not correct: %v", vc.RawValueOffset()) t.Fatalf("RawValueOffset() not correct: %v", vc.RawValueOffset())
@ -118,7 +118,7 @@ func TestValueContext_RawValueOffset(t *testing.T) {
func TestValueContext_AddressableData(t *testing.T) { func TestValueContext_AddressableData(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := newValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
if bytes.Equal(vc.AddressableData(), addressableData) != true { if bytes.Equal(vc.AddressableData(), addressableData) != true {
t.Fatalf("AddressableData() not correct: %v", vc.AddressableData()) t.Fatalf("AddressableData() not correct: %v", vc.AddressableData())
@ -128,7 +128,7 @@ func TestValueContext_AddressableData(t *testing.T) {
func TestValueContext_ByteOrder(t *testing.T) { func TestValueContext_ByteOrder(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := newValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
if vc.ByteOrder() != TestDefaultByteOrder { if vc.ByteOrder() != TestDefaultByteOrder {
t.Fatalf("ByteOrder() not correct: %v", vc.ByteOrder()) t.Fatalf("ByteOrder() not correct: %v", vc.ByteOrder())
@ -138,7 +138,7 @@ func TestValueContext_ByteOrder(t *testing.T) {
func TestValueContext_IfdPath(t *testing.T) { func TestValueContext_IfdPath(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := newValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
if vc.IfdPath() != "aa/bb" { if vc.IfdPath() != "aa/bb" {
t.Fatalf("IfdPath() not correct: [%s]", vc.IfdPath()) t.Fatalf("IfdPath() not correct: [%s]", vc.IfdPath())
@ -148,7 +148,7 @@ func TestValueContext_IfdPath(t *testing.T) {
func TestValueContext_TagId(t *testing.T) { func TestValueContext_TagId(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := newValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
if vc.TagId() != 0x1234 { if vc.TagId() != 0x1234 {
t.Fatalf("TagId() not correct: (%d)", vc.TagId()) t.Fatalf("TagId() not correct: (%d)", vc.TagId())
@ -159,7 +159,7 @@ func TestValueContext_isEmbedded__True(t *testing.T) {
unitCount := uint32(4) unitCount := uint32(4)
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := newValueContext("aa/bb", 0x1234, unitCount, 22, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, 22, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder)
if vc.isEmbedded() != true { if vc.isEmbedded() != true {
t.Fatalf("isEmbedded() not correct: %v", vc.isEmbedded()) t.Fatalf("isEmbedded() not correct: %v", vc.isEmbedded())
@ -170,7 +170,7 @@ func TestValueContext_isEmbedded__False(t *testing.T) {
unitCount := uint32(5) unitCount := uint32(5)
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := newValueContext("aa/bb", 0x1234, unitCount, 22, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, 22, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder)
if vc.isEmbedded() != false { if vc.isEmbedded() != false {
t.Fatalf("isEmbedded() not correct: %v", vc.isEmbedded()) t.Fatalf("isEmbedded() not correct: %v", vc.isEmbedded())
@ -186,7 +186,7 @@ func TestValueContext_readRawEncoded__IsEmbedded(t *testing.T) {
valueOffset := uint32(0) valueOffset := uint32(0)
addressableData := []byte{} addressableData := []byte{}
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder)
recovered, err := vc.readRawEncoded() recovered, err := vc.readRawEncoded()
log.PanicIf(err) log.PanicIf(err)
@ -208,7 +208,7 @@ func TestValueContext_readRawEncoded__IsRelative(t *testing.T) {
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder)
recovered, err := vc.readRawEncoded() recovered, err := vc.readRawEncoded()
log.PanicIf(err) log.PanicIf(err)
@ -228,7 +228,7 @@ func TestValueContext_Format__Byte(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -248,7 +248,7 @@ func TestValueContext_Format__Ascii(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -268,7 +268,7 @@ func TestValueContext_Format__AsciiNoNul(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAsciiNoNul, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAsciiNoNul, TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -288,7 +288,7 @@ func TestValueContext_Format__Short(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -308,7 +308,7 @@ func TestValueContext_Format__Long(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -332,7 +332,7 @@ func TestValueContext_Format__Rational(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeRational, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeRational, TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -352,7 +352,7 @@ func TestValueContext_Format__SignedLong(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedLong, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedLong, TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -376,7 +376,7 @@ func TestValueContext_Format__SignedRational(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedRational, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedRational, TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -409,7 +409,7 @@ func TestValueContext_Format__Undefined__NoEffectiveType(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -429,7 +429,7 @@ func TestValueContext_Format__Undefined__HasEffectiveType(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
vc.SetUndefinedValueType(TypeAscii) vc.SetUndefinedValueType(TypeAscii)
@ -451,7 +451,7 @@ func TestValueContext_FormatFirst__Bytes(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder)
value, err := vc.FormatFirst() value, err := vc.FormatFirst()
log.PanicIf(err) log.PanicIf(err)
@ -471,7 +471,7 @@ func TestValueContext_FormatFirst__String(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder)
value, err := vc.FormatFirst() value, err := vc.FormatFirst()
log.PanicIf(err) log.PanicIf(err)
@ -491,7 +491,7 @@ func TestValueContext_FormatFirst__List(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder)
value, err := vc.FormatFirst() value, err := vc.FormatFirst()
log.PanicIf(err) log.PanicIf(err)
@ -511,7 +511,7 @@ func TestValueContext_ReadBytes(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder)
value, err := vc.ReadBytes() value, err := vc.ReadBytes()
log.PanicIf(err) log.PanicIf(err)
@ -531,7 +531,7 @@ func TestValueContext_ReadAscii(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder)
value, err := vc.ReadAscii() value, err := vc.ReadAscii()
log.PanicIf(err) log.PanicIf(err)
@ -551,7 +551,7 @@ func TestValueContext_ReadAsciiNoNul(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAsciiNoNul, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAsciiNoNul, TestDefaultByteOrder)
value, err := vc.ReadAsciiNoNul() value, err := vc.ReadAsciiNoNul()
log.PanicIf(err) log.PanicIf(err)
@ -571,7 +571,7 @@ func TestValueContext_ReadShorts(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder)
value, err := vc.ReadShorts() value, err := vc.ReadShorts()
log.PanicIf(err) log.PanicIf(err)
@ -591,7 +591,7 @@ func TestValueContext_ReadLongs(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder)
value, err := vc.ReadLongs() value, err := vc.ReadLongs()
log.PanicIf(err) log.PanicIf(err)
@ -615,7 +615,7 @@ func TestValueContext_ReadRationals(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeRational, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeRational, TestDefaultByteOrder)
value, err := vc.ReadRationals() value, err := vc.ReadRationals()
log.PanicIf(err) log.PanicIf(err)
@ -640,7 +640,7 @@ func TestValueContext_ReadSignedLongs(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedLong, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedLong, TestDefaultByteOrder)
value, err := vc.ReadSignedLongs() value, err := vc.ReadSignedLongs()
log.PanicIf(err) log.PanicIf(err)
@ -664,7 +664,7 @@ func TestValueContext_ReadSignedRationals(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedRational, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedRational, TestDefaultByteOrder)
value, err := vc.ReadSignedRationals() value, err := vc.ReadSignedRationals()
log.PanicIf(err) log.PanicIf(err)
@ -689,7 +689,7 @@ func TestValueContext_Values__Byte(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)
@ -709,7 +709,7 @@ func TestValueContext_Values__Ascii(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)
@ -729,7 +729,7 @@ func TestValueContext_Values__AsciiNoNul(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAsciiNoNul, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAsciiNoNul, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)
@ -749,7 +749,7 @@ func TestValueContext_Values__Short(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)
@ -769,7 +769,7 @@ func TestValueContext_Values__Long(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)
@ -793,7 +793,7 @@ func TestValueContext_Values__Rational(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeRational, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeRational, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)
@ -818,7 +818,7 @@ func TestValueContext_Values__SignedLong(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedLong, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedLong, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)
@ -842,7 +842,7 @@ func TestValueContext_Values__SignedRational(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedRational, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedRational, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)

View File

@ -187,8 +187,6 @@ func (ve *ValueEncoder) Encode(value interface{}) (ed EncodedData, err error) {
} }
}() }()
// TODO(dustin): This is redundant with EncodeWithType. Refactor one to use the other.
switch value.(type) { switch value.(type) {
case []byte: case []byte:
ed, err = ve.encodeBytes(value.([]byte)) ed, err = ve.encodeBytes(value.([]byte))

View File

@ -177,7 +177,7 @@ func ParseExifHeader(data []byte) (eh ExifHeader, err error) {
} }
// Visit recursively invokes a callback for every tag. // Visit recursively invokes a callback for every tag.
func Visit(rootIfdName string, ifdMapping *IfdMapping, tagIndex *TagIndex, exifData []byte, visitor RawTagVisitor) (eh ExifHeader, err error) { func Visit(rootIfdName string, ifdMapping *IfdMapping, tagIndex *TagIndex, exifData []byte, visitor RawTagWalk) (eh ExifHeader, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))

View File

@ -11,13 +11,28 @@ import (
"io/ioutil" "io/ioutil"
"github.com/dsoprea/go-logging" "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 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 TestVisit(t *testing.T) { func TestVisit(t *testing.T) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err := log.Wrap(state.(error)) err := log.Wrap(state.(error))
log.PrintErrorf(err, "Exif failure.") log.PrintError(err)
t.Fatalf("Test failure.")
} }
}() }()
@ -56,7 +71,7 @@ func TestVisit(t *testing.T) {
tags := make([]string, 0) tags := make([]string, 0)
visitor := func(fqIfdPath string, ifdIndex int, tagId uint16, tagType TagType, valueContext ValueContext) (err error) { visitor := func(fqIfdPath string, ifdIndex int, tagId uint16, tagType exifcommon.TagTypePrimitive, valueContext *exifcommon.ValueContext) (err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
@ -78,10 +93,10 @@ func TestVisit(t *testing.T) {
} }
valueString := "" valueString := ""
if tagType.Type() == TypeUndefined { if tagType == exifcommon.TypeUndefined {
value, err := valueContext.Undefined() value, err := exifundefined.Decode(fqIfdPath, tagId, valueContext, valueContext.ByteOrder())
if err != nil { if err != nil {
if err == ErrUnhandledUnknownTypedTag { if err == exifcommon.ErrUnhandledUnknownTypedTag {
valueString = "!UNDEFINED!" valueString = "!UNDEFINED!"
} else { } else {
log.Panic(err) log.Panic(err)
@ -90,17 +105,23 @@ func TestVisit(t *testing.T) {
valueString = fmt.Sprintf("%v", value) valueString = fmt.Sprintf("%v", value)
} else { } else {
var err error
valueString, err = valueContext.FormatFirst() valueString, err = valueContext.FormatFirst()
log.PanicIf(err) 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.Name(), valueString) 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)
tags = append(tags, description) tags = append(tags, description)
return nil return nil
} }
_, err = Visit(IfdStandard, im, ti, data[foundAt:], visitor) vw := &visitorWrapper{
f: visitor,
}
_, err = Visit(exifcommon.IfdStandard, im, ti, data[foundAt:], vw)
log.PanicIf(err) log.PanicIf(err)
expected := []string{ expected := []string{
@ -124,7 +145,7 @@ func TestVisit(t *testing.T) {
"IFD-PATH=[IFD/Exif] ID=(0x9000) NAME=[ExifVersion] COUNT=(4) TYPE=[UNDEFINED] VALUE=[0230]", "IFD-PATH=[IFD/Exif] ID=(0x9000) NAME=[ExifVersion] COUNT=(4) TYPE=[UNDEFINED] VALUE=[0230]",
"IFD-PATH=[IFD/Exif] ID=(0x9003) NAME=[DateTimeOriginal] COUNT=(20) TYPE=[ASCII] VALUE=[2017:12:02 08:18:50]", "IFD-PATH=[IFD/Exif] ID=(0x9003) NAME=[DateTimeOriginal] COUNT=(20) TYPE=[ASCII] VALUE=[2017:12:02 08:18:50]",
"IFD-PATH=[IFD/Exif] ID=(0x9004) NAME=[DateTimeDigitized] COUNT=(20) TYPE=[ASCII] VALUE=[2017:12:02 08:18:50]", "IFD-PATH=[IFD/Exif] ID=(0x9004) NAME=[DateTimeDigitized] COUNT=(20) TYPE=[ASCII] VALUE=[2017:12:02 08:18:50]",
"IFD-PATH=[IFD/Exif] ID=(0x9101) NAME=[ComponentsConfiguration] COUNT=(4) TYPE=[UNDEFINED] VALUE=[ComponentsConfiguration<ID=[YCBCR] BYTES=[1 2 3 0]>]", "IFD-PATH=[IFD/Exif] ID=(0x9101) NAME=[ComponentsConfiguration] COUNT=(4) TYPE=[UNDEFINED] VALUE=[Exif9101ComponentsConfiguration<ID=[YCBCR] BYTES=[1 2 3 0]>]",
"IFD-PATH=[IFD/Exif] ID=(0x9201) NAME=[ShutterSpeedValue] COUNT=(1) TYPE=[SRATIONAL] VALUE=[614400/65536]", "IFD-PATH=[IFD/Exif] ID=(0x9201) NAME=[ShutterSpeedValue] COUNT=(1) TYPE=[SRATIONAL] VALUE=[614400/65536]",
"IFD-PATH=[IFD/Exif] ID=(0x9202) NAME=[ApertureValue] COUNT=(1) TYPE=[RATIONAL] VALUE=[262144/65536]", "IFD-PATH=[IFD/Exif] ID=(0x9202) NAME=[ApertureValue] COUNT=(1) TYPE=[RATIONAL] VALUE=[262144/65536]",
"IFD-PATH=[IFD/Exif] ID=(0x9204) NAME=[ExposureBiasValue] COUNT=(1) TYPE=[SRATIONAL] VALUE=[0/1]", "IFD-PATH=[IFD/Exif] ID=(0x9204) NAME=[ExposureBiasValue] COUNT=(1) TYPE=[SRATIONAL] VALUE=[0/1]",
@ -213,7 +234,9 @@ func TestCollect(t *testing.T) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err := log.Wrap(state.(error)) err := log.Wrap(state.(error))
log.PrintErrorf(err, "Exif failure.") log.PrintError(err)
t.Fatalf("Test failure.")
} }
}() }()
@ -259,52 +282,52 @@ func TestCollect(t *testing.T) {
t.Fatalf("Root IFD chain not terminated correctly (2).") t.Fatalf("Root IFD chain not terminated correctly (2).")
} }
if rootIfd.IfdPath != IfdPathStandard { if rootIfd.IfdPath != exifcommon.IfdPathStandard {
t.Fatalf("Root IFD is not labeled correctly: [%s]", rootIfd.IfdPath) t.Fatalf("Root IFD is not labeled correctly: [%s]", rootIfd.IfdPath)
} else if rootIfd.NextIfd.IfdPath != IfdPathStandard { } else if rootIfd.NextIfd.IfdPath != exifcommon.IfdPathStandard {
t.Fatalf("Root IFD sibling is not labeled correctly: [%s]", rootIfd.IfdPath) t.Fatalf("Root IFD sibling is not labeled correctly: [%s]", rootIfd.IfdPath)
} else if rootIfd.Children[0].IfdPath != IfdPathStandardExif { } else if rootIfd.Children[0].IfdPath != exifcommon.IfdPathStandardExif {
t.Fatalf("Root IFD child (0) is not labeled correctly: [%s]", rootIfd.Children[0].IfdPath) t.Fatalf("Root IFD child (0) is not labeled correctly: [%s]", rootIfd.Children[0].IfdPath)
} else if rootIfd.Children[1].IfdPath != IfdPathStandardGps { } else if rootIfd.Children[1].IfdPath != exifcommon.IfdPathStandardGps {
t.Fatalf("Root IFD child (1) is not labeled correctly: [%s]", rootIfd.Children[1].IfdPath) t.Fatalf("Root IFD child (1) is not labeled correctly: [%s]", rootIfd.Children[1].IfdPath)
} else if rootIfd.Children[0].Children[0].IfdPath != IfdPathStandardExifIop { } else if rootIfd.Children[0].Children[0].IfdPath != exifcommon.IfdPathStandardExifIop {
t.Fatalf("Exif IFD child is not an IOP IFD: [%s]", rootIfd.Children[0].Children[0].IfdPath) t.Fatalf("Exif IFD child is not an IOP IFD: [%s]", rootIfd.Children[0].Children[0].IfdPath)
} }
if lookup[IfdPathStandard][0].IfdPath != IfdPathStandard { if lookup[exifcommon.IfdPathStandard][0].IfdPath != exifcommon.IfdPathStandard {
t.Fatalf("Lookup for standard IFD not correct.") t.Fatalf("Lookup for standard IFD not correct.")
} else if lookup[IfdPathStandard][1].IfdPath != IfdPathStandard { } else if lookup[exifcommon.IfdPathStandard][1].IfdPath != exifcommon.IfdPathStandard {
t.Fatalf("Lookup for standard IFD not correct.") t.Fatalf("Lookup for standard IFD not correct.")
} }
if lookup[IfdPathStandardExif][0].IfdPath != IfdPathStandardExif { if lookup[exifcommon.IfdPathStandardExif][0].IfdPath != exifcommon.IfdPathStandardExif {
t.Fatalf("Lookup for EXIF IFD not correct.") t.Fatalf("Lookup for EXIF IFD not correct.")
} }
if lookup[IfdPathStandardGps][0].IfdPath != IfdPathStandardGps { if lookup[exifcommon.IfdPathStandardGps][0].IfdPath != exifcommon.IfdPathStandardGps {
t.Fatalf("Lookup for GPS IFD not correct.") t.Fatalf("Lookup for GPS IFD not correct.")
} }
if lookup[IfdPathStandardExifIop][0].IfdPath != IfdPathStandardExifIop { if lookup[exifcommon.IfdPathStandardExifIop][0].IfdPath != exifcommon.IfdPathStandardExifIop {
t.Fatalf("Lookup for IOP IFD not correct.") t.Fatalf("Lookup for IOP IFD not correct.")
} }
foundExif := 0 foundExif := 0
foundGps := 0 foundGps := 0
for _, ite := range lookup[IfdPathStandard][0].Entries { for _, ite := range lookup[exifcommon.IfdPathStandard][0].Entries {
if ite.ChildIfdPath == IfdPathStandardExif { if ite.ChildIfdPath == exifcommon.IfdPathStandardExif {
foundExif++ foundExif++
if ite.TagId != IfdExifId { if ite.TagId != exifcommon.IfdExifId {
t.Fatalf("EXIF IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId, IfdExifId) t.Fatalf("EXIF IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId, exifcommon.IfdExifId)
} }
} }
if ite.ChildIfdPath == IfdPathStandardGps { if ite.ChildIfdPath == exifcommon.IfdPathStandardGps {
foundGps++ foundGps++
if ite.TagId != IfdGpsId { if ite.TagId != exifcommon.IfdGpsId {
t.Fatalf("GPS IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId, IfdGpsId) t.Fatalf("GPS IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId, exifcommon.IfdGpsId)
} }
} }
} }
@ -316,12 +339,12 @@ func TestCollect(t *testing.T) {
} }
foundIop := 0 foundIop := 0
for _, ite := range lookup[IfdPathStandardExif][0].Entries { for _, ite := range lookup[exifcommon.IfdPathStandardExif][0].Entries {
if ite.ChildIfdPath == IfdPathStandardExifIop { if ite.ChildIfdPath == exifcommon.IfdPathStandardExifIop {
foundIop++ foundIop++
if ite.TagId != IfdIopId { if ite.TagId != exifcommon.IfdIopId {
t.Fatalf("IOP IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId, IfdIopId) t.Fatalf("IOP IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId, exifcommon.IfdIopId)
} }
} }
} }
@ -343,13 +366,13 @@ func TestParseExifHeader(t *testing.T) {
} }
func TestExif_BuildAndParseExifHeader(t *testing.T) { func TestExif_BuildAndParseExifHeader(t *testing.T) {
headerBytes, err := BuildExifHeader(TestDefaultByteOrder, 0x11223344) headerBytes, err := BuildExifHeader(exifcommon.TestDefaultByteOrder, 0x11223344)
log.PanicIf(err) log.PanicIf(err)
eh, err := ParseExifHeader(headerBytes) eh, err := ParseExifHeader(headerBytes)
log.PanicIf(err) log.PanicIf(err)
if eh.ByteOrder != TestDefaultByteOrder { if eh.ByteOrder != exifcommon.TestDefaultByteOrder {
t.Fatalf("Byte-order of EXIF header not correct.") t.Fatalf("Byte-order of EXIF header not correct.")
} else if eh.FirstIfdOffset != 0x11223344 { } else if eh.FirstIfdOffset != 0x11223344 {
t.Fatalf("First IFD offset not correct.") t.Fatalf("First IFD offset not correct.")
@ -357,7 +380,7 @@ func TestExif_BuildAndParseExifHeader(t *testing.T) {
} }
func ExampleBuildExifHeader() { func ExampleBuildExifHeader() {
headerBytes, err := BuildExifHeader(TestDefaultByteOrder, 0x11223344) headerBytes, err := BuildExifHeader(exifcommon.TestDefaultByteOrder, 0x11223344)
log.PanicIf(err) log.PanicIf(err)
eh, err := ParseExifHeader(headerBytes) eh, err := ParseExifHeader(headerBytes)

View File

@ -6,6 +6,8 @@ import (
"strings" "strings"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
) )
var ( var (
@ -363,16 +365,16 @@ func LoadStandardIfds(im *IfdMapping) (err error) {
} }
}() }()
err = im.Add([]uint16{}, IfdRootId, IfdStandard) err = im.Add([]uint16{}, exifcommon.IfdRootId, exifcommon.IfdStandard)
log.PanicIf(err) log.PanicIf(err)
err = im.Add([]uint16{IfdRootId}, IfdExifId, IfdExif) err = im.Add([]uint16{exifcommon.IfdRootId}, exifcommon.IfdExifId, exifcommon.IfdExif)
log.PanicIf(err) log.PanicIf(err)
err = im.Add([]uint16{IfdRootId, IfdExifId}, IfdIopId, IfdIop) err = im.Add([]uint16{exifcommon.IfdRootId, exifcommon.IfdExifId}, exifcommon.IfdIopId, exifcommon.IfdIop)
log.PanicIf(err) log.PanicIf(err)
err = im.Add([]uint16{IfdRootId}, IfdGpsId, IfdGps) err = im.Add([]uint16{exifcommon.IfdRootId}, exifcommon.IfdGpsId, exifcommon.IfdGps)
log.PanicIf(err) log.PanicIf(err)
return nil return nil

View File

@ -13,6 +13,9 @@ import (
"encoding/binary" "encoding/binary"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
"github.com/dsoprea/go-exif/v2/undefined"
) )
var ( var (
@ -94,7 +97,7 @@ type BuilderTag struct {
ifdPath string ifdPath string
tagId uint16 tagId uint16
typeId TagTypePrimitive typeId exifcommon.TagTypePrimitive
// value is either a value that can be encoded, an IfdBuilder instance (for // value is either a value that can be encoded, an IfdBuilder instance (for
// child IFDs), or an IfdTagEntry instance representing an existing, // child IFDs), or an IfdTagEntry instance representing an existing,
@ -106,7 +109,7 @@ type BuilderTag struct {
byteOrder binary.ByteOrder byteOrder binary.ByteOrder
} }
func NewBuilderTag(ifdPath string, tagId uint16, typeId TagTypePrimitive, value *IfdBuilderTagValue, byteOrder binary.ByteOrder) *BuilderTag { func NewBuilderTag(ifdPath string, tagId uint16, typeId exifcommon.TagTypePrimitive, value *IfdBuilderTagValue, byteOrder binary.ByteOrder) *BuilderTag {
return &BuilderTag{ return &BuilderTag{
ifdPath: ifdPath, ifdPath: ifdPath,
tagId: tagId, tagId: tagId,
@ -120,7 +123,7 @@ func NewChildIfdBuilderTag(ifdPath string, tagId uint16, value *IfdBuilderTagVal
return &BuilderTag{ return &BuilderTag{
ifdPath: ifdPath, ifdPath: ifdPath,
tagId: tagId, tagId: tagId,
typeId: TypeLong, typeId: exifcommon.TypeLong,
value: value, value: value,
} }
} }
@ -135,13 +138,13 @@ func (bt *BuilderTag) String() string {
if bt.value.IsBytes() == true { if bt.value.IsBytes() == true {
var err error var err error
valueString, err = Format(bt.value.Bytes(), bt.typeId, false, bt.byteOrder) valueString, err = exifcommon.Format(bt.value.Bytes(), bt.typeId, false, bt.byteOrder)
log.PanicIf(err) log.PanicIf(err)
} else { } else {
valueString = fmt.Sprintf("%v", bt.value) valueString = fmt.Sprintf("%v", bt.value)
} }
return fmt.Sprintf("BuilderTag<IFD-PATH=[%s] TAG-ID=(0x%04x) TAG-TYPE=[%s] VALUE=[%s]>", bt.ifdPath, bt.tagId, TypeNames[bt.typeId], valueString) return fmt.Sprintf("BuilderTag<IFD-PATH=[%s] TAG-ID=(0x%04x) TAG-TYPE=[%s] VALUE=[%s]>", bt.ifdPath, bt.tagId, bt.typeId.String(), valueString)
} }
func (bt *BuilderTag) SetValue(byteOrder binary.ByteOrder, value interface{}) (err error) { func (bt *BuilderTag) SetValue(byteOrder binary.ByteOrder, value interface{}) (err error) {
@ -153,19 +156,24 @@ func (bt *BuilderTag) SetValue(byteOrder binary.ByteOrder, value interface{}) (e
// TODO(dustin): !! Add test. // TODO(dustin): !! Add test.
tt := NewTagType(bt.typeId, byteOrder) var ed exifcommon.EncodedData
ve := NewValueEncoder(byteOrder) if bt.typeId == exifcommon.TypeUndefined {
encodeable := value.(exifundefined.EncodeableValue)
var ed EncodedData encoded, unitCount, err := exifundefined.Encode(encodeable, byteOrder)
if bt.typeId == TypeUndefined {
var err error
ed, err = EncodeUndefined(bt.ifdPath, bt.tagId, value)
log.PanicIf(err) log.PanicIf(err)
ed = exifcommon.EncodedData{
Type: exifcommon.TypeUndefined,
Encoded: encoded,
UnitCount: unitCount,
}
} else { } else {
ve := exifcommon.NewValueEncoder(byteOrder)
var err error var err error
ed, err = ve.EncodeWithType(tt, value) ed, err = ve.Encode(value)
log.PanicIf(err) log.PanicIf(err)
} }
@ -177,30 +185,29 @@ func (bt *BuilderTag) SetValue(byteOrder binary.ByteOrder, value interface{}) (e
// NewStandardBuilderTag constructs a `BuilderTag` instance. The type is looked // NewStandardBuilderTag constructs a `BuilderTag` instance. The type is looked
// up. `ii` is the type of IFD that owns this tag. // up. `ii` is the type of IFD that owns this tag.
func NewStandardBuilderTag(ifdPath string, it *IndexedTag, byteOrder binary.ByteOrder, value interface{}) *BuilderTag { func NewStandardBuilderTag(ifdPath string, it *IndexedTag, byteOrder binary.ByteOrder, value interface{}) *BuilderTag {
typeId := it.Type var rawBytes []byte
tt := NewTagType(typeId, byteOrder) if it.Type == exifcommon.TypeUndefined {
encodeable := value.(exifundefined.EncodeableValue)
ve := NewValueEncoder(byteOrder)
var ed EncodedData
if it.Type == TypeUndefined {
var err error var err error
ed, err = EncodeUndefined(ifdPath, it.Id, value) rawBytes, _, err = exifundefined.Encode(encodeable, byteOrder)
log.PanicIf(err) log.PanicIf(err)
} else { } else {
var err error ve := exifcommon.NewValueEncoder(byteOrder)
ed, err = ve.EncodeWithType(tt, value) ed, err := ve.Encode(value)
log.PanicIf(err) log.PanicIf(err)
rawBytes = ed.Encoded
} }
tagValue := NewIfdBuilderTagValueFromBytes(ed.Encoded) tagValue := NewIfdBuilderTagValueFromBytes(rawBytes)
return NewBuilderTag( return NewBuilderTag(
ifdPath, ifdPath,
it.Id, it.Id,
typeId, it.Type,
tagValue, tagValue,
byteOrder) byteOrder)
} }
@ -288,7 +295,7 @@ func NewIfdBuilderWithExistingIfd(ifd *Ifd) (ib *IfdBuilder) {
var ifdTagId uint16 var ifdTagId uint16
// There is no tag-ID for the root IFD. It will never be a child IFD. // There is no tag-ID for the root IFD. It will never be a child IFD.
if ifdPath != IfdPathStandard { if ifdPath != exifcommon.IfdPathStandard {
mi, err := ifd.ifdMapping.GetWithPath(ifdPath) mi, err := ifd.ifdMapping.GetWithPath(ifdPath)
log.PanicIf(err) log.PanicIf(err)
@ -523,7 +530,7 @@ func (ib *IfdBuilder) SetThumbnail(data []byte) (err error) {
} }
}() }()
if ib.ifdPath != IfdPathStandard { if ib.ifdPath != exifcommon.IfdPathStandard {
log.Panicf("thumbnails can only go into a root Ifd (and only the second one)") log.Panicf("thumbnails can only go into a root Ifd (and only the second one)")
} }
@ -540,7 +547,7 @@ func (ib *IfdBuilder) SetThumbnail(data []byte) (err error) {
NewBuilderTag( NewBuilderTag(
ib.ifdPath, ib.ifdPath,
ThumbnailOffsetTagId, ThumbnailOffsetTagId,
TypeLong, exifcommon.TypeLong,
ibtvfb, ibtvfb,
ib.byteOrder) ib.byteOrder)
@ -1113,13 +1120,15 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResol
var rawBytes []byte var rawBytes []byte
if ite.TagType == TypeUndefined { if ite.TagType == exifcommon.TypeUndefined {
// It's an undefined-type value. Try to process, or skip if // It's an undefined-type value. Try to process (or skip if
// we don't know how to. // 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.
undefinedInterface, err := valueContext.Undefined() value, err := exifundefined.Decode(ite.IfdPath, ite.TagId, valueContext, ib.byteOrder)
if err != nil { if err != nil {
if err == ErrUnhandledUnknownTypedTag { if err == exifcommon.ErrUnhandledUnknownTypedTag {
// It's an undefined-type tag that we don't handle. If // 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 // we don't know how to handle it, we can't know how
// many bytes it is and we must skip it. // many bytes it is and we must skip it.
@ -1129,19 +1138,14 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResol
log.Panic(err) log.Panic(err)
} }
undefined, ok := undefinedInterface.(UnknownTagValue) rawBytes, _, err = exifundefined.Encode(value, ib.byteOrder)
if ok != true {
log.Panicf("unexpected value returned from undefined-value processor")
}
rawBytes, err = undefined.ValueBytes()
log.PanicIf(err) log.PanicIf(err)
} else { } else {
// It's a value with a standard type. // It's a value with a standard type.
var err error var err error
rawBytes, err = valueContext.readRawEncoded() rawBytes, err = valueContext.ReadRawEncoded()
log.PanicIf(err) log.PanicIf(err)
} }

View File

@ -8,6 +8,8 @@ import (
"encoding/binary" "encoding/binary"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
) )
const ( const (
@ -219,8 +221,8 @@ func (ibe *IfdByteEncoder) encodeTagToBytes(ib *IfdBuilder, bt *BuilderTag, bw *
if bt.value.IsBytes() == true { if bt.value.IsBytes() == true {
effectiveType := bt.typeId effectiveType := bt.typeId
if bt.typeId == TypeUndefined { if bt.typeId == exifcommon.TypeUndefined {
effectiveType = TypeByte effectiveType = exifcommon.TypeByte
} }
// It's a non-unknown value.Calculate the count of values of // It's a non-unknown value.Calculate the count of values of

View File

@ -7,11 +7,13 @@ import (
"testing" "testing"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
) )
func Test_ByteWriter_writeAsBytes_uint8(t *testing.T) { func Test_ByteWriter_writeAsBytes_uint8(t *testing.T) {
b := new(bytes.Buffer) b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder) bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
err := bw.writeAsBytes(uint8(0x12)) err := bw.writeAsBytes(uint8(0x12))
log.PanicIf(err) log.PanicIf(err)
@ -23,7 +25,7 @@ func Test_ByteWriter_writeAsBytes_uint8(t *testing.T) {
func Test_ByteWriter_writeAsBytes_uint16(t *testing.T) { func Test_ByteWriter_writeAsBytes_uint16(t *testing.T) {
b := new(bytes.Buffer) b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder) bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
err := bw.writeAsBytes(uint16(0x1234)) err := bw.writeAsBytes(uint16(0x1234))
log.PanicIf(err) log.PanicIf(err)
@ -35,7 +37,7 @@ func Test_ByteWriter_writeAsBytes_uint16(t *testing.T) {
func Test_ByteWriter_writeAsBytes_uint32(t *testing.T) { func Test_ByteWriter_writeAsBytes_uint32(t *testing.T) {
b := new(bytes.Buffer) b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder) bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
err := bw.writeAsBytes(uint32(0x12345678)) err := bw.writeAsBytes(uint32(0x12345678))
log.PanicIf(err) log.PanicIf(err)
@ -47,7 +49,7 @@ func Test_ByteWriter_writeAsBytes_uint32(t *testing.T) {
func Test_ByteWriter_WriteUint16(t *testing.T) { func Test_ByteWriter_WriteUint16(t *testing.T) {
b := new(bytes.Buffer) b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder) bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
err := bw.WriteUint16(uint16(0x1234)) err := bw.WriteUint16(uint16(0x1234))
log.PanicIf(err) log.PanicIf(err)
@ -59,7 +61,7 @@ func Test_ByteWriter_WriteUint16(t *testing.T) {
func Test_ByteWriter_WriteUint32(t *testing.T) { func Test_ByteWriter_WriteUint32(t *testing.T) {
b := new(bytes.Buffer) b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder) bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
err := bw.WriteUint32(uint32(0x12345678)) err := bw.WriteUint32(uint32(0x12345678))
log.PanicIf(err) log.PanicIf(err)
@ -71,7 +73,7 @@ func Test_ByteWriter_WriteUint32(t *testing.T) {
func Test_ByteWriter_WriteFourBytes(t *testing.T) { func Test_ByteWriter_WriteFourBytes(t *testing.T) {
b := new(bytes.Buffer) b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder) bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
err := bw.WriteFourBytes([]byte{0x11, 0x22, 0x33, 0x44}) err := bw.WriteFourBytes([]byte{0x11, 0x22, 0x33, 0x44})
log.PanicIf(err) log.PanicIf(err)
@ -83,7 +85,7 @@ func Test_ByteWriter_WriteFourBytes(t *testing.T) {
func Test_ByteWriter_WriteFourBytes_TooMany(t *testing.T) { func Test_ByteWriter_WriteFourBytes_TooMany(t *testing.T) {
b := new(bytes.Buffer) b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder) bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
err := bw.WriteFourBytes([]byte{0x11, 0x22, 0x33, 0x44, 0x55}) err := bw.WriteFourBytes([]byte{0x11, 0x22, 0x33, 0x44, 0x55})
if err == nil { if err == nil {
@ -194,15 +196,15 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_embedded1(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandardGps, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandardGps, exifcommon.TestDefaultByteOrder)
it, err := ti.Get(ib.ifdPath, uint16(0x0000)) it, err := ti.Get(ib.ifdPath, uint16(0x0000))
log.PanicIf(err) log.PanicIf(err)
bt := NewStandardBuilderTag(IfdPathStandardGps, it, TestDefaultByteOrder, []uint8{uint8(0x12)}) bt := NewStandardBuilderTag(exifcommon.IfdPathStandardGps, it, exifcommon.TestDefaultByteOrder, []uint8{uint8(0x12)})
b := new(bytes.Buffer) b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder) bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
addressableOffset := uint32(0x1234) addressableOffset := uint32(0x1234)
ida := newIfdDataAllocator(addressableOffset) ida := newIfdDataAllocator(addressableOffset)
@ -228,15 +230,15 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_embedded2(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandardGps, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandardGps, exifcommon.TestDefaultByteOrder)
it, err := ti.Get(ib.ifdPath, uint16(0x0000)) it, err := ti.Get(ib.ifdPath, uint16(0x0000))
log.PanicIf(err) log.PanicIf(err)
bt := NewStandardBuilderTag(IfdPathStandardGps, it, TestDefaultByteOrder, []uint8{uint8(0x12), uint8(0x34), uint8(0x56), uint8(0x78)}) bt := NewStandardBuilderTag(exifcommon.IfdPathStandardGps, it, exifcommon.TestDefaultByteOrder, []uint8{uint8(0x12), uint8(0x34), uint8(0x56), uint8(0x78)})
b := new(bytes.Buffer) b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder) bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
addressableOffset := uint32(0x1234) addressableOffset := uint32(0x1234)
ida := newIfdDataAllocator(addressableOffset) ida := newIfdDataAllocator(addressableOffset)
@ -262,10 +264,10 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_allocated(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandardGps, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandardGps, exifcommon.TestDefaultByteOrder)
b := new(bytes.Buffer) b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder) bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
addressableOffset := uint32(0x1234) addressableOffset := uint32(0x1234)
ida := newIfdDataAllocator(addressableOffset) ida := newIfdDataAllocator(addressableOffset)
@ -273,7 +275,7 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_allocated(t *testing.T) {
it, err := ti.Get(ib.ifdPath, uint16(0x0000)) it, err := ti.Get(ib.ifdPath, uint16(0x0000))
log.PanicIf(err) log.PanicIf(err)
bt := NewStandardBuilderTag(IfdPathStandardGps, it, TestDefaultByteOrder, []uint8{uint8(0x12), uint8(0x34), uint8(0x56), uint8(0x78), uint8(0x9a)}) bt := NewStandardBuilderTag(exifcommon.IfdPathStandardGps, it, exifcommon.TestDefaultByteOrder, []uint8{uint8(0x12), uint8(0x34), uint8(0x56), uint8(0x78), uint8(0x9a)})
childIfdBlock, err := ibe.encodeTagToBytes(ib, bt, bw, ida, uint32(0)) childIfdBlock, err := ibe.encodeTagToBytes(ib, bt, bw, ida, uint32(0))
log.PanicIf(err) log.PanicIf(err)
@ -290,7 +292,7 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_allocated(t *testing.T) {
// Test that another allocation encodes to the new offset. // Test that another allocation encodes to the new offset.
bt = NewStandardBuilderTag(IfdPathStandardGps, it, TestDefaultByteOrder, []uint8{uint8(0xbc), uint8(0xde), uint8(0xf0), uint8(0x12), uint8(0x34)}) bt = NewStandardBuilderTag(exifcommon.IfdPathStandardGps, it, exifcommon.TestDefaultByteOrder, []uint8{uint8(0xbc), uint8(0xde), uint8(0xf0), uint8(0x12), uint8(0x34)})
childIfdBlock, err = ibe.encodeTagToBytes(ib, bt, bw, ida, uint32(0)) childIfdBlock, err = ibe.encodeTagToBytes(ib, bt, bw, ida, uint32(0))
log.PanicIf(err) log.PanicIf(err)
@ -321,17 +323,17 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withoutAllocate(t *testing.T
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
b := new(bytes.Buffer) b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder) bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
addressableOffset := uint32(0x1234) addressableOffset := uint32(0x1234)
ida := newIfdDataAllocator(addressableOffset) ida := newIfdDataAllocator(addressableOffset)
childIb := NewIfdBuilder(im, ti, IfdPathStandardExif, TestDefaultByteOrder) childIb := NewIfdBuilder(im, ti, exifcommon.IfdPathStandardExif, exifcommon.TestDefaultByteOrder)
tagValue := NewIfdBuilderTagValueFromIfdBuilder(childIb) tagValue := NewIfdBuilderTagValueFromIfdBuilder(childIb)
bt := NewChildIfdBuilderTag(IfdPathStandard, IfdExifId, tagValue) bt := NewChildIfdBuilderTag(exifcommon.IfdPathStandard, exifcommon.IfdExifId, tagValue)
nextIfdOffsetToWrite := uint32(0) nextIfdOffsetToWrite := uint32(0)
childIfdBlock, err := ibe.encodeTagToBytes(ib, bt, bw, ida, nextIfdOffsetToWrite) childIfdBlock, err := ibe.encodeTagToBytes(ib, bt, bw, ida, nextIfdOffsetToWrite)
@ -365,12 +367,12 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
childIb := NewIfdBuilder(im, ti, IfdPathStandardExif, TestDefaultByteOrder) childIb := NewIfdBuilder(im, ti, exifcommon.IfdPathStandardExif, exifcommon.TestDefaultByteOrder)
childIbTestTag := &BuilderTag{ childIbTestTag := &BuilderTag{
ifdPath: IfdPathStandardExif, ifdPath: exifcommon.IfdPathStandardExif,
tagId: 0x8822, tagId: 0x8822,
typeId: TypeShort, typeId: exifcommon.TypeShort,
value: NewIfdBuilderTagValueFromBytes([]byte{0x12, 0x34}), value: NewIfdBuilderTagValueFromBytes([]byte{0x12, 0x34}),
} }
@ -379,7 +381,7 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) {
// Formally compose the tag that refers to it. // Formally compose the tag that refers to it.
tagValue := NewIfdBuilderTagValueFromIfdBuilder(childIb) tagValue := NewIfdBuilderTagValueFromIfdBuilder(childIb)
bt := NewChildIfdBuilderTag(IfdPathStandard, IfdExifId, tagValue) bt := NewChildIfdBuilderTag(exifcommon.IfdPathStandard, exifcommon.IfdExifId, tagValue)
// Encode the tag. Since we've actually provided an offset at which we can // Encode the tag. Since we've actually provided an offset at which we can
// allocate data, the child-IFD will automatically be encoded, allocated, // allocate data, the child-IFD will automatically be encoded, allocated,
@ -388,10 +390,10 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) {
ibe := NewIfdByteEncoder() ibe := NewIfdByteEncoder()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
b := new(bytes.Buffer) b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder) bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
// addressableOffset is the offset of where large data can be allocated // addressableOffset is the offset of where large data can be allocated
// (which follows the IFD table/block). Large, in that it can't be stored // (which follows the IFD table/block). Large, in that it can't be stored
@ -420,14 +422,14 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) {
t.Fatalf("Child IFD is not the right size: (%d)", len(childIfdBlock)) t.Fatalf("Child IFD is not the right size: (%d)", len(childIfdBlock))
} }
iteV, err := ParseOneTag(im, ti, fmt.Sprintf("%s%d", IfdPathStandard, 0), IfdPathStandard, TestDefaultByteOrder, tagBytes, false) iteV, err := ParseOneTag(im, ti, fmt.Sprintf("%s%d", exifcommon.IfdPathStandard, 0), exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder, tagBytes, false)
log.PanicIf(err) log.PanicIf(err)
if iteV.TagId != IfdExifId { if iteV.TagId != exifcommon.IfdExifId {
t.Fatalf("IFD first tag-ID not correct: (0x%02x)", iteV.TagId) t.Fatalf("IFD first tag-ID not correct: (0x%02x)", iteV.TagId)
} else if iteV.TagIndex != 0 { } else if iteV.TagIndex != 0 {
t.Fatalf("IFD first tag index not correct: (%d)", iteV.TagIndex) t.Fatalf("IFD first tag index not correct: (%d)", iteV.TagIndex)
} else if iteV.TagType != TypeLong { } else if iteV.TagType != exifcommon.TypeLong {
t.Fatalf("IFD first tag type not correct: (%d)", iteV.TagType) t.Fatalf("IFD first tag type not correct: (%d)", iteV.TagType)
} else if iteV.UnitCount != 1 { } else if iteV.UnitCount != 1 {
t.Fatalf("IFD first tag unit-count not correct: (%d)", iteV.UnitCount) t.Fatalf("IFD first tag unit-count not correct: (%d)", iteV.UnitCount)
@ -435,15 +437,15 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) {
t.Fatalf("IFD's child-IFD offset (as offset) is not correct: (%d) != (%d)", 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 { } 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) t.Fatalf("IFD's child-IFD offset (as raw bytes) is not correct: [%x]", iteV.RawValueOffset)
} else if iteV.ChildIfdPath != IfdPathStandardExif { } else if iteV.ChildIfdPath != exifcommon.IfdPathStandardExif {
t.Fatalf("IFD first tag IFD-name name not correct: [%s]", iteV.ChildIfdPath) t.Fatalf("IFD first tag IFD-name name not correct: [%s]", iteV.ChildIfdPath)
} else if iteV.IfdPath != IfdPathStandard { } else if iteV.IfdPath != exifcommon.IfdPathStandard {
t.Fatalf("IFD first tag parent IFD not correct: %v", iteV.IfdPath) t.Fatalf("IFD first tag parent IFD not correct: %v", iteV.IfdPath)
} }
// Validate the child's raw IFD bytes. // Validate the child's raw IFD bytes.
childNextIfdOffset, childEntries, err := ParseOneIfd(im, ti, "IFD0/Exif0", "IFD/Exif", TestDefaultByteOrder, childIfdBlock, nil, false) childNextIfdOffset, childEntries, err := ParseOneIfd(im, ti, "IFD0/Exif0", "IFD/Exif", exifcommon.TestDefaultByteOrder, childIfdBlock, nil, false)
log.PanicIf(err) log.PanicIf(err)
if childNextIfdOffset != uint32(0) { if childNextIfdOffset != uint32(0) {
@ -458,7 +460,7 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) {
t.Fatalf("Child IFD first tag-ID not correct: (0x%02x)", ite.TagId) t.Fatalf("Child IFD first tag-ID not correct: (0x%02x)", ite.TagId)
} else if ite.TagIndex != 0 { } else if ite.TagIndex != 0 {
t.Fatalf("Child IFD first tag index not correct: (%d)", ite.TagIndex) t.Fatalf("Child IFD first tag index not correct: (%d)", ite.TagIndex)
} else if ite.TagType != TypeShort { } else if ite.TagType != exifcommon.TypeShort {
t.Fatalf("Child IFD first tag type not correct: (%d)", ite.TagType) t.Fatalf("Child IFD first tag type not correct: (%d)", ite.TagType)
} else if ite.UnitCount != 1 { } else if ite.UnitCount != 1 {
t.Fatalf("Child IFD first tag unit-count not correct: (%d)", ite.UnitCount) t.Fatalf("Child IFD first tag unit-count not correct: (%d)", ite.UnitCount)
@ -468,7 +470,7 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) {
t.Fatalf("Child IFD first tag value value (as raw bytes) not correct: [%v]", ite.RawValueOffset) t.Fatalf("Child IFD first tag value value (as raw bytes) not correct: [%v]", ite.RawValueOffset)
} else if ite.ChildIfdPath != "" { } else if ite.ChildIfdPath != "" {
t.Fatalf("Child IFD first tag IFD-name name not empty: [%s]", ite.ChildIfdPath) t.Fatalf("Child IFD first tag IFD-name name not empty: [%s]", ite.ChildIfdPath)
} else if ite.IfdPath != IfdPathStandardExif { } else if ite.IfdPath != exifcommon.IfdPathStandardExif {
t.Fatalf("Child IFD first tag parent IFD not correct: %v", ite.IfdPath) t.Fatalf("Child IFD first tag parent IFD not correct: %v", ite.IfdPath)
} }
} }
@ -495,16 +497,16 @@ func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
it, err := ib.tagIndex.Get(ib.ifdPath, uint16(0x000b)) it, err := ib.tagIndex.Get(ib.ifdPath, uint16(0x000b))
log.PanicIf(err) log.PanicIf(err)
valueString := "testvalue" valueString := "testvalue"
bt := NewStandardBuilderTag(IfdPathStandard, it, TestDefaultByteOrder, valueString) bt := NewStandardBuilderTag(exifcommon.IfdPathStandard, it, exifcommon.TestDefaultByteOrder, valueString)
b := new(bytes.Buffer) b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder) bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
// addressableOffset is the offset of where large data can be allocated // addressableOffset is the offset of where large data can be allocated
// (which follows the IFD table/block). Large, in that it can't be stored // (which follows the IFD table/block). Large, in that it can't be stored
@ -529,14 +531,14 @@ func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) {
t.Fatalf("Child IFD not have been allocated.") t.Fatalf("Child IFD not have been allocated.")
} }
ite, err := ParseOneTag(im, ti, fmt.Sprintf("%s%d", IfdPathStandard, 0), IfdPathStandard, TestDefaultByteOrder, tagBytes, false) ite, err := ParseOneTag(im, ti, fmt.Sprintf("%s%d", exifcommon.IfdPathStandard, 0), exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder, tagBytes, false)
log.PanicIf(err) log.PanicIf(err)
if ite.TagId != 0x000b { if ite.TagId != 0x000b {
t.Fatalf("Tag-ID not correct: (0x%02x)", ite.TagId) t.Fatalf("Tag-ID not correct: (0x%02x)", ite.TagId)
} else if ite.TagIndex != 0 { } else if ite.TagIndex != 0 {
t.Fatalf("Tag index not correct: (%d)", ite.TagIndex) t.Fatalf("Tag index not correct: (%d)", ite.TagIndex)
} else if ite.TagType != TypeAscii { } else if ite.TagType != exifcommon.TypeAscii {
t.Fatalf("Tag type not correct: (%d)", ite.TagType) t.Fatalf("Tag type not correct: (%d)", ite.TagType)
} else if ite.UnitCount != (uint32(len(valueString) + 1)) { } else if ite.UnitCount != (uint32(len(valueString) + 1)) {
t.Fatalf("Tag unit-count not correct: (%d)", ite.UnitCount) t.Fatalf("Tag unit-count not correct: (%d)", ite.UnitCount)
@ -546,7 +548,7 @@ func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) {
t.Fatalf("Tag's value (as raw bytes) is not correct: [%x]", ite.RawValueOffset) t.Fatalf("Tag's value (as raw bytes) is not correct: [%x]", ite.RawValueOffset)
} else if ite.ChildIfdPath != "" { } else if ite.ChildIfdPath != "" {
t.Fatalf("Tag's IFD-name should be empty: [%s]", ite.ChildIfdPath) t.Fatalf("Tag's IFD-name should be empty: [%s]", ite.ChildIfdPath)
} else if ite.IfdPath != IfdPathStandard { } else if ite.IfdPath != exifcommon.IfdPathStandard {
t.Fatalf("Tag's parent IFD is not correct: %v", ite.IfdPath) t.Fatalf("Tag's parent IFD is not correct: %v", ite.IfdPath)
} }
@ -617,7 +619,7 @@ func Test_IfdByteEncoder_encodeIfdToBytes_simple(t *testing.T) {
} }
if bytes.Compare(tableAndAllocated, expectedIfdAndDataBytes) != 0 { if bytes.Compare(tableAndAllocated, expectedIfdAndDataBytes) != 0 {
t.Fatalf("IFD table and allocated data not correct: %v", DumpBytesClauseToString(tableAndAllocated)) t.Fatalf("IFD table and allocated data not correct: %v", exifcommon.DumpBytesClauseToString(tableAndAllocated))
} }
} }
@ -655,7 +657,7 @@ func Test_IfdByteEncoder_encodeIfdToBytes_fullExif(t *testing.T) {
b := new(bytes.Buffer) b := new(bytes.Buffer)
headerBytes, err := BuildExifHeader(TestDefaultByteOrder, ExifDefaultFirstIfdOffset) headerBytes, err := BuildExifHeader(exifcommon.TestDefaultByteOrder, ExifDefaultFirstIfdOffset)
log.PanicIf(err) log.PanicIf(err)
_, err = b.Write(headerBytes) _, err = b.Write(headerBytes)
@ -693,7 +695,7 @@ func Test_IfdByteEncoder_EncodeToExifPayload(t *testing.T) {
b := new(bytes.Buffer) b := new(bytes.Buffer)
headerBytes, err := BuildExifHeader(TestDefaultByteOrder, ExifDefaultFirstIfdOffset) headerBytes, err := BuildExifHeader(exifcommon.TestDefaultByteOrder, ExifDefaultFirstIfdOffset)
log.PanicIf(err) log.PanicIf(err)
_, err = b.Write(headerBytes) _, err = b.Write(headerBytes)
@ -737,7 +739,7 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
err = ib.AddStandard(0x000b, "asciivalue") err = ib.AddStandard(0x000b, "asciivalue")
log.PanicIf(err) log.PanicIf(err)
@ -747,7 +749,7 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
// Add a child IB right in the middle. // Add a child IB right in the middle.
childIb := NewIfdBuilder(im, ti, IfdPathStandardExif, TestDefaultByteOrder) childIb := NewIfdBuilder(im, ti, exifcommon.IfdPathStandardExif, exifcommon.TestDefaultByteOrder)
err = childIb.AddStandardWithName("ISOSpeedRatings", []uint16{0x1122}) err = childIb.AddStandardWithName("ISOSpeedRatings", []uint16{0x1122})
log.PanicIf(err) log.PanicIf(err)
@ -764,7 +766,7 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
// Add another child IB, just to ensure a little more punishment and make // Add another child IB, just to ensure a little more punishment and make
// sure we're managing our allocation offsets correctly. // sure we're managing our allocation offsets correctly.
childIb2 := NewIfdBuilder(im, ti, IfdPathStandardGps, TestDefaultByteOrder) childIb2 := NewIfdBuilder(im, ti, exifcommon.IfdPathStandardGps, exifcommon.TestDefaultByteOrder)
err = childIb2.AddStandardWithName("GPSAltitudeRef", []uint8{0x11, 0x22}) err = childIb2.AddStandardWithName("GPSAltitudeRef", []uint8{0x11, 0x22})
log.PanicIf(err) log.PanicIf(err)
@ -772,13 +774,13 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
err = ib.AddChildIb(childIb2) err = ib.AddChildIb(childIb2)
log.PanicIf(err) log.PanicIf(err)
err = ib.AddStandard(0x013e, []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}) err = ib.AddStandard(0x013e, []exifcommon.Rational{{Numerator: 0x11112222, Denominator: 0x33334444}})
log.PanicIf(err) log.PanicIf(err)
// Link to another IB (sibling relationship). The root/standard IFD may // Link to another IB (sibling relationship). The root/standard IFD may
// occur twice in some JPEGs (for thumbnail or FlashPix images). // occur twice in some JPEGs (for thumbnail or FlashPix images).
nextIb := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) nextIb := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
err = nextIb.AddStandard(0x0101, []uint32{0x11223344}) err = nextIb.AddStandard(0x0101, []uint32{0x11223344})
log.PanicIf(err) log.PanicIf(err)
@ -852,7 +854,7 @@ func ExampleIfdByteEncoder_EncodeToExif() {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
err = ib.AddStandardWithName("ProcessingSoftware", "asciivalue") err = ib.AddStandardWithName("ProcessingSoftware", "asciivalue")
log.PanicIf(err) log.PanicIf(err)
@ -866,10 +868,10 @@ func ExampleIfdByteEncoder_EncodeToExif() {
err = ib.AddStandardWithName("ImageWidth", []uint32{0x44556677}) err = ib.AddStandardWithName("ImageWidth", []uint32{0x44556677})
log.PanicIf(err) log.PanicIf(err)
err = ib.AddStandardWithName("WhitePoint", []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}) err = ib.AddStandardWithName("WhitePoint", []exifcommon.Rational{{Numerator: 0x11112222, Denominator: 0x33334444}})
log.PanicIf(err) log.PanicIf(err)
err = ib.AddStandardWithName("ShutterSpeedValue", []SignedRational{{Numerator: 0x11112222, Denominator: 0x33334444}}) err = ib.AddStandardWithName("ShutterSpeedValue", []exifcommon.SignedRational{{Numerator: 0x11112222, Denominator: 0x33334444}})
log.PanicIf(err) log.PanicIf(err)
// Encode it. // Encode it.
@ -889,7 +891,7 @@ func ExampleIfdByteEncoder_EncodeToExif() {
addressableData := exifData[ExifAddressableAreaStart:] addressableData := exifData[ExifAddressableAreaStart:]
for i, e := range index.RootIfd.Entries { for i, e := range index.RootIfd.Entries {
value, err := e.Value(addressableData, TestDefaultByteOrder) value, err := e.Value(addressableData, exifcommon.TestDefaultByteOrder)
log.PanicIf(err) log.PanicIf(err)
fmt.Printf("%d: %s [%v]\n", i, e, value) fmt.Printf("%d: %s [%v]\n", i, e, value)

View File

@ -7,6 +7,8 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/dsoprea/go-exif/v2/common"
"github.com/dsoprea/go-exif/v2/undefined"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
) )
@ -17,11 +19,11 @@ func TestIfdBuilder_Add(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -30,8 +32,8 @@ func TestIfdBuilder_Add(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string2")), value: NewIfdBuilderTagValueFromBytes([]byte("test string2")),
} }
@ -40,8 +42,8 @@ func TestIfdBuilder_Add(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string3")), value: NewIfdBuilderTagValueFromBytes([]byte("test string3")),
} }
@ -52,8 +54,8 @@ func TestIfdBuilder_Add(t *testing.T) {
originalBytes := []byte{0x11, 0x22, 0x33} originalBytes := []byte{0x11, 0x22, 0x33}
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x44, tagId: 0x44,
value: NewIfdBuilderTagValueFromBytes([]byte(originalBytes)), value: NewIfdBuilderTagValueFromBytes([]byte(originalBytes)),
} }
@ -61,11 +63,11 @@ func TestIfdBuilder_Add(t *testing.T) {
err = ib.Add(bt) err = ib.Add(bt)
log.PanicIf(err) log.PanicIf(err)
if ib.ifdPath != IfdPathStandard { if ib.ifdPath != exifcommon.IfdPathStandard {
t.Fatalf("IFD name not correct.") t.Fatalf("IFD name not correct.")
} else if ib.ifdTagId != 0 { } else if ib.ifdTagId != 0 {
t.Fatalf("IFD tag-ID not correct.") t.Fatalf("IFD tag-ID not correct.")
} else if ib.byteOrder != TestDefaultByteOrder { } else if ib.byteOrder != exifcommon.TestDefaultByteOrder {
t.Fatalf("IFD byte-order not correct.") t.Fatalf("IFD byte-order not correct.")
} else if len(ib.tags) != 4 { } else if len(ib.tags) != 4 {
t.Fatalf("IFD tag-count not correct.") t.Fatalf("IFD tag-count not correct.")
@ -110,8 +112,8 @@ func TestIfdBuilder_SetNextIb(t *testing.T) {
ti := NewTagIndex() ti := NewTagIndex()
ib1 := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib1 := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
ib2 := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib2 := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
if ib1.nextIb != nil { if ib1.nextIb != nil {
t.Fatalf("Next-IFD for IB1 not initially terminal.") t.Fatalf("Next-IFD for IB1 not initially terminal.")
@ -134,11 +136,11 @@ func TestIfdBuilder_AddChildIb(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -146,13 +148,13 @@ func TestIfdBuilder_AddChildIb(t *testing.T) {
err = ib.Add(bt) err = ib.Add(bt)
log.PanicIf(err) log.PanicIf(err)
ibChild := NewIfdBuilder(im, ti, IfdPathStandardExif, TestDefaultByteOrder) ibChild := NewIfdBuilder(im, ti, exifcommon.IfdPathStandardExif, exifcommon.TestDefaultByteOrder)
err = ib.AddChildIb(ibChild) err = ib.AddChildIb(ibChild)
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -193,7 +195,7 @@ func TestIfdBuilder_AddTagsFromExisting(t *testing.T) {
_, index, err := Collect(im, ti, exifData) _, index, err := Collect(im, ti, exifData)
log.PanicIf(err) log.PanicIf(err)
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
err = ib.AddTagsFromExisting(index.RootIfd, nil, nil, nil) err = ib.AddTagsFromExisting(index.RootIfd, nil, nil, nil)
log.PanicIf(err) log.PanicIf(err)
@ -229,7 +231,7 @@ func TestIfdBuilder_AddTagsFromExisting__Includes(t *testing.T) {
_, index, err := Collect(im, ti, exifData) _, index, err := Collect(im, ti, exifData)
log.PanicIf(err) log.PanicIf(err)
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
err = ib.AddTagsFromExisting(index.RootIfd, nil, []uint16{0x00ff}, nil) err = ib.AddTagsFromExisting(index.RootIfd, nil, []uint16{0x00ff}, nil)
log.PanicIf(err) log.PanicIf(err)
@ -262,7 +264,7 @@ func TestIfdBuilder_AddTagsFromExisting__Excludes(t *testing.T) {
_, index, err := Collect(im, ti, exifData) _, index, err := Collect(im, ti, exifData)
log.PanicIf(err) log.PanicIf(err)
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
err = ib.AddTagsFromExisting(index.RootIfd, nil, nil, []uint16{0xff}) err = ib.AddTagsFromExisting(index.RootIfd, nil, nil, []uint16{0xff})
log.PanicIf(err) log.PanicIf(err)
@ -291,11 +293,11 @@ func TestIfdBuilder_FindN__First_1(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -304,8 +306,8 @@ func TestIfdBuilder_FindN__First_1(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string2")), value: NewIfdBuilderTagValueFromBytes([]byte("test string2")),
} }
@ -314,8 +316,8 @@ func TestIfdBuilder_FindN__First_1(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string3")), value: NewIfdBuilderTagValueFromBytes([]byte("test string3")),
} }
@ -347,11 +349,11 @@ func TestIfdBuilder_FindN__First_2_1Returned(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -360,8 +362,8 @@ func TestIfdBuilder_FindN__First_2_1Returned(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string2")), value: NewIfdBuilderTagValueFromBytes([]byte("test string2")),
} }
@ -370,8 +372,8 @@ func TestIfdBuilder_FindN__First_2_1Returned(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string3")), value: NewIfdBuilderTagValueFromBytes([]byte("test string3")),
} }
@ -403,11 +405,11 @@ func TestIfdBuilder_FindN__First_2_2Returned(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -416,8 +418,8 @@ func TestIfdBuilder_FindN__First_2_2Returned(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string2")), value: NewIfdBuilderTagValueFromBytes([]byte("test string2")),
} }
@ -426,8 +428,8 @@ func TestIfdBuilder_FindN__First_2_2Returned(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string3")), value: NewIfdBuilderTagValueFromBytes([]byte("test string3")),
} }
@ -436,8 +438,8 @@ func TestIfdBuilder_FindN__First_2_2Returned(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string4")), value: NewIfdBuilderTagValueFromBytes([]byte("test string4")),
} }
@ -446,8 +448,8 @@ func TestIfdBuilder_FindN__First_2_2Returned(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string5")), value: NewIfdBuilderTagValueFromBytes([]byte("test string5")),
} }
@ -486,11 +488,11 @@ func TestIfdBuilder_FindN__Middle_WithDuplicates(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -499,8 +501,8 @@ func TestIfdBuilder_FindN__Middle_WithDuplicates(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string2")), value: NewIfdBuilderTagValueFromBytes([]byte("test string2")),
} }
@ -509,8 +511,8 @@ func TestIfdBuilder_FindN__Middle_WithDuplicates(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string3")), value: NewIfdBuilderTagValueFromBytes([]byte("test string3")),
} }
@ -519,8 +521,8 @@ func TestIfdBuilder_FindN__Middle_WithDuplicates(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string4")), value: NewIfdBuilderTagValueFromBytes([]byte("test string4")),
} }
@ -529,8 +531,8 @@ func TestIfdBuilder_FindN__Middle_WithDuplicates(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string5")), value: NewIfdBuilderTagValueFromBytes([]byte("test string5")),
} }
@ -539,8 +541,8 @@ func TestIfdBuilder_FindN__Middle_WithDuplicates(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string6")), value: NewIfdBuilderTagValueFromBytes([]byte("test string6")),
} }
@ -572,11 +574,11 @@ func TestIfdBuilder_FindN__Middle_NoDuplicates(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -585,8 +587,8 @@ func TestIfdBuilder_FindN__Middle_NoDuplicates(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string2")), value: NewIfdBuilderTagValueFromBytes([]byte("test string2")),
} }
@ -595,8 +597,8 @@ func TestIfdBuilder_FindN__Middle_NoDuplicates(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string3")), value: NewIfdBuilderTagValueFromBytes([]byte("test string3")),
} }
@ -605,8 +607,8 @@ func TestIfdBuilder_FindN__Middle_NoDuplicates(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string4")), value: NewIfdBuilderTagValueFromBytes([]byte("test string4")),
} }
@ -638,7 +640,7 @@ func TestIfdBuilder_FindN__Miss(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
found, err := ib.FindN(0x11, 1) found, err := ib.FindN(0x11, 1)
log.PanicIf(err) log.PanicIf(err)
@ -655,11 +657,11 @@ func TestIfdBuilder_Find__Hit(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -668,8 +670,8 @@ func TestIfdBuilder_Find__Hit(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string2")), value: NewIfdBuilderTagValueFromBytes([]byte("test string2")),
} }
@ -678,8 +680,8 @@ func TestIfdBuilder_Find__Hit(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string3")), value: NewIfdBuilderTagValueFromBytes([]byte("test string3")),
} }
@ -688,8 +690,8 @@ func TestIfdBuilder_Find__Hit(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string4")), value: NewIfdBuilderTagValueFromBytes([]byte("test string4")),
} }
@ -719,11 +721,11 @@ func TestIfdBuilder_Find__Miss(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -732,8 +734,8 @@ func TestIfdBuilder_Find__Miss(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string2")), value: NewIfdBuilderTagValueFromBytes([]byte("test string2")),
} }
@ -742,8 +744,8 @@ func TestIfdBuilder_Find__Miss(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string3")), value: NewIfdBuilderTagValueFromBytes([]byte("test string3")),
} }
@ -752,8 +754,8 @@ func TestIfdBuilder_Find__Miss(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string4")), value: NewIfdBuilderTagValueFromBytes([]byte("test string4")),
} }
@ -776,11 +778,11 @@ func TestIfdBuilder_Replace(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -789,8 +791,8 @@ func TestIfdBuilder_Replace(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string2")), value: NewIfdBuilderTagValueFromBytes([]byte("test string2")),
} }
@ -799,8 +801,8 @@ func TestIfdBuilder_Replace(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string3")), value: NewIfdBuilderTagValueFromBytes([]byte("test string3")),
} }
@ -818,8 +820,8 @@ func TestIfdBuilder_Replace(t *testing.T) {
} }
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x99, tagId: 0x99,
value: NewIfdBuilderTagValueFromBytes([]byte("test string4")), value: NewIfdBuilderTagValueFromBytes([]byte("test string4")),
} }
@ -844,11 +846,11 @@ func TestIfdBuilder_ReplaceN(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -857,8 +859,8 @@ func TestIfdBuilder_ReplaceN(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string2")), value: NewIfdBuilderTagValueFromBytes([]byte("test string2")),
} }
@ -867,8 +869,8 @@ func TestIfdBuilder_ReplaceN(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string3")), value: NewIfdBuilderTagValueFromBytes([]byte("test string3")),
} }
@ -886,8 +888,8 @@ func TestIfdBuilder_ReplaceN(t *testing.T) {
} }
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0xA9, tagId: 0xA9,
value: NewIfdBuilderTagValueFromBytes([]byte("test string4")), value: NewIfdBuilderTagValueFromBytes([]byte("test string4")),
} }
@ -912,11 +914,11 @@ func TestIfdBuilder_DeleteFirst(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -925,8 +927,8 @@ func TestIfdBuilder_DeleteFirst(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string2")), value: NewIfdBuilderTagValueFromBytes([]byte("test string2")),
} }
@ -935,8 +937,8 @@ func TestIfdBuilder_DeleteFirst(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string3")), value: NewIfdBuilderTagValueFromBytes([]byte("test string3")),
} }
@ -945,8 +947,8 @@ func TestIfdBuilder_DeleteFirst(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string4")), value: NewIfdBuilderTagValueFromBytes([]byte("test string4")),
} }
@ -1014,11 +1016,11 @@ func TestIfdBuilder_DeleteN(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -1027,8 +1029,8 @@ func TestIfdBuilder_DeleteN(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string2")), value: NewIfdBuilderTagValueFromBytes([]byte("test string2")),
} }
@ -1037,8 +1039,8 @@ func TestIfdBuilder_DeleteN(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string3")), value: NewIfdBuilderTagValueFromBytes([]byte("test string3")),
} }
@ -1047,8 +1049,8 @@ func TestIfdBuilder_DeleteN(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string4")), value: NewIfdBuilderTagValueFromBytes([]byte("test string4")),
} }
@ -1116,11 +1118,11 @@ func TestIfdBuilder_DeleteN_Two(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -1129,8 +1131,8 @@ func TestIfdBuilder_DeleteN_Two(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string2")), value: NewIfdBuilderTagValueFromBytes([]byte("test string2")),
} }
@ -1139,8 +1141,8 @@ func TestIfdBuilder_DeleteN_Two(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string3")), value: NewIfdBuilderTagValueFromBytes([]byte("test string3")),
} }
@ -1149,8 +1151,8 @@ func TestIfdBuilder_DeleteN_Two(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string4")), value: NewIfdBuilderTagValueFromBytes([]byte("test string4")),
} }
@ -1202,11 +1204,11 @@ func TestIfdBuilder_DeleteAll(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
bt := &BuilderTag{ bt := &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x11, tagId: 0x11,
value: NewIfdBuilderTagValueFromBytes([]byte("test string")), value: NewIfdBuilderTagValueFromBytes([]byte("test string")),
} }
@ -1215,8 +1217,8 @@ func TestIfdBuilder_DeleteAll(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string2")), value: NewIfdBuilderTagValueFromBytes([]byte("test string2")),
} }
@ -1225,8 +1227,8 @@ func TestIfdBuilder_DeleteAll(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x22, tagId: 0x22,
value: NewIfdBuilderTagValueFromBytes([]byte("test string3")), value: NewIfdBuilderTagValueFromBytes([]byte("test string3")),
} }
@ -1235,8 +1237,8 @@ func TestIfdBuilder_DeleteAll(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
bt = &BuilderTag{ bt = &BuilderTag{
ifdPath: IfdPathStandard, ifdPath: exifcommon.IfdPathStandard,
typeId: TypeByte, typeId: exifcommon.TypeByte,
tagId: 0x33, tagId: 0x33,
value: NewIfdBuilderTagValueFromBytes([]byte("test string4")), value: NewIfdBuilderTagValueFromBytes([]byte("test string4")),
} }
@ -1486,15 +1488,69 @@ func TestIfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
t.Fatalf("Tag-type not as expected: %d != %d ITE=%s", recoveredIte.TagType, originalIte.TagType, recoveredIte) t.Fatalf("Tag-type not as expected: %d != %d ITE=%s", recoveredIte.TagType, originalIte.TagType, recoveredIte)
} }
var originalValueBytes []byte
if originalIte.TagType == exifcommon.TypeUndefined {
var err error
valueContext :=
newValueContextFromTag(
originalIte,
originalIndex.RootIfd.addressableData,
originalIndex.RootIfd.ByteOrder)
value, err := exifundefined.Decode(
originalIte.IfdPath,
originalIte.TagId,
valueContext,
originalIndex.RootIfd.ByteOrder)
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. // 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.ValueBytes(originalIndex.RootIfd.addressableData, originalIndex.RootIfd.ByteOrder)
log.PanicIf(err)
}
var recoveredValueBytes []byte
if recoveredIte.TagType == exifcommon.TypeUndefined {
var err error
valueContext :=
newValueContextFromTag(
recoveredIte,
recoveredIndex.RootIfd.addressableData,
recoveredIndex.RootIfd.ByteOrder)
value, err := exifundefined.Decode(
recoveredIte.IfdPath,
recoveredIte.TagId,
valueContext,
recoveredIndex.RootIfd.ByteOrder)
log.PanicIf(err) log.PanicIf(err)
recoveredValueBytes, err := recoveredIte.ValueBytes(recoveredIndex.RootIfd.addressableData, recoveredIndex.RootIfd.ByteOrder) recoveredValueBytes, _, err = exifundefined.Encode(value, recoveredIndex.RootIfd.ByteOrder)
log.PanicIf(err) } else {
var err error
if bytes.Compare(originalValueBytes, recoveredValueBytes) != 0 { recoveredValueBytes, err = recoveredIte.ValueBytes(recoveredIndex.RootIfd.addressableData, recoveredIndex.RootIfd.ByteOrder)
t.Fatalf("bytes of tag content not correct: %s != %s", originalIte, recoveredIte) log.PanicIf(err)
}
if bytes.Compare(recoveredValueBytes, originalValueBytes) != 0 {
fmt.Printf("ACTUAL: %s\n", originalIte)
exifcommon.DumpBytes(recoveredValueBytes)
fmt.Printf("EXPECTED: %s\n", recoveredIte)
exifcommon.DumpBytes(originalValueBytes)
t.Fatalf("Bytes of tag content not correct.")
} }
} }
} }
@ -1529,8 +1585,8 @@ func TestIfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) {
// ucBt, err := exifBt.value.Ib().FindTagWithName("UserComment") // ucBt, err := exifBt.value.Ib().FindTagWithName("UserComment")
// log.PanicIf(err) // log.PanicIf(err)
// uc := TagUnknownType_9298_UserComment{ // uc := exifundefined.Tag9286UserComment{
// EncodingType: TagUnknownType_9298_UserComment_Encoding_ASCII, // EncodingType: TagUndefinedType_9286_UserComment_Encoding_ASCII,
// EncodingBytes: []byte("TEST COMMENT"), // EncodingBytes: []byte("TEST COMMENT"),
// } // }
@ -1687,8 +1743,8 @@ func ExampleBuilderTag_SetValue() {
// its type-specific struct. // its type-specific struct.
// TODO(dustin): !! Add an example for setting a non-unknown value, too. // TODO(dustin): !! Add an example for setting a non-unknown value, too.
uc := TagUnknownType_9298_UserComment{ uc := exifundefined.Tag9286UserComment{
EncodingType: TagUnknownType_9298_UserComment_Encoding_ASCII, EncodingType: exifundefined.TagUndefinedType_9286_UserComment_Encoding_ASCII,
EncodingBytes: []byte("TEST COMMENT"), EncodingBytes: []byte("TEST COMMENT"),
} }
@ -1793,19 +1849,19 @@ func TestIfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) {
err := LoadStandardIfds(im) err := LoadStandardIfds(im)
log.PanicIf(err) log.PanicIf(err)
mi, err := im.GetWithPath(IfdPathStandardGps) mi, err := im.GetWithPath(exifcommon.IfdPathStandardGps)
log.PanicIf(err) log.PanicIf(err)
tagId := mi.TagId tagId := mi.TagId
parentIfd := &Ifd{ parentIfd := &Ifd{
IfdPath: IfdPathStandard, IfdPath: exifcommon.IfdPathStandard,
tagIndex: ti, tagIndex: ti,
} }
ifd := &Ifd{ ifd := &Ifd{
IfdPath: IfdPathStandardGps, IfdPath: exifcommon.IfdPathStandardGps,
ByteOrder: TestDefaultByteOrder, ByteOrder: exifcommon.TestDefaultByteOrder,
Offset: 0x123, Offset: 0x123,
ParentIfd: parentIfd, ParentIfd: parentIfd,
@ -1829,12 +1885,12 @@ func TestIfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) {
func TestNewStandardBuilderTag__OneUnit(t *testing.T) { func TestNewStandardBuilderTag__OneUnit(t *testing.T) {
ti := NewTagIndex() ti := NewTagIndex()
it, err := ti.Get(IfdPathStandardExif, uint16(0x8833)) it, err := ti.Get(exifcommon.IfdPathStandardExif, uint16(0x8833))
log.PanicIf(err) log.PanicIf(err)
bt := NewStandardBuilderTag(IfdPathStandardExif, it, TestDefaultByteOrder, []uint32{uint32(0x1234)}) bt := NewStandardBuilderTag(exifcommon.IfdPathStandardExif, it, exifcommon.TestDefaultByteOrder, []uint32{uint32(0x1234)})
if bt.ifdPath != IfdPathStandardExif { if bt.ifdPath != exifcommon.IfdPathStandardExif {
t.Fatalf("II in BuilderTag not correct") t.Fatalf("II in BuilderTag not correct")
} else if bt.tagId != 0x8833 { } else if bt.tagId != 0x8833 {
t.Fatalf("tag-ID not correct") t.Fatalf("tag-ID not correct")
@ -1846,12 +1902,12 @@ func TestNewStandardBuilderTag__OneUnit(t *testing.T) {
func TestNewStandardBuilderTag__TwoUnits(t *testing.T) { func TestNewStandardBuilderTag__TwoUnits(t *testing.T) {
ti := NewTagIndex() ti := NewTagIndex()
it, err := ti.Get(IfdPathStandardExif, uint16(0x8833)) it, err := ti.Get(exifcommon.IfdPathStandardExif, uint16(0x8833))
log.PanicIf(err) log.PanicIf(err)
bt := NewStandardBuilderTag(IfdPathStandardExif, it, TestDefaultByteOrder, []uint32{uint32(0x1234), uint32(0x5678)}) bt := NewStandardBuilderTag(exifcommon.IfdPathStandardExif, it, exifcommon.TestDefaultByteOrder, []uint32{uint32(0x1234), uint32(0x5678)})
if bt.ifdPath != IfdPathStandardExif { if bt.ifdPath != exifcommon.IfdPathStandardExif {
t.Fatalf("II in BuilderTag not correct") t.Fatalf("II in BuilderTag not correct")
} else if bt.tagId != 0x8833 { } else if bt.tagId != 0x8833 {
t.Fatalf("tag-ID not correct") t.Fatalf("tag-ID not correct")
@ -1869,7 +1925,7 @@ func TestIfdBuilder_AddStandardWithName(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
err = ib.AddStandardWithName("ProcessingSoftware", "some software") err = ib.AddStandardWithName("ProcessingSoftware", "some software")
log.PanicIf(err) log.PanicIf(err)
@ -1880,7 +1936,7 @@ func TestIfdBuilder_AddStandardWithName(t *testing.T) {
bt := ib.tags[0] bt := ib.tags[0]
if bt.ifdPath != IfdPathStandard { if bt.ifdPath != exifcommon.IfdPathStandard {
t.Fatalf("II not correct: %s", bt.ifdPath) t.Fatalf("II not correct: %s", bt.ifdPath)
} else if bt.tagId != 0x000b { } else if bt.tagId != 0x000b {
t.Fatalf("Tag-ID not correct: (0x%04x)", bt.tagId) t.Fatalf("Tag-ID not correct: (0x%04x)", bt.tagId)
@ -1900,7 +1956,7 @@ func TestGetOrCreateIbFromRootIb__Noop(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
rootIb := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) rootIb := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
ib, err := GetOrCreateIbFromRootIb(rootIb, "IFD") ib, err := GetOrCreateIbFromRootIb(rootIb, "IFD")
log.PanicIf(err) log.PanicIf(err)
@ -1921,7 +1977,7 @@ func TestGetOrCreateIbFromRootIb__FqNoop(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
rootIb := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) rootIb := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
ib, err := GetOrCreateIbFromRootIb(rootIb, "IFD0") ib, err := GetOrCreateIbFromRootIb(rootIb, "IFD0")
log.PanicIf(err) log.PanicIf(err)
@ -1942,7 +1998,7 @@ func TestGetOrCreateIbFromRootIb_InvalidChild(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
rootIb := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) rootIb := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
_, err = GetOrCreateIbFromRootIb(rootIb, "IFD/Invalid") _, err = GetOrCreateIbFromRootIb(rootIb, "IFD/Invalid")
if err == nil { if err == nil {
@ -1966,7 +2022,7 @@ func TestGetOrCreateIbFromRootIb__Child(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
rootIb := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) rootIb := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
lines := rootIb.DumpToStrings() lines := rootIb.DumpToStrings()
expected := []string{ expected := []string{

View File

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"reflect"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -12,6 +11,9 @@ import (
"encoding/binary" "encoding/binary"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
"github.com/dsoprea/go-exif/v2/undefined"
) )
var ( var (
@ -159,7 +161,7 @@ func (ie *IfdEnumerate) parseTag(fqIfdPath string, tagPosition int, ite *IfdTagE
tagTypeRaw, _, err := ite.getUint16() tagTypeRaw, _, err := ite.getUint16()
log.PanicIf(err) log.PanicIf(err)
tagType := TagTypePrimitive(tagTypeRaw) tagType := exifcommon.TagTypePrimitive(tagTypeRaw)
unitCount, _, err := ite.getUint32() unitCount, _, err := ite.getUint32()
log.PanicIf(err) log.PanicIf(err)
@ -167,7 +169,7 @@ func (ie *IfdEnumerate) parseTag(fqIfdPath string, tagPosition int, ite *IfdTagE
valueOffset, rawValueOffset, err := ite.getUint32() valueOffset, rawValueOffset, err := ite.getUint32()
log.PanicIf(err) log.PanicIf(err)
if _, found := TypeNames[tagType]; found == false { if tagType.IsValid() == false {
log.Panic(ErrTagTypeNotValid) log.Panic(ErrTagTypeNotValid)
} }
@ -210,7 +212,7 @@ func (ie *IfdEnumerate) parseTag(fqIfdPath string, tagPosition int, ite *IfdTagE
return tag, nil return tag, nil
} }
func (ie *IfdEnumerate) GetValueContext(ite *IfdTagEntry) *ValueContext { func (ie *IfdEnumerate) GetValueContext(ite *IfdTagEntry) *exifcommon.ValueContext {
// TODO(dustin): Add test // TODO(dustin): Add test
@ -229,120 +231,56 @@ func (ie *IfdEnumerate) resolveTagValue(ite *IfdTagEntry) (valueBytes []byte, is
} }
}() }()
addressableData := ie.exifData[ExifAddressableAreaStart:] valueContext := ie.GetValueContext(ite)
// Return the exact bytes of the unknown-type value. Returning a string // Return the exact bytes of the unknown-type value. Returning a string
// (`ValueString`) is easy because we can just pass everything to // (`ValueString`) is easy because we can just pass everything to
// `Sprintf()`. Returning the raw, typed value (`Value`) is easy // `Sprintf()`. Returning the raw, typed value (`Value`) is easy
// (obviously). However, here, in order to produce the list of bytes, we // (obviously). However, here, in order to produce the list of bytes, we
// need to coerce whatever `Undefined()` returns. // need to coerce whatever `Undefined()` returns.
if ite.TagType == TypeUndefined { if ite.TagType == exifcommon.TypeUndefined {
valueContext := ie.GetValueContext(ite) value, err := exifundefined.Decode(ite.IfdPath, ite.TagId, valueContext, ie.byteOrder)
value, err := valueContext.Undefined()
if err != nil { if err != nil {
if err == ErrUnhandledUnknownTypedTag { if err == exifcommon.ErrUnhandledUnknownTypedTag {
valueBytes = []byte(UnparseableUnknownTagValuePlaceholder) return nil, true, nil
return valueBytes, true, nil
} }
log.Panic(err) log.Panic(err)
} else {
switch value.(type) {
case []byte:
return value.([]byte), false, nil
case TagUnknownType_UnknownValue:
b := []byte(value.(TagUnknownType_UnknownValue))
return b, false, nil
case string:
return []byte(value.(string)), false, nil
case UnknownTagValue:
valueBytes, err := value.(UnknownTagValue).ValueBytes()
log.PanicIf(err)
return valueBytes, false, nil
default:
// TODO(dustin): !! Finish translating the rest of the types (make reusable and replace into other similar implementations?)
log.Panicf("can not produce bytes for unknown-type tag (0x%04x) (1): [%s]", ite.TagId, reflect.TypeOf(value))
} }
}
} else {
originalType := NewTagType(ite.TagType, ie.byteOrder)
byteCount := uint32(originalType.Type().Size()) * ite.UnitCount
tt := NewTagType(TypeByte, ie.byteOrder) encodeable := value.(exifundefined.EncodeableValue)
if tt.valueIsEmbedded(byteCount) == true { valueBytes, _, err = exifundefined.Encode(encodeable, ie.byteOrder)
iteLogger.Debugf(nil, "Reading BYTE value (ITE; embedded).")
// In this case, the bytes normally used for the offset are actually
// data.
valueBytes, err = tt.ParseBytes(ite.RawValueOffset, byteCount)
log.PanicIf(err) log.PanicIf(err)
} else { } else {
iteLogger.Debugf(nil, "Reading BYTE value (ITE; at offset).") var err error
valueBytes, err = tt.ParseBytes(addressableData[ite.ValueOffset:], byteCount) valueBytes, err = valueContext.ReadRawEncoded()
log.PanicIf(err) log.PanicIf(err)
} }
}
return valueBytes, false, nil return valueBytes, false, nil
} }
// RawTagVisitorPtr is an optional callback that can get hit for every tag we parse // 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 // through. `addressableData` is the byte array startign after the EXIF header
// (where the offsets of all IFDs and values are calculated from). // (where the offsets of all IFDs and values are calculated from).
// //
// This was reimplemented as an interface to allow for simpler change management // This was reimplemented as an interface to allow for simpler change management
// in the future. // in the future.
type RawTagWalk interface { type RawTagWalk interface {
Visit(fqIfdPath string, ifdIndex int, tagId uint16, tagType TagType, valueContext *ValueContext) (err error) Visit(fqIfdPath string, ifdIndex int, tagId uint16, tagType exifcommon.TagTypePrimitive, valueContext *exifcommon.ValueContext) (err error)
} }
type RawTagWalkLegacyWrapper struct {
legacyVisitor RawTagVisitor
}
func (rtwlw RawTagWalkLegacyWrapper) Visit(fqIfdPath string, ifdIndex int, tagId uint16, tagType TagType, valueContext *ValueContext) (err error) {
return rtwlw.legacyVisitor(fqIfdPath, ifdIndex, tagId, tagType, *valueContext)
}
// RawTagVisitor 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).
//
// DEPRECATED(dustin): Use a RawTagWalk instead.
type RawTagVisitor func(fqIfdPath string, ifdIndex int, tagId uint16, tagType TagType, valueContext ValueContext) (err error)
// ParseIfd decodes the IFD block that we're currently sitting on the first // ParseIfd decodes the IFD block that we're currently sitting on the first
// byte of. // byte of.
func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, ite *IfdTagEnumerator, visitor interface{}, doDescend bool, resolveValues bool) (nextIfdOffset uint32, entries []*IfdTagEntry, thumbnailData []byte, err error) { func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, ite *IfdTagEnumerator, visitor RawTagWalk, doDescend bool, resolveValues bool) (nextIfdOffset uint32, entries []*IfdTagEntry, thumbnailData []byte, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
} }
}() }()
var visitorWrapper RawTagWalk
if visitor != nil {
var ok bool
visitorWrapper, ok = visitor.(RawTagWalk)
if ok == false {
// Legacy usage.
// `ok` can be `true` but `legacyVisitor` can still be `nil` (when
// passed as nil).
if legacyVisitor, ok := visitor.(RawTagVisitor); ok == true && legacyVisitor != nil {
visitorWrapper = RawTagWalkLegacyWrapper{
legacyVisitor: legacyVisitor,
}
}
}
}
tagCount, _, err := ite.getUint16() tagCount, _, err := ite.getUint16()
log.PanicIf(err) log.PanicIf(err)
@ -373,12 +311,10 @@ func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, ite *IfdTagEnum
continue continue
} }
if visitorWrapper != nil { if visitor != nil {
tt := NewTagType(tag.TagType, ie.byteOrder)
valueContext := ie.GetValueContext(tag) valueContext := ie.GetValueContext(tag)
err := visitorWrapper.Visit(fqIfdPath, ifdIndex, tag.TagId, tt, valueContext) err := visitor.Visit(fqIfdPath, ifdIndex, tag.TagId, tag.TagType, valueContext)
log.PanicIf(err) log.PanicIf(err)
} }
@ -430,7 +366,7 @@ func (ie *IfdEnumerate) parseThumbnail(offsetIte, lengthIte *IfdTagEntry) (thumb
length := vList[0] length := vList[0]
// The tag is official a LONG type, but it's actually an offset to a blob of bytes. // The tag is official a LONG type, but it's actually an offset to a blob of bytes.
offsetIte.TagType = TypeByte offsetIte.TagType = exifcommon.TypeByte
offsetIte.UnitCount = length offsetIte.UnitCount = length
thumbnailData, err = offsetIte.ValueBytes(addressableData, ie.byteOrder) thumbnailData, err = offsetIte.ValueBytes(addressableData, ie.byteOrder)
@ -440,7 +376,7 @@ func (ie *IfdEnumerate) parseThumbnail(offsetIte, lengthIte *IfdTagEntry) (thumb
} }
// Scan enumerates the different EXIF's IFD blocks. // Scan enumerates the different EXIF's IFD blocks.
func (ie *IfdEnumerate) scan(fqIfdName string, ifdOffset uint32, visitor interface{}, resolveValues bool) (err error) { func (ie *IfdEnumerate) scan(fqIfdName string, ifdOffset uint32, visitor RawTagWalk, resolveValues bool) (err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
@ -466,7 +402,7 @@ func (ie *IfdEnumerate) scan(fqIfdName string, ifdOffset uint32, visitor interfa
// Scan enumerates the different EXIF blocks (called IFDs). `rootIfdName` will // Scan enumerates the different EXIF blocks (called IFDs). `rootIfdName` will
// be "IFD" in the TIFF standard. // be "IFD" in the TIFF standard.
func (ie *IfdEnumerate) Scan(rootIfdName string, ifdOffset uint32, visitor RawTagVisitor, resolveValue bool) (err error) { func (ie *IfdEnumerate) Scan(rootIfdName string, ifdOffset uint32, visitor RawTagWalk, resolveValue bool) (err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
@ -717,8 +653,8 @@ func (ifd *Ifd) printTagTree(populateValues bool, index, level int, nextLink boo
value, err = ifd.TagValue(tag) value, err = ifd.TagValue(tag)
if err != nil { if err != nil {
if err == ErrUnhandledUnknownTypedTag { if err == exifcommon.ErrUnhandledUnknownTypedTag {
value = UnparseableUnknownTagValuePlaceholder value = exifundefined.UnparseableUnknownTagValuePlaceholder
} else { } else {
log.Panic(err) log.Panic(err)
} }
@ -863,8 +799,8 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
gi = new(GpsInfo) gi = new(GpsInfo)
if ifd.IfdPath != IfdPathStandardGps { if ifd.IfdPath != exifcommon.IfdPathStandardGps {
log.Panicf("GPS can only be read on GPS IFD: [%s] != [%s]", ifd.IfdPath, IfdPathStandardGps) 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[TagVersionId]; found == false {
@ -926,7 +862,7 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
// Parse location. // Parse location.
latitudeRaw := latitudeValue.([]Rational) latitudeRaw := latitudeValue.([]exifcommon.Rational)
gi.Latitude = GpsDegrees{ gi.Latitude = GpsDegrees{
Orientation: latitudeRefValue.(string)[0], Orientation: latitudeRefValue.(string)[0],
@ -935,7 +871,7 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
Seconds: float64(latitudeRaw[2].Numerator) / float64(latitudeRaw[2].Denominator), Seconds: float64(latitudeRaw[2].Numerator) / float64(latitudeRaw[2].Denominator),
} }
longitudeRaw := longitudeValue.([]Rational) longitudeRaw := longitudeValue.([]exifcommon.Rational)
gi.Longitude = GpsDegrees{ gi.Longitude = GpsDegrees{
Orientation: longitudeRefValue.(string)[0], Orientation: longitudeRefValue.(string)[0],
@ -956,7 +892,7 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
altitudeRefValue, err := ifd.TagValue(altitudeRefTags[0]) altitudeRefValue, err := ifd.TagValue(altitudeRefTags[0])
log.PanicIf(err) log.PanicIf(err)
altitudeRaw := altitudeValue.([]Rational) altitudeRaw := altitudeValue.([]exifcommon.Rational)
altitude := int(altitudeRaw[0].Numerator / altitudeRaw[0].Denominator) altitude := int(altitudeRaw[0].Numerator / altitudeRaw[0].Denominator)
if altitudeRefValue.([]byte)[0] == 1 { if altitudeRefValue.([]byte)[0] == 1 {
altitude *= -1 altitude *= -1
@ -984,7 +920,7 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
timestampValue, err := ifd.TagValue(timestampTags[0]) timestampValue, err := ifd.TagValue(timestampTags[0])
log.PanicIf(err) log.PanicIf(err)
timestampRaw := timestampValue.([]Rational) timestampRaw := timestampValue.([]exifcommon.Rational)
hour := int(timestampRaw[0].Numerator / timestampRaw[0].Denominator) hour := int(timestampRaw[0].Numerator / timestampRaw[0].Denominator)
minute := int(timestampRaw[1].Numerator / timestampRaw[1].Denominator) minute := int(timestampRaw[1].Numerator / timestampRaw[1].Denominator)
@ -1023,7 +959,7 @@ func (ifd *Ifd) EnumerateTagsRecursively(visitor ParsedTagVisitor) (err error) {
return nil return nil
} }
func (ifd *Ifd) GetValueContext(ite *IfdTagEntry) *ValueContext { func (ifd *Ifd) GetValueContext(ite *IfdTagEntry) *exifcommon.ValueContext {
return newValueContextFromTag( return newValueContextFromTag(
ite, ite,
ifd.addressableData, ifd.addressableData,
@ -1068,9 +1004,9 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32, resolveValues bool) (index
queue := []QueuedIfd{ queue := []QueuedIfd{
{ {
Name: IfdStandard, Name: exifcommon.IfdStandard,
IfdPath: IfdStandard, IfdPath: exifcommon.IfdStandard,
FqIfdPath: IfdStandard, FqIfdPath: exifcommon.IfdStandard,
TagId: 0xffff, TagId: 0xffff,
@ -1258,7 +1194,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 // ParseOneIfd is a hack to use an IE to parse a raw IFD block. Can be used for
// testing. // testing.
func ParseOneIfd(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath, ifdPath string, byteOrder binary.ByteOrder, ifdBlock []byte, visitor RawTagVisitor, resolveValues bool) (nextIfdOffset uint32, entries []*IfdTagEntry, err error) { func ParseOneIfd(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath, ifdPath string, byteOrder binary.ByteOrder, ifdBlock []byte, visitor RawTagWalk, resolveValues bool) (nextIfdOffset uint32, entries []*IfdTagEntry, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
@ -1308,8 +1244,8 @@ func FindIfdFromRootIfd(rootIfd *Ifd, ifdPath string) (ifd *Ifd, err error) {
if len(lineage) == 0 { if len(lineage) == 0 {
log.Panicf("IFD path must be non-empty.") log.Panicf("IFD path must be non-empty.")
} else if lineage[0].Name != IfdStandard { } else if lineage[0].Name != exifcommon.IfdStandard {
log.Panicf("First IFD path item must be [%s].", IfdStandard) log.Panicf("First IFD path item must be [%s].", exifcommon.IfdStandard)
} }
desiredRootIndex := lineage[0].Index desiredRootIndex := lineage[0].Index

View File

@ -11,15 +11,17 @@ import (
"io/ioutil" "io/ioutil"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
) )
func TestIfdTagEntry_ValueBytes(t *testing.T) { func TestIfdTagEntry_ValueBytes(t *testing.T) {
byteOrder := binary.BigEndian byteOrder := binary.BigEndian
ve := NewValueEncoder(byteOrder) ve := exifcommon.NewValueEncoder(byteOrder)
original := []byte("original text") original := []byte("original text")
ed, err := ve.encodeBytes(original) ed, err := ve.Encode(original)
log.PanicIf(err) log.PanicIf(err)
// Now, pass the raw encoded value as if it was the entire addressable area // Now, pass the raw encoded value as if it was the entire addressable area
@ -27,7 +29,7 @@ func TestIfdTagEntry_ValueBytes(t *testing.T) {
// value happened to be recorded at the beginning. // value happened to be recorded at the beginning.
ite := IfdTagEntry{ ite := IfdTagEntry{
TagType: TypeByte, TagType: exifcommon.TypeByte,
UnitCount: uint32(len(original)), UnitCount: uint32(len(original)),
ValueOffset: 0, ValueOffset: 0,
} }
@ -264,7 +266,7 @@ func TestIfd_GpsInfo(t *testing.T) {
_, index, err := Collect(im, ti, rawExif) _, index, err := Collect(im, ti, rawExif)
log.PanicIf(err) log.PanicIf(err)
ifd, err := index.RootIfd.ChildWithIfdPath(IfdPathStandardGps) ifd, err := index.RootIfd.ChildWithIfdPath(exifcommon.IfdPathStandardGps)
log.PanicIf(err) log.PanicIf(err)
gi, err := ifd.GpsInfo() gi, err := ifd.GpsInfo()
@ -482,7 +484,7 @@ func ExampleIfd_GpsInfo() {
_, index, err := Collect(im, ti, rawExif) _, index, err := Collect(im, ti, rawExif)
log.PanicIf(err) log.PanicIf(err)
ifd, err := index.RootIfd.ChildWithIfdPath(IfdPathStandardGps) ifd, err := index.RootIfd.ChildWithIfdPath(exifcommon.IfdPathStandardGps)
log.PanicIf(err) log.PanicIf(err)
gi, err := ifd.GpsInfo() gi, err := ifd.GpsInfo()

View File

@ -2,11 +2,13 @@ package exif
import ( import (
"fmt" "fmt"
"reflect"
"encoding/binary" "encoding/binary"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
"github.com/dsoprea/go-exif/v2/undefined"
) )
var ( var (
@ -16,7 +18,7 @@ var (
type IfdTagEntry struct { type IfdTagEntry struct {
TagId uint16 TagId uint16
TagIndex int TagIndex int
TagType TagTypePrimitive TagType exifcommon.TagTypePrimitive
UnitCount uint32 UnitCount uint32
ValueOffset uint32 ValueOffset uint32
RawValueOffset []byte RawValueOffset []byte
@ -44,7 +46,7 @@ type IfdTagEntry struct {
} }
func (ite *IfdTagEntry) String() string { 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, TypeNames[ite.TagType], ite.UnitCount) 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. // TODO(dustin): TODO(dustin): Stop exporting IfdPath and TagId.
@ -60,7 +62,7 @@ func (ite *IfdTagEntry) String() string {
// } // }
// ValueString renders a string from whatever the value in this tag is. // ValueString renders a string from whatever the value in this tag is.
func (ite *IfdTagEntry) ValueString(addressableData []byte, byteOrder binary.ByteOrder) (value string, err error) { func (ite *IfdTagEntry) ValueString(addressableData []byte, byteOrder binary.ByteOrder) (phrase string, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
@ -73,17 +75,23 @@ func (ite *IfdTagEntry) ValueString(addressableData []byte, byteOrder binary.Byt
addressableData, addressableData,
byteOrder) byteOrder)
if ite.TagType == TypeUndefined { if ite.TagType == exifcommon.TypeUndefined {
valueRaw, err := valueContext.Undefined() var err error
value, err := exifundefined.Decode(ite.IfdPath, ite.TagId, valueContext, byteOrder)
log.PanicIf(err) log.PanicIf(err)
value = fmt.Sprintf("%v", valueRaw) s := value.(fmt.Stringer)
phrase = s.String()
} else { } else {
value, err = valueContext.Format() var err error
phrase, err = valueContext.Format()
log.PanicIf(err) log.PanicIf(err)
} }
return value, nil return phrase, nil
} }
// ValueBytes renders a specific list of bytes from the value in this tag. // ValueBytes renders a specific list of bytes from the value in this tag.
@ -94,60 +102,33 @@ func (ite *IfdTagEntry) ValueBytes(addressableData []byte, byteOrder binary.Byte
} }
}() }()
// 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 == TypeUndefined {
valueContext := valueContext :=
newValueContextFromTag( newValueContextFromTag(
ite, ite,
addressableData, addressableData,
byteOrder) byteOrder)
value, err := valueContext.Undefined() // 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 {
value, err := exifundefined.Decode(ite.IfdPath, ite.TagId, valueContext, byteOrder)
log.PanicIf(err) log.PanicIf(err)
switch value.(type) { ve := exifcommon.NewValueEncoder(byteOrder)
case []byte:
return value.([]byte), nil ed, err := ve.Encode(value)
case TagUnknownType_UnknownValue:
b := []byte(value.(TagUnknownType_UnknownValue))
return b, nil
case string:
return []byte(value.(string)), nil
case UnknownTagValue:
valueBytes, err := value.(UnknownTagValue).ValueBytes()
log.PanicIf(err) log.PanicIf(err)
return valueBytes, nil return ed.Encoded, nil
default:
// TODO(dustin): !! Finish translating the rest of the types (make reusable and replace into other similar implementations?)
log.Panicf("can not produce bytes for unknown-type tag (0x%04x) (2): [%s]", ite.TagId, reflect.TypeOf(value))
}
}
originalType := NewTagType(ite.TagType, byteOrder)
byteCount := uint32(originalType.Type().Size()) * ite.UnitCount
tt := NewTagType(TypeByte, byteOrder)
if tt.valueIsEmbedded(byteCount) == true {
iteLogger.Debugf(nil, "Reading BYTE value (ITE; embedded).")
// In this case, the bytes normally used for the offset are actually
// data.
value, err = tt.ParseBytes(ite.RawValueOffset, byteCount)
log.PanicIf(err)
} else { } else {
iteLogger.Debugf(nil, "Reading BYTE value (ITE; at offset).") rawBytes, err := valueContext.ReadRawEncoded()
value, err = tt.ParseBytes(addressableData[ite.ValueOffset:], byteCount)
log.PanicIf(err) log.PanicIf(err)
}
return value, nil return rawBytes, nil
}
} }
// Value returns the specific, parsed, typed value from the tag. // Value returns the specific, parsed, typed value from the tag.
@ -164,13 +145,15 @@ func (ite *IfdTagEntry) Value(addressableData []byte, byteOrder binary.ByteOrder
addressableData, addressableData,
byteOrder) byteOrder)
if ite.TagType == TypeUndefined { if ite.TagType == exifcommon.TypeUndefined {
value, err = valueContext.Undefined() var err error
value, err = exifundefined.Decode(ite.IfdPath, ite.TagId, valueContext, byteOrder)
log.PanicIf(err) log.PanicIf(err)
} else { } else {
tt := NewTagType(ite.TagType, byteOrder) var err error
value, err = tt.Resolve(valueContext) value, err = valueContext.Values()
log.PanicIf(err) log.PanicIf(err)
} }
@ -206,7 +189,7 @@ func (itevr *IfdTagEntryValueResolver) ValueBytes(ite *IfdTagEntry) (value []byt
itevr.addressableData, itevr.addressableData,
itevr.byteOrder) itevr.byteOrder)
rawBytes, err := valueContext.readRawEncoded() rawBytes, err := valueContext.ReadRawEncoded()
log.PanicIf(err) log.PanicIf(err)
return rawBytes, nil return rawBytes, nil

View File

@ -2,25 +2,28 @@ package exif
import ( import (
"bytes" "bytes"
"fmt"
"testing" "testing"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
) )
func TestIfdTagEntry_ValueString_Allocated(t *testing.T) { func TestIfdTagEntry_ValueString_Allocated(t *testing.T) {
ite := IfdTagEntry{ ite := IfdTagEntry{
TagId: 0x1, TagId: 0x1,
TagIndex: 0, TagIndex: 0,
TagType: TypeByte, TagType: exifcommon.TypeByte,
UnitCount: 6, UnitCount: 6,
ValueOffset: 0x0, ValueOffset: 0x0,
RawValueOffset: []byte{0x0, 0x0, 0x0, 0x0}, RawValueOffset: []byte{0x0, 0x0, 0x0, 0x0},
IfdPath: IfdPathStandard, IfdPath: exifcommon.IfdPathStandard,
} }
data := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66} data := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
value, err := ite.ValueString(data, TestDefaultByteOrder) value, err := ite.ValueString(data, exifcommon.TestDefaultByteOrder)
log.PanicIf(err) log.PanicIf(err)
expected := "11 22 33 44 55 66" expected := "11 22 33 44 55 66"
@ -35,14 +38,14 @@ func TestIfdTagEntry_ValueString_Embedded(t *testing.T) {
ite := IfdTagEntry{ ite := IfdTagEntry{
TagId: 0x1, TagId: 0x1,
TagIndex: 0, TagIndex: 0,
TagType: TypeByte, TagType: exifcommon.TypeByte,
UnitCount: 4, UnitCount: 4,
ValueOffset: 0, ValueOffset: 0,
RawValueOffset: data, RawValueOffset: data,
IfdPath: IfdPathStandard, IfdPath: exifcommon.IfdPathStandard,
} }
value, err := ite.ValueString(nil, TestDefaultByteOrder) value, err := ite.ValueString(nil, exifcommon.TestDefaultByteOrder)
log.PanicIf(err) log.PanicIf(err)
expected := "11 22 33 44" expected := "11 22 33 44"
@ -51,20 +54,29 @@ func TestIfdTagEntry_ValueString_Embedded(t *testing.T) {
} }
} }
func TestIfdTagEntry_ValueString_Unknown(t *testing.T) { func TestIfdTagEntry_ValueString_Undefined(t *testing.T) {
defer func() {
if state := recover(); state != nil {
err := log.Wrap(state.(error))
log.PrintError(err)
t.Fatalf("Test failure.")
}
}()
data := []uint8{'0', '2', '3', '0'} data := []uint8{'0', '2', '3', '0'}
ite := IfdTagEntry{ ite := IfdTagEntry{
TagId: 0x9000, TagId: 0x9000,
TagIndex: 0, TagIndex: 0,
TagType: TypeUndefined, TagType: exifcommon.TypeUndefined,
UnitCount: 4, UnitCount: 4,
ValueOffset: 0x0, ValueOffset: 0x0,
RawValueOffset: data, RawValueOffset: data,
IfdPath: IfdPathStandardExif, IfdPath: exifcommon.IfdPathStandardExif,
} }
value, err := ite.ValueString(nil, TestDefaultByteOrder) value, err := ite.ValueString(nil, exifcommon.TestDefaultByteOrder)
log.PanicIf(err) log.PanicIf(err)
expected := "0230" expected := "0230"
@ -77,16 +89,16 @@ func TestIfdTagEntry_ValueBytes_Allocated(t *testing.T) {
ite := IfdTagEntry{ ite := IfdTagEntry{
TagId: 0x1, TagId: 0x1,
TagIndex: 0, TagIndex: 0,
TagType: TypeByte, TagType: exifcommon.TypeByte,
UnitCount: 6, UnitCount: 6,
ValueOffset: 0x0, ValueOffset: 0x0,
RawValueOffset: []byte{0x0, 0x0, 0x0, 0x0}, RawValueOffset: []byte{0x0, 0x0, 0x0, 0x0},
IfdPath: IfdPathStandard, IfdPath: exifcommon.IfdPathStandard,
} }
data := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66} data := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
value, err := ite.ValueBytes(data, TestDefaultByteOrder) value, err := ite.ValueBytes(data, exifcommon.TestDefaultByteOrder)
log.PanicIf(err) log.PanicIf(err)
if bytes.Compare(value, data) != 0 { if bytes.Compare(value, data) != 0 {
@ -100,14 +112,14 @@ func TestIfdTagEntry_ValueBytes_Embedded(t *testing.T) {
ite := IfdTagEntry{ ite := IfdTagEntry{
TagId: 0x1, TagId: 0x1,
TagIndex: 0, TagIndex: 0,
TagType: TypeByte, TagType: exifcommon.TypeByte,
UnitCount: 4, UnitCount: 4,
ValueOffset: 0x0, ValueOffset: 0x0,
RawValueOffset: data, RawValueOffset: data,
IfdPath: IfdPathStandard, IfdPath: exifcommon.IfdPathStandard,
} }
value, err := ite.ValueBytes(nil, TestDefaultByteOrder) value, err := ite.ValueBytes(nil, exifcommon.TestDefaultByteOrder)
log.PanicIf(err) log.PanicIf(err)
if bytes.Compare(value, data) != 0 { if bytes.Compare(value, data) != 0 {
@ -121,14 +133,14 @@ func TestIfdTagEntry_Value_Normal(t *testing.T) {
ite := IfdTagEntry{ ite := IfdTagEntry{
TagId: 0x1, TagId: 0x1,
TagIndex: 0, TagIndex: 0,
TagType: TypeByte, TagType: exifcommon.TypeByte,
UnitCount: 4, UnitCount: 4,
ValueOffset: 0x0, ValueOffset: 0x0,
RawValueOffset: data, RawValueOffset: data,
IfdPath: IfdPathStandard, IfdPath: exifcommon.IfdPathStandard,
} }
value, err := ite.Value(nil, TestDefaultByteOrder) value, err := ite.Value(nil, exifcommon.TestDefaultByteOrder)
log.PanicIf(err) log.PanicIf(err)
if bytes.Compare(value.([]byte), data) != 0 { if bytes.Compare(value.([]byte), data) != 0 {
@ -136,29 +148,27 @@ func TestIfdTagEntry_Value_Normal(t *testing.T) {
} }
} }
func TestIfdTagEntry_Value_Unknown(t *testing.T) { func TestIfdTagEntry_Value_Undefined(t *testing.T) {
data := []uint8{'0', '2', '3', '0'} data := []uint8{'0', '2', '3', '0'}
ite := IfdTagEntry{ ite := IfdTagEntry{
TagId: 0x9000, TagId: 0x9000,
TagIndex: 0, TagIndex: 0,
TagType: TypeUndefined, TagType: exifcommon.TypeUndefined,
UnitCount: 4, UnitCount: 4,
ValueOffset: 0x0, ValueOffset: 0x0,
RawValueOffset: data, RawValueOffset: data,
IfdPath: IfdPathStandardExif, IfdPath: exifcommon.IfdPathStandardExif,
} }
value, err := ite.Value(nil, TestDefaultByteOrder) value, err := ite.Value(nil, exifcommon.TestDefaultByteOrder)
log.PanicIf(err) log.PanicIf(err)
gs := value.(TagUnknownType_GeneralString) s := value.(fmt.Stringer)
recovered := []byte(s.String())
vb, err := gs.ValueBytes() if bytes.Compare(recovered, data) != 0 {
log.PanicIf(err) t.Fatalf("Value not expected: [%s] != [%s]", recovered, data)
if bytes.Compare(vb, data) != 0 {
t.Fatalf("Value not expected: [%s] != [%s]", value, data)
} }
} }
@ -166,11 +176,11 @@ func TestIfdTagEntry_String(t *testing.T) {
ite := IfdTagEntry{ ite := IfdTagEntry{
TagId: 0x1, TagId: 0x1,
TagIndex: 0, TagIndex: 0,
TagType: TypeByte, TagType: exifcommon.TypeByte,
UnitCount: 6, UnitCount: 6,
ValueOffset: 0x0, ValueOffset: 0x0,
RawValueOffset: []byte{0x0, 0x0, 0x0, 0x0}, RawValueOffset: []byte{0x0, 0x0, 0x0, 0x0},
IfdPath: IfdPathStandard, IfdPath: exifcommon.IfdPathStandard,
} }
expected := "IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x0001) TAG-TYPE=[BYTE] UNIT-COUNT=(6)>" expected := "IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x0001) TAG-TYPE=[BYTE] UNIT-COUNT=(6)>"
@ -185,21 +195,21 @@ func TestIfdTagEntryValueResolver_ValueBytes(t *testing.T) {
ite := IfdTagEntry{ ite := IfdTagEntry{
TagId: 0x1, TagId: 0x1,
TagIndex: 0, TagIndex: 0,
TagType: TypeByte, TagType: exifcommon.TypeByte,
UnitCount: uint32(len(allocatedData)), UnitCount: uint32(len(allocatedData)),
ValueOffset: 0x8, ValueOffset: 0x8,
RawValueOffset: []byte{0x0, 0x0, 0x0, 0x0}, RawValueOffset: []byte{0x0, 0x0, 0x0, 0x0},
IfdPath: IfdPathStandard, IfdPath: exifcommon.IfdPathStandard,
} }
headerBytes, err := BuildExifHeader(TestDefaultByteOrder, uint32(0)) headerBytes, err := BuildExifHeader(exifcommon.TestDefaultByteOrder, uint32(0))
log.PanicIf(err) log.PanicIf(err)
exifData := make([]byte, len(headerBytes)+len(allocatedData)) exifData := make([]byte, len(headerBytes)+len(allocatedData))
copy(exifData[0:], headerBytes) copy(exifData[0:], headerBytes)
copy(exifData[len(headerBytes):], allocatedData) copy(exifData[len(headerBytes):], allocatedData)
itevr := NewIfdTagEntryValueResolver(exifData, TestDefaultByteOrder) itevr := NewIfdTagEntryValueResolver(exifData, exifcommon.TestDefaultByteOrder)
value, err := itevr.ValueBytes(&ite) value, err := itevr.ValueBytes(&ite)
log.PanicIf(err) log.PanicIf(err)

View File

@ -7,6 +7,8 @@ import (
"testing" "testing"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
) )
func TestIfdMapping_Add(t *testing.T) { func TestIfdMapping_Add(t *testing.T) {
@ -106,12 +108,12 @@ func TestIfdMapping_Get(t *testing.T) {
err := LoadStandardIfds(im) err := LoadStandardIfds(im)
log.PanicIf(err) log.PanicIf(err)
mi, err := im.Get([]uint16{IfdRootId, IfdExifId, IfdIopId}) mi, err := im.Get([]uint16{exifcommon.IfdRootId, exifcommon.IfdExifId, exifcommon.IfdIopId})
log.PanicIf(err) log.PanicIf(err)
if mi.ParentTagId != IfdExifId { if mi.ParentTagId != exifcommon.IfdExifId {
t.Fatalf("Parent tag-ID not correct") t.Fatalf("Parent tag-ID not correct")
} else if mi.TagId != IfdIopId { } else if mi.TagId != exifcommon.IfdIopId {
t.Fatalf("Tag-ID not correct") t.Fatalf("Tag-ID not correct")
} else if mi.Name != "Iop" { } else if mi.Name != "Iop" {
t.Fatalf("name not correct") t.Fatalf("name not correct")
@ -129,9 +131,9 @@ func TestIfdMapping_GetWithPath(t *testing.T) {
mi, err := im.GetWithPath("IFD/Exif/Iop") mi, err := im.GetWithPath("IFD/Exif/Iop")
log.PanicIf(err) log.PanicIf(err)
if mi.ParentTagId != IfdExifId { if mi.ParentTagId != exifcommon.IfdExifId {
t.Fatalf("Parent tag-ID not correct") t.Fatalf("Parent tag-ID not correct")
} else if mi.TagId != IfdIopId { } else if mi.TagId != exifcommon.IfdIopId {
t.Fatalf("Tag-ID not correct") t.Fatalf("Tag-ID not correct")
} else if mi.Name != "Iop" { } else if mi.Name != "Iop" {
t.Fatalf("name not correct") t.Fatalf("name not correct")

View File

@ -5,6 +5,8 @@ import (
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"github.com/dsoprea/go-exif/v2/common"
) )
const ( const (
@ -59,7 +61,7 @@ type IndexedTag struct {
Id uint16 Id uint16
Name string Name string
IfdPath string IfdPath string
Type TagTypePrimitive Type exifcommon.TagTypePrimitive
} }
func (it *IndexedTag) String() string { func (it *IndexedTag) String() string {
@ -203,7 +205,7 @@ func LoadStandardTags(ti *TagIndex) (err error) {
continue continue
} }
tagTypeId, found := TypeNamesR[tagTypeName] tagTypeId, found := exifcommon.GetTypeByName(tagTypeName)
if found == false { if found == false {
log.Panicf("type [%s] for [%s] not valid", tagTypeName, tagName) log.Panicf("type [%s] for [%s] not valid", tagTypeName, tagName)
continue continue

View File

@ -4,15 +4,17 @@ import (
"testing" "testing"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
) )
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
ti := NewTagIndex() ti := NewTagIndex()
it, err := ti.Get(IfdPathStandard, 0x10f) it, err := ti.Get(exifcommon.IfdPathStandard, 0x10f)
log.PanicIf(err) log.PanicIf(err)
if it.Is(IfdPathStandard, 0x10f) == false || it.IsName(IfdPathStandard, "Make") == false { if it.Is(exifcommon.IfdPathStandard, 0x10f) == false || it.IsName(exifcommon.IfdPathStandard, "Make") == false {
t.Fatalf("tag info not correct") t.Fatalf("tag info not correct")
} }
} }
@ -20,10 +22,10 @@ func TestGet(t *testing.T) {
func TestGetWithName(t *testing.T) { func TestGetWithName(t *testing.T) {
ti := NewTagIndex() ti := NewTagIndex()
it, err := ti.GetWithName(IfdPathStandard, "Make") it, err := ti.GetWithName(exifcommon.IfdPathStandard, "Make")
log.PanicIf(err) log.PanicIf(err)
if it.Is(IfdPathStandard, 0x10f) == false || it.Is(IfdPathStandard, 0x10f) == false { if it.Is(exifcommon.IfdPathStandard, 0x10f) == false {
t.Fatalf("tag info not correct") t.Fatalf("tag info not correct")
} }
} }

View File

@ -9,6 +9,8 @@ import (
"io/ioutil" "io/ioutil"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
) )
var ( var (
@ -32,7 +34,7 @@ func getExifSimpleTestIb() *IfdBuilder {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
err = ib.AddStandard(0x000b, "asciivalue") err = ib.AddStandard(0x000b, "asciivalue")
log.PanicIf(err) log.PanicIf(err)
@ -43,7 +45,7 @@ func getExifSimpleTestIb() *IfdBuilder {
err = ib.AddStandard(0x0100, []uint32{0x33445566}) err = ib.AddStandard(0x0100, []uint32{0x33445566})
log.PanicIf(err) log.PanicIf(err)
err = ib.AddStandard(0x013e, []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}) err = ib.AddStandard(0x013e, []exifcommon.Rational{{Numerator: 0x11112222, Denominator: 0x33334444}})
log.PanicIf(err) log.PanicIf(err)
return ib return ib
@ -63,7 +65,7 @@ func getExifSimpleTestIbBytes() []byte {
log.PanicIf(err) log.PanicIf(err)
ti := NewTagIndex() ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
err = ib.AddStandard(0x000b, "asciivalue") err = ib.AddStandard(0x000b, "asciivalue")
log.PanicIf(err) log.PanicIf(err)
@ -74,7 +76,7 @@ func getExifSimpleTestIbBytes() []byte {
err = ib.AddStandard(0x0100, []uint32{0x33445566}) err = ib.AddStandard(0x0100, []uint32{0x33445566})
log.PanicIf(err) log.PanicIf(err)
err = ib.AddStandard(0x013e, []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}) err = ib.AddStandard(0x013e, []exifcommon.Rational{{Numerator: 0x11112222, Denominator: 0x33334444}})
log.PanicIf(err) log.PanicIf(err)
ibe := NewIfdByteEncoder() ibe := NewIfdByteEncoder()
@ -103,7 +105,7 @@ func validateExifSimpleTestIb(exifData []byte, t *testing.T) {
eh, index, err := Collect(im, ti, exifData) eh, index, err := Collect(im, ti, exifData)
log.PanicIf(err) log.PanicIf(err)
if eh.ByteOrder != TestDefaultByteOrder { if eh.ByteOrder != exifcommon.TestDefaultByteOrder {
t.Fatalf("EXIF byte-order is not correct: %v", eh.ByteOrder) t.Fatalf("EXIF byte-order is not correct: %v", eh.ByteOrder)
} else if eh.FirstIfdOffset != ExifDefaultFirstIfdOffset { } else if eh.FirstIfdOffset != ExifDefaultFirstIfdOffset {
t.Fatalf("EXIF first IFD-offset not correct: (0x%02x)", eh.FirstIfdOffset) t.Fatalf("EXIF first IFD-offset not correct: (0x%02x)", eh.FirstIfdOffset)
@ -115,9 +117,9 @@ func validateExifSimpleTestIb(exifData []byte, t *testing.T) {
ifd := index.RootIfd ifd := index.RootIfd
if ifd.ByteOrder != TestDefaultByteOrder { if ifd.ByteOrder != exifcommon.TestDefaultByteOrder {
t.Fatalf("IFD byte-order not correct.") t.Fatalf("IFD byte-order not correct.")
} else if ifd.IfdPath != IfdStandard { } else if ifd.IfdPath != exifcommon.IfdStandard {
t.Fatalf("IFD name not correct.") t.Fatalf("IFD name not correct.")
} else if ifd.Index != 0 { } else if ifd.Index != 0 {
t.Fatalf("IFD index not zero: (%d)", ifd.Index) t.Fatalf("IFD index not zero: (%d)", ifd.Index)
@ -142,7 +144,7 @@ func validateExifSimpleTestIb(exifData []byte, t *testing.T) {
{tagId: 0x000b, value: "asciivalue"}, {tagId: 0x000b, value: "asciivalue"},
{tagId: 0x00ff, value: []uint16{0x1122}}, {tagId: 0x00ff, value: []uint16{0x1122}},
{tagId: 0x0100, value: []uint32{0x33445566}}, {tagId: 0x0100, value: []uint32{0x33445566}},
{tagId: 0x013e, value: []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}}, {tagId: 0x013e, value: []exifcommon.Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}},
} }
for i, e := range ifd.Entries { for i, e := range ifd.Entries {
@ -150,7 +152,7 @@ func validateExifSimpleTestIb(exifData []byte, t *testing.T) {
t.Fatalf("Tag-ID for entry (%d) not correct: (0x%02x) != (0x%02x)", i, e.TagId, expected[i].tagId) t.Fatalf("Tag-ID for entry (%d) not correct: (0x%02x) != (0x%02x)", i, e.TagId, expected[i].tagId)
} }
value, err := e.Value(addressableData, TestDefaultByteOrder) value, err := e.Value(addressableData, exifcommon.TestDefaultByteOrder)
log.PanicIf(err) log.PanicIf(err)
if reflect.DeepEqual(value, expected[i].value) != true { if reflect.DeepEqual(value, expected[i].value) != true {

View File

@ -1,8 +1,6 @@
package exifundefined package exifundefined
import ( import (
"reflect"
"encoding/binary" "encoding/binary"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
@ -10,14 +8,14 @@ import (
"github.com/dsoprea/go-exif/v2/common" "github.com/dsoprea/go-exif/v2/common"
) )
func Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) { func Encode(value EncodeableValue, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
} }
}() }()
encoderName := reflect.TypeOf(value).Name() encoderName := value.EncoderName()
encoder, found := encoders[encoderName] encoder, found := encoders[encoderName]
if found == false { if found == false {
@ -31,7 +29,7 @@ func Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unit
} }
// UndefinedValue knows how to resolve the value for most unknown-type tags. // UndefinedValue knows how to resolve the value for most unknown-type tags.
func Decode(ifdPath string, tagId uint16, valueContext *exifcommon.ValueContext, byteOrder binary.ByteOrder) (value interface{}, err error) { func Decode(ifdPath string, tagId uint16, valueContext *exifcommon.ValueContext, byteOrder binary.ByteOrder) (value EncodeableValue, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))

View File

@ -1,6 +1,8 @@
package exifundefined package exifundefined
import ( import (
"fmt"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common" "github.com/dsoprea/go-exif/v2/common"
@ -13,10 +15,18 @@ type Tag8828Oecf struct {
Values []exifcommon.SignedRational Values []exifcommon.SignedRational
} }
func (oecf Tag8828Oecf) String() string {
return fmt.Sprintf("Tag8828Oecf<COLUMNS=(%d) ROWS=(%d)>", oecf.Columns, oecf.Rows)
}
func (oecf Tag8828Oecf) EncoderName() string {
return "Codec8828Oecf"
}
type Codec8828Oecf struct { type Codec8828Oecf struct {
} }
func (Codec8828Oecf) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) { func (Codec8828Oecf) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))

View File

@ -1,15 +1,44 @@
package exifundefined package exifundefined
import ( import (
"encoding/binary"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common" "github.com/dsoprea/go-exif/v2/common"
) )
type Tag9000ExifVersion struct {
string
}
func (Tag9000ExifVersion) EncoderName() string {
return "Codec9000ExifVersion"
}
func (ev Tag9000ExifVersion) String() string {
return ev.string
}
type Codec9000ExifVersion struct { type Codec9000ExifVersion struct {
} }
func (Codec9000ExifVersion) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) { func (Codec9000ExifVersion) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
s, ok := value.(Tag9000ExifVersion)
if ok == false {
log.Panicf("can only encode a Tag9000ExifVersion")
}
return []byte(s.string), uint32(len(s.string)), nil
}
func (Codec9000ExifVersion) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
@ -21,10 +50,14 @@ func (Codec9000ExifVersion) Decode(valueContext *exifcommon.ValueContext) (value
valueString, err := valueContext.ReadAsciiNoNul() valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err) log.PanicIf(err)
return TagUndefinedGeneralString(valueString), nil return Tag9000ExifVersion{valueString}, nil
} }
func init() { func init() {
registerEncoder(
Tag9000ExifVersion{},
Codec9000ExifVersion{})
registerDecoder( registerDecoder(
exifcommon.IfdPathStandardExif, exifcommon.IfdPathStandardExif,
0x9000, 0x9000,

View File

@ -55,6 +55,10 @@ type TagExif9101ComponentsConfiguration struct {
ConfigurationBytes []byte ConfigurationBytes []byte
} }
func (TagExif9101ComponentsConfiguration) EncoderName() string {
return "CodecExif9101ComponentsConfiguration"
}
func (cc TagExif9101ComponentsConfiguration) String() string { func (cc TagExif9101ComponentsConfiguration) String() string {
return fmt.Sprintf("Exif9101ComponentsConfiguration<ID=[%s] BYTES=%v>", TagUndefinedType_9101_ComponentsConfiguration_Names[cc.ConfigurationId], cc.ConfigurationBytes) return fmt.Sprintf("Exif9101ComponentsConfiguration<ID=[%s] BYTES=%v>", TagUndefinedType_9101_ComponentsConfiguration_Names[cc.ConfigurationId], cc.ConfigurationBytes)
} }
@ -79,7 +83,7 @@ func (CodecExif9101ComponentsConfiguration) Encode(value interface{}, byteOrder
return cc.ConfigurationBytes, uint32(len(cc.ConfigurationBytes)), nil return cc.ConfigurationBytes, uint32(len(cc.ConfigurationBytes)), nil
} }
func (CodecExif9101ComponentsConfiguration) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) { func (CodecExif9101ComponentsConfiguration) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))

View File

@ -17,6 +17,10 @@ type Tag927CMakerNote struct {
MakerNoteBytes []byte MakerNoteBytes []byte
} }
func (Tag927CMakerNote) EncoderName() string {
return "Codec927CMakerNote"
}
func (mn Tag927CMakerNote) String() string { func (mn Tag927CMakerNote) String() string {
parts := make([]string, 20) parts := make([]string, 20)
for i, c := range mn.MakerNoteType { for i, c := range mn.MakerNoteType {
@ -53,7 +57,7 @@ func (Codec927CMakerNote) Encode(value interface{}, byteOrder binary.ByteOrder)
return mn.MakerNoteBytes, uint32(len(mn.MakerNoteBytes)), nil return mn.MakerNoteBytes, uint32(len(mn.MakerNoteBytes)), nil
} }
func (Codec927CMakerNote) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) { func (Codec927CMakerNote) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))

View File

@ -43,6 +43,10 @@ type Tag9286UserComment struct {
EncodingBytes []byte EncodingBytes []byte
} }
func (Tag9286UserComment) EncoderName() string {
return "Codec9286UserComment"
}
func (uc Tag9286UserComment) String() string { func (uc Tag9286UserComment) String() string {
var valuePhrase string var valuePhrase string
@ -85,7 +89,7 @@ func (Codec9286UserComment) Encode(value interface{}, byteOrder binary.ByteOrder
return encoded, uint32(len(encoded)), nil return encoded, uint32(len(encoded)), nil
} }
func (Codec9286UserComment) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) { func (Codec9286UserComment) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))

View File

@ -1,15 +1,44 @@
package exifundefined package exifundefined
import ( import (
"encoding/binary"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common" "github.com/dsoprea/go-exif/v2/common"
) )
type TagA000FlashpixVersion struct {
string
}
func (TagA000FlashpixVersion) EncoderName() string {
return "CodecA000FlashpixVersion"
}
func (fv TagA000FlashpixVersion) String() string {
return fv.string
}
type CodecA000FlashpixVersion struct { type CodecA000FlashpixVersion struct {
} }
func (CodecA000FlashpixVersion) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) { func (CodecA000FlashpixVersion) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
s, ok := value.(TagA000FlashpixVersion)
if ok == false {
log.Panicf("can only encode a TagA000FlashpixVersion")
}
return []byte(s.string), uint32(len(s.string)), nil
}
func (CodecA000FlashpixVersion) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
@ -21,10 +50,14 @@ func (CodecA000FlashpixVersion) Decode(valueContext *exifcommon.ValueContext) (v
valueString, err := valueContext.ReadAsciiNoNul() valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err) log.PanicIf(err)
return TagUndefinedGeneralString(valueString), nil return TagA000FlashpixVersion{valueString}, nil
} }
func init() { func init() {
registerEncoder(
TagA000FlashpixVersion{},
CodecA000FlashpixVersion{})
registerDecoder( registerDecoder(
exifcommon.IfdPathStandardExif, exifcommon.IfdPathStandardExif,
0xa000, 0xa000,

View File

@ -2,6 +2,7 @@ package exifundefined
import ( import (
"bytes" "bytes"
"fmt"
"encoding/binary" "encoding/binary"
@ -17,6 +18,14 @@ type TagA20CSpatialFrequencyResponse struct {
Values []exifcommon.Rational Values []exifcommon.Rational
} }
func (TagA20CSpatialFrequencyResponse) EncoderName() string {
return "CodecA20CSpatialFrequencyResponse"
}
func (sfr TagA20CSpatialFrequencyResponse) String() string {
return fmt.Sprintf("CodecA20CSpatialFrequencyResponse<COLUMNS=(%d) ROWS=(%d)>", sfr.Columns, sfr.Rows)
}
type CodecA20CSpatialFrequencyResponse struct { type CodecA20CSpatialFrequencyResponse struct {
} }
@ -69,7 +78,7 @@ func (CodecA20CSpatialFrequencyResponse) Encode(value interface{}, byteOrder bin
return encoded, uint32(len(encoded)), nil return encoded, uint32(len(encoded)), nil
} }
func (CodecA20CSpatialFrequencyResponse) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) { func (CodecA20CSpatialFrequencyResponse) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
@ -141,11 +150,11 @@ func (CodecA20CSpatialFrequencyResponse) Decode(valueContext *exifcommon.ValueCo
func init() { func init() {
registerEncoder( registerEncoder(
TagA302CfaPattern{}, TagA20CSpatialFrequencyResponse{},
CodecA302CfaPattern{}) CodecA20CSpatialFrequencyResponse{})
registerDecoder( registerDecoder(
exifcommon.IfdPathStandardExif, exifcommon.IfdPathStandardExif,
0xa302, 0xa20c,
CodecA302CfaPattern{}) CodecA20CSpatialFrequencyResponse{})
} }

View File

@ -1,6 +1,8 @@
package exifundefined package exifundefined
import ( import (
"fmt"
"encoding/binary" "encoding/binary"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
@ -10,6 +12,14 @@ import (
type TagExifA300FileSource uint32 type TagExifA300FileSource uint32
func (TagExifA300FileSource) EncoderName() string {
return "CodecExifA300FileSource"
}
func (af TagExifA300FileSource) String() string {
return fmt.Sprintf("%d", af)
}
const ( const (
TagUndefinedType_A300_SceneType_Others TagExifA300FileSource = 0 TagUndefinedType_A300_SceneType_Others TagExifA300FileSource = 0
TagUndefinedType_A300_SceneType_ScannerOfTransparentType TagExifA300FileSource = 1 TagUndefinedType_A300_SceneType_ScannerOfTransparentType TagExifA300FileSource = 1
@ -42,7 +52,7 @@ func (CodecExifA300FileSource) Encode(value interface{}, byteOrder binary.ByteOr
return ed.Encoded, uint32(int(ed.UnitCount)), nil return ed.Encoded, uint32(int(ed.UnitCount)), nil
} }
func (CodecExifA300FileSource) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) { func (CodecExifA300FileSource) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))

View File

@ -1,6 +1,8 @@
package exifundefined package exifundefined
import ( import (
"fmt"
"encoding/binary" "encoding/binary"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
@ -10,6 +12,14 @@ import (
type TagExifA301SceneType uint32 type TagExifA301SceneType uint32
func (TagExifA301SceneType) EncoderName() string {
return "CodecExifA301SceneType"
}
func (st TagExifA301SceneType) String() string {
return fmt.Sprintf("%d", st)
}
const ( const (
TagUndefinedType_A301_SceneType_DirectlyPhotographedImage TagExifA301SceneType = 1 TagUndefinedType_A301_SceneType_DirectlyPhotographedImage TagExifA301SceneType = 1
) )
@ -39,7 +49,7 @@ func (CodecExifA301SceneType) Encode(value interface{}, byteOrder binary.ByteOrd
return ed.Encoded, uint32(int(ed.UnitCount)), nil return ed.Encoded, uint32(int(ed.UnitCount)), nil
} }
func (CodecExifA301SceneType) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) { func (CodecExifA301SceneType) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))

View File

@ -2,6 +2,7 @@ package exifundefined
import ( import (
"bytes" "bytes"
"fmt"
"encoding/binary" "encoding/binary"
@ -16,6 +17,14 @@ type TagA302CfaPattern struct {
CfaValue []byte CfaValue []byte
} }
func (TagA302CfaPattern) EncoderName() string {
return "CodecA302CfaPattern"
}
func (cp TagA302CfaPattern) String() string {
return fmt.Sprintf("TagA302CfaPattern<HORZ-REPEAT=(%d) VERT-REPEAT=(%d)>", cp.HorizontalRepeat, cp.VerticalRepeat)
}
type CodecA302CfaPattern struct { type CodecA302CfaPattern struct {
} }
@ -51,7 +60,7 @@ func (CodecA302CfaPattern) Encode(value interface{}, byteOrder binary.ByteOrder)
return encoded, uint32(len(encoded)), nil return encoded, uint32(len(encoded)), nil
} }
func (CodecA302CfaPattern) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) { func (CodecA302CfaPattern) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))

View File

@ -1,15 +1,44 @@
package exifundefined package exifundefined
import ( import (
"encoding/binary"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common" "github.com/dsoprea/go-exif/v2/common"
) )
type Tag0002InteropVersion struct {
string
}
func (Tag0002InteropVersion) EncoderName() string {
return "Codec0002InteropVersion"
}
func (iv Tag0002InteropVersion) String() string {
return iv.string
}
type Codec0002InteropVersion struct { type Codec0002InteropVersion struct {
} }
func (Codec0002InteropVersion) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) { func (Codec0002InteropVersion) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
s, ok := value.(Tag0002InteropVersion)
if ok == false {
log.Panicf("can only encode a Tag0002InteropVersion")
}
return []byte(s.string), uint32(len(s.string)), nil
}
func (Codec0002InteropVersion) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
@ -21,10 +50,14 @@ func (Codec0002InteropVersion) Decode(valueContext *exifcommon.ValueContext) (va
valueString, err := valueContext.ReadAsciiNoNul() valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err) log.PanicIf(err)
return TagUndefinedGeneralString(valueString), nil return Tag0002InteropVersion{valueString}, nil
} }
func init() { func init() {
registerEncoder(
Tag0002InteropVersion{},
Codec0002InteropVersion{})
registerDecoder( registerDecoder(
exifcommon.IfdPathStandardExifIop, exifcommon.IfdPathStandardExifIop,
0x0002, 0x0002,

View File

@ -1,15 +1,44 @@
package exifundefined package exifundefined
import ( import (
"encoding/binary"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common" "github.com/dsoprea/go-exif/v2/common"
) )
type Tag001BGPSProcessingMethod struct {
string
}
func (Tag001BGPSProcessingMethod) EncoderName() string {
return "Codec001BGPSProcessingMethod"
}
func (gpm Tag001BGPSProcessingMethod) String() string {
return gpm.string
}
type Codec001BGPSProcessingMethod struct { type Codec001BGPSProcessingMethod struct {
} }
func (Codec001BGPSProcessingMethod) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) { func (Codec001BGPSProcessingMethod) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
s, ok := value.(Tag001BGPSProcessingMethod)
if ok == false {
log.Panicf("can only encode a Tag001BGPSProcessingMethod")
}
return []byte(s.string), uint32(len(s.string)), nil
}
func (Codec001BGPSProcessingMethod) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
@ -21,10 +50,14 @@ func (Codec001BGPSProcessingMethod) Decode(valueContext *exifcommon.ValueContext
valueString, err := valueContext.ReadAsciiNoNul() valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err) log.PanicIf(err)
return TagUndefinedGeneralString(valueString), nil return Tag001BGPSProcessingMethod{valueString}, nil
} }
func init() { func init() {
registerEncoder(
Tag001BGPSProcessingMethod{},
Codec001BGPSProcessingMethod{})
registerDecoder( registerDecoder(
exifcommon.IfdPathStandardGps, exifcommon.IfdPathStandardGps,
0x001b, 0x001b,

View File

@ -1,15 +1,44 @@
package exifundefined package exifundefined
import ( import (
"encoding/binary"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common" "github.com/dsoprea/go-exif/v2/common"
) )
type Tag001CGPSAreaInformation struct {
string
}
func (Tag001CGPSAreaInformation) EncoderName() string {
return "Codec001CGPSAreaInformation"
}
func (gai Tag001CGPSAreaInformation) String() string {
return gai.string
}
type Codec001CGPSAreaInformation struct { type Codec001CGPSAreaInformation struct {
} }
func (Codec001CGPSAreaInformation) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) { func (Codec001CGPSAreaInformation) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
s, ok := value.(Tag001CGPSAreaInformation)
if ok == false {
log.Panicf("can only encode a Tag001CGPSAreaInformation")
}
return []byte(s.string), uint32(len(s.string)), nil
}
func (Codec001CGPSAreaInformation) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
@ -21,10 +50,14 @@ func (Codec001CGPSAreaInformation) Decode(valueContext *exifcommon.ValueContext)
valueString, err := valueContext.ReadAsciiNoNul() valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err) log.PanicIf(err)
return TagUndefinedGeneralString(valueString), nil return Tag001CGPSAreaInformation{valueString}, nil
} }
func init() { func init() {
registerEncoder(
Tag001CGPSAreaInformation{},
Codec001CGPSAreaInformation{})
registerDecoder( registerDecoder(
exifcommon.IfdPathStandardGps, exifcommon.IfdPathStandardGps,
0x001c, 0x001c,

View File

@ -1,8 +1,6 @@
package exifundefined package exifundefined
import ( import (
"reflect"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
) )
@ -11,11 +9,11 @@ type UndefinedTagHandle struct {
TagId uint16 TagId uint16
} }
func registerEncoder(entity interface{}, encoder UndefinedValueEncoder) { func registerEncoder(entity EncodeableValue, encoder UndefinedValueEncoder) {
typeName := reflect.TypeOf(entity).Name() typeName := entity.EncoderName()
_, found := encoders[typeName] _, found := encoders[typeName]
if found != true { if found == true {
log.Panicf("encoder already registered: %v", typeName) log.Panicf("encoder already registered: %v", typeName)
} }
@ -29,7 +27,7 @@ func registerDecoder(ifdPath string, tagId uint16, decoder UndefinedValueDecoder
} }
_, found := decoders[uth] _, found := decoders[uth]
if found != true { if found == true {
log.Panicf("decoder already registered: %v", uth) log.Panicf("decoder already registered: %v", uth)
} }

View File

@ -22,24 +22,19 @@ type UndefinedValueEncoder interface {
Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error)
} }
type EncodeableValue interface {
EncoderName() string
}
// UndefinedValueEncoder knows how to decode an undefined-type tag's value from // UndefinedValueEncoder knows how to decode an undefined-type tag's value from
// bytes. // bytes.
type UndefinedValueDecoder interface { type UndefinedValueDecoder interface {
Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error)
} }
// TODO(dustin): Rename `UnknownTagValue` to `UndefinedTagValue`. type TagUndefinedType_UnknownValue []byte
// OBSOLETE(dustin): Use a `UndefinedValueEncoder` instead of an `UnknownTagValue`.
type UnknownTagValue interface { func (tutuv TagUndefinedType_UnknownValue) String() string {
ValueBytes() ([]byte, error)
}
// TODO(dustin): Rename `TagUnknownType_UnknownValue` to `TagUndefinedType_UnknownValue`.
type TagUnknownType_UnknownValue []byte
func (tutuv TagUnknownType_UnknownValue) String() string {
parts := make([]string, len(tutuv)) parts := make([]string, len(tutuv))
for i, c := range tutuv { for i, c := range tutuv {
parts[i] = fmt.Sprintf("%02x", c) parts[i] = fmt.Sprintf("%02x", c)
@ -54,5 +49,3 @@ func (tutuv TagUnknownType_UnknownValue) String() string {
return fmt.Sprintf("Unknown<DATA=[%s] LEN=(%d) SHA1=[%020x]>", strings.Join(parts, " "), len(tutuv), digest) return fmt.Sprintf("Unknown<DATA=[%s] LEN=(%d) SHA1=[%020x]>", strings.Join(parts, " "), len(tutuv), digest)
} }
type TagUndefinedGeneralString string

View File

@ -1,13 +1,15 @@
package exif package exif
import ( import (
"bytes"
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
"github.com/dsoprea/go-exif/v2/undefined"
) )
// ParseExifFullTimestamp parses dates like "2018:11:30 13:01:49" into a UTC // ParseExifFullTimestamp parses dates like "2018:11:30 13:01:49" into a UTC
@ -75,7 +77,7 @@ type ExifTag struct {
TagId uint16 `json:"id"` TagId uint16 `json:"id"`
TagName string `json:"name"` TagName string `json:"name"`
TagTypeId TagTypePrimitive `json:"type_id"` TagTypeId exifcommon.TagTypePrimitive `json:"type_id"`
TagTypeName string `json:"type_name"` TagTypeName string `json:"type_name"`
Value interface{} `json:"value"` Value interface{} `json:"value"`
ValueBytes []byte `json:"value_bytes"` ValueBytes []byte `json:"value_bytes"`
@ -126,15 +128,15 @@ func GetFlatExifData(exifData []byte) (exifTags []ExifTag, err error) {
value, err := ifd.TagValue(ite) value, err := ifd.TagValue(ite)
if err != nil { if err != nil {
if err == ErrUnhandledUnknownTypedTag { if err == exifcommon.ErrUnhandledUnknownTypedTag {
value = UnparseableUnknownTagValuePlaceholder value = exifundefined.UnparseableUnknownTagValuePlaceholder
} else { } else {
log.Panic(err) log.Panic(err)
} }
} }
valueBytes, err := ifd.TagValueBytes(ite) valueBytes, err := ifd.TagValueBytes(ite)
if err != nil && err != ErrUnhandledUnknownTypedTag { if err != nil && err != exifcommon.ErrUnhandledUnknownTypedTag {
log.Panic(err) log.Panic(err)
} }
@ -143,7 +145,7 @@ func GetFlatExifData(exifData []byte) (exifTags []ExifTag, err error) {
TagId: ite.TagId, TagId: ite.TagId,
TagName: tagName, TagName: tagName,
TagTypeId: ite.TagType, TagTypeId: ite.TagType,
TagTypeName: TypeNames[ite.TagType], TagTypeName: ite.TagType.String(),
Value: value, Value: value,
ValueBytes: valueBytes, ValueBytes: valueBytes,
ChildIfdPath: ite.ChildIfdPath, ChildIfdPath: ite.ChildIfdPath,

View File

@ -1,80 +1,13 @@
package exif package exif
import ( import (
"io/ioutil"
"fmt" "fmt"
"os"
"testing" "testing"
"time" "time"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
) )
func TestDumpBytes(t *testing.T) {
f, err := ioutil.TempFile(os.TempDir(), "utilitytest")
log.PanicIf(err)
defer os.Remove(f.Name())
originalStdout := os.Stdout
os.Stdout = f
DumpBytes([]byte{0x11, 0x22})
os.Stdout = originalStdout
_, err = f.Seek(0, 0)
log.PanicIf(err)
content, err := ioutil.ReadAll(f)
log.PanicIf(err)
if string(content) != "DUMP: 11 22 \n" {
t.Fatalf("content not correct: [%s]", string(content))
}
}
func TestDumpBytesClause(t *testing.T) {
f, err := ioutil.TempFile(os.TempDir(), "utilitytest")
log.PanicIf(err)
defer os.Remove(f.Name())
originalStdout := os.Stdout
os.Stdout = f
DumpBytesClause([]byte{0x11, 0x22})
os.Stdout = originalStdout
_, err = f.Seek(0, 0)
log.PanicIf(err)
content, err := ioutil.ReadAll(f)
log.PanicIf(err)
if string(content) != "DUMP: []byte { 0x11, 0x22 }\n" {
t.Fatalf("content not correct: [%s]", string(content))
}
}
func TestDumpBytesToString(t *testing.T) {
s := DumpBytesToString([]byte{0x12, 0x34, 0x56})
if s != "12 34 56" {
t.Fatalf("result not expected")
}
}
func TestDumpBytesClauseToString(t *testing.T) {
s := DumpBytesClauseToString([]byte{0x12, 0x34, 0x56})
if s != "0x12, 0x34, 0x56" {
t.Fatalf("result not expected")
}
}
func TestParseExifFullTimestamp(t *testing.T) { func TestParseExifFullTimestamp(t *testing.T) {
timestamp, err := ParseExifFullTimestamp("2018:11:30 13:01:49") timestamp, err := ParseExifFullTimestamp("2018:11:30 13:01:49")
log.PanicIf(err) log.PanicIf(err)

View File

@ -2,10 +2,12 @@ package exif
import ( import (
"encoding/binary" "encoding/binary"
"github.com/dsoprea/go-exif/v2/common"
) )
func newValueContextFromTag(ite *IfdTagEntry, addressableData []byte, byteOrder binary.ByteOrder) *ValueContext { func newValueContextFromTag(ite *IfdTagEntry, addressableData []byte, byteOrder binary.ByteOrder) *exifcommon.ValueContext {
return newValueContext( return exifcommon.NewValueContext(
ite.IfdPath, ite.IfdPath,
ite.TagId, ite.TagId,
ite.UnitCount, ite.UnitCount,