value_context.go: `ValueContext` now wraps members in accessors

It also embeds the type and byte-order so the VC can materialize/process
values self-sufficiently.
pull/28/head
Dustin Oprea 2019-12-29 00:35:35 -05:00
parent a69c3987eb
commit 7fb09bbf9f
6 changed files with 122 additions and 85 deletions

View File

@ -131,7 +131,7 @@ func main() {
TagName: it.Name,
TagTypeId: tagType.Type(),
TagTypeName: tagType.Name(),
UnitCount: valueContext.UnitCount,
UnitCount: valueContext.UnitCount(),
Value: value,
ValueString: valueString,
}

View File

@ -94,7 +94,7 @@ func TestVisit(t *testing.T) {
log.PanicIf(err)
}
description := fmt.Sprintf("IFD-PATH=[%s] ID=(0x%04x) NAME=[%s] COUNT=(%d) TYPE=[%s] VALUE=[%s]", ifdPath, tagId, it.Name, valueContext.UnitCount, tagType.Name(), valueString)
description := fmt.Sprintf("IFD-PATH=[%s] ID=(0x%04x) NAME=[%s] COUNT=(%d) TYPE=[%s] VALUE=[%s]", ifdPath, tagId, it.Name, valueContext.UnitCount(), tagType.Name(), valueString)
tags = append(tags, description)
return nil

View File

@ -233,12 +233,15 @@ func (ie *IfdEnumerate) resolveTagValue(ite *IfdTagEntry) (valueBytes []byte, is
// (obviously). However, here, in order to produce the list of bytes, we
// need to coerce whatever `UndefinedValue()` returns.
if ite.TagType == TypeUndefined {
valueContext := ValueContext{
UnitCount: ite.UnitCount,
ValueOffset: ite.ValueOffset,
RawValueOffset: ite.RawValueOffset,
AddressableData: addressableData,
}
valueContext :=
newValueContext(
ite.UnitCount,
ite.ValueOffset,
ite.RawValueOffset,
addressableData,
ite.TagType,
ie.byteOrder,
)
value, err := UndefinedValue(ite.IfdPath, ite.TagId, valueContext, ie.byteOrder)
if err != nil {
@ -338,12 +341,14 @@ func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, ite *IfdTagEnum
if visitor != nil {
tt := NewTagType(tag.TagType, ie.byteOrder)
vc := ValueContext{
UnitCount: tag.UnitCount,
ValueOffset: tag.ValueOffset,
RawValueOffset: tag.RawValueOffset,
AddressableData: ie.exifData[ExifAddressableAreaStart:],
}
vc :=
newValueContext(
tag.UnitCount,
tag.ValueOffset,
tag.RawValueOffset,
ie.exifData[ExifAddressableAreaStart:],
tag.TagType,
ie.byteOrder)
err := visitor(fqIfdPath, ifdIndex, tag.TagId, tt, vc)
log.PanicIf(err)

View File

@ -55,12 +55,14 @@ func (ite IfdTagEntry) ValueString(addressableData []byte, byteOrder binary.Byte
}
}()
vc := ValueContext{
UnitCount: ite.UnitCount,
ValueOffset: ite.ValueOffset,
RawValueOffset: ite.RawValueOffset,
AddressableData: addressableData,
}
vc :=
newValueContext(
ite.UnitCount,
ite.ValueOffset,
ite.RawValueOffset,
addressableData,
ite.TagType,
byteOrder)
if ite.TagType == TypeUndefined {
valueRaw, err := UndefinedValue(ite.IfdPath, ite.TagId, vc, byteOrder)
@ -91,12 +93,14 @@ func (ite IfdTagEntry) ValueBytes(addressableData []byte, byteOrder binary.ByteO
// (obviously). However, here, in order to produce the list of bytes, we
// need to coerce whatever `UndefinedValue()` returns.
if ite.TagType == TypeUndefined {
valueContext := ValueContext{
UnitCount: ite.UnitCount,
ValueOffset: ite.ValueOffset,
RawValueOffset: ite.RawValueOffset,
AddressableData: addressableData,
}
valueContext :=
newValueContext(
ite.UnitCount,
ite.ValueOffset,
ite.RawValueOffset,
addressableData,
ite.TagType,
byteOrder)
value, err := UndefinedValue(ite.IfdPath, ite.TagId, valueContext, byteOrder)
log.PanicIf(err)
@ -150,12 +154,14 @@ func (ite IfdTagEntry) Value(addressableData []byte, byteOrder binary.ByteOrder)
}
}()
vc := ValueContext{
UnitCount: ite.UnitCount,
ValueOffset: ite.ValueOffset,
RawValueOffset: ite.RawValueOffset,
AddressableData: addressableData,
}
vc :=
newValueContext(
ite.UnitCount,
ite.ValueOffset,
ite.RawValueOffset,
addressableData,
ite.TagType,
byteOrder)
if ite.TagType == TypeUndefined {
value, err = UndefinedValue(ite.IfdPath, ite.TagId, vc, byteOrder)

88
type.go
View File

@ -158,11 +158,11 @@ func (tt TagType) readRawEncoded(valueContext ValueContext) (rawBytes []byte, er
unitSizeRaw := uint32(tt.tagType.Size())
if tt.valueIsEmbedded(valueContext.UnitCount) == true {
byteLength := unitSizeRaw * valueContext.UnitCount
return valueContext.RawValueOffset[:byteLength], nil
if tt.valueIsEmbedded(valueContext.UnitCount()) == true {
byteLength := unitSizeRaw * valueContext.UnitCount()
return valueContext.RawValueOffset()[:byteLength], nil
} else {
return valueContext.AddressableData[valueContext.ValueOffset : valueContext.ValueOffset+valueContext.UnitCount*unitSizeRaw], nil
return valueContext.AddressableData()[valueContext.ValueOffset() : valueContext.ValueOffset()+valueContext.UnitCount()*unitSizeRaw], nil
}
}
@ -409,21 +409,21 @@ func (tt TagType) ReadByteValues(valueContext ValueContext) (value []byte, err e
}
}()
if tt.valueIsEmbedded(valueContext.UnitCount) == true {
if tt.valueIsEmbedded(valueContext.UnitCount()) == true {
typeLogger.Debugf(nil, "Reading BYTE value (embedded).")
// In this case, the bytes normally used for the offset are actually
// data.
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
rawValue := valueContext.RawValueOffset[:byteLength]
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount()
rawValue := valueContext.RawValueOffset()[:byteLength]
value, err = tt.ParseBytes(rawValue, valueContext.UnitCount)
value, err = tt.ParseBytes(rawValue, valueContext.UnitCount())
log.PanicIf(err)
} else {
typeLogger.Debugf(nil, "Reading BYTE value (at offset).")
value, err = tt.ParseBytes(valueContext.AddressableData[valueContext.ValueOffset:], valueContext.UnitCount)
value, err = tt.ParseBytes(valueContext.AddressableData()[valueContext.ValueOffset():], valueContext.UnitCount())
log.PanicIf(err)
}
@ -437,18 +437,18 @@ func (tt TagType) ReadAsciiValue(valueContext ValueContext) (value string, err e
}
}()
if tt.valueIsEmbedded(valueContext.UnitCount) == true {
if tt.valueIsEmbedded(valueContext.UnitCount()) == true {
typeLogger.Debugf(nil, "Reading ASCII value (embedded).")
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
rawValue := valueContext.RawValueOffset[:byteLength]
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount()
rawValue := valueContext.RawValueOffset()[:byteLength]
value, err = tt.ParseAscii(rawValue, valueContext.UnitCount)
value, err = tt.ParseAscii(rawValue, valueContext.UnitCount())
log.PanicIf(err)
} else {
typeLogger.Debugf(nil, "Reading ASCII value (at offset).")
value, err = tt.ParseAscii(valueContext.AddressableData[valueContext.ValueOffset:], valueContext.UnitCount)
value, err = tt.ParseAscii(valueContext.AddressableData()[valueContext.ValueOffset():], valueContext.UnitCount())
log.PanicIf(err)
}
@ -462,18 +462,18 @@ func (tt TagType) ReadAsciiNoNulValue(valueContext ValueContext) (value string,
}
}()
if tt.valueIsEmbedded(valueContext.UnitCount) == true {
if tt.valueIsEmbedded(valueContext.UnitCount()) == true {
typeLogger.Debugf(nil, "Reading ASCII value (no-nul; embedded).")
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
rawValue := valueContext.RawValueOffset[:byteLength]
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount()
rawValue := valueContext.RawValueOffset()[:byteLength]
value, err = tt.ParseAsciiNoNul(rawValue, valueContext.UnitCount)
value, err = tt.ParseAsciiNoNul(rawValue, valueContext.UnitCount())
log.PanicIf(err)
} else {
typeLogger.Debugf(nil, "Reading ASCII value (no-nul; at offset).")
value, err = tt.ParseAsciiNoNul(valueContext.AddressableData[valueContext.ValueOffset:], valueContext.UnitCount)
value, err = tt.ParseAsciiNoNul(valueContext.AddressableData()[valueContext.ValueOffset():], valueContext.UnitCount())
log.PanicIf(err)
}
@ -487,18 +487,18 @@ func (tt TagType) ReadShortValues(valueContext ValueContext) (value []uint16, er
}
}()
if tt.valueIsEmbedded(valueContext.UnitCount) == true {
if tt.valueIsEmbedded(valueContext.UnitCount()) == true {
typeLogger.Debugf(nil, "Reading SHORT value (embedded).")
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
rawValue := valueContext.RawValueOffset[:byteLength]
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount()
rawValue := valueContext.RawValueOffset()[:byteLength]
value, err = tt.ParseShorts(rawValue, valueContext.UnitCount)
value, err = tt.ParseShorts(rawValue, valueContext.UnitCount())
log.PanicIf(err)
} else {
typeLogger.Debugf(nil, "Reading SHORT value (at offset).")
value, err = tt.ParseShorts(valueContext.AddressableData[valueContext.ValueOffset:], valueContext.UnitCount)
value, err = tt.ParseShorts(valueContext.AddressableData()[valueContext.ValueOffset():], valueContext.UnitCount())
log.PanicIf(err)
}
@ -512,18 +512,18 @@ func (tt TagType) ReadLongValues(valueContext ValueContext) (value []uint32, err
}
}()
if tt.valueIsEmbedded(valueContext.UnitCount) == true {
if tt.valueIsEmbedded(valueContext.UnitCount()) == true {
typeLogger.Debugf(nil, "Reading LONG value (embedded).")
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
rawValue := valueContext.RawValueOffset[:byteLength]
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount()
rawValue := valueContext.RawValueOffset()[:byteLength]
value, err = tt.ParseLongs(rawValue, valueContext.UnitCount)
value, err = tt.ParseLongs(rawValue, valueContext.UnitCount())
log.PanicIf(err)
} else {
typeLogger.Debugf(nil, "Reading LONG value (at offset).")
value, err = tt.ParseLongs(valueContext.AddressableData[valueContext.ValueOffset:], valueContext.UnitCount)
value, err = tt.ParseLongs(valueContext.AddressableData()[valueContext.ValueOffset():], valueContext.UnitCount())
log.PanicIf(err)
}
@ -537,18 +537,18 @@ func (tt TagType) ReadRationalValues(valueContext ValueContext) (value []Rationa
}
}()
if tt.valueIsEmbedded(valueContext.UnitCount) == true {
if tt.valueIsEmbedded(valueContext.UnitCount()) == true {
typeLogger.Debugf(nil, "Reading RATIONAL value (embedded).")
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
rawValue := valueContext.RawValueOffset[:byteLength]
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount()
rawValue := valueContext.RawValueOffset()[:byteLength]
value, err = tt.ParseRationals(rawValue, valueContext.UnitCount)
value, err = tt.ParseRationals(rawValue, valueContext.UnitCount())
log.PanicIf(err)
} else {
typeLogger.Debugf(nil, "Reading RATIONAL value (at offset).")
value, err = tt.ParseRationals(valueContext.AddressableData[valueContext.ValueOffset:], valueContext.UnitCount)
value, err = tt.ParseRationals(valueContext.AddressableData()[valueContext.ValueOffset():], valueContext.UnitCount())
log.PanicIf(err)
}
@ -562,18 +562,18 @@ func (tt TagType) ReadSignedLongValues(valueContext ValueContext) (value []int32
}
}()
if tt.valueIsEmbedded(valueContext.UnitCount) == true {
if tt.valueIsEmbedded(valueContext.UnitCount()) == true {
typeLogger.Debugf(nil, "Reading SLONG value (embedded).")
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
rawValue := valueContext.RawValueOffset[:byteLength]
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount()
rawValue := valueContext.RawValueOffset()[:byteLength]
value, err = tt.ParseSignedLongs(rawValue, valueContext.UnitCount)
value, err = tt.ParseSignedLongs(rawValue, valueContext.UnitCount())
log.PanicIf(err)
} else {
typeLogger.Debugf(nil, "Reading SLONG value (at offset).")
value, err = tt.ParseSignedLongs(valueContext.AddressableData[valueContext.ValueOffset:], valueContext.UnitCount)
value, err = tt.ParseSignedLongs(valueContext.AddressableData()[valueContext.ValueOffset():], valueContext.UnitCount())
log.PanicIf(err)
}
@ -587,18 +587,18 @@ func (tt TagType) ReadSignedRationalValues(valueContext ValueContext) (value []S
}
}()
if tt.valueIsEmbedded(valueContext.UnitCount) == true {
if tt.valueIsEmbedded(valueContext.UnitCount()) == true {
typeLogger.Debugf(nil, "Reading SRATIONAL value (embedded).")
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
rawValue := valueContext.RawValueOffset[:byteLength]
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount()
rawValue := valueContext.RawValueOffset()[:byteLength]
value, err = tt.ParseSignedRationals(rawValue, valueContext.UnitCount)
value, err = tt.ParseSignedRationals(rawValue, valueContext.UnitCount())
log.PanicIf(err)
} else {
typeLogger.Debugf(nil, "Reading SRATIONAL value (at offset).")
value, err = tt.ParseSignedRationals(valueContext.AddressableData[valueContext.ValueOffset:], valueContext.UnitCount)
value, err = tt.ParseSignedRationals(valueContext.AddressableData()[valueContext.ValueOffset():], valueContext.UnitCount())
log.PanicIf(err)
}

View File

@ -1,19 +1,45 @@
package exif
import (
"encoding/binary"
)
// ValueContext describes 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
addressableData []byte
tagType TagTypePrimitive
byteOrder binary.ByteOrder
}
func newValueContext(unitCount, valueOffset uint32, rawValueOffset, addressableData []byte) ValueContext {
func (vc ValueContext) UnitCount() uint32 {
return vc.unitCount
}
func (vc ValueContext) ValueOffset() uint32 {
return vc.valueOffset
}
func (vc ValueContext) RawValueOffset() []byte {
return vc.rawValueOffset
}
func (vc ValueContext) AddressableData() []byte {
return vc.addressableData
}
func newValueContext(unitCount, valueOffset uint32, rawValueOffset, addressableData []byte, tagType TagTypePrimitive, byteOrder binary.ByteOrder) ValueContext {
return ValueContext{
UnitCount: unitCount,
ValueOffset: valueOffset,
RawValueOffset: rawValueOffset,
AddressableData: addressableData,
unitCount: unitCount,
valueOffset: valueOffset,
rawValueOffset: rawValueOffset,
addressableData: addressableData,
tagType: tagType,
byteOrder: byteOrder,
}
}