ifd_builder: Now embed type in `builderTag`.

- We were automatically looking this up but this will prevent users from
  having a mechanism to use custom tags.
pull/3/head
Dustin Oprea 2018-05-02 06:40:36 -04:00
parent b748843a75
commit 16586eb8cb
5 changed files with 63 additions and 43 deletions

View File

@ -66,6 +66,7 @@ type builderTag struct {
ii IfdIdentity
tagId uint16
typeId uint16
// value is either a value that can be encoded, an IfdBuilder instance (for
// child IFDs), or an IfdTagEntry instance representing an existing,
@ -73,10 +74,34 @@ type builderTag struct {
value *IfdBuilderTagValue
}
func NewBuilderTag(ii IfdIdentity, tagId uint16, value *IfdBuilderTagValue) builderTag {
func NewBuilderTag(ii IfdIdentity, tagId uint16, typeId uint16, value *IfdBuilderTagValue) builderTag {
return builderTag{
ii: ii,
tagId: tagId,
typeId: typeId,
value: value,
}
}
func NewStandardBuilderTag(ii IfdIdentity, tagId uint16, value *IfdBuilderTagValue) builderTag {
ti := NewTagIndex()
it, err := ti.Get(ii, tagId)
log.PanicIf(err)
return builderTag{
ii: ii,
tagId: tagId,
typeId: it.Type,
value: value,
}
}
func NewChildIfdTag(ii IfdIdentity, tagId uint16, value *IfdBuilderTagValue) builderTag {
return builderTag{
ii: ii,
tagId: tagId,
typeId: TypeLong,
value: value,
}
}
@ -102,18 +127,21 @@ func (bt builderTag) String() string {
// NewBuilderTagFromConfig allows us to easily generate solid, consistent tags
// for testing with. `ii` is the tpye of IFD that owns this tag.
func NewBuilderTagFromConfig(ii IfdIdentity, tagId uint16, byteOrder binary.ByteOrder, value interface{}) builderTag {
var typeId uint16
var tagValue *IfdBuilderTagValue
switch value.(type) {
case *IfdBuilder:
tagValue = NewIfdBuilderTagValueFromIfdBuilder(value.(*IfdBuilder))
typeId = TypeLong
default:
ti := NewTagIndex()
it, err := ti.Get(ii, tagId)
log.PanicIf(err)
tt := NewTagType(it.Type, byteOrder)
typeId = it.Type
tt := NewTagType(typeId, byteOrder)
ve := NewValueEncoder(byteOrder)
@ -123,11 +151,11 @@ func NewBuilderTagFromConfig(ii IfdIdentity, tagId uint16, byteOrder binary.Byte
tagValue = NewIfdBuilderTagValueFromBytes(ed.Encoded)
}
return builderTag{
ii: ii,
tagId: tagId,
value: tagValue,
}
return NewBuilderTag(
ii,
tagId,
typeId,
tagValue)
}
// NewBuilderTagFromConfigWithName allows us to easily generate solid, consistent tags
@ -148,11 +176,11 @@ func NewBuilderTagFromConfigWithName(ii IfdIdentity, tagName string, byteOrder b
tagValue := NewIfdBuilderTagValueFromBytes(ed.Encoded)
return builderTag{
ii: ii,
tagId: it.Id,
value: tagValue,
}
return NewBuilderTag(
ii,
it.Id,
it.Type,
tagValue)
}
@ -554,11 +582,10 @@ func (ib *IfdBuilder) AddChildIb(childIb *IfdBuilder) (err error) {
value := NewIfdBuilderTagValueFromIfdBuilder(childIb)
bt := builderTag{
ii: childIb.ii,
tagId: childIb.ifdTagId,
value: value,
}
bt := NewChildIfdTag(
childIb.ii,
childIb.ifdTagId,
value)
ib.tags = append(ib.tags, bt)
@ -614,6 +641,7 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResol
bt := builderTag{
tagId: ite.TagId,
typeId: ite.TagType,
}
if itevr == nil {

View File

@ -144,30 +144,20 @@ func (ibe *IfdByteEncoder) encodeTagToBytes(ib *IfdBuilder, bt *builderTag, bw *
}
}()
ti := NewTagIndex()
// Write tag-ID.
err = bw.WriteUint16(bt.tagId)
log.PanicIf(err)
// Write type.
it, err := ti.Get(ib.ii, bt.tagId)
log.PanicIf(err)
// Works for both values and child IFDs (which have an official size of
// LONG).
err = bw.WriteUint16(it.Type)
err = bw.WriteUint16(bt.typeId)
log.PanicIf(err)
// Write unit-count.
// TODO(dustin): !! Test that we write a list of shorts, uints, etc.. correctly.
// TODO(dustin): !! Make sure we test all of the different cases below.
if bt.value.IsBytes() == true {
effectiveType := it.Type
if it.Type == TypeUndefined {
effectiveType := bt.typeId
if bt.typeId == TypeUndefined {
effectiveType = TypeByte
}

View File

@ -180,6 +180,13 @@ func Test_IfdByteEncoder__Arithmetic(t *testing.T) {
}
func Test_IfdByteEncoder_encodeTagToBytes_bytes_embedded1(t *testing.T) {
defer func() {
if state := recover(); state != nil {
err := log.Wrap(state.(error))
log.PrintErrorf(err, "Test failure.")
}
}()
ibe := NewIfdByteEncoder()
ib := NewIfdBuilder(GpsIi, TestDefaultByteOrder)
@ -313,11 +320,10 @@ func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) {
childIb := NewIfdBuilder(ExifIi, TestDefaultByteOrder)
childIbTestTag := builderTag{
ii: ExifIi,
tagId: 0x8822,
value: NewIfdBuilderTagValueFromBytes([]byte { 0x12, 0x34 }),
}
childIbTestTag := NewStandardBuilderTag(
ExifIi,
0x8822,
NewIfdBuilderTagValueFromBytes([]byte { 0x12, 0x34 }))
childIb.Add(childIbTestTag)
@ -795,6 +801,3 @@ func ExampleIfdByteEncoder_EncodeToExif() {
}
// TODO(dustin): !! Write test with both chained and child IFDs
// TODO(dustin): !! Test specific unknown-type tags.
// TODO(dustin): !! Test what happens with unhandled unknown-type tags (though it should never get to this point in the normal workflow).

View File

@ -9,10 +9,6 @@ import (
"github.com/dsoprea/go-logging"
)
// TODO(dustin): !! We need to have knowledge of the types so that we can validate or induce extra info for the adds.
func TestAdd(t *testing.T) {
ib := NewIfdBuilder(RootIi, TestDefaultByteOrder)

View File

@ -28,7 +28,7 @@ func TestUndefinedValue_ExifVersion(t *testing.T) {
// have the bytes.
encodedValue := NewIfdBuilderTagValueFromBytes(ed.Encoded)
bt := NewBuilderTag(ii, 0x9000, encodedValue)
bt := NewStandardBuilderTag(ii, 0x9000, encodedValue)
// Stage the build.
@ -73,3 +73,6 @@ func TestUndefinedValue_ExifVersion(t *testing.T) {
t.Fatalf("Tag's parent IFD is not correct: %v", ite.Ii)
}
}
// TODO(dustin): !! Add tests for remaining, well-defined unknown
// TODO(dustin): !! Test what happens with unhandled unknown-type tags (though it should never get to this point in the normal workflow).