summaryrefslogtreecommitdiff
path: root/internal/media/png-stripper.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/media/png-stripper.go')
-rw-r--r--internal/media/png-stripper.go211
1 files changed, 0 insertions, 211 deletions
diff --git a/internal/media/png-stripper.go b/internal/media/png-stripper.go
deleted file mode 100644
index 09126f6a5..000000000
--- a/internal/media/png-stripper.go
+++ /dev/null
@@ -1,211 +0,0 @@
-// GoToSocial
-// Copyright (C) GoToSocial Authors admin@gotosocial.org
-// SPDX-License-Identifier: AGPL-3.0-or-later
-//
-// 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 media
-
-/*
- The code in this file is taken from the following source:
- https://github.com/google/wuffs/blob/414a011491ff513b86d8694c5d71800f3cb5a715/script/strip-png-ancillary-chunks.go
-
- It presents a workaround for this issue: https://github.com/golang/go/issues/43382
-
- The license for the copied code is reproduced below:
-
- Copyright 2021 The Wuffs Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- https://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-// strip-png-ancillary-chunks.go copies PNG data from stdin to stdout, removing
-// any ancillary chunks.
-//
-// Specification-compliant PNG decoders are required to honor critical chunks
-// but may ignore ancillary (non-critical) chunks. Stripping out ancillary
-// chunks before decoding should mean that different PNG decoders will agree on
-// the decoded output regardless of which ancillary chunk types they choose to
-// honor. Specifically, some PNG decoders may implement color and gamma
-// correction but not all do.
-//
-// This program will strip out all ancillary chunks, but it should be
-// straightforward to copy-paste-and-modify it to strip out only certain chunk
-// types (e.g. only "tRNS" transparency chunks).
-//
-// --------
-//
-// A PNG file consists of an 8-byte magic identifier and then a series of
-// chunks. Each chunk is:
-//
-// - a 4-byte uint32 payload length N.
-// - a 4-byte chunk type (e.g. "gAMA" for gamma correction metadata).
-// - an N-byte payload.
-// - a 4-byte CRC-32 checksum of the previous (N + 4) bytes, including the
-// chunk type but excluding the payload length.
-//
-// Chunk types consist of 4 ASCII letters. The upper-case / lower-case bit of
-// the first letter denote critical or ancillary chunks: "IDAT" and "PLTE" are
-// critical, "gAMA" and "tEXt" are ancillary. See
-// https://www.w3.org/TR/2003/REC-PNG-20031110/#5Chunk-naming-conventions
-//
-// --------
-
-import (
- "encoding/binary"
- "io"
-)
-
-const (
- chunkTypeIHDR = 0x49484452
- chunkTypePLTE = 0x504C5445
- chunkTypeIDAT = 0x49444154
- chunkTypeIEND = 0x49454E44
- chunkTypeTRNS = 0x74524e53
-)
-
-func isNecessaryChunkType(chunkType uint32) bool {
- switch chunkType {
- case chunkTypeIHDR:
- return true
- case chunkTypePLTE:
- return true
- case chunkTypeIDAT:
- return true
- case chunkTypeIEND:
- return true
- case chunkTypeTRNS:
- return true
- }
- return false
-}
-
-// pngAncillaryChunkStripper wraps another io.Reader to strip ancillary chunks,
-// if the data is in the PNG file format. If the data isn't PNG, it is passed
-// through unmodified.
-type pngAncillaryChunkStripper struct {
- // Reader is the wrapped io.Reader.
- Reader io.Reader
-
- // stickyErr is the first error returned from the wrapped io.Reader.
- stickyErr error
-
- // buffer[rIndex:wIndex] holds data read from the wrapped io.Reader that
- // wasn't passed through yet.
- buffer [8]byte
- rIndex int
- wIndex int
-
- // pending and discard is the number of remaining bytes for (and whether to
- // discard or pass through) the current chunk-in-progress.
- pending int64
- discard bool
-
- // notPNG is set true if the data stream doesn't start with the 8-byte PNG
- // magic identifier. If true, the wrapped io.Reader's data (including the
- // first up-to-8 bytes) is passed through without modification.
- notPNG bool
-
- // seenMagic is whether we've seen the 8-byte PNG magic identifier.
- seenMagic bool
-}
-
-// Read implements io.Reader.
-func (r *pngAncillaryChunkStripper) Read(p []byte) (int, error) {
- for {
- // If the wrapped io.Reader returned a non-nil error, drain r.buffer
- // (what data we have) and return that error (if fully drained).
- if r.stickyErr != nil {
- n := copy(p, r.buffer[r.rIndex:r.wIndex])
- r.rIndex += n
- if r.rIndex < r.wIndex {
- return n, nil
- }
- return n, r.stickyErr
- }
-
- // Handle trivial requests, including draining our buffer.
- if len(p) == 0 {
- return 0, nil
- } else if r.rIndex < r.wIndex {
- n := copy(p, r.buffer[r.rIndex:r.wIndex])
- r.rIndex += n
- return n, nil
- }
-
- // From here onwards, our buffer is drained: r.rIndex == r.wIndex.
-
- // Handle non-PNG input.
- if r.notPNG {
- return r.Reader.Read(p)
- }
-
- // Continue processing any PNG chunk that's in progress, whether
- // discarding it or passing it through.
- for r.pending > 0 {
- if int64(len(p)) > r.pending {
- p = p[:r.pending]
- }
- n, err := r.Reader.Read(p)
- r.pending -= int64(n)
- r.stickyErr = err
- if r.discard {
- continue
- }
- return n, err
- }
-
- // We're either expecting the 8-byte PNG magic identifier or the 4-byte
- // PNG chunk length + 4-byte PNG chunk type. Either way, read 8 bytes.
- r.rIndex = 0
- r.wIndex, r.stickyErr = io.ReadFull(r.Reader, r.buffer[:8])
- if r.stickyErr != nil {
- // Undo io.ReadFull converting io.EOF to io.ErrUnexpectedEOF.
- if r.stickyErr == io.ErrUnexpectedEOF {
- r.stickyErr = io.EOF
- }
- continue
- }
-
- // Process those 8 bytes, either:
- // - a PNG chunk (if we've already seen the PNG magic identifier),
- // - the PNG magic identifier itself (if the input is a PNG) or
- // - something else (if it's not a PNG).
- //nolint:gocritic
- if r.seenMagic {
- // The number of pending bytes is equal to (N + 4) because of the 4
- // byte trailer, a checksum.
- r.pending = int64(binary.BigEndian.Uint32(r.buffer[:4])) + 4
- chunkType := binary.BigEndian.Uint32(r.buffer[4:])
- r.discard = !isNecessaryChunkType(chunkType)
- if r.discard {
- r.rIndex = r.wIndex
- }
- } else if string(r.buffer[:8]) == "\x89PNG\x0D\x0A\x1A\x0A" {
- r.seenMagic = true
- } else {
- r.notPNG = true
- }
- }
-}