...

Source file src/github.com/dsoprea/go-exif/v3/ifd_builder_encode_test.go

Documentation: github.com/dsoprea/go-exif/v3

     1  package exif
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/dsoprea/go-logging"
    10  
    11  	"github.com/dsoprea/go-exif/v3/common"
    12  )
    13  
    14  func Test_ByteWriter_writeAsBytes_uint8(t *testing.T) {
    15  	b := new(bytes.Buffer)
    16  	bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
    17  
    18  	err := bw.writeAsBytes(uint8(0x12))
    19  	log.PanicIf(err)
    20  
    21  	if bytes.Compare(b.Bytes(), []byte{0x12}) != 0 {
    22  		t.Fatalf("uint8 not encoded correctly.")
    23  	}
    24  }
    25  
    26  func Test_ByteWriter_writeAsBytes_uint16(t *testing.T) {
    27  	b := new(bytes.Buffer)
    28  	bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
    29  
    30  	err := bw.writeAsBytes(uint16(0x1234))
    31  	log.PanicIf(err)
    32  
    33  	if bytes.Compare(b.Bytes(), []byte{0x12, 0x34}) != 0 {
    34  		t.Fatalf("uint16 not encoded correctly.")
    35  	}
    36  }
    37  
    38  func Test_ByteWriter_writeAsBytes_uint32(t *testing.T) {
    39  	b := new(bytes.Buffer)
    40  	bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
    41  
    42  	err := bw.writeAsBytes(uint32(0x12345678))
    43  	log.PanicIf(err)
    44  
    45  	if bytes.Compare(b.Bytes(), []byte{0x12, 0x34, 0x56, 0x78}) != 0 {
    46  		t.Fatalf("uint32 not encoded correctly.")
    47  	}
    48  }
    49  
    50  func Test_ByteWriter_WriteUint16(t *testing.T) {
    51  	b := new(bytes.Buffer)
    52  	bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
    53  
    54  	err := bw.WriteUint16(uint16(0x1234))
    55  	log.PanicIf(err)
    56  
    57  	if bytes.Compare(b.Bytes(), []byte{0x12, 0x34}) != 0 {
    58  		t.Fatalf("uint16 not encoded correctly (as bytes).")
    59  	}
    60  }
    61  
    62  func Test_ByteWriter_WriteUint32(t *testing.T) {
    63  	b := new(bytes.Buffer)
    64  	bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
    65  
    66  	err := bw.WriteUint32(uint32(0x12345678))
    67  	log.PanicIf(err)
    68  
    69  	if bytes.Compare(b.Bytes(), []byte{0x12, 0x34, 0x56, 0x78}) != 0 {
    70  		t.Fatalf("uint32 not encoded correctly (as bytes).")
    71  	}
    72  }
    73  
    74  func Test_ByteWriter_WriteFourBytes(t *testing.T) {
    75  	b := new(bytes.Buffer)
    76  	bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
    77  
    78  	err := bw.WriteFourBytes([]byte{0x11, 0x22, 0x33, 0x44})
    79  	log.PanicIf(err)
    80  
    81  	if bytes.Compare(b.Bytes(), []byte{0x11, 0x22, 0x33, 0x44}) != 0 {
    82  		t.Fatalf("four-bytes not encoded correctly.")
    83  	}
    84  }
    85  
    86  func Test_ByteWriter_WriteFourBytes_TooMany(t *testing.T) {
    87  	b := new(bytes.Buffer)
    88  	bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
    89  
    90  	err := bw.WriteFourBytes([]byte{0x11, 0x22, 0x33, 0x44, 0x55})
    91  	if err == nil {
    92  		t.Fatalf("expected error for not exactly four-bytes")
    93  	} else if err.Error() != "value is not four-bytes: (5)" {
    94  		t.Fatalf("wrong error for not exactly four bytes: %v", err)
    95  	}
    96  }
    97  
    98  func Test_IfdDataAllocator_Allocate_InitialOffset1(t *testing.T) {
    99  	addressableOffset := uint32(0)
   100  	ida := newIfdDataAllocator(addressableOffset)
   101  
   102  	if ida.NextOffset() != addressableOffset {
   103  		t.Fatalf("initial offset not correct: (%d) != (%d)", ida.NextOffset(), addressableOffset)
   104  	} else if len(ida.Bytes()) != 0 {
   105  		t.Fatalf("initial buffer not empty")
   106  	}
   107  
   108  	data := []byte{0x1, 0x2, 0x3}
   109  	offset, err := ida.Allocate(data)
   110  	log.PanicIf(err)
   111  
   112  	expected := uint32(addressableOffset + 0)
   113  	if offset != expected {
   114  		t.Fatalf("offset not bumped correctly (2): (%d) != (%d)", offset, expected)
   115  	} else if ida.NextOffset() != offset+uint32(3) {
   116  		t.Fatalf("position counter not advanced properly")
   117  	} else if bytes.Compare(ida.Bytes(), []byte{0x1, 0x2, 0x3}) != 0 {
   118  		t.Fatalf("buffer not correct after write (1)")
   119  	}
   120  
   121  	data = []byte{0x4, 0x5, 0x6}
   122  	offset, err = ida.Allocate(data)
   123  	log.PanicIf(err)
   124  
   125  	expected = uint32(addressableOffset + 3)
   126  	if offset != expected {
   127  		t.Fatalf("offset not bumped correctly (3): (%d) != (%d)", offset, expected)
   128  	} else if ida.NextOffset() != offset+uint32(3) {
   129  		t.Fatalf("position counter not advanced properly")
   130  	} else if bytes.Compare(ida.Bytes(), []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}) != 0 {
   131  		t.Fatalf("buffer not correct after write (2)")
   132  	}
   133  }
   134  
   135  func Test_IfdDataAllocator_Allocate_InitialOffset2(t *testing.T) {
   136  	addressableOffset := uint32(10)
   137  	ida := newIfdDataAllocator(addressableOffset)
   138  
   139  	if ida.NextOffset() != addressableOffset {
   140  		t.Fatalf("initial offset not correct: (%d) != (%d)", ida.NextOffset(), addressableOffset)
   141  	} else if len(ida.Bytes()) != 0 {
   142  		t.Fatalf("initial buffer not empty")
   143  	}
   144  
   145  	data := []byte{0x1, 0x2, 0x3}
   146  	offset, err := ida.Allocate(data)
   147  	log.PanicIf(err)
   148  
   149  	expected := uint32(addressableOffset + 0)
   150  	if offset != expected {
   151  		t.Fatalf("offset not bumped correctly (2): (%d) != (%d)", offset, expected)
   152  	} else if ida.NextOffset() != offset+uint32(3) {
   153  		t.Fatalf("position counter not advanced properly")
   154  	} else if bytes.Compare(ida.Bytes(), []byte{0x1, 0x2, 0x3}) != 0 {
   155  		t.Fatalf("buffer not correct after write (1)")
   156  	}
   157  
   158  	data = []byte{0x4, 0x5, 0x6}
   159  	offset, err = ida.Allocate(data)
   160  	log.PanicIf(err)
   161  
   162  	expected = uint32(addressableOffset + 3)
   163  	if offset != expected {
   164  		t.Fatalf("offset not bumped correctly (3): (%d) != (%d)", offset, expected)
   165  	} else if ida.NextOffset() != offset+uint32(3) {
   166  		t.Fatalf("position counter not advanced properly")
   167  	} else if bytes.Compare(ida.Bytes(), []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}) != 0 {
   168  		t.Fatalf("buffer not correct after write (2)")
   169  	}
   170  }
   171  
   172  func Test_IfdByteEncoder__Arithmetic(t *testing.T) {
   173  	ibe := NewIfdByteEncoder()
   174  
   175  	if (ibe.TableSize(1) - ibe.TableSize(0)) != IfdTagEntrySize {
   176  		t.Fatalf("table-size/entry-size not consistent (1)")
   177  	} else if (ibe.TableSize(11) - ibe.TableSize(10)) != IfdTagEntrySize {
   178  		t.Fatalf("table-size/entry-size not consistent (2)")
   179  	}
   180  }
   181  
   182  func Test_IfdByteEncoder_encodeTagToBytes_bytes_embedded1(t *testing.T) {
   183  	defer func() {
   184  		if state := recover(); state != nil {
   185  			err := log.Wrap(state.(error))
   186  			log.PrintError(err)
   187  			t.Fatalf("Test failed.")
   188  		}
   189  	}()
   190  
   191  	ibe := NewIfdByteEncoder()
   192  
   193  	im, err := exifcommon.NewIfdMappingWithStandard()
   194  	log.PanicIf(err)
   195  
   196  	ti := NewTagIndex()
   197  	ib := NewIfdBuilder(im, ti, exifcommon.IfdGpsInfoStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   198  
   199  	it, err := ti.Get(ib.IfdIdentity(), uint16(0x0000))
   200  	log.PanicIf(err)
   201  
   202  	bt := NewStandardBuilderTag(exifcommon.IfdGpsInfoStandardIfdIdentity.UnindexedString(), it, exifcommon.TestDefaultByteOrder, []uint8{uint8(0x12)})
   203  
   204  	b := new(bytes.Buffer)
   205  	bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
   206  
   207  	addressableOffset := uint32(0x1234)
   208  	ida := newIfdDataAllocator(addressableOffset)
   209  
   210  	childIfdBlock, err := ibe.encodeTagToBytes(ib, bt, bw, ida, uint32(0))
   211  	log.PanicIf(err)
   212  
   213  	if childIfdBlock != nil {
   214  		t.Fatalf("no child-IFDs were expected to be allocated")
   215  	} else if bytes.Compare(b.Bytes(), []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x12, 0x00, 0x00, 0x00}) != 0 {
   216  		t.Fatalf("encoded tag-entry bytes not correct")
   217  	} else if ida.NextOffset() != addressableOffset {
   218  		t.Fatalf("allocation was done but not expected")
   219  	}
   220  }
   221  
   222  func Test_IfdByteEncoder_encodeTagToBytes_bytes_embedded2(t *testing.T) {
   223  	ibe := NewIfdByteEncoder()
   224  
   225  	im, err := exifcommon.NewIfdMappingWithStandard()
   226  	log.PanicIf(err)
   227  
   228  	ti := NewTagIndex()
   229  	ib := NewIfdBuilder(im, ti, exifcommon.IfdGpsInfoStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   230  
   231  	it, err := ti.Get(ib.IfdIdentity(), uint16(0x0000))
   232  	log.PanicIf(err)
   233  
   234  	bt := NewStandardBuilderTag(exifcommon.IfdGpsInfoStandardIfdIdentity.UnindexedString(), it, exifcommon.TestDefaultByteOrder, []uint8{uint8(0x12), uint8(0x34), uint8(0x56), uint8(0x78)})
   235  
   236  	b := new(bytes.Buffer)
   237  	bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
   238  
   239  	addressableOffset := uint32(0x1234)
   240  	ida := newIfdDataAllocator(addressableOffset)
   241  
   242  	childIfdBlock, err := ibe.encodeTagToBytes(ib, bt, bw, ida, uint32(0))
   243  	log.PanicIf(err)
   244  
   245  	if childIfdBlock != nil {
   246  		t.Fatalf("no child-IFDs were expected to be allocated")
   247  	} else if bytes.Compare(b.Bytes(), []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x12, 0x34, 0x56, 0x78}) != 0 {
   248  		t.Fatalf("encoded tag-entry bytes not correct")
   249  	} else if ida.NextOffset() != addressableOffset {
   250  		t.Fatalf("allocation was done but not expected")
   251  	}
   252  }
   253  
   254  func Test_IfdByteEncoder_encodeTagToBytes_bytes_allocated(t *testing.T) {
   255  	ibe := NewIfdByteEncoder()
   256  
   257  	im, err := exifcommon.NewIfdMappingWithStandard()
   258  	log.PanicIf(err)
   259  
   260  	ti := NewTagIndex()
   261  	ib := NewIfdBuilder(im, ti, exifcommon.IfdGpsInfoStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   262  
   263  	b := new(bytes.Buffer)
   264  	bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
   265  
   266  	addressableOffset := uint32(0x1234)
   267  	ida := newIfdDataAllocator(addressableOffset)
   268  
   269  	it, err := ti.Get(ib.IfdIdentity(), uint16(0x0000))
   270  	log.PanicIf(err)
   271  
   272  	bt := NewStandardBuilderTag(exifcommon.IfdGpsInfoStandardIfdIdentity.UnindexedString(), it, exifcommon.TestDefaultByteOrder, []uint8{uint8(0x12), uint8(0x34), uint8(0x56), uint8(0x78), uint8(0x9a)})
   273  
   274  	childIfdBlock, err := ibe.encodeTagToBytes(ib, bt, bw, ida, uint32(0))
   275  	log.PanicIf(err)
   276  
   277  	if childIfdBlock != nil {
   278  		t.Fatalf("no child-IFDs were expected to be allocated (1)")
   279  	} else if bytes.Compare(b.Bytes(), []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x12, 0x34}) != 0 {
   280  		t.Fatalf("encoded tag-entry bytes not correct (1)")
   281  	} else if ida.NextOffset() != addressableOffset+uint32(5) {
   282  		t.Fatalf("allocation offset not expected (1)")
   283  	} else if bytes.Compare(ida.Bytes(), []byte{0x12, 0x34, 0x56, 0x78, 0x9A}) != 0 {
   284  		t.Fatalf("allocated data not correct (1)")
   285  	}
   286  
   287  	// Test that another allocation encodes to the new offset.
   288  
   289  	bt = NewStandardBuilderTag(exifcommon.IfdGpsInfoStandardIfdIdentity.UnindexedString(), it, exifcommon.TestDefaultByteOrder, []uint8{uint8(0xbc), uint8(0xde), uint8(0xf0), uint8(0x12), uint8(0x34)})
   290  
   291  	childIfdBlock, err = ibe.encodeTagToBytes(ib, bt, bw, ida, uint32(0))
   292  	log.PanicIf(err)
   293  
   294  	if childIfdBlock != nil {
   295  		t.Fatalf("no child-IFDs were expected to be allocated (2)")
   296  	} else if bytes.Compare(b.Bytes(), []byte{
   297  		0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x12, 0x34, // Tag 1
   298  		0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x12, 0x39, // Tag 2
   299  	}) != 0 {
   300  		t.Fatalf("encoded tag-entry bytes not correct (2)")
   301  	} else if ida.NextOffset() != addressableOffset+uint32(10) {
   302  		t.Fatalf("allocation offset not expected (2)")
   303  	} else if bytes.Compare(ida.Bytes(), []byte{
   304  		0x12, 0x34, 0x56, 0x78, 0x9A,
   305  		0xbc, 0xde, 0xf0, 0x12, 0x34,
   306  	}) != 0 {
   307  		t.Fatalf("allocated data not correct (2)")
   308  	}
   309  }
   310  
   311  func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withoutAllocate(t *testing.T) {
   312  	ibe := NewIfdByteEncoder()
   313  
   314  	im, err := exifcommon.NewIfdMappingWithStandard()
   315  	log.PanicIf(err)
   316  
   317  	ti := NewTagIndex()
   318  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   319  
   320  	b := new(bytes.Buffer)
   321  	bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
   322  
   323  	addressableOffset := uint32(0x1234)
   324  	ida := newIfdDataAllocator(addressableOffset)
   325  
   326  	childIb := NewIfdBuilder(im, ti, exifcommon.IfdExifStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   327  	tagValue := NewIfdBuilderTagValueFromIfdBuilder(childIb)
   328  	bt := NewChildIfdBuilderTag(exifcommon.IfdStandardIfdIdentity.UnindexedString(), exifcommon.IfdExifStandardIfdIdentity.TagId(), tagValue)
   329  
   330  	nextIfdOffsetToWrite := uint32(0)
   331  	childIfdBlock, err := ibe.encodeTagToBytes(ib, bt, bw, ida, nextIfdOffsetToWrite)
   332  	log.PanicIf(err)
   333  
   334  	if childIfdBlock != nil {
   335  		t.Fatalf("no child-IFDs were expected to be allocated")
   336  	} else if bytes.Compare(b.Bytes(), []byte{0x87, 0x69, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}) != 0 {
   337  		t.Fatalf("encoded tag-entry with child-IFD not correct")
   338  	} else if ida.NextOffset() != addressableOffset {
   339  		t.Fatalf("allocation offset not expected")
   340  	}
   341  }
   342  
   343  func Test_IfdByteEncoder_encodeTagToBytes_childIfd__withAllocate(t *testing.T) {
   344  	defer func() {
   345  		if state := recover(); state != nil {
   346  			err := log.Wrap(state.(error))
   347  			log.PrintError(err)
   348  			t.Fatalf("Test failed.")
   349  		}
   350  	}()
   351  
   352  	// Create a child IFD (represented by an IB instance) that we can allocate
   353  	// space for and then attach to a tag (which would normally be an entry,
   354  	// then, in a higher IFD).
   355  
   356  	im, err := exifcommon.NewIfdMappingWithStandard()
   357  	log.PanicIf(err)
   358  
   359  	ti := NewTagIndex()
   360  	childIb := NewIfdBuilder(im, ti, exifcommon.IfdExifStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   361  
   362  	childIbTestTag := &BuilderTag{
   363  		ifdPath: exifcommon.IfdExifStandardIfdIdentity.UnindexedString(),
   364  		tagId:   0x8822,
   365  		typeId:  exifcommon.TypeShort,
   366  		value:   NewIfdBuilderTagValueFromBytes([]byte{0x12, 0x34}),
   367  	}
   368  
   369  	childIb.Add(childIbTestTag)
   370  
   371  	// Formally compose the tag that refers to it.
   372  
   373  	tagValue := NewIfdBuilderTagValueFromIfdBuilder(childIb)
   374  	bt := NewChildIfdBuilderTag(exifcommon.IfdStandardIfdIdentity.UnindexedString(), exifcommon.IfdExifStandardIfdIdentity.TagId(), tagValue)
   375  
   376  	// Encode the tag. Since we've actually provided an offset at which we can
   377  	// allocate data, the child-IFD will automatically be encoded, allocated,
   378  	// and installed into the allocated-data block (which will follow the IFD
   379  	// block/table in the file).
   380  
   381  	ibe := NewIfdByteEncoder()
   382  
   383  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   384  
   385  	b := new(bytes.Buffer)
   386  	bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
   387  
   388  	// addressableOffset is the offset of where large data can be allocated
   389  	// (which follows the IFD table/block). Large, in that it can't be stored
   390  	// in the table itself. Just used for arithmetic. This is just where the
   391  	// data for the current IFD can be written. It's not absolute for the EXIF
   392  	// data in general.
   393  	addressableOffset := uint32(0x1234)
   394  	ida := newIfdDataAllocator(addressableOffset)
   395  
   396  	// This is the offset of where the next IFD can be written in the EXIF byte
   397  	// stream. Just used for arithmetic.
   398  	nextIfdOffsetToWrite := uint32(2000)
   399  
   400  	childIfdBlock, err := ibe.encodeTagToBytes(ib, bt, bw, ida, nextIfdOffsetToWrite)
   401  	log.PanicIf(err)
   402  
   403  	if ida.NextOffset() != addressableOffset {
   404  		t.Fatalf("IDA offset changed but no allocations where expected: (0x%02x)", ida.NextOffset())
   405  	}
   406  
   407  	tagBytes := b.Bytes()
   408  
   409  	if len(tagBytes) != 12 {
   410  		t.Fatalf("Tag not encoded to the right number of bytes: (%d)", len(tagBytes))
   411  	} else if len(childIfdBlock) != 18 {
   412  		t.Fatalf("Child IFD is not the right size: (%d)", len(childIfdBlock))
   413  	}
   414  
   415  	iteV, err := parseOneTag(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder, tagBytes)
   416  	log.PanicIf(err)
   417  
   418  	if iteV.TagId() != exifcommon.IfdExifStandardIfdIdentity.TagId() {
   419  		t.Fatalf("IFD first tag-ID not correct: (0x%02x)", iteV.TagId())
   420  	} else if iteV.tagIndex != 0 {
   421  		t.Fatalf("IFD first tag index not correct: (%d)", iteV.tagIndex)
   422  	} else if iteV.TagType() != exifcommon.TypeLong {
   423  		t.Fatalf("IFD first tag type not correct: (%d)", iteV.TagType())
   424  	} else if iteV.UnitCount() != 1 {
   425  		t.Fatalf("IFD first tag unit-count not correct: (%d)", iteV.UnitCount())
   426  	} else if iteV.getValueOffset() != nextIfdOffsetToWrite {
   427  		t.Fatalf("IFD's child-IFD offset (as offset) is not correct: (%d) != (%d)", iteV.getValueOffset(), nextIfdOffsetToWrite)
   428  	} else if iteV.ChildIfdPath() != exifcommon.IfdExifStandardIfdIdentity.UnindexedString() {
   429  		t.Fatalf("IFD first tag IFD-name name not correct: [%s]", iteV.ChildIfdPath())
   430  	} else if iteV.IfdPath() != exifcommon.IfdStandardIfdIdentity.UnindexedString() {
   431  		t.Fatalf("IFD first tag parent IFD not correct: %v", iteV.IfdPath())
   432  	}
   433  
   434  	// Validate the child's raw IFD bytes.
   435  
   436  	childNextIfdOffset, childEntries, err := parseOneIfd(im, ti, exifcommon.IfdExifStandardIfdIdentity, exifcommon.TestDefaultByteOrder, childIfdBlock, nil)
   437  	log.PanicIf(err)
   438  
   439  	if childNextIfdOffset != uint32(0) {
   440  		t.Fatalf("Child IFD: Next IFD offset should be (0): (0x%08x)", childNextIfdOffset)
   441  	} else if len(childEntries) != 1 {
   442  		t.Fatalf("Child IFD: Expected exactly one entry: (%d)", len(childEntries))
   443  	}
   444  
   445  	ite := childEntries[0]
   446  
   447  	if ite.TagId() != 0x8822 {
   448  		t.Fatalf("Child IFD first tag-ID not correct: (0x%02x)", ite.TagId())
   449  	} else if ite.tagIndex != 0 {
   450  		t.Fatalf("Child IFD first tag index not correct: (%d)", ite.tagIndex)
   451  	} else if ite.TagType() != exifcommon.TypeShort {
   452  		t.Fatalf("Child IFD first tag type not correct: (%d)", ite.TagType())
   453  	} else if ite.UnitCount() != 1 {
   454  		t.Fatalf("Child IFD first tag unit-count not correct: (%d)", ite.UnitCount())
   455  	} else if ite.ChildIfdPath() != "" {
   456  		t.Fatalf("Child IFD first tag IFD-name name not empty: [%s]", ite.ChildIfdPath())
   457  	} else if ite.IfdPath() != exifcommon.IfdExifStandardIfdIdentity.UnindexedString() {
   458  		t.Fatalf("Child IFD first tag parent IFD not correct: %v", ite.IfdPath())
   459  	}
   460  }
   461  
   462  func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) {
   463  	defer func() {
   464  		if state := recover(); state != nil {
   465  			err := log.Wrap(state.(error))
   466  			log.PrintError(err)
   467  			t.Fatalf("Test failed.")
   468  		}
   469  	}()
   470  
   471  	// Encode the tag. Since we've actually provided an offset at which we can
   472  	// allocate data, the child-IFD will automatically be encoded, allocated,
   473  	// and installed into the allocated-data block (which will follow the IFD
   474  	// block/table in the file).
   475  
   476  	ibe := NewIfdByteEncoder()
   477  
   478  	im, err := exifcommon.NewIfdMappingWithStandard()
   479  	log.PanicIf(err)
   480  
   481  	ti := NewTagIndex()
   482  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   483  
   484  	it, err := ib.tagIndex.Get(ib.IfdIdentity(), uint16(0x000b))
   485  	log.PanicIf(err)
   486  
   487  	valueString := "testvalue"
   488  	bt := NewStandardBuilderTag(exifcommon.IfdStandardIfdIdentity.UnindexedString(), it, exifcommon.TestDefaultByteOrder, valueString)
   489  
   490  	b := new(bytes.Buffer)
   491  	bw := NewByteWriter(b, exifcommon.TestDefaultByteOrder)
   492  
   493  	// addressableOffset is the offset of where large data can be allocated
   494  	// (which follows the IFD table/block). Large, in that it can't be stored
   495  	// in the table itself. Just used for arithmetic. This is just where the
   496  	// data for the current IFD can be written. It's not absolute for the EXIF
   497  	// data in general.
   498  	addressableOffset := uint32(0x1234)
   499  	ida := newIfdDataAllocator(addressableOffset)
   500  
   501  	childIfdBlock, err := ibe.encodeTagToBytes(ib, bt, bw, ida, uint32(0))
   502  	log.PanicIf(err)
   503  
   504  	if ida.NextOffset() == addressableOffset {
   505  		t.Fatalf("IDA offset did not change even though there should've been an allocation.")
   506  	}
   507  
   508  	tagBytes := b.Bytes()
   509  
   510  	if len(tagBytes) != 12 {
   511  		t.Fatalf("Tag not encoded to the right number of bytes: (%d)", len(tagBytes))
   512  	} else if len(childIfdBlock) != 0 {
   513  		t.Fatalf("Child IFD not have been allocated.")
   514  	}
   515  
   516  	ite, err := parseOneTag(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder, tagBytes)
   517  	log.PanicIf(err)
   518  
   519  	if ite.TagId() != 0x000b {
   520  		t.Fatalf("Tag-ID not correct: (0x%02x)", ite.TagId())
   521  	} else if ite.tagIndex != 0 {
   522  		t.Fatalf("Tag index not correct: (%d)", ite.tagIndex)
   523  	} else if ite.TagType() != exifcommon.TypeAscii {
   524  		t.Fatalf("Tag type not correct: (%d)", ite.TagType())
   525  	} else if ite.UnitCount() != (uint32(len(valueString) + 1)) {
   526  		t.Fatalf("Tag unit-count not correct: (%d)", ite.UnitCount())
   527  	} else if ite.ChildIfdPath() != "" {
   528  		t.Fatalf("Tag's IFD-name should be empty: [%s]", ite.ChildIfdPath())
   529  	} else if ite.IfdPath() != exifcommon.IfdStandardIfdIdentity.UnindexedString() {
   530  		t.Fatalf("Tag's parent IFD is not correct: %v", ite.IfdPath())
   531  	}
   532  
   533  	expectedBuffer := bytes.NewBufferString(valueString)
   534  	expectedBuffer.Write([]byte{0x0})
   535  	expectedBytes := expectedBuffer.Bytes()
   536  
   537  	allocatedBytes := ida.Bytes()
   538  
   539  	if bytes.Compare(allocatedBytes, expectedBytes) != 0 {
   540  		t.Fatalf("Allocated bytes not correct: %v != %v", allocatedBytes, expectedBytes)
   541  	}
   542  }
   543  
   544  func Test_IfdByteEncoder_encodeIfdToBytes_simple(t *testing.T) {
   545  	ib := getExifSimpleTestIb()
   546  
   547  	// Write the byte stream.
   548  
   549  	ibe := NewIfdByteEncoder()
   550  
   551  	// addressableOffset is the offset of where large data can be allocated
   552  	// (which follows the IFD table/block). Large, in that it can't be stored
   553  	// in the table itself. Just used for arithmetic. This is just where the
   554  	// data for the current IFD can be written. It's not absolute for the EXIF
   555  	// data in general.
   556  	addressableOffset := uint32(0x1234)
   557  
   558  	tableAndAllocated, tableSize, allocatedDataSize, childIfdSizes, err := ibe.encodeIfdToBytes(ib, addressableOffset, uint32(0), false)
   559  	log.PanicIf(err)
   560  
   561  	expectedTableSize := ibe.TableSize(4)
   562  	if tableSize != expectedTableSize {
   563  		t.Fatalf("Table-size not the right size: (%d) != (%d)", tableSize, expectedTableSize)
   564  	} else if len(childIfdSizes) != 0 {
   565  		t.Fatalf("One or more child IFDs were allocated but shouldn't have been: (%d)", len(childIfdSizes))
   566  	}
   567  
   568  	// The ASCII value plus the rational size.
   569  	expectedAllocatedSize := 11 + 8
   570  
   571  	if int(allocatedDataSize) != expectedAllocatedSize {
   572  		t.Fatalf("Allocated data size not correct: (%d)", allocatedDataSize)
   573  	}
   574  
   575  	expectedIfdAndDataBytes := []byte{
   576  		// IFD table block.
   577  
   578  		// - Tag count
   579  		0x00, 0x04,
   580  
   581  		// - Tags
   582  		0x00, 0x0b, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x12, 0x34,
   583  		0x00, 0xff, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x11, 0x22, 0x00, 0x00,
   584  		0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x33, 0x44, 0x55, 0x66,
   585  		0x01, 0x3e, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x12, 0x3f,
   586  
   587  		// - Next IFD offset
   588  		0x00, 0x00, 0x00, 0x00,
   589  
   590  		// IFD data block.
   591  
   592  		// - The one ASCII value
   593  		0x61, 0x73, 0x63, 0x69, 0x69, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00,
   594  
   595  		// - The one rational value
   596  		0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x44, 0x44,
   597  	}
   598  
   599  	if bytes.Compare(tableAndAllocated, expectedIfdAndDataBytes) != 0 {
   600  		t.Fatalf("IFD table and allocated data not correct: %v", exifcommon.DumpBytesClauseToString(tableAndAllocated))
   601  	}
   602  }
   603  
   604  func Test_IfdByteEncoder_encodeIfdToBytes_fullExif(t *testing.T) {
   605  	defer func() {
   606  		if state := recover(); state != nil {
   607  			err := log.Wrap(state.(error))
   608  			log.PrintError(err)
   609  			t.Fatalf("Test failed.")
   610  		}
   611  	}()
   612  
   613  	ib := getExifSimpleTestIb()
   614  
   615  	// Encode the IFD to a byte stream.
   616  
   617  	ibe := NewIfdByteEncoder()
   618  
   619  	// Run a simulation just to figure out the sizes.
   620  	_, tableSize, allocatedDataSize, _, err := ibe.encodeIfdToBytes(ib, uint32(0), uint32(0), false)
   621  	log.PanicIf(err)
   622  
   623  	addressableOffset := ExifDefaultFirstIfdOffset + tableSize
   624  	nextIfdOffsetToWrite := addressableOffset + allocatedDataSize
   625  
   626  	// Run the final encode now that we can correctly assign the offsets.
   627  	tableAndAllocated, _, _, _, err := ibe.encodeIfdToBytes(ib, addressableOffset, uint32(nextIfdOffsetToWrite), false)
   628  	log.PanicIf(err)
   629  
   630  	if len(tableAndAllocated) != (int(tableSize) + int(allocatedDataSize)) {
   631  		t.Fatalf("Table-and-data size doesn't match what was expected: (%d) != (%d + %d)", len(tableAndAllocated), tableSize, allocatedDataSize)
   632  	}
   633  
   634  	// Wrap the IFD in a formal EXIF block.
   635  
   636  	b := new(bytes.Buffer)
   637  
   638  	headerBytes, err := BuildExifHeader(exifcommon.TestDefaultByteOrder, ExifDefaultFirstIfdOffset)
   639  	log.PanicIf(err)
   640  
   641  	_, err = b.Write(headerBytes)
   642  	log.PanicIf(err)
   643  
   644  	_, err = b.Write(tableAndAllocated)
   645  	log.PanicIf(err)
   646  
   647  	// Now, try parsing it as EXIF data, making sure to resolve (read:
   648  	// dereference) the values (which will include the allocated ones).
   649  
   650  	exifData := b.Bytes()
   651  	validateExifSimpleTestIb(exifData, t)
   652  }
   653  
   654  func Test_IfdByteEncoder_EncodeToExifPayload(t *testing.T) {
   655  	defer func() {
   656  		if state := recover(); state != nil {
   657  			err := log.Wrap(state.(error))
   658  			log.PrintError(err)
   659  			t.Fatalf("Test failed.")
   660  		}
   661  	}()
   662  
   663  	ib := getExifSimpleTestIb()
   664  
   665  	// Encode the IFD to a byte stream.
   666  
   667  	ibe := NewIfdByteEncoder()
   668  
   669  	encodedIfds, err := ibe.EncodeToExifPayload(ib)
   670  	log.PanicIf(err)
   671  
   672  	// Wrap the IFD in a formal EXIF block.
   673  
   674  	b := new(bytes.Buffer)
   675  
   676  	headerBytes, err := BuildExifHeader(exifcommon.TestDefaultByteOrder, ExifDefaultFirstIfdOffset)
   677  	log.PanicIf(err)
   678  
   679  	_, err = b.Write(headerBytes)
   680  	log.PanicIf(err)
   681  
   682  	_, err = b.Write(encodedIfds)
   683  	log.PanicIf(err)
   684  
   685  	// Now, try parsing it as EXIF data, making sure to resolve (read:
   686  	// dereference) the values (which will include the allocated ones).
   687  
   688  	exifData := b.Bytes()
   689  	validateExifSimpleTestIb(exifData, t)
   690  }
   691  
   692  func Test_IfdByteEncoder_EncodeToExif(t *testing.T) {
   693  	ib := getExifSimpleTestIb()
   694  
   695  	// TODO(dustin): Do a child-IFD allocation in addition to the tag allocations.
   696  
   697  	ibe := NewIfdByteEncoder()
   698  
   699  	exifData, err := ibe.EncodeToExif(ib)
   700  	log.PanicIf(err)
   701  
   702  	validateExifSimpleTestIb(exifData, t)
   703  }
   704  
   705  func Test_IfdByteEncoder_EncodeToExif_WithChildAndSibling(t *testing.T) {
   706  	defer func() {
   707  		if state := recover(); state != nil {
   708  			err := log.Wrap(state.(error))
   709  			log.PrintError(err)
   710  			t.Fatalf("Test failed.")
   711  		}
   712  	}()
   713  
   714  	im, err := exifcommon.NewIfdMappingWithStandard()
   715  	log.PanicIf(err)
   716  
   717  	ti := NewTagIndex()
   718  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   719  
   720  	err = ib.AddStandard(0x000b, "asciivalue")
   721  	log.PanicIf(err)
   722  
   723  	err = ib.AddStandard(0x00ff, []uint16{0x1122})
   724  	log.PanicIf(err)
   725  
   726  	// Add a child IB right in the middle.
   727  
   728  	childIb := NewIfdBuilder(im, ti, exifcommon.IfdExifStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   729  
   730  	err = childIb.AddStandardWithName("ISOSpeedRatings", []uint16{0x1122})
   731  	log.PanicIf(err)
   732  
   733  	err = childIb.AddStandardWithName("ISOSpeed", []uint32{0x33445566})
   734  	log.PanicIf(err)
   735  
   736  	err = ib.AddChildIb(childIb)
   737  	log.PanicIf(err)
   738  
   739  	err = ib.AddStandard(0x0100, []uint32{0x33445566})
   740  	log.PanicIf(err)
   741  
   742  	// Add another child IB, just to ensure a little more punishment and make
   743  	// sure we're managing our allocation offsets correctly.
   744  
   745  	childIb2 := NewIfdBuilder(im, ti, exifcommon.IfdGpsInfoStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   746  
   747  	err = childIb2.AddStandardWithName("GPSAltitudeRef", []uint8{0x11, 0x22})
   748  	log.PanicIf(err)
   749  
   750  	err = ib.AddChildIb(childIb2)
   751  	log.PanicIf(err)
   752  
   753  	err = ib.AddStandard(0x013e, []exifcommon.Rational{{Numerator: 0x11112222, Denominator: 0x33334444}})
   754  	log.PanicIf(err)
   755  
   756  	// Link to another IB (sibling relationship). The root/standard IFD may
   757  	// occur twice in some JPEGs (for thumbnail or FlashPix images).
   758  
   759  	nextIb := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   760  
   761  	err = nextIb.AddStandard(0x0101, []uint32{0x11223344})
   762  	log.PanicIf(err)
   763  
   764  	err = nextIb.AddStandard(0x0102, []uint16{0x5566})
   765  	log.PanicIf(err)
   766  
   767  	ib.SetNextIb(nextIb)
   768  
   769  	// Encode.
   770  
   771  	ibe := NewIfdByteEncoder()
   772  
   773  	exifData, err := ibe.EncodeToExif(ib)
   774  	log.PanicIf(err)
   775  
   776  	// Parse.
   777  
   778  	_, index, err := Collect(im, ti, exifData)
   779  	log.PanicIf(err)
   780  
   781  	tagsDump := index.RootIfd.DumpTree()
   782  
   783  	actual := strings.Join(tagsDump, "\n")
   784  
   785  	expected :=
   786  		`> IFD [ROOT]->[IFD]:(0) TOP
   787    - (0x000b)
   788    - (0x00ff)
   789    - (0x8769)
   790    > IFD [IFD]->[IFD/Exif]:(0) TOP
   791      - (0x8827)
   792      - (0x8833)
   793    < IFD [IFD]->[IFD/Exif]:(0) BOTTOM
   794    - (0x0100)
   795    - (0x8825)
   796    > IFD [IFD]->[IFD/GPSInfo]:(0) TOP
   797      - (0x0005)
   798    < IFD [IFD]->[IFD/GPSInfo]:(0) BOTTOM
   799    - (0x013e)
   800  < IFD [ROOT]->[IFD]:(0) BOTTOM
   801  * LINKING TO SIBLING IFD [IFD]:(1)
   802  > IFD [ROOT]->[IFD]:(1) TOP
   803    - (0x0101)
   804    - (0x0102)
   805  < IFD [ROOT]->[IFD]:(1) BOTTOM`
   806  
   807  	if actual != expected {
   808  		fmt.Printf("\n")
   809  
   810  		fmt.Printf("Actual:\n")
   811  		fmt.Printf("\n")
   812  		fmt.Printf("%s\n", actual)
   813  		fmt.Printf("\n")
   814  
   815  		fmt.Printf("Expected:\n")
   816  		fmt.Printf("\n")
   817  		fmt.Printf("%s\n", expected)
   818  		fmt.Printf("\n")
   819  
   820  		t.Fatalf("IFD hierarchy not correct.")
   821  	}
   822  }
   823  
   824  func ExampleIfdByteEncoder_EncodeToExif() {
   825  	// Construct an IFD.
   826  
   827  	im, err := exifcommon.NewIfdMappingWithStandard()
   828  	log.PanicIf(err)
   829  
   830  	ti := NewTagIndex()
   831  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   832  
   833  	err = ib.AddStandardWithName("ProcessingSoftware", "asciivalue")
   834  	log.PanicIf(err)
   835  
   836  	err = ib.AddStandardWithName("DotRange", []uint8{0x11})
   837  	log.PanicIf(err)
   838  
   839  	err = ib.AddStandardWithName("SubfileType", []uint16{0x2233})
   840  	log.PanicIf(err)
   841  
   842  	err = ib.AddStandardWithName("ImageWidth", []uint32{0x44556677})
   843  	log.PanicIf(err)
   844  
   845  	err = ib.AddStandardWithName("WhitePoint", []exifcommon.Rational{{Numerator: 0x11112222, Denominator: 0x33334444}})
   846  	log.PanicIf(err)
   847  
   848  	err = ib.AddStandardWithName("ShutterSpeedValue", []exifcommon.SignedRational{{Numerator: 0x11112222, Denominator: 0x33334444}})
   849  	log.PanicIf(err)
   850  
   851  	// Encode it.
   852  
   853  	ibe := NewIfdByteEncoder()
   854  
   855  	exifData, err := ibe.EncodeToExif(ib)
   856  	log.PanicIf(err)
   857  
   858  	// Parse it so we can see it.
   859  
   860  	_, index, err := Collect(im, ti, exifData)
   861  	log.PanicIf(err)
   862  
   863  	for i, ite := range index.RootIfd.Entries() {
   864  		value, err := ite.Value()
   865  		log.PanicIf(err)
   866  
   867  		fmt.Printf("%d: %s [%v]\n", i, ite, value)
   868  	}
   869  
   870  	// Output:
   871  	//
   872  	// 0: IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x000b) TAG-TYPE=[ASCII] UNIT-COUNT=(11)> [asciivalue]
   873  	// 1: IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x0150) TAG-TYPE=[BYTE] UNIT-COUNT=(1)> [[17]]
   874  	// 2: IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x00ff) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> [[8755]]
   875  	// 3: IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x0100) TAG-TYPE=[LONG] UNIT-COUNT=(1)> [[1146447479]]
   876  	// 4: IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x013e) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> [[{286335522 858997828}]]
   877  	// 5: IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x9201) TAG-TYPE=[SRATIONAL] UNIT-COUNT=(1)> [[{286335522 858997828}]]
   878  }
   879  

View as plain text