New integration of common/ and undefined/ subpackages

- common/type.go: Add FormatFromType() .
- Renamed common/type_encode.go to common/value_encoder.go .
for/master
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 (
"errors"
"fmt"
"reflect"
"strconv"
"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 (
// TODO(dustin): Rename TypeNames() to typeNames() and add getter.
TypeNames = map[TagTypePrimitive]string{
@ -108,7 +125,7 @@ var (
TypeAsciiNoNul: "_ASCII_NO_NUL",
}
TypeNamesR = map[string]TagTypePrimitive{}
typeNamesR = map[string]TagTypePrimitive{}
)
type Rational struct {
@ -123,14 +140,134 @@ type SignedRational struct {
// 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) (value string, err error) {
func FormatFromType(value interface{}, justFirst bool) (phrase string, err error) {
defer func() {
if state := recover(); state != nil {
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()
@ -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.
valueSuffix := ""
if justFirst == true && unitCount > 1 && tagType != TypeByte && tagType != TypeAscii && tagType != TypeAsciiNoNul {
unitCount = 1
valueSuffix = "..."
}
var value interface{}
if tagType == TypeByte {
items, err := parser.ParseBytes(rawBytes, unitCount)
switch tagType {
case TypeByte:
var err error
value, err = parser.ParseBytes(rawBytes, unitCount)
log.PanicIf(err)
case TypeAscii:
var err error
return DumpBytesToString(items), nil
} else if tagType == TypeAscii {
phrase, err := parser.ParseAscii(rawBytes, unitCount)
value, err = parser.ParseAscii(rawBytes, unitCount)
log.PanicIf(err)
case TypeAsciiNoNul:
var err error
return phrase, nil
} else if tagType == TypeAsciiNoNul {
phrase, err := parser.ParseAsciiNoNul(rawBytes, unitCount)
value, err = parser.ParseAsciiNoNul(rawBytes, unitCount)
log.PanicIf(err)
case TypeShort:
var err error
return phrase, nil
} else if tagType == TypeShort {
items, err := parser.ParseShorts(rawBytes, unitCount, byteOrder)
value, err = parser.ParseShorts(rawBytes, unitCount, byteOrder)
log.PanicIf(err)
case TypeLong:
var err error
if len(items) > 0 {
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)
value, err = parser.ParseLongs(rawBytes, unitCount, byteOrder)
log.PanicIf(err)
case TypeRational:
var err error
if len(items) > 0 {
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)
value, err = parser.ParseRationals(rawBytes, unitCount, byteOrder)
log.PanicIf(err)
case TypeSignedLong:
var err error
if len(items) > 0 {
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)
value, err = parser.ParseSignedLongs(rawBytes, unitCount, byteOrder)
log.PanicIf(err)
case TypeSignedRational:
var err error
if len(items) > 0 {
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)
value, err = parser.ParseSignedRationals(rawBytes, unitCount, byteOrder)
log.PanicIf(err)
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 {
default:
// Affects only "unknown" values, in general.
log.Panicf("value of type [%s] can not be formatted into string", tagType.String())
// Never called.
return "", nil
}
phrase, err = FormatFromType(value, justFirst)
log.PanicIf(err)
return phrase, nil
}
// TranslateStringToType converts user-provided strings to properly-typed
@ -323,8 +412,15 @@ func TranslateStringToType(tagType TagTypePrimitive, valueString string) (value
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() {
for typeId, typeName := range TypeNames {
TypeNamesR[typeName] = typeId
typeNamesR[typeName] = typeId
}
}

View File

@ -7,6 +7,7 @@ import (
"github.com/dsoprea/go-logging"
)
// DumpBytes prints a list of hex-encoded bytes.
func DumpBytes(data []byte) {
fmt.Printf("DUMP: ")
for _, x := range data {
@ -16,6 +17,8 @@ func DumpBytes(data []byte) {
fmt.Printf("\n")
}
// DumpBytesClause prints a list like DumpBytes(), but encapsulated in
// "[]byte { ... }".
func DumpBytesClause(data []byte) {
fmt.Printf("DUMP: ")
@ -32,6 +35,7 @@ func DumpBytesClause(data []byte) {
fmt.Printf(" }\n")
}
// DumpBytesToString returns a stringified list of hex-encoded bytes.
func DumpBytesToString(data []byte) string {
b := new(bytes.Buffer)
@ -48,6 +52,7 @@ func DumpBytesToString(data []byte) string {
return b.String()
}
// DumpBytesClauseToString returns a comma-separated list of hex-encoded bytes.
func DumpBytesClauseToString(data []byte) string {
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`).
// 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{
unitCount: unitCount,
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.
//
// Where the type is not ASCII, `justFirst` indicates whether to just stringify

View File

@ -11,7 +11,7 @@ import (
func TestNewValueContext(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22}
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" {
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}
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)
}
@ -56,7 +56,7 @@ func TestValueContext_SetUndefinedValueType__ErrorWhenNotUndefined(t *testing.T)
func TestValueContext_SetUndefinedValueType__Ok(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22}
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)
@ -72,7 +72,7 @@ func TestValueContext_SetUndefinedValueType__Ok(t *testing.T) {
func TestValueContext_effectiveValueType(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22}
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)
@ -88,7 +88,7 @@ func TestValueContext_effectiveValueType(t *testing.T) {
func TestValueContext_UnitCount(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22}
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 {
t.Fatalf("UnitCount() not correct: (%d)", vc.UnitCount())
@ -98,7 +98,7 @@ func TestValueContext_UnitCount(t *testing.T) {
func TestValueContext_ValueOffset(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22}
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 {
t.Fatalf("ValueOffset() not correct: (%d)", vc.ValueOffset())
@ -108,7 +108,7 @@ func TestValueContext_ValueOffset(t *testing.T) {
func TestValueContext_RawValueOffset(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22}
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 {
t.Fatalf("RawValueOffset() not correct: %v", vc.RawValueOffset())
@ -118,7 +118,7 @@ func TestValueContext_RawValueOffset(t *testing.T) {
func TestValueContext_AddressableData(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22}
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 {
t.Fatalf("AddressableData() not correct: %v", vc.AddressableData())
@ -128,7 +128,7 @@ func TestValueContext_AddressableData(t *testing.T) {
func TestValueContext_ByteOrder(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22}
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 {
t.Fatalf("ByteOrder() not correct: %v", vc.ByteOrder())
@ -138,7 +138,7 @@ func TestValueContext_ByteOrder(t *testing.T) {
func TestValueContext_IfdPath(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22}
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" {
t.Fatalf("IfdPath() not correct: [%s]", vc.IfdPath())
@ -148,7 +148,7 @@ func TestValueContext_IfdPath(t *testing.T) {
func TestValueContext_TagId(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22}
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 {
t.Fatalf("TagId() not correct: (%d)", vc.TagId())
@ -159,7 +159,7 @@ func TestValueContext_isEmbedded__True(t *testing.T) {
unitCount := uint32(4)
rawValueOffset := []byte{0, 0, 0, 22}
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 {
t.Fatalf("isEmbedded() not correct: %v", vc.isEmbedded())
@ -170,7 +170,7 @@ func TestValueContext_isEmbedded__False(t *testing.T) {
unitCount := uint32(5)
rawValueOffset := []byte{0, 0, 0, 22}
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 {
t.Fatalf("isEmbedded() not correct: %v", vc.isEmbedded())
@ -186,7 +186,7 @@ func TestValueContext_readRawEncoded__IsEmbedded(t *testing.T) {
valueOffset := uint32(0)
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()
log.PanicIf(err)
@ -208,7 +208,7 @@ func TestValueContext_readRawEncoded__IsRelative(t *testing.T) {
addressableData := []byte{1, 2, 3, 4}
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()
log.PanicIf(err)
@ -228,7 +228,7 @@ func TestValueContext_Format__Byte(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -248,7 +248,7 @@ func TestValueContext_Format__Ascii(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -268,7 +268,7 @@ func TestValueContext_Format__AsciiNoNul(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -288,7 +288,7 @@ func TestValueContext_Format__Short(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -308,7 +308,7 @@ func TestValueContext_Format__Long(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -332,7 +332,7 @@ func TestValueContext_Format__Rational(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -352,7 +352,7 @@ func TestValueContext_Format__SignedLong(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -376,7 +376,7 @@ func TestValueContext_Format__SignedRational(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -409,7 +409,7 @@ func TestValueContext_Format__Undefined__NoEffectiveType(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -429,7 +429,7 @@ func TestValueContext_Format__Undefined__HasEffectiveType(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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)
@ -451,7 +451,7 @@ func TestValueContext_FormatFirst__Bytes(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -471,7 +471,7 @@ func TestValueContext_FormatFirst__String(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -491,7 +491,7 @@ func TestValueContext_FormatFirst__List(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -511,7 +511,7 @@ func TestValueContext_ReadBytes(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -531,7 +531,7 @@ func TestValueContext_ReadAscii(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -551,7 +551,7 @@ func TestValueContext_ReadAsciiNoNul(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -571,7 +571,7 @@ func TestValueContext_ReadShorts(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -591,7 +591,7 @@ func TestValueContext_ReadLongs(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -615,7 +615,7 @@ func TestValueContext_ReadRationals(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -640,7 +640,7 @@ func TestValueContext_ReadSignedLongs(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -664,7 +664,7 @@ func TestValueContext_ReadSignedRationals(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -689,7 +689,7 @@ func TestValueContext_Values__Byte(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -709,7 +709,7 @@ func TestValueContext_Values__Ascii(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -729,7 +729,7 @@ func TestValueContext_Values__AsciiNoNul(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -749,7 +749,7 @@ func TestValueContext_Values__Short(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -769,7 +769,7 @@ func TestValueContext_Values__Long(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -793,7 +793,7 @@ func TestValueContext_Values__Rational(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -818,7 +818,7 @@ func TestValueContext_Values__SignedLong(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
log.PanicIf(err)
@ -842,7 +842,7 @@ func TestValueContext_Values__SignedRational(t *testing.T) {
addressableData := []byte{0, 0, 0, 0}
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()
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) {
case []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.
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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))

View File

@ -11,13 +11,28 @@ import (
"io/ioutil"
"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) {
defer func() {
if state := recover(); state != nil {
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)
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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
@ -78,10 +93,10 @@ func TestVisit(t *testing.T) {
}
valueString := ""
if tagType.Type() == TypeUndefined {
value, err := valueContext.Undefined()
if tagType == exifcommon.TypeUndefined {
value, err := exifundefined.Decode(fqIfdPath, tagId, valueContext, valueContext.ByteOrder())
if err != nil {
if err == ErrUnhandledUnknownTypedTag {
if err == exifcommon.ErrUnhandledUnknownTypedTag {
valueString = "!UNDEFINED!"
} else {
log.Panic(err)
@ -90,17 +105,23 @@ func TestVisit(t *testing.T) {
valueString = fmt.Sprintf("%v", value)
} else {
var err error
valueString, err = valueContext.FormatFirst()
log.PanicIf(err)
}
description := fmt.Sprintf("IFD-PATH=[%s] ID=(0x%04x) NAME=[%s] COUNT=(%d) TYPE=[%s] VALUE=[%s]", ifdPath, tagId, it.Name, valueContext.UnitCount(), tagType.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)
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)
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=(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=(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=(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]",
@ -213,7 +234,9 @@ func TestCollect(t *testing.T) {
defer func() {
if state := recover(); state != nil {
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).")
}
if rootIfd.IfdPath != IfdPathStandard {
if rootIfd.IfdPath != exifcommon.IfdPathStandard {
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)
} 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)
} 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)
} 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)
}
if lookup[IfdPathStandard][0].IfdPath != IfdPathStandard {
if lookup[exifcommon.IfdPathStandard][0].IfdPath != exifcommon.IfdPathStandard {
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.")
}
if lookup[IfdPathStandardExif][0].IfdPath != IfdPathStandardExif {
if lookup[exifcommon.IfdPathStandardExif][0].IfdPath != exifcommon.IfdPathStandardExif {
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.")
}
if lookup[IfdPathStandardExifIop][0].IfdPath != IfdPathStandardExifIop {
if lookup[exifcommon.IfdPathStandardExifIop][0].IfdPath != exifcommon.IfdPathStandardExifIop {
t.Fatalf("Lookup for IOP IFD not correct.")
}
foundExif := 0
foundGps := 0
for _, ite := range lookup[IfdPathStandard][0].Entries {
if ite.ChildIfdPath == IfdPathStandardExif {
for _, ite := range lookup[exifcommon.IfdPathStandard][0].Entries {
if ite.ChildIfdPath == exifcommon.IfdPathStandardExif {
foundExif++
if ite.TagId != IfdExifId {
t.Fatalf("EXIF IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId, IfdExifId)
if ite.TagId != exifcommon.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++
if ite.TagId != IfdGpsId {
t.Fatalf("GPS IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId, IfdGpsId)
if ite.TagId != exifcommon.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
for _, ite := range lookup[IfdPathStandardExif][0].Entries {
if ite.ChildIfdPath == IfdPathStandardExifIop {
for _, ite := range lookup[exifcommon.IfdPathStandardExif][0].Entries {
if ite.ChildIfdPath == exifcommon.IfdPathStandardExifIop {
foundIop++
if ite.TagId != IfdIopId {
t.Fatalf("IOP IFD tag-ID mismatch: (0x%04x) != (0x%04x)", ite.TagId, IfdIopId)
if ite.TagId != exifcommon.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) {
headerBytes, err := BuildExifHeader(TestDefaultByteOrder, 0x11223344)
headerBytes, err := BuildExifHeader(exifcommon.TestDefaultByteOrder, 0x11223344)
log.PanicIf(err)
eh, err := ParseExifHeader(headerBytes)
log.PanicIf(err)
if eh.ByteOrder != TestDefaultByteOrder {
if eh.ByteOrder != exifcommon.TestDefaultByteOrder {
t.Fatalf("Byte-order of EXIF header not correct.")
} else if eh.FirstIfdOffset != 0x11223344 {
t.Fatalf("First IFD offset not correct.")
@ -357,7 +380,7 @@ func TestExif_BuildAndParseExifHeader(t *testing.T) {
}
func ExampleBuildExifHeader() {
headerBytes, err := BuildExifHeader(TestDefaultByteOrder, 0x11223344)
headerBytes, err := BuildExifHeader(exifcommon.TestDefaultByteOrder, 0x11223344)
log.PanicIf(err)
eh, err := ParseExifHeader(headerBytes)

View File

@ -6,6 +6,8 @@ import (
"strings"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
)
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)
err = im.Add([]uint16{IfdRootId}, IfdExifId, IfdExif)
err = im.Add([]uint16{exifcommon.IfdRootId}, exifcommon.IfdExifId, exifcommon.IfdExif)
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)
err = im.Add([]uint16{IfdRootId}, IfdGpsId, IfdGps)
err = im.Add([]uint16{exifcommon.IfdRootId}, exifcommon.IfdGpsId, exifcommon.IfdGps)
log.PanicIf(err)
return nil

View File

@ -13,6 +13,9 @@ import (
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
"github.com/dsoprea/go-exif/v2/undefined"
)
var (
@ -94,7 +97,7 @@ type BuilderTag struct {
ifdPath string
tagId uint16
typeId TagTypePrimitive
typeId exifcommon.TagTypePrimitive
// value is either a value that can be encoded, an IfdBuilder instance (for
// child IFDs), or an IfdTagEntry instance representing an existing,
@ -106,7 +109,7 @@ type BuilderTag struct {
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{
ifdPath: ifdPath,
tagId: tagId,
@ -120,7 +123,7 @@ func NewChildIfdBuilderTag(ifdPath string, tagId uint16, value *IfdBuilderTagVal
return &BuilderTag{
ifdPath: ifdPath,
tagId: tagId,
typeId: TypeLong,
typeId: exifcommon.TypeLong,
value: value,
}
}
@ -135,13 +138,13 @@ func (bt *BuilderTag) String() string {
if bt.value.IsBytes() == true {
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)
} else {
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) {
@ -153,19 +156,24 @@ func (bt *BuilderTag) SetValue(byteOrder binary.ByteOrder, value interface{}) (e
// TODO(dustin): !! Add test.
tt := NewTagType(bt.typeId, byteOrder)
ve := NewValueEncoder(byteOrder)
var ed exifcommon.EncodedData
if bt.typeId == exifcommon.TypeUndefined {
encodeable := value.(exifundefined.EncodeableValue)
var ed EncodedData
if bt.typeId == TypeUndefined {
var err error
ed, err = EncodeUndefined(bt.ifdPath, bt.tagId, value)
encoded, unitCount, err := exifundefined.Encode(encodeable, byteOrder)
log.PanicIf(err)
ed = exifcommon.EncodedData{
Type: exifcommon.TypeUndefined,
Encoded: encoded,
UnitCount: unitCount,
}
} else {
ve := exifcommon.NewValueEncoder(byteOrder)
var err error
ed, err = ve.EncodeWithType(tt, value)
ed, err = ve.Encode(value)
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
// up. `ii` is the type of IFD that owns this tag.
func NewStandardBuilderTag(ifdPath string, it *IndexedTag, byteOrder binary.ByteOrder, value interface{}) *BuilderTag {
typeId := it.Type
tt := NewTagType(typeId, byteOrder)
var rawBytes []byte
if it.Type == exifcommon.TypeUndefined {
encodeable := value.(exifundefined.EncodeableValue)
ve := NewValueEncoder(byteOrder)
var ed EncodedData
if it.Type == TypeUndefined {
var err error
ed, err = EncodeUndefined(ifdPath, it.Id, value)
rawBytes, _, err = exifundefined.Encode(encodeable, byteOrder)
log.PanicIf(err)
} else {
var err error
ve := exifcommon.NewValueEncoder(byteOrder)
ed, err = ve.EncodeWithType(tt, value)
ed, err := ve.Encode(value)
log.PanicIf(err)
rawBytes = ed.Encoded
}
tagValue := NewIfdBuilderTagValueFromBytes(ed.Encoded)
tagValue := NewIfdBuilderTagValueFromBytes(rawBytes)
return NewBuilderTag(
ifdPath,
it.Id,
typeId,
it.Type,
tagValue,
byteOrder)
}
@ -288,7 +295,7 @@ func NewIfdBuilderWithExistingIfd(ifd *Ifd) (ib *IfdBuilder) {
var ifdTagId uint16
// 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)
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)")
}
@ -540,7 +547,7 @@ func (ib *IfdBuilder) SetThumbnail(data []byte) (err error) {
NewBuilderTag(
ib.ifdPath,
ThumbnailOffsetTagId,
TypeLong,
exifcommon.TypeLong,
ibtvfb,
ib.byteOrder)
@ -1113,13 +1120,15 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResol
var rawBytes []byte
if ite.TagType == TypeUndefined {
// It's an undefined-type value. Try to process, or skip if
// we don't know how to.
if ite.TagType == exifcommon.TypeUndefined {
// It's an undefined-type value. Try to process (or skip if
// we don't know how to), and encode back to bytes. This is the
// cleanest way of using what we already have to both determine
// if we support this tag and producing the bytes for it.
undefinedInterface, err := valueContext.Undefined()
value, err := exifundefined.Decode(ite.IfdPath, ite.TagId, valueContext, ib.byteOrder)
if err != nil {
if err == ErrUnhandledUnknownTypedTag {
if err == exifcommon.ErrUnhandledUnknownTypedTag {
// It's an undefined-type tag that we don't handle. If
// we don't know how to handle it, we can't know how
// many bytes it is and we must skip it.
@ -1129,19 +1138,14 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResol
log.Panic(err)
}
undefined, ok := undefinedInterface.(UnknownTagValue)
if ok != true {
log.Panicf("unexpected value returned from undefined-value processor")
}
rawBytes, err = undefined.ValueBytes()
rawBytes, _, err = exifundefined.Encode(value, ib.byteOrder)
log.PanicIf(err)
} else {
// It's a value with a standard type.
var err error
rawBytes, err = valueContext.readRawEncoded()
rawBytes, err = valueContext.ReadRawEncoded()
log.PanicIf(err)
}

View File

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

View File

@ -7,11 +7,13 @@ import (
"testing"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
)
func Test_ByteWriter_writeAsBytes_uint8(t *testing.T) {
b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder)
bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
err := bw.writeAsBytes(uint8(0x12))
log.PanicIf(err)
@ -23,7 +25,7 @@ func Test_ByteWriter_writeAsBytes_uint8(t *testing.T) {
func Test_ByteWriter_writeAsBytes_uint16(t *testing.T) {
b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder)
bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
err := bw.writeAsBytes(uint16(0x1234))
log.PanicIf(err)
@ -35,7 +37,7 @@ func Test_ByteWriter_writeAsBytes_uint16(t *testing.T) {
func Test_ByteWriter_writeAsBytes_uint32(t *testing.T) {
b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder)
bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
err := bw.writeAsBytes(uint32(0x12345678))
log.PanicIf(err)
@ -47,7 +49,7 @@ func Test_ByteWriter_writeAsBytes_uint32(t *testing.T) {
func Test_ByteWriter_WriteUint16(t *testing.T) {
b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder)
bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
err := bw.WriteUint16(uint16(0x1234))
log.PanicIf(err)
@ -59,7 +61,7 @@ func Test_ByteWriter_WriteUint16(t *testing.T) {
func Test_ByteWriter_WriteUint32(t *testing.T) {
b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder)
bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
err := bw.WriteUint32(uint32(0x12345678))
log.PanicIf(err)
@ -71,7 +73,7 @@ func Test_ByteWriter_WriteUint32(t *testing.T) {
func Test_ByteWriter_WriteFourBytes(t *testing.T) {
b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder)
bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
err := bw.WriteFourBytes([]byte{0x11, 0x22, 0x33, 0x44})
log.PanicIf(err)
@ -83,7 +85,7 @@ func Test_ByteWriter_WriteFourBytes(t *testing.T) {
func Test_ByteWriter_WriteFourBytes_TooMany(t *testing.T) {
b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder)
bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
err := bw.WriteFourBytes([]byte{0x11, 0x22, 0x33, 0x44, 0x55})
if err == nil {
@ -194,15 +196,15 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_embedded1(t *testing.T) {
log.PanicIf(err)
ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandardGps, TestDefaultByteOrder)
ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandardGps, exifcommon.TestDefaultByteOrder)
it, err := ti.Get(ib.ifdPath, uint16(0x0000))
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)
bw := NewByteWriter(b, TestDefaultByteOrder)
bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
addressableOffset := uint32(0x1234)
ida := newIfdDataAllocator(addressableOffset)
@ -228,15 +230,15 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_embedded2(t *testing.T) {
log.PanicIf(err)
ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandardGps, TestDefaultByteOrder)
ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandardGps, exifcommon.TestDefaultByteOrder)
it, err := ti.Get(ib.ifdPath, uint16(0x0000))
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)
bw := NewByteWriter(b, TestDefaultByteOrder)
bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
addressableOffset := uint32(0x1234)
ida := newIfdDataAllocator(addressableOffset)
@ -262,10 +264,10 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_allocated(t *testing.T) {
log.PanicIf(err)
ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandardGps, TestDefaultByteOrder)
ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandardGps, exifcommon.TestDefaultByteOrder)
b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder)
bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
addressableOffset := uint32(0x1234)
ida := newIfdDataAllocator(addressableOffset)
@ -273,7 +275,7 @@ func Test_IfdByteEncoder_encodeTagToBytes_bytes_allocated(t *testing.T) {
it, err := ti.Get(ib.ifdPath, uint16(0x0000))
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))
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.
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))
log.PanicIf(err)
@ -321,17 +323,17 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withoutAllocate(t *testing.T
log.PanicIf(err)
ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder)
bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
addressableOffset := uint32(0x1234)
ida := newIfdDataAllocator(addressableOffset)
childIb := NewIfdBuilder(im, ti, IfdPathStandardExif, TestDefaultByteOrder)
childIb := NewIfdBuilder(im, ti, exifcommon.IfdPathStandardExif, exifcommon.TestDefaultByteOrder)
tagValue := NewIfdBuilderTagValueFromIfdBuilder(childIb)
bt := NewChildIfdBuilderTag(IfdPathStandard, IfdExifId, tagValue)
bt := NewChildIfdBuilderTag(exifcommon.IfdPathStandard, exifcommon.IfdExifId, tagValue)
nextIfdOffsetToWrite := uint32(0)
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)
ti := NewTagIndex()
childIb := NewIfdBuilder(im, ti, IfdPathStandardExif, TestDefaultByteOrder)
childIb := NewIfdBuilder(im, ti, exifcommon.IfdPathStandardExif, exifcommon.TestDefaultByteOrder)
childIbTestTag := &BuilderTag{
ifdPath: IfdPathStandardExif,
ifdPath: exifcommon.IfdPathStandardExif,
tagId: 0x8822,
typeId: TypeShort,
typeId: exifcommon.TypeShort,
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.
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
// 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()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder)
bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
// 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
@ -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))
}
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)
if iteV.TagId != IfdExifId {
if iteV.TagId != exifcommon.IfdExifId {
t.Fatalf("IFD first tag-ID not correct: (0x%02x)", iteV.TagId)
} else if iteV.TagIndex != 0 {
t.Fatalf("IFD first tag index not correct: (%d)", iteV.TagIndex)
} else if iteV.TagType != TypeLong {
} else if iteV.TagType != exifcommon.TypeLong {
t.Fatalf("IFD first tag type not correct: (%d)", iteV.TagType)
} else if iteV.UnitCount != 1 {
t.Fatalf("IFD first tag unit-count not correct: (%d)", iteV.UnitCount)
@ -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)
} else if bytes.Compare(iteV.RawValueOffset, []byte{0x0, 0x0, 0x07, 0xd0}) != 0 {
t.Fatalf("IFD's child-IFD offset (as raw bytes) is not correct: [%x]", iteV.RawValueOffset)
} else if iteV.ChildIfdPath != IfdPathStandardExif {
} else if iteV.ChildIfdPath != exifcommon.IfdPathStandardExif {
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)
}
// 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)
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)
} else if ite.TagIndex != 0 {
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)
} else if ite.UnitCount != 1 {
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)
} else if 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)
}
}
@ -495,16 +497,16 @@ func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) {
log.PanicIf(err)
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))
log.PanicIf(err)
valueString := "testvalue"
bt := NewStandardBuilderTag(IfdPathStandard, it, TestDefaultByteOrder, valueString)
bt := NewStandardBuilderTag(exifcommon.IfdPathStandard, it, exifcommon.TestDefaultByteOrder, valueString)
b := new(bytes.Buffer)
bw := NewByteWriter(b, TestDefaultByteOrder)
bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
// 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
@ -529,14 +531,14 @@ func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) {
t.Fatalf("Child IFD not have been allocated.")
}
ite, err := ParseOneTag(im, ti, fmt.Sprintf("%s%d", 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)
if ite.TagId != 0x000b {
t.Fatalf("Tag-ID not correct: (0x%02x)", ite.TagId)
} else if ite.TagIndex != 0 {
t.Fatalf("Tag index not correct: (%d)", ite.TagIndex)
} else if ite.TagType != TypeAscii {
} else if ite.TagType != exifcommon.TypeAscii {
t.Fatalf("Tag type not correct: (%d)", ite.TagType)
} else if ite.UnitCount != (uint32(len(valueString) + 1)) {
t.Fatalf("Tag unit-count not correct: (%d)", ite.UnitCount)
@ -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)
} else if 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)
}
@ -617,7 +619,7 @@ func Test_IfdByteEncoder_encodeIfdToBytes_simple(t *testing.T) {
}
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)
headerBytes, err := BuildExifHeader(TestDefaultByteOrder, ExifDefaultFirstIfdOffset)
headerBytes, err := BuildExifHeader(exifcommon.TestDefaultByteOrder, ExifDefaultFirstIfdOffset)
log.PanicIf(err)
_, err = b.Write(headerBytes)
@ -693,7 +695,7 @@ func Test_IfdByteEncoder_EncodeToExifPayload(t *testing.T) {
b := new(bytes.Buffer)
headerBytes, err := BuildExifHeader(TestDefaultByteOrder, ExifDefaultFirstIfdOffset)
headerBytes, err := BuildExifHeader(exifcommon.TestDefaultByteOrder, ExifDefaultFirstIfdOffset)
log.PanicIf(err)
_, err = b.Write(headerBytes)
@ -737,7 +739,7 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
log.PanicIf(err)
ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
err = ib.AddStandard(0x000b, "asciivalue")
log.PanicIf(err)
@ -747,7 +749,7 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
// 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})
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
// 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})
log.PanicIf(err)
@ -772,13 +774,13 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
err = ib.AddChildIb(childIb2)
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)
// Link to another IB (sibling relationship). The root/standard IFD may
// 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})
log.PanicIf(err)
@ -852,7 +854,7 @@ func ExampleIfdByteEncoder_EncodeToExif() {
log.PanicIf(err)
ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
err = ib.AddStandardWithName("ProcessingSoftware", "asciivalue")
log.PanicIf(err)
@ -866,10 +868,10 @@ func ExampleIfdByteEncoder_EncodeToExif() {
err = ib.AddStandardWithName("ImageWidth", []uint32{0x44556677})
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)
err = ib.AddStandardWithName("ShutterSpeedValue", []SignedRational{{Numerator: 0x11112222, Denominator: 0x33334444}})
err = ib.AddStandardWithName("ShutterSpeedValue", []exifcommon.SignedRational{{Numerator: 0x11112222, Denominator: 0x33334444}})
log.PanicIf(err)
// Encode it.
@ -889,7 +891,7 @@ func ExampleIfdByteEncoder_EncodeToExif() {
addressableData := exifData[ExifAddressableAreaStart:]
for i, e := range index.RootIfd.Entries {
value, err := e.Value(addressableData, TestDefaultByteOrder)
value, err := e.Value(addressableData, exifcommon.TestDefaultByteOrder)
log.PanicIf(err)
fmt.Printf("%d: %s [%v]\n", i, e, value)

View File

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

View File

@ -4,7 +4,6 @@ import (
"bytes"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"time"
@ -12,6 +11,9 @@ import (
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
"github.com/dsoprea/go-exif/v2/undefined"
)
var (
@ -159,7 +161,7 @@ func (ie *IfdEnumerate) parseTag(fqIfdPath string, tagPosition int, ite *IfdTagE
tagTypeRaw, _, err := ite.getUint16()
log.PanicIf(err)
tagType := TagTypePrimitive(tagTypeRaw)
tagType := exifcommon.TagTypePrimitive(tagTypeRaw)
unitCount, _, err := ite.getUint32()
log.PanicIf(err)
@ -167,7 +169,7 @@ func (ie *IfdEnumerate) parseTag(fqIfdPath string, tagPosition int, ite *IfdTagE
valueOffset, rawValueOffset, err := ite.getUint32()
log.PanicIf(err)
if _, found := TypeNames[tagType]; found == false {
if tagType.IsValid() == false {
log.Panic(ErrTagTypeNotValid)
}
@ -210,7 +212,7 @@ func (ie *IfdEnumerate) parseTag(fqIfdPath string, tagPosition int, ite *IfdTagE
return tag, nil
}
func (ie *IfdEnumerate) GetValueContext(ite *IfdTagEntry) *ValueContext {
func (ie *IfdEnumerate) GetValueContext(ite *IfdTagEntry) *exifcommon.ValueContext {
// 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
// (`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 := ie.GetValueContext(ite)
value, err := valueContext.Undefined()
if ite.TagType == exifcommon.TypeUndefined {
value, err := exifundefined.Decode(ite.IfdPath, ite.TagId, valueContext, ie.byteOrder)
if err != nil {
if err == ErrUnhandledUnknownTypedTag {
valueBytes = []byte(UnparseableUnknownTagValuePlaceholder)
return valueBytes, true, nil
if err == exifcommon.ErrUnhandledUnknownTypedTag {
return nil, true, nil
}
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))
}
}
encodeable := value.(exifundefined.EncodeableValue)
valueBytes, _, err = exifundefined.Encode(encodeable, ie.byteOrder)
log.PanicIf(err)
} else {
originalType := NewTagType(ite.TagType, ie.byteOrder)
byteCount := uint32(originalType.Type().Size()) * ite.UnitCount
var err error
tt := NewTagType(TypeByte, ie.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.
valueBytes, err = tt.ParseBytes(ite.RawValueOffset, byteCount)
log.PanicIf(err)
} else {
iteLogger.Debugf(nil, "Reading BYTE value (ITE; at offset).")
valueBytes, err = tt.ParseBytes(addressableData[ite.ValueOffset:], byteCount)
log.PanicIf(err)
}
valueBytes, err = valueContext.ReadRawEncoded()
log.PanicIf(err)
}
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
// (where the offsets of all IFDs and values are calculated from).
//
// This was reimplemented as an interface to allow for simpler change management
// in the future.
type RawTagWalk interface {
Visit(fqIfdPath string, ifdIndex int, tagId uint16, tagType 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
// 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() {
if state := recover(); state != nil {
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()
log.PanicIf(err)
@ -373,12 +311,10 @@ func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, ite *IfdTagEnum
continue
}
if visitorWrapper != nil {
tt := NewTagType(tag.TagType, ie.byteOrder)
if visitor != nil {
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)
}
@ -430,7 +366,7 @@ func (ie *IfdEnumerate) parseThumbnail(offsetIte, lengthIte *IfdTagEntry) (thumb
length := vList[0]
// The tag is official a LONG type, but it's actually an offset to a blob of bytes.
offsetIte.TagType = TypeByte
offsetIte.TagType = exifcommon.TypeByte
offsetIte.UnitCount = length
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.
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() {
if state := recover(); state != nil {
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
// 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() {
if state := recover(); state != nil {
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)
if err != nil {
if err == ErrUnhandledUnknownTypedTag {
value = UnparseableUnknownTagValuePlaceholder
if err == exifcommon.ErrUnhandledUnknownTypedTag {
value = exifundefined.UnparseableUnknownTagValuePlaceholder
} else {
log.Panic(err)
}
@ -863,8 +799,8 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
gi = new(GpsInfo)
if ifd.IfdPath != IfdPathStandardGps {
log.Panicf("GPS can only be read on GPS IFD: [%s] != [%s]", ifd.IfdPath, IfdPathStandardGps)
if ifd.IfdPath != exifcommon.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 {
@ -926,7 +862,7 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
// Parse location.
latitudeRaw := latitudeValue.([]Rational)
latitudeRaw := latitudeValue.([]exifcommon.Rational)
gi.Latitude = GpsDegrees{
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),
}
longitudeRaw := longitudeValue.([]Rational)
longitudeRaw := longitudeValue.([]exifcommon.Rational)
gi.Longitude = GpsDegrees{
Orientation: longitudeRefValue.(string)[0],
@ -956,7 +892,7 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
altitudeRefValue, err := ifd.TagValue(altitudeRefTags[0])
log.PanicIf(err)
altitudeRaw := altitudeValue.([]Rational)
altitudeRaw := altitudeValue.([]exifcommon.Rational)
altitude := int(altitudeRaw[0].Numerator / altitudeRaw[0].Denominator)
if altitudeRefValue.([]byte)[0] == 1 {
altitude *= -1
@ -984,7 +920,7 @@ func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error) {
timestampValue, err := ifd.TagValue(timestampTags[0])
log.PanicIf(err)
timestampRaw := timestampValue.([]Rational)
timestampRaw := timestampValue.([]exifcommon.Rational)
hour := int(timestampRaw[0].Numerator / timestampRaw[0].Denominator)
minute := int(timestampRaw[1].Numerator / timestampRaw[1].Denominator)
@ -1023,7 +959,7 @@ func (ifd *Ifd) EnumerateTagsRecursively(visitor ParsedTagVisitor) (err error) {
return nil
}
func (ifd *Ifd) GetValueContext(ite *IfdTagEntry) *ValueContext {
func (ifd *Ifd) GetValueContext(ite *IfdTagEntry) *exifcommon.ValueContext {
return newValueContextFromTag(
ite,
ifd.addressableData,
@ -1068,9 +1004,9 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32, resolveValues bool) (index
queue := []QueuedIfd{
{
Name: IfdStandard,
IfdPath: IfdStandard,
FqIfdPath: IfdStandard,
Name: exifcommon.IfdStandard,
IfdPath: exifcommon.IfdStandard,
FqIfdPath: exifcommon.IfdStandard,
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
// 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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
@ -1308,8 +1244,8 @@ func FindIfdFromRootIfd(rootIfd *Ifd, ifdPath string) (ifd *Ifd, err error) {
if len(lineage) == 0 {
log.Panicf("IFD path must be non-empty.")
} else if lineage[0].Name != IfdStandard {
log.Panicf("First IFD path item must be [%s].", IfdStandard)
} else if lineage[0].Name != exifcommon.IfdStandard {
log.Panicf("First IFD path item must be [%s].", exifcommon.IfdStandard)
}
desiredRootIndex := lineage[0].Index

View File

@ -11,15 +11,17 @@ import (
"io/ioutil"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
)
func TestIfdTagEntry_ValueBytes(t *testing.T) {
byteOrder := binary.BigEndian
ve := NewValueEncoder(byteOrder)
ve := exifcommon.NewValueEncoder(byteOrder)
original := []byte("original text")
ed, err := ve.encodeBytes(original)
ed, err := ve.Encode(original)
log.PanicIf(err)
// 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.
ite := IfdTagEntry{
TagType: TypeByte,
TagType: exifcommon.TypeByte,
UnitCount: uint32(len(original)),
ValueOffset: 0,
}
@ -264,7 +266,7 @@ func TestIfd_GpsInfo(t *testing.T) {
_, index, err := Collect(im, ti, rawExif)
log.PanicIf(err)
ifd, err := index.RootIfd.ChildWithIfdPath(IfdPathStandardGps)
ifd, err := index.RootIfd.ChildWithIfdPath(exifcommon.IfdPathStandardGps)
log.PanicIf(err)
gi, err := ifd.GpsInfo()
@ -482,7 +484,7 @@ func ExampleIfd_GpsInfo() {
_, index, err := Collect(im, ti, rawExif)
log.PanicIf(err)
ifd, err := index.RootIfd.ChildWithIfdPath(IfdPathStandardGps)
ifd, err := index.RootIfd.ChildWithIfdPath(exifcommon.IfdPathStandardGps)
log.PanicIf(err)
gi, err := ifd.GpsInfo()

View File

@ -2,11 +2,13 @@ package exif
import (
"fmt"
"reflect"
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
"github.com/dsoprea/go-exif/v2/undefined"
)
var (
@ -16,7 +18,7 @@ var (
type IfdTagEntry struct {
TagId uint16
TagIndex int
TagType TagTypePrimitive
TagType exifcommon.TagTypePrimitive
UnitCount uint32
ValueOffset uint32
RawValueOffset []byte
@ -44,7 +46,7 @@ type IfdTagEntry struct {
}
func (ite *IfdTagEntry) String() string {
return fmt.Sprintf("IfdTagEntry<TAG-IFD-PATH=[%s] TAG-ID=(0x%04x) TAG-TYPE=[%s] UNIT-COUNT=(%d)>", ite.IfdPath, ite.TagId, 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.
@ -60,7 +62,7 @@ func (ite *IfdTagEntry) String() string {
// }
// 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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
@ -73,17 +75,23 @@ func (ite *IfdTagEntry) ValueString(addressableData []byte, byteOrder binary.Byt
addressableData,
byteOrder)
if ite.TagType == TypeUndefined {
valueRaw, err := valueContext.Undefined()
if ite.TagType == exifcommon.TypeUndefined {
var err error
value, err := exifundefined.Decode(ite.IfdPath, ite.TagId, valueContext, byteOrder)
log.PanicIf(err)
value = fmt.Sprintf("%v", valueRaw)
s := value.(fmt.Stringer)
phrase = s.String()
} else {
value, err = valueContext.Format()
var err error
phrase, err = valueContext.Format()
log.PanicIf(err)
}
return value, nil
return phrase, nil
}
// 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
}
}()
valueContext :=
newValueContextFromTag(
ite,
addressableData,
byteOrder)
// 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 :=
newValueContextFromTag(
ite,
addressableData,
byteOrder)
value, err := valueContext.Undefined()
if ite.TagType == exifcommon.TypeUndefined {
value, err := exifundefined.Decode(ite.IfdPath, ite.TagId, valueContext, byteOrder)
log.PanicIf(err)
switch value.(type) {
case []byte:
return value.([]byte), nil
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)
ve := exifcommon.NewValueEncoder(byteOrder)
return valueBytes, 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)
ed, err := ve.Encode(value)
log.PanicIf(err)
return ed.Encoded, nil
} else {
iteLogger.Debugf(nil, "Reading BYTE value (ITE; at offset).")
value, err = tt.ParseBytes(addressableData[ite.ValueOffset:], byteCount)
rawBytes, err := valueContext.ReadRawEncoded()
log.PanicIf(err)
}
return value, nil
return rawBytes, nil
}
}
// Value returns the specific, parsed, typed value from the tag.
@ -164,13 +145,15 @@ func (ite *IfdTagEntry) Value(addressableData []byte, byteOrder binary.ByteOrder
addressableData,
byteOrder)
if ite.TagType == TypeUndefined {
value, err = valueContext.Undefined()
if ite.TagType == exifcommon.TypeUndefined {
var err error
value, err = exifundefined.Decode(ite.IfdPath, ite.TagId, valueContext, byteOrder)
log.PanicIf(err)
} else {
tt := NewTagType(ite.TagType, byteOrder)
var err error
value, err = tt.Resolve(valueContext)
value, err = valueContext.Values()
log.PanicIf(err)
}
@ -206,7 +189,7 @@ func (itevr *IfdTagEntryValueResolver) ValueBytes(ite *IfdTagEntry) (value []byt
itevr.addressableData,
itevr.byteOrder)
rawBytes, err := valueContext.readRawEncoded()
rawBytes, err := valueContext.ReadRawEncoded()
log.PanicIf(err)
return rawBytes, nil

View File

@ -2,25 +2,28 @@ package exif
import (
"bytes"
"fmt"
"testing"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
)
func TestIfdTagEntry_ValueString_Allocated(t *testing.T) {
ite := IfdTagEntry{
TagId: 0x1,
TagIndex: 0,
TagType: TypeByte,
TagType: exifcommon.TypeByte,
UnitCount: 6,
ValueOffset: 0x0,
RawValueOffset: []byte{0x0, 0x0, 0x0, 0x0},
IfdPath: IfdPathStandard,
IfdPath: exifcommon.IfdPathStandard,
}
data := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
value, err := ite.ValueString(data, TestDefaultByteOrder)
value, err := ite.ValueString(data, exifcommon.TestDefaultByteOrder)
log.PanicIf(err)
expected := "11 22 33 44 55 66"
@ -35,14 +38,14 @@ func TestIfdTagEntry_ValueString_Embedded(t *testing.T) {
ite := IfdTagEntry{
TagId: 0x1,
TagIndex: 0,
TagType: TypeByte,
TagType: exifcommon.TypeByte,
UnitCount: 4,
ValueOffset: 0,
RawValueOffset: data,
IfdPath: IfdPathStandard,
IfdPath: exifcommon.IfdPathStandard,
}
value, err := ite.ValueString(nil, TestDefaultByteOrder)
value, err := ite.ValueString(nil, exifcommon.TestDefaultByteOrder)
log.PanicIf(err)
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'}
ite := IfdTagEntry{
TagId: 0x9000,
TagIndex: 0,
TagType: TypeUndefined,
TagType: exifcommon.TypeUndefined,
UnitCount: 4,
ValueOffset: 0x0,
RawValueOffset: data,
IfdPath: IfdPathStandardExif,
IfdPath: exifcommon.IfdPathStandardExif,
}
value, err := ite.ValueString(nil, TestDefaultByteOrder)
value, err := ite.ValueString(nil, exifcommon.TestDefaultByteOrder)
log.PanicIf(err)
expected := "0230"
@ -77,16 +89,16 @@ func TestIfdTagEntry_ValueBytes_Allocated(t *testing.T) {
ite := IfdTagEntry{
TagId: 0x1,
TagIndex: 0,
TagType: TypeByte,
TagType: exifcommon.TypeByte,
UnitCount: 6,
ValueOffset: 0x0,
RawValueOffset: []byte{0x0, 0x0, 0x0, 0x0},
IfdPath: IfdPathStandard,
IfdPath: exifcommon.IfdPathStandard,
}
data := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
value, err := ite.ValueBytes(data, TestDefaultByteOrder)
value, err := ite.ValueBytes(data, exifcommon.TestDefaultByteOrder)
log.PanicIf(err)
if bytes.Compare(value, data) != 0 {
@ -100,14 +112,14 @@ func TestIfdTagEntry_ValueBytes_Embedded(t *testing.T) {
ite := IfdTagEntry{
TagId: 0x1,
TagIndex: 0,
TagType: TypeByte,
TagType: exifcommon.TypeByte,
UnitCount: 4,
ValueOffset: 0x0,
RawValueOffset: data,
IfdPath: IfdPathStandard,
IfdPath: exifcommon.IfdPathStandard,
}
value, err := ite.ValueBytes(nil, TestDefaultByteOrder)
value, err := ite.ValueBytes(nil, exifcommon.TestDefaultByteOrder)
log.PanicIf(err)
if bytes.Compare(value, data) != 0 {
@ -121,14 +133,14 @@ func TestIfdTagEntry_Value_Normal(t *testing.T) {
ite := IfdTagEntry{
TagId: 0x1,
TagIndex: 0,
TagType: TypeByte,
TagType: exifcommon.TypeByte,
UnitCount: 4,
ValueOffset: 0x0,
RawValueOffset: data,
IfdPath: IfdPathStandard,
IfdPath: exifcommon.IfdPathStandard,
}
value, err := ite.Value(nil, TestDefaultByteOrder)
value, err := ite.Value(nil, exifcommon.TestDefaultByteOrder)
log.PanicIf(err)
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'}
ite := IfdTagEntry{
TagId: 0x9000,
TagIndex: 0,
TagType: TypeUndefined,
TagType: exifcommon.TypeUndefined,
UnitCount: 4,
ValueOffset: 0x0,
RawValueOffset: data,
IfdPath: IfdPathStandardExif,
IfdPath: exifcommon.IfdPathStandardExif,
}
value, err := ite.Value(nil, TestDefaultByteOrder)
value, err := ite.Value(nil, exifcommon.TestDefaultByteOrder)
log.PanicIf(err)
gs := value.(TagUnknownType_GeneralString)
s := value.(fmt.Stringer)
recovered := []byte(s.String())
vb, err := gs.ValueBytes()
log.PanicIf(err)
if bytes.Compare(vb, data) != 0 {
t.Fatalf("Value not expected: [%s] != [%s]", value, data)
if bytes.Compare(recovered, data) != 0 {
t.Fatalf("Value not expected: [%s] != [%s]", recovered, data)
}
}
@ -166,11 +176,11 @@ func TestIfdTagEntry_String(t *testing.T) {
ite := IfdTagEntry{
TagId: 0x1,
TagIndex: 0,
TagType: TypeByte,
TagType: exifcommon.TypeByte,
UnitCount: 6,
ValueOffset: 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)>"
@ -185,21 +195,21 @@ func TestIfdTagEntryValueResolver_ValueBytes(t *testing.T) {
ite := IfdTagEntry{
TagId: 0x1,
TagIndex: 0,
TagType: TypeByte,
TagType: exifcommon.TypeByte,
UnitCount: uint32(len(allocatedData)),
ValueOffset: 0x8,
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)
exifData := make([]byte, len(headerBytes)+len(allocatedData))
copy(exifData[0:], headerBytes)
copy(exifData[len(headerBytes):], allocatedData)
itevr := NewIfdTagEntryValueResolver(exifData, TestDefaultByteOrder)
itevr := NewIfdTagEntryValueResolver(exifData, exifcommon.TestDefaultByteOrder)
value, err := itevr.ValueBytes(&ite)
log.PanicIf(err)

View File

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

View File

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

View File

@ -4,15 +4,17 @@ import (
"testing"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
)
func TestGet(t *testing.T) {
ti := NewTagIndex()
it, err := ti.Get(IfdPathStandard, 0x10f)
it, err := ti.Get(exifcommon.IfdPathStandard, 0x10f)
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")
}
}
@ -20,10 +22,10 @@ func TestGet(t *testing.T) {
func TestGetWithName(t *testing.T) {
ti := NewTagIndex()
it, err := ti.GetWithName(IfdPathStandard, "Make")
it, err := ti.GetWithName(exifcommon.IfdPathStandard, "Make")
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")
}
}

View File

@ -9,6 +9,8 @@ import (
"io/ioutil"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
)
var (
@ -32,7 +34,7 @@ func getExifSimpleTestIb() *IfdBuilder {
log.PanicIf(err)
ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
err = ib.AddStandard(0x000b, "asciivalue")
log.PanicIf(err)
@ -43,7 +45,7 @@ func getExifSimpleTestIb() *IfdBuilder {
err = ib.AddStandard(0x0100, []uint32{0x33445566})
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)
return ib
@ -63,7 +65,7 @@ func getExifSimpleTestIbBytes() []byte {
log.PanicIf(err)
ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)
ib := NewIfdBuilder(im, ti, exifcommon.IfdPathStandard, exifcommon.TestDefaultByteOrder)
err = ib.AddStandard(0x000b, "asciivalue")
log.PanicIf(err)
@ -74,7 +76,7 @@ func getExifSimpleTestIbBytes() []byte {
err = ib.AddStandard(0x0100, []uint32{0x33445566})
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)
ibe := NewIfdByteEncoder()
@ -103,7 +105,7 @@ func validateExifSimpleTestIb(exifData []byte, t *testing.T) {
eh, index, err := Collect(im, ti, exifData)
log.PanicIf(err)
if eh.ByteOrder != TestDefaultByteOrder {
if eh.ByteOrder != exifcommon.TestDefaultByteOrder {
t.Fatalf("EXIF byte-order is not correct: %v", eh.ByteOrder)
} else if eh.FirstIfdOffset != ExifDefaultFirstIfdOffset {
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
if ifd.ByteOrder != TestDefaultByteOrder {
if ifd.ByteOrder != exifcommon.TestDefaultByteOrder {
t.Fatalf("IFD byte-order not correct.")
} else if ifd.IfdPath != IfdStandard {
} else if ifd.IfdPath != exifcommon.IfdStandard {
t.Fatalf("IFD name not correct.")
} else if ifd.Index != 0 {
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: 0x00ff, value: []uint16{0x1122}},
{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 {
@ -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)
}
value, err := e.Value(addressableData, TestDefaultByteOrder)
value, err := e.Value(addressableData, exifcommon.TestDefaultByteOrder)
log.PanicIf(err)
if reflect.DeepEqual(value, expected[i].value) != true {

View File

@ -1,8 +1,6 @@
package exifundefined
import (
"reflect"
"encoding/binary"
"github.com/dsoprea/go-logging"
@ -10,14 +8,14 @@ import (
"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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
encoderName := reflect.TypeOf(value).Name()
encoderName := value.EncoderName()
encoder, found := encoders[encoderName]
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.
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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))

View File

@ -1,6 +1,8 @@
package exifundefined
import (
"fmt"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v2/common"
@ -13,10 +15,18 @@ type Tag8828Oecf struct {
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 {
}
func (Codec8828Oecf) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) {
func (Codec8828Oecf) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))

View File

@ -1,15 +1,44 @@
package exifundefined
import (
"encoding/binary"
"github.com/dsoprea/go-logging"
"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 {
}
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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
@ -21,10 +50,14 @@ func (Codec9000ExifVersion) Decode(valueContext *exifcommon.ValueContext) (value
valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err)
return TagUndefinedGeneralString(valueString), nil
return Tag9000ExifVersion{valueString}, nil
}
func init() {
registerEncoder(
Tag9000ExifVersion{},
Codec9000ExifVersion{})
registerDecoder(
exifcommon.IfdPathStandardExif,
0x9000,

View File

@ -55,6 +55,10 @@ type TagExif9101ComponentsConfiguration struct {
ConfigurationBytes []byte
}
func (TagExif9101ComponentsConfiguration) EncoderName() string {
return "CodecExif9101ComponentsConfiguration"
}
func (cc TagExif9101ComponentsConfiguration) String() string {
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
}
func (CodecExif9101ComponentsConfiguration) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) {
func (CodecExif9101ComponentsConfiguration) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))

View File

@ -17,6 +17,10 @@ type Tag927CMakerNote struct {
MakerNoteBytes []byte
}
func (Tag927CMakerNote) EncoderName() string {
return "Codec927CMakerNote"
}
func (mn Tag927CMakerNote) String() string {
parts := make([]string, 20)
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
}
func (Codec927CMakerNote) Decode(valueContext *exifcommon.ValueContext) (value interface{}, err error) {
func (Codec927CMakerNote) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))

View File

@ -43,6 +43,10 @@ type Tag9286UserComment struct {
EncodingBytes []byte
}
func (Tag9286UserComment) EncoderName() string {
return "Codec9286UserComment"
}
func (uc Tag9286UserComment) String() string {
var valuePhrase string
@ -85,7 +89,7 @@ func (Codec9286UserComment) Encode(value interface{}, byteOrder binary.ByteOrder
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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))

View File

@ -1,15 +1,44 @@
package exifundefined
import (
"encoding/binary"
"github.com/dsoprea/go-logging"
"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 {
}
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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
@ -21,10 +50,14 @@ func (CodecA000FlashpixVersion) Decode(valueContext *exifcommon.ValueContext) (v
valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err)
return TagUndefinedGeneralString(valueString), nil
return TagA000FlashpixVersion{valueString}, nil
}
func init() {
registerEncoder(
TagA000FlashpixVersion{},
CodecA000FlashpixVersion{})
registerDecoder(
exifcommon.IfdPathStandardExif,
0xa000,

View File

@ -2,6 +2,7 @@ package exifundefined
import (
"bytes"
"fmt"
"encoding/binary"
@ -17,6 +18,14 @@ type TagA20CSpatialFrequencyResponse struct {
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 {
}
@ -69,7 +78,7 @@ func (CodecA20CSpatialFrequencyResponse) Encode(value interface{}, byteOrder bin
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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
@ -141,11 +150,11 @@ func (CodecA20CSpatialFrequencyResponse) Decode(valueContext *exifcommon.ValueCo
func init() {
registerEncoder(
TagA302CfaPattern{},
CodecA302CfaPattern{})
TagA20CSpatialFrequencyResponse{},
CodecA20CSpatialFrequencyResponse{})
registerDecoder(
exifcommon.IfdPathStandardExif,
0xa302,
CodecA302CfaPattern{})
0xa20c,
CodecA20CSpatialFrequencyResponse{})
}

View File

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

View File

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

View File

@ -2,6 +2,7 @@ package exifundefined
import (
"bytes"
"fmt"
"encoding/binary"
@ -16,6 +17,14 @@ type TagA302CfaPattern struct {
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 {
}
@ -51,7 +60,7 @@ func (CodecA302CfaPattern) Encode(value interface{}, byteOrder binary.ByteOrder)
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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))

View File

@ -1,15 +1,44 @@
package exifundefined
import (
"encoding/binary"
"github.com/dsoprea/go-logging"
"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 {
}
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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
@ -21,10 +50,14 @@ func (Codec0002InteropVersion) Decode(valueContext *exifcommon.ValueContext) (va
valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err)
return TagUndefinedGeneralString(valueString), nil
return Tag0002InteropVersion{valueString}, nil
}
func init() {
registerEncoder(
Tag0002InteropVersion{},
Codec0002InteropVersion{})
registerDecoder(
exifcommon.IfdPathStandardExifIop,
0x0002,

View File

@ -1,15 +1,44 @@
package exifundefined
import (
"encoding/binary"
"github.com/dsoprea/go-logging"
"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 {
}
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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
@ -21,10 +50,14 @@ func (Codec001BGPSProcessingMethod) Decode(valueContext *exifcommon.ValueContext
valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err)
return TagUndefinedGeneralString(valueString), nil
return Tag001BGPSProcessingMethod{valueString}, nil
}
func init() {
registerEncoder(
Tag001BGPSProcessingMethod{},
Codec001BGPSProcessingMethod{})
registerDecoder(
exifcommon.IfdPathStandardGps,
0x001b,

View File

@ -1,15 +1,44 @@
package exifundefined
import (
"encoding/binary"
"github.com/dsoprea/go-logging"
"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 {
}
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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
@ -21,10 +50,14 @@ func (Codec001CGPSAreaInformation) Decode(valueContext *exifcommon.ValueContext)
valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err)
return TagUndefinedGeneralString(valueString), nil
return Tag001CGPSAreaInformation{valueString}, nil
}
func init() {
registerEncoder(
Tag001CGPSAreaInformation{},
Codec001CGPSAreaInformation{})
registerDecoder(
exifcommon.IfdPathStandardGps,
0x001c,

View File

@ -1,8 +1,6 @@
package exifundefined
import (
"reflect"
"github.com/dsoprea/go-logging"
)
@ -11,11 +9,11 @@ type UndefinedTagHandle struct {
TagId uint16
}
func registerEncoder(entity interface{}, encoder UndefinedValueEncoder) {
typeName := reflect.TypeOf(entity).Name()
func registerEncoder(entity EncodeableValue, encoder UndefinedValueEncoder) {
typeName := entity.EncoderName()
_, found := encoders[typeName]
if found != true {
if found == true {
log.Panicf("encoder already registered: %v", typeName)
}
@ -29,7 +27,7 @@ func registerDecoder(ifdPath string, tagId uint16, decoder UndefinedValueDecoder
}
_, found := decoders[uth]
if found != true {
if found == true {
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)
}
type EncodeableValue interface {
EncoderName() string
}
// UndefinedValueEncoder knows how to decode an undefined-type tag's value from
// bytes.
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`.
// OBSOLETE(dustin): Use a `UndefinedValueEncoder` instead of an `UnknownTagValue`.
type TagUndefinedType_UnknownValue []byte
type UnknownTagValue interface {
ValueBytes() ([]byte, error)
}
// TODO(dustin): Rename `TagUnknownType_UnknownValue` to `TagUndefinedType_UnknownValue`.
type TagUnknownType_UnknownValue []byte
func (tutuv TagUnknownType_UnknownValue) String() string {
func (tutuv TagUndefinedType_UnknownValue) String() string {
parts := make([]string, len(tutuv))
for i, c := range tutuv {
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)
}
type TagUndefinedGeneralString string

View File

@ -1,13 +1,15 @@
package exif
import (
"bytes"
"fmt"
"strconv"
"strings"
"time"
"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
@ -75,10 +77,10 @@ type ExifTag struct {
TagId uint16 `json:"id"`
TagName string `json:"name"`
TagTypeId TagTypePrimitive `json:"type_id"`
TagTypeName string `json:"type_name"`
Value interface{} `json:"value"`
ValueBytes []byte `json:"value_bytes"`
TagTypeId exifcommon.TagTypePrimitive `json:"type_id"`
TagTypeName string `json:"type_name"`
Value interface{} `json:"value"`
ValueBytes []byte `json:"value_bytes"`
ChildIfdPath string `json:"child_ifd_path"`
}
@ -126,15 +128,15 @@ func GetFlatExifData(exifData []byte) (exifTags []ExifTag, err error) {
value, err := ifd.TagValue(ite)
if err != nil {
if err == ErrUnhandledUnknownTypedTag {
value = UnparseableUnknownTagValuePlaceholder
if err == exifcommon.ErrUnhandledUnknownTypedTag {
value = exifundefined.UnparseableUnknownTagValuePlaceholder
} else {
log.Panic(err)
}
}
valueBytes, err := ifd.TagValueBytes(ite)
if err != nil && err != ErrUnhandledUnknownTypedTag {
if err != nil && err != exifcommon.ErrUnhandledUnknownTypedTag {
log.Panic(err)
}
@ -143,7 +145,7 @@ func GetFlatExifData(exifData []byte) (exifTags []ExifTag, err error) {
TagId: ite.TagId,
TagName: tagName,
TagTypeId: ite.TagType,
TagTypeName: TypeNames[ite.TagType],
TagTypeName: ite.TagType.String(),
Value: value,
ValueBytes: valueBytes,
ChildIfdPath: ite.ChildIfdPath,

View File

@ -1,80 +1,13 @@
package exif
import (
"io/ioutil"
"fmt"
"os"
"testing"
"time"
"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) {
timestamp, err := ParseExifFullTimestamp("2018:11:30 13:01:49")
log.PanicIf(err)

View File

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