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 }