From 7fb09bbf9fcbc761f5163947224e2a5dae465ada Mon Sep 17 00:00:00 2001 From: Dustin Oprea Date: Sun, 29 Dec 2019 00:35:35 -0500 Subject: [PATCH] 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. --- exif-read-tool/main.go | 2 +- exif_test.go | 2 +- ifd_enumerate.go | 29 ++++++++------ ifd_tag_entry.go | 42 +++++++++++--------- type.go | 88 +++++++++++++++++++++--------------------- value_context.go | 44 ++++++++++++++++----- 6 files changed, 122 insertions(+), 85 deletions(-) diff --git a/exif-read-tool/main.go b/exif-read-tool/main.go index 469071d..a091a2e 100644 --- a/exif-read-tool/main.go +++ b/exif-read-tool/main.go @@ -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, } diff --git a/exif_test.go b/exif_test.go index d9ca204..9a02b3d 100644 --- a/exif_test.go +++ b/exif_test.go @@ -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 diff --git a/ifd_enumerate.go b/ifd_enumerate.go index e3f82f9..28c0e7b 100644 --- a/ifd_enumerate.go +++ b/ifd_enumerate.go @@ -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) diff --git a/ifd_tag_entry.go b/ifd_tag_entry.go index feec23e..bf386f6 100644 --- a/ifd_tag_entry.go +++ b/ifd_tag_entry.go @@ -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) diff --git a/type.go b/type.go index a39c0f3..a25cbf1 100644 --- a/type.go +++ b/type.go @@ -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) } diff --git a/value_context.go b/value_context.go index 10c6534..4d60c04 100644 --- a/value_context.go +++ b/value_context.go @@ -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, } }