diff options
| author | 2025-11-19 08:00:00 +0800 | |
|---|---|---|
| committer | 2025-11-19 08:00:00 +0800 | |
| commit | ed0a113f034aa42aea23471c4bc0d7af159b7002 (patch) | |
| tree | 7e828011b9e213499ce382eb17e2552da6e48de4 /internal/zlibx/decompress.go | |
| parent | Remove some redundant code (diff) | |
| signature | No signature | |
Probably should name the custom packages specially
Diffstat (limited to 'internal/zlibx/decompress.go')
| -rw-r--r-- | internal/zlibx/decompress.go | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/internal/zlibx/decompress.go b/internal/zlibx/decompress.go new file mode 100644 index 00000000..34e62c6f --- /dev/null +++ b/internal/zlibx/decompress.go @@ -0,0 +1,69 @@ +package zlibx + +import ( + "encoding/binary" + "io" + + "git.sr.ht/~runxiyu/furgit/internal/adler32" + "git.sr.ht/~runxiyu/furgit/internal/bufpool" + "git.sr.ht/~runxiyu/furgit/internal/flatex" +) + +// 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 := flatex.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 +} |
