mirror of https://github.com/dsoprea/go-exif.git
Added all tests for type.go, type_encode.go, parser.go, value_context.go, and utility.go
- Add .MODULE_ROOT anchor file to support testing.for/master
parent
bf3bc4e542
commit
5c7dc45079
Binary file not shown.
|
@ -1,13 +1,63 @@
|
|||
package exifcommon
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
var (
|
||||
assetsPath = ""
|
||||
testImageFilepath = ""
|
||||
|
||||
testExifData = make([]byte, 0)
|
||||
|
||||
// EncodeDefaultByteOrder is the default byte-order for encoding operations.
|
||||
EncodeDefaultByteOrder = binary.BigEndian
|
||||
|
||||
// Default byte order for tests.
|
||||
TestDefaultByteOrder = binary.BigEndian
|
||||
)
|
||||
|
||||
func getModuleRootPath() string {
|
||||
currentWd, err := os.Getwd()
|
||||
log.PanicIf(err)
|
||||
|
||||
currentPath := currentWd
|
||||
|
||||
for {
|
||||
tryStampFilepath := path.Join(currentPath, ".MODULE_ROOT")
|
||||
|
||||
f, err := os.Open(tryStampFilepath)
|
||||
if err == nil {
|
||||
f.Close()
|
||||
break
|
||||
}
|
||||
|
||||
currentPath = path.Dir(currentPath)
|
||||
if currentPath == "/" {
|
||||
log.Panicf("could not find module-root")
|
||||
}
|
||||
}
|
||||
|
||||
return currentPath
|
||||
}
|
||||
|
||||
func init() {
|
||||
moduleRootPath := getModuleRootPath()
|
||||
assetsPath = path.Join(moduleRootPath, "assets")
|
||||
|
||||
testImageFilepath = path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
// Load test EXIF data.
|
||||
|
||||
filepath := path.Join(assetsPath, "NDM_8901.jpg.exif")
|
||||
|
||||
var err error
|
||||
testExifData, err = ioutil.ReadFile(filepath)
|
||||
log.PanicIf(err)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
// Parser knows how to parse all well-defined, encoded EXIF types.
|
||||
type Parser struct {
|
||||
}
|
||||
|
||||
|
@ -31,7 +32,8 @@ func (p *Parser) ParseBytes(data []byte, unitCount uint32) (value []uint8, err e
|
|||
return value, nil
|
||||
}
|
||||
|
||||
// ParseAscii returns a string and auto-strips the trailing NUL character.
|
||||
// ParseAscii returns a string and auto-strips the trailing NUL character that
|
||||
// should be at the end of the encoding.
|
||||
func (p *Parser) ParseAscii(data []byte, unitCount uint32) (value string, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -80,6 +82,7 @@ func (p *Parser) ParseAsciiNoNul(data []byte, unitCount uint32) (value string, e
|
|||
return string(data[:count]), nil
|
||||
}
|
||||
|
||||
// ParseShorts knows how to parse an encoded list of shorts.
|
||||
func (p *Parser) ParseShorts(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []uint16, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -103,6 +106,7 @@ func (p *Parser) ParseShorts(data []byte, unitCount uint32, byteOrder binary.Byt
|
|||
return value, nil
|
||||
}
|
||||
|
||||
// ParseLongs knows how to encode an encoded list of unsigned longs.
|
||||
func (p *Parser) ParseLongs(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []uint32, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -126,6 +130,7 @@ func (p *Parser) ParseLongs(data []byte, unitCount uint32, byteOrder binary.Byte
|
|||
return value, nil
|
||||
}
|
||||
|
||||
// ParseRationals knows how to parse an encoded list of unsigned rationals.
|
||||
func (p *Parser) ParseRationals(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []Rational, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -150,6 +155,7 @@ func (p *Parser) ParseRationals(data []byte, unitCount uint32, byteOrder binary.
|
|||
return value, nil
|
||||
}
|
||||
|
||||
// ParseSignedLongs knows how to parse an encoded list of signed longs.
|
||||
func (p *Parser) ParseSignedLongs(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []int32, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -176,6 +182,8 @@ func (p *Parser) ParseSignedLongs(data []byte, unitCount uint32, byteOrder binar
|
|||
return value, nil
|
||||
}
|
||||
|
||||
// ParseSignedRationals knows how to parse an encoded list of signed
|
||||
// rationals.
|
||||
func (p *Parser) ParseSignedRationals(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []SignedRational, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
|
|
@ -0,0 +1,320 @@
|
|||
package exifcommon
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
func TestParser_ParseBytes(t *testing.T) {
|
||||
p := new(Parser)
|
||||
|
||||
encoded := []byte("abcdefg")
|
||||
|
||||
value, err := p.ParseBytes(encoded, 1)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Equal(value, encoded[:1]) != true {
|
||||
t.Fatalf("Encoding not correct (1): %v", value)
|
||||
}
|
||||
|
||||
value, err = p.ParseBytes(encoded, 4)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Equal(value, encoded[:4]) != true {
|
||||
t.Fatalf("Encoding not correct (2): %v", value)
|
||||
}
|
||||
|
||||
value, err = p.ParseBytes(encoded, uint32(len(encoded)))
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Equal(value, encoded) != true {
|
||||
t.Fatalf("Encoding not correct (3): %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser_ParseAscii(t *testing.T) {
|
||||
p := new(Parser)
|
||||
|
||||
original := "abcdefg"
|
||||
|
||||
encoded := []byte(original[:1])
|
||||
encoded = append(encoded, 0)
|
||||
|
||||
value, err := p.ParseAscii(encoded, uint32(len(encoded)))
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != original[:1] {
|
||||
t.Fatalf("Encoding not correct (1): %s", value)
|
||||
}
|
||||
|
||||
encoded = []byte(original[:4])
|
||||
encoded = append(encoded, 0)
|
||||
|
||||
value, err = p.ParseAscii(encoded, uint32(len(encoded)))
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != original[:4] {
|
||||
t.Fatalf("Encoding not correct (2): %v", value)
|
||||
}
|
||||
|
||||
encoded = []byte(original)
|
||||
encoded = append(encoded, 0)
|
||||
|
||||
value, err = p.ParseAscii(encoded, uint32(len(encoded)))
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != original {
|
||||
t.Fatalf("Encoding not correct (3): %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser_ParseAsciiNoNul(t *testing.T) {
|
||||
p := new(Parser)
|
||||
|
||||
original := "abcdefg"
|
||||
|
||||
encoded := []byte(original)
|
||||
|
||||
value, err := p.ParseAsciiNoNul(encoded, 1)
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != original[:1] {
|
||||
t.Fatalf("Encoding not correct (1): %s", value)
|
||||
}
|
||||
|
||||
value, err = p.ParseAsciiNoNul(encoded, 4)
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != original[:4] {
|
||||
t.Fatalf("Encoding not correct (2): %v", value)
|
||||
}
|
||||
|
||||
value, err = p.ParseAsciiNoNul(encoded, uint32(len(encoded)))
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != original {
|
||||
t.Fatalf("Encoding not correct (3): (%d) %v", len(value), value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser_ParseShorts__Single(t *testing.T) {
|
||||
p := new(Parser)
|
||||
|
||||
encoded := []byte{0x00, 0x01}
|
||||
|
||||
value, err := p.ParseShorts(encoded, 1, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []uint16{1}) != true {
|
||||
t.Fatalf("Encoding not correct (1): %v", value)
|
||||
}
|
||||
|
||||
encoded = []byte{0x00, 0x01, 0x00, 0x02}
|
||||
|
||||
value, err = p.ParseShorts(encoded, 1, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []uint16{1}) != true {
|
||||
t.Fatalf("Encoding not correct (2): %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser_ParseShorts__Multiple(t *testing.T) {
|
||||
p := new(Parser)
|
||||
|
||||
encoded := []byte{0x00, 0x01, 0x00, 0x02}
|
||||
|
||||
value, err := p.ParseShorts(encoded, 2, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []uint16{1, 2}) != true {
|
||||
t.Fatalf("Encoding not correct: %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser_ParseLongs__Single(t *testing.T) {
|
||||
p := new(Parser)
|
||||
|
||||
encoded := []byte{0x00, 0x00, 0x00, 0x01}
|
||||
|
||||
value, err := p.ParseLongs(encoded, 1, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []uint32{1}) != true {
|
||||
t.Fatalf("Encoding not correct (1): %v", value)
|
||||
}
|
||||
|
||||
encoded = []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02}
|
||||
|
||||
value, err = p.ParseLongs(encoded, 1, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []uint32{1}) != true {
|
||||
t.Fatalf("Encoding not correct (2): %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser_ParseLongs__Multiple(t *testing.T) {
|
||||
p := new(Parser)
|
||||
|
||||
encoded := []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02}
|
||||
|
||||
value, err := p.ParseLongs(encoded, 2, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []uint32{1, 2}) != true {
|
||||
t.Fatalf("Encoding not correct: %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser_ParseRationals__Single(t *testing.T) {
|
||||
p := new(Parser)
|
||||
|
||||
encoded := []byte{
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
|
||||
}
|
||||
|
||||
value, err := p.ParseRationals(encoded, 1, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := []Rational{
|
||||
Rational{Numerator: 1, Denominator: 2},
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(value, expected) != true {
|
||||
t.Fatalf("Encoding not correct (1): %v", value)
|
||||
}
|
||||
|
||||
encoded = []byte{
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
|
||||
}
|
||||
|
||||
value, err = p.ParseRationals(encoded, 1, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
expected = []Rational{
|
||||
Rational{Numerator: 1, Denominator: 2},
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(value, expected) != true {
|
||||
t.Fatalf("Encoding not correct (2): %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser_ParseRationals__Multiple(t *testing.T) {
|
||||
p := new(Parser)
|
||||
|
||||
encoded := []byte{
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
|
||||
}
|
||||
|
||||
value, err := p.ParseRationals(encoded, 2, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := []Rational{
|
||||
Rational{Numerator: 1, Denominator: 2},
|
||||
Rational{Numerator: 3, Denominator: 4},
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(value, expected) != true {
|
||||
t.Fatalf("Encoding not correct (2): %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser_ParseSignedLongs__Single(t *testing.T) {
|
||||
p := new(Parser)
|
||||
|
||||
encoded := []byte{0x00, 0x00, 0x00, 0x01}
|
||||
|
||||
value, err := p.ParseSignedLongs(encoded, 1, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []int32{1}) != true {
|
||||
t.Fatalf("Encoding not correct (1): %v", value)
|
||||
}
|
||||
|
||||
encoded = []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02}
|
||||
|
||||
value, err = p.ParseSignedLongs(encoded, 1, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []int32{1}) != true {
|
||||
t.Fatalf("Encoding not correct (2): %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser_ParseSignedLongs__Multiple(t *testing.T) {
|
||||
p := new(Parser)
|
||||
|
||||
encoded := []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02}
|
||||
|
||||
value, err := p.ParseSignedLongs(encoded, 2, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []int32{1, 2}) != true {
|
||||
t.Fatalf("Encoding not correct: %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser_ParseSignedRationals__Single(t *testing.T) {
|
||||
p := new(Parser)
|
||||
|
||||
encoded := []byte{
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
|
||||
}
|
||||
|
||||
value, err := p.ParseSignedRationals(encoded, 1, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := []SignedRational{
|
||||
SignedRational{Numerator: 1, Denominator: 2},
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(value, expected) != true {
|
||||
t.Fatalf("Encoding not correct (1): %v", value)
|
||||
}
|
||||
|
||||
encoded = []byte{
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
|
||||
}
|
||||
|
||||
value, err = p.ParseSignedRationals(encoded, 1, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
expected = []SignedRational{
|
||||
SignedRational{Numerator: 1, Denominator: 2},
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(value, expected) != true {
|
||||
t.Fatalf("Encoding not correct (2): %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser_ParseSignedRationals__Multiple(t *testing.T) {
|
||||
p := new(Parser)
|
||||
|
||||
encoded := []byte{
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
|
||||
}
|
||||
|
||||
value, err := p.ParseSignedRationals(encoded, 2, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := []SignedRational{
|
||||
SignedRational{Numerator: 1, Denominator: 2},
|
||||
SignedRational{Numerator: 3, Denominator: 4},
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(value, expected) != true {
|
||||
t.Fatalf("Encoding not correct (2): %v", value)
|
||||
}
|
||||
}
|
|
@ -11,12 +11,65 @@ import (
|
|||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
var (
|
||||
typeLogger = log.NewLogger("exif.type")
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotEnoughData is used when there isn't enough data to accomodate what
|
||||
// we're trying to parse (sizeof(type) * unit_count).
|
||||
ErrNotEnoughData = errors.New("not enough data for type")
|
||||
|
||||
// ErrWrongType is used when we try to parse anything other than the
|
||||
// current type.
|
||||
ErrWrongType = errors.New("wrong type, can not parse")
|
||||
|
||||
// ErrUnhandledUnknownTypedTag is used when we try to parse a tag that's
|
||||
// recorded as an "unknown" type but not a documented tag (therefore
|
||||
// leaving us not knowning how to read it).
|
||||
ErrUnhandledUnknownTypedTag = errors.New("not a standard unknown-typed tag")
|
||||
)
|
||||
|
||||
// TagTypePrimitive is a type-alias that let's us easily lookup type properties.
|
||||
type TagTypePrimitive uint16
|
||||
|
||||
const (
|
||||
// TypeByte describes an encoded list of bytes.
|
||||
TypeByte TagTypePrimitive = 1
|
||||
|
||||
// TypeAscii describes an encoded list of characters that is terminated
|
||||
// with a NUL in its encoded form.
|
||||
TypeAscii TagTypePrimitive = 2
|
||||
|
||||
// TypeShort describes an encoded list of shorts.
|
||||
TypeShort TagTypePrimitive = 3
|
||||
|
||||
// TypeLong describes an encoded list of longs.
|
||||
TypeLong TagTypePrimitive = 4
|
||||
|
||||
// TypeRational describes an encoded list of rationals.
|
||||
TypeRational TagTypePrimitive = 5
|
||||
|
||||
// TypeUndefined describes an encoded value that has a complex/non-clearcut
|
||||
// interpretation.
|
||||
TypeUndefined TagTypePrimitive = 7
|
||||
|
||||
// TypeSignedLong describes an encoded list of signed longs.
|
||||
TypeSignedLong TagTypePrimitive = 9
|
||||
|
||||
// TypeSignedRational describes an encoded list of signed rationals.
|
||||
TypeSignedRational TagTypePrimitive = 10
|
||||
|
||||
// TypeAsciiNoNul is just a pseudo-type, for our own purposes.
|
||||
TypeAsciiNoNul TagTypePrimitive = 0xf0
|
||||
)
|
||||
|
||||
// String returns the name of the type
|
||||
func (typeType TagTypePrimitive) String() string {
|
||||
return TypeNames[typeType]
|
||||
}
|
||||
|
||||
// Size returns the size of one atomic unit of the type.
|
||||
func (tagType TagTypePrimitive) Size() int {
|
||||
if tagType == TypeByte {
|
||||
return 1
|
||||
|
@ -40,24 +93,6 @@ func (tagType TagTypePrimitive) Size() int {
|
|||
}
|
||||
}
|
||||
|
||||
const (
|
||||
TypeByte TagTypePrimitive = 1
|
||||
TypeAscii TagTypePrimitive = 2
|
||||
TypeShort TagTypePrimitive = 3
|
||||
TypeLong TagTypePrimitive = 4
|
||||
TypeRational TagTypePrimitive = 5
|
||||
TypeUndefined TagTypePrimitive = 7
|
||||
TypeSignedLong TagTypePrimitive = 9
|
||||
TypeSignedRational TagTypePrimitive = 10
|
||||
|
||||
// TypeAsciiNoNul is just a pseudo-type, for our own purposes.
|
||||
TypeAsciiNoNul TagTypePrimitive = 0xf0
|
||||
)
|
||||
|
||||
var (
|
||||
typeLogger = log.NewLogger("exif.type")
|
||||
)
|
||||
|
||||
var (
|
||||
// TODO(dustin): Rename TypeNames() to typeNames() and add getter.
|
||||
TypeNames = map[TagTypePrimitive]string{
|
||||
|
@ -76,21 +111,6 @@ var (
|
|||
TypeNamesR = map[string]TagTypePrimitive{}
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotEnoughData is used when there isn't enough data to accomodate what
|
||||
// we're trying to parse (sizeof(type) * unit_count).
|
||||
ErrNotEnoughData = errors.New("not enough data for type")
|
||||
|
||||
// ErrWrongType is used when we try to parse anything other than the
|
||||
// current type.
|
||||
ErrWrongType = errors.New("wrong type, can not parse")
|
||||
|
||||
// ErrUnhandledUnknownTag is used when we try to parse a tag that's
|
||||
// recorded as an "unknown" type but not a documented tag (therefore
|
||||
// leaving us not knowning how to read it).
|
||||
ErrUnhandledUnknownTypedTag = errors.New("not a standard unknown-typed tag")
|
||||
)
|
||||
|
||||
type Rational struct {
|
||||
Numerator uint32
|
||||
Denominator uint32
|
||||
|
@ -101,15 +121,8 @@ type SignedRational struct {
|
|||
Denominator int32
|
||||
}
|
||||
|
||||
func TagTypeSize(tagType TagTypePrimitive) int {
|
||||
|
||||
// DEPRECATED(dustin): `(TagTypePrimitive).Size()` should be used, directly.
|
||||
|
||||
return tagType.Size()
|
||||
}
|
||||
|
||||
// Format returns a stringified value for the given bytes. Automatically
|
||||
// calculates count based on type size.
|
||||
// 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) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -236,7 +249,11 @@ func Format(rawBytes []byte, tagType TagTypePrimitive, justFirst bool, byteOrder
|
|||
}
|
||||
}
|
||||
|
||||
func EncodeStringToBytes(tagType TagTypePrimitive, valueString string) (value interface{}, err error) {
|
||||
// TranslateStringToType converts user-provided strings to properly-typed
|
||||
// values. If a string, returns a string. Else, assumes that it's a single
|
||||
// number. If a list needs to be processed, it is the caller's responsibility to
|
||||
// split it (according to whichever convention has been established).
|
||||
func TranslateStringToType(tagType TagTypePrimitive, valueString string) (value interface{}, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
|
@ -249,7 +266,10 @@ func EncodeStringToBytes(tagType TagTypePrimitive, valueString string) (value in
|
|||
}
|
||||
|
||||
if tagType == TypeByte {
|
||||
return []byte(valueString), nil
|
||||
wide, err := strconv.ParseInt(valueString, 16, 8)
|
||||
log.PanicIf(err)
|
||||
|
||||
return byte(wide), nil
|
||||
} else if tagType == TypeAscii || tagType == TypeAsciiNoNul {
|
||||
// Whether or not we're putting an NUL on the end is only relevant for
|
||||
// byte-level encoding. This function really just supports a user
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
func TestByteCycle(t *testing.T) {
|
||||
func TestValueEncoder_encodeBytes__Cycle(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
@ -28,15 +28,15 @@ func TestByteCycle(t *testing.T) {
|
|||
t.Fatalf("Unit-count not correct.")
|
||||
}
|
||||
|
||||
tt := NewTagType(ed.Type, byteOrder)
|
||||
recovered, err := tt.ParseBytes(ed.Encoded, ed.UnitCount)
|
||||
recovered, err := parser.ParseBytes(ed.Encoded, ed.UnitCount)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(recovered, original) != true {
|
||||
t.Fatalf("Value not recovered correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsciiCycle(t *testing.T) {
|
||||
func TestValueEncoder_encodeAscii__Cycle(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
@ -61,15 +61,15 @@ func TestAsciiCycle(t *testing.T) {
|
|||
// Check that the string was recovered correctly and with the trailing NUL
|
||||
// character autostripped.
|
||||
|
||||
tt := NewTagType(TypeAscii, byteOrder)
|
||||
recovered, err := tt.ParseAscii(ed.Encoded, ed.UnitCount)
|
||||
recovered, err := parser.ParseAscii(ed.Encoded, ed.UnitCount)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(recovered, original) != true {
|
||||
t.Fatalf("Value not recovered correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsciiNoNulCycle(t *testing.T) {
|
||||
func TestValueEncoder_encodeAsciiNoNul__Cycle(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
@ -93,15 +93,15 @@ func TestAsciiNoNulCycle(t *testing.T) {
|
|||
// Check that the string was recovered correctly and with the trailing NUL
|
||||
// character ignored (because not expected in the context of that type).
|
||||
|
||||
tt := NewTagType(TypeAsciiNoNul, byteOrder)
|
||||
recovered, err := tt.ParseAsciiNoNul(ed.Encoded, ed.UnitCount)
|
||||
recovered, err := parser.ParseAsciiNoNul(ed.Encoded, ed.UnitCount)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(recovered, string(expected)) != true {
|
||||
t.Fatalf("Value not recovered correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShortCycle(t *testing.T) {
|
||||
func TestValueEncoder_encodeShorts__Cycle(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
@ -128,15 +128,15 @@ func TestShortCycle(t *testing.T) {
|
|||
t.Fatalf("Unit-count not correct.")
|
||||
}
|
||||
|
||||
tt := NewTagType(ed.Type, byteOrder)
|
||||
recovered, err := tt.ParseShorts(ed.Encoded, ed.UnitCount)
|
||||
recovered, err := parser.ParseShorts(ed.Encoded, ed.UnitCount, byteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(recovered, original) != true {
|
||||
t.Fatalf("Value not recovered correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLongCycle(t *testing.T) {
|
||||
func TestValueEncoder_encodeLongs__Cycle(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
@ -163,15 +163,15 @@ func TestLongCycle(t *testing.T) {
|
|||
t.Fatalf("Unit-count not correct.")
|
||||
}
|
||||
|
||||
tt := NewTagType(ed.Type, byteOrder)
|
||||
recovered, err := tt.ParseLongs(ed.Encoded, ed.UnitCount)
|
||||
recovered, err := parser.ParseLongs(ed.Encoded, ed.UnitCount, byteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(recovered, original) != true {
|
||||
t.Fatalf("Value not recovered correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRationalCycle(t *testing.T) {
|
||||
func TestValueEncoder_encodeRationals__Cycle(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
@ -224,15 +224,15 @@ func TestRationalCycle(t *testing.T) {
|
|||
t.Fatalf("Unit-count not correct.")
|
||||
}
|
||||
|
||||
tt := NewTagType(ed.Type, byteOrder)
|
||||
recovered, err := tt.ParseRationals(ed.Encoded, ed.UnitCount)
|
||||
recovered, err := parser.ParseRationals(ed.Encoded, ed.UnitCount, byteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(recovered, original) != true {
|
||||
t.Fatalf("Value not recovered correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignedLongCycle(t *testing.T) {
|
||||
func TestValueEncoder_encodeSignedLongs__Cycle(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
@ -259,15 +259,15 @@ func TestSignedLongCycle(t *testing.T) {
|
|||
t.Fatalf("Unit-count not correct.")
|
||||
}
|
||||
|
||||
tt := NewTagType(ed.Type, byteOrder)
|
||||
recovered, err := tt.ParseSignedLongs(ed.Encoded, ed.UnitCount)
|
||||
recovered, err := parser.ParseSignedLongs(ed.Encoded, ed.UnitCount, byteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(recovered, original) != true {
|
||||
t.Fatalf("Value not recovered correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignedRationalCycle(t *testing.T) {
|
||||
func TestValueEncoder_encodeSignedRationals__Cycle(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
@ -320,15 +320,15 @@ func TestSignedRationalCycle(t *testing.T) {
|
|||
t.Fatalf("Unit-count not correct.")
|
||||
}
|
||||
|
||||
tt := NewTagType(ed.Type, byteOrder)
|
||||
recovered, err := tt.ParseSignedRationals(ed.Encoded, ed.UnitCount)
|
||||
recovered, err := parser.ParseSignedRationals(ed.Encoded, ed.UnitCount, byteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(recovered, original) != true {
|
||||
t.Fatalf("Value not recovered correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncode_Byte(t *testing.T) {
|
||||
func TestValueEncoder_Encode__Byte(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
@ -350,7 +350,7 @@ func TestEncode_Byte(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEncode_Ascii(t *testing.T) {
|
||||
func TestValueEncoder_Encode__Ascii(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
@ -373,7 +373,7 @@ func TestEncode_Ascii(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEncode_Short(t *testing.T) {
|
||||
func TestValueEncoder_Encode__Short(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
@ -401,7 +401,7 @@ func TestEncode_Short(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEncode_Long(t *testing.T) {
|
||||
func TestValueEncoder_Encode__Long(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
@ -429,7 +429,7 @@ func TestEncode_Long(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEncode_Rational(t *testing.T) {
|
||||
func TestValueEncoder_Encode__Rational(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
@ -483,7 +483,7 @@ func TestEncode_Rational(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEncode_SignedLong(t *testing.T) {
|
||||
func TestValueEncoder_Encode__SignedLong(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
@ -511,7 +511,7 @@ func TestEncode_SignedLong(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEncode_SignedRational(t *testing.T) {
|
||||
func TestValueEncoder_Encode__SignedRational(t *testing.T) {
|
||||
byteOrder := TestDefaultByteOrder
|
||||
ve := NewValueEncoder(byteOrder)
|
||||
|
||||
|
|
|
@ -0,0 +1,344 @@
|
|||
package exifcommon
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
func TestTypeByte_String(t *testing.T) {
|
||||
if TypeByte.String() != "BYTE" {
|
||||
t.Fatalf("Type name not correct (byte): [%s]", TypeByte.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeAscii_String(t *testing.T) {
|
||||
if TypeAscii.String() != "ASCII" {
|
||||
t.Fatalf("Type name not correct (ASCII): [%s]", TypeAscii.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeAsciiNoNul_String(t *testing.T) {
|
||||
if TypeAsciiNoNul.String() != "_ASCII_NO_NUL" {
|
||||
t.Fatalf("Type name not correct (ASCII no-NUL): [%s]", TypeAsciiNoNul.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeShort_String(t *testing.T) {
|
||||
if TypeShort.String() != "SHORT" {
|
||||
t.Fatalf("Type name not correct (short): [%s]", TypeShort.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeLong_String(t *testing.T) {
|
||||
if TypeLong.String() != "LONG" {
|
||||
t.Fatalf("Type name not correct (long): [%s]", TypeLong.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeRational_String(t *testing.T) {
|
||||
if TypeRational.String() != "RATIONAL" {
|
||||
t.Fatalf("Type name not correct (rational): [%s]", TypeRational.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeSignedLong_String(t *testing.T) {
|
||||
if TypeSignedLong.String() != "SLONG" {
|
||||
t.Fatalf("Type name not correct (signed long): [%s]", TypeSignedLong.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeSignedRational_String(t *testing.T) {
|
||||
if TypeSignedRational.String() != "SRATIONAL" {
|
||||
t.Fatalf("Type name not correct (signed rational): [%s]", TypeSignedRational.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeByte_Size(t *testing.T) {
|
||||
if TypeByte.Size() != 1 {
|
||||
t.Fatalf("Type size not correct (byte): (%d)", TypeByte.Size())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeAscii_Size(t *testing.T) {
|
||||
if TypeAscii.Size() != 1 {
|
||||
t.Fatalf("Type size not correct (ASCII): (%d)", TypeAscii.Size())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeAsciiNoNul_Size(t *testing.T) {
|
||||
if TypeAsciiNoNul.Size() != 1 {
|
||||
t.Fatalf("Type size not correct (ASCII no-NUL): (%d)", TypeAsciiNoNul.Size())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeShort_Size(t *testing.T) {
|
||||
if TypeShort.Size() != 2 {
|
||||
t.Fatalf("Type size not correct (short): (%d)", TypeShort.Size())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeLong_Size(t *testing.T) {
|
||||
if TypeLong.Size() != 4 {
|
||||
t.Fatalf("Type size not correct (long): (%d)", TypeLong.Size())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeRational_Size(t *testing.T) {
|
||||
if TypeRational.Size() != 8 {
|
||||
t.Fatalf("Type size not correct (rational): (%d)", TypeRational.Size())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeSignedLong_Size(t *testing.T) {
|
||||
if TypeSignedLong.Size() != 4 {
|
||||
t.Fatalf("Type size not correct (signed long): (%d)", TypeSignedLong.Size())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeSignedRational_Size(t *testing.T) {
|
||||
if TypeSignedRational.Size() != 8 {
|
||||
t.Fatalf("Type size not correct (signed rational): (%d)", TypeSignedRational.Size())
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormat__Byte(t *testing.T) {
|
||||
r := []byte{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
|
||||
s, err := Format(r, TypeByte, false, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if s != "01 02 03 04 05 06 07 08" {
|
||||
t.Fatalf("Format output not correct (bytes): [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormat__Ascii(t *testing.T) {
|
||||
r := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
|
||||
|
||||
s, err := Format(r, TypeAscii, false, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if s != "abcdefg" {
|
||||
t.Fatalf("Format output not correct (ASCII): [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormat__AsciiNoNul(t *testing.T) {
|
||||
r := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
|
||||
s, err := Format(r, TypeAsciiNoNul, false, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if s != "abcdefgh" {
|
||||
t.Fatalf("Format output not correct (ASCII no-NUL): [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormat__Short(t *testing.T) {
|
||||
r := []byte{0, 1, 0, 2}
|
||||
|
||||
s, err := Format(r, TypeShort, false, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if s != "[1 2]" {
|
||||
t.Fatalf("Format output not correct (shorts): [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormat__Long(t *testing.T) {
|
||||
r := []byte{0, 0, 0, 1, 0, 0, 0, 2}
|
||||
|
||||
s, err := Format(r, TypeLong, false, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if s != "[1 2]" {
|
||||
t.Fatalf("Format output not correct (longs): [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormat__Rational(t *testing.T) {
|
||||
r := []byte{
|
||||
0, 0, 0, 1, 0, 0, 0, 2,
|
||||
0, 0, 0, 3, 0, 0, 0, 4,
|
||||
}
|
||||
|
||||
s, err := Format(r, TypeRational, false, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if s != "[1/2 3/4]" {
|
||||
t.Fatalf("Format output not correct (rationals): [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormat__SignedLong(t *testing.T) {
|
||||
r := []byte{0, 0, 0, 1, 0, 0, 0, 2}
|
||||
|
||||
s, err := Format(r, TypeSignedLong, false, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if s != "[1 2]" {
|
||||
t.Fatalf("Format output not correct (signed longs): [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormat__SignedRational(t *testing.T) {
|
||||
r := []byte{
|
||||
0, 0, 0, 1, 0, 0, 0, 2,
|
||||
0, 0, 0, 3, 0, 0, 0, 4,
|
||||
}
|
||||
|
||||
s, err := Format(r, TypeSignedRational, false, TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if s != "[1/2 3/4]" {
|
||||
t.Fatalf("Format output not correct (signed rationals): [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormat__Undefined(t *testing.T) {
|
||||
r := []byte{'a', 'b'}
|
||||
|
||||
_, err := Format(r, TypeUndefined, false, TestDefaultByteOrder)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error.")
|
||||
} else if err.Error() != "can not determine tag-value size for type (7): [UNDEFINED]" {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslateStringToType__TypeUndefined(t *testing.T) {
|
||||
_, err := TranslateStringToType(TypeUndefined, "")
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error.")
|
||||
} else if err.Error() != "undefined-type values are not supported" {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslateStringToType__TypeByte(t *testing.T) {
|
||||
v, err := TranslateStringToType(TypeByte, "02")
|
||||
log.PanicIf(err)
|
||||
|
||||
if v != byte(2) {
|
||||
t.Fatalf("Translation of string to type not correct (bytes): %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslateStringToType__TypeAscii(t *testing.T) {
|
||||
v, err := TranslateStringToType(TypeAscii, "abcdefgh")
|
||||
log.PanicIf(err)
|
||||
|
||||
if v != "abcdefgh" {
|
||||
t.Fatalf("Translation of string to type not correct (ascii): %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslateStringToType__TypeAsciiNoNul(t *testing.T) {
|
||||
v, err := TranslateStringToType(TypeAsciiNoNul, "abcdefgh")
|
||||
log.PanicIf(err)
|
||||
|
||||
if v != "abcdefgh" {
|
||||
t.Fatalf("Translation of string to type not correct (ascii no-NUL): %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslateStringToType__TypeShort(t *testing.T) {
|
||||
v, err := TranslateStringToType(TypeShort, "11")
|
||||
log.PanicIf(err)
|
||||
|
||||
if v != uint16(11) {
|
||||
t.Fatalf("Translation of string to type not correct (short): %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslateStringToType__TypeLong(t *testing.T) {
|
||||
v, err := TranslateStringToType(TypeLong, "11")
|
||||
log.PanicIf(err)
|
||||
|
||||
if v != uint32(11) {
|
||||
t.Fatalf("Translation of string to type not correct (long): %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslateStringToType__TypeRational(t *testing.T) {
|
||||
v, err := TranslateStringToType(TypeRational, "11/22")
|
||||
log.PanicIf(err)
|
||||
|
||||
r := v.(Rational)
|
||||
|
||||
if r.Numerator != 11 || r.Denominator != 22 {
|
||||
t.Fatalf("Translation of string to type not correct (rational): %v", r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslateStringToType__TypeSignedLong(t *testing.T) {
|
||||
v, err := TranslateStringToType(TypeSignedLong, "11")
|
||||
log.PanicIf(err)
|
||||
|
||||
if v != int32(11) {
|
||||
t.Fatalf("Translation of string to type not correct (signed long): %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslateStringToType__TypeSignedRational(t *testing.T) {
|
||||
v, err := TranslateStringToType(TypeSignedRational, "11/22")
|
||||
log.PanicIf(err)
|
||||
|
||||
r := v.(SignedRational)
|
||||
|
||||
if r.Numerator != 11 || r.Denominator != 22 {
|
||||
t.Fatalf("Translation of string to type not correct (signed rational): %v", r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslateStringToType__InvalidType(t *testing.T) {
|
||||
_, err := TranslateStringToType(99, "11/22")
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error for invalid type.")
|
||||
} else if err.Error() != "from-string encoding for type not supported; this shouldn't happen: []" {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// } else if tagType == TypeLong {
|
||||
// n, err := strconv.ParseUint(valueString, 10, 32)
|
||||
// log.PanicIf(err)
|
||||
|
||||
// return uint32(n), nil
|
||||
// } else if tagType == TypeRational {
|
||||
// parts := strings.SplitN(valueString, "/", 2)
|
||||
|
||||
// numerator, err := strconv.ParseUint(parts[0], 10, 32)
|
||||
// log.PanicIf(err)
|
||||
|
||||
// denominator, err := strconv.ParseUint(parts[1], 10, 32)
|
||||
// log.PanicIf(err)
|
||||
|
||||
// return Rational{
|
||||
// Numerator: uint32(numerator),
|
||||
// Denominator: uint32(denominator),
|
||||
// }, nil
|
||||
// } else if tagType == TypeSignedLong {
|
||||
// n, err := strconv.ParseInt(valueString, 10, 32)
|
||||
// log.PanicIf(err)
|
||||
|
||||
// return int32(n), nil
|
||||
// } else if tagType == TypeSignedRational {
|
||||
// parts := strings.SplitN(valueString, "/", 2)
|
||||
|
||||
// numerator, err := strconv.ParseInt(parts[0], 10, 32)
|
||||
// log.PanicIf(err)
|
||||
|
||||
// denominator, err := strconv.ParseInt(parts[1], 10, 32)
|
||||
// log.PanicIf(err)
|
||||
|
||||
// return SignedRational{
|
||||
// Numerator: int32(numerator),
|
||||
// Denominator: int32(denominator),
|
||||
// }, nil
|
||||
// }
|
||||
|
||||
// log.Panicf("from-string encoding for type not supported; this shouldn't happen: [%s]", tagType.String())
|
||||
// return nil, nil
|
||||
// }
|
|
@ -10,8 +10,8 @@ var (
|
|||
parser *Parser
|
||||
)
|
||||
|
||||
// ValueContext describes all of the parameters required to find and extract
|
||||
// the actual tag value.
|
||||
// ValueContext embeds all of the parameters required to find and extract the
|
||||
// actual tag value.
|
||||
type ValueContext struct {
|
||||
unitCount uint32
|
||||
valueOffset uint32
|
||||
|
@ -29,6 +29,9 @@ type ValueContext struct {
|
|||
tagId uint16
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return &ValueContext{
|
||||
unitCount: unitCount,
|
||||
|
@ -44,34 +47,48 @@ func newValueContext(ifdPath string, tagId uint16, unitCount, valueOffset uint32
|
|||
}
|
||||
}
|
||||
|
||||
func (vc *ValueContext) SetUnknownValueType(tagType TagTypePrimitive) {
|
||||
// SetUndefinedValueType sets the effective type if this is an unknown-type tag.
|
||||
func (vc *ValueContext) SetUndefinedValueType(tagType TagTypePrimitive) {
|
||||
if vc.tagType != TypeUndefined {
|
||||
log.Panicf("can not set effective type for unknown-type tag because this is *not* an unknown-type tag")
|
||||
}
|
||||
|
||||
vc.undefinedValueTagType = tagType
|
||||
}
|
||||
|
||||
// UnitCount returns the embedded unit-count.
|
||||
func (vc *ValueContext) UnitCount() uint32 {
|
||||
return vc.unitCount
|
||||
}
|
||||
|
||||
// ValueOffset returns the value-offset decoded as a `uint32`.
|
||||
func (vc *ValueContext) ValueOffset() uint32 {
|
||||
return vc.valueOffset
|
||||
}
|
||||
|
||||
// RawValueOffset returns the uninterpreted value-offset. This is used for
|
||||
// embedded values (values small enough to fit within the offset bytes rather
|
||||
// than needing to be stored elsewhere and referred to by an actual offset).
|
||||
func (vc *ValueContext) RawValueOffset() []byte {
|
||||
return vc.rawValueOffset
|
||||
}
|
||||
|
||||
// AddressableData returns the block of data that we can dereference into.
|
||||
func (vc *ValueContext) AddressableData() []byte {
|
||||
return vc.addressableData
|
||||
}
|
||||
|
||||
// ByteOrder returns the byte-order of numbers.
|
||||
func (vc *ValueContext) ByteOrder() binary.ByteOrder {
|
||||
return vc.byteOrder
|
||||
}
|
||||
|
||||
// IfdPath returns the path of the IFD containing this tag.
|
||||
func (vc *ValueContext) IfdPath() string {
|
||||
return vc.ifdPath
|
||||
}
|
||||
|
||||
// TagId returns the ID of the tag that we represent.
|
||||
func (vc *ValueContext) TagId() uint16 {
|
||||
return vc.tagId
|
||||
}
|
||||
|
@ -85,6 +102,8 @@ func (vc *ValueContext) isEmbedded() bool {
|
|||
return (tagType.Size() * int(vc.unitCount)) <= 4
|
||||
}
|
||||
|
||||
// effectiveValueType returns the effective type of the unknown-type tag or, if
|
||||
// not unknown, the actual type.
|
||||
func (vc *ValueContext) effectiveValueType() (tagType TagTypePrimitive) {
|
||||
if vc.tagType == TypeUndefined {
|
||||
tagType = vc.undefinedValueTagType
|
||||
|
@ -99,6 +118,7 @@ func (vc *ValueContext) effectiveValueType() (tagType TagTypePrimitive) {
|
|||
return tagType
|
||||
}
|
||||
|
||||
// readRawEncoded returns the encoded bytes for the value that we represent.
|
||||
func (vc *ValueContext) readRawEncoded() (rawBytes []byte, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -137,13 +157,13 @@ func (vc *ValueContext) Format() (value string, err error) {
|
|||
rawBytes, err := vc.readRawEncoded()
|
||||
log.PanicIf(err)
|
||||
|
||||
phrase, err := Format(rawBytes, vc.tagType, false, vc.byteOrder)
|
||||
phrase, err := Format(rawBytes, vc.effectiveValueType(), false, vc.byteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
return phrase, nil
|
||||
}
|
||||
|
||||
// FormatOne is similar to `Format` but only gets and stringifies the first
|
||||
// FormatFirst is similar to `Format` but only gets and stringifies the first
|
||||
// item.
|
||||
func (vc *ValueContext) FormatFirst() (value string, err error) {
|
||||
defer func() {
|
||||
|
@ -161,6 +181,7 @@ func (vc *ValueContext) FormatFirst() (value string, err error) {
|
|||
return phrase, nil
|
||||
}
|
||||
|
||||
// ReadBytes parses the encoded byte-array from the value-context.
|
||||
func (vc *ValueContext) ReadBytes() (value []byte, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -177,6 +198,8 @@ func (vc *ValueContext) ReadBytes() (value []byte, err error) {
|
|||
return value, nil
|
||||
}
|
||||
|
||||
// ReadAscii parses the encoded NUL-terminated ASCII string from the value-
|
||||
// context.
|
||||
func (vc *ValueContext) ReadAscii() (value string, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -193,6 +216,8 @@ func (vc *ValueContext) ReadAscii() (value string, err error) {
|
|||
return value, nil
|
||||
}
|
||||
|
||||
// ReadAsciiNoNul parses the non-NUL-terminated encoded ASCII string from the
|
||||
// value-context.
|
||||
func (vc *ValueContext) ReadAsciiNoNul() (value string, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -209,6 +234,7 @@ func (vc *ValueContext) ReadAsciiNoNul() (value string, err error) {
|
|||
return value, nil
|
||||
}
|
||||
|
||||
// ReadShorts parses the list of encoded shorts from the value-context.
|
||||
func (vc *ValueContext) ReadShorts() (value []uint16, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -225,6 +251,7 @@ func (vc *ValueContext) ReadShorts() (value []uint16, err error) {
|
|||
return value, nil
|
||||
}
|
||||
|
||||
// ReadLongs parses the list of encoded, unsigned longs from the value-context.
|
||||
func (vc *ValueContext) ReadLongs() (value []uint32, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -241,6 +268,8 @@ func (vc *ValueContext) ReadLongs() (value []uint32, err error) {
|
|||
return value, nil
|
||||
}
|
||||
|
||||
// ReadRationals parses the list of encoded, unsigned rationals from the value-
|
||||
// context.
|
||||
func (vc *ValueContext) ReadRationals() (value []Rational, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -257,6 +286,7 @@ func (vc *ValueContext) ReadRationals() (value []Rational, err error) {
|
|||
return value, nil
|
||||
}
|
||||
|
||||
// ReadSignedLongs parses the list of encoded, signed longs from the value-context.
|
||||
func (vc *ValueContext) ReadSignedLongs() (value []int32, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -273,6 +303,8 @@ func (vc *ValueContext) ReadSignedLongs() (value []int32, err error) {
|
|||
return value, nil
|
||||
}
|
||||
|
||||
// ReadSignedRationals parses the list of encoded, signed rationals from the
|
||||
// value-context.
|
||||
func (vc *ValueContext) ReadSignedRationals() (value []SignedRational, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
|
@ -341,21 +373,6 @@ func (vc *ValueContext) Values() (values interface{}, err error) {
|
|||
return values, nil
|
||||
}
|
||||
|
||||
// // Undefined attempts to identify and decode supported undefined-type fields.
|
||||
// // This is the primary, preferred interface to reading undefined values.
|
||||
// func (vc *ValueContext) Undefined() (value interface{}, err error) {
|
||||
// defer func() {
|
||||
// if state := recover(); state != nil {
|
||||
// err = log.Wrap(state.(error))
|
||||
// }
|
||||
// }()
|
||||
|
||||
// value, err = UndefinedValue(vc.ifdPath, vc.tagId, vc, vc.byteOrder)
|
||||
// log.PanicIf(err)
|
||||
|
||||
// return value, nil
|
||||
// }
|
||||
|
||||
func init() {
|
||||
parser = new(Parser)
|
||||
}
|
||||
|
|
|
@ -2,111 +2,857 @@ package exifcommon
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
if vc.ifdPath != "aa/bb" {
|
||||
t.Fatalf("ifdPath not correct: [%s]", vc.ifdPath)
|
||||
} else if vc.tagId != 0x1234 {
|
||||
t.Fatalf("tagId not correct: (0x%04x)", vc.tagId)
|
||||
} else if vc.unitCount != 11 {
|
||||
t.Fatalf("unitCount not correct: (%d)", vc.unitCount)
|
||||
} else if vc.valueOffset != 22 {
|
||||
t.Fatalf("valueOffset not correct: (%d)", vc.valueOffset)
|
||||
} else if bytes.Equal(vc.rawValueOffset, rawValueOffset) != true {
|
||||
t.Fatalf("rawValueOffset not correct: %v", vc.rawValueOffset)
|
||||
} else if bytes.Equal(vc.addressableData, addressableData) != true {
|
||||
t.Fatalf("addressableData not correct: %v", vc.addressableData)
|
||||
} else if vc.tagType != TypeLong {
|
||||
t.Fatalf("tagType not correct: (%d)", vc.tagType)
|
||||
} else if vc.byteOrder != TestDefaultByteOrder {
|
||||
t.Fatalf("byteOrder not correct: %v", vc.byteOrder)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_SetUndefinedValueType__ErrorWhenNotUndefined(t *testing.T) {
|
||||
defer func() {
|
||||
if errRaw := recover(); errRaw != nil {
|
||||
err := errRaw.(error)
|
||||
if err.Error() != "can not set effective type for unknown-type tag because this is *not* an unknown-type tag" {
|
||||
t.Fatalf("Error not expected: [%s]", err.Error())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
t.Fatalf("Expected error.")
|
||||
}()
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 22}
|
||||
addressableData := []byte{1, 2, 3, 4}
|
||||
vc := newValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder)
|
||||
|
||||
vc.SetUndefinedValueType(TypeLong)
|
||||
}
|
||||
|
||||
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.SetUndefinedValueType(TypeLong)
|
||||
|
||||
if vc.tagType != TypeUndefined {
|
||||
t.Fatalf("Internal type not still 'undefined': (%d)", vc.tagType)
|
||||
} else if vc.undefinedValueTagType != TypeLong {
|
||||
t.Fatalf("Internal undefined-type not correct: (%d)", vc.undefinedValueTagType)
|
||||
} else if vc.effectiveValueType() != TypeLong {
|
||||
t.Fatalf("Effective tag not correct: (%d)", vc.effectiveValueType())
|
||||
}
|
||||
}
|
||||
|
||||
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.SetUndefinedValueType(TypeLong)
|
||||
|
||||
if vc.tagType != TypeUndefined {
|
||||
t.Fatalf("Internal type not still 'undefined': (%d)", vc.tagType)
|
||||
} else if vc.undefinedValueTagType != TypeLong {
|
||||
t.Fatalf("Internal undefined-type not correct: (%d)", vc.undefinedValueTagType)
|
||||
} else if vc.effectiveValueType() != TypeLong {
|
||||
t.Fatalf("Effective tag not correct: (%d)", vc.effectiveValueType())
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if vc.UnitCount() != 11 {
|
||||
t.Fatalf("UnitCount() not correct: (%d)", vc.UnitCount())
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if vc.ValueOffset() != 22 {
|
||||
t.Fatalf("ValueOffset() not correct: (%d)", vc.ValueOffset())
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if bytes.Equal(vc.RawValueOffset(), rawValueOffset) != true {
|
||||
t.Fatalf("RawValueOffset() not correct: %v", vc.RawValueOffset())
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if bytes.Equal(vc.AddressableData(), addressableData) != true {
|
||||
t.Fatalf("AddressableData() not correct: %v", vc.AddressableData())
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if vc.ByteOrder() != TestDefaultByteOrder {
|
||||
t.Fatalf("ByteOrder() not correct: %v", vc.ByteOrder())
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if vc.IfdPath() != "aa/bb" {
|
||||
t.Fatalf("IfdPath() not correct: [%s]", vc.IfdPath())
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if vc.TagId() != 0x1234 {
|
||||
t.Fatalf("TagId() not correct: (%d)", vc.TagId())
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if vc.isEmbedded() != true {
|
||||
t.Fatalf("isEmbedded() not correct: %v", vc.isEmbedded())
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if vc.isEmbedded() != false {
|
||||
t.Fatalf("isEmbedded() not correct: %v", vc.isEmbedded())
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_readRawEncoded__IsEmbedded(t *testing.T) {
|
||||
unitCount := uint32(4)
|
||||
|
||||
rawValueOffset := []byte{1, 2, 3, 4}
|
||||
|
||||
// Ignored, in this case.
|
||||
valueOffset := uint32(0)
|
||||
|
||||
addressableData := []byte{}
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder)
|
||||
|
||||
recovered, err := vc.readRawEncoded()
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Equal(recovered, rawValueOffset) != true {
|
||||
t.Fatalf("Embedded value bytes not recovered correctly: %v", recovered)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_readRawEncoded__IsRelative(t *testing.T) {
|
||||
unitCount := uint32(5)
|
||||
|
||||
// Ignored, in this case.
|
||||
rawValueOffset := []byte{0, 0, 0, 0}
|
||||
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{5, 6, 7, 8, 9}
|
||||
addressableData := []byte{1, 2, 3, 4}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder)
|
||||
|
||||
recovered, err := vc.readRawEncoded()
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Equal(recovered, data) != true {
|
||||
t.Fatalf("Relative value bytes not recovered correctly: %v", recovered)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Format__Byte(t *testing.T) {
|
||||
unitCount := uint32(8)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Format()
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != "61 62 63 64 65 66 67 68" {
|
||||
t.Fatalf("Format not correct for bytes: [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Format__Ascii(t *testing.T) {
|
||||
unitCount := uint32(8)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Format()
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != "abcdefg" {
|
||||
t.Fatalf("Format not correct for ASCII: [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Format__AsciiNoNul(t *testing.T) {
|
||||
unitCount := uint32(8)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAsciiNoNul, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Format()
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != "abcdefgh" {
|
||||
t.Fatalf("Format not correct for ASCII (no NUL): [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Format__Short(t *testing.T) {
|
||||
unitCount := uint32(4)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 1, 0, 2, 0, 3, 0, 4}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Format()
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != "[1 2 3 4]" {
|
||||
t.Fatalf("Format not correct for shorts: [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Format__Long(t *testing.T) {
|
||||
unitCount := uint32(2)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Format()
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != "[1 2]" {
|
||||
t.Fatalf("Format not correct for longs: [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Format__Rational(t *testing.T) {
|
||||
unitCount := uint32(2)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{
|
||||
0, 0, 0, 1, 0, 0, 0, 2,
|
||||
0, 0, 0, 3, 0, 0, 0, 4,
|
||||
}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeRational, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Format()
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != "[1/2 3/4]" {
|
||||
t.Fatalf("Format not correct for rationals: [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Format__SignedLong(t *testing.T) {
|
||||
unitCount := uint32(2)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedLong, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Format()
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != "[1 2]" {
|
||||
t.Fatalf("Format not correct for signed-longs: [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Format__SignedRational(t *testing.T) {
|
||||
unitCount := uint32(2)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{
|
||||
0, 0, 0, 1, 0, 0, 0, 2,
|
||||
0, 0, 0, 3, 0, 0, 0, 4,
|
||||
}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedRational, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Format()
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != "[1/2 3/4]" {
|
||||
t.Fatalf("Format not correct for signed-rationals: [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Format__Undefined__NoEffectiveType(t *testing.T) {
|
||||
defer func() {
|
||||
if errRaw := recover(); errRaw != nil {
|
||||
err := errRaw.(error)
|
||||
if err.Error() != "undefined-value type not set" {
|
||||
t.Fatalf("Error not expected: [%s]", err.Error())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
t.Fatalf("Expected error.")
|
||||
}()
|
||||
|
||||
unitCount := uint32(8)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Format()
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != "61 62 63 64 65 66 67 68" {
|
||||
t.Fatalf("Format not correct for bytes: [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Format__Undefined__HasEffectiveType(t *testing.T) {
|
||||
unitCount := uint32(8)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
|
||||
|
||||
vc.SetUndefinedValueType(TypeAscii)
|
||||
|
||||
value, err := vc.Format()
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != "abcdefg" {
|
||||
t.Fatalf("Format not correct for undefined (with effective type of string): [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_FormatFirst__Bytes(t *testing.T) {
|
||||
unitCount := uint32(8)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.FormatFirst()
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != "61 62 63 64 65 66 67 68" {
|
||||
t.Fatalf("FormatFirst not correct for bytes: [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_FormatFirst__String(t *testing.T) {
|
||||
unitCount := uint32(8)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.FormatFirst()
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != "abcdefg" {
|
||||
t.Fatalf("FormatFirst not correct for ASCII: [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_FormatFirst__List(t *testing.T) {
|
||||
unitCount := uint32(4)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 1, 0, 2, 0, 3, 0, 4}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.FormatFirst()
|
||||
log.PanicIf(err)
|
||||
|
||||
if value != "1..." {
|
||||
t.Fatalf("FormatFirst not correct for shorts: [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_ReadBytes(t *testing.T) {
|
||||
unitCount := uint32(8)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.ReadBytes()
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Equal(value, data) != true {
|
||||
t.Fatalf("ReadBytes not correct: %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_ReadAscii(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Test failure.")
|
||||
}
|
||||
}()
|
||||
unitCount := uint32(8)
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(testImageFilepath)
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.ReadAscii()
|
||||
log.PanicIf(err)
|
||||
|
||||
im := NewIfdMapping()
|
||||
|
||||
err = LoadStandardIfds(im)
|
||||
log.PanicIf(err)
|
||||
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(im, ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
ifd := index.RootIfd
|
||||
|
||||
var ite *IfdTagEntry
|
||||
for _, thisIte := range ifd.Entries {
|
||||
if thisIte.TagId == 0x0110 {
|
||||
ite = thisIte
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ite == nil {
|
||||
t.Fatalf("Tag not found.")
|
||||
}
|
||||
|
||||
valueContext := ifd.GetValueContext(ite)
|
||||
|
||||
decodedString, err := valueContext.ReadAscii()
|
||||
log.PanicIf(err)
|
||||
|
||||
decodedBytes := []byte(decodedString)
|
||||
|
||||
expected := []byte("Canon EOS 5D Mark III")
|
||||
|
||||
if bytes.Compare(decodedBytes, expected) != 0 {
|
||||
t.Fatalf("Decoded bytes not correct.")
|
||||
if value != "abcdefg" {
|
||||
t.Fatalf("ReadAscii not correct: [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Undefined(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Test failure.")
|
||||
}
|
||||
}()
|
||||
func TestValueContext_ReadAsciiNoNul(t *testing.T) {
|
||||
unitCount := uint32(8)
|
||||
|
||||
rawExif, err := SearchFileAndExtractExif(testImageFilepath)
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAsciiNoNul, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.ReadAsciiNoNul()
|
||||
log.PanicIf(err)
|
||||
|
||||
im := NewIfdMapping()
|
||||
|
||||
err = LoadStandardIfds(im)
|
||||
log.PanicIf(err)
|
||||
|
||||
ti := NewTagIndex()
|
||||
|
||||
_, index, err := Collect(im, ti, rawExif)
|
||||
log.PanicIf(err)
|
||||
|
||||
ifdExif := index.Lookup[IfdPathStandardExif][0]
|
||||
|
||||
var ite *IfdTagEntry
|
||||
for _, thisIte := range ifdExif.Entries {
|
||||
if thisIte.TagId == 0x9000 {
|
||||
ite = thisIte
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ite == nil {
|
||||
t.Fatalf("Tag not found.")
|
||||
}
|
||||
|
||||
valueContext := ifdExif.GetValueContext(ite)
|
||||
|
||||
value, err := valueContext.Undefined()
|
||||
log.PanicIf(err)
|
||||
|
||||
gs, ok := value.(TagUnknownType_GeneralString)
|
||||
if ok != true {
|
||||
t.Fatalf("Undefined value not processed correctly.")
|
||||
}
|
||||
|
||||
decodedBytes, err := gs.ValueBytes()
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := []byte("0230")
|
||||
|
||||
if bytes.Compare(decodedBytes, expected) != 0 {
|
||||
t.Fatalf("Decoded bytes not correct.")
|
||||
if value != "abcdefgh" {
|
||||
t.Fatalf("ReadAsciiNoNul not correct: [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_ReadShorts(t *testing.T) {
|
||||
unitCount := uint32(4)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 1, 0, 2, 0, 3, 0, 4}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.ReadShorts()
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []uint16{1, 2, 3, 4}) != true {
|
||||
t.Fatalf("ReadShorts not correct: %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_ReadLongs(t *testing.T) {
|
||||
unitCount := uint32(2)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.ReadLongs()
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []uint32{1, 2}) != true {
|
||||
t.Fatalf("ReadLongs not correct: %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_ReadRationals(t *testing.T) {
|
||||
unitCount := uint32(2)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{
|
||||
0, 0, 0, 1, 0, 0, 0, 2,
|
||||
0, 0, 0, 3, 0, 0, 0, 4,
|
||||
}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeRational, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.ReadRationals()
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := []Rational{
|
||||
Rational{Numerator: 1, Denominator: 2},
|
||||
Rational{Numerator: 3, Denominator: 4},
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(value, expected) != true {
|
||||
t.Fatalf("ReadRationals not correct: %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_ReadSignedLongs(t *testing.T) {
|
||||
unitCount := uint32(2)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedLong, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.ReadSignedLongs()
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []int32{1, 2}) != true {
|
||||
t.Fatalf("ReadSignedLongs not correct: %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_ReadSignedRationals(t *testing.T) {
|
||||
unitCount := uint32(2)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{
|
||||
0, 0, 0, 1, 0, 0, 0, 2,
|
||||
0, 0, 0, 3, 0, 0, 0, 4,
|
||||
}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedRational, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.ReadSignedRationals()
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := []SignedRational{
|
||||
SignedRational{Numerator: 1, Denominator: 2},
|
||||
SignedRational{Numerator: 3, Denominator: 4},
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(value, expected) != true {
|
||||
t.Fatalf("ReadSignedRationals not correct: %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Values__Byte(t *testing.T) {
|
||||
unitCount := uint32(8)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Values()
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, data) != true {
|
||||
t.Fatalf("Values not correct (bytes): %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Values__Ascii(t *testing.T) {
|
||||
unitCount := uint32(8)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Values()
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, "abcdefg") != true {
|
||||
t.Fatalf("Values not correct (ASCII): [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Values__AsciiNoNul(t *testing.T) {
|
||||
unitCount := uint32(8)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAsciiNoNul, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Values()
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, "abcdefgh") != true {
|
||||
t.Fatalf("Values not correct (ASCII no-NUL): [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Values__Short(t *testing.T) {
|
||||
unitCount := uint32(4)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 1, 0, 2, 0, 3, 0, 4}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Values()
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []uint16{1, 2, 3, 4}) != true {
|
||||
t.Fatalf("Values not correct (shorts): %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Values__Long(t *testing.T) {
|
||||
unitCount := uint32(2)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Values()
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []uint32{1, 2}) != true {
|
||||
t.Fatalf("Values not correct (longs): %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Values__Rational(t *testing.T) {
|
||||
unitCount := uint32(2)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{
|
||||
0, 0, 0, 1, 0, 0, 0, 2,
|
||||
0, 0, 0, 3, 0, 0, 0, 4,
|
||||
}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeRational, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Values()
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := []Rational{
|
||||
Rational{Numerator: 1, Denominator: 2},
|
||||
Rational{Numerator: 3, Denominator: 4},
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(value, expected) != true {
|
||||
t.Fatalf("Values not correct (rationals): %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Values__SignedLong(t *testing.T) {
|
||||
unitCount := uint32(2)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedLong, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Values()
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []int32{1, 2}) != true {
|
||||
t.Fatalf("Values not correct (signed longs): %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueContext_Values__SignedRational(t *testing.T) {
|
||||
unitCount := uint32(2)
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 4}
|
||||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{
|
||||
0, 0, 0, 1, 0, 0, 0, 2,
|
||||
0, 0, 0, 3, 0, 0, 0, 4,
|
||||
}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
addressableData = append(addressableData, data...)
|
||||
|
||||
vc := newValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedRational, TestDefaultByteOrder)
|
||||
|
||||
value, err := vc.Values()
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := []SignedRational{
|
||||
SignedRational{Numerator: 1, Denominator: 2},
|
||||
SignedRational{Numerator: 3, Denominator: 4},
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(value, expected) != true {
|
||||
t.Fatalf("Values not correct (signed rationals): %v", value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,22 +159,36 @@ func validateExifSimpleTestIb(exifData []byte, t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
// This will only be executed when we're running tests in this package and
|
||||
// not when this package is being imported from a subpackage.
|
||||
func getModuleRootPath() string {
|
||||
currentWd, err := os.Getwd()
|
||||
log.PanicIf(err)
|
||||
|
||||
goPath := os.Getenv("GOPATH")
|
||||
if goPath != "" {
|
||||
assetsPath = path.Join(goPath, "src", "github.com", "dsoprea", "go-exif", "assets")
|
||||
} else {
|
||||
// Module-enabled context.
|
||||
currentPath := currentWd
|
||||
|
||||
currentWd, err := os.Getwd()
|
||||
log.PanicIf(err)
|
||||
for {
|
||||
tryStampFilepath := path.Join(currentPath, ".MODULE_ROOT")
|
||||
|
||||
assetsPath = path.Join(currentWd, "assets")
|
||||
f, err := os.Open(tryStampFilepath)
|
||||
if err != nil && err != os.ErrNotExist {
|
||||
log.Panic(err)
|
||||
} else if err == nil {
|
||||
f.Close()
|
||||
break
|
||||
}
|
||||
|
||||
currentPath := path.Dir(currentPath)
|
||||
if currentPath == "/" {
|
||||
log.Panicf("could not find module-root")
|
||||
}
|
||||
}
|
||||
|
||||
return currentPath
|
||||
}
|
||||
|
||||
func init() {
|
||||
moduleRootPath := getModuleRootPath()
|
||||
assetsPath = path.Join(moduleRootPath, "assets")
|
||||
|
||||
testImageFilepath = path.Join(assetsPath, "NDM_8901.jpg")
|
||||
|
||||
// Load test EXIF data.
|
||||
|
|
397
v2/tag_type.go
397
v2/tag_type.go
|
@ -1,397 +0,0 @@
|
|||
package exif
|
||||
|
||||
// NOTE(dustin): Most of this file encapsulates deprecated functionality and awaits being dumped in a future release.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
type TagType struct {
|
||||
tagType TagTypePrimitive
|
||||
name string
|
||||
byteOrder binary.ByteOrder
|
||||
}
|
||||
|
||||
func NewTagType(tagType TagTypePrimitive, byteOrder binary.ByteOrder) TagType {
|
||||
name, found := TypeNames[tagType]
|
||||
if found == false {
|
||||
log.Panicf("tag-type not valid: 0x%04x", tagType)
|
||||
}
|
||||
|
||||
return TagType{
|
||||
tagType: tagType,
|
||||
name: name,
|
||||
byteOrder: byteOrder,
|
||||
}
|
||||
}
|
||||
|
||||
func (tt TagType) String() string {
|
||||
return fmt.Sprintf("TagType<NAME=[%s]>", tt.name)
|
||||
}
|
||||
|
||||
func (tt TagType) Name() string {
|
||||
return tt.name
|
||||
}
|
||||
|
||||
func (tt TagType) Type() TagTypePrimitive {
|
||||
return tt.tagType
|
||||
}
|
||||
|
||||
func (tt TagType) ByteOrder() binary.ByteOrder {
|
||||
return tt.byteOrder
|
||||
}
|
||||
|
||||
func (tt TagType) Size() int {
|
||||
|
||||
// DEPRECATED(dustin): `(TagTypePrimitive).Size()` should be used, directly.
|
||||
|
||||
return tt.Type().Size()
|
||||
}
|
||||
|
||||
// valueIsEmbedded will return a boolean indicating whether the value should be
|
||||
// found directly within the IFD entry or an offset to somewhere else.
|
||||
func (tt TagType) valueIsEmbedded(unitCount uint32) bool {
|
||||
return (tt.tagType.Size() * int(unitCount)) <= 4
|
||||
}
|
||||
|
||||
func (tt TagType) readRawEncoded(valueContext ValueContext) (rawBytes []byte, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
unitSizeRaw := uint32(tt.tagType.Size())
|
||||
|
||||
if tt.valueIsEmbedded(valueContext.UnitCount()) == true {
|
||||
byteLength := unitSizeRaw * valueContext.UnitCount()
|
||||
return valueContext.RawValueOffset()[:byteLength], nil
|
||||
} else {
|
||||
return valueContext.AddressableData()[valueContext.ValueOffset() : valueContext.ValueOffset()+valueContext.UnitCount()*unitSizeRaw], nil
|
||||
}
|
||||
}
|
||||
|
||||
func (tt TagType) ParseBytes(data []byte, unitCount uint32) (value []uint8, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(*Parser).ParseBytes()` should be used.
|
||||
|
||||
value, err = parser.ParseBytes(data, unitCount)
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// ParseAscii returns a string and auto-strips the trailing NUL character.
|
||||
func (tt TagType) ParseAscii(data []byte, unitCount uint32) (value string, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(*Parser).ParseAscii()` should be used.
|
||||
|
||||
value, err = parser.ParseAscii(data, unitCount)
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// ParseAsciiNoNul returns a string without any consideration for a trailing NUL
|
||||
// character.
|
||||
func (tt TagType) ParseAsciiNoNul(data []byte, unitCount uint32) (value string, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(*Parser).ParseAsciiNoNul()` should be used.
|
||||
|
||||
value, err = parser.ParseAsciiNoNul(data, unitCount)
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (tt TagType) ParseShorts(data []byte, unitCount uint32) (value []uint16, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(*Parser).ParseShorts()` should be used.
|
||||
|
||||
value, err = parser.ParseShorts(data, unitCount, tt.byteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (tt TagType) ParseLongs(data []byte, unitCount uint32) (value []uint32, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(*Parser).ParseLongs()` should be used.
|
||||
|
||||
value, err = parser.ParseLongs(data, unitCount, tt.byteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (tt TagType) ParseRationals(data []byte, unitCount uint32) (value []Rational, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(*Parser).ParseRationals()` should be used.
|
||||
|
||||
value, err = parser.ParseRationals(data, unitCount, tt.byteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (tt TagType) ParseSignedLongs(data []byte, unitCount uint32) (value []int32, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(*Parser).ParseSignedLongs()` should be used.
|
||||
|
||||
value, err = parser.ParseSignedLongs(data, unitCount, tt.byteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (tt TagType) ParseSignedRationals(data []byte, unitCount uint32) (value []SignedRational, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(*Parser).ParseSignedRationals()` should be used.
|
||||
|
||||
value, err = parser.ParseSignedRationals(data, unitCount, tt.byteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (tt TagType) ReadByteValues(valueContext ValueContext) (value []byte, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(ValueContext).ReadBytes()` should be used.
|
||||
|
||||
value, err = valueContext.ReadBytes()
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (tt TagType) ReadAsciiValue(valueContext ValueContext) (value string, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(ValueContext).ReadAscii()` should be used.
|
||||
|
||||
value, err = valueContext.ReadAscii()
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (tt TagType) ReadAsciiNoNulValue(valueContext ValueContext) (value string, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(ValueContext).ReadAsciiNoNul()` should be used.
|
||||
|
||||
value, err = valueContext.ReadAsciiNoNul()
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (tt TagType) ReadShortValues(valueContext ValueContext) (value []uint16, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(ValueContext).ReadShorts()` should be used.
|
||||
|
||||
value, err = valueContext.ReadShorts()
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (tt TagType) ReadLongValues(valueContext ValueContext) (value []uint32, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(ValueContext).ReadLongs()` should be used.
|
||||
|
||||
value, err = valueContext.ReadLongs()
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (tt TagType) ReadRationalValues(valueContext ValueContext) (value []Rational, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(ValueContext).ReadRationals()` should be used.
|
||||
|
||||
value, err = valueContext.ReadRationals()
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (tt TagType) ReadSignedLongValues(valueContext ValueContext) (value []int32, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(ValueContext).ReadSignedLongs()` should be used.
|
||||
|
||||
value, err = valueContext.ReadSignedLongs()
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (tt TagType) ReadSignedRationalValues(valueContext ValueContext) (value []SignedRational, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(ValueContext).ReadSignedRationals()` should be used.
|
||||
|
||||
value, err = valueContext.ReadSignedRationals()
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// ResolveAsString resolves the given value and returns a flat string.
|
||||
//
|
||||
// Where the type is not ASCII, `justFirst` indicates whether to just stringify
|
||||
// the first item in the slice (or return an empty string if the slice is
|
||||
// empty).
|
||||
//
|
||||
// Since this method lacks the information to process unknown-type tags (e.g.
|
||||
// byte-order, tag-ID, IFD type), it will return an error if attempted. See
|
||||
// `Undefined()`.
|
||||
func (tt TagType) ResolveAsString(valueContext ValueContext, justFirst bool) (value string, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
if justFirst == true {
|
||||
value, err = valueContext.FormatFirst()
|
||||
log.PanicIf(err)
|
||||
} else {
|
||||
value, err = valueContext.Format()
|
||||
log.PanicIf(err)
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// Resolve knows how to resolve the given value.
|
||||
//
|
||||
// Since this method lacks the information to process unknown-type tags (e.g.
|
||||
// byte-order, tag-ID, IFD type), it will return an error if attempted. See
|
||||
// `Undefined()`.
|
||||
func (tt TagType) Resolve(valueContext *ValueContext) (values interface{}, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `(ValueContext).Values()` should be used.
|
||||
|
||||
values, err = valueContext.Values()
|
||||
log.PanicIf(err)
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// Encode knows how to encode the given value to a byte slice.
|
||||
func (tt TagType) Encode(value interface{}) (encoded []byte, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
ve := NewValueEncoder(tt.byteOrder)
|
||||
|
||||
ed, err := ve.EncodeWithType(tt, value)
|
||||
log.PanicIf(err)
|
||||
|
||||
return ed.Encoded, err
|
||||
}
|
||||
|
||||
func (tt TagType) FromString(valueString string) (value interface{}, err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
}
|
||||
}()
|
||||
|
||||
// DEPRECATED(dustin): `EncodeStringToBytes()` should be used.
|
||||
|
||||
value, err = EncodeStringToBytes(tt.tagType, valueString)
|
||||
log.PanicIf(err)
|
||||
|
||||
return value, nil
|
||||
}
|
|
@ -1,297 +0,0 @@
|
|||
package exifcommon
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
)
|
||||
|
||||
func TestTagType_EncodeDecode_Byte(t *testing.T) {
|
||||
tt := NewTagType(TypeByte, TestDefaultByteOrder)
|
||||
|
||||
data := []byte{0x11, 0x22, 0x33, 0x44, 0x55}
|
||||
|
||||
encoded, err := tt.Encode(data)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(encoded, data) != 0 {
|
||||
t.Fatalf("Data not encoded correctly.")
|
||||
}
|
||||
|
||||
restored, err := tt.ParseBytes(encoded, uint32(len(data)))
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(restored, data) != 0 {
|
||||
t.Fatalf("Data not decoded correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_EncodeDecode_Ascii(t *testing.T) {
|
||||
tt := NewTagType(TypeAscii, TestDefaultByteOrder)
|
||||
|
||||
data := "hello"
|
||||
|
||||
encoded, err := tt.Encode(data)
|
||||
log.PanicIf(err)
|
||||
|
||||
if string(encoded) != fmt.Sprintf("%s\000", data) {
|
||||
t.Fatalf("Data not encoded correctly.")
|
||||
}
|
||||
|
||||
restored, err := tt.ParseAscii(encoded, uint32(len(data)))
|
||||
log.PanicIf(err)
|
||||
|
||||
if restored != data {
|
||||
t.Fatalf("Data not decoded correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_EncodeDecode_Shorts(t *testing.T) {
|
||||
tt := NewTagType(TypeShort, TestDefaultByteOrder)
|
||||
|
||||
data := []uint16{0x11, 0x22, 0x33}
|
||||
|
||||
encoded, err := tt.Encode(data)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(encoded, []byte{0x00, 0x11, 0x00, 0x22, 0x00, 0x33}) != 0 {
|
||||
t.Fatalf("Data not encoded correctly.")
|
||||
}
|
||||
|
||||
restored, err := tt.ParseShorts(encoded, uint32(len(data)))
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(restored, data) != true {
|
||||
t.Fatalf("Data not decoded correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_EncodeDecode_Long(t *testing.T) {
|
||||
tt := NewTagType(TypeLong, TestDefaultByteOrder)
|
||||
|
||||
data := []uint32{0x11, 0x22, 0x33}
|
||||
|
||||
encoded, err := tt.Encode(data)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(encoded, []byte{0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x33}) != 0 {
|
||||
t.Fatalf("Data not encoded correctly.")
|
||||
}
|
||||
|
||||
restored, err := tt.ParseLongs(encoded, uint32(len(data)))
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(restored, data) != true {
|
||||
t.Fatalf("Data not decoded correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_EncodeDecode_Rational(t *testing.T) {
|
||||
tt := NewTagType(TypeRational, TestDefaultByteOrder)
|
||||
|
||||
data := []Rational{
|
||||
Rational{Numerator: 0x11, Denominator: 0x22},
|
||||
Rational{Numerator: 0x33, Denominator: 0x44},
|
||||
}
|
||||
|
||||
encoded, err := tt.Encode(data)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(encoded, []byte{0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x44}) != 0 {
|
||||
t.Fatalf("Data not encoded correctly.")
|
||||
}
|
||||
|
||||
restored, err := tt.ParseRationals(encoded, uint32(len(data)))
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(restored, data) != true {
|
||||
t.Fatalf("Data not decoded correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_EncodeDecode_SignedLong(t *testing.T) {
|
||||
tt := NewTagType(TypeSignedLong, TestDefaultByteOrder)
|
||||
|
||||
data := []int32{0x11, 0x22, 0x33}
|
||||
|
||||
encoded, err := tt.Encode(data)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(encoded, []byte{0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x33}) != 0 {
|
||||
t.Fatalf("Data not encoded correctly.")
|
||||
}
|
||||
|
||||
restored, err := tt.ParseSignedLongs(encoded, uint32(len(data)))
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(restored, data) != true {
|
||||
t.Fatalf("Data not decoded correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_EncodeDecode_SignedRational(t *testing.T) {
|
||||
tt := NewTagType(TypeSignedRational, TestDefaultByteOrder)
|
||||
|
||||
data := []SignedRational{
|
||||
SignedRational{Numerator: 0x11, Denominator: 0x22},
|
||||
SignedRational{Numerator: 0x33, Denominator: 0x44},
|
||||
}
|
||||
|
||||
encoded, err := tt.Encode(data)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Compare(encoded, []byte{0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x44}) != 0 {
|
||||
t.Fatalf("Data not encoded correctly.")
|
||||
}
|
||||
|
||||
restored, err := tt.ParseSignedRationals(encoded, uint32(len(data)))
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(restored, data) != true {
|
||||
t.Fatalf("Data not decoded correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_EncodeDecode_AsciiNoNul(t *testing.T) {
|
||||
tt := NewTagType(TypeAsciiNoNul, TestDefaultByteOrder)
|
||||
|
||||
data := "hello"
|
||||
|
||||
encoded, err := tt.Encode(data)
|
||||
log.PanicIf(err)
|
||||
|
||||
if string(encoded) != data {
|
||||
t.Fatalf("Data not encoded correctly.")
|
||||
}
|
||||
|
||||
restored, err := tt.ParseAsciiNoNul(encoded, uint32(len(data)))
|
||||
log.PanicIf(err)
|
||||
|
||||
if restored != data {
|
||||
t.Fatalf("Data not decoded correctly.")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(dustin): Add tests for TypeUndefined.
|
||||
|
||||
func TestTagType_FromString_Undefined(t *testing.T) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err := log.Wrap(state.(error))
|
||||
log.PrintErrorf(err, "Test failure.")
|
||||
|
||||
log.Panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
tt := NewTagType(TypeUndefined, TestDefaultByteOrder)
|
||||
|
||||
_, err := tt.FromString("")
|
||||
if err == nil {
|
||||
t.Fatalf("no error for undefined-type")
|
||||
} else if err.Error() != "undefined-type values are not supported" {
|
||||
fmt.Printf("[%s]\n", err.Error())
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_FromString_Byte(t *testing.T) {
|
||||
tt := NewTagType(TypeByte, TestDefaultByteOrder)
|
||||
|
||||
value, err := tt.FromString("abc")
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, []byte{'a', 'b', 'c'}) != true {
|
||||
t.Fatalf("byte value not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_FromString_Ascii(t *testing.T) {
|
||||
tt := NewTagType(TypeAscii, TestDefaultByteOrder)
|
||||
|
||||
value, err := tt.FromString("abc")
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, "abc") != true {
|
||||
t.Fatalf("ASCII value not correct: [%s]", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_FromString_Short(t *testing.T) {
|
||||
tt := NewTagType(TypeShort, TestDefaultByteOrder)
|
||||
|
||||
value, err := tt.FromString("55")
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, uint16(55)) != true {
|
||||
t.Fatalf("short value not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_FromString_Long(t *testing.T) {
|
||||
tt := NewTagType(TypeLong, TestDefaultByteOrder)
|
||||
|
||||
value, err := tt.FromString("66000")
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, uint32(66000)) != true {
|
||||
t.Fatalf("long value not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_FromString_Rational(t *testing.T) {
|
||||
tt := NewTagType(TypeRational, TestDefaultByteOrder)
|
||||
|
||||
value, err := tt.FromString("12/34")
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := Rational{
|
||||
Numerator: 12,
|
||||
Denominator: 34,
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(value, expected) != true {
|
||||
t.Fatalf("rational value not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_FromString_SignedLong(t *testing.T) {
|
||||
tt := NewTagType(TypeSignedLong, TestDefaultByteOrder)
|
||||
|
||||
value, err := tt.FromString("-66000")
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, int32(-66000)) != true {
|
||||
t.Fatalf("signed-long value not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_FromString_SignedRational(t *testing.T) {
|
||||
tt := NewTagType(TypeSignedRational, TestDefaultByteOrder)
|
||||
|
||||
value, err := tt.FromString("-12/34")
|
||||
log.PanicIf(err)
|
||||
|
||||
expected := SignedRational{
|
||||
Numerator: -12,
|
||||
Denominator: 34,
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(value, expected) != true {
|
||||
t.Fatalf("signd-rational value not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagType_FromString_AsciiNoNul(t *testing.T) {
|
||||
tt := NewTagType(TypeAsciiNoNul, TestDefaultByteOrder)
|
||||
|
||||
value, err := tt.FromString("abc")
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, "abc") != true {
|
||||
t.Fatalf("ASCII-no-nul value not correct")
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ func (Codec8828Oecf) Decode(valueContext *exifcommon.ValueContext) (value interf
|
|||
|
||||
// TODO(dustin): Add test using known good data.
|
||||
|
||||
valueContext.SetUnknownValueType(exifcommon.TypeByte)
|
||||
valueContext.SetUndefinedValueType(exifcommon.TypeByte)
|
||||
|
||||
valueBytes, err := valueContext.ReadBytes()
|
||||
log.PanicIf(err)
|
||||
|
|
|
@ -16,7 +16,7 @@ func (Codec9000ExifVersion) Decode(valueContext *exifcommon.ValueContext) (value
|
|||
}
|
||||
}()
|
||||
|
||||
valueContext.SetUnknownValueType(exifcommon.TypeAsciiNoNul)
|
||||
valueContext.SetUndefinedValueType(exifcommon.TypeAsciiNoNul)
|
||||
|
||||
valueString, err := valueContext.ReadAsciiNoNul()
|
||||
log.PanicIf(err)
|
||||
|
|
|
@ -86,7 +86,7 @@ func (CodecExif9101ComponentsConfiguration) Decode(valueContext *exifcommon.Valu
|
|||
}
|
||||
}()
|
||||
|
||||
valueContext.SetUnknownValueType(exifcommon.TypeByte)
|
||||
valueContext.SetUndefinedValueType(exifcommon.TypeByte)
|
||||
|
||||
valueBytes, err := valueContext.ReadBytes()
|
||||
log.PanicIf(err)
|
||||
|
|
|
@ -64,7 +64,7 @@ func (Codec927CMakerNote) Decode(valueContext *exifcommon.ValueContext) (value i
|
|||
// TODO(dustin): !! This is the Wild Wild West. This very well might be a child IFD, but any and all OEM's define their own formats. If we're going to be writing changes and this is complete EXIF (which may not have the first eight bytes), it might be fine. However, if these are just IFDs they'll be relative to the main EXIF, this will invalidate the MakerNote data for IFDs and any other implementations that use offsets unless we can interpret them all. It be best to return to this later and just exclude this from being written for now, though means a loss of a wealth of image metadata.
|
||||
// -> We can also just blindly try to interpret as an IFD and just validate that it's looks good (maybe it will even have a 'next ifd' pointer that we can validate is 0x0).
|
||||
|
||||
valueContext.SetUnknownValueType(exifcommon.TypeByte)
|
||||
valueContext.SetUndefinedValueType(exifcommon.TypeByte)
|
||||
|
||||
valueBytes, err := valueContext.ReadBytes()
|
||||
log.PanicIf(err)
|
||||
|
|
|
@ -92,7 +92,7 @@ func (Codec9286UserComment) Decode(valueContext *exifcommon.ValueContext) (value
|
|||
}
|
||||
}()
|
||||
|
||||
valueContext.SetUnknownValueType(exifcommon.TypeByte)
|
||||
valueContext.SetUndefinedValueType(exifcommon.TypeByte)
|
||||
|
||||
valueBytes, err := valueContext.ReadBytes()
|
||||
log.PanicIf(err)
|
||||
|
|
|
@ -16,7 +16,7 @@ func (CodecA000FlashpixVersion) Decode(valueContext *exifcommon.ValueContext) (v
|
|||
}
|
||||
}()
|
||||
|
||||
valueContext.SetUnknownValueType(exifcommon.TypeAsciiNoNul)
|
||||
valueContext.SetUndefinedValueType(exifcommon.TypeAsciiNoNul)
|
||||
|
||||
valueString, err := valueContext.ReadAsciiNoNul()
|
||||
log.PanicIf(err)
|
||||
|
|
|
@ -80,7 +80,7 @@ func (CodecA20CSpatialFrequencyResponse) Decode(valueContext *exifcommon.ValueCo
|
|||
|
||||
byteOrder := valueContext.ByteOrder()
|
||||
|
||||
valueContext.SetUnknownValueType(exifcommon.TypeByte)
|
||||
valueContext.SetUndefinedValueType(exifcommon.TypeByte)
|
||||
|
||||
valueBytes, err := valueContext.ReadBytes()
|
||||
log.PanicIf(err)
|
||||
|
|
|
@ -49,7 +49,7 @@ func (CodecExifA300FileSource) Decode(valueContext *exifcommon.ValueContext) (va
|
|||
}
|
||||
}()
|
||||
|
||||
valueContext.SetUnknownValueType(exifcommon.TypeLong)
|
||||
valueContext.SetUndefinedValueType(exifcommon.TypeLong)
|
||||
|
||||
valueLongs, err := valueContext.ReadLongs()
|
||||
log.PanicIf(err)
|
||||
|
|
|
@ -46,7 +46,7 @@ func (CodecExifA301SceneType) Decode(valueContext *exifcommon.ValueContext) (val
|
|||
}
|
||||
}()
|
||||
|
||||
valueContext.SetUnknownValueType(exifcommon.TypeLong)
|
||||
valueContext.SetUndefinedValueType(exifcommon.TypeLong)
|
||||
|
||||
valueLongs, err := valueContext.ReadLongs()
|
||||
log.PanicIf(err)
|
||||
|
|
|
@ -60,7 +60,7 @@ func (CodecA302CfaPattern) Decode(valueContext *exifcommon.ValueContext) (value
|
|||
|
||||
// TODO(dustin): Add test using known good data.
|
||||
|
||||
valueContext.SetUnknownValueType(exifcommon.TypeByte)
|
||||
valueContext.SetUndefinedValueType(exifcommon.TypeByte)
|
||||
|
||||
valueBytes, err := valueContext.ReadBytes()
|
||||
log.PanicIf(err)
|
||||
|
|
|
@ -16,7 +16,7 @@ func (Codec0002InteropVersion) Decode(valueContext *exifcommon.ValueContext) (va
|
|||
}
|
||||
}()
|
||||
|
||||
valueContext.SetUnknownValueType(exifcommon.TypeAsciiNoNul)
|
||||
valueContext.SetUndefinedValueType(exifcommon.TypeAsciiNoNul)
|
||||
|
||||
valueString, err := valueContext.ReadAsciiNoNul()
|
||||
log.PanicIf(err)
|
||||
|
|
|
@ -16,7 +16,7 @@ func (Codec001BGPSProcessingMethod) Decode(valueContext *exifcommon.ValueContext
|
|||
}
|
||||
}()
|
||||
|
||||
valueContext.SetUnknownValueType(exifcommon.TypeAsciiNoNul)
|
||||
valueContext.SetUndefinedValueType(exifcommon.TypeAsciiNoNul)
|
||||
|
||||
valueString, err := valueContext.ReadAsciiNoNul()
|
||||
log.PanicIf(err)
|
||||
|
|
|
@ -16,7 +16,7 @@ func (Codec001CGPSAreaInformation) Decode(valueContext *exifcommon.ValueContext)
|
|||
}
|
||||
}()
|
||||
|
||||
valueContext.SetUnknownValueType(exifcommon.TypeAsciiNoNul)
|
||||
valueContext.SetUndefinedValueType(exifcommon.TypeAsciiNoNul)
|
||||
|
||||
valueString, err := valueContext.ReadAsciiNoNul()
|
||||
log.PanicIf(err)
|
||||
|
|
Loading…
Reference in New Issue