use exif-terminator

This commit is contained in:
tsmethurst
2022-01-23 14:41:31 +01:00
parent 589bb9df02
commit 7d024ce74d
117 changed files with 3873 additions and 8725 deletions

View File

@ -0,0 +1,4 @@
## 0xa40b
The specification is not specific/clear enough to be handled. Without a working example ,we're deferring until some point in the future when either we or someone else has a better understanding.

View File

@ -0,0 +1,62 @@
package exifundefined
import (
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v3/common"
)
// Encode encodes the given encodeable undefined value to bytes.
func Encode(value EncodeableValue, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
encoderName := value.EncoderName()
encoder, found := encoders[encoderName]
if found == false {
log.Panicf("no encoder registered for type [%s]", encoderName)
}
encoded, unitCount, err = encoder.Encode(value, byteOrder)
log.PanicIf(err)
return encoded, unitCount, nil
}
// Decode constructs a value from raw encoded bytes
func Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
uth := UndefinedTagHandle{
IfdPath: valueContext.IfdPath(),
TagId: valueContext.TagId(),
}
decoder, found := decoders[uth]
if found == false {
// We have no choice but to return the error. We have no way of knowing how
// much data there is without already knowing what data-type this tag is.
return nil, exifcommon.ErrUnhandledUndefinedTypedTag
}
value, err = decoder.Decode(valueContext)
if err != nil {
if err == ErrUnparseableValue {
return nil, err
}
log.Panic(err)
}
return value, nil
}

View File

@ -0,0 +1,148 @@
package exifundefined
import (
"bytes"
"fmt"
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v3/common"
)
type Tag8828Oecf struct {
Columns uint16
Rows uint16
ColumnNames []string
Values []exifcommon.SignedRational
}
func (oecf Tag8828Oecf) String() string {
return fmt.Sprintf("Tag8828Oecf<COLUMNS=(%d) ROWS=(%d)>", oecf.Columns, oecf.Rows)
}
func (oecf Tag8828Oecf) EncoderName() string {
return "Codec8828Oecf"
}
type Codec8828Oecf struct {
}
func (Codec8828Oecf) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
// TODO(dustin): Add test
oecf, ok := value.(Tag8828Oecf)
if ok == false {
log.Panicf("can only encode a Tag8828Oecf")
}
b := new(bytes.Buffer)
err = binary.Write(b, byteOrder, oecf.Columns)
log.PanicIf(err)
err = binary.Write(b, byteOrder, oecf.Rows)
log.PanicIf(err)
for _, name := range oecf.ColumnNames {
_, err := b.Write([]byte(name))
log.PanicIf(err)
_, err = b.Write([]byte{0})
log.PanicIf(err)
}
ve := exifcommon.NewValueEncoder(byteOrder)
ed, err := ve.Encode(oecf.Values)
log.PanicIf(err)
_, err = b.Write(ed.Encoded)
log.PanicIf(err)
return b.Bytes(), uint32(b.Len()), nil
}
func (Codec8828Oecf) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
// TODO(dustin): Add test using known good data.
valueContext.SetUndefinedValueType(exifcommon.TypeByte)
valueBytes, err := valueContext.ReadBytes()
log.PanicIf(err)
oecf := Tag8828Oecf{}
oecf.Columns = valueContext.ByteOrder().Uint16(valueBytes[0:2])
oecf.Rows = valueContext.ByteOrder().Uint16(valueBytes[2:4])
columnNames := make([]string, oecf.Columns)
// startAt is where the current column name starts.
startAt := 4
// offset is our current position.
offset := startAt
currentColumnNumber := uint16(0)
for currentColumnNumber < oecf.Columns {
if valueBytes[offset] == 0 {
columnName := string(valueBytes[startAt:offset])
if len(columnName) == 0 {
log.Panicf("SFR column (%d) has zero length", currentColumnNumber)
}
columnNames[currentColumnNumber] = columnName
currentColumnNumber++
offset++
startAt = offset
continue
}
offset++
}
oecf.ColumnNames = columnNames
rawRationalBytes := valueBytes[offset:]
rationalSize := exifcommon.TypeSignedRational.Size()
if len(rawRationalBytes)%rationalSize > 0 {
log.Panicf("OECF signed-rationals not aligned: (%d) %% (%d) > 0", len(rawRationalBytes), rationalSize)
}
rationalCount := len(rawRationalBytes) / rationalSize
parser := new(exifcommon.Parser)
byteOrder := valueContext.ByteOrder()
items, err := parser.ParseSignedRationals(rawRationalBytes, uint32(rationalCount), byteOrder)
log.PanicIf(err)
oecf.Values = items
return oecf, nil
}
func init() {
registerDecoder(
exifcommon.IfdExifStandardIfdIdentity.UnindexedString(),
0x8828,
Codec8828Oecf{})
}

View File

@ -0,0 +1,69 @@
package exifundefined
import (
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v3/common"
)
type Tag9000ExifVersion struct {
ExifVersion string
}
func (Tag9000ExifVersion) EncoderName() string {
return "Codec9000ExifVersion"
}
func (ev Tag9000ExifVersion) String() string {
return ev.ExifVersion
}
type Codec9000ExifVersion struct {
}
func (Codec9000ExifVersion) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
s, ok := value.(Tag9000ExifVersion)
if ok == false {
log.Panicf("can only encode a Tag9000ExifVersion")
}
return []byte(s.ExifVersion), uint32(len(s.ExifVersion)), nil
}
func (Codec9000ExifVersion) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
valueContext.SetUndefinedValueType(exifcommon.TypeAsciiNoNul)
valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err)
ev := Tag9000ExifVersion{
ExifVersion: valueString,
}
return ev, nil
}
func init() {
registerEncoder(
Tag9000ExifVersion{},
Codec9000ExifVersion{})
registerDecoder(
exifcommon.IfdExifStandardIfdIdentity.UnindexedString(),
0x9000,
Codec9000ExifVersion{})
}

View File

@ -0,0 +1,124 @@
package exifundefined
import (
"bytes"
"fmt"
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v3/common"
)
const (
TagUndefinedType_9101_ComponentsConfiguration_Channel_Y = 0x1
TagUndefinedType_9101_ComponentsConfiguration_Channel_Cb = 0x2
TagUndefinedType_9101_ComponentsConfiguration_Channel_Cr = 0x3
TagUndefinedType_9101_ComponentsConfiguration_Channel_R = 0x4
TagUndefinedType_9101_ComponentsConfiguration_Channel_G = 0x5
TagUndefinedType_9101_ComponentsConfiguration_Channel_B = 0x6
)
const (
TagUndefinedType_9101_ComponentsConfiguration_OTHER = iota
TagUndefinedType_9101_ComponentsConfiguration_RGB = iota
TagUndefinedType_9101_ComponentsConfiguration_YCBCR = iota
)
var (
TagUndefinedType_9101_ComponentsConfiguration_Names = map[int]string{
TagUndefinedType_9101_ComponentsConfiguration_OTHER: "OTHER",
TagUndefinedType_9101_ComponentsConfiguration_RGB: "RGB",
TagUndefinedType_9101_ComponentsConfiguration_YCBCR: "YCBCR",
}
TagUndefinedType_9101_ComponentsConfiguration_Configurations = map[int][]byte{
TagUndefinedType_9101_ComponentsConfiguration_RGB: {
TagUndefinedType_9101_ComponentsConfiguration_Channel_R,
TagUndefinedType_9101_ComponentsConfiguration_Channel_G,
TagUndefinedType_9101_ComponentsConfiguration_Channel_B,
0,
},
TagUndefinedType_9101_ComponentsConfiguration_YCBCR: {
TagUndefinedType_9101_ComponentsConfiguration_Channel_Y,
TagUndefinedType_9101_ComponentsConfiguration_Channel_Cb,
TagUndefinedType_9101_ComponentsConfiguration_Channel_Cr,
0,
},
}
)
type TagExif9101ComponentsConfiguration struct {
ConfigurationId int
ConfigurationBytes []byte
}
func (TagExif9101ComponentsConfiguration) EncoderName() string {
return "CodecExif9101ComponentsConfiguration"
}
func (cc TagExif9101ComponentsConfiguration) String() string {
return fmt.Sprintf("Exif9101ComponentsConfiguration<ID=[%s] BYTES=%v>", TagUndefinedType_9101_ComponentsConfiguration_Names[cc.ConfigurationId], cc.ConfigurationBytes)
}
type CodecExif9101ComponentsConfiguration struct {
}
func (CodecExif9101ComponentsConfiguration) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
cc, ok := value.(TagExif9101ComponentsConfiguration)
if ok == false {
log.Panicf("can only encode a TagExif9101ComponentsConfiguration")
}
return cc.ConfigurationBytes, uint32(len(cc.ConfigurationBytes)), nil
}
func (CodecExif9101ComponentsConfiguration) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
valueContext.SetUndefinedValueType(exifcommon.TypeByte)
valueBytes, err := valueContext.ReadBytes()
log.PanicIf(err)
for configurationId, configurationBytes := range TagUndefinedType_9101_ComponentsConfiguration_Configurations {
if bytes.Equal(configurationBytes, valueBytes) == true {
cc := TagExif9101ComponentsConfiguration{
ConfigurationId: configurationId,
ConfigurationBytes: valueBytes,
}
return cc, nil
}
}
cc := TagExif9101ComponentsConfiguration{
ConfigurationId: TagUndefinedType_9101_ComponentsConfiguration_OTHER,
ConfigurationBytes: valueBytes,
}
return cc, nil
}
func init() {
registerEncoder(
TagExif9101ComponentsConfiguration{},
CodecExif9101ComponentsConfiguration{})
registerDecoder(
exifcommon.IfdExifStandardIfdIdentity.UnindexedString(),
0x9101,
CodecExif9101ComponentsConfiguration{})
}

View File

@ -0,0 +1,114 @@
package exifundefined
import (
"fmt"
"strings"
"crypto/sha1"
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v3/common"
)
type Tag927CMakerNote struct {
MakerNoteType []byte
MakerNoteBytes []byte
}
func (Tag927CMakerNote) EncoderName() string {
return "Codec927CMakerNote"
}
func (mn Tag927CMakerNote) String() string {
parts := make([]string, len(mn.MakerNoteType))
for i, c := range mn.MakerNoteType {
parts[i] = fmt.Sprintf("%02x", c)
}
h := sha1.New()
_, err := h.Write(mn.MakerNoteBytes)
log.PanicIf(err)
digest := h.Sum(nil)
return fmt.Sprintf("MakerNote<TYPE-ID=[%s] LEN=(%d) SHA1=[%020x]>", strings.Join(parts, " "), len(mn.MakerNoteBytes), digest)
}
type Codec927CMakerNote struct {
}
func (Codec927CMakerNote) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
mn, ok := value.(Tag927CMakerNote)
if ok == false {
log.Panicf("can only encode a Tag927CMakerNote")
}
// TODO(dustin): Confirm this size against the specification.
return mn.MakerNoteBytes, uint32(len(mn.MakerNoteBytes)), nil
}
func (Codec927CMakerNote) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
// MakerNote
// TODO(dustin): !! This is the Wild Wild West. This very well might be a child IFD, but any and all OEM's define their own formats. If we're going to be writing changes and this is complete EXIF (which may not have the first eight bytes), it might be fine. However, if these are just IFDs they'll be relative to the main EXIF, this will invalidate the MakerNote data for IFDs and any other implementations that use offsets unless we can interpret them all. It be best to return to this later and just exclude this from being written for now, though means a loss of a wealth of image metadata.
// -> We can also just blindly try to interpret as an IFD and just validate that it's looks good (maybe it will even have a 'next ifd' pointer that we can validate is 0x0).
valueContext.SetUndefinedValueType(exifcommon.TypeByte)
valueBytes, err := valueContext.ReadBytes()
log.PanicIf(err)
// TODO(dustin): Doesn't work, but here as an example.
// ie := NewIfdEnumerate(valueBytes, byteOrder)
// // TODO(dustin): !! Validate types (might have proprietary types, but it might be worth splitting the list between valid and not valid; maybe fail if a certain proportion are invalid, or maybe aren't less then a certain small integer)?
// ii, err := ie.Collect(0x0)
// for _, entry := range ii.RootIfd.Entries {
// fmt.Printf("ENTRY: 0x%02x %d\n", entry.TagId, entry.TagType)
// }
var makerNoteType []byte
if len(valueBytes) >= 20 {
makerNoteType = valueBytes[:20]
} else {
makerNoteType = valueBytes
}
mn := Tag927CMakerNote{
MakerNoteType: makerNoteType,
// MakerNoteBytes has the whole length of bytes. There's always
// the chance that the first 20 bytes includes actual data.
MakerNoteBytes: valueBytes,
}
return mn, nil
}
func init() {
registerEncoder(
Tag927CMakerNote{},
Codec927CMakerNote{})
registerDecoder(
exifcommon.IfdExifStandardIfdIdentity.UnindexedString(),
0x927c,
Codec927CMakerNote{})
}

View File

@ -0,0 +1,142 @@
package exifundefined
import (
"bytes"
"fmt"
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v3/common"
)
var (
exif9286Logger = log.NewLogger("exifundefined.exif_9286_user_comment")
)
const (
TagUndefinedType_9286_UserComment_Encoding_ASCII = iota
TagUndefinedType_9286_UserComment_Encoding_JIS = iota
TagUndefinedType_9286_UserComment_Encoding_UNICODE = iota
TagUndefinedType_9286_UserComment_Encoding_UNDEFINED = iota
)
var (
TagUndefinedType_9286_UserComment_Encoding_Names = map[int]string{
TagUndefinedType_9286_UserComment_Encoding_ASCII: "ASCII",
TagUndefinedType_9286_UserComment_Encoding_JIS: "JIS",
TagUndefinedType_9286_UserComment_Encoding_UNICODE: "UNICODE",
TagUndefinedType_9286_UserComment_Encoding_UNDEFINED: "UNDEFINED",
}
TagUndefinedType_9286_UserComment_Encodings = map[int][]byte{
TagUndefinedType_9286_UserComment_Encoding_ASCII: {'A', 'S', 'C', 'I', 'I', 0, 0, 0},
TagUndefinedType_9286_UserComment_Encoding_JIS: {'J', 'I', 'S', 0, 0, 0, 0, 0},
TagUndefinedType_9286_UserComment_Encoding_UNICODE: {'U', 'n', 'i', 'c', 'o', 'd', 'e', 0},
TagUndefinedType_9286_UserComment_Encoding_UNDEFINED: {0, 0, 0, 0, 0, 0, 0, 0},
}
)
type Tag9286UserComment struct {
EncodingType int
EncodingBytes []byte
}
func (Tag9286UserComment) EncoderName() string {
return "Codec9286UserComment"
}
func (uc Tag9286UserComment) String() string {
var valuePhrase string
if uc.EncodingType == TagUndefinedType_9286_UserComment_Encoding_ASCII {
return fmt.Sprintf("[ASCII] %s", string(uc.EncodingBytes))
} else {
if len(uc.EncodingBytes) <= 8 {
valuePhrase = fmt.Sprintf("%v", uc.EncodingBytes)
} else {
valuePhrase = fmt.Sprintf("%v...", uc.EncodingBytes[:8])
}
}
return fmt.Sprintf("UserComment<SIZE=(%d) ENCODING=[%s] V=%v LEN=(%d)>", len(uc.EncodingBytes), TagUndefinedType_9286_UserComment_Encoding_Names[uc.EncodingType], valuePhrase, len(uc.EncodingBytes))
}
type Codec9286UserComment struct {
}
func (Codec9286UserComment) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
uc, ok := value.(Tag9286UserComment)
if ok == false {
log.Panicf("can only encode a Tag9286UserComment")
}
encodingTypeBytes, found := TagUndefinedType_9286_UserComment_Encodings[uc.EncodingType]
if found == false {
log.Panicf("encoding-type not valid for unknown-type tag 9286 (UserComment): (%d)", uc.EncodingType)
}
encoded = make([]byte, len(uc.EncodingBytes)+8)
copy(encoded[:8], encodingTypeBytes)
copy(encoded[8:], uc.EncodingBytes)
// TODO(dustin): Confirm this size against the specification.
return encoded, uint32(len(encoded)), nil
}
func (Codec9286UserComment) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
valueContext.SetUndefinedValueType(exifcommon.TypeByte)
valueBytes, err := valueContext.ReadBytes()
log.PanicIf(err)
if len(valueBytes) < 8 {
return nil, ErrUnparseableValue
}
unknownUc := Tag9286UserComment{
EncodingType: TagUndefinedType_9286_UserComment_Encoding_UNDEFINED,
EncodingBytes: []byte{},
}
encoding := valueBytes[:8]
for encodingIndex, encodingBytes := range TagUndefinedType_9286_UserComment_Encodings {
if bytes.Compare(encoding, encodingBytes) == 0 {
uc := Tag9286UserComment{
EncodingType: encodingIndex,
EncodingBytes: valueBytes[8:],
}
return uc, nil
}
}
exif9286Logger.Warningf(nil, "User-comment encoding not valid. Returning 'unknown' type (the default).")
return unknownUc, nil
}
func init() {
registerEncoder(
Tag9286UserComment{},
Codec9286UserComment{})
registerDecoder(
exifcommon.IfdExifStandardIfdIdentity.UnindexedString(),
0x9286,
Codec9286UserComment{})
}

View File

@ -0,0 +1,69 @@
package exifundefined
import (
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v3/common"
)
type TagA000FlashpixVersion struct {
FlashpixVersion string
}
func (TagA000FlashpixVersion) EncoderName() string {
return "CodecA000FlashpixVersion"
}
func (fv TagA000FlashpixVersion) String() string {
return fv.FlashpixVersion
}
type CodecA000FlashpixVersion struct {
}
func (CodecA000FlashpixVersion) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
s, ok := value.(TagA000FlashpixVersion)
if ok == false {
log.Panicf("can only encode a TagA000FlashpixVersion")
}
return []byte(s.FlashpixVersion), uint32(len(s.FlashpixVersion)), nil
}
func (CodecA000FlashpixVersion) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
valueContext.SetUndefinedValueType(exifcommon.TypeAsciiNoNul)
valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err)
fv := TagA000FlashpixVersion{
FlashpixVersion: valueString,
}
return fv, nil
}
func init() {
registerEncoder(
TagA000FlashpixVersion{},
CodecA000FlashpixVersion{})
registerDecoder(
exifcommon.IfdExifStandardIfdIdentity.UnindexedString(),
0xa000,
CodecA000FlashpixVersion{})
}

View File

@ -0,0 +1,160 @@
package exifundefined
import (
"bytes"
"fmt"
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v3/common"
)
type TagA20CSpatialFrequencyResponse struct {
Columns uint16
Rows uint16
ColumnNames []string
Values []exifcommon.Rational
}
func (TagA20CSpatialFrequencyResponse) EncoderName() string {
return "CodecA20CSpatialFrequencyResponse"
}
func (sfr TagA20CSpatialFrequencyResponse) String() string {
return fmt.Sprintf("CodecA20CSpatialFrequencyResponse<COLUMNS=(%d) ROWS=(%d)>", sfr.Columns, sfr.Rows)
}
type CodecA20CSpatialFrequencyResponse struct {
}
func (CodecA20CSpatialFrequencyResponse) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
// TODO(dustin): Add test.
sfr, ok := value.(TagA20CSpatialFrequencyResponse)
if ok == false {
log.Panicf("can only encode a TagA20CSpatialFrequencyResponse")
}
b := new(bytes.Buffer)
err = binary.Write(b, byteOrder, sfr.Columns)
log.PanicIf(err)
err = binary.Write(b, byteOrder, sfr.Rows)
log.PanicIf(err)
// Write columns.
for _, name := range sfr.ColumnNames {
_, err := b.WriteString(name)
log.PanicIf(err)
err = b.WriteByte(0)
log.PanicIf(err)
}
// Write values.
ve := exifcommon.NewValueEncoder(byteOrder)
ed, err := ve.Encode(sfr.Values)
log.PanicIf(err)
_, err = b.Write(ed.Encoded)
log.PanicIf(err)
encoded = b.Bytes()
// TODO(dustin): Confirm this size against the specification.
return encoded, uint32(len(encoded)), nil
}
func (CodecA20CSpatialFrequencyResponse) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
// TODO(dustin): Add test using known good data.
byteOrder := valueContext.ByteOrder()
valueContext.SetUndefinedValueType(exifcommon.TypeByte)
valueBytes, err := valueContext.ReadBytes()
log.PanicIf(err)
sfr := TagA20CSpatialFrequencyResponse{}
sfr.Columns = byteOrder.Uint16(valueBytes[0:2])
sfr.Rows = byteOrder.Uint16(valueBytes[2:4])
columnNames := make([]string, sfr.Columns)
// startAt is where the current column name starts.
startAt := 4
// offset is our current position.
offset := 4
currentColumnNumber := uint16(0)
for currentColumnNumber < sfr.Columns {
if valueBytes[offset] == 0 {
columnName := string(valueBytes[startAt:offset])
if len(columnName) == 0 {
log.Panicf("SFR column (%d) has zero length", currentColumnNumber)
}
columnNames[currentColumnNumber] = columnName
currentColumnNumber++
offset++
startAt = offset
continue
}
offset++
}
sfr.ColumnNames = columnNames
rawRationalBytes := valueBytes[offset:]
rationalSize := exifcommon.TypeRational.Size()
if len(rawRationalBytes)%rationalSize > 0 {
log.Panicf("SFR rationals not aligned: (%d) %% (%d) > 0", len(rawRationalBytes), rationalSize)
}
rationalCount := len(rawRationalBytes) / rationalSize
parser := new(exifcommon.Parser)
items, err := parser.ParseRationals(rawRationalBytes, uint32(rationalCount), byteOrder)
log.PanicIf(err)
sfr.Values = items
return sfr, nil
}
func init() {
registerEncoder(
TagA20CSpatialFrequencyResponse{},
CodecA20CSpatialFrequencyResponse{})
registerDecoder(
exifcommon.IfdExifStandardIfdIdentity.UnindexedString(),
0xa20c,
CodecA20CSpatialFrequencyResponse{})
}

View File

@ -0,0 +1,79 @@
package exifundefined
import (
"fmt"
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v3/common"
)
type TagExifA300FileSource uint32
func (TagExifA300FileSource) EncoderName() string {
return "CodecExifA300FileSource"
}
func (af TagExifA300FileSource) String() string {
return fmt.Sprintf("0x%08x", uint32(af))
}
const (
TagUndefinedType_A300_SceneType_Others TagExifA300FileSource = 0
TagUndefinedType_A300_SceneType_ScannerOfTransparentType TagExifA300FileSource = 1
TagUndefinedType_A300_SceneType_ScannerOfReflexType TagExifA300FileSource = 2
TagUndefinedType_A300_SceneType_Dsc TagExifA300FileSource = 3
)
type CodecExifA300FileSource struct {
}
func (CodecExifA300FileSource) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
st, ok := value.(TagExifA300FileSource)
if ok == false {
log.Panicf("can only encode a TagExifA300FileSource")
}
ve := exifcommon.NewValueEncoder(byteOrder)
ed, err := ve.Encode([]uint32{uint32(st)})
log.PanicIf(err)
// TODO(dustin): Confirm this size against the specification. It's non-specific about what type it is, but it looks to be no more than a single integer scalar. So, we're assuming it's a LONG.
return ed.Encoded, 1, nil
}
func (CodecExifA300FileSource) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
valueContext.SetUndefinedValueType(exifcommon.TypeLong)
valueLongs, err := valueContext.ReadLongs()
log.PanicIf(err)
return TagExifA300FileSource(valueLongs[0]), nil
}
func init() {
registerEncoder(
TagExifA300FileSource(0),
CodecExifA300FileSource{})
registerDecoder(
exifcommon.IfdExifStandardIfdIdentity.UnindexedString(),
0xa300,
CodecExifA300FileSource{})
}

View File

@ -0,0 +1,76 @@
package exifundefined
import (
"fmt"
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v3/common"
)
type TagExifA301SceneType uint32
func (TagExifA301SceneType) EncoderName() string {
return "CodecExifA301SceneType"
}
func (st TagExifA301SceneType) String() string {
return fmt.Sprintf("0x%08x", uint32(st))
}
const (
TagUndefinedType_A301_SceneType_DirectlyPhotographedImage TagExifA301SceneType = 1
)
type CodecExifA301SceneType struct {
}
func (CodecExifA301SceneType) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
st, ok := value.(TagExifA301SceneType)
if ok == false {
log.Panicf("can only encode a TagExif9101ComponentsConfiguration")
}
ve := exifcommon.NewValueEncoder(byteOrder)
ed, err := ve.Encode([]uint32{uint32(st)})
log.PanicIf(err)
// TODO(dustin): Confirm this size against the specification. It's non-specific about what type it is, but it looks to be no more than a single integer scalar. So, we're assuming it's a LONG.
return ed.Encoded, uint32(int(ed.UnitCount)), nil
}
func (CodecExifA301SceneType) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
valueContext.SetUndefinedValueType(exifcommon.TypeLong)
valueLongs, err := valueContext.ReadLongs()
log.PanicIf(err)
return TagExifA301SceneType(valueLongs[0]), nil
}
func init() {
registerEncoder(
TagExifA301SceneType(0),
CodecExifA301SceneType{})
registerDecoder(
exifcommon.IfdExifStandardIfdIdentity.UnindexedString(),
0xa301,
CodecExifA301SceneType{})
}

View File

@ -0,0 +1,97 @@
package exifundefined
import (
"bytes"
"fmt"
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v3/common"
)
type TagA302CfaPattern struct {
HorizontalRepeat uint16
VerticalRepeat uint16
CfaValue []byte
}
func (TagA302CfaPattern) EncoderName() string {
return "CodecA302CfaPattern"
}
func (cp TagA302CfaPattern) String() string {
return fmt.Sprintf("TagA302CfaPattern<HORZ-REPEAT=(%d) VERT-REPEAT=(%d) CFA-VALUE=(%d)>", cp.HorizontalRepeat, cp.VerticalRepeat, len(cp.CfaValue))
}
type CodecA302CfaPattern struct {
}
func (CodecA302CfaPattern) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
// TODO(dustin): Add test.
cp, ok := value.(TagA302CfaPattern)
if ok == false {
log.Panicf("can only encode a TagA302CfaPattern")
}
b := new(bytes.Buffer)
err = binary.Write(b, byteOrder, cp.HorizontalRepeat)
log.PanicIf(err)
err = binary.Write(b, byteOrder, cp.VerticalRepeat)
log.PanicIf(err)
_, err = b.Write(cp.CfaValue)
log.PanicIf(err)
encoded = b.Bytes()
// TODO(dustin): Confirm this size against the specification.
return encoded, uint32(len(encoded)), nil
}
func (CodecA302CfaPattern) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
// TODO(dustin): Add test using known good data.
valueContext.SetUndefinedValueType(exifcommon.TypeByte)
valueBytes, err := valueContext.ReadBytes()
log.PanicIf(err)
cp := TagA302CfaPattern{}
cp.HorizontalRepeat = valueContext.ByteOrder().Uint16(valueBytes[0:2])
cp.VerticalRepeat = valueContext.ByteOrder().Uint16(valueBytes[2:4])
expectedLength := int(cp.HorizontalRepeat * cp.VerticalRepeat)
cp.CfaValue = valueBytes[4 : 4+expectedLength]
return cp, nil
}
func init() {
registerEncoder(
TagA302CfaPattern{},
CodecA302CfaPattern{})
registerDecoder(
exifcommon.IfdExifStandardIfdIdentity.UnindexedString(),
0xa302,
CodecA302CfaPattern{})
}

View File

@ -0,0 +1,69 @@
package exifundefined
import (
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v3/common"
)
type Tag0002InteropVersion struct {
InteropVersion string
}
func (Tag0002InteropVersion) EncoderName() string {
return "Codec0002InteropVersion"
}
func (iv Tag0002InteropVersion) String() string {
return iv.InteropVersion
}
type Codec0002InteropVersion struct {
}
func (Codec0002InteropVersion) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
s, ok := value.(Tag0002InteropVersion)
if ok == false {
log.Panicf("can only encode a Tag0002InteropVersion")
}
return []byte(s.InteropVersion), uint32(len(s.InteropVersion)), nil
}
func (Codec0002InteropVersion) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
valueContext.SetUndefinedValueType(exifcommon.TypeAsciiNoNul)
valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err)
iv := Tag0002InteropVersion{
InteropVersion: valueString,
}
return iv, nil
}
func init() {
registerEncoder(
Tag0002InteropVersion{},
Codec0002InteropVersion{})
registerDecoder(
exifcommon.IfdExifIopStandardIfdIdentity.UnindexedString(),
0x0002,
Codec0002InteropVersion{})
}

View File

@ -0,0 +1,65 @@
package exifundefined
import (
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v3/common"
)
type Tag001BGPSProcessingMethod struct {
string
}
func (Tag001BGPSProcessingMethod) EncoderName() string {
return "Codec001BGPSProcessingMethod"
}
func (gpm Tag001BGPSProcessingMethod) String() string {
return gpm.string
}
type Codec001BGPSProcessingMethod struct {
}
func (Codec001BGPSProcessingMethod) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
s, ok := value.(Tag001BGPSProcessingMethod)
if ok == false {
log.Panicf("can only encode a Tag001BGPSProcessingMethod")
}
return []byte(s.string), uint32(len(s.string)), nil
}
func (Codec001BGPSProcessingMethod) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
valueContext.SetUndefinedValueType(exifcommon.TypeAsciiNoNul)
valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err)
return Tag001BGPSProcessingMethod{valueString}, nil
}
func init() {
registerEncoder(
Tag001BGPSProcessingMethod{},
Codec001BGPSProcessingMethod{})
registerDecoder(
exifcommon.IfdGpsInfoStandardIfdIdentity.UnindexedString(),
0x001b,
Codec001BGPSProcessingMethod{})
}

View File

@ -0,0 +1,65 @@
package exifundefined
import (
"encoding/binary"
"github.com/dsoprea/go-logging"
"github.com/dsoprea/go-exif/v3/common"
)
type Tag001CGPSAreaInformation struct {
string
}
func (Tag001CGPSAreaInformation) EncoderName() string {
return "Codec001CGPSAreaInformation"
}
func (gai Tag001CGPSAreaInformation) String() string {
return gai.string
}
type Codec001CGPSAreaInformation struct {
}
func (Codec001CGPSAreaInformation) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
s, ok := value.(Tag001CGPSAreaInformation)
if ok == false {
log.Panicf("can only encode a Tag001CGPSAreaInformation")
}
return []byte(s.string), uint32(len(s.string)), nil
}
func (Codec001CGPSAreaInformation) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
valueContext.SetUndefinedValueType(exifcommon.TypeAsciiNoNul)
valueString, err := valueContext.ReadAsciiNoNul()
log.PanicIf(err)
return Tag001CGPSAreaInformation{valueString}, nil
}
func init() {
registerEncoder(
Tag001CGPSAreaInformation{},
Codec001CGPSAreaInformation{})
registerDecoder(
exifcommon.IfdGpsInfoStandardIfdIdentity.UnindexedString(),
0x001c,
Codec001CGPSAreaInformation{})
}

View File

@ -0,0 +1,42 @@
package exifundefined
import (
"github.com/dsoprea/go-logging"
)
// UndefinedTagHandle defines one undefined-type tag with a corresponding
// decoder.
type UndefinedTagHandle struct {
IfdPath string
TagId uint16
}
func registerEncoder(entity EncodeableValue, encoder UndefinedValueEncoder) {
typeName := entity.EncoderName()
_, found := encoders[typeName]
if found == true {
log.Panicf("encoder already registered: %v", typeName)
}
encoders[typeName] = encoder
}
func registerDecoder(ifdPath string, tagId uint16, decoder UndefinedValueDecoder) {
uth := UndefinedTagHandle{
IfdPath: ifdPath,
TagId: tagId,
}
_, found := decoders[uth]
if found == true {
log.Panicf("decoder already registered: %v", uth)
}
decoders[uth] = decoder
}
var (
encoders = make(map[string]UndefinedValueEncoder)
decoders = make(map[UndefinedTagHandle]UndefinedValueDecoder)
)

44
vendor/github.com/dsoprea/go-exif/v3/undefined/type.go generated vendored Normal file
View File

@ -0,0 +1,44 @@
package exifundefined
import (
"errors"
"encoding/binary"
"github.com/dsoprea/go-exif/v3/common"
)
const (
// UnparseableUnknownTagValuePlaceholder is the string to use for an unknown
// undefined tag.
UnparseableUnknownTagValuePlaceholder = "!UNKNOWN"
// UnparseableHandledTagValuePlaceholder is the string to use for a known
// value that is not parseable.
UnparseableHandledTagValuePlaceholder = "!MALFORMED"
)
var (
// ErrUnparseableValue is the error for a value that we should have been
// able to parse but were not able to.
ErrUnparseableValue = errors.New("unparseable undefined tag")
)
// UndefinedValueEncoder knows how to encode an undefined-type tag's value to
// bytes.
type UndefinedValueEncoder interface {
Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error)
}
// EncodeableValue wraps a value with the information that will be needed to re-
// encode it later.
type EncodeableValue interface {
EncoderName() string
String() string
}
// UndefinedValueDecoder knows how to decode an undefined-type tag's value from
// bytes.
type UndefinedValueDecoder interface {
Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error)
}