1 package exif
2
3
4
5
6
7
8 import (
9 "errors"
10 "fmt"
11 "strings"
12
13 "encoding/binary"
14
15 "github.com/dsoprea/go-logging"
16
17 "github.com/dsoprea/go-exif/v3/common"
18 "github.com/dsoprea/go-exif/v3/undefined"
19 )
20
21 var (
22 ifdBuilderLogger = log.NewLogger("exif.ifd_builder")
23 )
24
25 var (
26 ErrTagEntryNotFound = errors.New("tag entry not found")
27 ErrChildIbNotFound = errors.New("child IB not found")
28 )
29
30 type IfdBuilderTagValue struct {
31 valueBytes []byte
32 ib *IfdBuilder
33 }
34
35 func (ibtv IfdBuilderTagValue) String() string {
36 if ibtv.IsBytes() == true {
37 var valuePhrase string
38 if len(ibtv.valueBytes) <= 8 {
39 valuePhrase = fmt.Sprintf("%v", ibtv.valueBytes)
40 } else {
41 valuePhrase = fmt.Sprintf("%v...", ibtv.valueBytes[:8])
42 }
43
44 return fmt.Sprintf("IfdBuilderTagValue<BYTES=%v LEN=(%d)>", valuePhrase, len(ibtv.valueBytes))
45 } else if ibtv.IsIb() == true {
46 return fmt.Sprintf("IfdBuilderTagValue<IB=%s>", ibtv.ib)
47 } else {
48 log.Panicf("IBTV state undefined")
49 return ""
50 }
51 }
52
53 func NewIfdBuilderTagValueFromBytes(valueBytes []byte) *IfdBuilderTagValue {
54 return &IfdBuilderTagValue{
55 valueBytes: valueBytes,
56 }
57 }
58
59 func NewIfdBuilderTagValueFromIfdBuilder(ib *IfdBuilder) *IfdBuilderTagValue {
60 return &IfdBuilderTagValue{
61 ib: ib,
62 }
63 }
64
65
66
67 func (ibtv IfdBuilderTagValue) IsBytes() bool {
68 return ibtv.valueBytes != nil
69 }
70
71 func (ibtv IfdBuilderTagValue) Bytes() []byte {
72 if ibtv.IsBytes() == false {
73 log.Panicf("this tag is not a byte-slice value")
74 } else if ibtv.IsIb() == true {
75 log.Panicf("this tag is an IFD-builder value not a byte-slice")
76 }
77
78 return ibtv.valueBytes
79 }
80
81 func (ibtv IfdBuilderTagValue) IsIb() bool {
82 return ibtv.ib != nil
83 }
84
85 func (ibtv IfdBuilderTagValue) Ib() *IfdBuilder {
86 if ibtv.IsIb() == false {
87 log.Panicf("this tag is not an IFD-builder value")
88 } else if ibtv.IsBytes() == true {
89 log.Panicf("this tag is a byte-slice, not a IFD-builder")
90 }
91
92 return ibtv.ib
93 }
94
95 type BuilderTag struct {
96
97 ifdPath string
98
99 tagId uint16
100 typeId exifcommon.TagTypePrimitive
101
102
103
104
105 value *IfdBuilderTagValue
106
107
108
109 byteOrder binary.ByteOrder
110 }
111
112 func NewBuilderTag(ifdPath string, tagId uint16, typeId exifcommon.TagTypePrimitive, value *IfdBuilderTagValue, byteOrder binary.ByteOrder) *BuilderTag {
113 return &BuilderTag{
114 ifdPath: ifdPath,
115 tagId: tagId,
116 typeId: typeId,
117 value: value,
118 byteOrder: byteOrder,
119 }
120 }
121
122 func NewChildIfdBuilderTag(ifdPath string, tagId uint16, value *IfdBuilderTagValue) *BuilderTag {
123 return &BuilderTag{
124 ifdPath: ifdPath,
125 tagId: tagId,
126 typeId: exifcommon.TypeLong,
127 value: value,
128 }
129 }
130
131 func (bt *BuilderTag) Value() (value *IfdBuilderTagValue) {
132 return bt.value
133 }
134
135 func (bt *BuilderTag) String() string {
136 var valueString string
137
138 if bt.value.IsBytes() == true {
139 var err error
140
141 valueString, err = exifcommon.FormatFromBytes(bt.value.Bytes(), bt.typeId, false, bt.byteOrder)
142 log.PanicIf(err)
143 } else {
144 valueString = fmt.Sprintf("%v", bt.value)
145 }
146
147 return fmt.Sprintf("BuilderTag<IFD-PATH=[%s] TAG-ID=(0x%04x) TAG-TYPE=[%s] VALUE=[%s]>", bt.ifdPath, bt.tagId, bt.typeId.String(), valueString)
148 }
149
150 func (bt *BuilderTag) SetValue(byteOrder binary.ByteOrder, value interface{}) (err error) {
151 defer func() {
152 if state := recover(); state != nil {
153 err = log.Wrap(state.(error))
154 }
155 }()
156
157
158
159 var ed exifcommon.EncodedData
160 if bt.typeId == exifcommon.TypeUndefined {
161 encodeable := value.(exifundefined.EncodeableValue)
162
163 encoded, unitCount, err := exifundefined.Encode(encodeable, byteOrder)
164 log.PanicIf(err)
165
166 ed = exifcommon.EncodedData{
167 Type: exifcommon.TypeUndefined,
168 Encoded: encoded,
169 UnitCount: unitCount,
170 }
171 } else {
172 ve := exifcommon.NewValueEncoder(byteOrder)
173
174 var err error
175
176 ed, err = ve.Encode(value)
177 log.PanicIf(err)
178 }
179
180 bt.value = NewIfdBuilderTagValueFromBytes(ed.Encoded)
181
182 return nil
183 }
184
185
186
187 func NewStandardBuilderTag(ifdPath string, it *IndexedTag, byteOrder binary.ByteOrder, value interface{}) *BuilderTag {
188
189
190
191 tagType := it.GetEncodingType(value)
192
193 var rawBytes []byte
194 if it.DoesSupportType(exifcommon.TypeUndefined) == true {
195 encodeable := value.(exifundefined.EncodeableValue)
196
197 var err error
198
199 rawBytes, _, err = exifundefined.Encode(encodeable, byteOrder)
200 log.PanicIf(err)
201 } else {
202 ve := exifcommon.NewValueEncoder(byteOrder)
203
204 ed, err := ve.Encode(value)
205 log.PanicIf(err)
206
207 rawBytes = ed.Encoded
208 }
209
210 tagValue := NewIfdBuilderTagValueFromBytes(rawBytes)
211
212 return NewBuilderTag(
213 ifdPath,
214 it.Id,
215 tagType,
216 tagValue,
217 byteOrder)
218 }
219
220 type IfdBuilder struct {
221 ifdIdentity *exifcommon.IfdIdentity
222
223 byteOrder binary.ByteOrder
224
225
226
227
228 tags []*BuilderTag
229
230
231
232 existingOffset uint32
233
234
235 nextIb *IfdBuilder
236
237
238
239 thumbnailData []byte
240
241 ifdMapping *exifcommon.IfdMapping
242 tagIndex *TagIndex
243 }
244
245 func NewIfdBuilder(ifdMapping *exifcommon.IfdMapping, tagIndex *TagIndex, ii *exifcommon.IfdIdentity, byteOrder binary.ByteOrder) (ib *IfdBuilder) {
246 ib = &IfdBuilder{
247 ifdIdentity: ii,
248
249 byteOrder: byteOrder,
250 tags: make([]*BuilderTag, 0),
251
252 ifdMapping: ifdMapping,
253 tagIndex: tagIndex,
254 }
255
256 return ib
257 }
258
259
260
261 func NewIfdBuilderWithExistingIfd(ifd *Ifd) (ib *IfdBuilder) {
262 ib = &IfdBuilder{
263 ifdIdentity: ifd.IfdIdentity(),
264
265 byteOrder: ifd.ByteOrder(),
266 existingOffset: ifd.Offset(),
267 ifdMapping: ifd.ifdMapping,
268 tagIndex: ifd.tagIndex,
269 }
270
271 return ib
272 }
273
274
275
276 func NewIfdBuilderFromExistingChain(rootIfd *Ifd) (firstIb *IfdBuilder) {
277 var lastIb *IfdBuilder
278 i := 0
279 for thisExistingIfd := rootIfd; thisExistingIfd != nil; thisExistingIfd = thisExistingIfd.nextIfd {
280 newIb := NewIfdBuilder(
281 rootIfd.ifdMapping,
282 rootIfd.tagIndex,
283 rootIfd.ifdIdentity,
284 thisExistingIfd.ByteOrder())
285
286 if firstIb == nil {
287 firstIb = newIb
288 } else {
289 lastIb.SetNextIb(newIb)
290 }
291
292 err := newIb.AddTagsFromExisting(thisExistingIfd, nil, nil)
293 log.PanicIf(err)
294
295 lastIb = newIb
296 i++
297 }
298
299 return firstIb
300 }
301
302 func (ib *IfdBuilder) IfdIdentity() *exifcommon.IfdIdentity {
303 return ib.ifdIdentity
304 }
305
306 func (ib *IfdBuilder) NextIb() (nextIb *IfdBuilder, err error) {
307 return ib.nextIb, nil
308 }
309
310 func (ib *IfdBuilder) ChildWithTagId(childIfdTagId uint16) (childIb *IfdBuilder, err error) {
311 defer func() {
312 if state := recover(); state != nil {
313 err = log.Wrap(state.(error))
314 }
315 }()
316
317 for _, bt := range ib.tags {
318 if bt.value.IsIb() == false {
319 continue
320 }
321
322 childIbThis := bt.value.Ib()
323
324 if childIbThis.IfdIdentity().TagId() == childIfdTagId {
325 return childIbThis, nil
326 }
327 }
328
329 log.Panic(ErrChildIbNotFound)
330
331
332 return nil, nil
333 }
334
335 func getOrCreateIbFromRootIbInner(rootIb *IfdBuilder, parentIb *IfdBuilder, currentLineage []exifcommon.IfdTagIdAndIndex) (ib *IfdBuilder, err error) {
336 defer func() {
337 if state := recover(); state != nil {
338 err = log.Wrap(state.(error))
339 }
340 }()
341
342
343
344 thisIb := rootIb
345
346
347
348
349 var parentLineage []exifcommon.IfdTagIdAndIndex
350 if parentIb != nil {
351 var err error
352
353 parentLineage, err = thisIb.ifdMapping.ResolvePath(parentIb.IfdIdentity().String())
354 log.PanicIf(err)
355 }
356
357
358 currentItIi := currentLineage[0]
359
360
361
362
363 expectedFqRootIfdPath := ""
364 if parentLineage != nil {
365 expectedLineage := append(parentLineage, currentItIi)
366 expectedFqRootIfdPath = thisIb.ifdMapping.PathPhraseFromLineage(expectedLineage)
367 } else {
368 expectedFqRootIfdPath = thisIb.ifdMapping.PathPhraseFromLineage(currentLineage[:1])
369 }
370
371 if expectedFqRootIfdPath != thisIb.IfdIdentity().String() {
372 log.Panicf("the FQ IFD-path [%s] we were given does not match the builder's FQ IFD-path [%s]", expectedFqRootIfdPath, thisIb.IfdIdentity().String())
373 }
374
375
376
377 for i := 0; i < currentItIi.Index; i++ {
378 if thisIb.nextIb == nil {
379
380
381
382 iiSibling := thisIb.IfdIdentity().NewSibling(i + 1)
383 thisIb.nextIb = NewIfdBuilder(thisIb.ifdMapping, thisIb.tagIndex, iiSibling, thisIb.byteOrder)
384 }
385
386 thisIb = thisIb.nextIb
387 }
388
389
390 if len(currentLineage) == 1 {
391 return thisIb, nil
392 }
393
394
395
396 childItii := currentLineage[1]
397
398 var foundChild *IfdBuilder
399 for _, bt := range thisIb.tags {
400 if bt.value.IsIb() == false {
401 continue
402 }
403
404 childIb := bt.value.Ib()
405
406 if childIb.IfdIdentity().TagId() == childItii.TagId {
407 foundChild = childIb
408 break
409 }
410 }
411
412
413
414 if foundChild == nil {
415 currentIfdTag := thisIb.IfdIdentity().IfdTag()
416
417 childIfdTag :=
418 exifcommon.NewIfdTag(
419 ¤tIfdTag,
420 childItii.TagId,
421 childItii.Name)
422
423 iiChild := thisIb.IfdIdentity().NewChild(childIfdTag, 0)
424
425 foundChild =
426 NewIfdBuilder(
427 thisIb.ifdMapping,
428 thisIb.tagIndex,
429 iiChild,
430 thisIb.byteOrder)
431
432 err = thisIb.AddChildIb(foundChild)
433 log.PanicIf(err)
434 }
435
436 finalIb, err := getOrCreateIbFromRootIbInner(foundChild, thisIb, currentLineage[1:])
437 log.PanicIf(err)
438
439 return finalIb, nil
440 }
441
442
443
444
445 func GetOrCreateIbFromRootIb(rootIb *IfdBuilder, fqIfdPath string) (ib *IfdBuilder, err error) {
446 defer func() {
447 if state := recover(); state != nil {
448 err = log.Wrap(state.(error))
449 }
450 }()
451
452
453
454 lineage, err := rootIb.ifdMapping.ResolvePath(fqIfdPath)
455 log.PanicIf(err)
456
457 ib, err = getOrCreateIbFromRootIbInner(rootIb, nil, lineage)
458 log.PanicIf(err)
459
460 return ib, nil
461 }
462
463 func (ib *IfdBuilder) String() string {
464 nextIfdPhrase := ""
465 if ib.nextIb != nil {
466
467 nextIfdPhrase = ib.nextIb.IfdIdentity().UnindexedString()
468 }
469
470 return fmt.Sprintf("IfdBuilder<PATH=[%s] TAG-ID=(0x%04x) COUNT=(%d) OFF=(0x%04x) NEXT-IFD-PATH=[%s]>", ib.IfdIdentity().UnindexedString(), ib.IfdIdentity().TagId(), len(ib.tags), ib.existingOffset, nextIfdPhrase)
471 }
472
473 func (ib *IfdBuilder) Tags() (tags []*BuilderTag) {
474 return ib.tags
475 }
476
477
478
479
480
481
482
483
484
485
486
487
488 func (ib *IfdBuilder) SetThumbnail(data []byte) (err error) {
489 defer func() {
490 if state := recover(); state != nil {
491 err = log.Wrap(state.(error))
492 }
493 }()
494
495 if ib.IfdIdentity().UnindexedString() != exifcommon.IfdStandardIfdIdentity.UnindexedString() {
496 log.Panicf("thumbnails can only go into a root Ifd (and only the second one)")
497 }
498
499
500
501 if data == nil || len(data) == 0 {
502 log.Panic("thumbnail is empty")
503 }
504
505 ib.thumbnailData = data
506
507 ibtvfb := NewIfdBuilderTagValueFromBytes(ib.thumbnailData)
508 offsetBt :=
509 NewBuilderTag(
510 ib.IfdIdentity().UnindexedString(),
511 ThumbnailOffsetTagId,
512 exifcommon.TypeLong,
513 ibtvfb,
514 ib.byteOrder)
515
516 err = ib.Set(offsetBt)
517 log.PanicIf(err)
518
519 thumbnailSizeIt, err := ib.tagIndex.Get(ib.IfdIdentity(), ThumbnailSizeTagId)
520 log.PanicIf(err)
521
522 sizeBt := NewStandardBuilderTag(ib.IfdIdentity().UnindexedString(), thumbnailSizeIt, ib.byteOrder, []uint32{uint32(len(ib.thumbnailData))})
523
524 err = ib.Set(sizeBt)
525 log.PanicIf(err)
526
527 return nil
528 }
529
530 func (ib *IfdBuilder) Thumbnail() []byte {
531 return ib.thumbnailData
532 }
533
534 func (ib *IfdBuilder) printTagTree(levels int) {
535 indent := strings.Repeat(" ", levels*2)
536
537 i := 0
538 for currentIb := ib; currentIb != nil; currentIb = currentIb.nextIb {
539 prefix := " "
540 if i > 0 {
541 prefix = ">"
542 }
543
544 if levels == 0 {
545 fmt.Printf("%s%sIFD: %s INDEX=(%d)\n", indent, prefix, currentIb, i)
546 } else {
547 fmt.Printf("%s%sChild IFD: %s\n", indent, prefix, currentIb)
548 }
549
550 if len(currentIb.tags) > 0 {
551 fmt.Printf("\n")
552
553 for i, tag := range currentIb.tags {
554 isChildIb := false
555 _, err := ib.ifdMapping.GetChild(currentIb.IfdIdentity().UnindexedString(), tag.tagId)
556 if err == nil {
557 isChildIb = true
558 } else if log.Is(err, exifcommon.ErrChildIfdNotMapped) == false {
559 log.Panic(err)
560 }
561
562 tagName := ""
563
564
565 if isChildIb == true {
566 tagName = "<Child IFD>"
567 } else {
568 it, err := ib.tagIndex.Get(ib.ifdIdentity, tag.tagId)
569 if log.Is(err, ErrTagNotFound) == true {
570 tagName = "<UNKNOWN>"
571 } else if err != nil {
572 log.Panic(err)
573 } else {
574 tagName = it.Name
575 }
576 }
577
578 value := tag.Value()
579
580 if value.IsIb() == true {
581 fmt.Printf("%s (%d): [%s] %s\n", indent, i, tagName, value.Ib())
582 } else {
583 fmt.Printf("%s (%d): [%s] %s\n", indent, i, tagName, tag)
584 }
585
586 if isChildIb == true {
587 if tag.value.IsIb() == false {
588 log.Panicf("tag-ID (0x%04x) is an IFD but the tag value is not an IB instance: %v", tag.tagId, tag)
589 }
590
591 fmt.Printf("\n")
592
593 childIb := tag.value.Ib()
594 childIb.printTagTree(levels + 1)
595 }
596 }
597
598 fmt.Printf("\n")
599 }
600
601 i++
602 }
603 }
604
605 func (ib *IfdBuilder) PrintTagTree() {
606 ib.printTagTree(0)
607 }
608
609 func (ib *IfdBuilder) printIfdTree(levels int) {
610 indent := strings.Repeat(" ", levels*2)
611
612 i := 0
613 for currentIb := ib; currentIb != nil; currentIb = currentIb.nextIb {
614 prefix := " "
615 if i > 0 {
616 prefix = ">"
617 }
618
619 fmt.Printf("%s%s%s\n", indent, prefix, currentIb)
620
621 if len(currentIb.tags) > 0 {
622 for _, tag := range currentIb.tags {
623 isChildIb := false
624 _, err := ib.ifdMapping.GetChild(currentIb.IfdIdentity().UnindexedString(), tag.tagId)
625 if err == nil {
626 isChildIb = true
627 } else if log.Is(err, exifcommon.ErrChildIfdNotMapped) == false {
628 log.Panic(err)
629 }
630
631 if isChildIb == true {
632 if tag.value.IsIb() == false {
633 log.Panicf("tag-ID (0x%04x) is an IFD but the tag value is not an IB instance: %v", tag.tagId, tag)
634 }
635
636 childIb := tag.value.Ib()
637 childIb.printIfdTree(levels + 1)
638 }
639 }
640 }
641
642 i++
643 }
644 }
645
646 func (ib *IfdBuilder) PrintIfdTree() {
647 ib.printIfdTree(0)
648 }
649
650 func (ib *IfdBuilder) dumpToStrings(thisIb *IfdBuilder, prefix string, tagId uint16, lines []string) (linesOutput []string) {
651 if lines == nil {
652 linesOutput = make([]string, 0)
653 } else {
654 linesOutput = lines
655 }
656
657 siblingIfdIndex := 0
658 for ; thisIb != nil; thisIb = thisIb.nextIb {
659 line := fmt.Sprintf("IFD<PARENTS=[%s] FQ-IFD-PATH=[%s] IFD-INDEX=(%d) IFD-TAG-ID=(0x%04x) TAG=[0x%04x]>", prefix, thisIb.IfdIdentity().String(), siblingIfdIndex, thisIb.IfdIdentity().TagId(), tagId)
660 linesOutput = append(linesOutput, line)
661
662 for i, tag := range thisIb.tags {
663 var childIb *IfdBuilder
664 childIfdName := ""
665 if tag.value.IsIb() == true {
666 childIb = tag.value.Ib()
667 childIfdName = childIb.IfdIdentity().UnindexedString()
668 }
669
670 line := fmt.Sprintf("TAG<PARENTS=[%s] FQ-IFD-PATH=[%s] IFD-TAG-ID=(0x%04x) CHILD-IFD=[%s] TAG-INDEX=(%d) TAG=[0x%04x]>", prefix, thisIb.IfdIdentity().String(), thisIb.IfdIdentity().TagId(), childIfdName, i, tag.tagId)
671 linesOutput = append(linesOutput, line)
672
673 if childIb == nil {
674 continue
675 }
676
677 childPrefix := ""
678 if prefix == "" {
679 childPrefix = fmt.Sprintf("%s", thisIb.IfdIdentity().UnindexedString())
680 } else {
681 childPrefix = fmt.Sprintf("%s->%s", prefix, thisIb.IfdIdentity().UnindexedString())
682 }
683
684 linesOutput = thisIb.dumpToStrings(childIb, childPrefix, tag.tagId, linesOutput)
685 }
686
687 siblingIfdIndex++
688 }
689
690 return linesOutput
691 }
692
693 func (ib *IfdBuilder) DumpToStrings() (lines []string) {
694 return ib.dumpToStrings(ib, "", 0, lines)
695 }
696
697 func (ib *IfdBuilder) SetNextIb(nextIb *IfdBuilder) (err error) {
698 defer func() {
699 if state := recover(); state != nil {
700 err = log.Wrap(state.(error))
701 }
702 }()
703
704 ib.nextIb = nextIb
705
706 return nil
707 }
708
709 func (ib *IfdBuilder) DeleteN(tagId uint16, n int) (err error) {
710 defer func() {
711 if state := recover(); state != nil {
712 err = log.Wrap(state.(error))
713 }
714 }()
715
716 if n < 1 {
717 log.Panicf("N must be at least 1: (%d)", n)
718 }
719
720 for n > 0 {
721 j := -1
722 for i, bt := range ib.tags {
723 if bt.tagId == tagId {
724 j = i
725 break
726 }
727 }
728
729 if j == -1 {
730 log.Panic(ErrTagEntryNotFound)
731 }
732
733 ib.tags = append(ib.tags[:j], ib.tags[j+1:]...)
734 n--
735 }
736
737 return nil
738 }
739
740 func (ib *IfdBuilder) DeleteFirst(tagId uint16) (err error) {
741 defer func() {
742 if state := recover(); state != nil {
743 err = log.Wrap(state.(error))
744 }
745 }()
746
747 err = ib.DeleteN(tagId, 1)
748 log.PanicIf(err)
749
750 return nil
751 }
752
753 func (ib *IfdBuilder) DeleteAll(tagId uint16) (n int, err error) {
754 defer func() {
755 if state := recover(); state != nil {
756 err = log.Wrap(state.(error))
757 }
758 }()
759
760 for {
761 err = ib.DeleteN(tagId, 1)
762 if log.Is(err, ErrTagEntryNotFound) == true {
763 break
764 } else if err != nil {
765 log.Panic(err)
766 }
767
768 n++
769 }
770
771 return n, nil
772 }
773
774 func (ib *IfdBuilder) ReplaceAt(position int, bt *BuilderTag) (err error) {
775 defer func() {
776 if state := recover(); state != nil {
777 err = log.Wrap(state.(error))
778 }
779 }()
780
781 if position < 0 {
782 log.Panicf("replacement position must be 0 or greater")
783 } else if position >= len(ib.tags) {
784 log.Panicf("replacement position does not exist")
785 }
786
787 ib.tags[position] = bt
788
789 return nil
790 }
791
792 func (ib *IfdBuilder) Replace(tagId uint16, bt *BuilderTag) (err error) {
793 defer func() {
794 if state := recover(); state != nil {
795 err = log.Wrap(state.(error))
796 }
797 }()
798
799 position, err := ib.Find(tagId)
800 log.PanicIf(err)
801
802 ib.tags[position] = bt
803
804 return nil
805 }
806
807
808 func (ib *IfdBuilder) Set(bt *BuilderTag) (err error) {
809 defer func() {
810 if state := recover(); state != nil {
811 err = log.Wrap(state.(error))
812 }
813 }()
814
815 position, err := ib.Find(bt.tagId)
816 if err == nil {
817 ib.tags[position] = bt
818 } else if log.Is(err, ErrTagEntryNotFound) == true {
819 err = ib.add(bt)
820 log.PanicIf(err)
821 } else {
822 log.Panic(err)
823 }
824
825 return nil
826 }
827
828 func (ib *IfdBuilder) FindN(tagId uint16, maxFound int) (found []int, err error) {
829 defer func() {
830 if state := recover(); state != nil {
831 err = log.Wrap(state.(error))
832 }
833 }()
834
835 found = make([]int, 0)
836
837 for i, bt := range ib.tags {
838 if bt.tagId == tagId {
839 found = append(found, i)
840 if maxFound == 0 || len(found) >= maxFound {
841 break
842 }
843 }
844 }
845
846 return found, nil
847 }
848
849 func (ib *IfdBuilder) Find(tagId uint16) (position int, err error) {
850 defer func() {
851 if state := recover(); state != nil {
852 err = log.Wrap(state.(error))
853 }
854 }()
855
856 found, err := ib.FindN(tagId, 1)
857 log.PanicIf(err)
858
859 if len(found) == 0 {
860 log.Panic(ErrTagEntryNotFound)
861 }
862
863 return found[0], nil
864 }
865
866 func (ib *IfdBuilder) FindTag(tagId uint16) (bt *BuilderTag, err error) {
867 defer func() {
868 if state := recover(); state != nil {
869 err = log.Wrap(state.(error))
870 }
871 }()
872
873 found, err := ib.FindN(tagId, 1)
874 log.PanicIf(err)
875
876 if len(found) == 0 {
877 log.Panic(ErrTagEntryNotFound)
878 }
879
880 position := found[0]
881
882 return ib.tags[position], nil
883 }
884
885 func (ib *IfdBuilder) FindTagWithName(tagName string) (bt *BuilderTag, err error) {
886 defer func() {
887 if state := recover(); state != nil {
888 err = log.Wrap(state.(error))
889 }
890 }()
891
892 it, err := ib.tagIndex.GetWithName(ib.IfdIdentity(), tagName)
893 log.PanicIf(err)
894
895 found, err := ib.FindN(it.Id, 1)
896 log.PanicIf(err)
897
898 if len(found) == 0 {
899 log.Panic(ErrTagEntryNotFound)
900 }
901
902 position := found[0]
903
904 return ib.tags[position], nil
905 }
906
907 func (ib *IfdBuilder) add(bt *BuilderTag) (err error) {
908 defer func() {
909 if state := recover(); state != nil {
910 err = log.Wrap(state.(error))
911 }
912 }()
913
914 if bt.ifdPath == "" {
915 log.Panicf("BuilderTag ifdPath is not set: %s", bt)
916 } else if bt.typeId == 0x0 {
917 log.Panicf("BuilderTag type-ID is not set: %s", bt)
918 } else if bt.value == nil {
919 log.Panicf("BuilderTag value is not set: %s", bt)
920 }
921
922 ib.tags = append(ib.tags, bt)
923 return nil
924 }
925
926 func (ib *IfdBuilder) Add(bt *BuilderTag) (err error) {
927 defer func() {
928 if state := recover(); state != nil {
929 err = log.Wrap(state.(error))
930 }
931 }()
932
933 if bt.value.IsIb() == true {
934 log.Panicf("child IfdBuilders must be added via AddChildIb() or AddTagsFromExisting(), not Add()")
935 }
936
937 err = ib.add(bt)
938 log.PanicIf(err)
939
940 return nil
941 }
942
943
944 func (ib *IfdBuilder) AddChildIb(childIb *IfdBuilder) (err error) {
945 defer func() {
946 if state := recover(); state != nil {
947 err = log.Wrap(state.(error))
948 }
949 }()
950
951 if childIb.IfdIdentity().TagId() == 0 {
952 log.Panicf("IFD can not be used as a child IFD (not associated with a tag-ID): %v", childIb)
953 } else if childIb.byteOrder != ib.byteOrder {
954 log.Panicf("Child IFD does not have the same byte-order: [%s] != [%s]", childIb.byteOrder, ib.byteOrder)
955 }
956
957
958
959
960 for _, bt := range childIb.tags {
961 if bt.tagId == childIb.IfdIdentity().TagId() {
962 log.Panicf("child-IFD already added: %v", childIb.IfdIdentity().UnindexedString())
963 }
964 }
965
966 bt := ib.NewBuilderTagFromBuilder(childIb)
967 ib.tags = append(ib.tags, bt)
968
969 return nil
970 }
971
972 func (ib *IfdBuilder) NewBuilderTagFromBuilder(childIb *IfdBuilder) (bt *BuilderTag) {
973 defer func() {
974 if state := recover(); state != nil {
975 err := log.Wrap(state.(error))
976 log.Panic(err)
977 }
978 }()
979
980 value := NewIfdBuilderTagValueFromIfdBuilder(childIb)
981
982 bt = NewChildIfdBuilderTag(
983 ib.IfdIdentity().UnindexedString(),
984 childIb.IfdIdentity().TagId(),
985 value)
986
987 return bt
988 }
989
990
991
992
993 func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, includeTagIds []uint16, excludeTagIds []uint16) (err error) {
994 defer func() {
995 if state := recover(); state != nil {
996 err = log.Wrap(state.(error))
997 }
998 }()
999
1000 thumbnailData, err := ifd.Thumbnail()
1001 if err == nil {
1002 err = ib.SetThumbnail(thumbnailData)
1003 log.PanicIf(err)
1004 } else if log.Is(err, ErrNoThumbnail) == false {
1005 log.Panic(err)
1006 }
1007
1008 for i, ite := range ifd.Entries() {
1009 if ite.IsThumbnailOffset() == true || ite.IsThumbnailSize() {
1010
1011 continue
1012 }
1013
1014 if excludeTagIds != nil && len(excludeTagIds) > 0 {
1015 found := false
1016 for _, excludedTagId := range excludeTagIds {
1017 if excludedTagId == ite.TagId() {
1018 found = true
1019 }
1020 }
1021
1022 if found == true {
1023 continue
1024 }
1025 }
1026
1027 if includeTagIds != nil && len(includeTagIds) > 0 {
1028
1029
1030
1031 found := false
1032 for _, includedTagId := range includeTagIds {
1033 if includedTagId == ite.TagId() {
1034 found = true
1035 break
1036 }
1037 }
1038
1039 if found == false {
1040 continue
1041 }
1042 }
1043
1044 var bt *BuilderTag
1045
1046 if ite.ChildIfdPath() != "" {
1047
1048
1049
1050
1051
1052
1053 var childIfd *Ifd
1054 for _, thisChildIfd := range ifd.Children() {
1055 if thisChildIfd.ParentTagIndex() != i {
1056 continue
1057 } else if thisChildIfd.ifdIdentity.TagId() != 0xffff && thisChildIfd.ifdIdentity.TagId() != ite.TagId() {
1058 log.Panicf("child-IFD tag is not correct: TAG-POSITION=(%d) ITE=%s CHILD-IFD=%s", thisChildIfd.ParentTagIndex(), ite, thisChildIfd)
1059 }
1060
1061 childIfd = thisChildIfd
1062 break
1063 }
1064
1065 if childIfd == nil {
1066 childTagIds := make([]string, len(ifd.Children()))
1067 for j, childIfd := range ifd.Children() {
1068 childTagIds[j] = fmt.Sprintf("0x%04x (parent tag-position %d)", childIfd.ifdIdentity.TagId(), childIfd.ParentTagIndex())
1069 }
1070
1071 log.Panicf("could not find child IFD for child ITE: IFD-PATH=[%s] TAG-ID=(0x%04x) CURRENT-TAG-POSITION=(%d) CHILDREN=%v", ite.IfdPath(), ite.TagId(), i, childTagIds)
1072 }
1073
1074 childIb := NewIfdBuilderFromExistingChain(childIfd)
1075 bt = ib.NewBuilderTagFromBuilder(childIb)
1076 } else {
1077
1078
1079 rawBytes, err := ite.GetRawBytes()
1080 log.PanicIf(err)
1081
1082 value := NewIfdBuilderTagValueFromBytes(rawBytes)
1083
1084 bt = NewBuilderTag(
1085 ifd.ifdIdentity.UnindexedString(),
1086 ite.TagId(),
1087 ite.TagType(),
1088 value,
1089 ib.byteOrder)
1090 }
1091
1092 err := ib.add(bt)
1093 log.PanicIf(err)
1094 }
1095
1096 return nil
1097 }
1098
1099
1100
1101 func (ib *IfdBuilder) AddStandard(tagId uint16, value interface{}) (err error) {
1102 defer func() {
1103 if state := recover(); state != nil {
1104 err = log.Wrap(state.(error))
1105 }
1106 }()
1107
1108 it, err := ib.tagIndex.Get(ib.IfdIdentity(), tagId)
1109 log.PanicIf(err)
1110
1111 bt := NewStandardBuilderTag(ib.IfdIdentity().UnindexedString(), it, ib.byteOrder, value)
1112
1113 err = ib.add(bt)
1114 log.PanicIf(err)
1115
1116 return nil
1117 }
1118
1119
1120
1121
1122 func (ib *IfdBuilder) AddStandardWithName(tagName string, value interface{}) (err error) {
1123 defer func() {
1124 if state := recover(); state != nil {
1125 err = log.Wrap(state.(error))
1126 }
1127 }()
1128
1129 it, err := ib.tagIndex.GetWithName(ib.IfdIdentity(), tagName)
1130 log.PanicIf(err)
1131
1132 bt := NewStandardBuilderTag(ib.IfdIdentity().UnindexedString(), it, ib.byteOrder, value)
1133
1134 err = ib.add(bt)
1135 log.PanicIf(err)
1136
1137 return nil
1138 }
1139
1140
1141
1142 func (ib *IfdBuilder) SetStandard(tagId uint16, value interface{}) (err error) {
1143 defer func() {
1144 if state := recover(); state != nil {
1145 err = log.Wrap(state.(error))
1146 }
1147 }()
1148
1149
1150
1151 it, err := ib.tagIndex.Get(ib.IfdIdentity(), tagId)
1152 log.PanicIf(err)
1153
1154 bt := NewStandardBuilderTag(ib.IfdIdentity().UnindexedString(), it, ib.byteOrder, value)
1155
1156 i, err := ib.Find(tagId)
1157 if err != nil {
1158 if log.Is(err, ErrTagEntryNotFound) == false {
1159 log.Panic(err)
1160 }
1161
1162 ib.tags = append(ib.tags, bt)
1163 } else {
1164 ib.tags[i] = bt
1165 }
1166
1167 return nil
1168 }
1169
1170
1171
1172
1173 func (ib *IfdBuilder) SetStandardWithName(tagName string, value interface{}) (err error) {
1174 defer func() {
1175 if state := recover(); state != nil {
1176 err = log.Wrap(state.(error))
1177 }
1178 }()
1179
1180
1181
1182 it, err := ib.tagIndex.GetWithName(ib.IfdIdentity(), tagName)
1183 log.PanicIf(err)
1184
1185 bt := NewStandardBuilderTag(ib.IfdIdentity().UnindexedString(), it, ib.byteOrder, value)
1186
1187 i, err := ib.Find(bt.tagId)
1188 if err != nil {
1189 if log.Is(err, ErrTagEntryNotFound) == false {
1190 log.Panic(err)
1191 }
1192
1193 ib.tags = append(ib.tags, bt)
1194 } else {
1195 ib.tags[i] = bt
1196 }
1197
1198 return nil
1199 }
1200
View as plain text