info.go (2606B)
1 package photoshopinfo 2 3 import ( 4 "fmt" 5 "io" 6 7 "encoding/binary" 8 9 "github.com/dsoprea/go-logging" 10 ) 11 12 var ( 13 defaultByteOrder = binary.BigEndian 14 ) 15 16 // Photoshop30InfoRecord is the data for one parsed Photoshop-info record. 17 type Photoshop30InfoRecord struct { 18 // RecordType is the record-type. 19 RecordType string 20 21 // ImageResourceId is the image resource-ID. 22 ImageResourceId uint16 23 24 // Name is the name of the record. It is optional and will be an empty- 25 // string if not present. 26 Name string 27 28 // Data is the raw record data. 29 Data []byte 30 } 31 32 // String returns a descriptive string. 33 func (pir Photoshop30InfoRecord) String() string { 34 return fmt.Sprintf("RECORD-TYPE=[%s] IMAGE-RESOURCE-ID=[0x%04x] NAME=[%s] DATA-SIZE=(%d)", pir.RecordType, pir.ImageResourceId, pir.Name, len(pir.Data)) 35 } 36 37 // ReadPhotoshop30InfoRecord parses a single photoshop-info record. 38 func ReadPhotoshop30InfoRecord(r io.Reader) (pir Photoshop30InfoRecord, err error) { 39 defer func() { 40 if state := recover(); state != nil { 41 err = log.Wrap(state.(error)) 42 } 43 }() 44 45 recordType := make([]byte, 4) 46 _, err = io.ReadFull(r, recordType) 47 if err != nil { 48 if err == io.EOF { 49 return pir, err 50 } 51 52 log.Panic(err) 53 } 54 55 // TODO(dustin): Move BigEndian to constant/config. 56 57 irId := uint16(0) 58 err = binary.Read(r, defaultByteOrder, &irId) 59 log.PanicIf(err) 60 61 nameSize := uint8(0) 62 err = binary.Read(r, defaultByteOrder, &nameSize) 63 log.PanicIf(err) 64 65 // Add an extra byte if the two length+data size is odd to make the total 66 // bytes read even. 67 doAddPadding := (1+nameSize)%2 == 1 68 if doAddPadding == true { 69 nameSize++ 70 } 71 72 name := make([]byte, nameSize) 73 _, err = io.ReadFull(r, name) 74 log.PanicIf(err) 75 76 // If the last byte is padding, truncate it. 77 if doAddPadding == true { 78 name = name[:nameSize-1] 79 } 80 81 dataSize := uint32(0) 82 err = binary.Read(r, defaultByteOrder, &dataSize) 83 log.PanicIf(err) 84 85 data := make([]byte, dataSize+dataSize%2) 86 _, err = io.ReadFull(r, data) 87 log.PanicIf(err) 88 89 data = data[:dataSize] 90 91 pir = Photoshop30InfoRecord{ 92 RecordType: string(recordType), 93 ImageResourceId: irId, 94 Name: string(name), 95 Data: data, 96 } 97 98 return pir, nil 99 } 100 101 // ReadPhotoshop30Info parses a sequence of photoship-info records from the stream. 102 func ReadPhotoshop30Info(r io.Reader) (pirIndex map[uint16]Photoshop30InfoRecord, err error) { 103 pirIndex = make(map[uint16]Photoshop30InfoRecord) 104 105 for { 106 pir, err := ReadPhotoshop30InfoRecord(r) 107 if err != nil { 108 if err == io.EOF { 109 break 110 } 111 112 log.Panic(err) 113 } 114 115 pirIndex[pir.ImageResourceId] = pir 116 } 117 118 return pirIndex, nil 119 }