gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

value_context.go (12088B)


      1 package exifcommon
      2 
      3 import (
      4 	"errors"
      5 	"io"
      6 
      7 	"encoding/binary"
      8 
      9 	"github.com/dsoprea/go-logging"
     10 )
     11 
     12 var (
     13 	parser *Parser
     14 )
     15 
     16 var (
     17 	// ErrNotFarValue indicates that an offset-based lookup was attempted for a
     18 	// non-offset-based (embedded) value.
     19 	ErrNotFarValue = errors.New("not a far value")
     20 )
     21 
     22 // ValueContext embeds all of the parameters required to find and extract the
     23 // actual tag value.
     24 type ValueContext struct {
     25 	unitCount      uint32
     26 	valueOffset    uint32
     27 	rawValueOffset []byte
     28 	rs             io.ReadSeeker
     29 
     30 	tagType   TagTypePrimitive
     31 	byteOrder binary.ByteOrder
     32 
     33 	// undefinedValueTagType is the effective type to use if this is an
     34 	// "undefined" value.
     35 	undefinedValueTagType TagTypePrimitive
     36 
     37 	ifdPath string
     38 	tagId   uint16
     39 }
     40 
     41 // TODO(dustin): We can update newValueContext() to derive `valueOffset` itself (from `rawValueOffset`).
     42 
     43 // NewValueContext returns a new ValueContext struct.
     44 func NewValueContext(ifdPath string, tagId uint16, unitCount, valueOffset uint32, rawValueOffset []byte, rs io.ReadSeeker, tagType TagTypePrimitive, byteOrder binary.ByteOrder) *ValueContext {
     45 	return &ValueContext{
     46 		unitCount:      unitCount,
     47 		valueOffset:    valueOffset,
     48 		rawValueOffset: rawValueOffset,
     49 		rs:             rs,
     50 
     51 		tagType:   tagType,
     52 		byteOrder: byteOrder,
     53 
     54 		ifdPath: ifdPath,
     55 		tagId:   tagId,
     56 	}
     57 }
     58 
     59 // SetUndefinedValueType sets the effective type if this is an unknown-type tag.
     60 func (vc *ValueContext) SetUndefinedValueType(tagType TagTypePrimitive) {
     61 	if vc.tagType != TypeUndefined {
     62 		log.Panicf("can not set effective type for unknown-type tag because this is *not* an unknown-type tag")
     63 	}
     64 
     65 	vc.undefinedValueTagType = tagType
     66 }
     67 
     68 // UnitCount returns the embedded unit-count.
     69 func (vc *ValueContext) UnitCount() uint32 {
     70 	return vc.unitCount
     71 }
     72 
     73 // ValueOffset returns the value-offset decoded as a `uint32`.
     74 func (vc *ValueContext) ValueOffset() uint32 {
     75 	return vc.valueOffset
     76 }
     77 
     78 // RawValueOffset returns the uninterpreted value-offset. This is used for
     79 // embedded values (values small enough to fit within the offset bytes rather
     80 // than needing to be stored elsewhere and referred to by an actual offset).
     81 func (vc *ValueContext) RawValueOffset() []byte {
     82 	return vc.rawValueOffset
     83 }
     84 
     85 // AddressableData returns the block of data that we can dereference into.
     86 func (vc *ValueContext) AddressableData() io.ReadSeeker {
     87 
     88 	// RELEASE)dustin): Rename from AddressableData() to ReadSeeker()
     89 
     90 	return vc.rs
     91 }
     92 
     93 // ByteOrder returns the byte-order of numbers.
     94 func (vc *ValueContext) ByteOrder() binary.ByteOrder {
     95 	return vc.byteOrder
     96 }
     97 
     98 // IfdPath returns the path of the IFD containing this tag.
     99 func (vc *ValueContext) IfdPath() string {
    100 	return vc.ifdPath
    101 }
    102 
    103 // TagId returns the ID of the tag that we represent.
    104 func (vc *ValueContext) TagId() uint16 {
    105 	return vc.tagId
    106 }
    107 
    108 // isEmbedded returns whether the value is embedded or a reference. This can't
    109 // be precalculated since the size is not defined for all types (namely the
    110 // "undefined" types).
    111 func (vc *ValueContext) isEmbedded() bool {
    112 	tagType := vc.effectiveValueType()
    113 
    114 	return (tagType.Size() * int(vc.unitCount)) <= 4
    115 }
    116 
    117 // SizeInBytes returns the number of bytes that this value requires. The
    118 // underlying call will panic if the type is UNDEFINED. It is the
    119 // responsibility of the caller to preemptively check that.
    120 func (vc *ValueContext) SizeInBytes() int {
    121 	tagType := vc.effectiveValueType()
    122 
    123 	return tagType.Size() * int(vc.unitCount)
    124 }
    125 
    126 // effectiveValueType returns the effective type of the unknown-type tag or, if
    127 // not unknown, the actual type.
    128 func (vc *ValueContext) effectiveValueType() (tagType TagTypePrimitive) {
    129 	if vc.tagType == TypeUndefined {
    130 		tagType = vc.undefinedValueTagType
    131 
    132 		if tagType == 0 {
    133 			log.Panicf("undefined-value type not set")
    134 		}
    135 	} else {
    136 		tagType = vc.tagType
    137 	}
    138 
    139 	return tagType
    140 }
    141 
    142 // readRawEncoded returns the encoded bytes for the value that we represent.
    143 func (vc *ValueContext) readRawEncoded() (rawBytes []byte, err error) {
    144 	defer func() {
    145 		if state := recover(); state != nil {
    146 			err = log.Wrap(state.(error))
    147 		}
    148 	}()
    149 
    150 	tagType := vc.effectiveValueType()
    151 
    152 	unitSizeRaw := uint32(tagType.Size())
    153 
    154 	if vc.isEmbedded() == true {
    155 		byteLength := unitSizeRaw * vc.unitCount
    156 		return vc.rawValueOffset[:byteLength], nil
    157 	}
    158 
    159 	_, err = vc.rs.Seek(int64(vc.valueOffset), io.SeekStart)
    160 	log.PanicIf(err)
    161 
    162 	rawBytes = make([]byte, vc.unitCount*unitSizeRaw)
    163 
    164 	_, err = io.ReadFull(vc.rs, rawBytes)
    165 	log.PanicIf(err)
    166 
    167 	return rawBytes, nil
    168 }
    169 
    170 // GetFarOffset returns the offset if the value is not embedded [within the
    171 // pointer itself] or an error if an embedded value.
    172 func (vc *ValueContext) GetFarOffset() (offset uint32, err error) {
    173 	if vc.isEmbedded() == true {
    174 		return 0, ErrNotFarValue
    175 	}
    176 
    177 	return vc.valueOffset, nil
    178 }
    179 
    180 // ReadRawEncoded returns the encoded bytes for the value that we represent.
    181 func (vc *ValueContext) ReadRawEncoded() (rawBytes []byte, err error) {
    182 
    183 	// TODO(dustin): Remove this method and rename readRawEncoded in its place.
    184 
    185 	return vc.readRawEncoded()
    186 }
    187 
    188 // Format returns a string representation for the value.
    189 //
    190 // Where the type is not ASCII, `justFirst` indicates whether to just stringify
    191 // the first item in the slice (or return an empty string if the slice is
    192 // empty).
    193 //
    194 // Since this method lacks the information to process undefined-type tags (e.g.
    195 // byte-order, tag-ID, IFD type), it will return an error if attempted. See
    196 // `Undefined()`.
    197 func (vc *ValueContext) Format() (value string, err error) {
    198 	defer func() {
    199 		if state := recover(); state != nil {
    200 			err = log.Wrap(state.(error))
    201 		}
    202 	}()
    203 
    204 	rawBytes, err := vc.readRawEncoded()
    205 	log.PanicIf(err)
    206 
    207 	phrase, err := FormatFromBytes(rawBytes, vc.effectiveValueType(), false, vc.byteOrder)
    208 	log.PanicIf(err)
    209 
    210 	return phrase, nil
    211 }
    212 
    213 // FormatFirst is similar to `Format` but only gets and stringifies the first
    214 // item.
    215 func (vc *ValueContext) FormatFirst() (value string, err error) {
    216 	defer func() {
    217 		if state := recover(); state != nil {
    218 			err = log.Wrap(state.(error))
    219 		}
    220 	}()
    221 
    222 	rawBytes, err := vc.readRawEncoded()
    223 	log.PanicIf(err)
    224 
    225 	phrase, err := FormatFromBytes(rawBytes, vc.tagType, true, vc.byteOrder)
    226 	log.PanicIf(err)
    227 
    228 	return phrase, nil
    229 }
    230 
    231 // ReadBytes parses the encoded byte-array from the value-context.
    232 func (vc *ValueContext) ReadBytes() (value []byte, err error) {
    233 	defer func() {
    234 		if state := recover(); state != nil {
    235 			err = log.Wrap(state.(error))
    236 		}
    237 	}()
    238 
    239 	rawValue, err := vc.readRawEncoded()
    240 	log.PanicIf(err)
    241 
    242 	value, err = parser.ParseBytes(rawValue, vc.unitCount)
    243 	log.PanicIf(err)
    244 
    245 	return value, nil
    246 }
    247 
    248 // ReadAscii parses the encoded NUL-terminated ASCII string from the value-
    249 // context.
    250 func (vc *ValueContext) ReadAscii() (value string, err error) {
    251 	defer func() {
    252 		if state := recover(); state != nil {
    253 			err = log.Wrap(state.(error))
    254 		}
    255 	}()
    256 
    257 	rawValue, err := vc.readRawEncoded()
    258 	log.PanicIf(err)
    259 
    260 	value, err = parser.ParseAscii(rawValue, vc.unitCount)
    261 	log.PanicIf(err)
    262 
    263 	return value, nil
    264 }
    265 
    266 // ReadAsciiNoNul parses the non-NUL-terminated encoded ASCII string from the
    267 // value-context.
    268 func (vc *ValueContext) ReadAsciiNoNul() (value string, err error) {
    269 	defer func() {
    270 		if state := recover(); state != nil {
    271 			err = log.Wrap(state.(error))
    272 		}
    273 	}()
    274 
    275 	rawValue, err := vc.readRawEncoded()
    276 	log.PanicIf(err)
    277 
    278 	value, err = parser.ParseAsciiNoNul(rawValue, vc.unitCount)
    279 	log.PanicIf(err)
    280 
    281 	return value, nil
    282 }
    283 
    284 // ReadShorts parses the list of encoded shorts from the value-context.
    285 func (vc *ValueContext) ReadShorts() (value []uint16, err error) {
    286 	defer func() {
    287 		if state := recover(); state != nil {
    288 			err = log.Wrap(state.(error))
    289 		}
    290 	}()
    291 
    292 	rawValue, err := vc.readRawEncoded()
    293 	log.PanicIf(err)
    294 
    295 	value, err = parser.ParseShorts(rawValue, vc.unitCount, vc.byteOrder)
    296 	log.PanicIf(err)
    297 
    298 	return value, nil
    299 }
    300 
    301 // ReadLongs parses the list of encoded, unsigned longs from the value-context.
    302 func (vc *ValueContext) ReadLongs() (value []uint32, err error) {
    303 	defer func() {
    304 		if state := recover(); state != nil {
    305 			err = log.Wrap(state.(error))
    306 		}
    307 	}()
    308 
    309 	rawValue, err := vc.readRawEncoded()
    310 	log.PanicIf(err)
    311 
    312 	value, err = parser.ParseLongs(rawValue, vc.unitCount, vc.byteOrder)
    313 	log.PanicIf(err)
    314 
    315 	return value, nil
    316 }
    317 
    318 // ReadFloats parses the list of encoded, floats from the value-context.
    319 func (vc *ValueContext) ReadFloats() (value []float32, err error) {
    320 	defer func() {
    321 		if state := recover(); state != nil {
    322 			err = log.Wrap(state.(error))
    323 		}
    324 	}()
    325 
    326 	rawValue, err := vc.readRawEncoded()
    327 	log.PanicIf(err)
    328 
    329 	value, err = parser.ParseFloats(rawValue, vc.unitCount, vc.byteOrder)
    330 	log.PanicIf(err)
    331 
    332 	return value, nil
    333 }
    334 
    335 // ReadDoubles parses the list of encoded, doubles from the value-context.
    336 func (vc *ValueContext) ReadDoubles() (value []float64, err error) {
    337 	defer func() {
    338 		if state := recover(); state != nil {
    339 			err = log.Wrap(state.(error))
    340 		}
    341 	}()
    342 
    343 	rawValue, err := vc.readRawEncoded()
    344 	log.PanicIf(err)
    345 
    346 	value, err = parser.ParseDoubles(rawValue, vc.unitCount, vc.byteOrder)
    347 	log.PanicIf(err)
    348 
    349 	return value, nil
    350 }
    351 
    352 // ReadRationals parses the list of encoded, unsigned rationals from the value-
    353 // context.
    354 func (vc *ValueContext) ReadRationals() (value []Rational, err error) {
    355 	defer func() {
    356 		if state := recover(); state != nil {
    357 			err = log.Wrap(state.(error))
    358 		}
    359 	}()
    360 
    361 	rawValue, err := vc.readRawEncoded()
    362 	log.PanicIf(err)
    363 
    364 	value, err = parser.ParseRationals(rawValue, vc.unitCount, vc.byteOrder)
    365 	log.PanicIf(err)
    366 
    367 	return value, nil
    368 }
    369 
    370 // ReadSignedLongs parses the list of encoded, signed longs from the value-context.
    371 func (vc *ValueContext) ReadSignedLongs() (value []int32, err error) {
    372 	defer func() {
    373 		if state := recover(); state != nil {
    374 			err = log.Wrap(state.(error))
    375 		}
    376 	}()
    377 
    378 	rawValue, err := vc.readRawEncoded()
    379 	log.PanicIf(err)
    380 
    381 	value, err = parser.ParseSignedLongs(rawValue, vc.unitCount, vc.byteOrder)
    382 	log.PanicIf(err)
    383 
    384 	return value, nil
    385 }
    386 
    387 // ReadSignedRationals parses the list of encoded, signed rationals from the
    388 // value-context.
    389 func (vc *ValueContext) ReadSignedRationals() (value []SignedRational, err error) {
    390 	defer func() {
    391 		if state := recover(); state != nil {
    392 			err = log.Wrap(state.(error))
    393 		}
    394 	}()
    395 
    396 	rawValue, err := vc.readRawEncoded()
    397 	log.PanicIf(err)
    398 
    399 	value, err = parser.ParseSignedRationals(rawValue, vc.unitCount, vc.byteOrder)
    400 	log.PanicIf(err)
    401 
    402 	return value, nil
    403 }
    404 
    405 // Values knows how to resolve the given value. This value is always a list
    406 // (undefined-values aside), so we're named accordingly.
    407 //
    408 // Since this method lacks the information to process unknown-type tags (e.g.
    409 // byte-order, tag-ID, IFD type), it will return an error if attempted. See
    410 // `Undefined()`.
    411 func (vc *ValueContext) Values() (values interface{}, err error) {
    412 	defer func() {
    413 		if state := recover(); state != nil {
    414 			err = log.Wrap(state.(error))
    415 		}
    416 	}()
    417 
    418 	if vc.tagType == TypeByte {
    419 		values, err = vc.ReadBytes()
    420 		log.PanicIf(err)
    421 	} else if vc.tagType == TypeAscii {
    422 		values, err = vc.ReadAscii()
    423 		log.PanicIf(err)
    424 	} else if vc.tagType == TypeAsciiNoNul {
    425 		values, err = vc.ReadAsciiNoNul()
    426 		log.PanicIf(err)
    427 	} else if vc.tagType == TypeShort {
    428 		values, err = vc.ReadShorts()
    429 		log.PanicIf(err)
    430 	} else if vc.tagType == TypeLong {
    431 		values, err = vc.ReadLongs()
    432 		log.PanicIf(err)
    433 	} else if vc.tagType == TypeRational {
    434 		values, err = vc.ReadRationals()
    435 		log.PanicIf(err)
    436 	} else if vc.tagType == TypeSignedLong {
    437 		values, err = vc.ReadSignedLongs()
    438 		log.PanicIf(err)
    439 	} else if vc.tagType == TypeSignedRational {
    440 		values, err = vc.ReadSignedRationals()
    441 		log.PanicIf(err)
    442 	} else if vc.tagType == TypeFloat {
    443 		values, err = vc.ReadFloats()
    444 		log.PanicIf(err)
    445 	} else if vc.tagType == TypeDouble {
    446 		values, err = vc.ReadDoubles()
    447 		log.PanicIf(err)
    448 	} else if vc.tagType == TypeUndefined {
    449 		log.Panicf("will not parse undefined-type value")
    450 
    451 		// Never called.
    452 		return nil, nil
    453 	} else {
    454 		log.Panicf("value of type [%s] is unparseable", vc.tagType)
    455 		// Never called.
    456 		return nil, nil
    457 	}
    458 
    459 	return values, nil
    460 }
    461 
    462 func init() {
    463 	parser = new(Parser)
    464 }