mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 03:12:25 -05:00 
			
		
		
		
	use exif-terminator
This commit is contained in:
		
					parent
					
						
							
								589bb9df02
							
						
					
				
			
			
				commit
				
					
						7d024ce74d
					
				
			
		
					 117 changed files with 3873 additions and 8725 deletions
				
			
		
							
								
								
									
										651
									
								
								vendor/github.com/dsoprea/go-exif/v3/common/ifd.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										651
									
								
								vendor/github.com/dsoprea/go-exif/v3/common/ifd.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,651 @@ | |||
| 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}) | ||||
| ) | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue