diff options
Diffstat (limited to 'vendor/github.com/dsoprea/go-exif/v3/exif.go')
-rw-r--r-- | vendor/github.com/dsoprea/go-exif/v3/exif.go | 333 |
1 files changed, 0 insertions, 333 deletions
diff --git a/vendor/github.com/dsoprea/go-exif/v3/exif.go b/vendor/github.com/dsoprea/go-exif/v3/exif.go deleted file mode 100644 index f66e839d9..000000000 --- a/vendor/github.com/dsoprea/go-exif/v3/exif.go +++ /dev/null @@ -1,333 +0,0 @@ -package exif - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "io" - "os" - - "encoding/binary" - "io/ioutil" - - "github.com/dsoprea/go-logging" - - "github.com/dsoprea/go-exif/v3/common" -) - -const ( - // ExifAddressableAreaStart is the absolute offset in the file that all - // offsets are relative to. - ExifAddressableAreaStart = uint32(0x0) - - // ExifDefaultFirstIfdOffset is essentially the number of bytes in addition - // to `ExifAddressableAreaStart` that you have to move in order to escape - // the rest of the header and get to the earliest point where we can put - // stuff (which has to be the first IFD). This is the size of the header - // sequence containing the two-character byte-order, two-character fixed- - // bytes, and the four bytes describing the first-IFD offset. - ExifDefaultFirstIfdOffset = uint32(2 + 2 + 4) -) - -const ( - // ExifSignatureLength is the number of bytes in the EXIF signature (which - // customarily includes the first IFD offset). - ExifSignatureLength = 8 -) - -var ( - exifLogger = log.NewLogger("exif.exif") - - ExifBigEndianSignature = [4]byte{'M', 'M', 0x00, 0x2a} - ExifLittleEndianSignature = [4]byte{'I', 'I', 0x2a, 0x00} -) - -var ( - ErrNoExif = errors.New("no exif data") - ErrExifHeaderError = errors.New("exif header error") -) - -// SearchAndExtractExif searches for an EXIF blob in the byte-slice. -func SearchAndExtractExif(data []byte) (rawExif []byte, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - b := bytes.NewBuffer(data) - - rawExif, err = SearchAndExtractExifWithReader(b) - if err != nil { - if err == ErrNoExif { - return nil, err - } - - log.Panic(err) - } - - return rawExif, nil -} - -// SearchAndExtractExifN searches for an EXIF blob in the byte-slice, but skips -// the given number of EXIF blocks first. This is a forensics tool that helps -// identify multiple EXIF blocks in a file. -func SearchAndExtractExifN(data []byte, n int) (rawExif []byte, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - skips := 0 - totalDiscarded := 0 - for { - b := bytes.NewBuffer(data) - - var discarded int - - rawExif, discarded, err = searchAndExtractExifWithReaderWithDiscarded(b) - if err != nil { - if err == ErrNoExif { - return nil, err - } - - log.Panic(err) - } - - exifLogger.Debugf(nil, "Read EXIF block (%d).", skips) - - totalDiscarded += discarded - - if skips >= n { - exifLogger.Debugf(nil, "Reached requested EXIF block (%d).", n) - break - } - - nextOffset := discarded + 1 - exifLogger.Debugf(nil, "Skipping EXIF block (%d) by seeking to position (%d).", skips, nextOffset) - - data = data[nextOffset:] - skips++ - } - - exifLogger.Debugf(nil, "Found EXIF blob (%d) bytes from initial position.", totalDiscarded) - return rawExif, nil -} - -// searchAndExtractExifWithReaderWithDiscarded searches for an EXIF blob using -// an `io.Reader`. We can't know how much long the EXIF data is without parsing -// it, so this will likely grab up a lot of the image-data, too. -// -// This function returned the count of preceding bytes. -func searchAndExtractExifWithReaderWithDiscarded(r io.Reader) (rawExif []byte, discarded int, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - // Search for the beginning of the EXIF information. The EXIF is near the - // beginning of most JPEGs, so this likely doesn't have a high cost (at - // least, again, with JPEGs). - - br := bufio.NewReader(r) - - for { - window, err := br.Peek(ExifSignatureLength) - if err != nil { - if err == io.EOF { - return nil, 0, ErrNoExif - } - - log.Panic(err) - } - - _, err = ParseExifHeader(window) - if err != nil { - if log.Is(err, ErrNoExif) == true { - // No EXIF. Move forward by one byte. - - _, err := br.Discard(1) - log.PanicIf(err) - - discarded++ - - continue - } - - // Some other error. - log.Panic(err) - } - - break - } - - exifLogger.Debugf(nil, "Found EXIF blob (%d) bytes from initial position.", discarded) - - rawExif, err = ioutil.ReadAll(br) - log.PanicIf(err) - - return rawExif, discarded, nil -} - -// RELEASE(dustin): We should replace the implementation of SearchAndExtractExifWithReader with searchAndExtractExifWithReaderWithDiscarded and drop the latter. - -// SearchAndExtractExifWithReader searches for an EXIF blob using an -// `io.Reader`. We can't know how much long the EXIF data is without parsing it, -// so this will likely grab up a lot of the image-data, too. -func SearchAndExtractExifWithReader(r io.Reader) (rawExif []byte, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - rawExif, _, err = searchAndExtractExifWithReaderWithDiscarded(r) - if err != nil { - if err == ErrNoExif { - return nil, err - } - - log.Panic(err) - } - - return rawExif, nil -} - -// SearchFileAndExtractExif returns a slice from the beginning of the EXIF data -// to the end of the file (it's not practical to try and calculate where the -// data actually ends). -func SearchFileAndExtractExif(filepath string) (rawExif []byte, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - // Open the file. - - f, err := os.Open(filepath) - log.PanicIf(err) - - defer f.Close() - - rawExif, err = SearchAndExtractExifWithReader(f) - log.PanicIf(err) - - return rawExif, nil -} - -type ExifHeader struct { - ByteOrder binary.ByteOrder - FirstIfdOffset uint32 -} - -func (eh ExifHeader) String() string { - return fmt.Sprintf("ExifHeader<BYTE-ORDER=[%v] FIRST-IFD-OFFSET=(0x%02x)>", eh.ByteOrder, eh.FirstIfdOffset) -} - -// ParseExifHeader parses the bytes at the very top of the header. -// -// This will panic with ErrNoExif on any data errors so that we can double as -// an EXIF-detection routine. -func ParseExifHeader(data []byte) (eh ExifHeader, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - // Good reference: - // - // CIPA DC-008-2016; JEITA CP-3451D - // -> http://www.cipa.jp/std/documents/e/DC-008-Translation-2016-E.pdf - - if len(data) < ExifSignatureLength { - exifLogger.Warningf(nil, "Not enough data for EXIF header: (%d)", len(data)) - return eh, ErrNoExif - } - - if bytes.Equal(data[:4], ExifBigEndianSignature[:]) == true { - exifLogger.Debugf(nil, "Byte-order is big-endian.") - eh.ByteOrder = binary.BigEndian - } else if bytes.Equal(data[:4], ExifLittleEndianSignature[:]) == true { - eh.ByteOrder = binary.LittleEndian - exifLogger.Debugf(nil, "Byte-order is little-endian.") - } else { - return eh, ErrNoExif - } - - eh.FirstIfdOffset = eh.ByteOrder.Uint32(data[4:8]) - - return eh, nil -} - -// Visit recursively invokes a callback for every tag. -func Visit(rootIfdIdentity *exifcommon.IfdIdentity, ifdMapping *exifcommon.IfdMapping, tagIndex *TagIndex, exifData []byte, visitor TagVisitorFn, so *ScanOptions) (eh ExifHeader, furthestOffset uint32, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - eh, err = ParseExifHeader(exifData) - log.PanicIf(err) - - ebs := NewExifReadSeekerWithBytes(exifData) - ie := NewIfdEnumerate(ifdMapping, tagIndex, ebs, eh.ByteOrder) - - _, err = ie.Scan(rootIfdIdentity, eh.FirstIfdOffset, visitor, so) - log.PanicIf(err) - - furthestOffset = ie.FurthestOffset() - - return eh, furthestOffset, nil -} - -// Collect recursively builds a static structure of all IFDs and tags. -func Collect(ifdMapping *exifcommon.IfdMapping, tagIndex *TagIndex, exifData []byte) (eh ExifHeader, index IfdIndex, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - eh, err = ParseExifHeader(exifData) - log.PanicIf(err) - - ebs := NewExifReadSeekerWithBytes(exifData) - ie := NewIfdEnumerate(ifdMapping, tagIndex, ebs, eh.ByteOrder) - - index, err = ie.Collect(eh.FirstIfdOffset) - log.PanicIf(err) - - return eh, index, nil -} - -// BuildExifHeader constructs the bytes that go at the front of the stream. -func BuildExifHeader(byteOrder binary.ByteOrder, firstIfdOffset uint32) (headerBytes []byte, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - b := new(bytes.Buffer) - - var signatureBytes []byte - if byteOrder == binary.BigEndian { - signatureBytes = ExifBigEndianSignature[:] - } else { - signatureBytes = ExifLittleEndianSignature[:] - } - - _, err = b.Write(signatureBytes) - log.PanicIf(err) - - err = binary.Write(b, byteOrder, firstIfdOffset) - log.PanicIf(err) - - return b.Bytes(), nil -} |