mirror of https://github.com/dsoprea/go-exif.git
type.go: Created `TagTypePrimitive` alias for `uint16`
Added a `Size()` method to it and decommissioned redundant `TagTypeSize()` and `(TagType).Size()`. - ifd_enumerate.go: Moved `ValueContext` definition to value_context.go .pull/28/head
parent
483dbacf14
commit
a69c3987eb
|
@ -32,16 +32,16 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type IfdEntry struct {
|
type IfdEntry struct {
|
||||||
IfdPath string `json:"ifd_path"`
|
IfdPath string `json:"ifd_path"`
|
||||||
FqIfdPath string `json:"fq_ifd_path"`
|
FqIfdPath string `json:"fq_ifd_path"`
|
||||||
IfdIndex int `json:"ifd_index"`
|
IfdIndex int `json:"ifd_index"`
|
||||||
TagId uint16 `json:"tag_id"`
|
TagId uint16 `json:"tag_id"`
|
||||||
TagName string `json:"tag_name"`
|
TagName string `json:"tag_name"`
|
||||||
TagTypeId uint16 `json:"tag_type_id"`
|
TagTypeId exif.TagTypePrimitive `json:"tag_type_id"`
|
||||||
TagTypeName string `json:"tag_type_name"`
|
TagTypeName string `json:"tag_type_name"`
|
||||||
UnitCount uint32 `json:"unit_count"`
|
UnitCount uint32 `json:"unit_count"`
|
||||||
Value interface{} `json:"value"`
|
Value interface{} `json:"value"`
|
||||||
ValueString string `json:"value_string"`
|
ValueString string `json:"value_string"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -90,7 +90,7 @@ type BuilderTag struct {
|
||||||
ifdPath string
|
ifdPath string
|
||||||
|
|
||||||
tagId uint16
|
tagId uint16
|
||||||
typeId uint16
|
typeId TagTypePrimitive
|
||||||
|
|
||||||
// value is either a value that can be encoded, an IfdBuilder instance (for
|
// value is either a value that can be encoded, an IfdBuilder instance (for
|
||||||
// child IFDs), or an IfdTagEntry instance representing an existing,
|
// child IFDs), or an IfdTagEntry instance representing an existing,
|
||||||
|
@ -102,7 +102,7 @@ type BuilderTag struct {
|
||||||
byteOrder binary.ByteOrder
|
byteOrder binary.ByteOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBuilderTag(ifdPath string, tagId uint16, typeId uint16, value *IfdBuilderTagValue, byteOrder binary.ByteOrder) *BuilderTag {
|
func NewBuilderTag(ifdPath string, tagId uint16, typeId TagTypePrimitive, value *IfdBuilderTagValue, byteOrder binary.ByteOrder) *BuilderTag {
|
||||||
return &BuilderTag{
|
return &BuilderTag{
|
||||||
ifdPath: ifdPath,
|
ifdPath: ifdPath,
|
||||||
tagId: tagId,
|
tagId: tagId,
|
||||||
|
|
|
@ -212,7 +212,7 @@ func (ibe *IfdByteEncoder) encodeTagToBytes(ib *IfdBuilder, bt *BuilderTag, bw *
|
||||||
|
|
||||||
// Works for both values and child IFDs (which have an official size of
|
// Works for both values and child IFDs (which have an official size of
|
||||||
// LONG).
|
// LONG).
|
||||||
err = bw.WriteUint16(bt.typeId)
|
err = bw.WriteUint16(uint16(bt.typeId))
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
// Write unit-count.
|
// Write unit-count.
|
||||||
|
@ -226,7 +226,7 @@ func (ibe *IfdByteEncoder) encodeTagToBytes(ib *IfdBuilder, bt *BuilderTag, bw *
|
||||||
// It's a non-unknown value.Calculate the count of values of
|
// It's a non-unknown value.Calculate the count of values of
|
||||||
// the type that we're writing and the raw bytes for the whole list.
|
// the type that we're writing and the raw bytes for the whole list.
|
||||||
|
|
||||||
typeSize := uint32(TagTypeSize(effectiveType))
|
typeSize := uint32(effectiveType.Size())
|
||||||
|
|
||||||
valueBytes := bt.value.Bytes()
|
valueBytes := bt.value.Bytes()
|
||||||
|
|
||||||
|
|
|
@ -145,15 +145,6 @@ func NewIfdEnumerate(ifdMapping *IfdMapping, tagIndex *TagIndex, exifData []byte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ie *IfdEnumerate) getTagEnumerator(ifdOffset uint32) (ite *IfdTagEnumerator) {
|
func (ie *IfdEnumerate) getTagEnumerator(ifdOffset uint32) (ite *IfdTagEnumerator) {
|
||||||
ite = NewIfdTagEnumerator(
|
ite = NewIfdTagEnumerator(
|
||||||
ie.exifData[ExifAddressableAreaStart:],
|
ie.exifData[ExifAddressableAreaStart:],
|
||||||
|
@ -173,9 +164,11 @@ func (ie *IfdEnumerate) parseTag(fqIfdPath string, tagPosition int, ite *IfdTagE
|
||||||
tagId, _, err := ite.getUint16()
|
tagId, _, err := ite.getUint16()
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
tagType, _, err := ite.getUint16()
|
tagTypeRaw, _, err := ite.getUint16()
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
tagType := TagTypePrimitive(tagTypeRaw)
|
||||||
|
|
||||||
unitCount, _, err := ite.getUint32()
|
unitCount, _, err := ite.getUint32()
|
||||||
log.PanicIf(err)
|
log.PanicIf(err)
|
||||||
|
|
||||||
|
@ -276,7 +269,7 @@ func (ie *IfdEnumerate) resolveTagValue(ite *IfdTagEntry) (valueBytes []byte, is
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
originalType := NewTagType(ite.TagType, ie.byteOrder)
|
originalType := NewTagType(ite.TagType, ie.byteOrder)
|
||||||
byteCount := uint32(originalType.Size()) * ite.UnitCount
|
byteCount := uint32(originalType.Type().Size()) * ite.UnitCount
|
||||||
|
|
||||||
tt := NewTagType(TypeByte, ie.byteOrder)
|
tt := NewTagType(TypeByte, ie.byteOrder)
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ var (
|
||||||
type IfdTagEntry struct {
|
type IfdTagEntry struct {
|
||||||
TagId uint16
|
TagId uint16
|
||||||
TagIndex int
|
TagIndex int
|
||||||
TagType uint16
|
TagType TagTypePrimitive
|
||||||
UnitCount uint32
|
UnitCount uint32
|
||||||
ValueOffset uint32
|
ValueOffset uint32
|
||||||
RawValueOffset []byte
|
RawValueOffset []byte
|
||||||
|
@ -121,7 +121,7 @@ func (ite IfdTagEntry) ValueBytes(addressableData []byte, byteOrder binary.ByteO
|
||||||
}
|
}
|
||||||
|
|
||||||
originalType := NewTagType(ite.TagType, byteOrder)
|
originalType := NewTagType(ite.TagType, byteOrder)
|
||||||
byteCount := uint32(originalType.Size()) * ite.UnitCount
|
byteCount := uint32(originalType.Type().Size()) * ite.UnitCount
|
||||||
|
|
||||||
tt := NewTagType(TypeByte, byteOrder)
|
tt := NewTagType(TypeByte, byteOrder)
|
||||||
|
|
||||||
|
|
2
tags.go
2
tags.go
|
@ -59,7 +59,7 @@ type IndexedTag struct {
|
||||||
Id uint16
|
Id uint16
|
||||||
Name string
|
Name string
|
||||||
IfdPath string
|
IfdPath string
|
||||||
Type uint16
|
Type TagTypePrimitive
|
||||||
}
|
}
|
||||||
|
|
||||||
func (it *IndexedTag) String() string {
|
func (it *IndexedTag) String() string {
|
||||||
|
|
126
type.go
126
type.go
|
@ -12,18 +12,43 @@ import (
|
||||||
"github.com/dsoprea/go-logging"
|
"github.com/dsoprea/go-logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
type TagTypePrimitive uint16
|
||||||
TypeByte = uint16(1)
|
|
||||||
TypeAscii = uint16(2)
|
|
||||||
TypeShort = uint16(3)
|
|
||||||
TypeLong = uint16(4)
|
|
||||||
TypeRational = uint16(5)
|
|
||||||
TypeUndefined = uint16(7)
|
|
||||||
TypeSignedLong = uint16(9)
|
|
||||||
TypeSignedRational = uint16(10)
|
|
||||||
|
|
||||||
// Custom, for our purposes.
|
func (tagType TagTypePrimitive) Size() int {
|
||||||
TypeAsciiNoNul = uint16(0xf0)
|
if tagType == TypeByte {
|
||||||
|
return 1
|
||||||
|
} else if tagType == TypeAscii || tagType == TypeAsciiNoNul {
|
||||||
|
return 1
|
||||||
|
} else if tagType == TypeShort {
|
||||||
|
return 2
|
||||||
|
} else if tagType == TypeLong {
|
||||||
|
return 4
|
||||||
|
} else if tagType == TypeRational {
|
||||||
|
return 8
|
||||||
|
} else if tagType == TypeSignedLong {
|
||||||
|
return 4
|
||||||
|
} else if tagType == TypeSignedRational {
|
||||||
|
return 8
|
||||||
|
} else {
|
||||||
|
log.Panicf("can not determine tag-value size for type (%d): [%s]", tagType, TypeNames[tagType])
|
||||||
|
|
||||||
|
// Never called.
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypeByte TagTypePrimitive = 1
|
||||||
|
TypeAscii = 2
|
||||||
|
TypeShort = 3
|
||||||
|
TypeLong = 4
|
||||||
|
TypeRational = 5
|
||||||
|
TypeUndefined = 7
|
||||||
|
TypeSignedLong = 9
|
||||||
|
TypeSignedRational = 10
|
||||||
|
|
||||||
|
// TypeAsciiNoNul is just a pseudo-type, for our own purposes.
|
||||||
|
TypeAsciiNoNul = 0xf0
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -32,7 +57,7 @@ var (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// TODO(dustin): Rename TypeNames() to typeNames() and add getter.
|
// TODO(dustin): Rename TypeNames() to typeNames() and add getter.
|
||||||
TypeNames = map[uint16]string{
|
TypeNames = map[TagTypePrimitive]string{
|
||||||
TypeByte: "BYTE",
|
TypeByte: "BYTE",
|
||||||
TypeAscii: "ASCII",
|
TypeAscii: "ASCII",
|
||||||
TypeShort: "SHORT",
|
TypeShort: "SHORT",
|
||||||
|
@ -45,7 +70,7 @@ var (
|
||||||
TypeAsciiNoNul: "_ASCII_NO_NUL",
|
TypeAsciiNoNul: "_ASCII_NO_NUL",
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeNamesR = map[string]uint16{}
|
TypeNamesR = map[string]TagTypePrimitive{}
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -74,12 +99,12 @@ type SignedRational struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type TagType struct {
|
type TagType struct {
|
||||||
tagType uint16
|
tagType TagTypePrimitive
|
||||||
name string
|
name string
|
||||||
byteOrder binary.ByteOrder
|
byteOrder binary.ByteOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTagType(tagType uint16, byteOrder binary.ByteOrder) TagType {
|
func NewTagType(tagType TagTypePrimitive, byteOrder binary.ByteOrder) TagType {
|
||||||
name, found := TypeNames[tagType]
|
name, found := TypeNames[tagType]
|
||||||
if found == false {
|
if found == false {
|
||||||
log.Panicf("tag-type not valid: 0x%04x", tagType)
|
log.Panicf("tag-type not valid: 0x%04x", tagType)
|
||||||
|
@ -100,7 +125,7 @@ func (tt TagType) Name() string {
|
||||||
return tt.name
|
return tt.name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tt TagType) Type() uint16 {
|
func (tt TagType) Type() TagTypePrimitive {
|
||||||
return tt.tagType
|
return tt.tagType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,37 +133,20 @@ func (tt TagType) ByteOrder() binary.ByteOrder {
|
||||||
return tt.byteOrder
|
return tt.byteOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEPRECATED(dustin): `(TagTypePrimitive).Size()` should be used, directly.
|
||||||
func (tt TagType) Size() int {
|
func (tt TagType) Size() int {
|
||||||
return TagTypeSize(tt.Type())
|
return tt.Type().Size()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TagTypeSize(tagType uint16) int {
|
// DEPRECATED(dustin): `(TagTypePrimitive).Size()` should be used, directly.
|
||||||
if tagType == TypeByte {
|
func TagTypeSize(tagType TagTypePrimitive) int {
|
||||||
return 1
|
return tagType.Size()
|
||||||
} else if tagType == TypeAscii || tagType == TypeAsciiNoNul {
|
|
||||||
return 1
|
|
||||||
} else if tagType == TypeShort {
|
|
||||||
return 2
|
|
||||||
} else if tagType == TypeLong {
|
|
||||||
return 4
|
|
||||||
} else if tagType == TypeRational {
|
|
||||||
return 8
|
|
||||||
} else if tagType == TypeSignedLong {
|
|
||||||
return 4
|
|
||||||
} else if tagType == TypeSignedRational {
|
|
||||||
return 8
|
|
||||||
} else {
|
|
||||||
log.Panicf("can not determine tag-value size for type (%d): [%s]", tagType, TypeNames[tagType])
|
|
||||||
|
|
||||||
// Never called.
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// valueIsEmbedded will return a boolean indicating whether the value should be
|
// valueIsEmbedded will return a boolean indicating whether the value should be
|
||||||
// found directly within the IFD entry or an offset to somewhere else.
|
// found directly within the IFD entry or an offset to somewhere else.
|
||||||
func (tt TagType) valueIsEmbedded(unitCount uint32) bool {
|
func (tt TagType) valueIsEmbedded(unitCount uint32) bool {
|
||||||
return (tt.Size() * int(unitCount)) <= 4
|
return (tt.tagType.Size() * int(unitCount)) <= 4
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tt TagType) readRawEncoded(valueContext ValueContext) (rawBytes []byte, err error) {
|
func (tt TagType) readRawEncoded(valueContext ValueContext) (rawBytes []byte, err error) {
|
||||||
|
@ -148,11 +156,13 @@ func (tt TagType) readRawEncoded(valueContext ValueContext) (rawBytes []byte, er
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
unitSizeRaw := uint32(tt.tagType.Size())
|
||||||
|
|
||||||
if tt.valueIsEmbedded(valueContext.UnitCount) == true {
|
if tt.valueIsEmbedded(valueContext.UnitCount) == true {
|
||||||
byteLength := uint32(tt.Size()) * valueContext.UnitCount
|
byteLength := unitSizeRaw * valueContext.UnitCount
|
||||||
return valueContext.RawValueOffset[:byteLength], nil
|
return valueContext.RawValueOffset[:byteLength], nil
|
||||||
} else {
|
} else {
|
||||||
return valueContext.AddressableData[valueContext.ValueOffset : valueContext.ValueOffset+valueContext.UnitCount*uint32(tt.Size())], nil
|
return valueContext.AddressableData[valueContext.ValueOffset : valueContext.ValueOffset+valueContext.UnitCount*unitSizeRaw], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +179,7 @@ func (tt TagType) ParseBytes(data []byte, unitCount uint32) (value []uint8, err
|
||||||
|
|
||||||
count := int(unitCount)
|
count := int(unitCount)
|
||||||
|
|
||||||
if len(data) < (tt.Size() * count) {
|
if len(data) < (tt.tagType.Size() * count) {
|
||||||
log.Panic(ErrNotEnoughData)
|
log.Panic(ErrNotEnoughData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +202,7 @@ func (tt TagType) ParseAscii(data []byte, unitCount uint32) (value string, err e
|
||||||
|
|
||||||
count := int(unitCount)
|
count := int(unitCount)
|
||||||
|
|
||||||
if len(data) < (tt.Size() * count) {
|
if len(data) < (tt.tagType.Size() * count) {
|
||||||
log.Panic(ErrNotEnoughData)
|
log.Panic(ErrNotEnoughData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +234,7 @@ func (tt TagType) ParseAsciiNoNul(data []byte, unitCount uint32) (value string,
|
||||||
|
|
||||||
count := int(unitCount)
|
count := int(unitCount)
|
||||||
|
|
||||||
if len(data) < (tt.Size() * count) {
|
if len(data) < (tt.tagType.Size() * count) {
|
||||||
log.Panic(ErrNotEnoughData)
|
log.Panic(ErrNotEnoughData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,7 +254,7 @@ func (tt TagType) ParseShorts(data []byte, unitCount uint32) (value []uint16, er
|
||||||
|
|
||||||
count := int(unitCount)
|
count := int(unitCount)
|
||||||
|
|
||||||
if len(data) < (tt.Size() * count) {
|
if len(data) < (tt.tagType.Size() * count) {
|
||||||
log.Panic(ErrNotEnoughData)
|
log.Panic(ErrNotEnoughData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,7 +283,7 @@ func (tt TagType) ParseLongs(data []byte, unitCount uint32) (value []uint32, err
|
||||||
|
|
||||||
count := int(unitCount)
|
count := int(unitCount)
|
||||||
|
|
||||||
if len(data) < (tt.Size() * count) {
|
if len(data) < (tt.tagType.Size() * count) {
|
||||||
log.Panic(ErrNotEnoughData)
|
log.Panic(ErrNotEnoughData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +312,7 @@ func (tt TagType) ParseRationals(data []byte, unitCount uint32) (value []Rationa
|
||||||
|
|
||||||
count := int(unitCount)
|
count := int(unitCount)
|
||||||
|
|
||||||
if len(data) < (tt.Size() * count) {
|
if len(data) < (tt.tagType.Size() * count) {
|
||||||
log.Panic(ErrNotEnoughData)
|
log.Panic(ErrNotEnoughData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,7 +343,7 @@ func (tt TagType) ParseSignedLongs(data []byte, unitCount uint32) (value []int32
|
||||||
|
|
||||||
count := int(unitCount)
|
count := int(unitCount)
|
||||||
|
|
||||||
if len(data) < (tt.Size() * count) {
|
if len(data) < (tt.tagType.Size() * count) {
|
||||||
log.Panic(ErrNotEnoughData)
|
log.Panic(ErrNotEnoughData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,7 +376,7 @@ func (tt TagType) ParseSignedRationals(data []byte, unitCount uint32) (value []S
|
||||||
|
|
||||||
count := int(unitCount)
|
count := int(unitCount)
|
||||||
|
|
||||||
if len(data) < (tt.Size() * count) {
|
if len(data) < (tt.tagType.Size() * count) {
|
||||||
log.Panic(ErrNotEnoughData)
|
log.Panic(ErrNotEnoughData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,7 +415,7 @@ func (tt TagType) ReadByteValues(valueContext ValueContext) (value []byte, err e
|
||||||
// In this case, the bytes normally used for the offset are actually
|
// In this case, the bytes normally used for the offset are actually
|
||||||
// data.
|
// data.
|
||||||
|
|
||||||
byteLength := uint32(tt.Size()) * valueContext.UnitCount
|
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
|
||||||
rawValue := valueContext.RawValueOffset[:byteLength]
|
rawValue := valueContext.RawValueOffset[:byteLength]
|
||||||
|
|
||||||
value, err = tt.ParseBytes(rawValue, valueContext.UnitCount)
|
value, err = tt.ParseBytes(rawValue, valueContext.UnitCount)
|
||||||
|
@ -430,7 +440,7 @@ 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).")
|
typeLogger.Debugf(nil, "Reading ASCII value (embedded).")
|
||||||
|
|
||||||
byteLength := uint32(tt.Size()) * valueContext.UnitCount
|
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
|
||||||
rawValue := valueContext.RawValueOffset[:byteLength]
|
rawValue := valueContext.RawValueOffset[:byteLength]
|
||||||
|
|
||||||
value, err = tt.ParseAscii(rawValue, valueContext.UnitCount)
|
value, err = tt.ParseAscii(rawValue, valueContext.UnitCount)
|
||||||
|
@ -455,7 +465,7 @@ 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).")
|
typeLogger.Debugf(nil, "Reading ASCII value (no-nul; embedded).")
|
||||||
|
|
||||||
byteLength := uint32(tt.Size()) * valueContext.UnitCount
|
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
|
||||||
rawValue := valueContext.RawValueOffset[:byteLength]
|
rawValue := valueContext.RawValueOffset[:byteLength]
|
||||||
|
|
||||||
value, err = tt.ParseAsciiNoNul(rawValue, valueContext.UnitCount)
|
value, err = tt.ParseAsciiNoNul(rawValue, valueContext.UnitCount)
|
||||||
|
@ -480,7 +490,7 @@ 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).")
|
typeLogger.Debugf(nil, "Reading SHORT value (embedded).")
|
||||||
|
|
||||||
byteLength := uint32(tt.Size()) * valueContext.UnitCount
|
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
|
||||||
rawValue := valueContext.RawValueOffset[:byteLength]
|
rawValue := valueContext.RawValueOffset[:byteLength]
|
||||||
|
|
||||||
value, err = tt.ParseShorts(rawValue, valueContext.UnitCount)
|
value, err = tt.ParseShorts(rawValue, valueContext.UnitCount)
|
||||||
|
@ -505,7 +515,7 @@ 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).")
|
typeLogger.Debugf(nil, "Reading LONG value (embedded).")
|
||||||
|
|
||||||
byteLength := uint32(tt.Size()) * valueContext.UnitCount
|
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
|
||||||
rawValue := valueContext.RawValueOffset[:byteLength]
|
rawValue := valueContext.RawValueOffset[:byteLength]
|
||||||
|
|
||||||
value, err = tt.ParseLongs(rawValue, valueContext.UnitCount)
|
value, err = tt.ParseLongs(rawValue, valueContext.UnitCount)
|
||||||
|
@ -530,7 +540,7 @@ 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).")
|
typeLogger.Debugf(nil, "Reading RATIONAL value (embedded).")
|
||||||
|
|
||||||
byteLength := uint32(tt.Size()) * valueContext.UnitCount
|
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
|
||||||
rawValue := valueContext.RawValueOffset[:byteLength]
|
rawValue := valueContext.RawValueOffset[:byteLength]
|
||||||
|
|
||||||
value, err = tt.ParseRationals(rawValue, valueContext.UnitCount)
|
value, err = tt.ParseRationals(rawValue, valueContext.UnitCount)
|
||||||
|
@ -555,7 +565,7 @@ 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).")
|
typeLogger.Debugf(nil, "Reading SLONG value (embedded).")
|
||||||
|
|
||||||
byteLength := uint32(tt.Size()) * valueContext.UnitCount
|
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
|
||||||
rawValue := valueContext.RawValueOffset[:byteLength]
|
rawValue := valueContext.RawValueOffset[:byteLength]
|
||||||
|
|
||||||
value, err = tt.ParseSignedLongs(rawValue, valueContext.UnitCount)
|
value, err = tt.ParseSignedLongs(rawValue, valueContext.UnitCount)
|
||||||
|
@ -580,7 +590,7 @@ 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).")
|
typeLogger.Debugf(nil, "Reading SRATIONAL value (embedded).")
|
||||||
|
|
||||||
byteLength := uint32(tt.Size()) * valueContext.UnitCount
|
byteLength := uint32(tt.tagType.Size()) * valueContext.UnitCount
|
||||||
rawValue := valueContext.RawValueOffset[:byteLength]
|
rawValue := valueContext.RawValueOffset[:byteLength]
|
||||||
|
|
||||||
value, err = tt.ParseSignedRationals(rawValue, valueContext.UnitCount)
|
value, err = tt.ParseSignedRationals(rawValue, valueContext.UnitCount)
|
||||||
|
@ -632,7 +642,7 @@ func (tt TagType) Format(rawBytes []byte, justFirst bool) (value string, err err
|
||||||
// TODO(dustin): !! Add tests
|
// TODO(dustin): !! Add tests
|
||||||
|
|
||||||
typeId := tt.Type()
|
typeId := tt.Type()
|
||||||
typeSize := TagTypeSize(typeId)
|
typeSize := typeId.Size()
|
||||||
|
|
||||||
if len(rawBytes)%typeSize != 0 {
|
if len(rawBytes)%typeSize != 0 {
|
||||||
log.Panicf("byte-count (%d) does not align for [%s] type with a size of (%d) bytes", len(rawBytes), TypeNames[typeId], typeSize)
|
log.Panicf("byte-count (%d) does not align for [%s] type with a size of (%d) bytes", len(rawBytes), TypeNames[typeId], typeSize)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package exif
|
package exif
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
|
||||||
|
@ -13,15 +13,13 @@ var (
|
||||||
typeEncodeLogger = log.NewLogger("exif.type_encode")
|
typeEncodeLogger = log.NewLogger("exif.type_encode")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// EncodedData encapsulates the compound output of an encoding operation.
|
// EncodedData encapsulates the compound output of an encoding operation.
|
||||||
type EncodedData struct {
|
type EncodedData struct {
|
||||||
Type uint16
|
Type TagTypePrimitive
|
||||||
Encoded []byte
|
Encoded []byte
|
||||||
UnitCount uint32
|
UnitCount uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type ValueEncoder struct {
|
type ValueEncoder struct {
|
||||||
byteOrder binary.ByteOrder
|
byteOrder binary.ByteOrder
|
||||||
}
|
}
|
||||||
|
@ -32,7 +30,6 @@ func NewValueEncoder(byteOrder binary.ByteOrder) *ValueEncoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (ve *ValueEncoder) encodeBytes(value []uint8) (ed EncodedData, err error) {
|
func (ve *ValueEncoder) encodeBytes(value []uint8) (ed EncodedData, err error) {
|
||||||
ed.Type = TypeByte
|
ed.Type = TypeByte
|
||||||
ed.Encoded = []byte(value)
|
ed.Encoded = []byte(value)
|
||||||
|
@ -81,10 +78,10 @@ func (ve *ValueEncoder) encodeShorts(value []uint16) (ed EncodedData, err error)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
ed.UnitCount = uint32(len(value))
|
ed.UnitCount = uint32(len(value))
|
||||||
ed.Encoded = make([]byte, ed.UnitCount * 2)
|
ed.Encoded = make([]byte, ed.UnitCount*2)
|
||||||
|
|
||||||
for i := uint32(0); i < ed.UnitCount; i++ {
|
for i := uint32(0); i < ed.UnitCount; i++ {
|
||||||
// TODO(dustin): We have a ton of duplication in how we handle the byte-orders and the inherent risk of accidentally doing something inconsistently. Move this to reusable code.
|
// TODO(dustin): We have a ton of duplication in how we handle the byte-orders and the inherent risk of accidentally doing something inconsistently. Move this to reusable code.
|
||||||
if ve.byteOrder == binary.BigEndian {
|
if ve.byteOrder == binary.BigEndian {
|
||||||
binary.BigEndian.PutUint16(ed.Encoded[i*2:(i+1)*2], value[i])
|
binary.BigEndian.PutUint16(ed.Encoded[i*2:(i+1)*2], value[i])
|
||||||
} else {
|
} else {
|
||||||
|
@ -105,7 +102,7 @@ func (ve *ValueEncoder) encodeLongs(value []uint32) (ed EncodedData, err error)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
ed.UnitCount = uint32(len(value))
|
ed.UnitCount = uint32(len(value))
|
||||||
ed.Encoded = make([]byte, ed.UnitCount * 4)
|
ed.Encoded = make([]byte, ed.UnitCount*4)
|
||||||
|
|
||||||
for i := uint32(0); i < ed.UnitCount; i++ {
|
for i := uint32(0); i < ed.UnitCount; i++ {
|
||||||
if ve.byteOrder == binary.BigEndian {
|
if ve.byteOrder == binary.BigEndian {
|
||||||
|
@ -128,7 +125,7 @@ func (ve *ValueEncoder) encodeRationals(value []Rational) (ed EncodedData, err e
|
||||||
}()
|
}()
|
||||||
|
|
||||||
ed.UnitCount = uint32(len(value))
|
ed.UnitCount = uint32(len(value))
|
||||||
ed.Encoded = make([]byte, ed.UnitCount * 8)
|
ed.Encoded = make([]byte, ed.UnitCount*8)
|
||||||
|
|
||||||
for i := uint32(0); i < ed.UnitCount; i++ {
|
for i := uint32(0); i < ed.UnitCount; i++ {
|
||||||
if ve.byteOrder == binary.BigEndian {
|
if ve.byteOrder == binary.BigEndian {
|
||||||
|
@ -154,7 +151,7 @@ func (ve *ValueEncoder) encodeSignedLongs(value []int32) (ed EncodedData, err er
|
||||||
|
|
||||||
ed.UnitCount = uint32(len(value))
|
ed.UnitCount = uint32(len(value))
|
||||||
|
|
||||||
b := bytes.NewBuffer(make([]byte, 0, 8 * ed.UnitCount))
|
b := bytes.NewBuffer(make([]byte, 0, 8*ed.UnitCount))
|
||||||
|
|
||||||
for i := uint32(0); i < ed.UnitCount; i++ {
|
for i := uint32(0); i < ed.UnitCount; i++ {
|
||||||
if ve.byteOrder == binary.BigEndian {
|
if ve.byteOrder == binary.BigEndian {
|
||||||
|
@ -181,7 +178,7 @@ func (ve *ValueEncoder) encodeSignedRationals(value []SignedRational) (ed Encode
|
||||||
|
|
||||||
ed.UnitCount = uint32(len(value))
|
ed.UnitCount = uint32(len(value))
|
||||||
|
|
||||||
b := bytes.NewBuffer(make([]byte, 0, 8 * ed.UnitCount))
|
b := bytes.NewBuffer(make([]byte, 0, 8*ed.UnitCount))
|
||||||
|
|
||||||
for i := uint32(0); i < ed.UnitCount; i++ {
|
for i := uint32(0); i < ed.UnitCount; i++ {
|
||||||
if ve.byteOrder == binary.BigEndian {
|
if ve.byteOrder == binary.BigEndian {
|
||||||
|
|
|
@ -132,10 +132,10 @@ type ExifTag struct {
|
||||||
TagId uint16 `json:"id"`
|
TagId uint16 `json:"id"`
|
||||||
TagName string `json:"name"`
|
TagName string `json:"name"`
|
||||||
|
|
||||||
TagTypeId uint16 `json:"type_id"`
|
TagTypeId TagTypePrimitive `json:"type_id"`
|
||||||
TagTypeName string `json:"type_name"`
|
TagTypeName string `json:"type_name"`
|
||||||
Value interface{} `json:"value"`
|
Value interface{} `json:"value"`
|
||||||
ValueBytes []byte `json:"value_bytes"`
|
ValueBytes []byte `json:"value_bytes"`
|
||||||
|
|
||||||
ChildIfdPath string `json:"child_ifd_path"`
|
ChildIfdPath string `json:"child_ifd_path"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package exif
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
func newValueContext(unitCount, valueOffset uint32, rawValueOffset, addressableData []byte) ValueContext {
|
||||||
|
return ValueContext{
|
||||||
|
UnitCount: unitCount,
|
||||||
|
ValueOffset: valueOffset,
|
||||||
|
RawValueOffset: rawValueOffset,
|
||||||
|
AddressableData: addressableData,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue