diff --git a/assets/exif_read.json b/assets/exif_read.json index 2d49fb8..70ad002 100644 --- a/assets/exif_read.json +++ b/assets/exif_read.json @@ -641,8 +641,8 @@ "tag_type_id": 1, "tag_type_name": "BYTE", "unit_count": 4, - "value": "2", - "value_string": "2" + "value": "0x02", + "value_string": "0x02" }, { "ifd_name": "IFD", diff --git a/exif-read-tool/main_test.go b/exif-read-tool/main_test.go index 4270d97..f53e191 100644 --- a/exif-read-tool/main_test.go +++ b/exif-read-tool/main_test.go @@ -89,7 +89,7 @@ IFD=[Exif] ID=(0xa432) NAME=[LensSpecification] COUNT=(4) TYPE=[RATIONAL] VALUE= IFD=[Exif] ID=(0xa434) NAME=[LensModel] COUNT=(22) TYPE=[ASCII] VALUE=[EF16-35mm f/4L IS USM] IFD=[Exif] ID=(0xa435) NAME=[LensSerialNumber] COUNT=(11) TYPE=[ASCII] VALUE=[2400001068] IFD=[IFD] ID=(0x8825) NAME=[GPSTag] COUNT=(1) TYPE=[LONG] VALUE=[9554] -IFD=[GPSInfo] ID=(0x0000) NAME=[GPSVersionID] COUNT=(4) TYPE=[BYTE] VALUE=[2] +IFD=[GPSInfo] ID=(0x0000) NAME=[GPSVersionID] COUNT=(4) TYPE=[BYTE] VALUE=[0x02] IFD=[IFD] ID=(0x0103) NAME=[Compression] COUNT=(1) TYPE=[SHORT] VALUE=[6] IFD=[IFD] ID=(0x011a) NAME=[XResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[72/1] IFD=[IFD] ID=(0x011b) NAME=[YResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[72/1] diff --git a/exif_test.go b/exif_test.go index c8bfb83..9ca3f98 100644 --- a/exif_test.go +++ b/exif_test.go @@ -169,7 +169,7 @@ func TestVisit(t *testing.T) { "IFD=[Exif] ID=(0xa434) NAME=[LensModel] COUNT=(22) TYPE=[ASCII] VALUE=[EF16-35mm f/4L IS USM]", "IFD=[Exif] ID=(0xa435) NAME=[LensSerialNumber] COUNT=(11) TYPE=[ASCII] VALUE=[2400001068]", "IFD=[IFD] ID=(0x8825) NAME=[GPSTag] COUNT=(1) TYPE=[LONG] VALUE=[9554]", - "IFD=[GPSInfo] ID=(0x0000) NAME=[GPSVersionID] COUNT=(4) TYPE=[BYTE] VALUE=[2]", + "IFD=[GPSInfo] ID=(0x0000) NAME=[GPSVersionID] COUNT=(4) TYPE=[BYTE] VALUE=[0x02]", "IFD=[IFD] ID=(0x0103) NAME=[Compression] COUNT=(1) TYPE=[SHORT] VALUE=[6]", "IFD=[IFD] ID=(0x011a) NAME=[XResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[72/1]", "IFD=[IFD] ID=(0x011b) NAME=[YResolution] COUNT=(1) TYPE=[RATIONAL] VALUE=[72/1]", @@ -179,7 +179,25 @@ func TestVisit(t *testing.T) { } if reflect.DeepEqual(tags, expected) == false { - t.Fatalf("tags not correct:\n%v", tags) + fmt.Printf("\n") + fmt.Printf("ACTUAL:\n") + fmt.Printf("\n") + + for _, line := range tags { + fmt.Println(line) + } + + fmt.Printf("\n") + fmt.Printf("EXPECTED:\n") + fmt.Printf("\n") + + for _, line := range expected { + fmt.Println(line) + } + + fmt.Printf("\n") + + t.Fatalf("tags not correct.") } } diff --git a/ifd_builder_encode_test.go b/ifd_builder_encode_test.go index 9b08600..703abd4 100644 --- a/ifd_builder_encode_test.go +++ b/ifd_builder_encode_test.go @@ -568,7 +568,7 @@ func validateExifSimpleTestIb(exifData []byte, t *testing.T) { t.Fatalf("Tag-ID for entry (%d) not correct: (0x%02x) != (0x%02x)", i, e.TagId, expected[i].tagId) } - value, err := e.Value(TestDefaultByteOrder, addressableData) + value, err := e.Value(addressableData, TestDefaultByteOrder) log.PanicIf(err) if reflect.DeepEqual(value, expected[i].value) != true { @@ -742,7 +742,7 @@ func Test_IfdByteEncoder_EncodeToExif(t *testing.T) { validateExifSimpleTestIb(exifData, t) } -func Test_IfdByteEncoder_EncodeToExif_WithChild(t *testing.T) { +func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) { defer func() { if state := recover(); state != nil { err := log.Wrap(state.(error)) @@ -780,10 +780,11 @@ func Test_IfdByteEncoder_EncodeToExif_WithChild(t *testing.T) { log.PanicIf(err) -// TODO(dustin): !! Finish this. - // // Link to another IB (sibling relationship). The root IFD may occur twice - // // in some JPEGs (for thumbnail or FlashPix images). + // Link to another IB (sibling relationship). The root IFD may occur twice + // in some JPEGs (for thumbnail or FlashPix images). + +// TODO(dustin): !! Debugging. // nextIb := NewIfdBuilder(RootIi, TestDefaultByteOrder) // err = nextIb.AddFromConfig(0x0101, []uint32 { 0x11223344 }) @@ -874,7 +875,7 @@ func ExampleIfdByteEncoder_EncodeToExif() { addressableData := exifData[ExifAddressableAreaStart:] for i, e := range index.RootIfd.Entries { - value, err := e.Value(EncodeDefaultByteOrder, addressableData) + value, err := e.Value(addressableData, EncodeDefaultByteOrder) log.PanicIf(err) fmt.Printf("%d: %s %v\n", i, e, value) @@ -949,7 +950,7 @@ func ExampleIfdByteEncoder_EncodeToExif() { // addressableData := exifData[ExifAddressableAreaStart:] // for i, e := range index.RootIfd.Entries { -// value, err := e.Value(EncodeDefaultByteOrder, addressableData) +// value, err := e.Value(addressableData, EncodeDefaultByteOrder) // log.PanicIf(err) // fmt.Printf("%d: %s %v\n", i, e, value) diff --git a/ifd_tag_entry.go b/ifd_tag_entry.go index 0891d11..26572df 100644 --- a/ifd_tag_entry.go +++ b/ifd_tag_entry.go @@ -33,7 +33,7 @@ func (ite IfdTagEntry) String() string { } // ValueString renders a string from whatever the value in this tag is. -func (ite IfdTagEntry) ValueString(byteOrder binary.ByteOrder, addressableData []byte) (value string, err error) { +func (ite IfdTagEntry) ValueString(addressableData []byte, byteOrder binary.ByteOrder) (value string, err error) { defer func() { if state := recover(); state != nil { err = log.Wrap(state.(error)) @@ -125,7 +125,7 @@ func (ite IfdTagEntry) ValueBytes(addressableData []byte, byteOrder binary.ByteO } // Value returns the specific, parsed, typed value from the tag. -func (ite IfdTagEntry) Value(byteOrder binary.ByteOrder, addressableData []byte) (value interface{}, err error) { +func (ite IfdTagEntry) Value(addressableData []byte, byteOrder binary.ByteOrder) (value interface{}, err error) { defer func() { if state := recover(); state != nil { err = log.Wrap(state.(error)) diff --git a/ifd_tag_entry_test.go b/ifd_tag_entry_test.go new file mode 100644 index 0000000..3f90095 --- /dev/null +++ b/ifd_tag_entry_test.go @@ -0,0 +1,185 @@ +package exif + +import ( + "testing" + "bytes" + + "github.com/dsoprea/go-logging" +) + +func Test_IfdTagEntry_ValueString_Allocated(t *testing.T) { + ite := IfdTagEntry{ + TagId: 0x1, + TagIndex: 0, + TagType: TypeByte, + UnitCount: 6, + ValueOffset: 0x0, + RawValueOffset: []byte { 0x0, 0x0, 0x0, 0x0 }, + Ii: RootIi, + } + + data := []byte { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 } + + value, err := ite.ValueString(data, TestDefaultByteOrder) + log.PanicIf(err) + + expected := "11 22 33 44 55 66" + if value != expected { + t.Fatalf("Value not expected: [%s] != [%s]", value, expected) + } +} + +func Test_IfdTagEntry_ValueString_Embedded(t *testing.T) { + data := []byte { 0x11, 0x22, 0x33, 0x44 } + + ite := IfdTagEntry{ + TagId: 0x1, + TagIndex: 0, + TagType: TypeByte, + UnitCount: 4, + ValueOffset: 0, + RawValueOffset: data, + Ii: RootIi, + } + + value, err := ite.ValueString(nil, TestDefaultByteOrder) + log.PanicIf(err) + + expected := "11 22 33 44" + if value != expected { + t.Fatalf("Value not expected: [%s] != [%s]", value, expected) + } +} + +func Test_IfdTagEntry_ValueBytes_Allocated(t *testing.T) { + ite := IfdTagEntry{ + TagId: 0x1, + TagIndex: 0, + TagType: TypeByte, + UnitCount: 6, + ValueOffset: 0x0, + RawValueOffset: []byte { 0x0, 0x0, 0x0, 0x0 }, + Ii: RootIi, + } + + data := []byte { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 } + + value, err := ite.ValueBytes(data, TestDefaultByteOrder) + log.PanicIf(err) + + if bytes.Compare(value, data) != 0 { + t.Fatalf("Value not expected: [%s] != [%s]", value, data) + } +} + +func Test_IfdTagEntry_ValueBytes_Embedded(t *testing.T) { + data := []byte { 0x11, 0x22, 0x33, 0x44 } + + ite := IfdTagEntry{ + TagId: 0x1, + TagIndex: 0, + TagType: TypeByte, + UnitCount: 4, + ValueOffset: 0x0, + RawValueOffset: data, + Ii: RootIi, + } + + value, err := ite.ValueBytes(nil, TestDefaultByteOrder) + log.PanicIf(err) + + if bytes.Compare(value, data) != 0 { + t.Fatalf("Value not expected: [%s] != [%s]", value, data) + } +} + +func Test_IfdTagEntry_Value_Normal(t *testing.T) { + data := []byte { 0x11, 0x22, 0x33, 0x44 } + + ite := IfdTagEntry{ + TagId: 0x1, + TagIndex: 0, + TagType: TypeByte, + UnitCount: 4, + ValueOffset: 0x0, + RawValueOffset: data, + Ii: RootIi, + } + + value, err := ite.Value(nil, TestDefaultByteOrder) + log.PanicIf(err) + + if bytes.Compare(value.([]byte), data) != 0 { + t.Fatalf("Value not expected: [%s] != [%s]", value, data) + } +} + +func Test_IfdTagEntry_Value_Unknown(t *testing.T) { + data := []uint8 { '0', '2', '3', '0' } + + ite := IfdTagEntry{ + TagId: 0x9000, + TagIndex: 0, + TagType: TypeUndefined, + UnitCount: 4, + ValueOffset: 0x0, + RawValueOffset: data, + Ii: ExifIi, + } + + value, err := ite.Value(nil, TestDefaultByteOrder) + log.PanicIf(err) + + gs := value.(TagUnknownType_GeneralString) + + vb, err := gs.ValueBytes() + log.PanicIf(err) + + if bytes.Compare(vb, data) != 0 { + t.Fatalf("Value not expected: [%s] != [%s]", value, data) + } +} + +func Test_IfdTagEntry_String(t *testing.T) { + ite := IfdTagEntry{ + TagId: 0x1, + TagIndex: 0, + TagType: TypeByte, + UnitCount: 6, + ValueOffset: 0x0, + RawValueOffset: []byte { 0x0, 0x0, 0x0, 0x0 }, + Ii: RootIi, + } + + expected := "IfdTagEntry" + if ite.String() != expected { + t.Fatalf("string representation not expected: [%s] != [%s]", ite.String(), expected) + } +} + +func Test_IfdTagEntryValueResolver_ValueBytes(t *testing.T) { + ite := IfdTagEntry{ + TagId: 0x1, + TagIndex: 0, + TagType: TypeByte, + UnitCount: 6, + ValueOffset: 0x0, + RawValueOffset: []byte { 0x0, 0x0, 0x0, 0x0 }, + Ii: RootIi, + } + + exifData := make([]byte, ExifAddressableAreaStart + 6) + copy(exifData, ExifHeaderPrefixBytes) + + allocatedData := []byte { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 } + copy(exifData[ExifAddressableAreaStart:], allocatedData) + + itevr := NewIfdTagEntryValueResolver(exifData, TestDefaultByteOrder) + + value, err := itevr.ValueBytes(&ite) + log.PanicIf(err) + + if bytes.Compare(value, allocatedData) != 0 { + t.Fatalf("bytes not expected: %v != %v", value, allocatedData) + } +} diff --git a/type.go b/type.go index 020e7ad..d639993 100644 --- a/type.go +++ b/type.go @@ -582,9 +582,9 @@ func (tt TagType) ResolveAsString(valueContext ValueContext, justFirst bool) (va log.PanicIf(err) if justFirst == false { - return fmt.Sprintf("%v", raw), nil + return DumpBytesToString(raw), nil } else if valueContext.UnitCount > 0 { - return fmt.Sprintf("%v", raw[0]), nil + return fmt.Sprintf("0x%02x", raw[0]), nil } else { return "", nil }