diff options
| author | 2026-02-20 19:06:13 +0800 | |
|---|---|---|
| committer | 2026-02-20 19:07:14 +0800 | |
| commit | aa513c069c1418734aea894dc944e27c6a78a3bb (patch) | |
| tree | 687f0a11bb550fa088fd82a98ceb8979bbc35f69 /internal/flatex | |
| parent | Comment on prior reverts removing the pack writing API (diff) | |
| signature | No signature | |
Delete everything, I'm redesigning this.
I'll stop using a flat package and make things much more modular.
And also experiment with streaming APIs so large blobs don't OOM us.
Diffstat (limited to 'internal/flatex')
| -rw-r--r-- | internal/flatex/LICENSE | 27 | ||||
| -rw-r--r-- | internal/flatex/decompress.go | 38 | ||||
| -rw-r--r-- | internal/flatex/decompress_test.go | 57 | ||||
| -rw-r--r-- | internal/flatex/huffman.go | 245 | ||||
| -rw-r--r-- | internal/flatex/slice_inflate.go | 472 | ||||
| -rw-r--r-- | internal/flatex/window_decoder.go | 101 |
6 files changed, 0 insertions, 940 deletions
diff --git a/internal/flatex/LICENSE b/internal/flatex/LICENSE deleted file mode 100644 index 2a7cf70d..00000000 --- a/internal/flatex/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/flatex/decompress.go b/internal/flatex/decompress.go deleted file mode 100644 index 065e23f3..00000000 --- a/internal/flatex/decompress.go +++ /dev/null @@ -1,38 +0,0 @@ -package flatex - -import ( - "io" - - "codeberg.org/lindenii/furgit/internal/bufpool" -) - -func DecompressSized(src []byte, sizeHint int) (bufpool.Buffer, int, error) { - d := sliceInflaterPool.Get().(*sliceInflater) - defer sliceInflaterPool.Put(d) - - if err := d.reset(src); err != nil { - return bufpool.Buffer{}, 0, err - } - - out := bufpool.Borrow(sizeHint) - out.Resize(0) - - for { - if len(d.toRead) > 0 { - out.Append(d.toRead) - d.toRead = nil - continue - } - if d.err != nil { - if d.err == io.EOF { - return out, d.pos, nil - } - out.Release() - return bufpool.Buffer{}, 0, d.err - } - d.step(d) - if d.err != nil && len(d.toRead) == 0 { - d.toRead = d.window.readFlush() - } - } -} diff --git a/internal/flatex/decompress_test.go b/internal/flatex/decompress_test.go deleted file mode 100644 index e53a6581..00000000 --- a/internal/flatex/decompress_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package flatex - -import ( - "bytes" - stdflate "compress/flate" - "testing" -) - -func compressDeflate(t *testing.T, payload []byte) []byte { - t.Helper() - var buf bytes.Buffer - w, err := stdflate.NewWriter(&buf, stdflate.DefaultCompression) - 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 TestDecompressSized(t *testing.T) { - payload := bytes.Repeat([]byte("golang"), 32) - compressed := compressDeflate(t, payload) - - out, _, err := DecompressSized(compressed, 0) - if err != nil { - t.Fatalf("DecompressSized: %v", err) - } - defer out.Release() - - if !bytes.Equal(out.Bytes(), payload) { - t.Fatalf("unexpected payload: got %q", out.Bytes()) - } -} - -func TestDecompressSizedUsesHint(t *testing.T) { - payload := []byte("short") - compressed := compressDeflate(t, payload) - - const hint = 1 << 19 - out, _, err := DecompressSized(compressed, hint) - if err != nil { - t.Fatalf("DecompressSized: %v", err) - } - defer out.Release() - - if !bytes.Equal(out.Bytes(), payload) { - t.Fatalf("unexpected payload: got %q", out.Bytes()) - } - if cap(out.Bytes()) < hint { - t.Fatalf("expected capacity >= %d, got %d", hint, cap(out.Bytes())) - } -} diff --git a/internal/flatex/huffman.go b/internal/flatex/huffman.go deleted file mode 100644 index 32172dbb..00000000 --- a/internal/flatex/huffman.go +++ /dev/null @@ -1,245 +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 flatex implements the DEFLATE compressed data format, described in -// RFC 1951. The [compress/gzip] and [compress/zlib] packages implement access -// to DEFLATE-based file formats. -package flatex - -import ( - "math/bits" - "strconv" - "sync" -) - -const ( - // The special code used to mark the end of a block. - endBlockMarker = 256 - maxCodeLen = 16 // max length of Huffman code - maxMatchOffset = 1 << 15 // The largest match offset - // The next three numbers come from the RFC section 3.2.7, with the - // additional proviso in section 3.2.5 which implies that distance codes - // 30 and 31 should never occur in compressed data. - maxNumLit = 286 - maxNumDist = 30 - numCodes = 19 // number of codes in Huffman meta-code -) - -// A CorruptInputError reports the presence of corrupt input at a given offset. -type CorruptInputError int64 - -func (e CorruptInputError) Error() string { - return "flate: corrupt input before offset " + strconv.FormatInt(int64(e), 10) -} - -// The data structure for decoding Huffman tables is based on that of -// zlib. There is a lookup table of a fixed bit width (huffmanChunkBits), -// For codes smaller than the table width, there are multiple entries -// (each combination of trailing bits has the same value). For codes -// larger than the table width, the table contains a link to an overflow -// table. The width of each entry in the link table is the maximum code -// size minus the chunk width. -// -// Note that you can do a lookup in the table even without all bits -// filled. Since the extra bits are zero, and the DEFLATE Huffman codes -// have the property that shorter codes come before longer ones, the -// bit length estimate in the result is a lower bound on the actual -// number of bits. -// -// See the following: -// https://github.com/madler/zlib/raw/master/doc/algorithm.txt - -// chunk & 15 is number of bits -// chunk >> 4 is value, including table link - -const ( - huffmanChunkBits = 9 - huffmanNumChunks = 1 << huffmanChunkBits - huffmanCountMask = 15 - huffmanValueShift = 4 -) - -type huffmanDecoder struct { - min int // the minimum code length - chunks [huffmanNumChunks]uint32 // chunks as described above - links [][]uint32 // overflow links - linkMask uint32 // mask the width of the link table -} - -// Initialize Huffman decoding tables from array of code lengths. -// Following this function, h is guaranteed to be initialized into a complete -// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a -// degenerate case where the tree has only a single symbol with length 1. Empty -// trees are permitted. -func (h *huffmanDecoder) init(lengths []int) bool { - // Sanity enables additional runtime tests during Huffman - // table construction. It's intended to be used during - // development to supplement the currently ad-hoc unit tests. - const sanity = false - - if h.min != 0 { - *h = huffmanDecoder{} - } - - // Count number of codes of each length, - // compute min and max length. - var count [maxCodeLen]int - var min, max int - for _, n := range lengths { - if n == 0 { - continue - } - if min == 0 || n < min { - min = n - } - if n > max { - max = n - } - count[n]++ - } - - // Empty tree. The decompressor.huffSym function will fail later if the tree - // is used. Technically, an empty tree is only valid for the HDIST tree and - // not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree - // is guaranteed to fail since it will attempt to use the tree to decode the - // codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is - // guaranteed to fail later since the compressed data section must be - // composed of at least one symbol (the end-of-block marker). - if max == 0 { - return true - } - - code := 0 - var nextcode [maxCodeLen]int - for i := min; i <= max; i++ { - code <<= 1 - nextcode[i] = code - code += count[i] - } - - // Check that the coding is complete (i.e., that we've - // assigned all 2-to-the-max possible bit sequences). - // Exception: To be compatible with zlib, we also need to - // accept degenerate single-code codings. See also - // TestDegenerateHuffmanCoding. - if code != 1<<uint(max) && (code != 1 || max != 1) { - return false - } - - h.min = min - if max > huffmanChunkBits { - numLinks := 1 << (uint(max) - huffmanChunkBits) - h.linkMask = uint32(numLinks - 1) - - // create link tables - link := nextcode[huffmanChunkBits+1] >> 1 - h.links = make([][]uint32, huffmanNumChunks-link) - for j := uint(link); j < huffmanNumChunks; j++ { - reverse := int(bits.Reverse16(uint16(j))) - reverse >>= uint(16 - huffmanChunkBits) - off := j - uint(link) - if sanity && h.chunks[reverse] != 0 { - panic("impossible: overwriting existing chunk") - } - h.chunks[reverse] = uint32(off<<huffmanValueShift | (huffmanChunkBits + 1)) - h.links[off] = make([]uint32, numLinks) - } - } - - for i, n := range lengths { - if n == 0 { - continue - } - code := nextcode[n] - nextcode[n]++ - chunk := uint32(i<<huffmanValueShift | n) - reverse := int(bits.Reverse16(uint16(code))) - reverse >>= uint(16 - n) - if n <= huffmanChunkBits { - for off := reverse; off < len(h.chunks); off += 1 << uint(n) { - // We should never need to overwrite - // an existing chunk. Also, 0 is - // never a valid chunk, because the - // lower 4 "count" bits should be - // between 1 and 15. - if sanity && h.chunks[off] != 0 { - panic("impossible: overwriting existing chunk") - } - h.chunks[off] = chunk - } - } else { - j := reverse & (huffmanNumChunks - 1) - if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 { - // Longer codes should have been - // associated with a link table above. - panic("impossible: not an indirect chunk") - } - value := h.chunks[j] >> huffmanValueShift - linktab := h.links[value] - reverse >>= huffmanChunkBits - for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) { - if sanity && linktab[off] != 0 { - panic("impossible: overwriting existing chunk") - } - linktab[off] = chunk - } - } - } - - if sanity { - // Above we've sanity checked that we never overwrote - // an existing entry. Here we additionally check that - // we filled the tables completely. - for i, chunk := range h.chunks { - if chunk == 0 { - // As an exception, in the degenerate - // single-code case, we allow odd - // chunks to be missing. - if code == 1 && i%2 == 1 { - continue - } - panic("impossible: missing chunk") - } - } - for _, linktab := range h.links { - for _, chunk := range linktab { - if chunk == 0 { - panic("impossible: missing chunk") - } - } - } - } - - return true -} - -// RFC 1951 section 3.2.7. -// Compression with dynamic Huffman codes -var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15} - -var ( - // Initialize the fixedHuffmanDecoder only once upon first use. - fixedOnce sync.Once - fixedHuffmanDecoder huffmanDecoder -) - -func fixedHuffmanDecoderInit() { - fixedOnce.Do(func() { - // These come from the RFC section 3.2.6. - var bits [288]int - for i := 0; i < 144; i++ { - bits[i] = 8 - } - for i := 144; i < 256; i++ { - bits[i] = 9 - } - for i := 256; i < 280; i++ { - bits[i] = 7 - } - for i := 280; i < 288; i++ { - bits[i] = 8 - } - fixedHuffmanDecoder.init(bits[:]) - }) -} diff --git a/internal/flatex/slice_inflate.go b/internal/flatex/slice_inflate.go deleted file mode 100644 index f9120143..00000000 --- a/internal/flatex/slice_inflate.go +++ /dev/null @@ -1,472 +0,0 @@ -package flatex - -import ( - "io" - "math/bits" - "sync" -) - -// sliceInflater is a specialized DEFLATE decoder that reads directly from an -// in-memory byte slice. It mirrors the main decompressor but avoids the -// overhead of the Reader interfaces, enabling faster byte-slice decoding. -type sliceInflater struct { - input []byte - pos int - roffset int64 - - b uint32 - nb uint - - h1, h2 huffmanDecoder - - bits *[maxNumLit + maxNumDist]int - codebits *[numCodes]int - - window windowDecoder - - toRead []byte - step func(*sliceInflater) - stepState int - final bool - err error - hl, hd *huffmanDecoder - copyLen int - copyDist int -} - -var sliceInflaterPool = sync.Pool{ - New: func() any { - fixedHuffmanDecoderInit() - return &sliceInflater{ - bits: new([maxNumLit + maxNumDist]int), - codebits: new([numCodes]int), - } - }, -} - -func (f *sliceInflater) reset(src []byte) error { - bits := f.bits - codebits := f.codebits - windowState := f.window - *f = sliceInflater{ - input: src, - bits: bits, - codebits: codebits, - window: windowState, - step: (*sliceInflater).nextBlock, - } - f.window.init(maxMatchOffset) - return nil -} - -func (f *sliceInflater) nextBlock() { - for f.nb < 1+2 { - if err := f.moreBits(); err != nil { - f.err = err - return - } - } - f.final = f.b&1 == 1 - f.b >>= 1 - typ := f.b & 3 - f.b >>= 2 - f.nb -= 1 + 2 - switch typ { - case 0: - f.dataBlock() - case 1: - f.hl = &fixedHuffmanDecoder - f.hd = nil - f.huffmanBlock() - case 2: - if err := f.readHuffman(); err != nil { - f.err = err - return - } - f.hl = &f.h1 - f.hd = &f.h2 - f.huffmanBlock() - default: - f.err = CorruptInputError(f.roffset) - } -} - -func (f *sliceInflater) huffmanBlock() { - const ( - stateInit = iota - stateDict - ) - switch f.stepState { - case stateInit: - goto readLiteral - case stateDict: - goto copyHistory - } - -readLiteral: - { - v, err := f.huffSym(f.hl) - if err != nil { - f.err = err - return - } - var n uint - var length int - switch { - case v < 256: - f.window.writeByte(byte(v)) - if f.window.availWrite() == 0 { - f.toRead = f.window.readFlush() - f.step = (*sliceInflater).huffmanBlock - f.stepState = stateInit - return - } - goto readLiteral - case v == 256: - f.finishBlock() - return - case v < 265: - length = v - (257 - 3) - n = 0 - case v < 269: - length = v*2 - (265*2 - 11) - n = 1 - case v < 273: - length = v*4 - (269*4 - 19) - n = 2 - case v < 277: - length = v*8 - (273*8 - 35) - n = 3 - case v < 281: - length = v*16 - (277*16 - 67) - n = 4 - case v < 285: - length = v*32 - (281*32 - 131) - n = 5 - case v < maxNumLit: - length = 258 - n = 0 - default: - f.err = CorruptInputError(f.roffset) - return - } - if n > 0 { - for f.nb < n { - if err = f.moreBits(); err != nil { - f.err = err - return - } - } - length += int(f.b & uint32(1<<n-1)) - f.b >>= n - f.nb -= n - } - - var dist int - if f.hd == nil { - for f.nb < 5 { - if err = f.moreBits(); err != nil { - f.err = err - return - } - } - dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3))) - f.b >>= 5 - f.nb -= 5 - } else { - if dist, err = f.huffSym(f.hd); err != nil { - f.err = err - return - } - } - - switch { - case dist < 4: - dist++ - case dist < maxNumDist: - nb := uint(dist-2) >> 1 - extra := (dist & 1) << nb - for f.nb < nb { - if err = f.moreBits(); err != nil { - f.err = err - return - } - } - extra |= int(f.b & uint32(1<<nb-1)) - f.b >>= nb - f.nb -= nb - dist = 1<<(nb+1) + 1 + extra - default: - f.err = CorruptInputError(f.roffset) - return - } - - if dist > f.window.histSize() { - f.err = CorruptInputError(f.roffset) - return - } - - f.copyLen, f.copyDist = length, dist - goto copyHistory - } - -copyHistory: - { - cnt := f.window.tryWriteCopy(f.copyDist, f.copyLen) - if cnt == 0 { - cnt = f.window.writeCopy(f.copyDist, f.copyLen) - } - f.copyLen -= cnt - - if f.window.availWrite() == 0 || f.copyLen > 0 { - f.toRead = f.window.readFlush() - f.step = (*sliceInflater).huffmanBlock - f.stepState = stateDict - return - } - goto readLiteral - } -} - -func (f *sliceInflater) dataBlock() { - f.nb = 0 - f.b = 0 - - if f.pos+4 > len(f.input) { - f.pos = len(f.input) - f.err = io.ErrUnexpectedEOF - return - } - hdr := f.input[f.pos : f.pos+4] - f.pos += 4 - f.roffset += 4 - n := int(hdr[0]) | int(hdr[1])<<8 - nn := int(hdr[2]) | int(hdr[3])<<8 - if uint16(nn) != uint16(^n) { - f.err = CorruptInputError(f.roffset) - return - } - - if n == 0 { - f.toRead = f.window.readFlush() - f.finishBlock() - return - } - - f.copyLen = n - f.copyData() -} - -func (f *sliceInflater) copyData() { - for { - if f.copyLen == 0 { - f.finishBlock() - return - } - buf := f.window.writeSlice() - if len(buf) == 0 { - f.toRead = f.window.readFlush() - f.step = (*sliceInflater).copyData - return - } - n := f.copyLen - if n > len(buf) { - n = len(buf) - } - if f.pos+n > len(f.input) { - f.err = io.ErrUnexpectedEOF - return - } - copy(buf[:n], f.input[f.pos:f.pos+n]) - f.pos += n - f.roffset += int64(n) - f.copyLen -= n - f.window.writeMark(n) - if f.window.availWrite() == 0 { - f.toRead = f.window.readFlush() - f.step = (*sliceInflater).copyData - return - } - } -} - -func (f *sliceInflater) finishBlock() { - if f.final { - if f.window.availRead() > 0 { - f.toRead = f.window.readFlush() - } - f.err = io.EOF - } - f.step = (*sliceInflater).nextBlock - f.stepState = 0 -} - -func (f *sliceInflater) moreBits() error { - if f.pos >= len(f.input) { - return io.ErrUnexpectedEOF - } - c := f.input[f.pos] - f.pos++ - f.roffset++ - f.b |= uint32(c) << (f.nb & 31) - f.nb += 8 - return nil -} - -func (f *sliceInflater) huffSym(h *huffmanDecoder) (int, error) { - n := uint(h.min) - nb, b := f.nb, f.b - for { - for nb < n { - if f.pos >= len(f.input) { - f.b = b - f.nb = nb - return 0, io.ErrUnexpectedEOF - } - c := f.input[f.pos] - f.pos++ - f.roffset++ - b |= uint32(c) << (nb & 31) - nb += 8 - } - chunk := h.chunks[b&(huffmanNumChunks-1)] - n = uint(chunk & huffmanCountMask) - if n > huffmanChunkBits { - chunk = h.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&h.linkMask] - n = uint(chunk & huffmanCountMask) - } - if n <= nb { - if n == 0 { - f.b = b - f.nb = nb - f.err = CorruptInputError(f.roffset) - return 0, f.err - } - f.b = b >> (n & 31) - f.nb = nb - n - return int(chunk >> huffmanValueShift), nil - } - } -} - -func (f *sliceInflater) readHuffman() error { - for f.nb < 5+5+4 { - if err := f.moreBits(); err != nil { - return err - } - } - nlit := int(f.b&0x1F) + 257 - if nlit > maxNumLit { - return CorruptInputError(f.roffset) - } - f.b >>= 5 - ndist := int(f.b&0x1F) + 1 - if ndist > maxNumDist { - return CorruptInputError(f.roffset) - } - f.b >>= 5 - nclen := int(f.b&0xF) + 4 - f.b >>= 4 - f.nb -= 5 + 5 + 4 - codebits := f.codebits[:] - bits := f.bits[:] - clear(codebits) - clear(bits) - for i := 0; i < nclen; i++ { - for f.nb < 3 { - if err := f.moreBits(); err != nil { - return err - } - } - codebits[codeOrder[i]] = int(f.b & 0x7) - f.b >>= 3 - f.nb -= 3 - } - if !f.h1.init(codebits) { - return CorruptInputError(f.roffset) - } - for i := range bits { - bits[i] = 0 - } - i := 0 - for i < nlit+ndist { - x, err := f.huffSym(&f.h1) - if err != nil { - return err - } - switch { - case x < 16: - bits[i] = x - i++ - case x == 16: - if i == 0 { - return CorruptInputError(f.roffset) - } - repeat := 3 - for f.nb < 2 { - if err := f.moreBits(); err != nil { - return err - } - } - repeat += int(f.b & 0x3) - f.b >>= 2 - f.nb -= 2 - for repeat > 0 { - if i >= len(bits) { - return CorruptInputError(f.roffset) - } - bits[i] = bits[i-1] - i++ - repeat-- - } - case x == 17: - repeat := 3 - for f.nb < 3 { - if err := f.moreBits(); err != nil { - return err - } - } - repeat += int(f.b & 0x7) - f.b >>= 3 - f.nb -= 3 - for repeat > 0 { - if i >= len(bits) { - return CorruptInputError(f.roffset) - } - bits[i] = 0 - i++ - repeat-- - } - case x == 18: - repeat := 11 - for f.nb < 7 { - if err := f.moreBits(); err != nil { - return err - } - } - repeat += int(f.b & 0x7F) - f.b >>= 7 - f.nb -= 7 - for repeat > 0 { - if i >= len(bits) { - return CorruptInputError(f.roffset) - } - bits[i] = 0 - i++ - repeat-- - } - default: - return CorruptInputError(f.roffset) - } - } - if !f.h1.init(bits[:nlit]) { - return CorruptInputError(f.roffset) - } - if !f.h2.init(bits[nlit : nlit+ndist]) { - return CorruptInputError(f.roffset) - } - if f.h1.min < bits[endBlockMarker] { - f.h1.min = bits[endBlockMarker] - } - return nil -} diff --git a/internal/flatex/window_decoder.go b/internal/flatex/window_decoder.go deleted file mode 100644 index 492c6a96..00000000 --- a/internal/flatex/window_decoder.go +++ /dev/null @@ -1,101 +0,0 @@ -package flatex - -// windowDecoder implements the sliding window used in decompression. -type windowDecoder struct { - hist []byte - - wrPos int - rdPos int - full bool -} - -func (wd *windowDecoder) init(size int) { - *wd = windowDecoder{hist: wd.hist} - - if cap(wd.hist) < size { - wd.hist = make([]byte, size) - } - wd.hist = wd.hist[:size] - - wd.wrPos = 0 - wd.rdPos = 0 - wd.full = false -} - -func (wd *windowDecoder) histSize() int { - if wd.full { - return len(wd.hist) - } - return wd.wrPos -} - -func (wd *windowDecoder) availRead() int { - return wd.wrPos - wd.rdPos -} - -func (wd *windowDecoder) availWrite() int { - return len(wd.hist) - wd.wrPos -} - -func (wd *windowDecoder) writeSlice() []byte { - return wd.hist[wd.wrPos:] -} - -func (wd *windowDecoder) writeMark(cnt int) { - wd.wrPos += cnt -} - -func (wd *windowDecoder) writeByte(c byte) { - wd.hist[wd.wrPos] = c - wd.wrPos++ -} - -func (wd *windowDecoder) writeCopy(dist, length int) int { - dstBase := wd.wrPos - dstPos := dstBase - srcPos := dstPos - dist - endPos := dstPos + length - if endPos > len(wd.hist) { - endPos = len(wd.hist) - } - - if srcPos < 0 { - srcPos += len(wd.hist) - dstPos += copy(wd.hist[dstPos:endPos], wd.hist[srcPos:]) - srcPos = 0 - } - - for dstPos < endPos { - dstPos += copy(wd.hist[dstPos:endPos], wd.hist[srcPos:dstPos]) - } - - wd.wrPos = dstPos - return dstPos - dstBase -} - -func (wd *windowDecoder) tryWriteCopy(dist, length int) int { - dstPos := wd.wrPos - endPos := dstPos + length - if dstPos < dist || endPos > len(wd.hist) { - return 0 - } - dstBase := dstPos - srcPos := dstPos - dist - - for dstPos < endPos { - dstPos += copy(wd.hist[dstPos:endPos], wd.hist[srcPos:dstPos]) - } - - wd.wrPos = dstPos - return dstPos - dstBase -} - -func (wd *windowDecoder) readFlush() []byte { - toRead := wd.hist[wd.rdPos:wd.wrPos] - wd.rdPos = wd.wrPos - if wd.wrPos == len(wd.hist) { - wd.wrPos, wd.rdPos = 0, 0 - wd.full = true - } - return toRead -} |
