diff options
Diffstat (limited to 'internal/zlib')
| -rw-r--r-- | internal/zlib/LICENSE | 27 | ||||
| -rw-r--r-- | internal/zlib/decompress.go | 69 | ||||
| -rw-r--r-- | internal/zlib/decompress_test.go | 84 | ||||
| -rw-r--r-- | internal/zlib/reader.go | 198 |
4 files changed, 0 insertions, 378 deletions
diff --git a/internal/zlib/LICENSE b/internal/zlib/LICENSE deleted file mode 100644 index 2a7cf70d..00000000 --- a/internal/zlib/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright 2009 The Go Authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google LLC nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/internal/zlib/decompress.go b/internal/zlib/decompress.go deleted file mode 100644 index 55f6d3e2..00000000 --- a/internal/zlib/decompress.go +++ /dev/null @@ -1,69 +0,0 @@ -package zlib - -import ( - "encoding/binary" - "io" - - "git.sr.ht/~runxiyu/furgit/internal/adler32" - "git.sr.ht/~runxiyu/furgit/internal/bufpool" - "git.sr.ht/~runxiyu/furgit/internal/flate" -) - -// Decompress inflates the provided zlib wrapped stream and returns the -// uncompressed data inside a pooled bufpool.Buffer. -func Decompress(src []byte) (bufpool.Buffer, error) { - return DecompressDict(src, nil) -} - -// DecompressDict is like Decompress but accepts a preset dictionary. The -// dictionary must match the checksum embedded in the stream if the dictionary -// flag is present. -func DecompressDict(src []byte, dict []byte) (bufpool.Buffer, error) { - if len(src) < 6 { - return bufpool.Buffer{}, io.ErrUnexpectedEOF - } - - cmf := src[0] - flg := src[1] - if (cmf&0x0f != zlibDeflate) || (cmf>>4 > zlibMaxWindow) || (binary.BigEndian.Uint16(src[:2])%31 != 0) { - return bufpool.Buffer{}, ErrHeader - } - - offset := 2 - haveDict := flg&0x20 != 0 - if haveDict { - if len(src) < offset+4 { - return bufpool.Buffer{}, io.ErrUnexpectedEOF - } - if dict == nil { - return bufpool.Buffer{}, ErrDictionary - } - checksum := binary.BigEndian.Uint32(src[offset : offset+4]) - if checksum != adler32.Checksum(dict) { - return bufpool.Buffer{}, ErrDictionary - } - offset += 4 - } - - if len(src[offset:]) < 4 { - return bufpool.Buffer{}, io.ErrUnexpectedEOF - } - - deflateData := src[offset:] - out, consumed, err := flate.DecompressDict(deflateData, dict) - if err != nil { - return bufpool.Buffer{}, err - } - - checksumPos := offset + consumed - if checksumPos+4 > len(src) { - out.Release() - return bufpool.Buffer{}, io.ErrUnexpectedEOF - } - expected := binary.BigEndian.Uint32(src[checksumPos : checksumPos+4]) - if expected != adler32.Checksum(out.Bytes()) { - out.Release() - return bufpool.Buffer{}, ErrChecksum - } - return out, nil -} diff --git a/internal/zlib/decompress_test.go b/internal/zlib/decompress_test.go deleted file mode 100644 index bb517ae6..00000000 --- a/internal/zlib/decompress_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package zlib - -import ( - "bytes" - stdzlib "compress/zlib" - "testing" -) - -func compressZlib(t *testing.T, payload, dict []byte) []byte { - t.Helper() - var buf bytes.Buffer - var ( - w *stdzlib.Writer - err error - ) - if dict != nil { - w, err = stdzlib.NewWriterLevelDict(&buf, stdzlib.DefaultCompression, dict) - } else { - w = stdzlib.NewWriter(&buf) - } - if err != nil { - t.Fatalf("NewWriter: %v", err) - } - if _, err := w.Write(payload); err != nil { - t.Fatalf("Write: %v", err) - } - if err := w.Close(); err != nil { - t.Fatalf("Close: %v", err) - } - return buf.Bytes() -} - -func TestDecompress(t *testing.T) { - payload := []byte("hello, zlib world!") - compressed := compressZlib(t, payload, nil) - - out, err := Decompress(compressed) - if err != nil { - t.Fatalf("Decompress: %v", err) - } - defer out.Release() - - if !bytes.Equal(out.Bytes(), payload) { - t.Fatalf("unexpected payload %q", out.Bytes()) - } -} - -func TestDecompressDict(t *testing.T) { - dict := []byte("git dictionary for zlib") - payload := append([]byte(nil), dict...) - payload = append(payload, []byte(" -- extended body -- extended body")...) - compressed := compressZlib(t, payload, dict) - - out, err := DecompressDict(compressed, dict) - if err != nil { - t.Fatalf("DecompressDict: %v", err) - } - defer out.Release() - - if !bytes.Equal(out.Bytes(), payload) { - t.Fatalf("unexpected payload %q", out.Bytes()) - } -} - -func TestDecompressDictMissing(t *testing.T) { - dict := []byte("preset dictionary") - payload := append([]byte(nil), dict...) - payload = append(payload, []byte(" .. more data ..")...) - compressed := compressZlib(t, payload, dict) - - if _, err := Decompress(compressed); err != ErrDictionary { - t.Fatalf("expected ErrDictionary, got %v", err) - } -} - -func TestDecompressChecksumError(t *testing.T) { - payload := []byte("checksum check") - compressed := compressZlib(t, payload, nil) - compressed[len(compressed)-1] ^= 0xff - - if _, err := Decompress(compressed); err != ErrChecksum { - t.Fatalf("expected ErrChecksum, got %v", err) - } -} diff --git a/internal/zlib/reader.go b/internal/zlib/reader.go deleted file mode 100644 index 2c8fd215..00000000 --- a/internal/zlib/reader.go +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package zlib implements reading and writing of zlib format compressed data, -as specified in RFC 1950. - -This package differs from the standard library's compress/zlib package -in that it pools readers to reduce allocations. Writers are unchanged. - -Note that closing the reader causes it to be returned to a pool for -reuse. Therefore, the caller must not retain references to the -reader after closing it; in the standard library's compress/zlib package, -it is legal to Reset a closed reader and continue using it; that is -not allowed here, so there is simply no Resetter interface. - -The implementation provides filters that uncompress during reading -and compress during writing. For example, to write compressed data -to a buffer: - - var b bytes.Buffer - w := zlib.NewWriter(&b) - w.Write([]byte("hello, world\n")) - w.Close() - -and to read that data back: - - r, err := zlib.NewReader(&b) - io.Copy(os.Stdout, r) - r.Close() -*/ -package zlib - -import ( - "bufio" - "encoding/binary" - "errors" - "hash" - "io" - "sync" - - "git.sr.ht/~runxiyu/furgit/internal/adler32" - "git.sr.ht/~runxiyu/furgit/internal/flate" -) - -const ( - zlibDeflate = 8 - zlibMaxWindow = 7 -) - -var ( - // ErrChecksum is returned when reading ZLIB data that has an invalid checksum. - ErrChecksum = errors.New("zlib: invalid checksum") - // ErrDictionary is returned when reading ZLIB data that has an invalid dictionary. - ErrDictionary = errors.New("zlib: invalid dictionary") - // ErrHeader is returned when reading ZLIB data that has an invalid header. - ErrHeader = errors.New("zlib: invalid header") -) - -var pool = sync.Pool{ - New: func() any { - r := new(reader) - return r - }, -} - -type reader struct { - r flate.Reader - decompressor io.ReadCloser - digest hash.Hash32 - err error - scratch [4]byte -} - -// NewReader creates a new ReadCloser. -// Reads from the returned ReadCloser read and decompress data from r. -// If r does not implement [io.ByteReader], the decompressor may read more -// data than necessary from r. -// It is the caller's responsibility to call Close on the ReadCloser when done. -func NewReader(r io.Reader) (io.ReadCloser, error) { - return NewReaderDict(r, nil) -} - -// NewReaderDict is like [NewReader] but uses a preset dictionary. -// NewReaderDict ignores the dictionary if the compressed data does not refer to it. -// If the compressed data refers to a different dictionary, NewReaderDict returns [ErrDictionary]. -func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) { - v := pool.Get() - z, ok := v.(*reader) - if !ok { - panic("zlib: pool returned unexpected type") - } - err := z.Reset(r, dict) - if err != nil { - return nil, err - } - return z, nil -} - -func (z *reader) Read(p []byte) (int, error) { - if z.err != nil { - return 0, z.err - } - - var n int - n, z.err = z.decompressor.Read(p) - z.digest.Write(p[0:n]) - if z.err != io.EOF { - // In the normal case we return here. - return n, z.err - } - - // Finished file; check checksum. - if _, err := io.ReadFull(z.r, z.scratch[0:4]); err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - z.err = err - return n, z.err - } - // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952). - checksum := binary.BigEndian.Uint32(z.scratch[:4]) - if checksum != z.digest.Sum32() { - z.err = ErrChecksum - return n, z.err - } - return n, io.EOF -} - -// Calling Close does not close the wrapped [io.Reader] originally passed to [NewReader]. -// In order for the ZLIB checksum to be verified, the reader must be -// fully consumed until the [io.EOF]. -func (z *reader) Close() error { - if z.err != nil && z.err != io.EOF { - return z.err - } - z.err = z.decompressor.Close() - if z.err != nil { - return z.err - } - - pool.Put(z) - return nil -} - -func (z *reader) Reset(r io.Reader, dict []byte) error { - *z = reader{decompressor: z.decompressor} - if fr, ok := r.(flate.Reader); ok { - z.r = fr - } else { - z.r = bufio.NewReader(r) - } - - // Read the header (RFC 1950 section 2.2.). - _, z.err = io.ReadFull(z.r, z.scratch[0:2]) - if z.err != nil { - if z.err == io.EOF { - z.err = io.ErrUnexpectedEOF - } - return z.err - } - h := binary.BigEndian.Uint16(z.scratch[:2]) - if (z.scratch[0]&0x0f != zlibDeflate) || (z.scratch[0]>>4 > zlibMaxWindow) || (h%31 != 0) { - z.err = ErrHeader - return z.err - } - haveDict := z.scratch[1]&0x20 != 0 - if haveDict { - _, z.err = io.ReadFull(z.r, z.scratch[0:4]) - if z.err != nil { - if z.err == io.EOF { - z.err = io.ErrUnexpectedEOF - } - return z.err - } - checksum := binary.BigEndian.Uint32(z.scratch[:4]) - if checksum != adler32.Checksum(dict) { - z.err = ErrDictionary - return z.err - } - } - - if z.decompressor == nil { - if haveDict { - z.decompressor = flate.NewReaderDict(z.r, dict) - } else { - z.decompressor = flate.NewReader(z.r) - } - } else { - z.err = z.decompressor.(flate.Resetter).Reset(z.r, dict) - if z.err != nil { - return z.err - } - } - z.digest = adler32.New() - return nil -} |
