...

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

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

     1  package exifcommon
     2  
     3  import (
     4  	"bytes"
     5  	"math"
     6  	"reflect"
     7  	"time"
     8  
     9  	"encoding/binary"
    10  
    11  	"github.com/dsoprea/go-logging"
    12  )
    13  
    14  var (
    15  	typeEncodeLogger = log.NewLogger("exif.type_encode")
    16  )
    17  
    18  // EncodedData encapsulates the compound output of an encoding operation.
    19  type EncodedData struct {
    20  	Type    TagTypePrimitive
    21  	Encoded []byte
    22  
    23  	// TODO(dustin): Is this really necessary? We might have this just to correlate to the incoming stream format (raw bytes and a unit-count both for incoming and outgoing).
    24  	UnitCount uint32
    25  }
    26  
    27  // ValueEncoder knows how to encode values of every type to bytes.
    28  type ValueEncoder struct {
    29  	byteOrder binary.ByteOrder
    30  }
    31  
    32  // NewValueEncoder returns a new ValueEncoder.
    33  func NewValueEncoder(byteOrder binary.ByteOrder) *ValueEncoder {
    34  	return &ValueEncoder{
    35  		byteOrder: byteOrder,
    36  	}
    37  }
    38  
    39  func (ve *ValueEncoder) encodeBytes(value []uint8) (ed EncodedData, err error) {
    40  	ed.Type = TypeByte
    41  	ed.Encoded = []byte(value)
    42  	ed.UnitCount = uint32(len(value))
    43  
    44  	return ed, nil
    45  }
    46  
    47  func (ve *ValueEncoder) encodeAscii(value string) (ed EncodedData, err error) {
    48  	ed.Type = TypeAscii
    49  
    50  	ed.Encoded = []byte(value)
    51  	ed.Encoded = append(ed.Encoded, 0)
    52  
    53  	ed.UnitCount = uint32(len(ed.Encoded))
    54  
    55  	return ed, nil
    56  }
    57  
    58  // encodeAsciiNoNul returns a string encoded as a byte-string without a trailing
    59  // NUL byte.
    60  //
    61  // Note that:
    62  //
    63  // 1. This type can not be automatically encoded using `Encode()`. The default
    64  //    mode is to encode *with* a trailing NUL byte using `encodeAscii`. Only
    65  //    certain undefined-type tags using an unterminated ASCII string and these
    66  //    are exceptional in nature.
    67  //
    68  // 2. The presence of this method allows us to completely test the complimentary
    69  //    no-nul parser.
    70  //
    71  func (ve *ValueEncoder) encodeAsciiNoNul(value string) (ed EncodedData, err error) {
    72  	ed.Type = TypeAsciiNoNul
    73  	ed.Encoded = []byte(value)
    74  	ed.UnitCount = uint32(len(ed.Encoded))
    75  
    76  	return ed, nil
    77  }
    78  
    79  func (ve *ValueEncoder) encodeShorts(value []uint16) (ed EncodedData, err error) {
    80  	defer func() {
    81  		if state := recover(); state != nil {
    82  			err = log.Wrap(state.(error))
    83  		}
    84  	}()
    85  
    86  	ed.UnitCount = uint32(len(value))
    87  	ed.Encoded = make([]byte, ed.UnitCount*2)
    88  
    89  	for i := uint32(0); i < ed.UnitCount; i++ {
    90  		ve.byteOrder.PutUint16(ed.Encoded[i*2:(i+1)*2], value[i])
    91  	}
    92  
    93  	ed.Type = TypeShort
    94  
    95  	return ed, nil
    96  }
    97  
    98  func (ve *ValueEncoder) encodeLongs(value []uint32) (ed EncodedData, err error) {
    99  	defer func() {
   100  		if state := recover(); state != nil {
   101  			err = log.Wrap(state.(error))
   102  		}
   103  	}()
   104  
   105  	ed.UnitCount = uint32(len(value))
   106  	ed.Encoded = make([]byte, ed.UnitCount*4)
   107  
   108  	for i := uint32(0); i < ed.UnitCount; i++ {
   109  		ve.byteOrder.PutUint32(ed.Encoded[i*4:(i+1)*4], value[i])
   110  	}
   111  
   112  	ed.Type = TypeLong
   113  
   114  	return ed, nil
   115  }
   116  
   117  func (ve *ValueEncoder) encodeFloats(value []float32) (ed EncodedData, err error) {
   118  	defer func() {
   119  		if state := recover(); state != nil {
   120  			err = log.Wrap(state.(error))
   121  		}
   122  	}()
   123  
   124  	ed.UnitCount = uint32(len(value))
   125  	ed.Encoded = make([]byte, ed.UnitCount*4)
   126  
   127  	for i := uint32(0); i < ed.UnitCount; i++ {
   128  		ve.byteOrder.PutUint32(ed.Encoded[i*4:(i+1)*4], math.Float32bits(value[i]))
   129  	}
   130  
   131  	ed.Type = TypeFloat
   132  
   133  	return ed, nil
   134  }
   135  
   136  func (ve *ValueEncoder) encodeDoubles(value []float64) (ed EncodedData, err error) {
   137  	defer func() {
   138  		if state := recover(); state != nil {
   139  			err = log.Wrap(state.(error))
   140  		}
   141  	}()
   142  
   143  	ed.UnitCount = uint32(len(value))
   144  	ed.Encoded = make([]byte, ed.UnitCount*8)
   145  
   146  	for i := uint32(0); i < ed.UnitCount; i++ {
   147  		ve.byteOrder.PutUint64(ed.Encoded[i*8:(i+1)*8], math.Float64bits(value[i]))
   148  	}
   149  
   150  	ed.Type = TypeDouble
   151  
   152  	return ed, nil
   153  }
   154  
   155  func (ve *ValueEncoder) encodeRationals(value []Rational) (ed EncodedData, err error) {
   156  	defer func() {
   157  		if state := recover(); state != nil {
   158  			err = log.Wrap(state.(error))
   159  		}
   160  	}()
   161  
   162  	ed.UnitCount = uint32(len(value))
   163  	ed.Encoded = make([]byte, ed.UnitCount*8)
   164  
   165  	for i := uint32(0); i < ed.UnitCount; i++ {
   166  		ve.byteOrder.PutUint32(ed.Encoded[i*8+0:i*8+4], value[i].Numerator)
   167  		ve.byteOrder.PutUint32(ed.Encoded[i*8+4:i*8+8], value[i].Denominator)
   168  	}
   169  
   170  	ed.Type = TypeRational
   171  
   172  	return ed, nil
   173  }
   174  
   175  func (ve *ValueEncoder) encodeSignedLongs(value []int32) (ed EncodedData, err error) {
   176  	defer func() {
   177  		if state := recover(); state != nil {
   178  			err = log.Wrap(state.(error))
   179  		}
   180  	}()
   181  
   182  	ed.UnitCount = uint32(len(value))
   183  
   184  	b := bytes.NewBuffer(make([]byte, 0, 8*ed.UnitCount))
   185  
   186  	for i := uint32(0); i < ed.UnitCount; i++ {
   187  		err := binary.Write(b, ve.byteOrder, value[i])
   188  		log.PanicIf(err)
   189  	}
   190  
   191  	ed.Type = TypeSignedLong
   192  	ed.Encoded = b.Bytes()
   193  
   194  	return ed, nil
   195  }
   196  
   197  func (ve *ValueEncoder) encodeSignedRationals(value []SignedRational) (ed EncodedData, err error) {
   198  	defer func() {
   199  		if state := recover(); state != nil {
   200  			err = log.Wrap(state.(error))
   201  		}
   202  	}()
   203  
   204  	ed.UnitCount = uint32(len(value))
   205  
   206  	b := bytes.NewBuffer(make([]byte, 0, 8*ed.UnitCount))
   207  
   208  	for i := uint32(0); i < ed.UnitCount; i++ {
   209  		err := binary.Write(b, ve.byteOrder, value[i].Numerator)
   210  		log.PanicIf(err)
   211  
   212  		err = binary.Write(b, ve.byteOrder, value[i].Denominator)
   213  		log.PanicIf(err)
   214  	}
   215  
   216  	ed.Type = TypeSignedRational
   217  	ed.Encoded = b.Bytes()
   218  
   219  	return ed, nil
   220  }
   221  
   222  // Encode returns bytes for the given value, infering type from the actual
   223  // value. This does not support `TypeAsciiNoNull` (all strings are encoded as
   224  // `TypeAscii`).
   225  func (ve *ValueEncoder) Encode(value interface{}) (ed EncodedData, err error) {
   226  	defer func() {
   227  		if state := recover(); state != nil {
   228  			err = log.Wrap(state.(error))
   229  		}
   230  	}()
   231  
   232  	switch t := value.(type) {
   233  	case []byte:
   234  		ed, err = ve.encodeBytes(t)
   235  		log.PanicIf(err)
   236  	case string:
   237  		ed, err = ve.encodeAscii(t)
   238  		log.PanicIf(err)
   239  	case []uint16:
   240  		ed, err = ve.encodeShorts(t)
   241  		log.PanicIf(err)
   242  	case []uint32:
   243  		ed, err = ve.encodeLongs(t)
   244  		log.PanicIf(err)
   245  	case []float32:
   246  		ed, err = ve.encodeFloats(t)
   247  		log.PanicIf(err)
   248  	case []float64:
   249  		ed, err = ve.encodeDoubles(t)
   250  		log.PanicIf(err)
   251  	case []Rational:
   252  		ed, err = ve.encodeRationals(t)
   253  		log.PanicIf(err)
   254  	case []int32:
   255  		ed, err = ve.encodeSignedLongs(t)
   256  		log.PanicIf(err)
   257  	case []SignedRational:
   258  		ed, err = ve.encodeSignedRationals(t)
   259  		log.PanicIf(err)
   260  	case time.Time:
   261  		// For convenience, if the user doesn't want to deal with translation
   262  		// semantics with timestamps.
   263  
   264  		s := ExifFullTimestampString(t)
   265  
   266  		ed, err = ve.encodeAscii(s)
   267  		log.PanicIf(err)
   268  	default:
   269  		log.Panicf("value not encodable: [%s] [%v]", reflect.TypeOf(value), value)
   270  	}
   271  
   272  	return ed, nil
   273  }
   274  

View as plain text