summaryrefslogtreecommitdiff
path: root/vendor/github.com/dsoprea/go-exif/v3/common/value_context.go
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2024-08-02 11:46:41 +0000
committerLibravatar GitHub <noreply@github.com>2024-08-02 12:46:41 +0100
commit94e87610c4ce9bbb1c614a61bab29c1422fed11b (patch)
tree2e06b8ce64212140e796f6077ba841b6cc678501 /vendor/github.com/dsoprea/go-exif/v3/common/value_context.go
parent[feature] Allow import of following and blocks via CSV (#3150) (diff)
downloadgotosocial-94e87610c4ce9bbb1c614a61bab29c1422fed11b.tar.xz
[chore] add back exif-terminator and use only for jpeg,png,webp (#3161)
* add back exif-terminator and use only for jpeg,png,webp * fix arguments passed to terminateExif() * pull in latest exif-terminator * fix test * update processed img --------- Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Diffstat (limited to 'vendor/github.com/dsoprea/go-exif/v3/common/value_context.go')
-rw-r--r--vendor/github.com/dsoprea/go-exif/v3/common/value_context.go464
1 files changed, 464 insertions, 0 deletions
diff --git a/vendor/github.com/dsoprea/go-exif/v3/common/value_context.go b/vendor/github.com/dsoprea/go-exif/v3/common/value_context.go
new file mode 100644
index 000000000..b9e634106
--- /dev/null
+++ b/vendor/github.com/dsoprea/go-exif/v3/common/value_context.go
@@ -0,0 +1,464 @@
+package exifcommon
+
+import (
+ "errors"
+ "io"
+
+ "encoding/binary"
+
+ "github.com/dsoprea/go-logging"
+)
+
+var (
+ parser *Parser
+)
+
+var (
+ // ErrNotFarValue indicates that an offset-based lookup was attempted for a
+ // non-offset-based (embedded) value.
+ ErrNotFarValue = errors.New("not a far value")
+)
+
+// ValueContext embeds all of the parameters required to find and extract the
+// actual tag value.
+type ValueContext struct {
+ unitCount uint32
+ valueOffset uint32
+ rawValueOffset []byte
+ rs io.ReadSeeker
+
+ tagType TagTypePrimitive
+ byteOrder binary.ByteOrder
+
+ // undefinedValueTagType is the effective type to use if this is an
+ // "undefined" value.
+ undefinedValueTagType TagTypePrimitive
+
+ ifdPath string
+ tagId uint16
+}
+
+// TODO(dustin): We can update newValueContext() to derive `valueOffset` itself (from `rawValueOffset`).
+
+// NewValueContext returns a new ValueContext struct.
+func NewValueContext(ifdPath string, tagId uint16, unitCount, valueOffset uint32, rawValueOffset []byte, rs io.ReadSeeker, tagType TagTypePrimitive, byteOrder binary.ByteOrder) *ValueContext {
+ return &ValueContext{
+ unitCount: unitCount,
+ valueOffset: valueOffset,
+ rawValueOffset: rawValueOffset,
+ rs: rs,
+
+ tagType: tagType,
+ byteOrder: byteOrder,
+
+ ifdPath: ifdPath,
+ tagId: tagId,
+ }
+}
+
+// SetUndefinedValueType sets the effective type if this is an unknown-type tag.
+func (vc *ValueContext) SetUndefinedValueType(tagType TagTypePrimitive) {
+ if vc.tagType != TypeUndefined {
+ log.Panicf("can not set effective type for unknown-type tag because this is *not* an unknown-type tag")
+ }
+
+ vc.undefinedValueTagType = tagType
+}
+
+// UnitCount returns the embedded unit-count.
+func (vc *ValueContext) UnitCount() uint32 {
+ return vc.unitCount
+}
+
+// ValueOffset returns the value-offset decoded as a `uint32`.
+func (vc *ValueContext) ValueOffset() uint32 {
+ return vc.valueOffset
+}
+
+// RawValueOffset returns the uninterpreted value-offset. This is used for
+// embedded values (values small enough to fit within the offset bytes rather
+// than needing to be stored elsewhere and referred to by an actual offset).
+func (vc *ValueContext) RawValueOffset() []byte {
+ return vc.rawValueOffset
+}
+
+// AddressableData returns the block of data that we can dereference into.
+func (vc *ValueContext) AddressableData() io.ReadSeeker {
+
+ // RELEASE)dustin): Rename from AddressableData() to ReadSeeker()
+
+ return vc.rs
+}
+
+// ByteOrder returns the byte-order of numbers.
+func (vc *ValueContext) ByteOrder() binary.ByteOrder {
+ return vc.byteOrder
+}
+
+// IfdPath returns the path of the IFD containing this tag.
+func (vc *ValueContext) IfdPath() string {
+ return vc.ifdPath
+}
+
+// TagId returns the ID of the tag that we represent.
+func (vc *ValueContext) TagId() uint16 {
+ return vc.tagId
+}
+
+// isEmbedded returns whether the value is embedded or a reference. This can't
+// be precalculated since the size is not defined for all types (namely the
+// "undefined" types).
+func (vc *ValueContext) isEmbedded() bool {
+ tagType := vc.effectiveValueType()
+
+ return (tagType.Size() * int(vc.unitCount)) <= 4
+}
+
+// SizeInBytes returns the number of bytes that this value requires. The
+// underlying call will panic if the type is UNDEFINED. It is the
+// responsibility of the caller to preemptively check that.
+func (vc *ValueContext) SizeInBytes() int {
+ tagType := vc.effectiveValueType()
+
+ return tagType.Size() * int(vc.unitCount)
+}
+
+// effectiveValueType returns the effective type of the unknown-type tag or, if
+// not unknown, the actual type.
+func (vc *ValueContext) effectiveValueType() (tagType TagTypePrimitive) {
+ if vc.tagType == TypeUndefined {
+ tagType = vc.undefinedValueTagType
+
+ if tagType == 0 {
+ log.Panicf("undefined-value type not set")
+ }
+ } else {
+ tagType = vc.tagType
+ }
+
+ return tagType
+}
+
+// readRawEncoded returns the encoded bytes for the value that we represent.
+func (vc *ValueContext) readRawEncoded() (rawBytes []byte, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ tagType := vc.effectiveValueType()
+
+ unitSizeRaw := uint32(tagType.Size())
+
+ if vc.isEmbedded() == true {
+ byteLength := unitSizeRaw * vc.unitCount
+ return vc.rawValueOffset[:byteLength], nil
+ }
+
+ _, err = vc.rs.Seek(int64(vc.valueOffset), io.SeekStart)
+ log.PanicIf(err)
+
+ rawBytes = make([]byte, vc.unitCount*unitSizeRaw)
+
+ _, err = io.ReadFull(vc.rs, rawBytes)
+ log.PanicIf(err)
+
+ return rawBytes, nil
+}
+
+// GetFarOffset returns the offset if the value is not embedded [within the
+// pointer itself] or an error if an embedded value.
+func (vc *ValueContext) GetFarOffset() (offset uint32, err error) {
+ if vc.isEmbedded() == true {
+ return 0, ErrNotFarValue
+ }
+
+ return vc.valueOffset, nil
+}
+
+// ReadRawEncoded returns the encoded bytes for the value that we represent.
+func (vc *ValueContext) ReadRawEncoded() (rawBytes []byte, err error) {
+
+ // TODO(dustin): Remove this method and rename readRawEncoded in its place.
+
+ return vc.readRawEncoded()
+}
+
+// Format returns a string representation for the value.
+//
+// Where the type is not ASCII, `justFirst` indicates whether to just stringify
+// the first item in the slice (or return an empty string if the slice is
+// empty).
+//
+// Since this method lacks the information to process undefined-type tags (e.g.
+// byte-order, tag-ID, IFD type), it will return an error if attempted. See
+// `Undefined()`.
+func (vc *ValueContext) Format() (value string, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ rawBytes, err := vc.readRawEncoded()
+ log.PanicIf(err)
+
+ phrase, err := FormatFromBytes(rawBytes, vc.effectiveValueType(), false, vc.byteOrder)
+ log.PanicIf(err)
+
+ return phrase, nil
+}
+
+// FormatFirst is similar to `Format` but only gets and stringifies the first
+// item.
+func (vc *ValueContext) FormatFirst() (value string, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ rawBytes, err := vc.readRawEncoded()
+ log.PanicIf(err)
+
+ phrase, err := FormatFromBytes(rawBytes, vc.tagType, true, vc.byteOrder)
+ log.PanicIf(err)
+
+ return phrase, nil
+}
+
+// ReadBytes parses the encoded byte-array from the value-context.
+func (vc *ValueContext) ReadBytes() (value []byte, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ rawValue, err := vc.readRawEncoded()
+ log.PanicIf(err)
+
+ value, err = parser.ParseBytes(rawValue, vc.unitCount)
+ log.PanicIf(err)
+
+ return value, nil
+}
+
+// ReadAscii parses the encoded NUL-terminated ASCII string from the value-
+// context.
+func (vc *ValueContext) ReadAscii() (value string, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ rawValue, err := vc.readRawEncoded()
+ log.PanicIf(err)
+
+ value, err = parser.ParseAscii(rawValue, vc.unitCount)
+ log.PanicIf(err)
+
+ return value, nil
+}
+
+// ReadAsciiNoNul parses the non-NUL-terminated encoded ASCII string from the
+// value-context.
+func (vc *ValueContext) ReadAsciiNoNul() (value string, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ rawValue, err := vc.readRawEncoded()
+ log.PanicIf(err)
+
+ value, err = parser.ParseAsciiNoNul(rawValue, vc.unitCount)
+ log.PanicIf(err)
+
+ return value, nil
+}
+
+// ReadShorts parses the list of encoded shorts from the value-context.
+func (vc *ValueContext) ReadShorts() (value []uint16, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ rawValue, err := vc.readRawEncoded()
+ log.PanicIf(err)
+
+ value, err = parser.ParseShorts(rawValue, vc.unitCount, vc.byteOrder)
+ log.PanicIf(err)
+
+ return value, nil
+}
+
+// ReadLongs parses the list of encoded, unsigned longs from the value-context.
+func (vc *ValueContext) ReadLongs() (value []uint32, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ rawValue, err := vc.readRawEncoded()
+ log.PanicIf(err)
+
+ value, err = parser.ParseLongs(rawValue, vc.unitCount, vc.byteOrder)
+ log.PanicIf(err)
+
+ return value, nil
+}
+
+// ReadFloats parses the list of encoded, floats from the value-context.
+func (vc *ValueContext) ReadFloats() (value []float32, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ rawValue, err := vc.readRawEncoded()
+ log.PanicIf(err)
+
+ value, err = parser.ParseFloats(rawValue, vc.unitCount, vc.byteOrder)
+ log.PanicIf(err)
+
+ return value, nil
+}
+
+// ReadDoubles parses the list of encoded, doubles from the value-context.
+func (vc *ValueContext) ReadDoubles() (value []float64, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ rawValue, err := vc.readRawEncoded()
+ log.PanicIf(err)
+
+ value, err = parser.ParseDoubles(rawValue, vc.unitCount, vc.byteOrder)
+ log.PanicIf(err)
+
+ return value, nil
+}
+
+// ReadRationals parses the list of encoded, unsigned rationals from the value-
+// context.
+func (vc *ValueContext) ReadRationals() (value []Rational, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ rawValue, err := vc.readRawEncoded()
+ log.PanicIf(err)
+
+ value, err = parser.ParseRationals(rawValue, vc.unitCount, vc.byteOrder)
+ log.PanicIf(err)
+
+ return value, nil
+}
+
+// ReadSignedLongs parses the list of encoded, signed longs from the value-context.
+func (vc *ValueContext) ReadSignedLongs() (value []int32, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ rawValue, err := vc.readRawEncoded()
+ log.PanicIf(err)
+
+ value, err = parser.ParseSignedLongs(rawValue, vc.unitCount, vc.byteOrder)
+ log.PanicIf(err)
+
+ return value, nil
+}
+
+// ReadSignedRationals parses the list of encoded, signed rationals from the
+// value-context.
+func (vc *ValueContext) ReadSignedRationals() (value []SignedRational, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ rawValue, err := vc.readRawEncoded()
+ log.PanicIf(err)
+
+ value, err = parser.ParseSignedRationals(rawValue, vc.unitCount, vc.byteOrder)
+ log.PanicIf(err)
+
+ return value, nil
+}
+
+// Values knows how to resolve the given value. This value is always a list
+// (undefined-values aside), so we're named accordingly.
+//
+// Since this method lacks the information to process unknown-type tags (e.g.
+// byte-order, tag-ID, IFD type), it will return an error if attempted. See
+// `Undefined()`.
+func (vc *ValueContext) Values() (values interface{}, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ if vc.tagType == TypeByte {
+ values, err = vc.ReadBytes()
+ log.PanicIf(err)
+ } else if vc.tagType == TypeAscii {
+ values, err = vc.ReadAscii()
+ log.PanicIf(err)
+ } else if vc.tagType == TypeAsciiNoNul {
+ values, err = vc.ReadAsciiNoNul()
+ log.PanicIf(err)
+ } else if vc.tagType == TypeShort {
+ values, err = vc.ReadShorts()
+ log.PanicIf(err)
+ } else if vc.tagType == TypeLong {
+ values, err = vc.ReadLongs()
+ log.PanicIf(err)
+ } else if vc.tagType == TypeRational {
+ values, err = vc.ReadRationals()
+ log.PanicIf(err)
+ } else if vc.tagType == TypeSignedLong {
+ values, err = vc.ReadSignedLongs()
+ log.PanicIf(err)
+ } else if vc.tagType == TypeSignedRational {
+ values, err = vc.ReadSignedRationals()
+ log.PanicIf(err)
+ } else if vc.tagType == TypeFloat {
+ values, err = vc.ReadFloats()
+ log.PanicIf(err)
+ } else if vc.tagType == TypeDouble {
+ values, err = vc.ReadDoubles()
+ log.PanicIf(err)
+ } else if vc.tagType == TypeUndefined {
+ log.Panicf("will not parse undefined-type value")
+
+ // Never called.
+ return nil, nil
+ } else {
+ log.Panicf("value of type [%s] is unparseable", vc.tagType)
+ // Never called.
+ return nil, nil
+ }
+
+ return values, nil
+}
+
+func init() {
+ parser = new(Parser)
+}