2021-02-09 20:17:06 +01:00
|
|
|
package photoshopinfo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
|
|
|
|
"encoding/binary"
|
|
|
|
|
2021-02-10 01:00:02 +01:00
|
|
|
"github.com/dsoprea/go-logging"
|
2021-02-09 20:17:06 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
defaultByteOrder = binary.BigEndian
|
|
|
|
)
|
|
|
|
|
|
|
|
// Photoshop30InfoRecord is the data for one parsed Photoshop-info record.
|
|
|
|
type Photoshop30InfoRecord struct {
|
|
|
|
// RecordType is the record-type.
|
|
|
|
RecordType string
|
|
|
|
|
|
|
|
// ImageResourceId is the image resource-ID.
|
|
|
|
ImageResourceId uint16
|
|
|
|
|
|
|
|
// Name is the name of the record. It is optional and will be an empty-
|
|
|
|
// string if not present.
|
|
|
|
Name string
|
|
|
|
|
|
|
|
// Data is the raw record data.
|
|
|
|
Data []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
// String returns a descriptive string.
|
|
|
|
func (pir Photoshop30InfoRecord) String() string {
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReadPhotoshop30InfoRecord parses a single photoshop-info record.
|
|
|
|
func ReadPhotoshop30InfoRecord(r io.Reader) (pir Photoshop30InfoRecord, err error) {
|
|
|
|
defer func() {
|
|
|
|
if state := recover(); state != nil {
|
|
|
|
err = log.Wrap(state.(error))
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
recordType := make([]byte, 4)
|
|
|
|
_, err = io.ReadFull(r, recordType)
|
|
|
|
if err != nil {
|
|
|
|
if err == io.EOF {
|
|
|
|
return pir, err
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(dustin): Move BigEndian to constant/config.
|
|
|
|
|
|
|
|
irId := uint16(0)
|
|
|
|
err = binary.Read(r, defaultByteOrder, &irId)
|
|
|
|
log.PanicIf(err)
|
|
|
|
|
|
|
|
nameSize := uint8(0)
|
|
|
|
err = binary.Read(r, defaultByteOrder, &nameSize)
|
|
|
|
log.PanicIf(err)
|
|
|
|
|
|
|
|
// Add an extra byte if the two length+data size is odd to make the total
|
|
|
|
// bytes read even.
|
|
|
|
doAddPadding := (1+nameSize)%2 == 1
|
|
|
|
if doAddPadding == true {
|
|
|
|
nameSize++
|
|
|
|
}
|
|
|
|
|
|
|
|
name := make([]byte, nameSize)
|
|
|
|
_, err = io.ReadFull(r, name)
|
|
|
|
log.PanicIf(err)
|
|
|
|
|
|
|
|
// If the last byte is padding, truncate it.
|
|
|
|
if doAddPadding == true {
|
|
|
|
name = name[:nameSize-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
dataSize := uint32(0)
|
|
|
|
err = binary.Read(r, defaultByteOrder, &dataSize)
|
|
|
|
log.PanicIf(err)
|
|
|
|
|
|
|
|
data := make([]byte, dataSize+dataSize%2)
|
|
|
|
_, err = io.ReadFull(r, data)
|
|
|
|
log.PanicIf(err)
|
|
|
|
|
|
|
|
data = data[:dataSize]
|
|
|
|
|
|
|
|
pir = Photoshop30InfoRecord{
|
|
|
|
RecordType: string(recordType),
|
|
|
|
ImageResourceId: irId,
|
|
|
|
Name: string(name),
|
|
|
|
Data: data,
|
|
|
|
}
|
|
|
|
|
|
|
|
return pir, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReadPhotoshop30Info parses a sequence of photoship-info records from the stream.
|
|
|
|
func ReadPhotoshop30Info(r io.Reader) (pirIndex map[uint16]Photoshop30InfoRecord, err error) {
|
|
|
|
pirIndex = make(map[uint16]Photoshop30InfoRecord)
|
|
|
|
|
|
|
|
for {
|
|
|
|
pir, err := ReadPhotoshop30InfoRecord(r)
|
|
|
|
if err != nil {
|
|
|
|
if err == io.EOF {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
pirIndex[pir.ImageResourceId] = pir
|
|
|
|
}
|
|
|
|
|
|
|
|
return pirIndex, nil
|
|
|
|
}
|