gtsocial-umbx

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

parser.go (6299B)


      1 package exifcommon
      2 
      3 import (
      4 	"bytes"
      5 	"errors"
      6 	"math"
      7 
      8 	"encoding/binary"
      9 
     10 	"github.com/dsoprea/go-logging"
     11 )
     12 
     13 var (
     14 	parserLogger = log.NewLogger("exifcommon.parser")
     15 )
     16 
     17 var (
     18 	ErrParseFail = errors.New("parse failure")
     19 )
     20 
     21 // Parser knows how to parse all well-defined, encoded EXIF types.
     22 type Parser struct {
     23 }
     24 
     25 // ParseBytesknows how to parse a byte-type value.
     26 func (p *Parser) ParseBytes(data []byte, unitCount uint32) (value []uint8, err error) {
     27 	defer func() {
     28 		if state := recover(); state != nil {
     29 			err = log.Wrap(state.(error))
     30 		}
     31 	}()
     32 
     33 	// TODO(dustin): Add test
     34 
     35 	count := int(unitCount)
     36 
     37 	if len(data) < (TypeByte.Size() * count) {
     38 		log.Panic(ErrNotEnoughData)
     39 	}
     40 
     41 	value = []uint8(data[:count])
     42 
     43 	return value, nil
     44 }
     45 
     46 // ParseAscii returns a string and auto-strips the trailing NUL character that
     47 // should be at the end of the encoding.
     48 func (p *Parser) ParseAscii(data []byte, unitCount uint32) (value string, err error) {
     49 	defer func() {
     50 		if state := recover(); state != nil {
     51 			err = log.Wrap(state.(error))
     52 		}
     53 	}()
     54 
     55 	// TODO(dustin): Add test
     56 
     57 	count := int(unitCount)
     58 
     59 	if len(data) < (TypeAscii.Size() * count) {
     60 		log.Panic(ErrNotEnoughData)
     61 	}
     62 
     63 	if len(data) == 0 || data[count-1] != 0 {
     64 		s := string(data[:count])
     65 		parserLogger.Warningf(nil, "ASCII not terminated with NUL as expected: [%v]", s)
     66 
     67 		for i, c := range s {
     68 			if c > 127 {
     69 				// Binary
     70 
     71 				t := s[:i]
     72 				parserLogger.Warningf(nil, "ASCII also had binary characters. Truncating: [%v]->[%s]", s, t)
     73 
     74 				return t, nil
     75 			}
     76 		}
     77 
     78 		return s, nil
     79 	}
     80 
     81 	// Auto-strip the NUL from the end. It serves no purpose outside of
     82 	// encoding semantics.
     83 
     84 	return string(data[:count-1]), nil
     85 }
     86 
     87 // ParseAsciiNoNul returns a string without any consideration for a trailing NUL
     88 // character.
     89 func (p *Parser) ParseAsciiNoNul(data []byte, unitCount uint32) (value string, err error) {
     90 	defer func() {
     91 		if state := recover(); state != nil {
     92 			err = log.Wrap(state.(error))
     93 		}
     94 	}()
     95 
     96 	// TODO(dustin): Add test
     97 
     98 	count := int(unitCount)
     99 
    100 	if len(data) < (TypeAscii.Size() * count) {
    101 		log.Panic(ErrNotEnoughData)
    102 	}
    103 
    104 	return string(data[:count]), nil
    105 }
    106 
    107 // ParseShorts knows how to parse an encoded list of shorts.
    108 func (p *Parser) ParseShorts(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []uint16, err error) {
    109 	defer func() {
    110 		if state := recover(); state != nil {
    111 			err = log.Wrap(state.(error))
    112 		}
    113 	}()
    114 
    115 	// TODO(dustin): Add test
    116 
    117 	count := int(unitCount)
    118 
    119 	if len(data) < (TypeShort.Size() * count) {
    120 		log.Panic(ErrNotEnoughData)
    121 	}
    122 
    123 	value = make([]uint16, count)
    124 	for i := 0; i < count; i++ {
    125 		value[i] = byteOrder.Uint16(data[i*2:])
    126 	}
    127 
    128 	return value, nil
    129 }
    130 
    131 // ParseLongs knows how to encode an encoded list of unsigned longs.
    132 func (p *Parser) ParseLongs(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []uint32, err error) {
    133 	defer func() {
    134 		if state := recover(); state != nil {
    135 			err = log.Wrap(state.(error))
    136 		}
    137 	}()
    138 
    139 	// TODO(dustin): Add test
    140 
    141 	count := int(unitCount)
    142 
    143 	if len(data) < (TypeLong.Size() * count) {
    144 		log.Panic(ErrNotEnoughData)
    145 	}
    146 
    147 	value = make([]uint32, count)
    148 	for i := 0; i < count; i++ {
    149 		value[i] = byteOrder.Uint32(data[i*4:])
    150 	}
    151 
    152 	return value, nil
    153 }
    154 
    155 // ParseFloats knows how to encode an encoded list of floats.
    156 func (p *Parser) ParseFloats(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []float32, err error) {
    157 	defer func() {
    158 		if state := recover(); state != nil {
    159 			err = log.Wrap(state.(error))
    160 		}
    161 	}()
    162 
    163 	count := int(unitCount)
    164 
    165 	if len(data) != (TypeFloat.Size() * count) {
    166 		log.Panic(ErrNotEnoughData)
    167 	}
    168 
    169 	value = make([]float32, count)
    170 	for i := 0; i < count; i++ {
    171 		value[i] = math.Float32frombits(byteOrder.Uint32(data[i*4 : (i+1)*4]))
    172 	}
    173 
    174 	return value, nil
    175 }
    176 
    177 // ParseDoubles knows how to encode an encoded list of doubles.
    178 func (p *Parser) ParseDoubles(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []float64, err error) {
    179 	defer func() {
    180 		if state := recover(); state != nil {
    181 			err = log.Wrap(state.(error))
    182 		}
    183 	}()
    184 
    185 	count := int(unitCount)
    186 
    187 	if len(data) != (TypeDouble.Size() * count) {
    188 		log.Panic(ErrNotEnoughData)
    189 	}
    190 
    191 	value = make([]float64, count)
    192 	for i := 0; i < count; i++ {
    193 		value[i] = math.Float64frombits(byteOrder.Uint64(data[i*8 : (i+1)*8]))
    194 	}
    195 
    196 	return value, nil
    197 }
    198 
    199 // ParseRationals knows how to parse an encoded list of unsigned rationals.
    200 func (p *Parser) ParseRationals(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []Rational, err error) {
    201 	defer func() {
    202 		if state := recover(); state != nil {
    203 			err = log.Wrap(state.(error))
    204 		}
    205 	}()
    206 
    207 	// TODO(dustin): Add test
    208 
    209 	count := int(unitCount)
    210 
    211 	if len(data) < (TypeRational.Size() * count) {
    212 		log.Panic(ErrNotEnoughData)
    213 	}
    214 
    215 	value = make([]Rational, count)
    216 	for i := 0; i < count; i++ {
    217 		value[i].Numerator = byteOrder.Uint32(data[i*8:])
    218 		value[i].Denominator = byteOrder.Uint32(data[i*8+4:])
    219 	}
    220 
    221 	return value, nil
    222 }
    223 
    224 // ParseSignedLongs knows how to parse an encoded list of signed longs.
    225 func (p *Parser) ParseSignedLongs(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []int32, err error) {
    226 	defer func() {
    227 		if state := recover(); state != nil {
    228 			err = log.Wrap(state.(error))
    229 		}
    230 	}()
    231 
    232 	// TODO(dustin): Add test
    233 
    234 	count := int(unitCount)
    235 
    236 	if len(data) < (TypeSignedLong.Size() * count) {
    237 		log.Panic(ErrNotEnoughData)
    238 	}
    239 
    240 	b := bytes.NewBuffer(data)
    241 
    242 	value = make([]int32, count)
    243 	for i := 0; i < count; i++ {
    244 		err := binary.Read(b, byteOrder, &value[i])
    245 		log.PanicIf(err)
    246 	}
    247 
    248 	return value, nil
    249 }
    250 
    251 // ParseSignedRationals knows how to parse an encoded list of signed
    252 // rationals.
    253 func (p *Parser) ParseSignedRationals(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []SignedRational, err error) {
    254 	defer func() {
    255 		if state := recover(); state != nil {
    256 			err = log.Wrap(state.(error))
    257 		}
    258 	}()
    259 
    260 	// TODO(dustin): Add test
    261 
    262 	count := int(unitCount)
    263 
    264 	if len(data) < (TypeSignedRational.Size() * count) {
    265 		log.Panic(ErrNotEnoughData)
    266 	}
    267 
    268 	b := bytes.NewBuffer(data)
    269 
    270 	value = make([]SignedRational, count)
    271 	for i := 0; i < count; i++ {
    272 		err = binary.Read(b, byteOrder, &value[i].Numerator)
    273 		log.PanicIf(err)
    274 
    275 		err = binary.Read(b, byteOrder, &value[i].Denominator)
    276 		log.PanicIf(err)
    277 	}
    278 
    279 	return value, nil
    280 }