summaryrefslogtreecommitdiff
path: root/vendor/github.com/superseriousbusiness/exif-terminator/terminator.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/superseriousbusiness/exif-terminator/terminator.go')
-rw-r--r--vendor/github.com/superseriousbusiness/exif-terminator/terminator.go94
1 files changed, 59 insertions, 35 deletions
diff --git a/vendor/github.com/superseriousbusiness/exif-terminator/terminator.go b/vendor/github.com/superseriousbusiness/exif-terminator/terminator.go
index 9d9e6e743..7dd3d9ad7 100644
--- a/vendor/github.com/superseriousbusiness/exif-terminator/terminator.go
+++ b/vendor/github.com/superseriousbusiness/exif-terminator/terminator.go
@@ -25,29 +25,34 @@ import (
"fmt"
"io"
- pngstructure "github.com/dsoprea/go-png-image-structure/v2"
jpegstructure "github.com/superseriousbusiness/go-jpeg-image-structure/v2"
+ pngstructure "github.com/superseriousbusiness/go-png-image-structure/v2"
)
func Terminate(in io.Reader, fileSize int, mediaType string) (io.Reader, error) {
- // to avoid keeping too much stuff in memory we want to pipe data directly
+ // To avoid keeping too much stuff
+ // in memory we want to pipe data
+ // directly to the reader.
pipeReader, pipeWriter := io.Pipe()
- // we don't know ahead of time how long segments might be: they could be as large as
- // the file itself, so unfortunately we need to allocate a buffer here that'scanner as large
- // as the file
+ // We don't know ahead of time how long
+ // segments might be: they could be as
+ // large as the file itself, so we need
+ // a buffer with generous overhead.
scanner := bufio.NewScanner(in)
scanner.Buffer([]byte{}, fileSize)
- var err error
+ var err error
switch mediaType {
case "image/jpeg", "jpeg", "jpg":
err = terminateJpeg(scanner, pipeWriter, fileSize)
+
case "image/webp", "webp":
err = terminateWebp(scanner, pipeWriter)
+
case "image/png", "png":
- // for pngs we need to skip the header bytes, so read them in
- // and check we're really dealing with a png here
+ // For pngs we need to skip the header bytes, so read
+ // them in and check we're really dealing with a png.
header := make([]byte, len(pngstructure.PngSignature))
if _, headerError := in.Read(header); headerError != nil {
err = headerError
@@ -67,68 +72,87 @@ func Terminate(in io.Reader, fileSize int, mediaType string) (io.Reader, error)
return pipeReader, err
}
-func terminateJpeg(scanner *bufio.Scanner, writer io.WriteCloser, expectedFileSize int) error {
- // jpeg visitor is where the spicy hack of streaming the de-exifed data is contained
+func terminateJpeg(scanner *bufio.Scanner, writer *io.PipeWriter, expectedFileSize int) error {
v := &jpegVisitor{
writer: writer,
expectedFileSize: expectedFileSize,
}
- // provide the visitor to the splitter so that it triggers on every section scan
+ // Provide the visitor to the splitter so
+ // that it triggers on every section scan.
js := jpegstructure.NewJpegSplitter(v)
- // the visitor also needs to read back the list of segments: for this it needs
- // to know what jpeg splitter it's attached to, so give it a pointer to the splitter
+ // The visitor also needs to read back the
+ // list of segments: for this it needs to
+ // know what jpeg splitter it's attached to,
+ // so give it a pointer to the splitter.
v.js = js
- // use the jpeg splitters 'split' function, which satisfies the bufio.SplitFunc interface
+ // Jpeg visitor's 'split' function
+ // satisfies bufio.SplitFunc{}.
scanner.Split(js.Split)
- scanAndClose(scanner, writer)
+ go scanAndClose(scanner, writer)
return nil
}
-func terminateWebp(scanner *bufio.Scanner, writer io.WriteCloser) error {
+func terminateWebp(scanner *bufio.Scanner, writer *io.PipeWriter) error {
v := &webpVisitor{
writer: writer,
}
- // use the webp visitor's 'split' function, which satisfies the bufio.SplitFunc interface
+ // Webp visitor's 'split' function
+ // satisfies bufio.SplitFunc{}.
scanner.Split(v.split)
- scanAndClose(scanner, writer)
+ go scanAndClose(scanner, writer)
return nil
}
-func terminatePng(scanner *bufio.Scanner, writer io.WriteCloser) error {
+func terminatePng(scanner *bufio.Scanner, writer *io.PipeWriter) error {
ps := pngstructure.NewPngSplitter()
+ // Don't bother checking CRC;
+ // we're overwriting it anyway.
+ ps.DoCheckCrc(false)
+
v := &pngVisitor{
ps: ps,
writer: writer,
lastWrittenChunk: -1,
}
- // use the png visitor's 'split' function, which satisfies the bufio.SplitFunc interface
+ // Png visitor's 'split' function
+ // satisfies bufio.SplitFunc{}.
scanner.Split(v.split)
- scanAndClose(scanner, writer)
+ go scanAndClose(scanner, writer)
return nil
}
-func scanAndClose(scanner *bufio.Scanner, writer io.WriteCloser) {
- // scan asynchronously until there's nothing left to scan, and then close the writer
- // so that the reader on the other side knows that we're done
- //
- // due to the nature of io.Pipe, writing won't actually work
- // until the pipeReader starts being read by the caller, which
- // is why we do this asynchronously
- go func() {
- defer writer.Close()
- for scanner.Scan() {
- }
- if scanner.Err() != nil {
- logger.Error(scanner.Err())
- }
+// scanAndClose scans through the given scanner until there's
+// nothing left to scan, and then closes the writer so that the
+// reader on the other side of the pipe knows that we're done.
+//
+// Any error encountered when scanning will be logged by terminator.
+//
+// Due to the nature of io.Pipe, writing won't actually work
+// until the pipeReader starts being read by the caller, which
+// is why this function should always be called asynchronously.
+func scanAndClose(scanner *bufio.Scanner, writer *io.PipeWriter) {
+ var err error
+
+ defer func() {
+ // Always close writer, using returned
+ // scanner error (if any). If err is nil
+ // then the standard io.EOF will be used.
+ // (this will not overwrite existing).
+ writer.CloseWithError(err)
}()
+
+ for scanner.Scan() {
+ }
+
+ // Set error on return.
+ err = scanner.Err()
}