Use encapsulated data/reader rather than bytes

Given a stream of data, it is possible to determine the beginning of
EXIF data but not the end. Therefore, either an image-aware
implementation must know how to parse an image and extract the EXIF
data or a brute-force search implementation (one of which is provided
by this project) must find the start anchor and then return all bytes
from that to the end of the file.

We have been made aware of some use-cases where a brute-force search
might be unavoidable due to trust or stability issues with the image
structure. This leads to large allocations. This can be avoided by
accomodating support that will allow for both a byte-slice or an
`io.ReadSeeker`. Since the EXIF structure is typically not read-
intensive (a couple of kilobytes if no thumbnail is present), this
should have a minimal performance impact.

Closes #42
This commit is contained in:
Dustin Oprea 2020-07-08 04:01:09 -04:00
parent 56058635d0
commit 312218d7b1
17 changed files with 633 additions and 121 deletions

View File

@ -2,6 +2,7 @@ package exifcommon
import ( import (
"errors" "errors"
"io"
"encoding/binary" "encoding/binary"
@ -24,7 +25,7 @@ type ValueContext struct {
unitCount uint32 unitCount uint32
valueOffset uint32 valueOffset uint32
rawValueOffset []byte rawValueOffset []byte
addressableData []byte rs io.ReadSeeker
tagType TagTypePrimitive tagType TagTypePrimitive
byteOrder binary.ByteOrder byteOrder binary.ByteOrder
@ -40,12 +41,12 @@ type ValueContext struct {
// TODO(dustin): We can update newValueContext() to derive `valueOffset` itself (from `rawValueOffset`). // TODO(dustin): We can update newValueContext() to derive `valueOffset` itself (from `rawValueOffset`).
// NewValueContext returns a new ValueContext struct. // NewValueContext returns a new ValueContext struct.
func NewValueContext(ifdPath string, tagId uint16, unitCount, valueOffset uint32, rawValueOffset, addressableData []byte, tagType TagTypePrimitive, byteOrder binary.ByteOrder) *ValueContext { func NewValueContext(ifdPath string, tagId uint16, unitCount, valueOffset uint32, rawValueOffset []byte, rs io.ReadSeeker, tagType TagTypePrimitive, byteOrder binary.ByteOrder) *ValueContext {
return &ValueContext{ return &ValueContext{
unitCount: unitCount, unitCount: unitCount,
valueOffset: valueOffset, valueOffset: valueOffset,
rawValueOffset: rawValueOffset, rawValueOffset: rawValueOffset,
addressableData: addressableData, rs: rs,
tagType: tagType, tagType: tagType,
byteOrder: byteOrder, byteOrder: byteOrder,
@ -82,8 +83,11 @@ func (vc *ValueContext) RawValueOffset() []byte {
} }
// AddressableData returns the block of data that we can dereference into. // AddressableData returns the block of data that we can dereference into.
func (vc *ValueContext) AddressableData() []byte { func (vc *ValueContext) AddressableData() io.ReadSeeker {
return vc.addressableData
// RELEASE)dustin): Rename from AddressableData() to ReadSeeker()
return vc.rs
} }
// ByteOrder returns the byte-order of numbers. // ByteOrder returns the byte-order of numbers.
@ -152,7 +156,15 @@ func (vc *ValueContext) readRawEncoded() (rawBytes []byte, err error) {
return vc.rawValueOffset[:byteLength], nil return vc.rawValueOffset[:byteLength], nil
} }
return vc.addressableData[vc.valueOffset : vc.valueOffset+vc.unitCount*unitSizeRaw], nil _, err = vc.rs.Seek(int64(vc.valueOffset), io.SeekStart)
log.PanicIf(err)
rawBytes = make([]byte, vc.unitCount*unitSizeRaw)
_, err = io.ReadFull(vc.rs, rawBytes)
log.PanicIf(err)
return rawBytes, nil
} }
// GetFarOffset returns the offset if the value is not embedded [within the // GetFarOffset returns the offset if the value is not embedded [within the

View File

@ -5,13 +5,26 @@ import (
"reflect" "reflect"
"testing" "testing"
"io/ioutil"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-utility/filesystem"
) )
func TestNewValueContext(t *testing.T) { func TestNewValueContext(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder) sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
11,
22,
rawValueOffset,
sb,
TypeLong,
TestDefaultByteOrder)
if vc.ifdPath != "aa/bb" { if vc.ifdPath != "aa/bb" {
t.Fatalf("ifdPath not correct: [%s]", vc.ifdPath) t.Fatalf("ifdPath not correct: [%s]", vc.ifdPath)
@ -23,13 +36,18 @@ func TestNewValueContext(t *testing.T) {
t.Fatalf("valueOffset not correct: (%d)", vc.valueOffset) t.Fatalf("valueOffset not correct: (%d)", vc.valueOffset)
} else if bytes.Equal(vc.rawValueOffset, rawValueOffset) != true { } else if bytes.Equal(vc.rawValueOffset, rawValueOffset) != true {
t.Fatalf("rawValueOffset not correct: %v", vc.rawValueOffset) 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 { } else if vc.tagType != TypeLong {
t.Fatalf("tagType not correct: (%d)", vc.tagType) t.Fatalf("tagType not correct: (%d)", vc.tagType)
} else if vc.byteOrder != TestDefaultByteOrder { } else if vc.byteOrder != TestDefaultByteOrder {
t.Fatalf("byteOrder not correct: %v", vc.byteOrder) t.Fatalf("byteOrder not correct: %v", vc.byteOrder)
} }
recoveredBytes, err := ioutil.ReadAll(vc.AddressableData())
log.PanicIf(err)
if bytes.Equal(recoveredBytes, addressableData) != true {
t.Fatalf("AddressableData() not correct: %v", recoveredBytes)
}
} }
func TestValueContext_SetUndefinedValueType__ErrorWhenNotUndefined(t *testing.T) { func TestValueContext_SetUndefinedValueType__ErrorWhenNotUndefined(t *testing.T) {
@ -47,16 +65,38 @@ func TestValueContext_SetUndefinedValueType__ErrorWhenNotUndefined(t *testing.T)
}() }()
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder) sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
11,
22,
rawValueOffset,
sb,
TypeLong,
TestDefaultByteOrder)
vc.SetUndefinedValueType(TypeLong) vc.SetUndefinedValueType(TypeLong)
} }
func TestValueContext_SetUndefinedValueType__Ok(t *testing.T) { func TestValueContext_SetUndefinedValueType__Ok(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
11,
22,
rawValueOffset,
sb,
TypeUndefined,
TestDefaultByteOrder)
vc.SetUndefinedValueType(TypeLong) vc.SetUndefinedValueType(TypeLong)
@ -71,8 +111,19 @@ func TestValueContext_SetUndefinedValueType__Ok(t *testing.T) {
func TestValueContext_effectiveValueType(t *testing.T) { func TestValueContext_effectiveValueType(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
11,
22,
rawValueOffset,
sb,
TypeUndefined,
TestDefaultByteOrder)
vc.SetUndefinedValueType(TypeLong) vc.SetUndefinedValueType(TypeLong)
@ -87,8 +138,19 @@ func TestValueContext_effectiveValueType(t *testing.T) {
func TestValueContext_UnitCount(t *testing.T) { func TestValueContext_UnitCount(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
11,
22,
rawValueOffset,
sb,
TypeUndefined,
TestDefaultByteOrder)
if vc.UnitCount() != 11 { if vc.UnitCount() != 11 {
t.Fatalf("UnitCount() not correct: (%d)", vc.UnitCount()) t.Fatalf("UnitCount() not correct: (%d)", vc.UnitCount())
@ -97,8 +159,19 @@ func TestValueContext_UnitCount(t *testing.T) {
func TestValueContext_ValueOffset(t *testing.T) { func TestValueContext_ValueOffset(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
11,
22,
rawValueOffset,
sb,
TypeUndefined,
TestDefaultByteOrder)
if vc.ValueOffset() != 22 { if vc.ValueOffset() != 22 {
t.Fatalf("ValueOffset() not correct: (%d)", vc.ValueOffset()) t.Fatalf("ValueOffset() not correct: (%d)", vc.ValueOffset())
@ -107,8 +180,19 @@ func TestValueContext_ValueOffset(t *testing.T) {
func TestValueContext_RawValueOffset(t *testing.T) { func TestValueContext_RawValueOffset(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
11,
22,
rawValueOffset,
sb,
TypeUndefined,
TestDefaultByteOrder)
if bytes.Equal(vc.RawValueOffset(), rawValueOffset) != true { if bytes.Equal(vc.RawValueOffset(), rawValueOffset) != true {
t.Fatalf("RawValueOffset() not correct: %v", vc.RawValueOffset()) t.Fatalf("RawValueOffset() not correct: %v", vc.RawValueOffset())
@ -117,18 +201,43 @@ func TestValueContext_RawValueOffset(t *testing.T) {
func TestValueContext_AddressableData(t *testing.T) { func TestValueContext_AddressableData(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4}
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
if bytes.Equal(vc.AddressableData(), addressableData) != true { addressableData := []byte{1, 2, 3, 4}
t.Fatalf("AddressableData() not correct: %v", vc.AddressableData()) sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
11,
22,
rawValueOffset,
sb,
TypeUndefined,
TestDefaultByteOrder)
recoveredBytes, err := ioutil.ReadAll(vc.AddressableData())
log.PanicIf(err)
if bytes.Equal(recoveredBytes, addressableData) != true {
t.Fatalf("AddressableData() not correct: %v", recoveredBytes)
} }
} }
func TestValueContext_ByteOrder(t *testing.T) { func TestValueContext_ByteOrder(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
11,
22,
rawValueOffset,
sb,
TypeUndefined,
TestDefaultByteOrder)
if vc.ByteOrder() != TestDefaultByteOrder { if vc.ByteOrder() != TestDefaultByteOrder {
t.Fatalf("ByteOrder() not correct: %v", vc.ByteOrder()) t.Fatalf("ByteOrder() not correct: %v", vc.ByteOrder())
@ -137,8 +246,19 @@ func TestValueContext_ByteOrder(t *testing.T) {
func TestValueContext_IfdPath(t *testing.T) { func TestValueContext_IfdPath(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
11,
22,
rawValueOffset,
sb,
TypeUndefined,
TestDefaultByteOrder)
if vc.IfdPath() != "aa/bb" { if vc.IfdPath() != "aa/bb" {
t.Fatalf("IfdPath() not correct: [%s]", vc.IfdPath()) t.Fatalf("IfdPath() not correct: [%s]", vc.IfdPath())
@ -147,8 +267,19 @@ func TestValueContext_IfdPath(t *testing.T) {
func TestValueContext_TagId(t *testing.T) { func TestValueContext_TagId(t *testing.T) {
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
11,
22,
rawValueOffset,
sb,
TypeUndefined,
TestDefaultByteOrder)
if vc.TagId() != 0x1234 { if vc.TagId() != 0x1234 {
t.Fatalf("TagId() not correct: (%d)", vc.TagId()) t.Fatalf("TagId() not correct: (%d)", vc.TagId())
@ -158,8 +289,19 @@ func TestValueContext_TagId(t *testing.T) {
func TestValueContext_isEmbedded__True(t *testing.T) { func TestValueContext_isEmbedded__True(t *testing.T) {
unitCount := uint32(4) unitCount := uint32(4)
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := NewValueContext("aa/bb", 0x1234, unitCount, 22, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
22,
rawValueOffset,
sb,
TypeByte,
TestDefaultByteOrder)
if vc.isEmbedded() != true { if vc.isEmbedded() != true {
t.Fatalf("isEmbedded() not correct: %v", vc.isEmbedded()) t.Fatalf("isEmbedded() not correct: %v", vc.isEmbedded())
@ -169,8 +311,19 @@ func TestValueContext_isEmbedded__True(t *testing.T) {
func TestValueContext_isEmbedded__False(t *testing.T) { func TestValueContext_isEmbedded__False(t *testing.T) {
unitCount := uint32(5) unitCount := uint32(5)
rawValueOffset := []byte{0, 0, 0, 22} rawValueOffset := []byte{0, 0, 0, 22}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
vc := NewValueContext("aa/bb", 0x1234, unitCount, 22, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
22,
rawValueOffset,
sb,
TypeByte,
TestDefaultByteOrder)
if vc.isEmbedded() != false { if vc.isEmbedded() != false {
t.Fatalf("isEmbedded() not correct: %v", vc.isEmbedded()) t.Fatalf("isEmbedded() not correct: %v", vc.isEmbedded())
@ -186,7 +339,17 @@ func TestValueContext_readRawEncoded__IsEmbedded(t *testing.T) {
valueOffset := uint32(0) valueOffset := uint32(0)
addressableData := []byte{} addressableData := []byte{}
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeByte,
TestDefaultByteOrder)
recovered, err := vc.readRawEncoded() recovered, err := vc.readRawEncoded()
log.PanicIf(err) log.PanicIf(err)
@ -205,10 +368,20 @@ func TestValueContext_readRawEncoded__IsRelative(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{5, 6, 7, 8, 9} data := []byte{5, 6, 7, 8, 9}
addressableData := []byte{1, 2, 3, 4} addressableData := []byte{1, 2, 3, 4}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeByte,
TestDefaultByteOrder)
recovered, err := vc.readRawEncoded() recovered, err := vc.readRawEncoded()
log.PanicIf(err) log.PanicIf(err)
@ -225,10 +398,20 @@ func TestValueContext_Format__Byte(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'} data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeByte,
TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -245,10 +428,20 @@ func TestValueContext_Format__Ascii(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0} data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeAscii,
TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -265,10 +458,20 @@ func TestValueContext_Format__AsciiNoNul(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'} data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAsciiNoNul, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeAsciiNoNul,
TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -285,10 +488,20 @@ func TestValueContext_Format__Short(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{0, 1, 0, 2, 0, 3, 0, 4} data := []byte{0, 1, 0, 2, 0, 3, 0, 4}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeShort,
TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -305,10 +518,20 @@ func TestValueContext_Format__Long(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{0, 0, 0, 1, 0, 0, 0, 2} data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeLong,
TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -331,8 +554,17 @@ func TestValueContext_Format__Rational(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeRational, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeRational,
TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -349,10 +581,20 @@ func TestValueContext_Format__SignedLong(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{0, 0, 0, 1, 0, 0, 0, 2} data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedLong, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeSignedLong,
TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -375,8 +617,17 @@ func TestValueContext_Format__SignedRational(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedRational, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeSignedRational,
TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -406,10 +657,20 @@ func TestValueContext_Format__Undefined__NoEffectiveType(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'} data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeUndefined,
TestDefaultByteOrder)
value, err := vc.Format() value, err := vc.Format()
log.PanicIf(err) log.PanicIf(err)
@ -426,10 +687,20 @@ func TestValueContext_Format__Undefined__HasEffectiveType(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0} data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeUndefined,
TestDefaultByteOrder)
vc.SetUndefinedValueType(TypeAscii) vc.SetUndefinedValueType(TypeAscii)
@ -448,10 +719,20 @@ func TestValueContext_FormatFirst__Bytes(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'} data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeByte,
TestDefaultByteOrder)
value, err := vc.FormatFirst() value, err := vc.FormatFirst()
log.PanicIf(err) log.PanicIf(err)
@ -468,10 +749,20 @@ func TestValueContext_FormatFirst__String(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0} data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeAscii,
TestDefaultByteOrder)
value, err := vc.FormatFirst() value, err := vc.FormatFirst()
log.PanicIf(err) log.PanicIf(err)
@ -488,10 +779,20 @@ func TestValueContext_FormatFirst__List(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{0, 1, 0, 2, 0, 3, 0, 4} data := []byte{0, 1, 0, 2, 0, 3, 0, 4}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeShort,
TestDefaultByteOrder)
value, err := vc.FormatFirst() value, err := vc.FormatFirst()
log.PanicIf(err) log.PanicIf(err)
@ -510,8 +811,17 @@ func TestValueContext_ReadBytes(t *testing.T) {
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'} data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeByte,
TestDefaultByteOrder)
value, err := vc.ReadBytes() value, err := vc.ReadBytes()
log.PanicIf(err) log.PanicIf(err)
@ -528,10 +838,20 @@ func TestValueContext_ReadAscii(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0} data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeAscii,
TestDefaultByteOrder)
value, err := vc.ReadAscii() value, err := vc.ReadAscii()
log.PanicIf(err) log.PanicIf(err)
@ -550,8 +870,17 @@ func TestValueContext_ReadAsciiNoNul(t *testing.T) {
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'} data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAsciiNoNul, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeAsciiNoNul,
TestDefaultByteOrder)
value, err := vc.ReadAsciiNoNul() value, err := vc.ReadAsciiNoNul()
log.PanicIf(err) log.PanicIf(err)
@ -568,10 +897,20 @@ func TestValueContext_ReadShorts(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{0, 1, 0, 2, 0, 3, 0, 4} data := []byte{0, 1, 0, 2, 0, 3, 0, 4}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeShort,
TestDefaultByteOrder)
value, err := vc.ReadShorts() value, err := vc.ReadShorts()
log.PanicIf(err) log.PanicIf(err)
@ -588,10 +927,20 @@ func TestValueContext_ReadLongs(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{0, 0, 0, 1, 0, 0, 0, 2} data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeLong,
TestDefaultByteOrder)
value, err := vc.ReadLongs() value, err := vc.ReadLongs()
log.PanicIf(err) log.PanicIf(err)
@ -614,8 +963,17 @@ func TestValueContext_ReadRationals(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeRational, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeRational,
TestDefaultByteOrder)
value, err := vc.ReadRationals() value, err := vc.ReadRationals()
log.PanicIf(err) log.PanicIf(err)
@ -637,10 +995,20 @@ func TestValueContext_ReadSignedLongs(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{0, 0, 0, 1, 0, 0, 0, 2} data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedLong, TestDefaultByteOrder) vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeSignedLong,
TestDefaultByteOrder)
value, err := vc.ReadSignedLongs() value, err := vc.ReadSignedLongs()
log.PanicIf(err) log.PanicIf(err)
@ -663,8 +1031,9 @@ func TestValueContext_ReadSignedRationals(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedRational, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, sb, TypeSignedRational, TestDefaultByteOrder)
value, err := vc.ReadSignedRationals() value, err := vc.ReadSignedRationals()
log.PanicIf(err) log.PanicIf(err)
@ -686,10 +1055,12 @@ func TestValueContext_Values__Byte(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'} data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeByte, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, sb, TypeByte, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)
@ -706,10 +1077,12 @@ func TestValueContext_Values__Ascii(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0} data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAscii, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, sb, TypeAscii, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)
@ -726,10 +1099,12 @@ func TestValueContext_Values__AsciiNoNul(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'} data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeAsciiNoNul, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, sb, TypeAsciiNoNul, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)
@ -746,10 +1121,12 @@ func TestValueContext_Values__Short(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{0, 1, 0, 2, 0, 3, 0, 4} data := []byte{0, 1, 0, 2, 0, 3, 0, 4}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeShort, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, sb, TypeShort, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)
@ -766,10 +1143,12 @@ func TestValueContext_Values__Long(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{0, 0, 0, 1, 0, 0, 0, 2} data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, sb, TypeLong, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)
@ -792,8 +1171,9 @@ func TestValueContext_Values__Rational(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeRational, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, sb, TypeRational, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)
@ -815,10 +1195,12 @@ func TestValueContext_Values__SignedLong(t *testing.T) {
valueOffset := uint32(4) valueOffset := uint32(4)
data := []byte{0, 0, 0, 1, 0, 0, 0, 2} data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedLong, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, sb, TypeSignedLong, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)
@ -841,8 +1223,9 @@ func TestValueContext_Values__SignedRational(t *testing.T) {
addressableData := []byte{0, 0, 0, 0} addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...) addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, addressableData, TypeSignedRational, TestDefaultByteOrder) vc := NewValueContext("aa/bb", 0x1234, unitCount, valueOffset, rawValueOffset, sb, TypeSignedRational, TestDefaultByteOrder)
value, err := vc.Values() value, err := vc.Values()
log.PanicIf(err) log.PanicIf(err)

50
v3/data_layer.go Normal file
View File

@ -0,0 +1,50 @@
package exif
import (
"io"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-utility/filesystem"
)
type ExifBlobSeeker interface {
GetReadSeeker(initialOffset int64) (rs io.ReadSeeker, err error)
}
// ExifReadSeeker knows how to retrieve data from the EXIF blob relative to the
// beginning of the blob (so, absolute position (0) is the first byte of the
// EXIF data).
type ExifReadSeeker struct {
rs io.ReadSeeker
}
func NewExifReadSeeker(rs io.ReadSeeker) *ExifReadSeeker {
return &ExifReadSeeker{
rs: rs,
}
}
func NewExifReadSeekerWithBytes(exifData []byte) *ExifReadSeeker {
sb := rifs.NewSeekableBufferWithBytes(exifData)
edbs := NewExifReadSeeker(sb)
return edbs
}
// Fork creates a new ReadSeeker instead that wraps a BouncebackReader to
// maintain its own position in the stream.
func (edbs *ExifReadSeeker) GetReadSeeker(initialOffset int64) (rs io.ReadSeeker, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
br, err := rifs.NewBouncebackReader(edbs.rs)
log.PanicIf(err)
_, err = br.Seek(initialOffset, io.SeekStart)
log.PanicIf(err)
return br, nil
}

View File

@ -202,7 +202,8 @@ func Visit(rootIfdIdentity *exifcommon.IfdIdentity, ifdMapping *exifcommon.IfdMa
eh, err = ParseExifHeader(exifData) eh, err = ParseExifHeader(exifData)
log.PanicIf(err) log.PanicIf(err)
ie := NewIfdEnumerate(ifdMapping, tagIndex, exifData, eh.ByteOrder) ebs := NewExifReadSeekerWithBytes(exifData)
ie := NewIfdEnumerate(ifdMapping, tagIndex, ebs, eh.ByteOrder)
_, err = ie.Scan(rootIfdIdentity, eh.FirstIfdOffset, visitor) _, err = ie.Scan(rootIfdIdentity, eh.FirstIfdOffset, visitor)
log.PanicIf(err) log.PanicIf(err)
@ -223,7 +224,8 @@ func Collect(ifdMapping *exifcommon.IfdMapping, tagIndex *TagIndex, exifData []b
eh, err = ParseExifHeader(exifData) eh, err = ParseExifHeader(exifData)
log.PanicIf(err) log.PanicIf(err)
ie := NewIfdEnumerate(ifdMapping, tagIndex, exifData, eh.ByteOrder) ebs := NewExifReadSeekerWithBytes(exifData)
ie := NewIfdEnumerate(ifdMapping, tagIndex, ebs, eh.ByteOrder)
index, err = ie.Collect(eh.FirstIfdOffset) index, err = ie.Collect(eh.FirstIfdOffset)
log.PanicIf(err) log.PanicIf(err)

View File

@ -43,6 +43,8 @@ func TestVisit(t *testing.T) {
// Search for the beginning of the EXIF information. The EXIF is near the // Search for the beginning of the EXIF information. The EXIF is near the
// very beginning of our/most JPEGs, so this has a very low cost. // very beginning of our/most JPEGs, so this has a very low cost.
// TODO(dustin): Just use SearchAndExtractExifWithReader() here.
foundAt := -1 foundAt := -1
for i := 0; i < len(data); i++ { for i := 0; i < len(data); i++ {
if _, err := ParseExifHeader(data[i:]); err == nil { if _, err := ParseExifHeader(data[i:]); err == nil {
@ -416,5 +418,6 @@ func ExampleBuildExifHeader() {
log.PanicIf(err) log.PanicIf(err)
fmt.Printf("%v\n", eh) fmt.Printf("%v\n", eh)
// Output: ExifHeader<BYTE-ORDER=[BigEndian] FIRST-IFD-OFFSET=(0x11223344)> // Output: ExifHeader<BYTE-ORDER=[BigEndian] FIRST-IFD-OFFSET=(0x11223344)>
} }

View File

@ -4,9 +4,11 @@ go 1.13
// Development only // Development only
// replace github.com/dsoprea/go-logging => ../../go-logging // replace github.com/dsoprea/go-logging => ../../go-logging
replace github.com/dsoprea/go-utility => ../../go-utility
require ( require (
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d
github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d github.com/golang/geo v0.0.0-20200319012246-673a6f80352d
github.com/jessevdk/go-flags v1.4.0 github.com/jessevdk/go-flags v1.4.0
golang.org/x/net v0.0.0-20200513185701-a91f0712d120 // indirect golang.org/x/net v0.0.0-20200513185701-a91f0712d120 // indirect

View File

@ -1,3 +1,4 @@
github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696 h1:VGFnZAcLwPpt1sHlAxml+pGLZz9A2s+K/s1YNhPC91Y= github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696 h1:VGFnZAcLwPpt1sHlAxml+pGLZz9A2s+K/s1YNhPC91Y=
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA= github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
github.com/dsoprea/go-logging v0.0.0-20200502191043-ec333ec7635f h1:XM9MVftaUNA4CcjV97+4bSy7u9Ns04DEYbZkswUrRtc= github.com/dsoprea/go-logging v0.0.0-20200502191043-ec333ec7635f h1:XM9MVftaUNA4CcjV97+4bSy7u9Ns04DEYbZkswUrRtc=
@ -6,6 +7,8 @@ github.com/dsoprea/go-logging v0.0.0-20200502201358-170ff607885f h1:FonKAuW3PmNt
github.com/dsoprea/go-logging v0.0.0-20200502201358-170ff607885f/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8= github.com/dsoprea/go-logging v0.0.0-20200502201358-170ff607885f/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d h1:F/7L5wr/fP/SKeO5HuMlNEX9Ipyx2MbH2rV9G4zJRpk= github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d h1:F/7L5wr/fP/SKeO5HuMlNEX9Ipyx2MbH2rV9G4zJRpk=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8= github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176 h1:CfXezFYb2STGOd1+n1HshvE191zVx+QX3A1nML5xxME=
github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4= github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4=
@ -19,6 +22,7 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY= golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY=

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"io"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -75,22 +76,22 @@ var (
// are fairly simple to enumerate. // are fairly simple to enumerate.
type byteParser struct { type byteParser struct {
byteOrder binary.ByteOrder byteOrder binary.ByteOrder
addressableData []byte rs io.ReadSeeker
ifdOffset uint32 ifdOffset uint32
currentOffset uint32 currentOffset uint32
} }
func newByteParser(addressableData []byte, byteOrder binary.ByteOrder, ifdOffset uint32) (bp *byteParser, err error) { // newByteParser returns a new byteParser struct.
if ifdOffset >= uint32(len(addressableData)) { //
return nil, ErrOffsetInvalid // initialOffset is for arithmetic-based tracking of where we should be at in
} // the stream.
func newByteParser(rs io.ReadSeeker, byteOrder binary.ByteOrder, initialOffset uint32) (bp *byteParser, err error) {
// TODO(dustin): Add test // TODO(dustin): Add test
bp = &byteParser{ bp = &byteParser{
addressableData: addressableData, rs: rs,
byteOrder: byteOrder, byteOrder: byteOrder,
currentOffset: ifdOffset, currentOffset: initialOffset,
} }
return bp, nil return bp, nil
@ -110,11 +111,11 @@ func (bp *byteParser) getUint16() (value uint16, raw []byte, err error) {
needBytes := 2 needBytes := 2
if bp.currentOffset+needBytes >= len(bp.addressableData) { raw = make([]byte, needBytes)
return 0, nil, io.EOF
} _, err = io.ReadFull(bp.rs, raw)
log.PanicIf(err)
raw = addressableData[bp.currentOffset : bp.currentOffset+needBytes]
value = bp.byteOrder.Uint16(raw) value = bp.byteOrder.Uint16(raw)
bp.currentOffset += uint32(needBytes) bp.currentOffset += uint32(needBytes)
@ -136,12 +137,12 @@ func (bp *byteParser) getUint32() (value uint32, raw []byte, err error) {
needBytes := 4 needBytes := 4
if bp.currentOffset+needBytes >= len(bp.addressableData) { raw = make([]byte, needBytes)
return 0, nil, io.EOF
}
raw = addressableData[bp.currentOffset : bp.currentOffset+needBytes] _, err = io.ReadFull(bp.rs, raw)
value = bp.byteOrder.Uint16(raw) log.PanicIf(err)
value = bp.byteOrder.Uint32(raw)
bp.currentOffset += uint32(needBytes) bp.currentOffset += uint32(needBytes)
@ -157,7 +158,7 @@ func (bp *byteParser) CurrentOffset() uint32 {
// IfdEnumerate is the main enumeration type. It knows how to parse the IFD // IfdEnumerate is the main enumeration type. It knows how to parse the IFD
// containers in the EXIF blob. // containers in the EXIF blob.
type IfdEnumerate struct { type IfdEnumerate struct {
exifData []byte ebs ExifBlobSeeker
byteOrder binary.ByteOrder byteOrder binary.ByteOrder
tagIndex *TagIndex tagIndex *TagIndex
ifdMapping *exifcommon.IfdMapping ifdMapping *exifcommon.IfdMapping
@ -165,9 +166,9 @@ type IfdEnumerate struct {
} }
// NewIfdEnumerate returns a new instance of IfdEnumerate. // NewIfdEnumerate returns a new instance of IfdEnumerate.
func NewIfdEnumerate(ifdMapping *exifcommon.IfdMapping, tagIndex *TagIndex, exifData []byte, byteOrder binary.ByteOrder) *IfdEnumerate { func NewIfdEnumerate(ifdMapping *exifcommon.IfdMapping, tagIndex *TagIndex, ebs ExifBlobSeeker, byteOrder binary.ByteOrder) *IfdEnumerate {
return &IfdEnumerate{ return &IfdEnumerate{
exifData: exifData, ebs: ebs,
byteOrder: byteOrder, byteOrder: byteOrder,
ifdMapping: ifdMapping, ifdMapping: ifdMapping,
tagIndex: tagIndex, tagIndex: tagIndex,
@ -181,11 +182,16 @@ func (ie *IfdEnumerate) getByteParser(ifdOffset uint32) (bp *byteParser, err err
} }
}() }()
initialOffset := ExifAddressableAreaStart + ifdOffset
rs, err := ie.ebs.GetReadSeeker(int64(initialOffset))
log.PanicIf(err)
bp, err = bp, err =
newByteParser( newByteParser(
ie.exifData[ExifAddressableAreaStart:], rs,
ie.byteOrder, ie.byteOrder,
ifdOffset) initialOffset)
if err != nil { if err != nil {
if err == ErrOffsetInvalid { if err == ErrOffsetInvalid {
@ -228,6 +234,9 @@ func (ie *IfdEnumerate) parseTag(ii *exifcommon.IfdIdentity, tagPosition int, bp
log.Panic(ErrTagTypeNotValid) log.Panic(ErrTagTypeNotValid)
} }
rs, err := ie.ebs.GetReadSeeker(0)
log.PanicIf(err)
ite = newIfdTagEntry( ite = newIfdTagEntry(
ii, ii,
tagId, tagId,
@ -236,7 +245,7 @@ func (ie *IfdEnumerate) parseTag(ii *exifcommon.IfdIdentity, tagPosition int, bp
unitCount, unitCount,
valueOffset, valueOffset,
rawValueOffset, rawValueOffset,
ie.exifData[ExifAddressableAreaStart:], rs,
ie.byteOrder) ie.byteOrder)
ifdPath := ii.UnindexedString() ifdPath := ii.UnindexedString()
@ -266,8 +275,8 @@ func (ie *IfdEnumerate) parseTag(ii *exifcommon.IfdIdentity, tagPosition int, bp
// TagVisitorFn is called for each tag when enumerating through the EXIF. // TagVisitorFn is called for each tag when enumerating through the EXIF.
type TagVisitorFn func(fqIfdPath string, ifdIndex int, ite *IfdTagEntry) (err error) type TagVisitorFn func(fqIfdPath string, ifdIndex int, ite *IfdTagEntry) (err error)
// postparseTag do some tag-level processing here following the parse of each. // tagPostParse do some tag-level processing here following the parse of each.
func (ie *IfdEnumerate) postparseTag(ite *IfdTagEntry, med *MiscellaneousExifData) (err error) { func (ie *IfdEnumerate) tagPostParse(ite *IfdTagEntry, med *MiscellaneousExifData) (err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err = log.Wrap(state.(error)) err = log.Wrap(state.(error))
@ -401,7 +410,7 @@ func (ie *IfdEnumerate) parseIfd(ii *exifcommon.IfdIdentity, bp *byteParser, vis
log.Panic(err) log.Panic(err)
} }
err = ie.postparseTag(ite, med) err = ie.tagPostParse(ite, med)
if err == nil { if err == nil {
if err == ErrTagNotFound { if err == ErrTagNotFound {
continue continue
@ -1382,9 +1391,16 @@ func ParseOneIfd(ifdMapping *exifcommon.IfdMapping, tagIndex *TagIndex, ii *exif
} }
}() }()
ie := NewIfdEnumerate(ifdMapping, tagIndex, make([]byte, 0), byteOrder) // TODO(dustin): Add test
bp, err := newByteParser(ifdBlock, byteOrder, 0) // RELEASE(dustin): Stop exporting this. Just supports tests.
ebs := NewExifReadSeekerWithBytes(ifdBlock)
rs, err := ebs.GetReadSeeker(0)
log.PanicIf(err)
bp, err := newByteParser(rs, byteOrder, 0)
if err != nil { if err != nil {
if err == ErrOffsetInvalid { if err == ErrOffsetInvalid {
return 0, nil, err return 0, nil, err
@ -1393,6 +1409,9 @@ func ParseOneIfd(ifdMapping *exifcommon.IfdMapping, tagIndex *TagIndex, ii *exif
log.Panic(err) log.Panic(err)
} }
dummyEbs := NewExifReadSeekerWithBytes([]byte{})
ie := NewIfdEnumerate(ifdMapping, tagIndex, dummyEbs, byteOrder)
nextIfdOffset, entries, _, err = ie.parseIfd(ii, bp, visitor, true, nil) nextIfdOffset, entries, _, err = ie.parseIfd(ii, bp, visitor, true, nil)
log.PanicIf(err) log.PanicIf(err)
@ -1407,9 +1426,16 @@ func ParseOneTag(ifdMapping *exifcommon.IfdMapping, tagIndex *TagIndex, ii *exif
} }
}() }()
ie := NewIfdEnumerate(ifdMapping, tagIndex, make([]byte, 0), byteOrder) // TODO(dustin): Add test
bp, err := newByteParser(tagBlock, byteOrder, 0) // RELEASE(dustin): Stop exporting this. Just supports tests.
ebs := NewExifReadSeekerWithBytes(tagBlock)
rs, err := ebs.GetReadSeeker(0)
log.PanicIf(err)
bp, err := newByteParser(rs, byteOrder, 0)
if err != nil { if err != nil {
if err == ErrOffsetInvalid { if err == ErrOffsetInvalid {
return nil, err return nil, err
@ -1418,10 +1444,13 @@ func ParseOneTag(ifdMapping *exifcommon.IfdMapping, tagIndex *TagIndex, ii *exif
log.Panic(err) log.Panic(err)
} }
dummyEbs := NewExifReadSeekerWithBytes([]byte{})
ie := NewIfdEnumerate(ifdMapping, tagIndex, dummyEbs, byteOrder)
ite, err = ie.parseTag(ii, 0, bp) ite, err = ie.parseTag(ii, 0, bp)
log.PanicIf(err) log.PanicIf(err)
err = ie.postparseTag(ite, nil) err = ie.tagPostParse(ite, nil)
if err != nil { if err != nil {
if err == ErrTagNotFound { if err == ErrTagNotFound {
return nil, err return nil, err

View File

@ -2,6 +2,7 @@ package exif
import ( import (
"fmt" "fmt"
"io"
"encoding/binary" "encoding/binary"
@ -42,13 +43,13 @@ type IfdTagEntry struct {
isUnhandledUnknown bool isUnhandledUnknown bool
addressableData []byte rs io.ReadSeeker
byteOrder binary.ByteOrder byteOrder binary.ByteOrder
tagName string tagName string
} }
func newIfdTagEntry(ii *exifcommon.IfdIdentity, tagId uint16, tagIndex int, tagType exifcommon.TagTypePrimitive, unitCount uint32, valueOffset uint32, rawValueOffset []byte, addressableData []byte, byteOrder binary.ByteOrder) *IfdTagEntry { func newIfdTagEntry(ii *exifcommon.IfdIdentity, tagId uint16, tagIndex int, tagType exifcommon.TagTypePrimitive, unitCount uint32, valueOffset uint32, rawValueOffset []byte, rs io.ReadSeeker, byteOrder binary.ByteOrder) *IfdTagEntry {
return &IfdTagEntry{ return &IfdTagEntry{
ifdIdentity: ii, ifdIdentity: ii,
tagId: tagId, tagId: tagId,
@ -57,7 +58,7 @@ func newIfdTagEntry(ii *exifcommon.IfdIdentity, tagId uint16, tagIndex int, tagT
unitCount: unitCount, unitCount: unitCount,
valueOffset: valueOffset, valueOffset: valueOffset,
rawValueOffset: rawValueOffset, rawValueOffset: rawValueOffset,
addressableData: addressableData, rs: rs,
byteOrder: byteOrder, byteOrder: byteOrder,
} }
} }
@ -291,7 +292,7 @@ func (ite *IfdTagEntry) getValueContext() *exifcommon.ValueContext {
ite.unitCount, ite.unitCount,
ite.valueOffset, ite.valueOffset,
ite.rawValueOffset, ite.rawValueOffset,
ite.addressableData, ite.rs,
ite.tagType, ite.tagType,
ite.byteOrder) ite.byteOrder)
} }

View File

@ -5,6 +5,7 @@ import (
"testing" "testing"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-utility/filesystem"
"github.com/dsoprea/go-exif/v2/common" "github.com/dsoprea/go-exif/v2/common"
) )
@ -13,6 +14,7 @@ func TestIfdTagEntry_RawBytes_Allocated(t *testing.T) {
data := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66} data := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
addressableBytes := data addressableBytes := data
sb := rifs.NewSeekableBufferWithBytes(addressableBytes)
ite := newIfdTagEntry( ite := newIfdTagEntry(
exifcommon.IfdStandardIfdIdentity, exifcommon.IfdStandardIfdIdentity,
@ -22,7 +24,7 @@ func TestIfdTagEntry_RawBytes_Allocated(t *testing.T) {
6, 6,
0, 0,
nil, nil,
addressableBytes, sb,
exifcommon.TestDefaultByteOrder) exifcommon.TestDefaultByteOrder)
value, err := ite.GetRawBytes() value, err := ite.GetRawBytes()

View File

@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-utility/filesystem"
"github.com/dsoprea/go-exif/v2/common" "github.com/dsoprea/go-exif/v2/common"
) )
@ -59,6 +60,7 @@ func TestCodec8828Oecf_Decode(t *testing.T) {
0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x16} 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x16}
addressableData := encoded addressableData := encoded
sb := rifs.NewSeekableBufferWithBytes(addressableData)
valueContext := exifcommon.NewValueContext( valueContext := exifcommon.NewValueContext(
"", "",
@ -66,7 +68,7 @@ func TestCodec8828Oecf_Decode(t *testing.T) {
uint32(len(encoded)), uint32(len(encoded)),
0, 0,
nil, nil,
addressableData, sb,
exifcommon.TypeUndefined, exifcommon.TypeUndefined,
exifcommon.TestDefaultByteOrder) exifcommon.TestDefaultByteOrder)

View File

@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-utility/filesystem"
"github.com/dsoprea/go-exif/v2/common" "github.com/dsoprea/go-exif/v2/common"
) )
@ -51,13 +52,15 @@ func TestCodec927CMakerNote_Decode(t *testing.T) {
MakerNoteBytes: b, MakerNoteBytes: b,
} }
sb := rifs.NewSeekableBufferWithBytes(b)
valueContext := exifcommon.NewValueContext( valueContext := exifcommon.NewValueContext(
"", "",
0, 0,
uint32(len(b)), uint32(len(b)),
0, 0,
nil, nil,
b, sb,
exifcommon.TypeUndefined, exifcommon.TypeUndefined,
exifcommon.TestDefaultByteOrder) exifcommon.TestDefaultByteOrder)

View File

@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-utility/filesystem"
"github.com/dsoprea/go-exif/v2/common" "github.com/dsoprea/go-exif/v2/common"
) )
@ -65,6 +66,7 @@ func TestCodec9286UserComment_Decode(t *testing.T) {
} }
addressableBytes := encoded addressableBytes := encoded
sb := rifs.NewSeekableBufferWithBytes(addressableBytes)
valueContext := exifcommon.NewValueContext( valueContext := exifcommon.NewValueContext(
"", "",
@ -72,7 +74,7 @@ func TestCodec9286UserComment_Decode(t *testing.T) {
uint32(len(encoded)), uint32(len(encoded)),
0, 0,
nil, nil,
addressableBytes, sb,
exifcommon.TypeUndefined, exifcommon.TypeUndefined,
exifcommon.TestDefaultByteOrder) exifcommon.TestDefaultByteOrder)

View File

@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-utility/filesystem"
"github.com/dsoprea/go-exif/v2/common" "github.com/dsoprea/go-exif/v2/common"
) )
@ -48,6 +49,7 @@ func TestCodecA000FlashpixVersion_Decode(t *testing.T) {
encoded := []byte(versionPhrase) encoded := []byte(versionPhrase)
addressableBytes := encoded addressableBytes := encoded
sb := rifs.NewSeekableBufferWithBytes(addressableBytes)
valueContext := exifcommon.NewValueContext( valueContext := exifcommon.NewValueContext(
"", "",
@ -55,7 +57,7 @@ func TestCodecA000FlashpixVersion_Decode(t *testing.T) {
uint32(len(encoded)), uint32(len(encoded)),
0, 0,
nil, nil,
addressableBytes, sb,
exifcommon.TypeUndefined, exifcommon.TypeUndefined,
exifcommon.TestDefaultByteOrder) exifcommon.TestDefaultByteOrder)

View File

@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-utility/filesystem"
"github.com/dsoprea/go-exif/v2/common" "github.com/dsoprea/go-exif/v2/common"
) )
@ -82,6 +83,7 @@ func TestCodecA20CSpatialFrequencyResponse_Decode(t *testing.T) {
} }
addressableBytes := encoded addressableBytes := encoded
sb := rifs.NewSeekableBufferWithBytes(addressableBytes)
valueContext := exifcommon.NewValueContext( valueContext := exifcommon.NewValueContext(
"", "",
@ -89,7 +91,7 @@ func TestCodecA20CSpatialFrequencyResponse_Decode(t *testing.T) {
uint32(len(encoded)), uint32(len(encoded)),
0, 0,
nil, nil,
addressableBytes, sb,
exifcommon.TypeUndefined, exifcommon.TypeUndefined,
exifcommon.TestDefaultByteOrder) exifcommon.TestDefaultByteOrder)

View File

@ -5,8 +5,10 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/dsoprea/go-exif/v2/common"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
"github.com/dsoprea/go-utility/filesystem"
"github.com/dsoprea/go-exif/v2/common"
) )
func TestTagA302CfaPattern_String(t *testing.T) { func TestTagA302CfaPattern_String(t *testing.T) {
@ -63,7 +65,8 @@ func TestCodecA302CfaPattern_Decode(t *testing.T) {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
} }
addressableData := encoded addressableBytes := encoded
sb := rifs.NewSeekableBufferWithBytes(addressableBytes)
valueContext := exifcommon.NewValueContext( valueContext := exifcommon.NewValueContext(
"", "",
@ -71,7 +74,7 @@ func TestCodecA302CfaPattern_Decode(t *testing.T) {
uint32(len(encoded)), uint32(len(encoded)),
0, 0,
nil, nil,
addressableData, sb,
exifcommon.TypeUndefined, exifcommon.TypeUndefined,
exifcommon.TestDefaultByteOrder) exifcommon.TestDefaultByteOrder)

View File

@ -2,6 +2,7 @@ package exif
import ( import (
"fmt" "fmt"
"io"
"math" "math"
"reflect" "reflect"
"strconv" "strconv"
@ -151,7 +152,8 @@ func GetFlatExifData(exifData []byte) (exifTags []ExifTag, err error) {
im := NewIfdMappingWithStandard() im := NewIfdMappingWithStandard()
ti := NewTagIndex() ti := NewTagIndex()
ie := NewIfdEnumerate(im, ti, exifData, eh.ByteOrder) ebs := NewExifReadSeekerWithBytes(exifData)
ie := NewIfdEnumerate(im, ti, ebs, eh.ByteOrder)
exifTags = make([]ExifTag, 0) exifTags = make([]ExifTag, 0)
@ -232,3 +234,11 @@ func GpsDegreesEquals(gi1, gi2 GpsDegrees) bool {
func IsTime(v interface{}) bool { func IsTime(v interface{}) bool {
return reflect.TypeOf(v) == timeType return reflect.TypeOf(v) == timeType
} }
// TODO(dustin): !! For debugging
func mustGetCurrentOffset(s io.Seeker) int64 {
offset, err := s.Seek(0, io.SeekCurrent)
log.PanicIf(err)
return offset
}