diff options
Diffstat (limited to 'vendor/github.com/dsoprea/go-exif/v3/common/ifd.go')
-rw-r--r-- | vendor/github.com/dsoprea/go-exif/v3/common/ifd.go | 651 |
1 files changed, 0 insertions, 651 deletions
diff --git a/vendor/github.com/dsoprea/go-exif/v3/common/ifd.go b/vendor/github.com/dsoprea/go-exif/v3/common/ifd.go deleted file mode 100644 index 01886e966..000000000 --- a/vendor/github.com/dsoprea/go-exif/v3/common/ifd.go +++ /dev/null @@ -1,651 +0,0 @@ -package exifcommon - -import ( - "errors" - "fmt" - "strings" - - "github.com/dsoprea/go-logging" -) - -var ( - ifdLogger = log.NewLogger("exifcommon.ifd") -) - -var ( - ErrChildIfdNotMapped = errors.New("no child-IFD for that tag-ID under parent") -) - -// MappedIfd is one node in the IFD-mapping. -type MappedIfd struct { - ParentTagId uint16 - Placement []uint16 - Path []string - - Name string - TagId uint16 - Children map[uint16]*MappedIfd -} - -// String returns a descriptive string. -func (mi *MappedIfd) String() string { - pathPhrase := mi.PathPhrase() - return fmt.Sprintf("MappedIfd<(0x%04X) [%s] PATH=[%s]>", mi.TagId, mi.Name, pathPhrase) -} - -// PathPhrase returns a non-fully-qualified IFD path. -func (mi *MappedIfd) PathPhrase() string { - return strings.Join(mi.Path, "/") -} - -// TODO(dustin): Refactor this to use IfdIdentity structs. - -// IfdMapping describes all of the IFDs that we currently recognize. -type IfdMapping struct { - rootNode *MappedIfd -} - -// NewIfdMapping returns a new IfdMapping struct. -func NewIfdMapping() (ifdMapping *IfdMapping) { - rootNode := &MappedIfd{ - Path: make([]string, 0), - Children: make(map[uint16]*MappedIfd), - } - - return &IfdMapping{ - rootNode: rootNode, - } -} - -// NewIfdMappingWithStandard retruns a new IfdMapping struct preloaded with the -// standard IFDs. -func NewIfdMappingWithStandard() (ifdMapping *IfdMapping, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - im := NewIfdMapping() - - err = LoadStandardIfds(im) - log.PanicIf(err) - - return im, nil -} - -// Get returns the node given the path slice. -func (im *IfdMapping) Get(parentPlacement []uint16) (childIfd *MappedIfd, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - ptr := im.rootNode - for _, tagId := range parentPlacement { - if descendantPtr, found := ptr.Children[tagId]; found == false { - log.Panicf("ifd child with tag-ID (%04x) not registered: [%s]", tagId, ptr.PathPhrase()) - } else { - ptr = descendantPtr - } - } - - return ptr, nil -} - -// GetWithPath returns the node given the path string. -func (im *IfdMapping) GetWithPath(pathPhrase string) (mi *MappedIfd, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - if pathPhrase == "" { - log.Panicf("path-phrase is empty") - } - - path := strings.Split(pathPhrase, "/") - ptr := im.rootNode - - for _, name := range path { - var hit *MappedIfd - for _, mi := range ptr.Children { - if mi.Name == name { - hit = mi - break - } - } - - if hit == nil { - log.Panicf("ifd child with name [%s] not registered: [%s]", name, ptr.PathPhrase()) - } - - ptr = hit - } - - return ptr, nil -} - -// GetChild is a convenience function to get the child path for a given parent -// placement and child tag-ID. -func (im *IfdMapping) GetChild(parentPathPhrase string, tagId uint16) (mi *MappedIfd, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - mi, err = im.GetWithPath(parentPathPhrase) - log.PanicIf(err) - - for _, childMi := range mi.Children { - if childMi.TagId == tagId { - return childMi, nil - } - } - - // Whether or not an IFD is defined in data, such an IFD is not registered - // and would be unknown. - log.Panic(ErrChildIfdNotMapped) - return nil, nil -} - -// IfdTagIdAndIndex represents a specific part of the IFD path. -// -// This is a legacy type. -type IfdTagIdAndIndex struct { - Name string - TagId uint16 - Index int -} - -// String returns a descriptive string. -func (itii IfdTagIdAndIndex) String() string { - return fmt.Sprintf("IfdTagIdAndIndex<NAME=[%s] ID=(%04x) INDEX=(%d)>", itii.Name, itii.TagId, itii.Index) -} - -// ResolvePath takes a list of names, which can also be suffixed with indices -// (to identify the second, third, etc.. sibling IFD) and returns a list of -// tag-IDs and those indices. -// -// Example: -// -// - IFD/Exif/Iop -// - IFD0/Exif/Iop -// -// This is the only call that supports adding the numeric indices. -func (im *IfdMapping) ResolvePath(pathPhrase string) (lineage []IfdTagIdAndIndex, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - pathPhrase = strings.TrimSpace(pathPhrase) - - if pathPhrase == "" { - log.Panicf("can not resolve empty path-phrase") - } - - path := strings.Split(pathPhrase, "/") - lineage = make([]IfdTagIdAndIndex, len(path)) - - ptr := im.rootNode - empty := IfdTagIdAndIndex{} - for i, name := range path { - indexByte := name[len(name)-1] - index := 0 - if indexByte >= '0' && indexByte <= '9' { - index = int(indexByte - '0') - name = name[:len(name)-1] - } - - itii := IfdTagIdAndIndex{} - for _, mi := range ptr.Children { - if mi.Name != name { - continue - } - - itii.Name = name - itii.TagId = mi.TagId - itii.Index = index - - ptr = mi - - break - } - - if itii == empty { - log.Panicf("ifd child with name [%s] not registered: [%s]", name, pathPhrase) - } - - lineage[i] = itii - } - - return lineage, nil -} - -// FqPathPhraseFromLineage returns the fully-qualified IFD path from the slice. -func (im *IfdMapping) FqPathPhraseFromLineage(lineage []IfdTagIdAndIndex) (fqPathPhrase string) { - fqPathParts := make([]string, len(lineage)) - for i, itii := range lineage { - if itii.Index > 0 { - fqPathParts[i] = fmt.Sprintf("%s%d", itii.Name, itii.Index) - } else { - fqPathParts[i] = itii.Name - } - } - - return strings.Join(fqPathParts, "/") -} - -// PathPhraseFromLineage returns the non-fully-qualified IFD path from the -// slice. -func (im *IfdMapping) PathPhraseFromLineage(lineage []IfdTagIdAndIndex) (pathPhrase string) { - pathParts := make([]string, len(lineage)) - for i, itii := range lineage { - pathParts[i] = itii.Name - } - - return strings.Join(pathParts, "/") -} - -// StripPathPhraseIndices returns a non-fully-qualified path-phrase (no -// indices). -func (im *IfdMapping) StripPathPhraseIndices(pathPhrase string) (strippedPathPhrase string, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - lineage, err := im.ResolvePath(pathPhrase) - log.PanicIf(err) - - strippedPathPhrase = im.PathPhraseFromLineage(lineage) - return strippedPathPhrase, nil -} - -// Add puts the given IFD at the given position of the tree. The position of the -// tree is referred to as the placement and is represented by a set of tag-IDs, -// where the leftmost is the root tag and the tags going to the right are -// progressive descendants. -func (im *IfdMapping) Add(parentPlacement []uint16, tagId uint16, name string) (err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - // TODO(dustin): !! It would be nicer to provide a list of names in the placement rather than tag-IDs. - - ptr, err := im.Get(parentPlacement) - log.PanicIf(err) - - path := make([]string, len(parentPlacement)+1) - if len(parentPlacement) > 0 { - copy(path, ptr.Path) - } - - path[len(path)-1] = name - - placement := make([]uint16, len(parentPlacement)+1) - if len(placement) > 0 { - copy(placement, ptr.Placement) - } - - placement[len(placement)-1] = tagId - - childIfd := &MappedIfd{ - ParentTagId: ptr.TagId, - Path: path, - Placement: placement, - Name: name, - TagId: tagId, - Children: make(map[uint16]*MappedIfd), - } - - if _, found := ptr.Children[tagId]; found == true { - log.Panicf("child IFD with tag-ID (%04x) already registered under IFD [%s] with tag-ID (%04x)", tagId, ptr.Name, ptr.TagId) - } - - ptr.Children[tagId] = childIfd - - return nil -} - -func (im *IfdMapping) dumpLineages(stack []*MappedIfd, input []string) (output []string, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - currentIfd := stack[len(stack)-1] - - output = input - for _, childIfd := range currentIfd.Children { - stackCopy := make([]*MappedIfd, len(stack)+1) - - copy(stackCopy, stack) - stackCopy[len(stack)] = childIfd - - // Add to output, but don't include the obligatory root node. - parts := make([]string, len(stackCopy)-1) - for i, mi := range stackCopy[1:] { - parts[i] = mi.Name - } - - output = append(output, strings.Join(parts, "/")) - - output, err = im.dumpLineages(stackCopy, output) - log.PanicIf(err) - } - - return output, nil -} - -// DumpLineages returns a slice of strings representing all mappings. -func (im *IfdMapping) DumpLineages() (output []string, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - stack := []*MappedIfd{im.rootNode} - output = make([]string, 0) - - output, err = im.dumpLineages(stack, output) - log.PanicIf(err) - - return output, nil -} - -// LoadStandardIfds loads the standard IFDs into the mapping. -func LoadStandardIfds(im *IfdMapping) (err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - err = im.Add( - []uint16{}, - IfdStandardIfdIdentity.TagId(), IfdStandardIfdIdentity.Name()) - - log.PanicIf(err) - - err = im.Add( - []uint16{IfdStandardIfdIdentity.TagId()}, - IfdExifStandardIfdIdentity.TagId(), IfdExifStandardIfdIdentity.Name()) - - log.PanicIf(err) - - err = im.Add( - []uint16{IfdStandardIfdIdentity.TagId(), IfdExifStandardIfdIdentity.TagId()}, - IfdExifIopStandardIfdIdentity.TagId(), IfdExifIopStandardIfdIdentity.Name()) - - log.PanicIf(err) - - err = im.Add( - []uint16{IfdStandardIfdIdentity.TagId()}, - IfdGpsInfoStandardIfdIdentity.TagId(), IfdGpsInfoStandardIfdIdentity.Name()) - - log.PanicIf(err) - - return nil -} - -// IfdTag describes a single IFD tag and its parent (if any). -type IfdTag struct { - parentIfdTag *IfdTag - tagId uint16 - name string -} - -func NewIfdTag(parentIfdTag *IfdTag, tagId uint16, name string) IfdTag { - return IfdTag{ - parentIfdTag: parentIfdTag, - tagId: tagId, - name: name, - } -} - -// ParentIfd returns the IfdTag of this IFD's parent. -func (it IfdTag) ParentIfd() *IfdTag { - return it.parentIfdTag -} - -// TagId returns the tag-ID of this IFD. -func (it IfdTag) TagId() uint16 { - return it.tagId -} - -// Name returns the simple name of this IFD. -func (it IfdTag) Name() string { - return it.name -} - -// String returns a descriptive string. -func (it IfdTag) String() string { - parentIfdPhrase := "" - if it.parentIfdTag != nil { - parentIfdPhrase = fmt.Sprintf(" PARENT=(0x%04x)[%s]", it.parentIfdTag.tagId, it.parentIfdTag.name) - } - - return fmt.Sprintf("IfdTag<TAG-ID=(0x%04x) NAME=[%s]%s>", it.tagId, it.name, parentIfdPhrase) -} - -var ( - // rootStandardIfd is the standard root IFD. - rootStandardIfd = NewIfdTag(nil, 0x0000, "IFD") // IFD - - // exifStandardIfd is the standard "Exif" IFD. - exifStandardIfd = NewIfdTag(&rootStandardIfd, 0x8769, "Exif") // IFD/Exif - - // iopStandardIfd is the standard "Iop" IFD. - iopStandardIfd = NewIfdTag(&exifStandardIfd, 0xA005, "Iop") // IFD/Exif/Iop - - // gpsInfoStandardIfd is the standard "GPS" IFD. - gpsInfoStandardIfd = NewIfdTag(&rootStandardIfd, 0x8825, "GPSInfo") // IFD/GPSInfo -) - -// IfdIdentityPart represents one component in an IFD path. -type IfdIdentityPart struct { - Name string - Index int -} - -// String returns a fully-qualified IFD path. -func (iip IfdIdentityPart) String() string { - if iip.Index > 0 { - return fmt.Sprintf("%s%d", iip.Name, iip.Index) - } else { - return iip.Name - } -} - -// UnindexedString returned a non-fully-qualified IFD path. -func (iip IfdIdentityPart) UnindexedString() string { - return iip.Name -} - -// IfdIdentity represents a single IFD path and provides access to various -// information and representations. -// -// Only global instances can be used for equality checks. -type IfdIdentity struct { - ifdTag IfdTag - parts []IfdIdentityPart - ifdPath string - fqIfdPath string -} - -// NewIfdIdentity returns a new IfdIdentity struct. -func NewIfdIdentity(ifdTag IfdTag, parts ...IfdIdentityPart) (ii *IfdIdentity) { - ii = &IfdIdentity{ - ifdTag: ifdTag, - parts: parts, - } - - ii.ifdPath = ii.getIfdPath() - ii.fqIfdPath = ii.getFqIfdPath() - - return ii -} - -// NewIfdIdentityFromString parses a string like "IFD/Exif" or "IFD1" or -// something more exotic with custom IFDs ("SomeIFD4/SomeChildIFD6"). Note that -// this will valid the unindexed IFD structure (because the standard tags from -// the specification are unindexed), but not, obviously, any indices (e.g. -// the numbers in "IFD0", "IFD1", "SomeIFD4/SomeChildIFD6"). It is -// required for the caller to check whether these specific instances -// were actually parsed out of the stream. -func NewIfdIdentityFromString(im *IfdMapping, fqIfdPath string) (ii *IfdIdentity, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - lineage, err := im.ResolvePath(fqIfdPath) - log.PanicIf(err) - - var lastIt *IfdTag - identityParts := make([]IfdIdentityPart, len(lineage)) - for i, itii := range lineage { - // Build out the tag that will eventually point to the IFD represented - // by the right-most part in the IFD path. - - it := &IfdTag{ - parentIfdTag: lastIt, - tagId: itii.TagId, - name: itii.Name, - } - - lastIt = it - - // Create the next IfdIdentity part. - - iip := IfdIdentityPart{ - Name: itii.Name, - Index: itii.Index, - } - - identityParts[i] = iip - } - - ii = NewIfdIdentity(*lastIt, identityParts...) - return ii, nil -} - -func (ii *IfdIdentity) getFqIfdPath() string { - partPhrases := make([]string, len(ii.parts)) - for i, iip := range ii.parts { - partPhrases[i] = iip.String() - } - - return strings.Join(partPhrases, "/") -} - -func (ii *IfdIdentity) getIfdPath() string { - partPhrases := make([]string, len(ii.parts)) - for i, iip := range ii.parts { - partPhrases[i] = iip.UnindexedString() - } - - return strings.Join(partPhrases, "/") -} - -// String returns a fully-qualified IFD path. -func (ii *IfdIdentity) String() string { - return ii.fqIfdPath -} - -// UnindexedString returns a non-fully-qualified IFD path. -func (ii *IfdIdentity) UnindexedString() string { - return ii.ifdPath -} - -// IfdTag returns the tag struct behind this IFD. -func (ii *IfdIdentity) IfdTag() IfdTag { - return ii.ifdTag -} - -// TagId returns the tag-ID of the IFD. -func (ii *IfdIdentity) TagId() uint16 { - return ii.ifdTag.TagId() -} - -// LeafPathPart returns the last right-most path-part, which represents the -// current IFD. -func (ii *IfdIdentity) LeafPathPart() IfdIdentityPart { - return ii.parts[len(ii.parts)-1] -} - -// Name returns the simple name of this IFD. -func (ii *IfdIdentity) Name() string { - return ii.LeafPathPart().Name -} - -// Index returns the index of this IFD (more then one IFD under a parent IFD -// will be numbered [0..n]). -func (ii *IfdIdentity) Index() int { - return ii.LeafPathPart().Index -} - -// Equals returns true if the two IfdIdentity instances are effectively -// identical. -// -// Since there's no way to get a specific fully-qualified IFD path without a -// certain slice of parts and all other fields are also derived from this, -// checking that the fully-qualified IFD path is equals is sufficient. -func (ii *IfdIdentity) Equals(ii2 *IfdIdentity) bool { - return ii.String() == ii2.String() -} - -// NewChild creates an IfdIdentity for an IFD that is a child of the current -// IFD. -func (ii *IfdIdentity) NewChild(childIfdTag IfdTag, index int) (iiChild *IfdIdentity) { - if *childIfdTag.parentIfdTag != ii.ifdTag { - log.Panicf("can not add child; we are not the parent:\nUS=%v\nCHILD=%v", ii.ifdTag, childIfdTag) - } - - childPart := IfdIdentityPart{childIfdTag.name, index} - childParts := append(ii.parts, childPart) - - iiChild = NewIfdIdentity(childIfdTag, childParts...) - return iiChild -} - -// NewSibling creates an IfdIdentity for an IFD that is a sibling to the current -// one. -func (ii *IfdIdentity) NewSibling(index int) (iiSibling *IfdIdentity) { - parts := make([]IfdIdentityPart, len(ii.parts)) - - copy(parts, ii.parts) - parts[len(parts)-1].Index = index - - iiSibling = NewIfdIdentity(ii.ifdTag, parts...) - return iiSibling -} - -var ( - // IfdStandardIfdIdentity represents the IFD path for IFD0. - IfdStandardIfdIdentity = NewIfdIdentity(rootStandardIfd, IfdIdentityPart{"IFD", 0}) - - // IfdExifStandardIfdIdentity represents the IFD path for IFD0/Exif0. - IfdExifStandardIfdIdentity = IfdStandardIfdIdentity.NewChild(exifStandardIfd, 0) - - // IfdExifIopStandardIfdIdentity represents the IFD path for IFD0/Exif0/Iop0. - IfdExifIopStandardIfdIdentity = IfdExifStandardIfdIdentity.NewChild(iopStandardIfd, 0) - - // IfdGPSInfoStandardIfdIdentity represents the IFD path for IFD0/GPSInfo0. - IfdGpsInfoStandardIfdIdentity = IfdStandardIfdIdentity.NewChild(gpsInfoStandardIfd, 0) - - // Ifd1StandardIfdIdentity represents the IFD path for IFD1. - Ifd1StandardIfdIdentity = NewIfdIdentity(rootStandardIfd, IfdIdentityPart{"IFD", 1}) -) |