| 
									
										
										
										
											2024-08-02 11:46:41 +00:00
										 |  |  | /* | 
					
						
							|  |  |  |    exif-terminator | 
					
						
							|  |  |  |    Copyright (C) 2022 SuperSeriousBusiness admin@gotosocial.org | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    This program is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  |    it under the terms of the GNU Affero General Public License as published by | 
					
						
							|  |  |  |    the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  |    (at your option) any later version. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |    GNU Affero General Public License for more details. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    You should have received a copy of the GNU Affero General Public License | 
					
						
							|  |  |  |    along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package terminator | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/binary" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2024-11-28 15:14:49 +00:00
										 |  |  | 	riffHeader = "RIFF" | 
					
						
							|  |  |  | 	webpHeader = "WEBP" | 
					
						
							|  |  |  | 	exifFourcc = "EXIF" | 
					
						
							|  |  |  | 	xmpFourcc  = "XMP " | 
					
						
							| 
									
										
										
										
											2024-08-02 11:46:41 +00:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	errNoRiffHeader = errors.New("no RIFF header") | 
					
						
							|  |  |  | 	errNoWebpHeader = errors.New("not a WEBP file") | 
					
						
							| 
									
										
										
										
											2024-11-28 15:14:49 +00:00
										 |  |  | 	errInvalidChunk = errors.New("invalid chunk") | 
					
						
							| 
									
										
										
										
											2024-08-02 11:46:41 +00:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type webpVisitor struct { | 
					
						
							|  |  |  | 	writer     io.Writer | 
					
						
							|  |  |  | 	doneHeader bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (v *webpVisitor) split(data []byte, atEOF bool) (advance int, token []byte, err error) { | 
					
						
							|  |  |  | 	// parse/write the header first | 
					
						
							|  |  |  | 	if !v.doneHeader { | 
					
						
							| 
									
										
										
										
											2024-11-28 15:14:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// const rifHeaderSize = 12 | 
					
						
							|  |  |  | 		if len(data) < 12 { | 
					
						
							|  |  |  | 			if atEOF { | 
					
						
							|  |  |  | 				err = errNoRiffHeader | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-08-02 11:46:41 +00:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-11-28 15:14:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if string(data[:4]) != riffHeader { | 
					
						
							| 
									
										
										
										
											2024-08-02 11:46:41 +00:00
										 |  |  | 			err = errNoRiffHeader | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-11-28 15:14:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if string(data[8:12]) != webpHeader { | 
					
						
							| 
									
										
										
										
											2024-08-02 11:46:41 +00:00
										 |  |  | 			err = errNoWebpHeader | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-11-28 15:14:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if _, err = v.writer.Write(data[:12]); err != nil { | 
					
						
							| 
									
										
										
										
											2024-08-02 11:46:41 +00:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-11-28 15:14:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		advance += 12 | 
					
						
							|  |  |  | 		data = data[12:] | 
					
						
							| 
									
										
										
										
											2024-08-02 11:46:41 +00:00
										 |  |  | 		v.doneHeader = true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-28 15:14:49 +00:00
										 |  |  | 	for { | 
					
						
							|  |  |  | 		// need enough for | 
					
						
							|  |  |  | 		// fourcc and size | 
					
						
							|  |  |  | 		if len(data) < 8 { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		size := int64(binary.LittleEndian.Uint32(data[4:])) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (size & 1) != 0 { | 
					
						
							|  |  |  | 			// odd chunk size: | 
					
						
							|  |  |  | 			// extra padding byte | 
					
						
							|  |  |  | 			size++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// wait until there is enough | 
					
						
							|  |  |  | 		if int64(len(data)) < 8+size { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-08-02 11:46:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// replace exif/xmp with blank | 
					
						
							| 
									
										
										
										
											2024-11-28 15:14:49 +00:00
										 |  |  | 		switch string(data[:4]) { | 
					
						
							|  |  |  | 		case exifFourcc, xmpFourcc: | 
					
						
							|  |  |  | 			clear(data[8 : 8+size]) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-08-02 11:46:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-28 15:14:49 +00:00
										 |  |  | 		if _, err = v.writer.Write(data[:8+size]); err != nil { | 
					
						
							|  |  |  | 			return | 
					
						
							| 
									
										
										
										
											2024-08-02 11:46:41 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-28 15:14:49 +00:00
										 |  |  | 		advance += 8 + int(size) | 
					
						
							|  |  |  | 		data = data[8+size:] | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-08-02 11:46:41 +00:00
										 |  |  | } |