ifd_enumerate: Refactored for reusability from a collector loop.

pull/3/head
Dustin Oprea 2018-04-18 06:28:12 -04:00
parent 33e3f2e4eb
commit acbda6d1e1
5 changed files with 73 additions and 16 deletions

View File

@ -126,7 +126,7 @@ visitor := func(indexedIfdName string, tagId uint16, tagType exif.TagType, value
return nil return nil
} }
err = e.Parse(data[foundAt:], visitor) err = e.Visit(data[foundAt:], visitor)
log.PanicIf(err) log.PanicIf(err)
``` ```

View File

@ -93,6 +93,6 @@ func main() {
return nil return nil
} }
err = e.Parse(data[foundAt:], visitor) err = e.Visit(data[foundAt:], visitor)
log.PanicIf(err) log.PanicIf(err)
} }

38
exif.go
View File

@ -11,7 +11,11 @@ import (
var ( var (
exifLogger = log.NewLogger("exif.exif") exifLogger = log.NewLogger("exif.exif")
)
var (
ErrNotExif = errors.New("not exif data") ErrNotExif = errors.New("not exif data")
ErrExifHeaderError = errors.New("exif header error")
) )
type Exif struct { type Exif struct {
@ -30,7 +34,13 @@ func (e *Exif) IsExif(data []byte) (ok bool) {
return false return false
} }
func (e *Exif) Parse(data []byte, visitor TagVisitor) (err error) {
type ExifHeader struct {
ByteOrder binary.ByteOrder
FirstIfdOffset uint32
}
func (e *Exif) ParseExifHeader(data []byte) (eh ExifHeader, 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))
@ -57,8 +67,8 @@ func (e *Exif) Parse(data []byte, visitor TagVisitor) (err error) {
fixedBytes := data[8:10] fixedBytes := data[8:10]
if fixedBytes[0] != 0x2a || fixedBytes[1] != 0x00 { if fixedBytes[0] != 0x2a || fixedBytes[1] != 0x00 {
exifLogger.Warningf(nil, "EXIF app-data header fixed-bytes should be 0x002a but are: [%v]", fixedBytes) exifLogger.Warningf(nil, "EXIF header fixed-bytes should be 0x002a but are: [%v]", fixedBytes)
return nil log.Panic(ErrExifHeaderError)
} }
firstIfdOffset := uint32(0) firstIfdOffset := uint32(0)
@ -68,9 +78,27 @@ func (e *Exif) Parse(data []byte, visitor TagVisitor) (err error) {
firstIfdOffset = binary.LittleEndian.Uint32(data[10:14]) firstIfdOffset = binary.LittleEndian.Uint32(data[10:14])
} }
ie := NewIfdEnumerate(data, byteOrder) eh = ExifHeader{
ByteOrder: byteOrder,
FirstIfdOffset: firstIfdOffset,
}
err = ie.Scan(IfdStandard, firstIfdOffset, visitor) return eh, nil
}
func (e *Exif) Visit(data []byte, visitor TagVisitor) (err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
eh, err := e.ParseExifHeader(data)
log.PanicIf(err)
ie := NewIfdEnumerate(data, eh.ByteOrder)
err = ie.Scan(IfdStandard, eh.FirstIfdOffset, visitor)
log.PanicIf(err) log.PanicIf(err)
return nil return nil

View File

@ -33,7 +33,7 @@ func TestIsExif_False(t *testing.T) {
} }
} }
func TestParse(t *testing.T) { func TestVisit(t *testing.T) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
err := log.Wrap(state.(error)) err := log.Wrap(state.(error))
@ -113,7 +113,7 @@ func TestParse(t *testing.T) {
return nil return nil
} }
err = e.Parse(data[foundAt:], visitor) err = e.Visit(data[foundAt:], visitor)
log.PanicIf(err) log.PanicIf(err)
// for _, line := range tags { // for _, line := range tags {

View File

@ -124,9 +124,21 @@ func (ie *IfdEnumerate) getTagEnumerator(ifdOffset uint32) (ite *IfdTagEnumerato
// the offsets of all IFDs and values are calculated from). // the offsets of all IFDs and values are calculated from).
type TagVisitor func(indexedIfdName string, tagId uint16, tagType TagType, valueContext ValueContext) (err error) type TagVisitor func(indexedIfdName string, tagId uint16, tagType TagType, valueContext ValueContext) (err error)
// parseIfd decodes the IFD block that we're currently sitting on the first
type IfdTagEntry struct {
TagId uint16
TagIndex int
TagType uint16
UnitCount uint32
ValueOffset uint32
RawValueOffset []byte
IsIfd bool
}
// ParseIfd decodes the IFD block that we're currently sitting on the first
// byte of. // byte of.
func (ie *IfdEnumerate) parseIfd(ifdName string, ifdIndex int, ifdOffset uint32, visitor TagVisitor) (nextIfdOffset uint32, err error) { func (ie *IfdEnumerate) ParseIfd(ifdName string, ifdIndex int, ifdOffset uint32, visitor TagVisitor, doDescend bool) (nextIfdOffset uint32, entries []IfdTagEntry, 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))
@ -155,6 +167,8 @@ func (ie *IfdEnumerate) parseIfd(ifdName string, ifdIndex int, ifdOffset uint32,
ifdLogger.Debugf(nil, "Current IFD tag-count: (%d)", tagCount) ifdLogger.Debugf(nil, "Current IFD tag-count: (%d)", tagCount)
entries = make([]IfdTagEntry, tagCount)
for i := uint16(0); i < tagCount; i++ { for i := uint16(0); i < tagCount; i++ {
tagId, _, err := ite.getUint16() tagId, _, err := ite.getUint16()
log.PanicIf(err) log.PanicIf(err)
@ -182,13 +196,28 @@ func (ie *IfdEnumerate) parseIfd(ifdName string, ifdIndex int, ifdOffset uint32,
log.PanicIf(err) log.PanicIf(err)
} }
tag := IfdTagEntry{
TagId: tagId,
TagIndex: int(i),
TagType: tagType,
UnitCount: unitCount,
ValueOffset: valueOffset,
RawValueOffset: rawValueOffset,
}
childIfdName, isIfd := IsIfdTag(tagId) childIfdName, isIfd := IsIfdTag(tagId)
if isIfd == true { if isIfd == true {
ifdLogger.Debugf(nil, "Descending to IFD [%s].", childIfdName) tag.IsIfd = true
err := ie.Scan(childIfdName, valueOffset, visitor) if doDescend == true {
log.PanicIf(err) ifdLogger.Debugf(nil, "Descending to IFD [%s].", childIfdName)
err := ie.Scan(childIfdName, valueOffset, visitor)
log.PanicIf(err)
}
} }
entries[i] = tag
} }
nextIfdOffset, _, err = ite.getUint32() nextIfdOffset, _, err = ite.getUint32()
@ -196,7 +225,7 @@ func (ie *IfdEnumerate) parseIfd(ifdName string, ifdIndex int, ifdOffset uint32,
ifdLogger.Debugf(nil, "Next IFD at offset: (%08x)", nextIfdOffset) ifdLogger.Debugf(nil, "Next IFD at offset: (%08x)", nextIfdOffset)
return nextIfdOffset, nil return nextIfdOffset, entries, nil
} }
// Scan enumerates the different EXIF blocks (called IFDs). // Scan enumerates the different EXIF blocks (called IFDs).
@ -208,7 +237,7 @@ func (ie *IfdEnumerate) Scan(ifdName string, ifdOffset uint32, visitor TagVisito
}() }()
for ifdIndex := 0;; ifdIndex++ { for ifdIndex := 0;; ifdIndex++ {
nextIfdOffset, err := ie.parseIfd(ifdName, ifdIndex, ifdOffset, visitor) nextIfdOffset, _, err := ie.ParseIfd(ifdName, ifdIndex, ifdOffset, visitor, true)
log.PanicIf(err) log.PanicIf(err)
if nextIfdOffset == 0 { if nextIfdOffset == 0 {