ifd_builder_encode: Bugfixed next-IFD offsets.

- Affected sibling IFDs.
This commit is contained in:
Dustin Oprea 2018-05-05 02:01:18 -04:00
parent 887842e85a
commit 6c71ccf651
2 changed files with 86 additions and 166 deletions

View File

@ -2,7 +2,6 @@ package exif
import ( import (
"bytes" "bytes"
// "fmt"
"encoding/binary" "encoding/binary"
@ -288,15 +287,18 @@ func (ibe *IfdByteEncoder) encodeIfdToBytes(ib *IfdBuilder, ifdAddressableOffset
// N the link from this IFD to the next IFD that will be written in the // N the link from this IFD to the next IFD that will be written in the
// next cycle. // next cycle.
if setNextIb == true { if setNextIb == true {
nextIfdOffsetToWrite += dataSize // Write address of next IFD in chain. This will be the original
// fmt.Printf("SETTING NEXT-IFD FOR %s TO: (0x%04x)\n", ib.ii, nextIfdOffsetToWrite) // allocation offset plus the size of everything we have allocated for
} else { // this IFD and its child-IFDs.
nextIfdOffsetToWrite = 0
}
// Write address of next IFD in chain. offset := ifdAddressableOffset + dataSize
err = bw.WriteUint32(nextIfdOffsetToWrite)
log.PanicIf(err) err := bw.WriteUint32(offset)
log.PanicIf(err)
} else {
err := bw.WriteUint32(0)
log.PanicIf(err)
}
_, err = b.Write(dataBytes) _, err = b.Write(dataBytes)
log.PanicIf(err) log.PanicIf(err)
@ -336,8 +338,6 @@ func (ibe *IfdByteEncoder) encodeAndAttachIfd(ib *IfdBuilder, ifdAddressableOffs
for thisIb := ib; thisIb != nil; thisIb = thisIb.nextIb { for thisIb := ib; thisIb != nil; thisIb = thisIb.nextIb {
// Do a dry-run in order to pre-determine its size requirement. // Do a dry-run in order to pre-determine its size requirement.
// fmt.Printf("BUILDING IFD: %s ifdAddressableOffset=(0x%04x)\n", ib.ii, ifdAddressableOffset)
_, tableSize, allocatedDataSize, _, err := ibe.encodeIfdToBytes(ib, ifdAddressableOffset, 0, false) _, tableSize, allocatedDataSize, _, err := ibe.encodeIfdToBytes(ib, ifdAddressableOffset, 0, false)
log.PanicIf(err) log.PanicIf(err)

View File

@ -5,6 +5,7 @@ import (
"bytes" "bytes"
"reflect" "reflect"
"fmt" "fmt"
"strings"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
) )
@ -793,18 +794,18 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
log.PanicIf(err) log.PanicIf(err)
// // Link to another IB (sibling relationship). The root/standard IFD may // Link to another IB (sibling relationship). The root/standard IFD may
// // occur twice in some JPEGs (for thumbnail or FlashPix images). // occur twice in some JPEGs (for thumbnail or FlashPix images).
// nextIb := NewIfdBuilder(RootIi, TestDefaultByteOrder) nextIb := NewIfdBuilder(RootIi, TestDefaultByteOrder)
// err = nextIb.AddFromConfig(0x0101, []uint32 { 0x11223344 }) err = nextIb.AddFromConfig(0x0101, []uint32 { 0x11223344 })
// log.PanicIf(err) log.PanicIf(err)
// err = nextIb.AddFromConfig(0x0102, []uint16 { 0x5566 }) err = nextIb.AddFromConfig(0x0102, []uint16 { 0x5566 })
// log.PanicIf(err) log.PanicIf(err)
// ib.SetNextIb(nextIb) ib.SetNextIb(nextIb)
// Encode. // Encode.
@ -824,184 +825,103 @@ func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
tagsDump := index.RootIfd.DumpTree() tagsDump := index.RootIfd.DumpTree()
expected := []string { actual := strings.Join(tagsDump, "\n")
"[ROOT]->[IFD] (0x000b)",
"[ROOT]->[IFD] (0x00ff)",
"[ROOT]->[IFD] (0x8769)",
"[IFD]->[Exif] (0x8827)",
"[IFD]->[Exif] (0x8833)",
"[ROOT]->[IFD] (0x0100)",
"[ROOT]->[IFD] (0x8825)",
"[IFD]->[GPSInfo] (0x0005)",
"[ROOT]->[IFD] (0x013e)",
}
if reflect.DeepEqual(tagsDump, expected) != true { expected :=
`> IFD [ROOT]->[IFD]:(0) TOP
- (0x000b)
- (0x00ff)
- (0x8769)
> IFD [IFD]->[Exif]:(0) TOP
- (0x8827)
- (0x8833)
< IFD [IFD]->[Exif]:(0) BOTTOM
- (0x0100)
- (0x8825)
> IFD [IFD]->[GPSInfo]:(0) TOP
- (0x0005)
< IFD [IFD]->[GPSInfo]:(0) BOTTOM
- (0x013e)
< IFD [ROOT]->[IFD]:(0) BOTTOM
* LINKING TO SIBLING IFD [IFD]:(1)
> IFD [ROOT]->[IFD]:(1) TOP
- (0x8827)
- (0x8833)
< IFD [ROOT]->[IFD]:(1) BOTTOM`
if actual != expected {
fmt.Printf("\n") fmt.Printf("\n")
fmt.Printf("Actual:\n") fmt.Printf("Actual:\n")
fmt.Printf("\n") fmt.Printf("\n")
fmt.Printf("%s\n", actual)
for i, line := range tagsDump {
fmt.Printf("%d: %s\n", i, line)
}
fmt.Printf("\n") fmt.Printf("\n")
fmt.Printf("Expected:\n") fmt.Printf("Expected:\n")
fmt.Printf("\n") fmt.Printf("\n")
fmt.Printf("%s\n", expected)
for i, line := range expected {
fmt.Printf("%d: %s\n", i, line)
}
fmt.Printf("\n") fmt.Printf("\n")
t.Fatalf("IFD hierarchy not correct.") t.Fatalf("IFD hierarchy not correct.")
} }
} }
// func ExampleIfdByteEncoder_EncodeToExif() { func ExampleIfdByteEncoder_EncodeToExif() {
// // Construct an IFD. // Construct an IFD.
// ib := NewIfdBuilder(RootIi, EncodeDefaultByteOrder) ib := NewIfdBuilder(RootIi, EncodeDefaultByteOrder)
// err := ib.AddFromConfigWithName("ProcessingSoftware", "asciivalue") err := ib.AddFromConfigWithName("ProcessingSoftware", "asciivalue")
// log.PanicIf(err) log.PanicIf(err)
// err = ib.AddFromConfigWithName("DotRange", []uint8 { 0x11 }) err = ib.AddFromConfigWithName("DotRange", []uint8 { 0x11 })
// log.PanicIf(err) log.PanicIf(err)
// err = ib.AddFromConfigWithName("SubfileType", []uint16 { 0x2233 }) err = ib.AddFromConfigWithName("SubfileType", []uint16 { 0x2233 })
// log.PanicIf(err) log.PanicIf(err)
// err = ib.AddFromConfigWithName("ImageWidth", []uint32 { 0x44556677 }) err = ib.AddFromConfigWithName("ImageWidth", []uint32 { 0x44556677 })
// log.PanicIf(err) log.PanicIf(err)
// err = ib.AddFromConfigWithName("WhitePoint", []Rational { { Numerator: 0x11112222, Denominator: 0x33334444 } }) err = ib.AddFromConfigWithName("WhitePoint", []Rational { { Numerator: 0x11112222, Denominator: 0x33334444 } })
// log.PanicIf(err) log.PanicIf(err)
// err = ib.AddFromConfigWithName("ShutterSpeedValue", []SignedRational { { Numerator: 0x11112222, Denominator: 0x33334444 } }) err = ib.AddFromConfigWithName("ShutterSpeedValue", []SignedRational { { Numerator: 0x11112222, Denominator: 0x33334444 } })
// log.PanicIf(err) log.PanicIf(err)
// // Encode it. // Encode it.
// ibe := NewIfdByteEncoder() ibe := NewIfdByteEncoder()
// exifData, err := ibe.EncodeToExif(ib) exifData, err := ibe.EncodeToExif(ib)
// log.PanicIf(err) log.PanicIf(err)
// // Parse it so we can see it. // Parse it so we can see it.
// e := NewExif() e := NewExif()
// _, index, err := e.Collect(exifData) _, index, err := e.Collect(exifData)
// log.PanicIf(err) log.PanicIf(err)
// // addressableData is the byte-slice where the allocated data can be // addressableData is the byte-slice where the allocated data can be
// // resolved (where position 0x0 will correlate with offset 0x0). // resolved (where position 0x0 will correlate with offset 0x0).
// addressableData := exifData[ExifAddressableAreaStart:] addressableData := exifData[ExifAddressableAreaStart:]
// for i, e := range index.RootIfd.Entries { for i, e := range index.RootIfd.Entries {
// value, err := e.Value(addressableData, EncodeDefaultByteOrder) value, err := e.Value(addressableData, EncodeDefaultByteOrder)
// log.PanicIf(err) log.PanicIf(err)
// fmt.Printf("%d: %s [%v]\n", i, e, value) fmt.Printf("%d: %s [%v]\n", i, e, value)
// } }
// // Output: // Output:
// // //
// // 0: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0b) TAG-TYPE=[ASCII] UNIT-COUNT=(11)> [asciivalue] // 0: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0b) TAG-TYPE=[ASCII] UNIT-COUNT=(11)> [asciivalue]
// // 1: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x150) TAG-TYPE=[BYTE] UNIT-COUNT=(1)> [[17]] // 1: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x150) TAG-TYPE=[BYTE] UNIT-COUNT=(1)> [[17]]
// // 2: IfdTagEntry<TAG-IFD=[] TAG-ID=(0xff) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> [[8755]] // 2: IfdTagEntry<TAG-IFD=[] TAG-ID=(0xff) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> [[8755]]
// // 3: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x100) TAG-TYPE=[LONG] UNIT-COUNT=(1)> [[1146447479]] // 3: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x100) TAG-TYPE=[LONG] UNIT-COUNT=(1)> [[1146447479]]
// // 4: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x13e) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> [[{286335522 858997828}]] // 4: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x13e) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> [[{286335522 858997828}]]
// // 5: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x9201) TAG-TYPE=[SRATIONAL] UNIT-COUNT=(1)> [[{286335522 858997828}]] // 5: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x9201) TAG-TYPE=[SRATIONAL] UNIT-COUNT=(1)> [[{286335522 858997828}]]
// } }
// func ExampleIfdByteEncoder_EncodeToExif_WithChild() {
// // Construct an IFD.
// ib := NewIfdBuilder(RootIi, EncodeDefaultByteOrder)
// err := ib.AddFromConfigWithName("ProcessingSoftware", "asciivalue")
// log.PanicIf(err)
// err = ib.AddFromConfigWithName("DotRange", []uint8 { 0x11 })
// log.PanicIf(err)
// err = ib.AddFromConfigWithName("SubfileType", []uint16 { 0x2233 })
// log.PanicIf(err)
// // Add a child IB right in the middle.
// childIb := NewIfdBuilder(ExifIi, EncodeDefaultByteOrder)
// err = childIb.AddFromConfigWithName("ISOSpeedRatings", []uint16 { 0x1122 })
// log.PanicIf(err)
// err = childIb.AddFromConfigWithName("ISOSpeed", []uint32 { 0x33445566 })
// log.PanicIf(err)
// err = ib.AddChildIb(childIb)
// log.PanicIf(err)
// err = ib.AddFromConfigWithName("ImageWidth", []uint32 { 0x44556677 })
// log.PanicIf(err)
// err = ib.AddFromConfigWithName("WhitePoint", []Rational { { Numerator: 0x11112222, Denominator: 0x33334444 } })
// log.PanicIf(err)
// err = ib.AddFromConfigWithName("ShutterSpeedValue", []SignedRational { { Numerator: 0x11112222, Denominator: 0x33334444 } })
// log.PanicIf(err)
// // Encode it.
// ibe := NewIfdByteEncoder()
// exifData, err := ibe.EncodeToExif(ib)
// log.PanicIf(err)
// // Parse it so we can see it.
// e := NewExif()
// _, index, err := e.Collect(exifData)
// log.PanicIf(err)
// // addressableData is the byte-slice where the allocated data can be
// // resolved (where position 0x0 will correlate with offset 0x0).
// addressableData := exifData[ExifAddressableAreaStart:]
// for i, e := range index.RootIfd.Entries {
// value, err := e.Value(addressableData, EncodeDefaultByteOrder)
// log.PanicIf(err)
// fmt.Printf("%d: %s %v\n", i, e, value)
// }
// // Output:
// //
// // 0: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0b) TAG-TYPE=[ASCII] UNIT-COUNT=(11)> asciivalue
// // 1: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x150) TAG-TYPE=[BYTE] UNIT-COUNT=(1)> [17]
// // 2: IfdTagEntry<TAG-IFD=[] TAG-ID=(0xff) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> [8755]
// // 3: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x100) TAG-TYPE=[LONG] UNIT-COUNT=(1)> [1146447479]
// // 4: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x13e) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> [{286335522 858997828}]
// // 5: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x9201) TAG-TYPE=[SRATIONAL] UNIT-COUNT=(1)> [{286335522 858997828}]
// }
// TODO(dustin): !! Write test with both chained and child IFDs