mirror of https://github.com/dsoprea/go-exif.git
ifd_enumerate.go: Rename IfdTagEnumerator to byteParser
It's more accurate, and no longer exported.dustin/add_skipped_tags_tracking
parent
5fdad87477
commit
416fd86ecd
|
@ -65,56 +65,60 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// IfdTagEnumerator knows how to decode an IFD and all of the tags it
|
// byteParser knows how to decode an IFD and all of the tags it
|
||||||
// describes.
|
// describes.
|
||||||
//
|
//
|
||||||
// The IFDs and the actual values can float throughout the EXIF block, but the
|
// The IFDs and the actual values can float throughout the EXIF block, but the
|
||||||
// IFD itself is just a minor header followed by a set of repeating,
|
// IFD itself is just a minor header followed by a set of repeating,
|
||||||
// statically-sized records. So, the tags (though notnecessarily their values)
|
// statically-sized records. So, the tags (though notnecessarily their values)
|
||||||
// are fairly simple to enumerate.
|
// are fairly simple to enumerate.
|
||||||
type IfdTagEnumerator struct {
|
type byteParser struct {
|
||||||
byteOrder binary.ByteOrder
|
byteOrder binary.ByteOrder
|
||||||
addressableData []byte
|
addressableData []byte
|
||||||
ifdOffset uint32
|
ifdOffset uint32
|
||||||
buffer *bytes.Buffer
|
buffer *bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIfdTagEnumerator(addressableData []byte, byteOrder binary.ByteOrder, ifdOffset uint32) (enumerator *IfdTagEnumerator, err error) {
|
func newByteParser(addressableData []byte, byteOrder binary.ByteOrder, ifdOffset uint32) (bp *byteParser, err error) {
|
||||||
if ifdOffset >= uint32(len(addressableData)) {
|
if ifdOffset >= uint32(len(addressableData)) {
|
||||||
return nil, ErrOffsetInvalid
|
return nil, ErrOffsetInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
enumerator = &IfdTagEnumerator{
|
// TODO(dustin): Add test
|
||||||
|
|
||||||
|
bp = &byteParser{
|
||||||
addressableData: addressableData,
|
addressableData: addressableData,
|
||||||
byteOrder: byteOrder,
|
byteOrder: byteOrder,
|
||||||
buffer: bytes.NewBuffer(addressableData[ifdOffset:]),
|
buffer: bytes.NewBuffer(addressableData[ifdOffset:]),
|
||||||
}
|
}
|
||||||
|
|
||||||
return enumerator, nil
|
return bp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getUint16 reads a uint16 and advances both our current and our current
|
// getUint16 reads a uint16 and advances both our current and our current
|
||||||
// accumulator (which allows us to know how far to seek to the beginning of the
|
// accumulator (which allows us to know how far to seek to the beginning of the
|
||||||
// next IFD when it's time to jump).
|
// next IFD when it's time to jump).
|
||||||
func (ife *IfdTagEnumerator) getUint16() (value uint16, raw []byte, err error) {
|
func (bp *byteParser) getUint16() (value uint16, raw []byte, 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))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// TODO(dustin): Add test
|
||||||
|
|
||||||
needBytes := 2
|
needBytes := 2
|
||||||
offset := 0
|
offset := 0
|
||||||
raw = make([]byte, needBytes)
|
raw = make([]byte, needBytes)
|
||||||
|
|
||||||
for offset < needBytes {
|
for offset < needBytes {
|
||||||
n, err := ife.buffer.Read(raw[offset:])
|
n, err := bp.buffer.Read(raw[offset:])
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
offset += n
|
offset += n
|
||||||
}
|
}
|
||||||
|
|
||||||
value = ife.byteOrder.Uint16(raw)
|
value = bp.byteOrder.Uint16(raw)
|
||||||
|
|
||||||
return value, raw, nil
|
return value, raw, nil
|
||||||
}
|
}
|
||||||
|
@ -122,25 +126,27 @@ func (ife *IfdTagEnumerator) getUint16() (value uint16, raw []byte, err error) {
|
||||||
// getUint32 reads a uint32 and advances both our current and our current
|
// getUint32 reads a uint32 and advances both our current and our current
|
||||||
// accumulator (which allows us to know how far to seek to the beginning of the
|
// accumulator (which allows us to know how far to seek to the beginning of the
|
||||||
// next IFD when it's time to jump).
|
// next IFD when it's time to jump).
|
||||||
func (ife *IfdTagEnumerator) getUint32() (value uint32, raw []byte, err error) {
|
func (bp *byteParser) getUint32() (value uint32, raw []byte, 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))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// TODO(dustin): Add test
|
||||||
|
|
||||||
needBytes := 4
|
needBytes := 4
|
||||||
offset := 0
|
offset := 0
|
||||||
raw = make([]byte, needBytes)
|
raw = make([]byte, needBytes)
|
||||||
|
|
||||||
for offset < needBytes {
|
for offset < needBytes {
|
||||||
n, err := ife.buffer.Read(raw[offset:])
|
n, err := bp.buffer.Read(raw[offset:])
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
offset += n
|
offset += n
|
||||||
}
|
}
|
||||||
|
|
||||||
value = ife.byteOrder.Uint32(raw)
|
value = bp.byteOrder.Uint32(raw)
|
||||||
|
|
||||||
return value, raw, nil
|
return value, raw, nil
|
||||||
}
|
}
|
||||||
|
@ -163,15 +169,15 @@ func NewIfdEnumerate(ifdMapping *IfdMapping, tagIndex *TagIndex, exifData []byte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ie *IfdEnumerate) getTagEnumerator(ifdOffset uint32) (enumerator *IfdTagEnumerator, err error) {
|
func (ie *IfdEnumerate) getByteParser(ifdOffset uint32) (bp *byteParser, 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))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
enumerator, err =
|
bp, err =
|
||||||
NewIfdTagEnumerator(
|
newByteParser(
|
||||||
ie.exifData[ExifAddressableAreaStart:],
|
ie.exifData[ExifAddressableAreaStart:],
|
||||||
ie.byteOrder,
|
ie.byteOrder,
|
||||||
ifdOffset)
|
ifdOffset)
|
||||||
|
@ -184,28 +190,28 @@ func (ie *IfdEnumerate) getTagEnumerator(ifdOffset uint32) (enumerator *IfdTagEn
|
||||||
log.Panic(err)
|
log.Panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return enumerator, nil
|
return bp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ie *IfdEnumerate) parseTag(fqIfdPath string, tagPosition int, enumerator *IfdTagEnumerator) (ite *IfdTagEntry, err error) {
|
func (ie *IfdEnumerate) parseTag(fqIfdPath string, tagPosition int, bp *byteParser) (ite *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))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
tagId, _, err := enumerator.getUint16()
|
tagId, _, err := bp.getUint16()
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
tagTypeRaw, _, err := enumerator.getUint16()
|
tagTypeRaw, _, err := bp.getUint16()
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
tagType := exifcommon.TagTypePrimitive(tagTypeRaw)
|
tagType := exifcommon.TagTypePrimitive(tagTypeRaw)
|
||||||
|
|
||||||
unitCount, _, err := enumerator.getUint32()
|
unitCount, _, err := bp.getUint32()
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
valueOffset, rawValueOffset, err := enumerator.getUint32()
|
valueOffset, rawValueOffset, err := bp.getUint32()
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
if tagType.IsValid() == false {
|
if tagType.IsValid() == false {
|
||||||
|
@ -254,14 +260,14 @@ type TagVisitorFn func(fqIfdPath string, ifdIndex int, ite *IfdTagEntry) (err er
|
||||||
|
|
||||||
// ParseIfd decodes the IFD block that we're currently sitting on the first
|
// ParseIfd decodes the IFD block that we're currently sitting on the first
|
||||||
// byte of.
|
// byte of.
|
||||||
func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, enumerator *IfdTagEnumerator, visitor TagVisitorFn, doDescend bool) (nextIfdOffset uint32, entries []*IfdTagEntry, thumbnailData []byte, err error) {
|
func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, bp *byteParser, visitor TagVisitorFn, doDescend bool) (nextIfdOffset uint32, entries []*IfdTagEntry, thumbnailData []byte, 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))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
tagCount, _, err := enumerator.getUint16()
|
tagCount, _, err := bp.getUint16()
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
ifdEnumerateLogger.Debugf(nil, "Current IFD tag-count: (%d)", tagCount)
|
ifdEnumerateLogger.Debugf(nil, "Current IFD tag-count: (%d)", tagCount)
|
||||||
|
@ -272,7 +278,7 @@ func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, enumerator *Ifd
|
||||||
var enumeratorThumbnailSize *IfdTagEntry
|
var enumeratorThumbnailSize *IfdTagEntry
|
||||||
|
|
||||||
for i := 0; i < int(tagCount); i++ {
|
for i := 0; i < int(tagCount); i++ {
|
||||||
ite, err := ie.parseTag(fqIfdPath, i, enumerator)
|
ite, err := ie.parseTag(fqIfdPath, i, bp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if log.Is(err, ErrTagTypeNotValid) == true {
|
if log.Is(err, ErrTagTypeNotValid) == true {
|
||||||
ifdEnumerateLogger.Warningf(nil, "Tag in IFD [%s] at position (%d) has invalid type (%d) and will be skipped.", fqIfdPath, i, ite.tagType)
|
ifdEnumerateLogger.Warningf(nil, "Tag in IFD [%s] at position (%d) has invalid type (%d) and will be skipped.", fqIfdPath, i, ite.tagType)
|
||||||
|
@ -317,7 +323,7 @@ func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, enumerator *Ifd
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
nextIfdOffset, _, err = enumerator.getUint32()
|
nextIfdOffset, _, err = bp.getUint32()
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
ifdEnumerateLogger.Debugf(nil, "Next IFD at offset: (%08x)", nextIfdOffset)
|
ifdEnumerateLogger.Debugf(nil, "Next IFD at offset: (%08x)", nextIfdOffset)
|
||||||
|
@ -365,7 +371,7 @@ func (ie *IfdEnumerate) scan(fqIfdName string, ifdOffset uint32, visitor TagVisi
|
||||||
for ifdIndex := 0; ; ifdIndex++ {
|
for ifdIndex := 0; ; ifdIndex++ {
|
||||||
ifdEnumerateLogger.Debugf(nil, "Parsing IFD [%s] (%d) at offset (0x%04x) (scan).", fqIfdName, ifdIndex, ifdOffset)
|
ifdEnumerateLogger.Debugf(nil, "Parsing IFD [%s] (%d) at offset (0x%04x) (scan).", fqIfdName, ifdIndex, ifdOffset)
|
||||||
|
|
||||||
enumerator, err := ie.getTagEnumerator(ifdOffset)
|
bp, err := ie.getByteParser(ifdOffset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == ErrOffsetInvalid {
|
if err == ErrOffsetInvalid {
|
||||||
ifdEnumerateLogger.Errorf(nil, nil, "IFD [%s] (%d) at offset (0x%04x) is unreachable. Terminating scan.", fqIfdName, ifdIndex, ifdOffset)
|
ifdEnumerateLogger.Errorf(nil, nil, "IFD [%s] (%d) at offset (0x%04x) is unreachable. Terminating scan.", fqIfdName, ifdIndex, ifdOffset)
|
||||||
|
@ -375,7 +381,7 @@ func (ie *IfdEnumerate) scan(fqIfdName string, ifdOffset uint32, visitor TagVisi
|
||||||
log.Panic(err)
|
log.Panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
nextIfdOffset, _, _, err := ie.ParseIfd(fqIfdName, ifdIndex, enumerator, visitor, true)
|
nextIfdOffset, _, _, err := ie.ParseIfd(fqIfdName, ifdIndex, bp, visitor, true)
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
if nextIfdOffset == 0 {
|
if nextIfdOffset == 0 {
|
||||||
|
@ -994,7 +1000,7 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32) (index IfdIndex, err error
|
||||||
|
|
||||||
ifdEnumerateLogger.Debugf(nil, "Parsing IFD [%s] (%d) at offset (0x%04x) (Collect).", ifdPath, currentIndex, offset)
|
ifdEnumerateLogger.Debugf(nil, "Parsing IFD [%s] (%d) at offset (0x%04x) (Collect).", ifdPath, currentIndex, offset)
|
||||||
|
|
||||||
enumerator, err := ie.getTagEnumerator(offset)
|
bp, err := ie.getByteParser(offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == ErrOffsetInvalid {
|
if err == ErrOffsetInvalid {
|
||||||
return index, err
|
return index, err
|
||||||
|
@ -1003,7 +1009,7 @@ func (ie *IfdEnumerate) Collect(rootIfdOffset uint32) (index IfdIndex, err error
|
||||||
log.Panic(err)
|
log.Panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
nextIfdOffset, entries, thumbnailData, err := ie.ParseIfd(fqIfdPath, currentIndex, enumerator, nil, false)
|
nextIfdOffset, entries, thumbnailData, err := ie.ParseIfd(fqIfdPath, currentIndex, bp, nil, false)
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
id := len(ifds)
|
id := len(ifds)
|
||||||
|
@ -1169,7 +1175,7 @@ func ParseOneIfd(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath, ifdPath
|
||||||
|
|
||||||
ie := NewIfdEnumerate(ifdMapping, tagIndex, make([]byte, 0), byteOrder)
|
ie := NewIfdEnumerate(ifdMapping, tagIndex, make([]byte, 0), byteOrder)
|
||||||
|
|
||||||
enumerator, err := NewIfdTagEnumerator(ifdBlock, byteOrder, 0)
|
bp, err := newByteParser(ifdBlock, byteOrder, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == ErrOffsetInvalid {
|
if err == ErrOffsetInvalid {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
|
@ -1178,7 +1184,7 @@ func ParseOneIfd(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath, ifdPath
|
||||||
log.Panic(err)
|
log.Panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
nextIfdOffset, entries, _, err = ie.ParseIfd(fqIfdPath, 0, enumerator, visitor, true)
|
nextIfdOffset, entries, _, err = ie.ParseIfd(fqIfdPath, 0, bp, visitor, true)
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
return nextIfdOffset, entries, nil
|
return nextIfdOffset, entries, nil
|
||||||
|
@ -1194,7 +1200,7 @@ func ParseOneTag(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath, ifdPath
|
||||||
|
|
||||||
ie := NewIfdEnumerate(ifdMapping, tagIndex, make([]byte, 0), byteOrder)
|
ie := NewIfdEnumerate(ifdMapping, tagIndex, make([]byte, 0), byteOrder)
|
||||||
|
|
||||||
enumerator, err := NewIfdTagEnumerator(tagBlock, byteOrder, 0)
|
bp, err := newByteParser(tagBlock, byteOrder, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == ErrOffsetInvalid {
|
if err == ErrOffsetInvalid {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -1203,7 +1209,7 @@ func ParseOneTag(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath, ifdPath
|
||||||
log.Panic(err)
|
log.Panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tag, err = ie.parseTag(fqIfdPath, 0, enumerator)
|
tag, err = ie.parseTag(fqIfdPath, 0, bp)
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
return tag, nil
|
return tag, nil
|
||||||
|
|
Loading…
Reference in New Issue