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
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
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
1404
1405 ibe := NewIfdByteEncoder()
1406
1407 updatedRawExif, err := ibe.EncodeToExif(rootIb)
1408 log.PanicIf(err)
1409
1410
1411
1412 _, updatedIndex, err := Collect(im, ti, updatedRawExif)
1413 log.PanicIf(err)
1414
1415 updatedRootIfd := updatedIndex.RootIfd
1416
1417
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
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
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
1477
1478 ibe := NewIfdByteEncoder()
1479
1480 updatedRawExif, err := ibe.EncodeToExif(rootIb)
1481 log.PanicIf(err)
1482
1483
1484
1485 _, updatedIndex, err := Collect(im, ti, updatedRawExif)
1486 log.PanicIf(err)
1487
1488 updatedRootIfd := updatedIndex.RootIfd
1489
1490
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
1501
1502
1503
1504
1505
1506 }
1507
1508 func ExampleIfdBuilder_SetStandardWithName_timestamp() {
1509
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
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
1539
1540 ibe := NewIfdByteEncoder()
1541
1542 updatedRawExif, err := ibe.EncodeToExif(rootIb)
1543 log.PanicIf(err)
1544
1545
1546
1547 _, updatedIndex, err := Collect(im, ti, updatedRawExif)
1548 log.PanicIf(err)
1549
1550 updatedRootIfd := updatedIndex.RootIfd
1551
1552
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
1568
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
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
1593
1594 ibe := NewIfdByteEncoder()
1595
1596 rootIb := NewIfdBuilderFromExistingChain(originalIndex.RootIfd)
1597
1598 updatedExif, err := ibe.EncodeToExif(rootIb)
1599 log.PanicIf(err)
1600
1601
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
1612
1613 if bytes.Compare(recoveredThumbnailData, originalThumbnailData) != 0 {
1614 t.Fatalf("recovered thumbnail does not match original")
1615 }
1616
1617
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
1652
1653
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
1662
1663 if ite.IsThumbnailOffset() == true || ite.IsThumbnailSize() == true {
1664 continue
1665 }
1666
1667 phrase := ite.String()
1668
1669
1670
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
1686
1687 if ite.IsThumbnailOffset() == true || ite.IsThumbnailSize() == true {
1688 continue
1689 }
1690
1691 phrase := ite.String()
1692
1693
1694
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
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
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
1884
1885 _, err = index.RootIfd.nextIfd.Thumbnail()
1886 log.PanicIf(err)
1887
1888
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
1906
1907 rootIb := NewIfdBuilderFromExistingChain(index.RootIfd)
1908
1909
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
1918
1919
1920
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
1930
1931 ibe := NewIfdByteEncoder()
1932
1933
1934
1935 _, err = ibe.EncodeToExif(rootIb)
1936 log.PanicIf(err)
1937
1938
1939 }
1940
1941
1942
1943
1944
1945
1946 func ExampleIfdBuilder_SetStandardWithName() {
1947 testImageFilepath := getTestImageFilepath()
1948
1949 rawExif, err := SearchFileAndExtractExif(testImageFilepath)
1950 log.PanicIf(err)
1951
1952
1953
1954 im, err := exifcommon.NewIfdMappingWithStandard()
1955 log.PanicIf(err)
1956
1957 ti := NewTagIndex()
1958
1959
1960
1961 _, index, err := Collect(im, ti, rawExif)
1962 log.PanicIf(err)
1963
1964 ib := NewIfdBuilderFromExistingChain(index.RootIfd)
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976 ifdPath := "IFD0"
1977
1978 childIb, err := GetOrCreateIbFromRootIb(ib, ifdPath)
1979 log.PanicIf(err)
1980
1981
1982
1983
1984 tagName := "ProcessingSoftware"
1985
1986 err = childIb.SetStandardWithName(tagName, "alternative software")
1987 log.PanicIf(err)
1988
1989
1990
1991 ibe := NewIfdByteEncoder()
1992
1993 updatedRawExif, err := ibe.EncodeToExif(ib)
1994 log.PanicIf(err)
1995
1996
1997
1998 _, index, err = Collect(im, ti, updatedRawExif)
1999 log.PanicIf(err)
2000
2001
2002
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
2018
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