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
}
err = e.Parse(data[foundAt:], visitor)
err = e.Visit(data[foundAt:], visitor)
log.PanicIf(err)
```

View File

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

38
exif.go
View File

@ -11,7 +11,11 @@ import (
var (
exifLogger = log.NewLogger("exif.exif")
)
var (
ErrNotExif = errors.New("not exif data")
ErrExifHeaderError = errors.New("exif header error")
)
type Exif struct {
@ -30,7 +34,13 @@ func (e *Exif) IsExif(data []byte) (ok bool) {
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() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
@ -57,8 +67,8 @@ func (e *Exif) Parse(data []byte, visitor TagVisitor) (err error) {
fixedBytes := data[8:10]
if fixedBytes[0] != 0x2a || fixedBytes[1] != 0x00 {
exifLogger.Warningf(nil, "EXIF app-data header fixed-bytes should be 0x002a but are: [%v]", fixedBytes)
return nil
exifLogger.Warningf(nil, "EXIF header fixed-bytes should be 0x002a but are: [%v]", fixedBytes)
log.Panic(ErrExifHeaderError)
}
firstIfdOffset := uint32(0)
@ -68,9 +78,27 @@ func (e *Exif) Parse(data []byte, visitor TagVisitor) (err error) {
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)
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() {
if state := recover(); state != nil {
err := log.Wrap(state.(error))
@ -113,7 +113,7 @@ func TestParse(t *testing.T) {
return nil
}
err = e.Parse(data[foundAt:], visitor)
err = e.Visit(data[foundAt:], visitor)
log.PanicIf(err)
// 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).
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.
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() {
if state := recover(); state != nil {
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)
entries = make([]IfdTagEntry, tagCount)
for i := uint16(0); i < tagCount; i++ {
tagId, _, err := ite.getUint16()
log.PanicIf(err)
@ -182,13 +196,28 @@ func (ie *IfdEnumerate) parseIfd(ifdName string, ifdIndex int, ifdOffset uint32,
log.PanicIf(err)
}
tag := IfdTagEntry{
TagId: tagId,
TagIndex: int(i),
TagType: tagType,
UnitCount: unitCount,
ValueOffset: valueOffset,
RawValueOffset: rawValueOffset,
}
childIfdName, isIfd := IsIfdTag(tagId)
if isIfd == true {
ifdLogger.Debugf(nil, "Descending to IFD [%s].", childIfdName)
tag.IsIfd = true
err := ie.Scan(childIfdName, valueOffset, visitor)
log.PanicIf(err)
if doDescend == true {
ifdLogger.Debugf(nil, "Descending to IFD [%s].", childIfdName)
err := ie.Scan(childIfdName, valueOffset, visitor)
log.PanicIf(err)
}
}
entries[i] = tag
}
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)
return nextIfdOffset, nil
return nextIfdOffset, entries, nil
}
// 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++ {
nextIfdOffset, err := ie.parseIfd(ifdName, ifdIndex, ifdOffset, visitor)
nextIfdOffset, _, err := ie.ParseIfd(ifdName, ifdIndex, ifdOffset, visitor, true)
log.PanicIf(err)
if nextIfdOffset == 0 {