...

Source file src/github.com/dsoprea/go-exif/v3/common/value_context.go

Documentation: github.com/dsoprea/go-exif/v3/common

     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  }
   465  

View as plain text