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 }