...

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

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

     1  package exif
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"reflect"
     7  	"sort"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/dsoprea/go-exif/v3/common"
    13  	"github.com/dsoprea/go-exif/v3/undefined"
    14  	"github.com/dsoprea/go-logging"
    15  )
    16  
    17  func TestIfdBuilder_Add(t *testing.T) {
    18  	im, err := exifcommon.NewIfdMappingWithStandard()
    19  	log.PanicIf(err)
    20  
    21  	ti := NewTagIndex()
    22  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
    23  
    24  	bt := &BuilderTag{
    25  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
    26  		typeId:  exifcommon.TypeByte,
    27  		tagId:   0x11,
    28  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
    29  	}
    30  
    31  	err = ib.Add(bt)
    32  	log.PanicIf(err)
    33  
    34  	bt = &BuilderTag{
    35  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
    36  		typeId:  exifcommon.TypeByte,
    37  		tagId:   0x22,
    38  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string2")),
    39  	}
    40  
    41  	err = ib.Add(bt)
    42  	log.PanicIf(err)
    43  
    44  	bt = &BuilderTag{
    45  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
    46  		typeId:  exifcommon.TypeByte,
    47  		tagId:   0x33,
    48  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string3")),
    49  	}
    50  
    51  	err = ib.Add(bt)
    52  	log.PanicIf(err)
    53  
    54  	originalBytes := []byte{0x11, 0x22, 0x33}
    55  
    56  	bt = &BuilderTag{
    57  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
    58  		typeId:  exifcommon.TypeByte,
    59  		tagId:   0x44,
    60  		value:   NewIfdBuilderTagValueFromBytes([]byte(originalBytes)),
    61  	}
    62  
    63  	err = ib.Add(bt)
    64  	log.PanicIf(err)
    65  
    66  	if ib.ifdIdentity.UnindexedString() != exifcommon.IfdStandardIfdIdentity.UnindexedString() {
    67  		t.Fatalf("IFD name not correct.")
    68  	} else if ib.IfdIdentity().TagId() != 0 {
    69  		t.Fatalf("IFD tag-ID not correct.")
    70  	} else if ib.byteOrder != exifcommon.TestDefaultByteOrder {
    71  		t.Fatalf("IFD byte-order not correct.")
    72  	} else if len(ib.tags) != 4 {
    73  		t.Fatalf("IFD tag-count not correct.")
    74  	} else if ib.existingOffset != 0 {
    75  		t.Fatalf("IFD offset not correct.")
    76  	} else if ib.nextIb != nil {
    77  		t.Fatalf("Next-IFD not correct.")
    78  	}
    79  
    80  	tags := ib.Tags()
    81  
    82  	if tags[0].tagId != 0x11 {
    83  		t.Fatalf("tag (0) tag-ID not correct")
    84  	} else if bytes.Compare(tags[0].value.Bytes(), []byte("test string")) != 0 {
    85  		t.Fatalf("tag (0) value not correct")
    86  	}
    87  
    88  	if tags[1].tagId != 0x22 {
    89  		t.Fatalf("tag (1) tag-ID not correct")
    90  	} else if bytes.Compare(tags[1].value.Bytes(), []byte("test string2")) != 0 {
    91  		t.Fatalf("tag (1) value not correct")
    92  	}
    93  
    94  	if tags[2].tagId != 0x33 {
    95  		t.Fatalf("tag (2) tag-ID not correct")
    96  	} else if bytes.Compare(tags[2].value.Bytes(), []byte("test string3")) != 0 {
    97  		t.Fatalf("tag (2) value not correct")
    98  	}
    99  
   100  	if tags[3].tagId != 0x44 {
   101  		t.Fatalf("tag (3) tag-ID not correct")
   102  	} else if bytes.Compare(tags[3].value.Bytes(), originalBytes) != 0 {
   103  		t.Fatalf("tag (3) value not correct")
   104  	}
   105  }
   106  
   107  func TestIfdBuilder_SetNextIb(t *testing.T) {
   108  	im, err := exifcommon.NewIfdMappingWithStandard()
   109  	log.PanicIf(err)
   110  
   111  	ti := NewTagIndex()
   112  
   113  	ib1 := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   114  	ib2 := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   115  
   116  	if ib1.nextIb != nil {
   117  		t.Fatalf("Next-IFD for IB1 not initially terminal.")
   118  	}
   119  
   120  	err = ib1.SetNextIb(ib2)
   121  	log.PanicIf(err)
   122  
   123  	if ib1.nextIb != ib2 {
   124  		t.Fatalf("Next-IFD for IB1 not correct.")
   125  	} else if ib2.nextIb != nil {
   126  		t.Fatalf("Next-IFD for IB2 terminal.")
   127  	}
   128  }
   129  
   130  func TestIfdBuilder_AddChildIb(t *testing.T) {
   131  	im, err := exifcommon.NewIfdMappingWithStandard()
   132  	log.PanicIf(err)
   133  
   134  	ti := NewTagIndex()
   135  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   136  
   137  	bt := &BuilderTag{
   138  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   139  		typeId:  exifcommon.TypeByte,
   140  		tagId:   0x11,
   141  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
   142  	}
   143  
   144  	err = ib.Add(bt)
   145  	log.PanicIf(err)
   146  
   147  	ibChild := NewIfdBuilder(im, ti, exifcommon.IfdExifStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   148  	err = ib.AddChildIb(ibChild)
   149  	log.PanicIf(err)
   150  
   151  	bt = &BuilderTag{
   152  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   153  		typeId:  exifcommon.TypeByte,
   154  		tagId:   0x22,
   155  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
   156  	}
   157  
   158  	err = ib.Add(bt)
   159  	log.PanicIf(err)
   160  
   161  	if ib.tags[0].tagId != 0x11 {
   162  		t.Fatalf("first tag not correct")
   163  	} else if ib.tags[1].tagId != ibChild.IfdIdentity().TagId() {
   164  		t.Fatalf("second tag ID does not match child-IFD tag-ID: (0x%04x) != (0x%04x)", ib.tags[1].tagId, ibChild.IfdIdentity().TagId())
   165  	} else if ib.tags[1].value.Ib() != ibChild {
   166  		t.Fatalf("second tagvalue does not match child-IFD")
   167  	} else if ib.tags[2].tagId != 0x22 {
   168  		t.Fatalf("third tag not correct")
   169  	}
   170  }
   171  
   172  func TestIfdBuilder_AddTagsFromExisting(t *testing.T) {
   173  	defer func() {
   174  		if state := recover(); state != nil {
   175  			err := log.Wrap(state.(error))
   176  			log.PrintError(err)
   177  
   178  			t.Fatalf("Test failure.")
   179  		}
   180  	}()
   181  
   182  	exifData := getExifSimpleTestIbBytes()
   183  
   184  	im, err := exifcommon.NewIfdMappingWithStandard()
   185  	log.PanicIf(err)
   186  
   187  	ti := NewTagIndex()
   188  
   189  	_, index, err := Collect(im, ti, exifData)
   190  	log.PanicIf(err)
   191  
   192  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   193  
   194  	err = ib.AddTagsFromExisting(index.RootIfd, nil, nil)
   195  	log.PanicIf(err)
   196  
   197  	expected := []uint16{
   198  		0x000b,
   199  		0x00ff,
   200  		0x0100,
   201  		0x013e,
   202  	}
   203  
   204  	if len(ib.tags) != len(expected) {
   205  		t.Fatalf("Tag count not correct: (%d) != (%d)", len(ib.tags), len(expected))
   206  	}
   207  
   208  	for i, tag := range ib.tags {
   209  		if tag.tagId != expected[i] {
   210  			t.Fatalf("Tag (%d) not correct: (0x%04x) != (0x%04x)", i, tag.tagId, expected[i])
   211  		}
   212  	}
   213  }
   214  
   215  func TestIfdBuilder_AddTagsFromExisting__Includes(t *testing.T) {
   216  	exifData := getExifSimpleTestIbBytes()
   217  
   218  	im, err := exifcommon.NewIfdMappingWithStandard()
   219  	log.PanicIf(err)
   220  
   221  	ti := NewTagIndex()
   222  
   223  	_, index, err := Collect(im, ti, exifData)
   224  	log.PanicIf(err)
   225  
   226  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   227  
   228  	err = ib.AddTagsFromExisting(index.RootIfd, []uint16{0x00ff}, nil)
   229  	log.PanicIf(err)
   230  
   231  	expected := []uint16{
   232  		0x00ff,
   233  	}
   234  
   235  	if len(ib.tags) != len(expected) {
   236  		t.Fatalf("Tag count not correct: (%d) != (%d)", len(ib.tags), len(expected))
   237  	}
   238  
   239  	for i, tag := range ib.tags {
   240  		if tag.tagId != expected[i] {
   241  			t.Fatalf("Tag (%d) not correct: (0x%04x) != (0x%04x)", i, tag.tagId, expected[i])
   242  		}
   243  	}
   244  }
   245  
   246  func TestIfdBuilder_AddTagsFromExisting__Excludes(t *testing.T) {
   247  	exifData := getExifSimpleTestIbBytes()
   248  
   249  	im, err := exifcommon.NewIfdMappingWithStandard()
   250  	log.PanicIf(err)
   251  
   252  	ti := NewTagIndex()
   253  
   254  	_, index, err := Collect(im, ti, exifData)
   255  	log.PanicIf(err)
   256  
   257  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   258  
   259  	err = ib.AddTagsFromExisting(index.RootIfd, nil, []uint16{0xff})
   260  	log.PanicIf(err)
   261  
   262  	expected := []uint16{
   263  		0x000b,
   264  		0x0100,
   265  		0x013e,
   266  	}
   267  
   268  	if len(ib.tags) != len(expected) {
   269  		t.Fatalf("Tag count not correct: (%d) != (%d)", len(ib.tags), len(expected))
   270  	}
   271  
   272  	for i, tag := range ib.tags {
   273  		if tag.tagId != expected[i] {
   274  			t.Fatalf("Tag (%d) not correct: (0x%04x) != (0x%04x)", i, tag.tagId, expected[i])
   275  		}
   276  	}
   277  }
   278  
   279  func TestIfdBuilder_FindN__First_1(t *testing.T) {
   280  	im, err := exifcommon.NewIfdMappingWithStandard()
   281  	log.PanicIf(err)
   282  
   283  	ti := NewTagIndex()
   284  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   285  
   286  	bt := &BuilderTag{
   287  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   288  		typeId:  exifcommon.TypeByte,
   289  		tagId:   0x11,
   290  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
   291  	}
   292  
   293  	err = ib.Add(bt)
   294  	log.PanicIf(err)
   295  
   296  	bt = &BuilderTag{
   297  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   298  		typeId:  exifcommon.TypeByte,
   299  		tagId:   0x22,
   300  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string2")),
   301  	}
   302  
   303  	err = ib.Add(bt)
   304  	log.PanicIf(err)
   305  
   306  	bt = &BuilderTag{
   307  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   308  		typeId:  exifcommon.TypeByte,
   309  		tagId:   0x33,
   310  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string3")),
   311  	}
   312  
   313  	err = ib.Add(bt)
   314  	log.PanicIf(err)
   315  
   316  	found, err := ib.FindN(0x11, 1)
   317  	log.PanicIf(err)
   318  
   319  	if len(found) != 1 {
   320  		log.Panicf("Exactly one result was not found: (%d)", len(found))
   321  	} else if found[0] != 0 {
   322  		log.Panicf("Result was not in the right place: (%d)", found[0])
   323  	}
   324  
   325  	tags := ib.Tags()
   326  	bt = tags[found[0]]
   327  
   328  	if bt.tagId != 0x11 {
   329  		log.Panicf("Found entry is not correct: (0x%04x)", bt.tagId)
   330  	}
   331  }
   332  
   333  func TestIfdBuilder_FindN__First_2_1Returned(t *testing.T) {
   334  	im, err := exifcommon.NewIfdMappingWithStandard()
   335  	log.PanicIf(err)
   336  
   337  	ti := NewTagIndex()
   338  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   339  
   340  	bt := &BuilderTag{
   341  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   342  		typeId:  exifcommon.TypeByte,
   343  		tagId:   0x11,
   344  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
   345  	}
   346  
   347  	err = ib.Add(bt)
   348  	log.PanicIf(err)
   349  
   350  	bt = &BuilderTag{
   351  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   352  		typeId:  exifcommon.TypeByte,
   353  		tagId:   0x22,
   354  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string2")),
   355  	}
   356  
   357  	err = ib.Add(bt)
   358  	log.PanicIf(err)
   359  
   360  	bt = &BuilderTag{
   361  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   362  		typeId:  exifcommon.TypeByte,
   363  		tagId:   0x33,
   364  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string3")),
   365  	}
   366  
   367  	err = ib.Add(bt)
   368  	log.PanicIf(err)
   369  
   370  	found, err := ib.FindN(0x11, 2)
   371  	log.PanicIf(err)
   372  
   373  	if len(found) != 1 {
   374  		log.Panicf("Exactly one result was not found: (%d)", len(found))
   375  	} else if found[0] != 0 {
   376  		log.Panicf("Result was not in the right place: (%d)", found[0])
   377  	}
   378  
   379  	tags := ib.Tags()
   380  	bt = tags[found[0]]
   381  
   382  	if bt.tagId != 0x11 {
   383  		log.Panicf("Found entry is not correct: (0x%04x)", bt.tagId)
   384  	}
   385  }
   386  
   387  func TestIfdBuilder_FindN__First_2_2Returned(t *testing.T) {
   388  	im, err := exifcommon.NewIfdMappingWithStandard()
   389  	log.PanicIf(err)
   390  
   391  	ti := NewTagIndex()
   392  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   393  
   394  	bt := &BuilderTag{
   395  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   396  		typeId:  exifcommon.TypeByte,
   397  		tagId:   0x11,
   398  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
   399  	}
   400  
   401  	err = ib.Add(bt)
   402  	log.PanicIf(err)
   403  
   404  	bt = &BuilderTag{
   405  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   406  		typeId:  exifcommon.TypeByte,
   407  		tagId:   0x22,
   408  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string2")),
   409  	}
   410  
   411  	err = ib.Add(bt)
   412  	log.PanicIf(err)
   413  
   414  	bt = &BuilderTag{
   415  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   416  		typeId:  exifcommon.TypeByte,
   417  		tagId:   0x33,
   418  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string3")),
   419  	}
   420  
   421  	err = ib.Add(bt)
   422  	log.PanicIf(err)
   423  
   424  	bt = &BuilderTag{
   425  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   426  		typeId:  exifcommon.TypeByte,
   427  		tagId:   0x11,
   428  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string4")),
   429  	}
   430  
   431  	err = ib.Add(bt)
   432  	log.PanicIf(err)
   433  
   434  	bt = &BuilderTag{
   435  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   436  		typeId:  exifcommon.TypeByte,
   437  		tagId:   0x11,
   438  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string5")),
   439  	}
   440  
   441  	err = ib.Add(bt)
   442  	log.PanicIf(err)
   443  
   444  	found, err := ib.FindN(0x11, 2)
   445  	log.PanicIf(err)
   446  
   447  	if len(found) != 2 {
   448  		log.Panicf("Exactly one result was not found: (%d)", len(found))
   449  	} else if found[0] != 0 {
   450  		log.Panicf("First result was not in the right place: (%d)", found[0])
   451  	} else if found[1] != 3 {
   452  		log.Panicf("Second result was not in the right place: (%d)", found[1])
   453  	}
   454  
   455  	tags := ib.Tags()
   456  
   457  	bt = tags[found[0]]
   458  	if bt.tagId != 0x11 || bytes.Compare(bt.value.Bytes(), []byte("test string")) != 0 {
   459  		log.Panicf("Found entry 0 is not correct: (0x%04x) [%s]", bt.tagId, bt.value)
   460  	}
   461  
   462  	bt = tags[found[1]]
   463  	if bt.tagId != 0x11 || bytes.Compare(bt.value.Bytes(), []byte("test string4")) != 0 {
   464  		log.Panicf("Found entry 1 is not correct: (0x%04x) [%s]", bt.tagId, bt.value)
   465  	}
   466  }
   467  
   468  func TestIfdBuilder_FindN__Middle_WithDuplicates(t *testing.T) {
   469  	im, err := exifcommon.NewIfdMappingWithStandard()
   470  	log.PanicIf(err)
   471  
   472  	ti := NewTagIndex()
   473  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   474  
   475  	bt := &BuilderTag{
   476  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   477  		typeId:  exifcommon.TypeByte,
   478  		tagId:   0x11,
   479  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
   480  	}
   481  
   482  	err = ib.Add(bt)
   483  	log.PanicIf(err)
   484  
   485  	bt = &BuilderTag{
   486  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   487  		typeId:  exifcommon.TypeByte,
   488  		tagId:   0x22,
   489  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string2")),
   490  	}
   491  
   492  	err = ib.Add(bt)
   493  	log.PanicIf(err)
   494  
   495  	bt = &BuilderTag{
   496  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   497  		typeId:  exifcommon.TypeByte,
   498  		tagId:   0x33,
   499  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string3")),
   500  	}
   501  
   502  	err = ib.Add(bt)
   503  	log.PanicIf(err)
   504  
   505  	bt = &BuilderTag{
   506  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   507  		typeId:  exifcommon.TypeByte,
   508  		tagId:   0x11,
   509  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string4")),
   510  	}
   511  
   512  	err = ib.Add(bt)
   513  	log.PanicIf(err)
   514  
   515  	bt = &BuilderTag{
   516  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   517  		typeId:  exifcommon.TypeByte,
   518  		tagId:   0x11,
   519  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string5")),
   520  	}
   521  
   522  	err = ib.Add(bt)
   523  	log.PanicIf(err)
   524  
   525  	bt = &BuilderTag{
   526  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   527  		typeId:  exifcommon.TypeByte,
   528  		tagId:   0x33,
   529  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string6")),
   530  	}
   531  
   532  	err = ib.Add(bt)
   533  	log.PanicIf(err)
   534  
   535  	found, err := ib.FindN(0x33, 1)
   536  	log.PanicIf(err)
   537  
   538  	if len(found) != 1 {
   539  		log.Panicf("Exactly one result was not found: (%d)", len(found))
   540  	} else if found[0] != 2 {
   541  		log.Panicf("Result was not in the right place: (%d)", found[0])
   542  	}
   543  
   544  	tags := ib.Tags()
   545  	bt = tags[found[0]]
   546  
   547  	if bt.tagId != 0x33 {
   548  		log.Panicf("Found entry is not correct: (0x%04x)", bt.tagId)
   549  	}
   550  }
   551  
   552  func TestIfdBuilder_FindN__Middle_NoDuplicates(t *testing.T) {
   553  	im, err := exifcommon.NewIfdMappingWithStandard()
   554  	log.PanicIf(err)
   555  
   556  	ti := NewTagIndex()
   557  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   558  
   559  	bt := &BuilderTag{
   560  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   561  		typeId:  exifcommon.TypeByte,
   562  		tagId:   0x11,
   563  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
   564  	}
   565  
   566  	err = ib.Add(bt)
   567  	log.PanicIf(err)
   568  
   569  	bt = &BuilderTag{
   570  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   571  		typeId:  exifcommon.TypeByte,
   572  		tagId:   0x22,
   573  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string2")),
   574  	}
   575  
   576  	err = ib.Add(bt)
   577  	log.PanicIf(err)
   578  
   579  	bt = &BuilderTag{
   580  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   581  		typeId:  exifcommon.TypeByte,
   582  		tagId:   0x33,
   583  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string3")),
   584  	}
   585  
   586  	err = ib.Add(bt)
   587  	log.PanicIf(err)
   588  
   589  	bt = &BuilderTag{
   590  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   591  		typeId:  exifcommon.TypeByte,
   592  		tagId:   0x11,
   593  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string4")),
   594  	}
   595  
   596  	err = ib.Add(bt)
   597  	log.PanicIf(err)
   598  
   599  	found, err := ib.FindN(0x33, 1)
   600  	log.PanicIf(err)
   601  
   602  	if len(found) != 1 {
   603  		log.Panicf("Exactly one result was not found: (%d)", len(found))
   604  	} else if found[0] != 2 {
   605  		log.Panicf("Result was not in the right place: (%d)", found[0])
   606  	}
   607  
   608  	tags := ib.Tags()
   609  	bt = tags[found[0]]
   610  
   611  	if bt.tagId != 0x33 {
   612  		log.Panicf("Found entry is not correct: (0x%04x)", bt.tagId)
   613  	}
   614  }
   615  
   616  func TestIfdBuilder_FindN__Miss(t *testing.T) {
   617  	im, err := exifcommon.NewIfdMappingWithStandard()
   618  	log.PanicIf(err)
   619  
   620  	ti := NewTagIndex()
   621  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   622  
   623  	found, err := ib.FindN(0x11, 1)
   624  	log.PanicIf(err)
   625  
   626  	if len(found) != 0 {
   627  		t.Fatalf("Expected empty results.")
   628  	}
   629  }
   630  
   631  func TestIfdBuilder_Find__Hit(t *testing.T) {
   632  	im, err := exifcommon.NewIfdMappingWithStandard()
   633  	log.PanicIf(err)
   634  
   635  	ti := NewTagIndex()
   636  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   637  
   638  	bt := &BuilderTag{
   639  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   640  		typeId:  exifcommon.TypeByte,
   641  		tagId:   0x11,
   642  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
   643  	}
   644  
   645  	err = ib.Add(bt)
   646  	log.PanicIf(err)
   647  
   648  	bt = &BuilderTag{
   649  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   650  		typeId:  exifcommon.TypeByte,
   651  		tagId:   0x22,
   652  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string2")),
   653  	}
   654  
   655  	err = ib.Add(bt)
   656  	log.PanicIf(err)
   657  
   658  	bt = &BuilderTag{
   659  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   660  		typeId:  exifcommon.TypeByte,
   661  		tagId:   0x33,
   662  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string3")),
   663  	}
   664  
   665  	err = ib.Add(bt)
   666  	log.PanicIf(err)
   667  
   668  	bt = &BuilderTag{
   669  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   670  		typeId:  exifcommon.TypeByte,
   671  		tagId:   0x11,
   672  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string4")),
   673  	}
   674  
   675  	err = ib.Add(bt)
   676  	log.PanicIf(err)
   677  
   678  	position, err := ib.Find(0x33)
   679  	log.PanicIf(err)
   680  
   681  	if position != 2 {
   682  		log.Panicf("Result was not in the right place: (%d)", position)
   683  	}
   684  
   685  	tags := ib.Tags()
   686  	bt = tags[position]
   687  
   688  	if bt.tagId != 0x33 {
   689  		log.Panicf("Found entry is not correct: (0x%04x)", bt.tagId)
   690  	}
   691  }
   692  
   693  func TestIfdBuilder_Find__Miss(t *testing.T) {
   694  	im, err := exifcommon.NewIfdMappingWithStandard()
   695  	log.PanicIf(err)
   696  
   697  	ti := NewTagIndex()
   698  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   699  
   700  	bt := &BuilderTag{
   701  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   702  		typeId:  exifcommon.TypeByte,
   703  		tagId:   0x11,
   704  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
   705  	}
   706  
   707  	err = ib.Add(bt)
   708  	log.PanicIf(err)
   709  
   710  	bt = &BuilderTag{
   711  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   712  		typeId:  exifcommon.TypeByte,
   713  		tagId:   0x22,
   714  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string2")),
   715  	}
   716  
   717  	err = ib.Add(bt)
   718  	log.PanicIf(err)
   719  
   720  	bt = &BuilderTag{
   721  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   722  		typeId:  exifcommon.TypeByte,
   723  		tagId:   0x33,
   724  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string3")),
   725  	}
   726  
   727  	err = ib.Add(bt)
   728  	log.PanicIf(err)
   729  
   730  	bt = &BuilderTag{
   731  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   732  		typeId:  exifcommon.TypeByte,
   733  		tagId:   0x11,
   734  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string4")),
   735  	}
   736  
   737  	err = ib.Add(bt)
   738  	log.PanicIf(err)
   739  
   740  	_, err = ib.Find(0x99)
   741  	if err == nil {
   742  		t.Fatalf("Expected an error.")
   743  	} else if log.Is(err, ErrTagEntryNotFound) == false {
   744  		log.Panic(err)
   745  	}
   746  }
   747  
   748  func TestIfdBuilder_Replace(t *testing.T) {
   749  	im, err := exifcommon.NewIfdMappingWithStandard()
   750  	log.PanicIf(err)
   751  
   752  	ti := NewTagIndex()
   753  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   754  
   755  	bt := &BuilderTag{
   756  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   757  		typeId:  exifcommon.TypeByte,
   758  		tagId:   0x11,
   759  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
   760  	}
   761  
   762  	err = ib.Add(bt)
   763  	log.PanicIf(err)
   764  
   765  	bt = &BuilderTag{
   766  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   767  		typeId:  exifcommon.TypeByte,
   768  		tagId:   0x22,
   769  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string2")),
   770  	}
   771  
   772  	err = ib.Add(bt)
   773  	log.PanicIf(err)
   774  
   775  	bt = &BuilderTag{
   776  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   777  		typeId:  exifcommon.TypeByte,
   778  		tagId:   0x33,
   779  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string3")),
   780  	}
   781  
   782  	err = ib.Add(bt)
   783  	log.PanicIf(err)
   784  
   785  	currentIds := make([]uint16, 3)
   786  	for i, bt := range ib.Tags() {
   787  		currentIds[i] = bt.tagId
   788  	}
   789  
   790  	if reflect.DeepEqual([]uint16{0x11, 0x22, 0x33}, currentIds) == false {
   791  		t.Fatalf("Pre-replace tags are not correct.")
   792  	}
   793  
   794  	bt = &BuilderTag{
   795  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   796  		typeId:  exifcommon.TypeByte,
   797  		tagId:   0x99,
   798  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string4")),
   799  	}
   800  
   801  	err = ib.Replace(0x22, bt)
   802  	log.PanicIf(err)
   803  
   804  	currentIds = make([]uint16, 3)
   805  	for i, bt := range ib.Tags() {
   806  		currentIds[i] = bt.tagId
   807  	}
   808  
   809  	if reflect.DeepEqual([]uint16{0x11, 0x99, 0x33}, currentIds) == false {
   810  		t.Fatalf("Post-replace tags are not correct.")
   811  	}
   812  }
   813  
   814  func TestIfdBuilder_ReplaceN(t *testing.T) {
   815  	im, err := exifcommon.NewIfdMappingWithStandard()
   816  	log.PanicIf(err)
   817  
   818  	ti := NewTagIndex()
   819  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   820  
   821  	bt := &BuilderTag{
   822  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   823  		typeId:  exifcommon.TypeByte,
   824  		tagId:   0x11,
   825  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
   826  	}
   827  
   828  	err = ib.Add(bt)
   829  	log.PanicIf(err)
   830  
   831  	bt = &BuilderTag{
   832  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   833  		typeId:  exifcommon.TypeByte,
   834  		tagId:   0x22,
   835  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string2")),
   836  	}
   837  
   838  	err = ib.Add(bt)
   839  	log.PanicIf(err)
   840  
   841  	bt = &BuilderTag{
   842  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   843  		typeId:  exifcommon.TypeByte,
   844  		tagId:   0x33,
   845  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string3")),
   846  	}
   847  
   848  	err = ib.Add(bt)
   849  	log.PanicIf(err)
   850  
   851  	currentIds := make([]uint16, 3)
   852  	for i, bt := range ib.Tags() {
   853  		currentIds[i] = bt.tagId
   854  	}
   855  
   856  	if reflect.DeepEqual([]uint16{0x11, 0x22, 0x33}, currentIds) == false {
   857  		t.Fatalf("Pre-replace tags are not correct.")
   858  	}
   859  
   860  	bt = &BuilderTag{
   861  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   862  		typeId:  exifcommon.TypeByte,
   863  		tagId:   0xA9,
   864  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string4")),
   865  	}
   866  
   867  	err = ib.ReplaceAt(1, bt)
   868  	log.PanicIf(err)
   869  
   870  	currentIds = make([]uint16, 3)
   871  	for i, bt := range ib.Tags() {
   872  		currentIds[i] = bt.tagId
   873  	}
   874  
   875  	if reflect.DeepEqual([]uint16{0x11, 0xA9, 0x33}, currentIds) == false {
   876  		t.Fatalf("Post-replace tags are not correct.")
   877  	}
   878  }
   879  
   880  func TestIfdBuilder_DeleteFirst(t *testing.T) {
   881  	im, err := exifcommon.NewIfdMappingWithStandard()
   882  	log.PanicIf(err)
   883  
   884  	ti := NewTagIndex()
   885  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   886  
   887  	bt := &BuilderTag{
   888  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   889  		typeId:  exifcommon.TypeByte,
   890  		tagId:   0x11,
   891  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
   892  	}
   893  
   894  	err = ib.Add(bt)
   895  	log.PanicIf(err)
   896  
   897  	bt = &BuilderTag{
   898  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   899  		typeId:  exifcommon.TypeByte,
   900  		tagId:   0x22,
   901  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string2")),
   902  	}
   903  
   904  	err = ib.Add(bt)
   905  	log.PanicIf(err)
   906  
   907  	bt = &BuilderTag{
   908  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   909  		typeId:  exifcommon.TypeByte,
   910  		tagId:   0x22,
   911  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string3")),
   912  	}
   913  
   914  	err = ib.Add(bt)
   915  	log.PanicIf(err)
   916  
   917  	bt = &BuilderTag{
   918  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   919  		typeId:  exifcommon.TypeByte,
   920  		tagId:   0x33,
   921  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string4")),
   922  	}
   923  
   924  	err = ib.Add(bt)
   925  	log.PanicIf(err)
   926  
   927  	if len(ib.Tags()) != 4 {
   928  		t.Fatalf("Pre-delete tag count not correct.")
   929  	}
   930  
   931  	currentIds := make([]uint16, 4)
   932  	for i, bt := range ib.Tags() {
   933  		currentIds[i] = bt.tagId
   934  	}
   935  
   936  	if reflect.DeepEqual([]uint16{0x11, 0x22, 0x22, 0x33}, currentIds) == false {
   937  		t.Fatalf("Pre-delete tags not correct.")
   938  	}
   939  
   940  	err = ib.DeleteFirst(0x22)
   941  	log.PanicIf(err)
   942  
   943  	if len(ib.Tags()) != 3 {
   944  		t.Fatalf("Post-delete (1) tag count not correct.")
   945  	}
   946  
   947  	currentIds = make([]uint16, 3)
   948  	for i, bt := range ib.Tags() {
   949  		currentIds[i] = bt.tagId
   950  	}
   951  
   952  	if reflect.DeepEqual([]uint16{0x11, 0x22, 0x33}, currentIds) == false {
   953  		t.Fatalf("Post-delete (1) tags not correct.")
   954  	}
   955  
   956  	err = ib.DeleteFirst(0x22)
   957  	log.PanicIf(err)
   958  
   959  	if len(ib.Tags()) != 2 {
   960  		t.Fatalf("Post-delete (2) tag count not correct.")
   961  	}
   962  
   963  	currentIds = make([]uint16, 2)
   964  	for i, bt := range ib.Tags() {
   965  		currentIds[i] = bt.tagId
   966  	}
   967  
   968  	if reflect.DeepEqual([]uint16{0x11, 0x33}, currentIds) == false {
   969  		t.Fatalf("Post-delete (2) tags not correct.")
   970  	}
   971  
   972  	err = ib.DeleteFirst(0x22)
   973  	if err == nil {
   974  		t.Fatalf("Expected an error.")
   975  	} else if log.Is(err, ErrTagEntryNotFound) == false {
   976  		log.Panic(err)
   977  	}
   978  }
   979  
   980  func TestIfdBuilder_DeleteN(t *testing.T) {
   981  	im, err := exifcommon.NewIfdMappingWithStandard()
   982  	log.PanicIf(err)
   983  
   984  	ti := NewTagIndex()
   985  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
   986  
   987  	bt := &BuilderTag{
   988  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   989  		typeId:  exifcommon.TypeByte,
   990  		tagId:   0x11,
   991  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
   992  	}
   993  
   994  	err = ib.Add(bt)
   995  	log.PanicIf(err)
   996  
   997  	bt = &BuilderTag{
   998  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
   999  		typeId:  exifcommon.TypeByte,
  1000  		tagId:   0x22,
  1001  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string2")),
  1002  	}
  1003  
  1004  	err = ib.Add(bt)
  1005  	log.PanicIf(err)
  1006  
  1007  	bt = &BuilderTag{
  1008  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
  1009  		typeId:  exifcommon.TypeByte,
  1010  		tagId:   0x22,
  1011  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string3")),
  1012  	}
  1013  
  1014  	err = ib.Add(bt)
  1015  	log.PanicIf(err)
  1016  
  1017  	bt = &BuilderTag{
  1018  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
  1019  		typeId:  exifcommon.TypeByte,
  1020  		tagId:   0x33,
  1021  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string4")),
  1022  	}
  1023  
  1024  	err = ib.Add(bt)
  1025  	log.PanicIf(err)
  1026  
  1027  	if len(ib.Tags()) != 4 {
  1028  		t.Fatalf("Pre-delete tag count not correct.")
  1029  	}
  1030  
  1031  	currentIds := make([]uint16, 4)
  1032  	for i, bt := range ib.Tags() {
  1033  		currentIds[i] = bt.tagId
  1034  	}
  1035  
  1036  	if reflect.DeepEqual([]uint16{0x11, 0x22, 0x22, 0x33}, currentIds) == false {
  1037  		t.Fatalf("Pre-delete tags not correct.")
  1038  	}
  1039  
  1040  	err = ib.DeleteN(0x22, 1)
  1041  	log.PanicIf(err)
  1042  
  1043  	if len(ib.Tags()) != 3 {
  1044  		t.Fatalf("Post-delete (1) tag count not correct.")
  1045  	}
  1046  
  1047  	currentIds = make([]uint16, 3)
  1048  	for i, bt := range ib.Tags() {
  1049  		currentIds[i] = bt.tagId
  1050  	}
  1051  
  1052  	if reflect.DeepEqual([]uint16{0x11, 0x22, 0x33}, currentIds) == false {
  1053  		t.Fatalf("Post-delete (1) tags not correct.")
  1054  	}
  1055  
  1056  	err = ib.DeleteN(0x22, 1)
  1057  	log.PanicIf(err)
  1058  
  1059  	if len(ib.Tags()) != 2 {
  1060  		t.Fatalf("Post-delete (2) tag count not correct.")
  1061  	}
  1062  
  1063  	currentIds = make([]uint16, 2)
  1064  	for i, bt := range ib.Tags() {
  1065  		currentIds[i] = bt.tagId
  1066  	}
  1067  
  1068  	if reflect.DeepEqual([]uint16{0x11, 0x33}, currentIds) == false {
  1069  		t.Fatalf("Post-delete (2) tags not correct.")
  1070  	}
  1071  
  1072  	err = ib.DeleteN(0x22, 1)
  1073  	if err == nil {
  1074  		t.Fatalf("Expected an error.")
  1075  	} else if log.Is(err, ErrTagEntryNotFound) == false {
  1076  		log.Panic(err)
  1077  	}
  1078  }
  1079  
  1080  func TestIfdBuilder_DeleteN_Two(t *testing.T) {
  1081  	im, err := exifcommon.NewIfdMappingWithStandard()
  1082  	log.PanicIf(err)
  1083  
  1084  	ti := NewTagIndex()
  1085  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
  1086  
  1087  	bt := &BuilderTag{
  1088  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
  1089  		typeId:  exifcommon.TypeByte,
  1090  		tagId:   0x11,
  1091  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
  1092  	}
  1093  
  1094  	err = ib.Add(bt)
  1095  	log.PanicIf(err)
  1096  
  1097  	bt = &BuilderTag{
  1098  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
  1099  		typeId:  exifcommon.TypeByte,
  1100  		tagId:   0x22,
  1101  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string2")),
  1102  	}
  1103  
  1104  	err = ib.Add(bt)
  1105  	log.PanicIf(err)
  1106  
  1107  	bt = &BuilderTag{
  1108  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
  1109  		typeId:  exifcommon.TypeByte,
  1110  		tagId:   0x22,
  1111  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string3")),
  1112  	}
  1113  
  1114  	err = ib.Add(bt)
  1115  	log.PanicIf(err)
  1116  
  1117  	bt = &BuilderTag{
  1118  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
  1119  		typeId:  exifcommon.TypeByte,
  1120  		tagId:   0x33,
  1121  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string4")),
  1122  	}
  1123  
  1124  	err = ib.Add(bt)
  1125  	log.PanicIf(err)
  1126  
  1127  	if len(ib.Tags()) != 4 {
  1128  		t.Fatalf("Pre-delete tag count not correct.")
  1129  	}
  1130  
  1131  	currentIds := make([]uint16, 4)
  1132  	for i, bt := range ib.Tags() {
  1133  		currentIds[i] = bt.tagId
  1134  	}
  1135  
  1136  	if reflect.DeepEqual([]uint16{0x11, 0x22, 0x22, 0x33}, currentIds) == false {
  1137  		t.Fatalf("Pre-delete tags not correct.")
  1138  	}
  1139  
  1140  	err = ib.DeleteN(0x22, 2)
  1141  	log.PanicIf(err)
  1142  
  1143  	if len(ib.Tags()) != 2 {
  1144  		t.Fatalf("Post-delete tag count not correct.")
  1145  	}
  1146  
  1147  	currentIds = make([]uint16, 2)
  1148  	for i, bt := range ib.Tags() {
  1149  		currentIds[i] = bt.tagId
  1150  	}
  1151  
  1152  	if reflect.DeepEqual([]uint16{0x11, 0x33}, currentIds) == false {
  1153  		t.Fatalf("Post-delete tags not correct.")
  1154  	}
  1155  
  1156  	err = ib.DeleteFirst(0x22)
  1157  	if err == nil {
  1158  		t.Fatalf("Expected an error.")
  1159  	} else if log.Is(err, ErrTagEntryNotFound) == false {
  1160  		log.Panic(err)
  1161  	}
  1162  }
  1163  
  1164  func TestIfdBuilder_DeleteAll(t *testing.T) {
  1165  	im, err := exifcommon.NewIfdMappingWithStandard()
  1166  	log.PanicIf(err)
  1167  
  1168  	ti := NewTagIndex()
  1169  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
  1170  
  1171  	bt := &BuilderTag{
  1172  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
  1173  		typeId:  exifcommon.TypeByte,
  1174  		tagId:   0x11,
  1175  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string")),
  1176  	}
  1177  
  1178  	err = ib.Add(bt)
  1179  	log.PanicIf(err)
  1180  
  1181  	bt = &BuilderTag{
  1182  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
  1183  		typeId:  exifcommon.TypeByte,
  1184  		tagId:   0x22,
  1185  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string2")),
  1186  	}
  1187  
  1188  	err = ib.Add(bt)
  1189  	log.PanicIf(err)
  1190  
  1191  	bt = &BuilderTag{
  1192  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
  1193  		typeId:  exifcommon.TypeByte,
  1194  		tagId:   0x22,
  1195  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string3")),
  1196  	}
  1197  
  1198  	err = ib.Add(bt)
  1199  	log.PanicIf(err)
  1200  
  1201  	bt = &BuilderTag{
  1202  		ifdPath: exifcommon.IfdStandardIfdIdentity.UnindexedString(),
  1203  		typeId:  exifcommon.TypeByte,
  1204  		tagId:   0x33,
  1205  		value:   NewIfdBuilderTagValueFromBytes([]byte("test string4")),
  1206  	}
  1207  
  1208  	err = ib.Add(bt)
  1209  	log.PanicIf(err)
  1210  
  1211  	if len(ib.Tags()) != 4 {
  1212  		t.Fatalf("Pre-delete tag count not correct.")
  1213  	}
  1214  
  1215  	currentIds := make([]uint16, 4)
  1216  	for i, bt := range ib.Tags() {
  1217  		currentIds[i] = bt.tagId
  1218  	}
  1219  
  1220  	if reflect.DeepEqual([]uint16{0x11, 0x22, 0x22, 0x33}, currentIds) == false {
  1221  		t.Fatalf("Pre-delete tags not correct.")
  1222  	}
  1223  
  1224  	n, err := ib.DeleteAll(0x22)
  1225  	log.PanicIf(err)
  1226  
  1227  	if n != 2 {
  1228  		t.Fatalf("Returned delete tag count not correct.")
  1229  	} else if len(ib.Tags()) != 2 {
  1230  		t.Fatalf("Post-delete tag count not correct.")
  1231  	}
  1232  
  1233  	currentIds = make([]uint16, 2)
  1234  	for i, bt := range ib.Tags() {
  1235  		currentIds[i] = bt.tagId
  1236  	}
  1237  
  1238  	if reflect.DeepEqual([]uint16{0x11, 0x33}, currentIds) == false {
  1239  		t.Fatalf("Post-delete tags not correct.")
  1240  	}
  1241  
  1242  	err = ib.DeleteFirst(0x22)
  1243  	if err == nil {
  1244  		t.Fatalf("Expected an error.")
  1245  	} else if log.Is(err, ErrTagEntryNotFound) == false {
  1246  		log.Panic(err)
  1247  	}
  1248  }
  1249  
  1250  func TestIfdBuilder_NewIfdBuilderFromExistingChain(t *testing.T) {
  1251  	defer func() {
  1252  		if state := recover(); state != nil {
  1253  			err := log.Wrap(state.(error))
  1254  			log.PrintErrorf(err, "Test failure.")
  1255  		}
  1256  	}()
  1257  
  1258  	testImageFilepath := getTestImageFilepath()
  1259  
  1260  	rawExif, err := SearchFileAndExtractExif(testImageFilepath)
  1261  	log.PanicIf(err)
  1262  
  1263  	im, err := exifcommon.NewIfdMappingWithStandard()
  1264  	log.PanicIf(err)
  1265  
  1266  	ti := NewTagIndex()
  1267  
  1268  	_, index, err := Collect(im, ti, rawExif)
  1269  	log.PanicIf(err)
  1270  
  1271  	ib := NewIfdBuilderFromExistingChain(index.RootIfd)
  1272  
  1273  	actual := ib.DumpToStrings()
  1274  
  1275  	expected := []string{
  1276  		"IFD<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-INDEX=(0) IFD-TAG-ID=(0x0000) TAG=[0x0000]>",
  1277  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(0) TAG=[0x010f]>",
  1278  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(1) TAG=[0x0110]>",
  1279  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(2) TAG=[0x0112]>",
  1280  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(3) TAG=[0x011a]>",
  1281  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(4) TAG=[0x011b]>",
  1282  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(5) TAG=[0x0128]>",
  1283  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(6) TAG=[0x0132]>",
  1284  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(7) TAG=[0x013b]>",
  1285  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(8) TAG=[0x0213]>",
  1286  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(9) TAG=[0x8298]>",
  1287  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[IFD/Exif] TAG-INDEX=(10) TAG=[0x8769]>",
  1288  		"IFD<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-INDEX=(0) IFD-TAG-ID=(0x8769) TAG=[0x8769]>",
  1289  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(0) TAG=[0x829a]>",
  1290  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(1) TAG=[0x829d]>",
  1291  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(2) TAG=[0x8822]>",
  1292  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(3) TAG=[0x8827]>",
  1293  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(4) TAG=[0x8830]>",
  1294  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(5) TAG=[0x8832]>",
  1295  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(6) TAG=[0x9000]>",
  1296  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(7) TAG=[0x9003]>",
  1297  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(8) TAG=[0x9004]>",
  1298  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(9) TAG=[0x9101]>",
  1299  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(10) TAG=[0x9201]>",
  1300  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(11) TAG=[0x9202]>",
  1301  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(12) TAG=[0x9204]>",
  1302  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(13) TAG=[0x9207]>",
  1303  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(14) TAG=[0x9209]>",
  1304  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(15) TAG=[0x920a]>",
  1305  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(16) TAG=[0x927c]>",
  1306  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(17) TAG=[0x9286]>",
  1307  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(18) TAG=[0x9290]>",
  1308  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(19) TAG=[0x9291]>",
  1309  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(20) TAG=[0x9292]>",
  1310  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(21) TAG=[0xa000]>",
  1311  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(22) TAG=[0xa001]>",
  1312  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(23) TAG=[0xa002]>",
  1313  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(24) TAG=[0xa003]>",
  1314  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[IFD/Exif/Iop] TAG-INDEX=(25) TAG=[0xa005]>",
  1315  		"IFD<PARENTS=[IFD->IFD/Exif] FQ-IFD-PATH=[IFD/Exif/Iop] IFD-INDEX=(0) IFD-TAG-ID=(0xa005) TAG=[0xa005]>",
  1316  		"TAG<PARENTS=[IFD->IFD/Exif] FQ-IFD-PATH=[IFD/Exif/Iop] IFD-TAG-ID=(0xa005) CHILD-IFD=[] TAG-INDEX=(0) TAG=[0x0001]>",
  1317  		"TAG<PARENTS=[IFD->IFD/Exif] FQ-IFD-PATH=[IFD/Exif/Iop] IFD-TAG-ID=(0xa005) CHILD-IFD=[] TAG-INDEX=(1) TAG=[0x0002]>",
  1318  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(26) TAG=[0xa20e]>",
  1319  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(27) TAG=[0xa20f]>",
  1320  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(28) TAG=[0xa210]>",
  1321  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(29) TAG=[0xa401]>",
  1322  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(30) TAG=[0xa402]>",
  1323  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(31) TAG=[0xa403]>",
  1324  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(32) TAG=[0xa406]>",
  1325  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(33) TAG=[0xa430]>",
  1326  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(34) TAG=[0xa431]>",
  1327  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(35) TAG=[0xa432]>",
  1328  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(36) TAG=[0xa434]>",
  1329  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[] TAG-INDEX=(37) TAG=[0xa435]>",
  1330  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[IFD/GPSInfo] TAG-INDEX=(11) TAG=[0x8825]>",
  1331  		"IFD<PARENTS=[IFD] FQ-IFD-PATH=[IFD/GPSInfo] IFD-INDEX=(0) IFD-TAG-ID=(0x8825) TAG=[0x8825]>",
  1332  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/GPSInfo] IFD-TAG-ID=(0x8825) CHILD-IFD=[] TAG-INDEX=(0) TAG=[0x0000]>",
  1333  		"IFD<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-INDEX=(1) IFD-TAG-ID=(0x0000) TAG=[0x0000]>",
  1334  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(0) TAG=[0x0201]>",
  1335  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(1) TAG=[0x0202]>",
  1336  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(2) TAG=[0x0103]>",
  1337  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(3) TAG=[0x011a]>",
  1338  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(4) TAG=[0x011b]>",
  1339  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[] TAG-INDEX=(5) TAG=[0x0128]>",
  1340  	}
  1341  
  1342  	if reflect.DeepEqual(actual, expected) == false {
  1343  		fmt.Printf("ACTUAL:\n%s\n\nEXPECTED:\n%s\n", strings.Join(actual, "\n"), strings.Join(expected, "\n"))
  1344  		t.Fatalf("IB did not [correctly] duplicate the IFD structure.")
  1345  	}
  1346  }
  1347  
  1348  func TestIfdBuilder_SetStandardWithName_UpdateGps(t *testing.T) {
  1349  	defer func() {
  1350  		if state := recover(); state != nil {
  1351  			err := log.Wrap(state.(error))
  1352  			log.PrintErrorf(err, "Test failure.")
  1353  		}
  1354  	}()
  1355  
  1356  	// Check initial value.
  1357  
  1358  	filepath := getTestGpsImageFilepath()
  1359  
  1360  	rawExif, err := SearchFileAndExtractExif(filepath)
  1361  	log.PanicIf(err)
  1362  
  1363  	im, err := exifcommon.NewIfdMappingWithStandard()
  1364  	log.PanicIf(err)
  1365  
  1366  	ti := NewTagIndex()
  1367  
  1368  	_, index, err := Collect(im, ti, rawExif)
  1369  	log.PanicIf(err)
  1370  
  1371  	rootIfd := index.RootIfd
  1372  
  1373  	gpsIfd, err := rootIfd.ChildWithIfdPath(exifcommon.IfdGpsInfoStandardIfdIdentity)
  1374  	log.PanicIf(err)
  1375  
  1376  	initialGi, err := gpsIfd.GpsInfo()
  1377  	log.PanicIf(err)
  1378  
  1379  	initialGpsLatitudePhrase := "Degrees<O=[N] D=(26) M=(35) S=(12)>"
  1380  
  1381  	if initialGi.Latitude.String() != initialGpsLatitudePhrase {
  1382  		t.Fatalf("Initial GPS latitude not correct: [%s]", initialGi.Latitude)
  1383  	}
  1384  
  1385  	// Update the value.
  1386  
  1387  	rootIb := NewIfdBuilderFromExistingChain(rootIfd)
  1388  
  1389  	gpsIb, err := rootIb.ChildWithTagId(exifcommon.IfdGpsInfoStandardIfdIdentity.TagId())
  1390  	log.PanicIf(err)
  1391  
  1392  	updatedGi := GpsDegrees{
  1393  		Degrees: 11,
  1394  		Minutes: 22,
  1395  		Seconds: 33,
  1396  	}
  1397  
  1398  	raw := updatedGi.Raw()
  1399  
  1400  	err = gpsIb.SetStandardWithName("GPSLatitude", raw)
  1401  	log.PanicIf(err)
  1402  
  1403  	// Encode to bytes.
  1404  
  1405  	ibe := NewIfdByteEncoder()
  1406  
  1407  	updatedRawExif, err := ibe.EncodeToExif(rootIb)
  1408  	log.PanicIf(err)
  1409  
  1410  	// Decode from bytes.
  1411  
  1412  	_, updatedIndex, err := Collect(im, ti, updatedRawExif)
  1413  	log.PanicIf(err)
  1414  
  1415  	updatedRootIfd := updatedIndex.RootIfd
  1416  
  1417  	// Test.
  1418  
  1419  	updatedGpsIfd, err := updatedRootIfd.ChildWithIfdPath(exifcommon.IfdGpsInfoStandardIfdIdentity)
  1420  	log.PanicIf(err)
  1421  
  1422  	recoveredUpdatedGi, err := updatedGpsIfd.GpsInfo()
  1423  	log.PanicIf(err)
  1424  
  1425  	updatedGpsLatitudePhrase := "Degrees<O=[N] D=(11) M=(22) S=(33)>"
  1426  
  1427  	if recoveredUpdatedGi.Latitude.String() != updatedGpsLatitudePhrase {
  1428  		t.Fatalf("Updated GPS latitude not set or recovered correctly: [%s]", recoveredUpdatedGi.Latitude)
  1429  	}
  1430  }
  1431  
  1432  func ExampleIfdBuilder_SetStandardWithName_updateGps() {
  1433  	// Check initial value.
  1434  
  1435  	filepath := getTestGpsImageFilepath()
  1436  
  1437  	rawExif, err := SearchFileAndExtractExif(filepath)
  1438  	log.PanicIf(err)
  1439  
  1440  	im, err := exifcommon.NewIfdMappingWithStandard()
  1441  	log.PanicIf(err)
  1442  
  1443  	ti := NewTagIndex()
  1444  
  1445  	_, index, err := Collect(im, ti, rawExif)
  1446  	log.PanicIf(err)
  1447  
  1448  	rootIfd := index.RootIfd
  1449  
  1450  	gpsIfd, err := rootIfd.ChildWithIfdPath(exifcommon.IfdGpsInfoStandardIfdIdentity)
  1451  	log.PanicIf(err)
  1452  
  1453  	initialGi, err := gpsIfd.GpsInfo()
  1454  	log.PanicIf(err)
  1455  
  1456  	fmt.Printf("Original:\n%s\n\n", initialGi.Latitude.String())
  1457  
  1458  	// Update the value.
  1459  
  1460  	rootIb := NewIfdBuilderFromExistingChain(rootIfd)
  1461  
  1462  	gpsIb, err := rootIb.ChildWithTagId(exifcommon.IfdGpsInfoStandardIfdIdentity.TagId())
  1463  	log.PanicIf(err)
  1464  
  1465  	updatedGi := GpsDegrees{
  1466  		Degrees: 11,
  1467  		Minutes: 22,
  1468  		Seconds: 33,
  1469  	}
  1470  
  1471  	raw := updatedGi.Raw()
  1472  
  1473  	err = gpsIb.SetStandardWithName("GPSLatitude", raw)
  1474  	log.PanicIf(err)
  1475  
  1476  	// Encode to bytes.
  1477  
  1478  	ibe := NewIfdByteEncoder()
  1479  
  1480  	updatedRawExif, err := ibe.EncodeToExif(rootIb)
  1481  	log.PanicIf(err)
  1482  
  1483  	// Decode from bytes.
  1484  
  1485  	_, updatedIndex, err := Collect(im, ti, updatedRawExif)
  1486  	log.PanicIf(err)
  1487  
  1488  	updatedRootIfd := updatedIndex.RootIfd
  1489  
  1490  	// Test.
  1491  
  1492  	updatedGpsIfd, err := updatedRootIfd.ChildWithIfdPath(exifcommon.IfdGpsInfoStandardIfdIdentity)
  1493  	log.PanicIf(err)
  1494  
  1495  	recoveredUpdatedGi, err := updatedGpsIfd.GpsInfo()
  1496  	log.PanicIf(err)
  1497  
  1498  	fmt.Printf("Updated, written, and re-read:\n%s\n", recoveredUpdatedGi.Latitude.String())
  1499  
  1500  	// Output:
  1501  	// Original:
  1502  	// Degrees<O=[N] D=(26) M=(35) S=(12)>
  1503  	//
  1504  	// Updated, written, and re-read:
  1505  	// Degrees<O=[N] D=(11) M=(22) S=(33)>
  1506  }
  1507  
  1508  func ExampleIfdBuilder_SetStandardWithName_timestamp() {
  1509  	// Check initial value.
  1510  
  1511  	filepath := getTestGpsImageFilepath()
  1512  
  1513  	rawExif, err := SearchFileAndExtractExif(filepath)
  1514  	log.PanicIf(err)
  1515  
  1516  	im, err := exifcommon.NewIfdMappingWithStandard()
  1517  	log.PanicIf(err)
  1518  
  1519  	ti := NewTagIndex()
  1520  
  1521  	_, index, err := Collect(im, ti, rawExif)
  1522  	log.PanicIf(err)
  1523  
  1524  	rootIfd := index.RootIfd
  1525  
  1526  	// Update the value.
  1527  
  1528  	rootIb := NewIfdBuilderFromExistingChain(rootIfd)
  1529  
  1530  	exifIb, err := rootIb.ChildWithTagId(exifcommon.IfdExifStandardIfdIdentity.TagId())
  1531  	log.PanicIf(err)
  1532  
  1533  	t := time.Date(2020, 06, 7, 1, 30, 0, 0, time.UTC)
  1534  
  1535  	err = exifIb.SetStandardWithName("DateTimeDigitized", t)
  1536  	log.PanicIf(err)
  1537  
  1538  	// Encode to bytes.
  1539  
  1540  	ibe := NewIfdByteEncoder()
  1541  
  1542  	updatedRawExif, err := ibe.EncodeToExif(rootIb)
  1543  	log.PanicIf(err)
  1544  
  1545  	// Decode from bytes.
  1546  
  1547  	_, updatedIndex, err := Collect(im, ti, updatedRawExif)
  1548  	log.PanicIf(err)
  1549  
  1550  	updatedRootIfd := updatedIndex.RootIfd
  1551  
  1552  	// Test.
  1553  
  1554  	updatedExifIfd, err := updatedRootIfd.ChildWithIfdPath(exifcommon.IfdExifStandardIfdIdentity)
  1555  	log.PanicIf(err)
  1556  
  1557  	results, err := updatedExifIfd.FindTagWithName("DateTimeDigitized")
  1558  	log.PanicIf(err)
  1559  
  1560  	ite := results[0]
  1561  
  1562  	phrase, err := ite.FormatFirst()
  1563  	log.PanicIf(err)
  1564  
  1565  	fmt.Printf("%s\n", phrase)
  1566  
  1567  	// Output:
  1568  	// 2020:06:07 01:30:00
  1569  }
  1570  
  1571  func TestIfdBuilder_NewIfdBuilderFromExistingChain_RealData(t *testing.T) {
  1572  	testImageFilepath := getTestImageFilepath()
  1573  
  1574  	rawExif, err := SearchFileAndExtractExif(testImageFilepath)
  1575  	log.PanicIf(err)
  1576  
  1577  	// Decode from binary.
  1578  
  1579  	im, err := exifcommon.NewIfdMappingWithStandard()
  1580  	log.PanicIf(err)
  1581  
  1582  	ti := NewTagIndex()
  1583  
  1584  	_, originalIndex, err := Collect(im, ti, rawExif)
  1585  	log.PanicIf(err)
  1586  
  1587  	originalThumbnailData, err := originalIndex.RootIfd.nextIfd.Thumbnail()
  1588  	log.PanicIf(err)
  1589  
  1590  	originalTags := originalIndex.RootIfd.DumpTags()
  1591  
  1592  	// Encode back to binary.
  1593  
  1594  	ibe := NewIfdByteEncoder()
  1595  
  1596  	rootIb := NewIfdBuilderFromExistingChain(originalIndex.RootIfd)
  1597  
  1598  	updatedExif, err := ibe.EncodeToExif(rootIb)
  1599  	log.PanicIf(err)
  1600  
  1601  	// Parse again.
  1602  
  1603  	_, recoveredIndex, err := Collect(im, ti, updatedExif)
  1604  	log.PanicIf(err)
  1605  
  1606  	recoveredTags := recoveredIndex.RootIfd.DumpTags()
  1607  
  1608  	recoveredThumbnailData, err := recoveredIndex.RootIfd.nextIfd.Thumbnail()
  1609  	log.PanicIf(err)
  1610  
  1611  	// Check the thumbnail.
  1612  
  1613  	if bytes.Compare(recoveredThumbnailData, originalThumbnailData) != 0 {
  1614  		t.Fatalf("recovered thumbnail does not match original")
  1615  	}
  1616  
  1617  	// Validate that all of the same IFDs were presented.
  1618  
  1619  	originalIfdTags := make([][2]interface{}, 0)
  1620  	for _, ite := range originalTags {
  1621  		if ite.ChildIfdPath() != "" {
  1622  			originalIfdTags = append(originalIfdTags, [2]interface{}{ite.IfdPath(), ite.TagId()})
  1623  		}
  1624  	}
  1625  
  1626  	recoveredIfdTags := make([][2]interface{}, 0)
  1627  	for _, ite := range recoveredTags {
  1628  		if ite.ChildIfdPath() != "" {
  1629  			recoveredIfdTags = append(recoveredIfdTags, [2]interface{}{ite.IfdPath(), ite.TagId()})
  1630  		}
  1631  	}
  1632  
  1633  	if reflect.DeepEqual(recoveredIfdTags, originalIfdTags) != true {
  1634  		fmt.Printf("Original IFD tags:\n\n")
  1635  
  1636  		for i, x := range originalIfdTags {
  1637  			fmt.Printf("  %02d %v\n", i, x)
  1638  		}
  1639  
  1640  		fmt.Printf("\nRecovered IFD tags:\n\n")
  1641  
  1642  		for i, x := range recoveredIfdTags {
  1643  			fmt.Printf("  %02d %v\n", i, x)
  1644  		}
  1645  
  1646  		fmt.Printf("\n")
  1647  
  1648  		t.Fatalf("Recovered IFD tags are not correct.")
  1649  	}
  1650  
  1651  	// Validate that all of the tags owned by the IFDs were presented. Note
  1652  	// that the thumbnail tags are not kept but only produced on the fly, which
  1653  	// is why we check it above.
  1654  
  1655  	if len(recoveredTags) != len(originalTags) {
  1656  		t.Fatalf("Recovered tag-count does not match original.")
  1657  	}
  1658  
  1659  	originalTagPhrases := make([]string, 0)
  1660  	for _, ite := range originalTags {
  1661  		// Adds a lot of noise if/when debugging, and we're already checking the
  1662  		// thumbnail bytes separately.
  1663  		if ite.IsThumbnailOffset() == true || ite.IsThumbnailSize() == true {
  1664  			continue
  1665  		}
  1666  
  1667  		phrase := ite.String()
  1668  
  1669  		// The value (the offset) of IFDs will almost never be the same after
  1670  		// reconstruction (by design).
  1671  		if ite.ChildIfdName() == "" {
  1672  			valuePhrase, err := ite.FormatFirst()
  1673  			log.PanicIf(err)
  1674  
  1675  			phrase += " " + valuePhrase
  1676  		}
  1677  
  1678  		originalTagPhrases = append(originalTagPhrases, phrase)
  1679  	}
  1680  
  1681  	sort.Strings(originalTagPhrases)
  1682  
  1683  	recoveredTagPhrases := make([]string, 0)
  1684  	for _, ite := range recoveredTags {
  1685  		// Adds a lot of noise if/when debugging, and we're already checking the
  1686  		// thumbnail bytes separately.
  1687  		if ite.IsThumbnailOffset() == true || ite.IsThumbnailSize() == true {
  1688  			continue
  1689  		}
  1690  
  1691  		phrase := ite.String()
  1692  
  1693  		// The value (the offset) of IFDs will almost never be the same after
  1694  		// reconstruction (by design).
  1695  		if ite.ChildIfdName() == "" {
  1696  			valuePhrase, err := ite.FormatFirst()
  1697  			log.PanicIf(err)
  1698  
  1699  			phrase += " " + valuePhrase
  1700  		}
  1701  
  1702  		recoveredTagPhrases = append(recoveredTagPhrases, phrase)
  1703  	}
  1704  
  1705  	sort.Strings(recoveredTagPhrases)
  1706  
  1707  	if reflect.DeepEqual(recoveredTagPhrases, originalTagPhrases) != true {
  1708  		fmt.Printf("ORIGINAL:\n")
  1709  		fmt.Printf("\n")
  1710  
  1711  		for _, tag := range originalTagPhrases {
  1712  			fmt.Printf("%s\n", tag)
  1713  		}
  1714  
  1715  		fmt.Printf("\n")
  1716  
  1717  		fmt.Printf("RECOVERED:\n")
  1718  		fmt.Printf("\n")
  1719  
  1720  		for _, tag := range recoveredTagPhrases {
  1721  			fmt.Printf("%s\n", tag)
  1722  		}
  1723  
  1724  		fmt.Printf("\n")
  1725  
  1726  		t.Fatalf("Recovered tags do not equal original tags.")
  1727  	}
  1728  }
  1729  
  1730  // func TestIfdBuilder_NewIfdBuilderFromExistingChain_RealData_WithUpdate(t *testing.T) {
  1731  //	testImageFilepath := getTestImageFilepath()
  1732  
  1733  // 	rawExif, err := SearchFileAndExtractExif(testImageFilepath)
  1734  // 	log.PanicIf(err)
  1735  
  1736  // 	// Decode from binary.
  1737  
  1738  // 	ti := NewTagIndex()
  1739  
  1740  // 	_, originalIndex, err := Collect(im, ti, rawExif)
  1741  // 	log.PanicIf(err)
  1742  
  1743  // 	originalThumbnailData, err := originalIndex.RootIfd.nextIfd.Thumbnail()
  1744  // 	log.PanicIf(err)
  1745  
  1746  // 	originalTags := originalIndex.RootIfd.DumpTags()
  1747  
  1748  // 	// Encode back to binary.
  1749  
  1750  // 	ibe := NewIfdByteEncoder()
  1751  
  1752  // 	rootIb := NewIfdBuilderFromExistingChain(originalIndex.RootIfd)
  1753  
  1754  // 	// Update a tag,.
  1755  
  1756  // 	exifBt, err := rootIb.FindTagWithName("ExifTag")
  1757  // 	log.PanicIf(err)
  1758  
  1759  // 	ucBt, err := exifBt.value.Ib().FindTagWithName("UserComment")
  1760  // 	log.PanicIf(err)
  1761  
  1762  // 	uc := exifundefined.Tag9286UserComment{
  1763  // 		EncodingType:  TagUndefinedType_9286_UserComment_Encoding_ASCII,
  1764  // 		EncodingBytes: []byte("TEST COMMENT"),
  1765  // 	}
  1766  
  1767  // 	err = ucBt.SetValue(rootIb.byteOrder, uc)
  1768  // 	log.PanicIf(err)
  1769  
  1770  // 	// Encode.
  1771  
  1772  // 	updatedExif, err := ibe.EncodeToExif(rootIb)
  1773  // 	log.PanicIf(err)
  1774  
  1775  // 	// Parse again.
  1776  
  1777  // 	_, recoveredIndex, err := Collect(im, ti, updatedExif)
  1778  // 	log.PanicIf(err)
  1779  
  1780  // 	recoveredTags := recoveredIndex.RootIfd.DumpTags()
  1781  
  1782  // 	recoveredThumbnailData, err := recoveredIndex.RootIfd.nextIfd.Thumbnail()
  1783  // 	log.PanicIf(err)
  1784  
  1785  // 	// Check the thumbnail.
  1786  
  1787  // 	if bytes.Compare(recoveredThumbnailData, originalThumbnailData) != 0 {
  1788  // 		t.Fatalf("recovered thumbnail does not match original")
  1789  // 	}
  1790  
  1791  // 	// Validate that all of the same IFDs were presented.
  1792  
  1793  // 	originalIfdTags := make([][2]interface{}, 0)
  1794  // 	for _, ite := range originalTags {
  1795  // 		if ite.ChildIfdPath() != "" {
  1796  // 			originalIfdTags = append(originalIfdTags, [2]interface{}{ite.IfdPath(), ite.TagId()})
  1797  // 		}
  1798  // 	}
  1799  
  1800  // 	recoveredIfdTags := make([][2]interface{}, 0)
  1801  // 	for _, ite := range recoveredTags {
  1802  // 		if ite.ChildIfdPath() != "" {
  1803  // 			recoveredIfdTags = append(recoveredIfdTags, [2]interface{}{ite.IfdPath(), ite.TagId()})
  1804  // 		}
  1805  // 	}
  1806  
  1807  // 	if reflect.DeepEqual(recoveredIfdTags, originalIfdTags) != true {
  1808  // 		fmt.Printf("Original IFD tags:\n\n")
  1809  
  1810  // 		for i, x := range originalIfdTags {
  1811  // 			fmt.Printf("  %02d %v\n", i, x)
  1812  // 		}
  1813  
  1814  // 		fmt.Printf("\nRecovered IFD tags:\n\n")
  1815  
  1816  // 		for i, x := range recoveredIfdTags {
  1817  // 			fmt.Printf("  %02d %v\n", i, x)
  1818  // 		}
  1819  
  1820  // 		fmt.Printf("\n")
  1821  
  1822  // 		t.Fatalf("Recovered IFD tags are not correct.")
  1823  // 	}
  1824  
  1825  // 	// Validate that all of the tags owned by the IFDs were presented. Note
  1826  // 	// that the thumbnail tags are not kept but only produced on the fly, which
  1827  // 	// is why we check it above.
  1828  
  1829  // 	if len(recoveredTags) != len(originalTags) {
  1830  // 		t.Fatalf("Recovered tag-count does not match original.")
  1831  // 	}
  1832  
  1833  // 	for i, recoveredIte := range recoveredTags {
  1834  // 		if recoveredIte.ChildIfdPath() != "" {
  1835  // 			continue
  1836  // 		}
  1837  
  1838  // 		originalIte := originalTags[i]
  1839  
  1840  // 		if recoveredIte.IfdPath() != originalIte.IfdPath() {
  1841  // 			t.Fatalf("IfdIdentity not as expected: %s != %s  ITE=%s", recoveredIte.IfdPath(), originalIte.IfdPath(), recoveredIte)
  1842  // 		} else if recoveredIte.TagId() != originalIte.TagId() {
  1843  // 			t.Fatalf("Tag-ID not as expected: %d != %d  ITE=%s", recoveredIte.TagId(), originalIte.TagId(), recoveredIte)
  1844  // 		} else if recoveredIte.TagType() != originalIte.TagType() {
  1845  // 			t.Fatalf("Tag-type not as expected: %d != %d  ITE=%s", recoveredIte.TagType(), originalIte.TagType(), recoveredIte)
  1846  // 		}
  1847  
  1848  // 		originalValueBytes, err := originalIte.ValueBytes(originalIndex.RootIfd.addressableData, originalIndex.RootIfd.ByteOrder())
  1849  // 		log.PanicIf(err)
  1850  
  1851  // 		recoveredValueBytes, err := recoveredIte.ValueBytes(recoveredIndex.RootIfd.addressableData, recoveredIndex.RootIfd.ByteOrder())
  1852  // 		log.PanicIf(err)
  1853  
  1854  // 		if recoveredIte.TagId() == 0x9286 {
  1855  // 			expectedValueBytes := make([]byte, 0)
  1856  
  1857  // 			expectedValueBytes = append(expectedValueBytes, []byte{'A', 'S', 'C', 'I', 'I', 0, 0, 0}...)
  1858  // 			expectedValueBytes = append(expectedValueBytes, []byte("TEST COMMENT")...)
  1859  
  1860  // 			if bytes.Compare(recoveredValueBytes, expectedValueBytes) != 0 {
  1861  // 				t.Fatalf("Recovered UserComment does not have the right value: %v != %v", recoveredValueBytes, expectedValueBytes)
  1862  // 			}
  1863  // 		} else if bytes.Compare(recoveredValueBytes, originalValueBytes) != 0 {
  1864  // 			t.Fatalf("bytes of tag content not correct: %v != %v  ITE=%s", recoveredValueBytes, originalValueBytes, recoveredIte)
  1865  // 		}
  1866  // 	}
  1867  // }
  1868  
  1869  func ExampleIfd_Thumbnail() {
  1870  	testImageFilepath := getTestImageFilepath()
  1871  
  1872  	rawExif, err := SearchFileAndExtractExif(testImageFilepath)
  1873  	log.PanicIf(err)
  1874  
  1875  	im, err := exifcommon.NewIfdMappingWithStandard()
  1876  	log.PanicIf(err)
  1877  
  1878  	ti := NewTagIndex()
  1879  
  1880  	_, index, err := Collect(im, ti, rawExif)
  1881  	log.PanicIf(err)
  1882  
  1883  	// This returns the raw bytes that you will be looking for, but there's no
  1884  	// use for them at this point in the example.
  1885  	_, err = index.RootIfd.nextIfd.Thumbnail()
  1886  	log.PanicIf(err)
  1887  
  1888  	// Output:
  1889  }
  1890  
  1891  func ExampleBuilderTag_SetValue() {
  1892  	testImageFilepath := getTestImageFilepath()
  1893  
  1894  	rawExif, err := SearchFileAndExtractExif(testImageFilepath)
  1895  	log.PanicIf(err)
  1896  
  1897  	im, err := exifcommon.NewIfdMappingWithStandard()
  1898  	log.PanicIf(err)
  1899  
  1900  	ti := NewTagIndex()
  1901  
  1902  	_, index, err := Collect(im, ti, rawExif)
  1903  	log.PanicIf(err)
  1904  
  1905  	// Create builder.
  1906  
  1907  	rootIb := NewIfdBuilderFromExistingChain(index.RootIfd)
  1908  
  1909  	// Find tag to update.
  1910  
  1911  	exifBt, err := rootIb.FindTagWithName("ExifTag")
  1912  	log.PanicIf(err)
  1913  
  1914  	ucBt, err := exifBt.value.Ib().FindTagWithName("UserComment")
  1915  	log.PanicIf(err)
  1916  
  1917  	// Update the value. Since this is an "undefined"-type tag, we have to use
  1918  	// its type-specific struct.
  1919  
  1920  	// TODO(dustin): !! Add an example for setting a non-unknown value, too.
  1921  	uc := exifundefined.Tag9286UserComment{
  1922  		EncodingType:  exifundefined.TagUndefinedType_9286_UserComment_Encoding_ASCII,
  1923  		EncodingBytes: []byte("TEST COMMENT"),
  1924  	}
  1925  
  1926  	err = ucBt.SetValue(rootIb.byteOrder, uc)
  1927  	log.PanicIf(err)
  1928  
  1929  	// Encode.
  1930  
  1931  	ibe := NewIfdByteEncoder()
  1932  
  1933  	// This returns the raw bytes that you will be looking for, but there's no
  1934  	// use for them at this point in the example.
  1935  	_, err = ibe.EncodeToExif(rootIb)
  1936  	log.PanicIf(err)
  1937  
  1938  	// Output:
  1939  }
  1940  
  1941  // ExampleIfdBuilder_SetStandardWithName establishes a chain of `IfdBuilder`
  1942  // structs from an existing chain of `Ifd` structs, navigates to the IB
  1943  // representing IFD0, updates the ProcessingSoftware tag to a different value,
  1944  // encodes down to a new EXIF block, reparses, and validates that the value for
  1945  // that tag is what we set it to.
  1946  func ExampleIfdBuilder_SetStandardWithName() {
  1947  	testImageFilepath := getTestImageFilepath()
  1948  
  1949  	rawExif, err := SearchFileAndExtractExif(testImageFilepath)
  1950  	log.PanicIf(err)
  1951  
  1952  	// Boilerplate.
  1953  
  1954  	im, err := exifcommon.NewIfdMappingWithStandard()
  1955  	log.PanicIf(err)
  1956  
  1957  	ti := NewTagIndex()
  1958  
  1959  	// Load current IFDs.
  1960  
  1961  	_, index, err := Collect(im, ti, rawExif)
  1962  	log.PanicIf(err)
  1963  
  1964  	ib := NewIfdBuilderFromExistingChain(index.RootIfd)
  1965  
  1966  	// Read the IFD whose tag we want to change.
  1967  
  1968  	// Standard:
  1969  	// - "IFD0"
  1970  	// - "IFD0/Exif0"
  1971  	// - "IFD0/Exif0/Iop0"
  1972  	// - "IFD0/GPSInfo0"
  1973  	//
  1974  	// If the numeric indices are not included, (0) is the default. Note that
  1975  	// this isn't strictly necessary in our case since IFD0 is the first IFD anyway, but we're putting it here to show usage.
  1976  	ifdPath := "IFD0"
  1977  
  1978  	childIb, err := GetOrCreateIbFromRootIb(ib, ifdPath)
  1979  	log.PanicIf(err)
  1980  
  1981  	// There are a few functions that allow you to surgically change the tags in an
  1982  	// IFD, but we're just gonna overwrite a tag that has an ASCII value.
  1983  
  1984  	tagName := "ProcessingSoftware"
  1985  
  1986  	err = childIb.SetStandardWithName(tagName, "alternative software")
  1987  	log.PanicIf(err)
  1988  
  1989  	// Encode the in-memory representation back down to bytes.
  1990  
  1991  	ibe := NewIfdByteEncoder()
  1992  
  1993  	updatedRawExif, err := ibe.EncodeToExif(ib)
  1994  	log.PanicIf(err)
  1995  
  1996  	// Reparse the EXIF to confirm that our value is there.
  1997  
  1998  	_, index, err = Collect(im, ti, updatedRawExif)
  1999  	log.PanicIf(err)
  2000  
  2001  	// This isn't strictly necessary for the same reason as above, but it's here
  2002  	// for documentation.
  2003  	childIfd, err := FindIfdFromRootIfd(index.RootIfd, ifdPath)
  2004  	log.PanicIf(err)
  2005  
  2006  	results, err := childIfd.FindTagWithName(tagName)
  2007  	log.PanicIf(err)
  2008  
  2009  	for _, ite := range results {
  2010  		valueRaw, err := ite.Value()
  2011  		log.PanicIf(err)
  2012  
  2013  		stringValue := valueRaw.(string)
  2014  		fmt.Println(stringValue)
  2015  	}
  2016  
  2017  	// Output:
  2018  	// alternative software
  2019  }
  2020  
  2021  func TestIfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) {
  2022  	ti := NewTagIndex()
  2023  
  2024  	im, err := exifcommon.NewIfdMappingWithStandard()
  2025  	log.PanicIf(err)
  2026  
  2027  	mi, err := im.GetWithPath(exifcommon.IfdGpsInfoStandardIfdIdentity.UnindexedString())
  2028  	log.PanicIf(err)
  2029  
  2030  	tagId := mi.TagId
  2031  
  2032  	parentIfd := &Ifd{
  2033  		ifdIdentity: exifcommon.IfdStandardIfdIdentity,
  2034  		tagIndex:    ti,
  2035  	}
  2036  
  2037  	ifd := &Ifd{
  2038  		ifdIdentity: exifcommon.IfdGpsInfoStandardIfdIdentity,
  2039  		byteOrder:   exifcommon.TestDefaultByteOrder,
  2040  		offset:      0x123,
  2041  		parentIfd:   parentIfd,
  2042  
  2043  		ifdMapping: im,
  2044  		tagIndex:   ti,
  2045  	}
  2046  
  2047  	ib := NewIfdBuilderWithExistingIfd(ifd)
  2048  
  2049  	if ib.IfdIdentity().UnindexedString() != ifd.ifdIdentity.UnindexedString() {
  2050  		t.Fatalf("IFD-name not correct.")
  2051  	} else if ib.IfdIdentity().TagId() != tagId {
  2052  		t.Fatalf("IFD tag-ID not correct.")
  2053  	} else if ib.byteOrder != ifd.ByteOrder() {
  2054  		t.Fatalf("IFD byte-order not correct.")
  2055  	} else if ib.existingOffset != ifd.Offset() {
  2056  		t.Fatalf("IFD offset not correct.")
  2057  	}
  2058  }
  2059  
  2060  func TestNewStandardBuilderTag__OneUnit(t *testing.T) {
  2061  	ti := NewTagIndex()
  2062  
  2063  	it, err := ti.Get(exifcommon.IfdExifStandardIfdIdentity, uint16(0x8833))
  2064  	log.PanicIf(err)
  2065  
  2066  	bt := NewStandardBuilderTag(exifcommon.IfdExifStandardIfdIdentity.UnindexedString(), it, exifcommon.TestDefaultByteOrder, []uint32{uint32(0x1234)})
  2067  
  2068  	if bt.ifdPath != exifcommon.IfdExifStandardIfdIdentity.UnindexedString() {
  2069  		t.Fatalf("II in BuilderTag not correct")
  2070  	} else if bt.tagId != 0x8833 {
  2071  		t.Fatalf("tag-ID not correct")
  2072  	} else if bytes.Compare(bt.value.Bytes(), []byte{0x0, 0x0, 0x12, 0x34}) != 0 {
  2073  		t.Fatalf("value not correct")
  2074  	}
  2075  }
  2076  
  2077  func TestNewStandardBuilderTag__TwoUnits(t *testing.T) {
  2078  	ti := NewTagIndex()
  2079  
  2080  	it, err := ti.Get(exifcommon.IfdExifStandardIfdIdentity, uint16(0x8833))
  2081  	log.PanicIf(err)
  2082  
  2083  	bt := NewStandardBuilderTag(exifcommon.IfdExifStandardIfdIdentity.UnindexedString(), it, exifcommon.TestDefaultByteOrder, []uint32{uint32(0x1234), uint32(0x5678)})
  2084  
  2085  	if bt.ifdPath != exifcommon.IfdExifStandardIfdIdentity.UnindexedString() {
  2086  		t.Fatalf("II in BuilderTag not correct")
  2087  	} else if bt.tagId != 0x8833 {
  2088  		t.Fatalf("tag-ID not correct")
  2089  	} else if bytes.Compare(bt.value.Bytes(), []byte{
  2090  		0x0, 0x0, 0x12, 0x34,
  2091  		0x0, 0x0, 0x56, 0x78}) != 0 {
  2092  		t.Fatalf("value not correct")
  2093  	}
  2094  }
  2095  
  2096  func TestIfdBuilder_AddStandardWithName(t *testing.T) {
  2097  	im, err := exifcommon.NewIfdMappingWithStandard()
  2098  	log.PanicIf(err)
  2099  
  2100  	ti := NewTagIndex()
  2101  	ib := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
  2102  
  2103  	err = ib.AddStandardWithName("ProcessingSoftware", "some software")
  2104  	log.PanicIf(err)
  2105  
  2106  	if len(ib.tags) != 1 {
  2107  		t.Fatalf("Exactly one tag was not found: (%d)", len(ib.tags))
  2108  	}
  2109  
  2110  	bt := ib.tags[0]
  2111  
  2112  	if bt.ifdPath != exifcommon.IfdStandardIfdIdentity.UnindexedString() {
  2113  		t.Fatalf("II not correct: %s", bt.ifdPath)
  2114  	} else if bt.tagId != 0x000b {
  2115  		t.Fatalf("Tag-ID not correct: (0x%04x)", bt.tagId)
  2116  	}
  2117  
  2118  	s := string(bt.value.Bytes())
  2119  
  2120  	if s != "some software\000" {
  2121  		t.Fatalf("Value not correct: (%d) [%s]", len(s), s)
  2122  	}
  2123  }
  2124  
  2125  func TestGetOrCreateIbFromRootIb__Noop(t *testing.T) {
  2126  	im, err := exifcommon.NewIfdMappingWithStandard()
  2127  	log.PanicIf(err)
  2128  
  2129  	ti := NewTagIndex()
  2130  	rootIb := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
  2131  
  2132  	ib, err := GetOrCreateIbFromRootIb(rootIb, "IFD")
  2133  	log.PanicIf(err)
  2134  
  2135  	if ib != rootIb {
  2136  		t.Fatalf("Expected same IB back from no-op get-or-create.")
  2137  	} else if ib.nextIb != nil {
  2138  		t.Fatalf("Expected no siblings on IB from no-op get-or-create.")
  2139  	} else if len(ib.tags) != 0 {
  2140  		t.Fatalf("Expected no new tags on IB from no-op get-or-create.")
  2141  	}
  2142  }
  2143  
  2144  func TestGetOrCreateIbFromRootIb__FqNoop(t *testing.T) {
  2145  	im, err := exifcommon.NewIfdMappingWithStandard()
  2146  	log.PanicIf(err)
  2147  
  2148  	ti := NewTagIndex()
  2149  	rootIb := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
  2150  
  2151  	ib, err := GetOrCreateIbFromRootIb(rootIb, "IFD0")
  2152  	log.PanicIf(err)
  2153  
  2154  	if ib != rootIb {
  2155  		t.Fatalf("Expected same IB back from no-op get-or-create.")
  2156  	} else if ib.nextIb != nil {
  2157  		t.Fatalf("Expected no siblings on IB from no-op get-or-create.")
  2158  	} else if len(ib.tags) != 0 {
  2159  		t.Fatalf("Expected no new tags on IB from no-op get-or-create.")
  2160  	}
  2161  }
  2162  
  2163  func TestGetOrCreateIbFromRootIb_InvalidChild(t *testing.T) {
  2164  	im, err := exifcommon.NewIfdMappingWithStandard()
  2165  	log.PanicIf(err)
  2166  
  2167  	ti := NewTagIndex()
  2168  	rootIb := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
  2169  
  2170  	_, err = GetOrCreateIbFromRootIb(rootIb, "IFD/Invalid")
  2171  	if err == nil {
  2172  		t.Fatalf("Expected failure for invalid IFD child in IB get-or-create.")
  2173  	} else if err.Error() != "ifd child with name [Invalid] not registered: [IFD/Invalid]" {
  2174  		log.Panic(err)
  2175  	}
  2176  }
  2177  
  2178  func TestGetOrCreateIbFromRootIb__Child(t *testing.T) {
  2179  	defer func() {
  2180  		if state := recover(); state != nil {
  2181  			err := log.Wrap(state.(error))
  2182  			log.PrintErrorf(err, "Test failure.")
  2183  		}
  2184  	}()
  2185  
  2186  	im, err := exifcommon.NewIfdMappingWithStandard()
  2187  	log.PanicIf(err)
  2188  
  2189  	ti := NewTagIndex()
  2190  	rootIb := NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, exifcommon.TestDefaultByteOrder)
  2191  
  2192  	lines := rootIb.DumpToStrings()
  2193  	expected := []string{
  2194  		"IFD<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-INDEX=(0) IFD-TAG-ID=(0x0000) TAG=[0x0000]>",
  2195  	}
  2196  
  2197  	if reflect.DeepEqual(lines, expected) != true {
  2198  		fmt.Printf("ACTUAL:\n")
  2199  		fmt.Printf("\n")
  2200  
  2201  		for i, line := range lines {
  2202  			fmt.Printf("%d: %s\n", i, line)
  2203  		}
  2204  
  2205  		fmt.Printf("\n")
  2206  
  2207  		fmt.Printf("EXPECTED:\n")
  2208  		fmt.Printf("\n")
  2209  
  2210  		for i, line := range expected {
  2211  			fmt.Printf("%d: %s\n", i, line)
  2212  		}
  2213  
  2214  		fmt.Printf("\n")
  2215  
  2216  		t.Fatalf("Constructed IFDs not correct.")
  2217  	}
  2218  
  2219  	ib, err := GetOrCreateIbFromRootIb(rootIb, "IFD/Exif")
  2220  	log.PanicIf(err)
  2221  
  2222  	if ib.IfdIdentity().String() != "IFD/Exif" {
  2223  		t.Fatalf("Returned IB does not have the expected path (IFD/Exif).")
  2224  	}
  2225  
  2226  	lines = rootIb.DumpToStrings()
  2227  	expected = []string{
  2228  		"IFD<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-INDEX=(0) IFD-TAG-ID=(0x0000) TAG=[0x0000]>",
  2229  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[IFD/Exif] TAG-INDEX=(0) TAG=[0x8769]>",
  2230  		"IFD<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-INDEX=(0) IFD-TAG-ID=(0x8769) TAG=[0x8769]>",
  2231  	}
  2232  
  2233  	if reflect.DeepEqual(lines, expected) != true {
  2234  		fmt.Printf("ACTUAL:\n")
  2235  		fmt.Printf("\n")
  2236  
  2237  		for i, line := range lines {
  2238  			fmt.Printf("%d: %s\n", i, line)
  2239  		}
  2240  
  2241  		fmt.Printf("\n")
  2242  
  2243  		fmt.Printf("EXPECTED:\n")
  2244  		fmt.Printf("\n")
  2245  
  2246  		for i, line := range expected {
  2247  			fmt.Printf("%d: %s\n", i, line)
  2248  		}
  2249  
  2250  		fmt.Printf("\n")
  2251  
  2252  		t.Fatalf("Constructed IFDs not correct.")
  2253  	}
  2254  
  2255  	ib, err = GetOrCreateIbFromRootIb(rootIb, "IFD0/Exif/Iop")
  2256  	log.PanicIf(err)
  2257  
  2258  	if ib.IfdIdentity().String() != "IFD/Exif/Iop" {
  2259  		t.Fatalf("Returned IB does not have the expected path (IFD/Exif/Iop).")
  2260  	}
  2261  
  2262  	lines = rootIb.DumpToStrings()
  2263  	expected = []string{
  2264  		"IFD<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-INDEX=(0) IFD-TAG-ID=(0x0000) TAG=[0x0000]>",
  2265  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[IFD/Exif] TAG-INDEX=(0) TAG=[0x8769]>",
  2266  		"IFD<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-INDEX=(0) IFD-TAG-ID=(0x8769) TAG=[0x8769]>",
  2267  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[IFD/Exif/Iop] TAG-INDEX=(0) TAG=[0xa005]>",
  2268  		"IFD<PARENTS=[IFD->IFD/Exif] FQ-IFD-PATH=[IFD/Exif/Iop] IFD-INDEX=(0) IFD-TAG-ID=(0xa005) TAG=[0xa005]>",
  2269  	}
  2270  
  2271  	if reflect.DeepEqual(lines, expected) != true {
  2272  		fmt.Printf("ACTUAL:\n")
  2273  		fmt.Printf("\n")
  2274  
  2275  		for i, line := range lines {
  2276  			fmt.Printf("%d: %s\n", i, line)
  2277  		}
  2278  
  2279  		fmt.Printf("\n")
  2280  
  2281  		fmt.Printf("EXPECTED:\n")
  2282  		fmt.Printf("\n")
  2283  
  2284  		for i, line := range expected {
  2285  			fmt.Printf("%d: %s\n", i, line)
  2286  		}
  2287  
  2288  		fmt.Printf("\n")
  2289  
  2290  		t.Fatalf("Constructed IFDs not correct.")
  2291  	}
  2292  
  2293  	ib, err = GetOrCreateIbFromRootIb(rootIb, "IFD1")
  2294  	log.PanicIf(err)
  2295  
  2296  	if ib.IfdIdentity().String() != "IFD1" {
  2297  		t.Fatalf("Returned IB does not have the expected path (IFD1).")
  2298  	}
  2299  
  2300  	lines = rootIb.DumpToStrings()
  2301  	expected = []string{
  2302  		"IFD<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-INDEX=(0) IFD-TAG-ID=(0x0000) TAG=[0x0000]>",
  2303  		"TAG<PARENTS=[] FQ-IFD-PATH=[IFD] IFD-TAG-ID=(0x0000) CHILD-IFD=[IFD/Exif] TAG-INDEX=(0) TAG=[0x8769]>",
  2304  		"IFD<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-INDEX=(0) IFD-TAG-ID=(0x8769) TAG=[0x8769]>",
  2305  		"TAG<PARENTS=[IFD] FQ-IFD-PATH=[IFD/Exif] IFD-TAG-ID=(0x8769) CHILD-IFD=[IFD/Exif/Iop] TAG-INDEX=(0) TAG=[0xa005]>",
  2306  		"IFD<PARENTS=[IFD->IFD/Exif] FQ-IFD-PATH=[IFD/Exif/Iop] IFD-INDEX=(0) IFD-TAG-ID=(0xa005) TAG=[0xa005]>",
  2307  		"IFD<PARENTS=[] FQ-IFD-PATH=[IFD1] IFD-INDEX=(1) IFD-TAG-ID=(0x0000) TAG=[0x0000]>",
  2308  	}
  2309  
  2310  	if reflect.DeepEqual(lines, expected) != true {
  2311  		fmt.Printf("ACTUAL:\n")
  2312  		fmt.Printf("\n")
  2313  
  2314  		for i, line := range lines {
  2315  			fmt.Printf("%d: %s\n", i, line)
  2316  		}
  2317  
  2318  		fmt.Printf("\n")
  2319  
  2320  		fmt.Printf("EXPECTED:\n")
  2321  		fmt.Printf("\n")
  2322  
  2323  		for i, line := range expected {
  2324  			fmt.Printf("%d: %s\n", i, line)
  2325  		}
  2326  
  2327  		fmt.Printf("\n")
  2328  
  2329  		t.Fatalf("Constructed IFDs not correct.")
  2330  	}
  2331  }
  2332  

View as plain text