init
This commit is contained in:
@@ -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.
|
||||
@@ -0,0 +1,62 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/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
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/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{})
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-utility/v2/filesystem"
|
||||
|
||||
"b612.me/exif/common"
|
||||
)
|
||||
|
||||
func TestTag8828Oecf_String(t *testing.T) {
|
||||
ut := Tag8828Oecf{
|
||||
Columns: 11,
|
||||
Rows: 22,
|
||||
}
|
||||
|
||||
s := ut.String()
|
||||
|
||||
if s != "Tag8828Oecf<COLUMNS=(11) ROWS=(22)>" {
|
||||
t.Fatalf("String not correct: [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodec8828Oecf_Encode(t *testing.T) {
|
||||
ut := Tag8828Oecf{
|
||||
Columns: 2,
|
||||
Rows: 22,
|
||||
ColumnNames: []string{"aa", "bb"},
|
||||
Values: []exifcommon.SignedRational{{11, 22}},
|
||||
}
|
||||
|
||||
codec := Codec8828Oecf{}
|
||||
|
||||
encoded, unitCount, err := codec.Encode(ut, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
expectedBytes := []byte{
|
||||
0x00, 0x02,
|
||||
0x00, 0x16,
|
||||
0x61, 0x61, 0x00, 0x62, 0x62, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x16}
|
||||
|
||||
if bytes.Equal(encoded, expectedBytes) != true {
|
||||
exifcommon.DumpBytesClause(encoded)
|
||||
|
||||
t.Fatalf("Encoded bytes not correct.")
|
||||
} else if unitCount != 18 {
|
||||
t.Fatalf("Unit-count not correct: (%d)", unitCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodec8828Oecf_Decode(t *testing.T) {
|
||||
encoded := []byte{
|
||||
0x00, 0x02,
|
||||
0x00, 0x16,
|
||||
0x61, 0x61, 0x00, 0x62, 0x62, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x16}
|
||||
|
||||
addressableData := encoded
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableData)
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
0,
|
||||
uint32(len(encoded)),
|
||||
0,
|
||||
nil,
|
||||
sb,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
codec := Codec8828Oecf{}
|
||||
|
||||
value, err := codec.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
|
||||
expectedValue := Tag8828Oecf{
|
||||
Columns: 2,
|
||||
Rows: 22,
|
||||
ColumnNames: []string{"aa", "bb"},
|
||||
Values: []exifcommon.SignedRational{{11, 22}},
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(value, expectedValue) != true {
|
||||
t.Fatalf("Decoded value not correct: %s", value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/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{})
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/common"
|
||||
)
|
||||
|
||||
func TestTag9000ExifVersion_String(t *testing.T) {
|
||||
ut := Tag9000ExifVersion{"abc"}
|
||||
s := ut.String()
|
||||
|
||||
if s != "abc" {
|
||||
t.Fatalf("String not correct: [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodec9000ExifVersion_Encode(t *testing.T) {
|
||||
s := "abc"
|
||||
ut := Tag9000ExifVersion{s}
|
||||
|
||||
codec := Codec9000ExifVersion{}
|
||||
|
||||
encoded, unitCount, err := codec.Encode(ut, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Equal(encoded, []byte(s)) != true {
|
||||
t.Fatalf("Encoded bytes not correct: %v", encoded)
|
||||
} else if unitCount != uint32(len(s)) {
|
||||
t.Fatalf("Unit-count not correct: (%d)", unitCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodec9000ExifVersion_Decode(t *testing.T) {
|
||||
s := "abc"
|
||||
ut := Tag9000ExifVersion{s}
|
||||
|
||||
encoded := []byte(s)
|
||||
|
||||
rawValueOffset := encoded
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
0,
|
||||
uint32(len(encoded)),
|
||||
0,
|
||||
rawValueOffset,
|
||||
nil,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
codec := Codec9000ExifVersion{}
|
||||
|
||||
value, err := codec.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, ut) != true {
|
||||
t.Fatalf("Decoded value not correct: %s\n", value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/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{})
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/common"
|
||||
)
|
||||
|
||||
func TestTagExif9101ComponentsConfiguration_String(t *testing.T) {
|
||||
ut := TagExif9101ComponentsConfiguration{
|
||||
ConfigurationId: TagUndefinedType_9101_ComponentsConfiguration_RGB,
|
||||
ConfigurationBytes: []byte{0x11, 0x22, 0x33, 0x44},
|
||||
}
|
||||
|
||||
s := ut.String()
|
||||
|
||||
if s != "Exif9101ComponentsConfiguration<ID=[RGB] BYTES=[17 34 51 68]>" {
|
||||
t.Fatalf("String not correct: [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodecExif9101ComponentsConfiguration_Encode(t *testing.T) {
|
||||
configurationBytes := []byte(TagUndefinedType_9101_ComponentsConfiguration_Names[TagUndefinedType_9101_ComponentsConfiguration_RGB])
|
||||
|
||||
ut := TagExif9101ComponentsConfiguration{
|
||||
ConfigurationId: TagUndefinedType_9101_ComponentsConfiguration_RGB,
|
||||
ConfigurationBytes: configurationBytes,
|
||||
}
|
||||
|
||||
codec := CodecExif9101ComponentsConfiguration{}
|
||||
|
||||
encoded, unitCount, err := codec.Encode(ut, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Equal(encoded, configurationBytes) != true {
|
||||
exifcommon.DumpBytesClause(encoded)
|
||||
|
||||
t.Fatalf("Encoded bytes not correct: %v", encoded)
|
||||
} else if unitCount != uint32(len(configurationBytes)) {
|
||||
t.Fatalf("Unit-count not correct: (%d)", unitCount)
|
||||
}
|
||||
|
||||
s := string(configurationBytes)
|
||||
|
||||
if s != TagUndefinedType_9101_ComponentsConfiguration_Names[TagUndefinedType_9101_ComponentsConfiguration_RGB] {
|
||||
t.Fatalf("Recovered configuration name not correct: [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodecExif9101ComponentsConfiguration_Decode(t *testing.T) {
|
||||
configurationBytes := TagUndefinedType_9101_ComponentsConfiguration_Configurations[TagUndefinedType_9101_ComponentsConfiguration_RGB]
|
||||
|
||||
ut := TagExif9101ComponentsConfiguration{
|
||||
ConfigurationId: TagUndefinedType_9101_ComponentsConfiguration_RGB,
|
||||
ConfigurationBytes: configurationBytes,
|
||||
}
|
||||
|
||||
rawValueOffset := configurationBytes
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
0,
|
||||
uint32(len(configurationBytes)),
|
||||
0,
|
||||
rawValueOffset,
|
||||
nil,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
codec := CodecExif9101ComponentsConfiguration{}
|
||||
|
||||
value, err := codec.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, ut) != true {
|
||||
t.Fatalf("Decoded value not correct: %s != %s\n", value, ut)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"crypto/sha1"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/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{})
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-utility/v2/filesystem"
|
||||
|
||||
"b612.me/exif/common"
|
||||
)
|
||||
|
||||
func TestTag927CMakerNote_String(t *testing.T) {
|
||||
ut := Tag927CMakerNote{
|
||||
MakerNoteType: []byte{0, 1, 2, 3, 4},
|
||||
MakerNoteBytes: []byte{5, 6, 7, 8, 9},
|
||||
}
|
||||
|
||||
s := ut.String()
|
||||
if s != "MakerNote<TYPE-ID=[00 01 02 03 04] LEN=(5) SHA1=[bdb42cb7eb76e64efe49b22369b404c67b0af55a]>" {
|
||||
t.Fatalf("String not correct: [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodec927CMakerNote_Encode(t *testing.T) {
|
||||
codec := Codec927CMakerNote{}
|
||||
|
||||
prefix := []byte{0, 1, 2, 3, 4}
|
||||
b := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
|
||||
ut := Tag927CMakerNote{
|
||||
MakerNoteType: prefix,
|
||||
MakerNoteBytes: b,
|
||||
}
|
||||
|
||||
encoded, unitCount, err := codec.Encode(ut, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Equal(encoded, b) != true {
|
||||
t.Fatalf("Encoding not correct: %v", encoded)
|
||||
} else if unitCount != uint32(len(b)) {
|
||||
t.Fatalf("Unit-count not correct: (%d)", len(b))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodec927CMakerNote_Decode(t *testing.T) {
|
||||
b := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
|
||||
ut := Tag927CMakerNote{
|
||||
MakerNoteType: b,
|
||||
MakerNoteBytes: b,
|
||||
}
|
||||
|
||||
sb := rifs.NewSeekableBufferWithBytes(b)
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
0,
|
||||
uint32(len(b)),
|
||||
0,
|
||||
nil,
|
||||
sb,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
codec := Codec927CMakerNote{}
|
||||
|
||||
value, err := codec.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, ut) != true {
|
||||
t.Fatalf("Decoded value not correct: %s != %s", value, ut)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/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{})
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-utility/v2/filesystem"
|
||||
|
||||
"b612.me/exif/common"
|
||||
)
|
||||
|
||||
func TestTag9286UserComment_String(t *testing.T) {
|
||||
comment := "some comment"
|
||||
|
||||
ut := Tag9286UserComment{
|
||||
EncodingType: TagUndefinedType_9286_UserComment_Encoding_ASCII,
|
||||
EncodingBytes: []byte(comment),
|
||||
}
|
||||
|
||||
s := ut.String()
|
||||
if s != "[ASCII] some comment" {
|
||||
t.Fatalf("String not correct: [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodec9286UserComment_Encode(t *testing.T) {
|
||||
comment := "some comment"
|
||||
|
||||
ut := Tag9286UserComment{
|
||||
EncodingType: TagUndefinedType_9286_UserComment_Encoding_ASCII,
|
||||
EncodingBytes: []byte(comment),
|
||||
}
|
||||
|
||||
codec := Codec9286UserComment{}
|
||||
|
||||
encoded, unitCount, err := codec.Encode(ut, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
typeBytes := TagUndefinedType_9286_UserComment_Encodings[TagUndefinedType_9286_UserComment_Encoding_ASCII]
|
||||
if bytes.Equal(encoded[:8], typeBytes) != true {
|
||||
exifcommon.DumpBytesClause(encoded[:8])
|
||||
|
||||
t.Fatalf("Encoding type not correct.")
|
||||
}
|
||||
|
||||
if bytes.Equal(encoded[8:], []byte(comment)) != true {
|
||||
exifcommon.DumpBytesClause(encoded[8:])
|
||||
|
||||
t.Fatalf("Encoded comment not correct.")
|
||||
}
|
||||
|
||||
if unitCount != uint32(len(encoded)) {
|
||||
t.Fatalf("Unit-count not correct: (%d)", unitCount)
|
||||
}
|
||||
|
||||
exifcommon.DumpBytesClause(encoded)
|
||||
|
||||
}
|
||||
|
||||
func TestCodec9286UserComment_Decode(t *testing.T) {
|
||||
encoded := []byte{
|
||||
0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00,
|
||||
0x73, 0x6f, 0x6d, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74,
|
||||
}
|
||||
|
||||
addressableBytes := encoded
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableBytes)
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
0,
|
||||
uint32(len(encoded)),
|
||||
0,
|
||||
nil,
|
||||
sb,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
codec := Codec9286UserComment{}
|
||||
|
||||
decoded, err := codec.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
|
||||
comment := "some comment"
|
||||
|
||||
expectedUt := Tag9286UserComment{
|
||||
EncodingType: TagUndefinedType_9286_UserComment_Encoding_ASCII,
|
||||
EncodingBytes: []byte(comment),
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(decoded, expectedUt) != true {
|
||||
t.Fatalf("Decoded struct not correct.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/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{})
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-utility/v2/filesystem"
|
||||
|
||||
"b612.me/exif/common"
|
||||
)
|
||||
|
||||
func TestTagA000FlashpixVersion_String(t *testing.T) {
|
||||
versionPhrase := "some version"
|
||||
|
||||
ut := TagA000FlashpixVersion{versionPhrase}
|
||||
|
||||
s := ut.String()
|
||||
if s != versionPhrase {
|
||||
t.Fatalf("String not correct: [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodecA000FlashpixVersion_Encode(t *testing.T) {
|
||||
versionPhrase := "some version"
|
||||
|
||||
ut := TagA000FlashpixVersion{versionPhrase}
|
||||
|
||||
codec := CodecA000FlashpixVersion{}
|
||||
|
||||
encoded, unitCount, err := codec.Encode(ut, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Equal(encoded, []byte(versionPhrase)) != true {
|
||||
exifcommon.DumpBytesClause(encoded)
|
||||
|
||||
t.Fatalf("Encoding not correct.")
|
||||
} else if unitCount != uint32(len(encoded)) {
|
||||
t.Fatalf("Unit-count not correct: (%d)", unitCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodecA000FlashpixVersion_Decode(t *testing.T) {
|
||||
versionPhrase := "some version"
|
||||
|
||||
expectedUt := TagA000FlashpixVersion{versionPhrase}
|
||||
|
||||
encoded := []byte(versionPhrase)
|
||||
|
||||
addressableBytes := encoded
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableBytes)
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
0,
|
||||
uint32(len(encoded)),
|
||||
0,
|
||||
nil,
|
||||
sb,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
codec := CodecA000FlashpixVersion{}
|
||||
|
||||
decoded, err := codec.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(decoded, expectedUt) != true {
|
||||
t.Fatalf("Decoded struct not correct.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/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{})
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-utility/v2/filesystem"
|
||||
|
||||
"b612.me/exif/common"
|
||||
)
|
||||
|
||||
func TestTagA20CSpatialFrequencyResponse_String(t *testing.T) {
|
||||
ut := TagA20CSpatialFrequencyResponse{
|
||||
Columns: 2,
|
||||
Rows: 9,
|
||||
ColumnNames: []string{"column1", "column2"},
|
||||
Values: []exifcommon.Rational{
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
},
|
||||
}
|
||||
|
||||
s := ut.String()
|
||||
if s != "CodecA20CSpatialFrequencyResponse<COLUMNS=(2) ROWS=(9)>" {
|
||||
t.Fatalf("String not correct: [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodecA20CSpatialFrequencyResponse_Encode(t *testing.T) {
|
||||
ut := TagA20CSpatialFrequencyResponse{
|
||||
Columns: 2,
|
||||
Rows: 9,
|
||||
ColumnNames: []string{"column1", "column2"},
|
||||
Values: []exifcommon.Rational{
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
},
|
||||
}
|
||||
|
||||
codec := CodecA20CSpatialFrequencyResponse{}
|
||||
|
||||
encoded, unitCount, err := codec.Encode(ut, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
expectedEncoded := []byte{
|
||||
0x00, 0x02,
|
||||
0x00, 0x09,
|
||||
0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x31, 0x00,
|
||||
0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x32, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
|
||||
}
|
||||
|
||||
if bytes.Equal(encoded, expectedEncoded) != true {
|
||||
exifcommon.DumpBytesClause(encoded)
|
||||
|
||||
t.Fatalf("Encoding not correct.")
|
||||
} else if unitCount != uint32(len(encoded)) {
|
||||
t.Fatalf("Unit-count not correct: (%d)", unitCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodecA20CSpatialFrequencyResponse_Decode(t *testing.T) {
|
||||
expectedUt := TagA20CSpatialFrequencyResponse{
|
||||
Columns: 2,
|
||||
Rows: 9,
|
||||
ColumnNames: []string{"column1", "column2"},
|
||||
Values: []exifcommon.Rational{
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
},
|
||||
}
|
||||
|
||||
encoded := []byte{
|
||||
0x00, 0x02,
|
||||
0x00, 0x09,
|
||||
0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x31, 0x00,
|
||||
0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x32, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
|
||||
}
|
||||
|
||||
addressableBytes := encoded
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableBytes)
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
0,
|
||||
uint32(len(encoded)),
|
||||
0,
|
||||
nil,
|
||||
sb,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
codec := CodecA20CSpatialFrequencyResponse{}
|
||||
|
||||
decoded, err := codec.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(decoded, expectedUt) != true {
|
||||
t.Fatalf("Decoded struct not correct.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/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{})
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/common"
|
||||
)
|
||||
|
||||
func TestTagExifA300FileSource_String(t *testing.T) {
|
||||
ut := TagExifA300FileSource(0x1234)
|
||||
|
||||
s := ut.String()
|
||||
if s != "0x00001234" {
|
||||
t.Fatalf("String not correct: [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodecExifA300FileSource_Encode(t *testing.T) {
|
||||
ut := TagExifA300FileSource(0x1234)
|
||||
|
||||
codec := CodecExifA300FileSource{}
|
||||
|
||||
encoded, unitCount, err := codec.Encode(ut, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
expectedEncoded := []byte{0, 0, 0x12, 0x34}
|
||||
|
||||
if bytes.Equal(encoded, expectedEncoded) != true {
|
||||
exifcommon.DumpBytesClause(encoded)
|
||||
|
||||
t.Fatalf("Encoding not correct.")
|
||||
} else if unitCount != 1 {
|
||||
t.Fatalf("Unit-count not correct: (%d)", unitCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodecExifA300FileSource_Decode(t *testing.T) {
|
||||
expectedUt := TagExifA300FileSource(0x1234)
|
||||
|
||||
encoded := []byte{0, 0, 0x12, 0x34}
|
||||
|
||||
rawValueOffset := encoded
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
rawValueOffset,
|
||||
nil,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
codec := CodecExifA300FileSource{}
|
||||
|
||||
decoded, err := codec.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(decoded, expectedUt) != true {
|
||||
t.Fatalf("Decoded struct not correct.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/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{})
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/common"
|
||||
)
|
||||
|
||||
func TestTagExifA301SceneType_String(t *testing.T) {
|
||||
ut := TagExifA301SceneType(0x1234)
|
||||
|
||||
s := ut.String()
|
||||
if s != "0x00001234" {
|
||||
t.Fatalf("String not correct: [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodecExifA301SceneType_Encode(t *testing.T) {
|
||||
ut := TagExifA301SceneType(0x1234)
|
||||
|
||||
codec := CodecExifA301SceneType{}
|
||||
|
||||
encoded, unitCount, err := codec.Encode(ut, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
expectedEncoded := []byte{0, 0, 0x12, 0x34}
|
||||
|
||||
if bytes.Equal(encoded, expectedEncoded) != true {
|
||||
exifcommon.DumpBytesClause(encoded)
|
||||
|
||||
t.Fatalf("Encoding not correct.")
|
||||
} else if unitCount != 1 {
|
||||
t.Fatalf("Unit-count not correct: (%d)", unitCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodecExifA301SceneType_Decode(t *testing.T) {
|
||||
expectedUt := TagExifA301SceneType(0x1234)
|
||||
|
||||
encoded := []byte{0, 0, 0x12, 0x34}
|
||||
|
||||
rawValueOffset := encoded
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
rawValueOffset,
|
||||
nil,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
codec := CodecExifA301SceneType{}
|
||||
|
||||
decoded, err := codec.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(decoded, expectedUt) != true {
|
||||
t.Fatalf("Decoded struct not correct.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/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{})
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
"github.com/dsoprea/go-utility/v2/filesystem"
|
||||
|
||||
"b612.me/exif/common"
|
||||
)
|
||||
|
||||
func TestTagA302CfaPattern_String(t *testing.T) {
|
||||
ut := TagA302CfaPattern{
|
||||
HorizontalRepeat: 2,
|
||||
VerticalRepeat: 3,
|
||||
CfaValue: []byte{
|
||||
0, 1, 2, 3, 4, 5,
|
||||
},
|
||||
}
|
||||
|
||||
s := ut.String()
|
||||
|
||||
if s != "TagA302CfaPattern<HORZ-REPEAT=(2) VERT-REPEAT=(3) CFA-VALUE=(6)>" {
|
||||
t.Fatalf("String not correct: [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodecA302CfaPattern_Encode(t *testing.T) {
|
||||
ut := TagA302CfaPattern{
|
||||
HorizontalRepeat: 2,
|
||||
VerticalRepeat: 3,
|
||||
CfaValue: []byte{
|
||||
0, 1, 2, 3, 4,
|
||||
5, 6, 7, 8, 9,
|
||||
10, 11, 12, 13, 14,
|
||||
},
|
||||
}
|
||||
|
||||
codec := CodecA302CfaPattern{}
|
||||
|
||||
encoded, unitCount, err := codec.Encode(ut, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
expectedBytes := []byte{
|
||||
0x00, 0x02,
|
||||
0x00, 0x03,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
||||
}
|
||||
|
||||
if bytes.Equal(encoded, expectedBytes) != true {
|
||||
exifcommon.DumpBytesClause(encoded)
|
||||
|
||||
t.Fatalf("Encoded bytes not correct.")
|
||||
} else if unitCount != 19 {
|
||||
t.Fatalf("Unit-count not correct: (%d)", unitCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodecA302CfaPattern_Decode(t *testing.T) {
|
||||
encoded := []byte{
|
||||
0x00, 0x02,
|
||||
0x00, 0x03,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
|
||||
}
|
||||
|
||||
addressableBytes := encoded
|
||||
sb := rifs.NewSeekableBufferWithBytes(addressableBytes)
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
0,
|
||||
uint32(len(encoded)),
|
||||
0,
|
||||
nil,
|
||||
sb,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
codec := CodecA302CfaPattern{}
|
||||
|
||||
value, err := codec.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
|
||||
expectedValue := TagA302CfaPattern{
|
||||
HorizontalRepeat: 2,
|
||||
VerticalRepeat: 3,
|
||||
CfaValue: []byte{
|
||||
0, 1, 2, 3, 4, 5,
|
||||
},
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(value, expectedValue) != true {
|
||||
t.Fatalf("Decoded value not correct: %s", value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/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{})
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/common"
|
||||
)
|
||||
|
||||
func TestTag0002InteropVersion_String(t *testing.T) {
|
||||
ut := Tag0002InteropVersion{"abc"}
|
||||
s := ut.String()
|
||||
|
||||
if s != "abc" {
|
||||
t.Fatalf("String not correct: [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodec0002InteropVersion_Encode(t *testing.T) {
|
||||
s := "abc"
|
||||
ut := Tag0002InteropVersion{s}
|
||||
|
||||
codec := Codec0002InteropVersion{}
|
||||
|
||||
encoded, unitCount, err := codec.Encode(ut, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Equal(encoded, []byte(s)) != true {
|
||||
t.Fatalf("Encoded bytes not correct: %v", encoded)
|
||||
} else if unitCount != uint32(len(s)) {
|
||||
t.Fatalf("Unit-count not correct: (%d)", unitCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodec0002InteropVersion_Decode(t *testing.T) {
|
||||
s := "abc"
|
||||
ut := Tag0002InteropVersion{s}
|
||||
|
||||
encoded := []byte(s)
|
||||
|
||||
rawValueOffset := encoded
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
0,
|
||||
uint32(len(encoded)),
|
||||
0,
|
||||
rawValueOffset,
|
||||
nil,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
codec := Codec0002InteropVersion{}
|
||||
|
||||
value, err := codec.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, ut) != true {
|
||||
t.Fatalf("Decoded value not correct: %s\n", value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/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{})
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/common"
|
||||
)
|
||||
|
||||
func TestTag001BGPSProcessingMethod_String(t *testing.T) {
|
||||
ut := Tag001BGPSProcessingMethod{"abc"}
|
||||
s := ut.String()
|
||||
|
||||
if s != "abc" {
|
||||
t.Fatalf("String not correct: [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodec001BGPSProcessingMethod_Encode(t *testing.T) {
|
||||
s := "abc"
|
||||
ut := Tag001BGPSProcessingMethod{s}
|
||||
|
||||
codec := Codec001BGPSProcessingMethod{}
|
||||
|
||||
encoded, unitCount, err := codec.Encode(ut, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Equal(encoded, []byte(s)) != true {
|
||||
t.Fatalf("Encoded bytes not correct: %v", encoded)
|
||||
} else if unitCount != uint32(len(s)) {
|
||||
t.Fatalf("Unit-count not correct: (%d)", unitCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodec001BGPSProcessingMethod_Decode(t *testing.T) {
|
||||
s := "abc"
|
||||
ut := Tag001BGPSProcessingMethod{s}
|
||||
|
||||
encoded := []byte(s)
|
||||
|
||||
rawValueOffset := encoded
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
0,
|
||||
uint32(len(encoded)),
|
||||
0,
|
||||
rawValueOffset,
|
||||
nil,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
codec := Codec001BGPSProcessingMethod{}
|
||||
|
||||
value, err := codec.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, ut) != true {
|
||||
t.Fatalf("Decoded value not correct: %s\n", value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/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{})
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dsoprea/go-logging"
|
||||
|
||||
"b612.me/exif/common"
|
||||
)
|
||||
|
||||
func TestTag001CGPSAreaInformation_String(t *testing.T) {
|
||||
ut := Tag001CGPSAreaInformation{"abc"}
|
||||
s := ut.String()
|
||||
|
||||
if s != "abc" {
|
||||
t.Fatalf("String not correct: [%s]", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodec001CGPSAreaInformation_Encode(t *testing.T) {
|
||||
s := "abc"
|
||||
ut := Tag001CGPSAreaInformation{s}
|
||||
|
||||
codec := Codec001CGPSAreaInformation{}
|
||||
|
||||
encoded, unitCount, err := codec.Encode(ut, exifcommon.TestDefaultByteOrder)
|
||||
log.PanicIf(err)
|
||||
|
||||
if bytes.Equal(encoded, []byte(s)) != true {
|
||||
t.Fatalf("Encoded bytes not correct: %v", encoded)
|
||||
} else if unitCount != uint32(len(s)) {
|
||||
t.Fatalf("Unit-count not correct: (%d)", unitCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodec001CGPSAreaInformation_Decode(t *testing.T) {
|
||||
s := "abc"
|
||||
ut := Tag001CGPSAreaInformation{s}
|
||||
|
||||
encoded := []byte(s)
|
||||
|
||||
rawValueOffset := encoded
|
||||
|
||||
valueContext := exifcommon.NewValueContext(
|
||||
"",
|
||||
0,
|
||||
uint32(len(encoded)),
|
||||
0,
|
||||
rawValueOffset,
|
||||
nil,
|
||||
exifcommon.TypeUndefined,
|
||||
exifcommon.TestDefaultByteOrder)
|
||||
|
||||
codec := Codec001CGPSAreaInformation{}
|
||||
|
||||
value, err := codec.Decode(valueContext)
|
||||
log.PanicIf(err)
|
||||
|
||||
if reflect.DeepEqual(value, ut) != true {
|
||||
t.Fatalf("Decoded value not correct: %s\n", value)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
)
|
||||
@@ -0,0 +1,44 @@
|
||||
package exifundefined
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"encoding/binary"
|
||||
|
||||
"b612.me/exif/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)
|
||||
}
|
||||
Reference in New Issue
Block a user