...

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

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

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

View as plain text