gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

webp.go (2419B)


      1 /*
      2    exif-terminator
      3    Copyright (C) 2022 SuperSeriousBusiness admin@gotosocial.org
      4 
      5    This program is free software: you can redistribute it and/or modify
      6    it under the terms of the GNU Affero General Public License as published by
      7    the Free Software Foundation, either version 3 of the License, or
      8    (at your option) any later version.
      9 
     10    This program is distributed in the hope that it will be useful,
     11    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13    GNU Affero General Public License for more details.
     14 
     15    You should have received a copy of the GNU Affero General Public License
     16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 */
     18 
     19 package terminator
     20 
     21 import (
     22 	"encoding/binary"
     23 	"errors"
     24 	"io"
     25 )
     26 
     27 const (
     28 	riffHeaderSize = 4 * 3
     29 )
     30 
     31 var (
     32 	riffHeader = [4]byte{'R', 'I', 'F', 'F'}
     33 	webpHeader = [4]byte{'W', 'E', 'B', 'P'}
     34 	exifFourcc = [4]byte{'E', 'X', 'I', 'F'}
     35 	xmpFourcc  = [4]byte{'X', 'M', 'P', ' '}
     36 
     37 	errNoRiffHeader = errors.New("no RIFF header")
     38 	errNoWebpHeader = errors.New("not a WEBP file")
     39 )
     40 
     41 type webpVisitor struct {
     42 	writer     io.Writer
     43 	doneHeader bool
     44 }
     45 
     46 func fourCC(b []byte) [4]byte {
     47 	return [4]byte{b[0], b[1], b[2], b[3]}
     48 }
     49 
     50 func (v *webpVisitor) split(data []byte, atEOF bool) (advance int, token []byte, err error) {
     51 	// parse/write the header first
     52 	if !v.doneHeader {
     53 		if len(data) < riffHeaderSize {
     54 			// need the full header
     55 			return
     56 		}
     57 		if fourCC(data) != riffHeader {
     58 			err = errNoRiffHeader
     59 			return
     60 		}
     61 		if fourCC(data[8:]) != webpHeader {
     62 			err = errNoWebpHeader
     63 			return
     64 		}
     65 		if _, err = v.writer.Write(data[:riffHeaderSize]); err != nil {
     66 			return
     67 		}
     68 		advance += riffHeaderSize
     69 		data = data[riffHeaderSize:]
     70 		v.doneHeader = true
     71 	}
     72 
     73 	// need enough for fourcc and size
     74 	if len(data) < 8 {
     75 		return
     76 	}
     77 	size := int64(binary.LittleEndian.Uint32(data[4:]))
     78 	if (size & 1) != 0 {
     79 		// odd chunk size - extra padding byte
     80 		size++
     81 	}
     82 	// wait until there is enough
     83 	if int64(len(data)-8) < size {
     84 		return
     85 	}
     86 
     87 	fourcc := fourCC(data)
     88 	rawChunkData := data[8 : 8+size]
     89 	if fourcc == exifFourcc || fourcc == xmpFourcc {
     90 		// replace exif/xmp with blank
     91 		rawChunkData = make([]byte, size)
     92 	}
     93 
     94 	if _, err = v.writer.Write(data[:8]); err == nil {
     95 		if _, err = v.writer.Write(rawChunkData); err == nil {
     96 			advance += 8 + int(size)
     97 		}
     98 	}
     99 
    100 	return
    101 }