mirror of https://github.com/dsoprea/go-exif.git
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 #42dustin/master
parent
56058635d0
commit
312218d7b1
|
@ -2,6 +2,7 @@ package exifcommon
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"encoding/binary"
|
||||
|
||||
|
@ -21,10 +22,10 @@ var (
|
|||
// ValueContext embeds all of the parameters required to find and extract the
|
||||
// actual tag value.
|
||||
type ValueContext struct {
|
||||
unitCount uint32
|
||||
valueOffset uint32
|
||||
rawValueOffset []byte
|
||||
addressableData []byte
|
||||
unitCount uint32
|
||||
valueOffset uint32
|
||||
rawValueOffset []byte
|
||||
rs io.ReadSeeker
|
||||
|
||||
tagType TagTypePrimitive
|
||||
byteOrder binary.ByteOrder
|
||||
|
@ -40,12 +41,12 @@ type ValueContext struct {
|
|||
// TODO(dustin): We can update newValueContext() to derive `valueOffset` itself (from `rawValueOffset`).
|
||||
|
||||
// NewValueContext returns a new ValueContext struct.
|
||||
func NewValueContext(ifdPath string, tagId uint16, unitCount, valueOffset uint32, rawValueOffset, addressableData []byte, tagType TagTypePrimitive, byteOrder binary.ByteOrder) *ValueContext {
|
||||
func NewValueContext(ifdPath string, tagId uint16, unitCount, valueOffset uint32, rawValueOffset []byte, rs io.ReadSeeker, tagType TagTypePrimitive, byteOrder binary.ByteOrder) *ValueContext {
|
||||
return &ValueContext{
|
||||
unitCount: unitCount,
|
||||
valueOffset: valueOffset,
|
||||
rawValueOffset: rawValueOffset,
|
||||
addressableData: addressableData,
|
||||
unitCount: unitCount,
|
||||
valueOffset: valueOffset,
|
||||
rawValueOffset: rawValueOffset,
|
||||
rs: rs,
|
||||
|
||||
tagType: tagType,
|
||||
byteOrder: byteOrder,
|
||||
|
@ -82,8 +83,11 @@ func (vc *ValueContext) RawValueOffset() []byte {
|
|||
}
|
||||
|
||||
// AddressableData returns the block of data that we can dereference into.
|
||||
func (vc *ValueContext) AddressableData() []byte {
|
||||
return vc.addressableData
|
||||
func (vc *ValueContext) AddressableData() io.ReadSeeker {
|
||||
|
||||
// RELEASE)dustin): Rename from AddressableData() to ReadSeeker()
|
||||
|
||||
return vc.rs
|
||||
}
|
||||
|
||||
// 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.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
|
||||
|
|
|
@ -5,13 +5,26 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-utility/filesystem"
|
||||
)
|
||||
|
||||
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)
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableData)
|
||||
|
||||
vc := NewValueContext(
|
||||
"aa/bb",
|
||||
0x1234,
|
||||
11,
|
||||
22,
|
||||
rawValueOffset,
|
||||
sb,
|
||||
TypeLong,
|
||||
TestDefaultByteOrder)
|
||||
|
||||
if vc.ifdPath != "aa/bb" {
|
||||
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)
|
||||
} 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)
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -47,16 +65,38 @@ func TestValueContext_SetUndefinedValueType__ErrorWhenNotUndefined(t *testing.T)
|
|||
}()
|
||||
|
||||
rawValueOffset := []byte{0, 0, 0, 22}
|
||||
|
||||
addressableData := []byte{1, 2, 3, 4}
|
||||
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeLong, TestDefaultByteOrder)
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableData)
|
||||
|
||||
vc := NewValueContext(
|
||||
"aa/bb",
|
||||
0x1234,
|
||||
11,
|
||||
22,
|
||||
rawValueOffset,
|
||||
sb,
|
||||
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)
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableData)
|
||||
|
||||
vc := NewValueContext(
|
||||
"aa/bb",
|
||||
0x1234,
|
||||
11,
|
||||
22,
|
||||
rawValueOffset,
|
||||
sb,
|
||||
TypeUndefined,
|
||||
TestDefaultByteOrder)
|
||||
|
||||
vc.SetUndefinedValueType(TypeLong)
|
||||
|
||||
|
@ -71,8 +111,19 @@ func TestValueContext_SetUndefinedValueType__Ok(t *testing.T) {
|
|||
|
||||
func TestValueContext_effectiveValueType(t *testing.T) {
|
||||
rawValueOffset := []byte{0, 0, 0, 22}
|
||||
|
||||
addressableData := []byte{1, 2, 3, 4}
|
||||
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableData)
|
||||
|
||||
vc := NewValueContext(
|
||||
"aa/bb",
|
||||
0x1234,
|
||||
11,
|
||||
22,
|
||||
rawValueOffset,
|
||||
sb,
|
||||
TypeUndefined,
|
||||
TestDefaultByteOrder)
|
||||
|
||||
vc.SetUndefinedValueType(TypeLong)
|
||||
|
||||
|
@ -87,8 +138,19 @@ func TestValueContext_effectiveValueType(t *testing.T) {
|
|||
|
||||
func TestValueContext_UnitCount(t *testing.T) {
|
||||
rawValueOffset := []byte{0, 0, 0, 22}
|
||||
|
||||
addressableData := []byte{1, 2, 3, 4}
|
||||
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableData)
|
||||
|
||||
vc := NewValueContext(
|
||||
"aa/bb",
|
||||
0x1234,
|
||||
11,
|
||||
22,
|
||||
rawValueOffset,
|
||||
sb,
|
||||
TypeUndefined,
|
||||
TestDefaultByteOrder)
|
||||
|
||||
if vc.UnitCount() != 11 {
|
||||
t.Fatalf("UnitCount() not correct: (%d)", vc.UnitCount())
|
||||
|
@ -97,8 +159,19 @@ func TestValueContext_UnitCount(t *testing.T) {
|
|||
|
||||
func TestValueContext_ValueOffset(t *testing.T) {
|
||||
rawValueOffset := []byte{0, 0, 0, 22}
|
||||
|
||||
addressableData := []byte{1, 2, 3, 4}
|
||||
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableData)
|
||||
|
||||
vc := NewValueContext(
|
||||
"aa/bb",
|
||||
0x1234,
|
||||
11,
|
||||
22,
|
||||
rawValueOffset,
|
||||
sb,
|
||||
TypeUndefined,
|
||||
TestDefaultByteOrder)
|
||||
|
||||
if vc.ValueOffset() != 22 {
|
||||
t.Fatalf("ValueOffset() not correct: (%d)", vc.ValueOffset())
|
||||
|
@ -107,8 +180,19 @@ func TestValueContext_ValueOffset(t *testing.T) {
|
|||
|
||||
func TestValueContext_RawValueOffset(t *testing.T) {
|
||||
rawValueOffset := []byte{0, 0, 0, 22}
|
||||
|
||||
addressableData := []byte{1, 2, 3, 4}
|
||||
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableData)
|
||||
|
||||
vc := NewValueContext(
|
||||
"aa/bb",
|
||||
0x1234,
|
||||
11,
|
||||
22,
|
||||
rawValueOffset,
|
||||
sb,
|
||||
TypeUndefined,
|
||||
TestDefaultByteOrder)
|
||||
|
||||
if bytes.Equal(vc.RawValueOffset(), rawValueOffset) != true {
|
||||
t.Fatalf("RawValueOffset() not correct: %v", vc.RawValueOffset())
|
||||
|
@ -117,18 +201,43 @@ func TestValueContext_RawValueOffset(t *testing.T) {
|
|||
|
||||
func TestValueContext_AddressableData(t *testing.T) {
|
||||
rawValueOffset := []byte{0, 0, 0, 22}
|
||||
addressableData := []byte{1, 2, 3, 4}
|
||||
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
|
||||
|
||||
if bytes.Equal(vc.AddressableData(), addressableData) != true {
|
||||
t.Fatalf("AddressableData() not correct: %v", vc.AddressableData())
|
||||
addressableData := []byte{1, 2, 3, 4}
|
||||
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) {
|
||||
rawValueOffset := []byte{0, 0, 0, 22}
|
||||
|
||||
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 {
|
||||
t.Fatalf("ByteOrder() not correct: %v", vc.ByteOrder())
|
||||
|
@ -137,8 +246,19 @@ func TestValueContext_ByteOrder(t *testing.T) {
|
|||
|
||||
func TestValueContext_IfdPath(t *testing.T) {
|
||||
rawValueOffset := []byte{0, 0, 0, 22}
|
||||
|
||||
addressableData := []byte{1, 2, 3, 4}
|
||||
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableData)
|
||||
|
||||
vc := NewValueContext(
|
||||
"aa/bb",
|
||||
0x1234,
|
||||
11,
|
||||
22,
|
||||
rawValueOffset,
|
||||
sb,
|
||||
TypeUndefined,
|
||||
TestDefaultByteOrder)
|
||||
|
||||
if vc.IfdPath() != "aa/bb" {
|
||||
t.Fatalf("IfdPath() not correct: [%s]", vc.IfdPath())
|
||||
|
@ -147,8 +267,19 @@ func TestValueContext_IfdPath(t *testing.T) {
|
|||
|
||||
func TestValueContext_TagId(t *testing.T) {
|
||||
rawValueOffset := []byte{0, 0, 0, 22}
|
||||
|
||||
addressableData := []byte{1, 2, 3, 4}
|
||||
vc := NewValueContext("aa/bb", 0x1234, 11, 22, rawValueOffset, addressableData, TypeUndefined, TestDefaultByteOrder)
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableData)
|
||||
|
||||
vc := NewValueContext(
|
||||
"aa/bb",
|
||||
0x1234,
|
||||
11,
|
||||
22,
|
||||
rawValueOffset,
|
||||
sb,
|
||||
TypeUndefined,
|
||||
TestDefaultByteOrder)
|
||||
|
||||
if vc.TagId() != 0x1234 {
|
||||
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) {
|
||||
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)
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableData)
|
||||
|
||||
vc := NewValueContext(
|
||||
"aa/bb",
|
||||
0x1234,
|
||||
unitCount,
|
||||
22,
|
||||
rawValueOffset,
|
||||
sb,
|
||||
TypeByte,
|
||||
TestDefaultByteOrder)
|
||||
|
||||
if vc.isEmbedded() != true {
|
||||
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) {
|
||||
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)
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableData)
|
||||
|
||||
vc := NewValueContext(
|
||||
"aa/bb",
|
||||
0x1234,
|
||||
unitCount,
|
||||
22,
|
||||
rawValueOffset,
|
||||
sb,
|
||||
TypeByte,
|
||||
TestDefaultByteOrder)
|
||||
|
||||
if vc.isEmbedded() != false {
|
||||
t.Fatalf("isEmbedded() not correct: %v", vc.isEmbedded())
|
||||
|
@ -186,7 +339,17 @@ func TestValueContext_readRawEncoded__IsEmbedded(t *testing.T) {
|
|||
valueOffset := uint32(0)
|
||||
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -205,10 +368,20 @@ func TestValueContext_readRawEncoded__IsRelative(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{5, 6, 7, 8, 9}
|
||||
|
||||
addressableData := []byte{1, 2, 3, 4}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -225,10 +398,20 @@ func TestValueContext_Format__Byte(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -245,10 +428,20 @@ func TestValueContext_Format__Ascii(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -265,10 +458,20 @@ func TestValueContext_Format__AsciiNoNul(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -285,10 +488,20 @@ func TestValueContext_Format__Short(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 1, 0, 2, 0, 3, 0, 4}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -305,10 +518,20 @@ func TestValueContext_Format__Long(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -331,8 +554,17 @@ func TestValueContext_Format__Rational(t *testing.T) {
|
|||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -349,10 +581,20 @@ func TestValueContext_Format__SignedLong(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -375,8 +617,17 @@ func TestValueContext_Format__SignedRational(t *testing.T) {
|
|||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -406,10 +657,20 @@ func TestValueContext_Format__Undefined__NoEffectiveType(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -426,10 +687,20 @@ func TestValueContext_Format__Undefined__HasEffectiveType(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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)
|
||||
|
||||
|
@ -448,10 +719,20 @@ func TestValueContext_FormatFirst__Bytes(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -468,10 +749,20 @@ func TestValueContext_FormatFirst__String(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -488,10 +779,20 @@ func TestValueContext_FormatFirst__List(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 1, 0, 2, 0, 3, 0, 4}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -510,8 +811,17 @@ func TestValueContext_ReadBytes(t *testing.T) {
|
|||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -528,10 +838,20 @@ func TestValueContext_ReadAscii(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -550,8 +870,17 @@ func TestValueContext_ReadAsciiNoNul(t *testing.T) {
|
|||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -568,10 +897,20 @@ func TestValueContext_ReadShorts(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 1, 0, 2, 0, 3, 0, 4}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -588,10 +927,20 @@ func TestValueContext_ReadLongs(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -614,8 +963,17 @@ func TestValueContext_ReadRationals(t *testing.T) {
|
|||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -637,10 +995,20 @@ func TestValueContext_ReadSignedLongs(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -663,8 +1031,9 @@ func TestValueContext_ReadSignedRationals(t *testing.T) {
|
|||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -686,10 +1055,12 @@ func TestValueContext_Values__Byte(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -706,10 +1077,12 @@ func TestValueContext_Values__Ascii(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -726,10 +1099,12 @@ func TestValueContext_Values__AsciiNoNul(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -746,10 +1121,12 @@ func TestValueContext_Values__Short(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 1, 0, 2, 0, 3, 0, 4}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -766,10 +1143,12 @@ func TestValueContext_Values__Long(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -792,8 +1171,9 @@ func TestValueContext_Values__Rational(t *testing.T) {
|
|||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -815,10 +1195,12 @@ func TestValueContext_Values__SignedLong(t *testing.T) {
|
|||
valueOffset := uint32(4)
|
||||
|
||||
data := []byte{0, 0, 0, 1, 0, 0, 0, 2}
|
||||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
@ -841,8 +1223,9 @@ func TestValueContext_Values__SignedRational(t *testing.T) {
|
|||
|
||||
addressableData := []byte{0, 0, 0, 0}
|
||||
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()
|
||||
log.PanicIf(err)
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -202,7 +202,8 @@ func Visit(rootIfdIdentity *exifcommon.IfdIdentity, ifdMapping *exifcommon.IfdMa
|
|||
eh, err = ParseExifHeader(exifData)
|
||||
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)
|
||||
log.PanicIf(err)
|
||||
|
@ -223,7 +224,8 @@ func Collect(ifdMapping *exifcommon.IfdMapping, tagIndex *TagIndex, exifData []b
|
|||
eh, err = ParseExifHeader(exifData)
|
||||
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)
|
||||
log.PanicIf(err)
|
||||
|
|
|
@ -43,6 +43,8 @@ func TestVisit(t *testing.T) {
|
|||
// 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.
|
||||
|
||||
// TODO(dustin): Just use SearchAndExtractExifWithReader() here.
|
||||
|
||||
foundAt := -1
|
||||
for i := 0; i < len(data); i++ {
|
||||
if _, err := ParseExifHeader(data[i:]); err == nil {
|
||||
|
@ -416,5 +418,6 @@ func ExampleBuildExifHeader() {
|
|||
log.PanicIf(err)
|
||||
|
||||
fmt.Printf("%v\n", eh)
|
||||
|
||||
// Output: ExifHeader<BYTE-ORDER=[BigEndian] FIRST-IFD-OFFSET=(0x11223344)>
|
||||
}
|
||||
|
|
|
@ -4,9 +4,11 @@ go 1.13
|
|||
|
||||
// Development only
|
||||
// replace github.com/dsoprea/go-logging => ../../go-logging
|
||||
replace github.com/dsoprea/go-utility => ../../go-utility
|
||||
|
||||
require (
|
||||
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/jessevdk/go-flags v1.4.0
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120 // indirect
|
||||
|
|
|
@ -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/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
|
||||
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-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-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/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
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/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-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/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY=
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -74,23 +75,23 @@ var (
|
|||
// statically-sized records. So, the tags (though notnecessarily their values)
|
||||
// are fairly simple to enumerate.
|
||||
type byteParser struct {
|
||||
byteOrder binary.ByteOrder
|
||||
addressableData []byte
|
||||
ifdOffset uint32
|
||||
currentOffset uint32
|
||||
byteOrder binary.ByteOrder
|
||||
rs io.ReadSeeker
|
||||
ifdOffset uint32
|
||||
currentOffset uint32
|
||||
}
|
||||
|
||||
func newByteParser(addressableData []byte, byteOrder binary.ByteOrder, ifdOffset uint32) (bp *byteParser, err error) {
|
||||
if ifdOffset >= uint32(len(addressableData)) {
|
||||
return nil, ErrOffsetInvalid
|
||||
}
|
||||
|
||||
// newByteParser returns a new byteParser struct.
|
||||
//
|
||||
// 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
|
||||
|
||||
bp = &byteParser{
|
||||
addressableData: addressableData,
|
||||
byteOrder: byteOrder,
|
||||
currentOffset: ifdOffset,
|
||||
rs: rs,
|
||||
byteOrder: byteOrder,
|
||||
currentOffset: initialOffset,
|
||||
}
|
||||
|
||||
return bp, nil
|
||||
|
@ -110,11 +111,11 @@ func (bp *byteParser) getUint16() (value uint16, raw []byte, err error) {
|
|||
|
||||
needBytes := 2
|
||||
|
||||
if bp.currentOffset+needBytes >= len(bp.addressableData) {
|
||||
return 0, nil, io.EOF
|
||||
}
|
||||
raw = make([]byte, needBytes)
|
||||
|
||||
_, err = io.ReadFull(bp.rs, raw)
|
||||
log.PanicIf(err)
|
||||
|
||||
raw = addressableData[bp.currentOffset : bp.currentOffset+needBytes]
|
||||
value = bp.byteOrder.Uint16(raw)
|
||||
|
||||
bp.currentOffset += uint32(needBytes)
|
||||
|
@ -136,12 +137,12 @@ func (bp *byteParser) getUint32() (value uint32, raw []byte, err error) {
|
|||
|
||||
needBytes := 4
|
||||
|
||||
if bp.currentOffset+needBytes >= len(bp.addressableData) {
|
||||
return 0, nil, io.EOF
|
||||
}
|
||||
raw = make([]byte, needBytes)
|
||||
|
||||
raw = addressableData[bp.currentOffset : bp.currentOffset+needBytes]
|
||||
value = bp.byteOrder.Uint16(raw)
|
||||
_, err = io.ReadFull(bp.rs, raw)
|
||||
log.PanicIf(err)
|
||||
|
||||
value = bp.byteOrder.Uint32(raw)
|
||||
|
||||
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
|
||||
// containers in the EXIF blob.
|
||||
type IfdEnumerate struct {
|
||||
exifData []byte
|
||||
ebs ExifBlobSeeker
|
||||
byteOrder binary.ByteOrder
|
||||
tagIndex *TagIndex
|
||||
ifdMapping *exifcommon.IfdMapping
|
||||
|
@ -165,9 +166,9 @@ type IfdEnumerate struct {
|
|||
}
|
||||
|
||||
// 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{
|
||||
exifData: exifData,
|
||||
ebs: ebs,
|
||||
byteOrder: byteOrder,
|
||||
ifdMapping: ifdMapping,
|
||||
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 =
|
||||
newByteParser(
|
||||
ie.exifData[ExifAddressableAreaStart:],
|
||||
rs,
|
||||
ie.byteOrder,
|
||||
ifdOffset)
|
||||
initialOffset)
|
||||
|
||||
if err != nil {
|
||||
if err == ErrOffsetInvalid {
|
||||
|
@ -228,6 +234,9 @@ func (ie *IfdEnumerate) parseTag(ii *exifcommon.IfdIdentity, tagPosition int, bp
|
|||
log.Panic(ErrTagTypeNotValid)
|
||||
}
|
||||
|
||||
rs, err := ie.ebs.GetReadSeeker(0)
|
||||
log.PanicIf(err)
|
||||
|
||||
ite = newIfdTagEntry(
|
||||
ii,
|
||||
tagId,
|
||||
|
@ -236,7 +245,7 @@ func (ie *IfdEnumerate) parseTag(ii *exifcommon.IfdIdentity, tagPosition int, bp
|
|||
unitCount,
|
||||
valueOffset,
|
||||
rawValueOffset,
|
||||
ie.exifData[ExifAddressableAreaStart:],
|
||||
rs,
|
||||
ie.byteOrder)
|
||||
|
||||
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.
|
||||
type TagVisitorFn func(fqIfdPath string, ifdIndex int, ite *IfdTagEntry) (err error)
|
||||
|
||||
// postparseTag do some tag-level processing here following the parse of each.
|
||||
func (ie *IfdEnumerate) postparseTag(ite *IfdTagEntry, med *MiscellaneousExifData) (err error) {
|
||||
// tagPostParse do some tag-level processing here following the parse of each.
|
||||
func (ie *IfdEnumerate) tagPostParse(ite *IfdTagEntry, med *MiscellaneousExifData) (err error) {
|
||||
defer func() {
|
||||
if state := recover(); state != nil {
|
||||
err = log.Wrap(state.(error))
|
||||
|
@ -401,7 +410,7 @@ func (ie *IfdEnumerate) parseIfd(ii *exifcommon.IfdIdentity, bp *byteParser, vis
|
|||
log.Panic(err)
|
||||
}
|
||||
|
||||
err = ie.postparseTag(ite, med)
|
||||
err = ie.tagPostParse(ite, med)
|
||||
if err == nil {
|
||||
if err == ErrTagNotFound {
|
||||
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 == ErrOffsetInvalid {
|
||||
return 0, nil, err
|
||||
|
@ -1393,6 +1409,9 @@ func ParseOneIfd(ifdMapping *exifcommon.IfdMapping, tagIndex *TagIndex, ii *exif
|
|||
log.Panic(err)
|
||||
}
|
||||
|
||||
dummyEbs := NewExifReadSeekerWithBytes([]byte{})
|
||||
ie := NewIfdEnumerate(ifdMapping, tagIndex, dummyEbs, byteOrder)
|
||||
|
||||
nextIfdOffset, entries, _, err = ie.parseIfd(ii, bp, visitor, true, nil)
|
||||
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 == ErrOffsetInvalid {
|
||||
return nil, err
|
||||
|
@ -1418,10 +1444,13 @@ func ParseOneTag(ifdMapping *exifcommon.IfdMapping, tagIndex *TagIndex, ii *exif
|
|||
log.Panic(err)
|
||||
}
|
||||
|
||||
dummyEbs := NewExifReadSeekerWithBytes([]byte{})
|
||||
ie := NewIfdEnumerate(ifdMapping, tagIndex, dummyEbs, byteOrder)
|
||||
|
||||
ite, err = ie.parseTag(ii, 0, bp)
|
||||
log.PanicIf(err)
|
||||
|
||||
err = ie.postparseTag(ite, nil)
|
||||
err = ie.tagPostParse(ite, nil)
|
||||
if err != nil {
|
||||
if err == ErrTagNotFound {
|
||||
return nil, err
|
||||
|
|
|
@ -2,6 +2,7 @@ package exif
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"encoding/binary"
|
||||
|
||||
|
@ -42,23 +43,23 @@ type IfdTagEntry struct {
|
|||
|
||||
isUnhandledUnknown bool
|
||||
|
||||
addressableData []byte
|
||||
byteOrder binary.ByteOrder
|
||||
rs io.ReadSeeker
|
||||
byteOrder binary.ByteOrder
|
||||
|
||||
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{
|
||||
ifdIdentity: ii,
|
||||
tagId: tagId,
|
||||
tagIndex: tagIndex,
|
||||
tagType: tagType,
|
||||
unitCount: unitCount,
|
||||
valueOffset: valueOffset,
|
||||
rawValueOffset: rawValueOffset,
|
||||
addressableData: addressableData,
|
||||
byteOrder: byteOrder,
|
||||
ifdIdentity: ii,
|
||||
tagId: tagId,
|
||||
tagIndex: tagIndex,
|
||||
tagType: tagType,
|
||||
unitCount: unitCount,
|
||||
valueOffset: valueOffset,
|
||||
rawValueOffset: rawValueOffset,
|
||||
rs: rs,
|
||||
byteOrder: byteOrder,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,7 +292,7 @@ func (ite *IfdTagEntry) getValueContext() *exifcommon.ValueContext {
|
|||
ite.unitCount,
|
||||
ite.valueOffset,
|
||||
ite.rawValueOffset,
|
||||
ite.addressableData,
|
||||
ite.rs,
|
||||
ite.tagType,
|
||||
ite.byteOrder)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-utility/filesystem"
|
||||
|
||||
"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}
|
||||
|
||||
addressableBytes := data
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableBytes)
|
||||
|
||||
ite := newIfdTagEntry(
|
||||
exifcommon.IfdStandardIfdIdentity,
|
||||
|
@ -22,7 +24,7 @@ func TestIfdTagEntry_RawBytes_Allocated(t *testing.T) {
|
|||
6,
|
||||
0,
|
||||
nil,
|
||||
addressableBytes,
|
||||
sb,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
value, err := ite.GetRawBytes()
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-utility/filesystem"
|
||||
|
||||
"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}
|
||||
|
||||
addressableData := encoded
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableData)
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
|
@ -66,7 +68,7 @@ func TestCodec8828Oecf_Decode(t *testing.T) {
|
|||
uint32(len(encoded)),
|
||||
0,
|
||||
nil,
|
||||
addressableData,
|
||||
sb,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-utility/filesystem"
|
||||
|
||||
"github.com/dsoprea/go-exif/v2/common"
|
||||
)
|
||||
|
@ -51,13 +52,15 @@ func TestCodec927CMakerNote_Decode(t *testing.T) {
|
|||
MakerNoteBytes: b,
|
||||
}
|
||||
|
||||
sb := rifs.NewSeekableBufferWithBytes(b)
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
0,
|
||||
uint32(len(b)),
|
||||
0,
|
||||
nil,
|
||||
b,
|
||||
sb,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-utility/filesystem"
|
||||
|
||||
"github.com/dsoprea/go-exif/v2/common"
|
||||
)
|
||||
|
@ -65,6 +66,7 @@ func TestCodec9286UserComment_Decode(t *testing.T) {
|
|||
}
|
||||
|
||||
addressableBytes := encoded
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableBytes)
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
|
@ -72,7 +74,7 @@ func TestCodec9286UserComment_Decode(t *testing.T) {
|
|||
uint32(len(encoded)),
|
||||
0,
|
||||
nil,
|
||||
addressableBytes,
|
||||
sb,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-utility/filesystem"
|
||||
|
||||
"github.com/dsoprea/go-exif/v2/common"
|
||||
)
|
||||
|
@ -48,6 +49,7 @@ func TestCodecA000FlashpixVersion_Decode(t *testing.T) {
|
|||
encoded := []byte(versionPhrase)
|
||||
|
||||
addressableBytes := encoded
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableBytes)
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
|
@ -55,7 +57,7 @@ func TestCodecA000FlashpixVersion_Decode(t *testing.T) {
|
|||
uint32(len(encoded)),
|
||||
0,
|
||||
nil,
|
||||
addressableBytes,
|
||||
sb,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-utility/filesystem"
|
||||
|
||||
"github.com/dsoprea/go-exif/v2/common"
|
||||
)
|
||||
|
@ -82,6 +83,7 @@ func TestCodecA20CSpatialFrequencyResponse_Decode(t *testing.T) {
|
|||
}
|
||||
|
||||
addressableBytes := encoded
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableBytes)
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
|
@ -89,7 +91,7 @@ func TestCodecA20CSpatialFrequencyResponse_Decode(t *testing.T) {
|
|||
uint32(len(encoded)),
|
||||
0,
|
||||
nil,
|
||||
addressableBytes,
|
||||
sb,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
|
|
|
@ -5,8 +5,10 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-exif/v2/common"
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-utility/filesystem"
|
||||
|
||||
"github.com/dsoprea/go-exif/v2/common"
|
||||
)
|
||||
|
||||
func TestTagA302CfaPattern_String(t *testing.T) {
|
||||
|
@ -63,7 +65,8 @@ func TestCodecA302CfaPattern_Decode(t *testing.T) {
|
|||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
|
||||
}
|
||||
|
||||
addressableData := encoded
|
||||
addressableBytes := encoded
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableBytes)
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
|
@ -71,7 +74,7 @@ func TestCodecA302CfaPattern_Decode(t *testing.T) {
|
|||
uint32(len(encoded)),
|
||||
0,
|
||||
nil,
|
||||
addressableData,
|
||||
sb,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package exif
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
@ -151,7 +152,8 @@ func GetFlatExifData(exifData []byte) (exifTags []ExifTag, err error) {
|
|||
im := NewIfdMappingWithStandard()
|
||||
ti := NewTagIndex()
|
||||
|
||||
ie := NewIfdEnumerate(im, ti, exifData, eh.ByteOrder)
|
||||
ebs := NewExifReadSeekerWithBytes(exifData)
|
||||
ie := NewIfdEnumerate(im, ti, ebs, eh.ByteOrder)
|
||||
|
||||
exifTags = make([]ExifTag, 0)
|
||||
|
||||
|
@ -232,3 +234,11 @@ func GpsDegreesEquals(gi1, gi2 GpsDegrees) bool {
|
|||
func IsTime(v interface{}) bool {
|
||||
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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue