diff options
author | Ondřej Surý <ondrej@sury.org> | 2012-01-30 15:38:19 +0100 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2012-01-30 15:38:19 +0100 |
commit | 4cecda6c347bd6902b960c6a35a967add7070b0d (patch) | |
tree | a462e224ff41ec9f3eb1a0b6e815806f9e8804ad /src/pkg/compress/flate | |
parent | 6c7ca6e4d4e26e4c8cbe0d183966011b3b088a0a (diff) | |
download | golang-4cecda6c347bd6902b960c6a35a967add7070b0d.tar.gz |
Imported Upstream version 2012.01.27upstream-weekly/2012.01.27
Diffstat (limited to 'src/pkg/compress/flate')
-rw-r--r-- | src/pkg/compress/flate/Makefile | 1 | ||||
-rw-r--r-- | src/pkg/compress/flate/deflate.go | 132 | ||||
-rw-r--r-- | src/pkg/compress/flate/deflate_test.go | 127 | ||||
-rw-r--r-- | src/pkg/compress/flate/flate_test.go | 12 | ||||
-rw-r--r-- | src/pkg/compress/flate/huffman_bit_writer.go | 35 | ||||
-rw-r--r-- | src/pkg/compress/flate/huffman_code.go | 4 | ||||
-rw-r--r-- | src/pkg/compress/flate/inflate.go | 43 | ||||
-rw-r--r-- | src/pkg/compress/flate/util.go | 72 |
8 files changed, 197 insertions, 229 deletions
diff --git a/src/pkg/compress/flate/Makefile b/src/pkg/compress/flate/Makefile index 197828a92..04fcb6b26 100644 --- a/src/pkg/compress/flate/Makefile +++ b/src/pkg/compress/flate/Makefile @@ -12,6 +12,5 @@ GOFILES=\ inflate.go\ reverse_bits.go\ token.go\ - util.go\ include ../../../Make.pkg diff --git a/src/pkg/compress/flate/deflate.go b/src/pkg/compress/flate/deflate.go index b1cee0b2f..1e725890b 100644 --- a/src/pkg/compress/flate/deflate.go +++ b/src/pkg/compress/flate/deflate.go @@ -7,7 +7,6 @@ package flate import ( "io" "math" - "os" ) const ( @@ -28,10 +27,12 @@ const ( // stop things from getting too large. maxFlateBlockTokens = 1 << 14 maxStoreBlockSize = 65535 - hashBits = 15 + hashBits = 17 hashSize = 1 << hashBits hashMask = (1 << hashBits) - 1 hashShift = (hashBits + minMatchLength - 1) / minMatchLength + + skipNever = math.MaxInt32 ) type compressionLevel struct { @@ -46,12 +47,12 @@ var levels = []compressionLevel{ {3, 0, 32, 32, 6}, // Levels 4-9 use increasingly more lazy matching // and increasingly stringent conditions for "good enough". - {4, 4, 16, 16, math.MaxInt32}, - {8, 16, 32, 32, math.MaxInt32}, - {8, 16, 128, 128, math.MaxInt32}, - {8, 32, 128, 256, math.MaxInt32}, - {32, 128, 258, 1024, math.MaxInt32}, - {32, 258, 258, 4096, math.MaxInt32}, + {4, 4, 16, 16, skipNever}, + {8, 16, 32, 32, skipNever}, + {8, 16, 128, 128, skipNever}, + {8, 32, 128, 256, skipNever}, + {32, 128, 258, 1024, skipNever}, + {32, 258, 258, 4096, skipNever}, } type compressor struct { @@ -69,9 +70,10 @@ type compressor struct { // If hashHead[hashValue] is within the current window, then // hashPrev[hashHead[hashValue] & windowMask] contains the previous index // with the same hash value. - chainHead int - hashHead []int - hashPrev []int + chainHead int + hashHead []int + hashPrev []int + hashOffset int // input window: unprocessed data is window[index:windowEnd] index int @@ -80,16 +82,15 @@ type compressor struct { blockStart int // window index where current tokens start byteAvailable bool // if true, still need to process window[index-1]. - // queued output tokens: tokens[:ti] + // queued output tokens tokens []token - ti int // deflate state length int offset int hash int maxInsertIndex int - err os.Error + err error } func (d *compressor) fillDeflate(b []byte) int { @@ -101,29 +102,16 @@ func (d *compressor) fillDeflate(b []byte) int { if d.blockStart >= windowSize { d.blockStart -= windowSize } else { - d.blockStart = math.MaxInt32 - } - for i, h := range d.hashHead { - v := h - windowSize - if v < -1 { - v = -1 - } - d.hashHead[i] = v - } - for i, h := range d.hashPrev { - v := -h - windowSize - if v < -1 { - v = -1 - } - d.hashPrev[i] = v + d.blockStart = skipNever } + d.hashOffset += windowSize } n := copy(d.window[d.windowEnd:], b) d.windowEnd += n return n } -func (d *compressor) writeBlock(tokens []token, index int, eof bool) os.Error { +func (d *compressor) writeBlock(tokens []token, index int, eof bool) error { if index > 0 || eof { var window []byte if d.blockStart <= index { @@ -187,14 +175,14 @@ func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead // hashPrev[i & windowMask] has already been overwritten, so stop now. break } - if i = d.hashPrev[i&windowMask]; i < minIndex || i < 0 { + if i = d.hashPrev[i&windowMask] - d.hashOffset; i < minIndex || i < 0 { break } } return } -func (d *compressor) writeStoredBlock(buf []byte) os.Error { +func (d *compressor) writeStoredBlock(buf []byte) error { if d.w.writeStoredHeader(len(buf), false); d.w.err != nil { return d.w.err } @@ -206,13 +194,12 @@ func (d *compressor) initDeflate() { d.hashHead = make([]int, hashSize) d.hashPrev = make([]int, windowSize) d.window = make([]byte, 2*windowSize) - fillInts(d.hashHead, -1) - d.tokens = make([]token, maxFlateBlockTokens, maxFlateBlockTokens+1) + d.hashOffset = 1 + d.tokens = make([]token, 0, maxFlateBlockTokens+1) d.length = minMatchLength - 1 d.offset = 0 d.byteAvailable = false d.index = 0 - d.ti = 0 d.hash = 0 d.chainHead = -1 } @@ -244,15 +231,14 @@ Loop: // Flush current output block if any. if d.byteAvailable { // There is still one pending token that needs to be flushed - d.tokens[d.ti] = literalToken(uint32(d.window[d.index-1])) - d.ti++ + d.tokens = append(d.tokens, literalToken(uint32(d.window[d.index-1]))) d.byteAvailable = false } - if d.ti > 0 { - if d.err = d.writeBlock(d.tokens[0:d.ti], d.index, false); d.err != nil { + if len(d.tokens) > 0 { + if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { return } - d.ti = 0 + d.tokens = d.tokens[:0] } break Loop } @@ -262,7 +248,7 @@ Loop: d.hash = (d.hash<<hashShift + int(d.window[d.index+2])) & hashMask d.chainHead = d.hashHead[d.hash] d.hashPrev[d.index&windowMask] = d.chainHead - d.hashHead[d.hash] = d.index + d.hashHead[d.hash] = d.index + d.hashOffset } prevLength := d.length prevOffset := d.offset @@ -273,34 +259,33 @@ Loop: minIndex = 0 } - if d.chainHead >= minIndex && - (d.fastSkipHashing != 0 && lookahead > minMatchLength-1 || - d.fastSkipHashing == 0 && lookahead > prevLength && prevLength < d.lazy) { - if newLength, newOffset, ok := d.findMatch(d.index, d.chainHead, minMatchLength-1, lookahead); ok { + if d.chainHead-d.hashOffset >= minIndex && + (d.fastSkipHashing != skipNever && lookahead > minMatchLength-1 || + d.fastSkipHashing == skipNever && lookahead > prevLength && prevLength < d.lazy) { + if newLength, newOffset, ok := d.findMatch(d.index, d.chainHead-d.hashOffset, minMatchLength-1, lookahead); ok { d.length = newLength d.offset = newOffset } } - if d.fastSkipHashing != 0 && d.length >= minMatchLength || - d.fastSkipHashing == 0 && prevLength >= minMatchLength && d.length <= prevLength { + if d.fastSkipHashing != skipNever && d.length >= minMatchLength || + d.fastSkipHashing == skipNever && prevLength >= minMatchLength && d.length <= prevLength { // There was a match at the previous step, and the current match is // not better. Output the previous match. - if d.fastSkipHashing != 0 { - d.tokens[d.ti] = matchToken(uint32(d.length-minMatchLength), uint32(d.offset-minOffsetSize)) + if d.fastSkipHashing != skipNever { + d.tokens = append(d.tokens, matchToken(uint32(d.length-minMatchLength), uint32(d.offset-minOffsetSize))) } else { - d.tokens[d.ti] = matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize)) + d.tokens = append(d.tokens, matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize))) } - d.ti++ // Insert in the hash table all strings up to the end of the match. // index and index-1 are already inserted. If there is not enough // lookahead, the last two strings are not inserted into the hash // table. if d.length <= d.fastSkipHashing { var newIndex int - if d.fastSkipHashing != 0 { + if d.fastSkipHashing != skipNever { newIndex = d.index + d.length } else { - newIndex = prevLength - 1 + newIndex = d.index + prevLength - 1 } for d.index++; d.index < newIndex; d.index++ { if d.index < d.maxInsertIndex { @@ -309,10 +294,10 @@ Loop: // Our chain should point to the previous value. d.hashPrev[d.index&windowMask] = d.hashHead[d.hash] // Set the head of the hash chain to us. - d.hashHead[d.hash] = d.index + d.hashHead[d.hash] = d.index + d.hashOffset } } - if d.fastSkipHashing == 0 { + if d.fastSkipHashing == skipNever { d.byteAvailable = false d.length = minMatchLength - 1 } @@ -320,32 +305,33 @@ Loop: // For matches this long, we don't bother inserting each individual // item into the table. d.index += d.length - d.hash = (int(d.window[d.index])<<hashShift + int(d.window[d.index+1])) + if d.index < d.maxInsertIndex { + d.hash = (int(d.window[d.index])<<hashShift + int(d.window[d.index+1])) + } } - if d.ti == maxFlateBlockTokens { + if len(d.tokens) == maxFlateBlockTokens { // The block includes the current character if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { return } - d.ti = 0 + d.tokens = d.tokens[:0] } } else { - if d.fastSkipHashing != 0 || d.byteAvailable { + if d.fastSkipHashing != skipNever || d.byteAvailable { i := d.index - 1 - if d.fastSkipHashing != 0 { + if d.fastSkipHashing != skipNever { i = d.index } - d.tokens[d.ti] = literalToken(uint32(d.window[i])) - d.ti++ - if d.ti == maxFlateBlockTokens { + d.tokens = append(d.tokens, literalToken(uint32(d.window[i]))) + if len(d.tokens) == maxFlateBlockTokens { if d.err = d.writeBlock(d.tokens, i+1, false); d.err != nil { return } - d.ti = 0 + d.tokens = d.tokens[:0] } } d.index++ - if d.fastSkipHashing == 0 { + if d.fastSkipHashing == skipNever { d.byteAvailable = true } } @@ -365,7 +351,7 @@ func (d *compressor) store() { d.windowEnd = 0 } -func (d *compressor) write(b []byte) (n int, err os.Error) { +func (d *compressor) write(b []byte) (n int, err error) { n = len(b) b = b[d.fill(d, b):] for len(b) > 0 { @@ -375,7 +361,7 @@ func (d *compressor) write(b []byte) (n int, err os.Error) { return n, d.err } -func (d *compressor) syncFlush() os.Error { +func (d *compressor) syncFlush() error { d.sync = true d.step(d) if d.err == nil { @@ -387,7 +373,7 @@ func (d *compressor) syncFlush() os.Error { return d.err } -func (d *compressor) init(w io.Writer, level int) (err os.Error) { +func (d *compressor) init(w io.Writer, level int) (err error) { d.w = newHuffmanBitWriter(w) switch { @@ -409,7 +395,7 @@ func (d *compressor) init(w io.Writer, level int) (err os.Error) { return nil } -func (d *compressor) close() os.Error { +func (d *compressor) close() error { d.sync = true d.step(d) if d.err != nil { @@ -455,7 +441,7 @@ type dictWriter struct { enabled bool } -func (w *dictWriter) Write(b []byte) (n int, err os.Error) { +func (w *dictWriter) Write(b []byte) (n int, err error) { if w.enabled { return w.w.Write(b) } @@ -470,7 +456,7 @@ type Writer struct { // Write writes data to w, which will eventually write the // compressed form of data to its underlying writer. -func (w *Writer) Write(data []byte) (n int, err os.Error) { +func (w *Writer) Write(data []byte) (n int, err error) { return w.d.write(data) } @@ -481,13 +467,13 @@ func (w *Writer) Write(data []byte) (n int, err os.Error) { // If the underlying writer returns an error, Flush returns that error. // // In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH. -func (w *Writer) Flush() os.Error { +func (w *Writer) Flush() error { // For more about flushing: // http://www.bolet.org/~pornin/deflate-flush.html return w.d.syncFlush() } // Close flushes and closes the writer. -func (w *Writer) Close() os.Error { +func (w *Writer) Close() error { return w.d.close() } diff --git a/src/pkg/compress/flate/deflate_test.go b/src/pkg/compress/flate/deflate_test.go index 930823685..24881d31c 100644 --- a/src/pkg/compress/flate/deflate_test.go +++ b/src/pkg/compress/flate/deflate_test.go @@ -9,7 +9,6 @@ import ( "fmt" "io" "io/ioutil" - "os" "sync" "testing" ) @@ -31,44 +30,44 @@ type reverseBitsTest struct { } var deflateTests = []*deflateTest{ - &deflateTest{[]byte{}, 0, []byte{1, 0, 0, 255, 255}}, - &deflateTest{[]byte{0x11}, -1, []byte{18, 4, 4, 0, 0, 255, 255}}, - &deflateTest{[]byte{0x11}, DefaultCompression, []byte{18, 4, 4, 0, 0, 255, 255}}, - &deflateTest{[]byte{0x11}, 4, []byte{18, 4, 4, 0, 0, 255, 255}}, - - &deflateTest{[]byte{0x11}, 0, []byte{0, 1, 0, 254, 255, 17, 1, 0, 0, 255, 255}}, - &deflateTest{[]byte{0x11, 0x12}, 0, []byte{0, 2, 0, 253, 255, 17, 18, 1, 0, 0, 255, 255}}, - &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 0, + {[]byte{}, 0, []byte{1, 0, 0, 255, 255}}, + {[]byte{0x11}, -1, []byte{18, 4, 4, 0, 0, 255, 255}}, + {[]byte{0x11}, DefaultCompression, []byte{18, 4, 4, 0, 0, 255, 255}}, + {[]byte{0x11}, 4, []byte{18, 4, 4, 0, 0, 255, 255}}, + + {[]byte{0x11}, 0, []byte{0, 1, 0, 254, 255, 17, 1, 0, 0, 255, 255}}, + {[]byte{0x11, 0x12}, 0, []byte{0, 2, 0, 253, 255, 17, 18, 1, 0, 0, 255, 255}}, + {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 0, []byte{0, 8, 0, 247, 255, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0, 0, 255, 255}, }, - &deflateTest{[]byte{}, 1, []byte{1, 0, 0, 255, 255}}, - &deflateTest{[]byte{0x11}, 1, []byte{18, 4, 4, 0, 0, 255, 255}}, - &deflateTest{[]byte{0x11, 0x12}, 1, []byte{18, 20, 2, 4, 0, 0, 255, 255}}, - &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 1, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}}, - &deflateTest{[]byte{}, 9, []byte{1, 0, 0, 255, 255}}, - &deflateTest{[]byte{0x11}, 9, []byte{18, 4, 4, 0, 0, 255, 255}}, - &deflateTest{[]byte{0x11, 0x12}, 9, []byte{18, 20, 2, 4, 0, 0, 255, 255}}, - &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 9, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}}, + {[]byte{}, 1, []byte{1, 0, 0, 255, 255}}, + {[]byte{0x11}, 1, []byte{18, 4, 4, 0, 0, 255, 255}}, + {[]byte{0x11, 0x12}, 1, []byte{18, 20, 2, 4, 0, 0, 255, 255}}, + {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 1, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}}, + {[]byte{}, 9, []byte{1, 0, 0, 255, 255}}, + {[]byte{0x11}, 9, []byte{18, 4, 4, 0, 0, 255, 255}}, + {[]byte{0x11, 0x12}, 9, []byte{18, 20, 2, 4, 0, 0, 255, 255}}, + {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 9, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}}, } var deflateInflateTests = []*deflateInflateTest{ - &deflateInflateTest{[]byte{}}, - &deflateInflateTest{[]byte{0x11}}, - &deflateInflateTest{[]byte{0x11, 0x12}}, - &deflateInflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}}, - &deflateInflateTest{[]byte{0x11, 0x10, 0x13, 0x41, 0x21, 0x21, 0x41, 0x13, 0x87, 0x78, 0x13}}, - &deflateInflateTest{largeDataChunk()}, + {[]byte{}}, + {[]byte{0x11}}, + {[]byte{0x11, 0x12}}, + {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}}, + {[]byte{0x11, 0x10, 0x13, 0x41, 0x21, 0x21, 0x41, 0x13, 0x87, 0x78, 0x13}}, + {largeDataChunk()}, } var reverseBitsTests = []*reverseBitsTest{ - &reverseBitsTest{1, 1, 1}, - &reverseBitsTest{1, 2, 2}, - &reverseBitsTest{1, 3, 4}, - &reverseBitsTest{1, 4, 8}, - &reverseBitsTest{1, 5, 16}, - &reverseBitsTest{17, 5, 17}, - &reverseBitsTest{257, 9, 257}, - &reverseBitsTest{29, 5, 23}, + {1, 1, 1}, + {1, 2, 2}, + {1, 3, 4}, + {1, 4, 8}, + {1, 5, 16}, + {17, 5, 17}, + {257, 9, 257}, + {29, 5, 23}, } func largeDataChunk() []byte { @@ -102,7 +101,7 @@ func newSyncBuffer() *syncBuffer { return &syncBuffer{ready: make(chan bool, 1)} } -func (b *syncBuffer) Read(p []byte) (n int, err os.Error) { +func (b *syncBuffer) Read(p []byte) (n int, err error) { for { b.mu.RLock() n, err = b.buf.Read(p) @@ -122,7 +121,7 @@ func (b *syncBuffer) signal() { } } -func (b *syncBuffer) Write(p []byte) (n int, err os.Error) { +func (b *syncBuffer) Write(p []byte) (n int, err error) { n, err = b.buf.Write(p) b.signal() return @@ -137,7 +136,7 @@ func (b *syncBuffer) ReadMode() { b.signal() } -func (b *syncBuffer) Close() os.Error { +func (b *syncBuffer) Close() error { b.closed = true b.signal() return nil @@ -204,7 +203,7 @@ func testSync(t *testing.T, level int, input []byte, name string) { } buf.ReadMode() out := make([]byte, 10) - if n, err := r.Read(out); n > 0 || err != os.EOF { + if n, err := r.Read(out); n > 0 || err != io.EOF { t.Errorf("testSync (%d, %d, %s): final Read: %d, %v (hex: %x)", level, len(input), name, n, err, out[0:n]) } if buf.buf.Len() != 0 { @@ -225,11 +224,18 @@ func testSync(t *testing.T, level int, input []byte, name string) { } } -func testToFromWithLevel(t *testing.T, level int, input []byte, name string) os.Error { +func testToFromWithLevel(t *testing.T, level int, input []byte, name string) error { + return testToFromWithLevelAndLimit(t, level, input, name, -1) +} + +func testToFromWithLevelAndLimit(t *testing.T, level int, input []byte, name string, limit int) error { buffer := bytes.NewBuffer(nil) w := NewWriter(buffer, level) w.Write(input) w.Close() + if limit > 0 && buffer.Len() > limit { + t.Errorf("level: %d, len(compress(data)) = %d > limit = %d", level, buffer.Len(), limit) + } r := NewReader(buffer) out, err := ioutil.ReadAll(r) if err != nil { @@ -245,12 +251,16 @@ func testToFromWithLevel(t *testing.T, level int, input []byte, name string) os. return nil } -func testToFrom(t *testing.T, input []byte, name string) { +func testToFromWithLimit(t *testing.T, input []byte, name string, limit [10]int) { for i := 0; i < 10; i++ { - testToFromWithLevel(t, i, input, name) + testToFromWithLevelAndLimit(t, i, input, name, limit[i]) } } +func testToFrom(t *testing.T, input []byte, name string) { + testToFromWithLimit(t, input, name, [10]int{}) +} + func TestDeflateInflate(t *testing.T) { for i, h := range deflateInflateTests { testToFrom(t, h.in, fmt.Sprintf("#%d", i)) @@ -266,12 +276,33 @@ func TestReverseBits(t *testing.T) { } } +type deflateInflateStringTest struct { + filename string + label string + limit [10]int +} + +var deflateInflateStringTests = []deflateInflateStringTest{ + { + "../testdata/e.txt", + "2.718281828...", + [...]int{10013, 5065, 5096, 5115, 5093, 5079, 5079, 5079, 5079, 5079}, + }, + { + "../testdata/Mark.Twain-Tom.Sawyer.txt", + "Mark.Twain-Tom.Sawyer", + [...]int{407330, 187598, 180361, 172974, 169160, 163476, 160936, 160506, 160295, 160295}, + }, +} + func TestDeflateInflateString(t *testing.T) { - gold, err := ioutil.ReadFile("../testdata/e.txt") - if err != nil { - t.Error(err) + for _, test := range deflateInflateStringTests { + gold, err := ioutil.ReadFile(test.filename) + if err != nil { + t.Error(err) + } + testToFromWithLimit(t, gold, test.label, test.limit) } - testToFromWithLevel(t, 1, gold, "2.718281828...") } func TestReaderDict(t *testing.T) { @@ -319,3 +350,15 @@ func TestWriterDict(t *testing.T) { t.Fatalf("writer wrote %q want %q", b1.Bytes(), b.Bytes()) } } + +// See http://code.google.com/p/go/issues/detail?id=2508 +func TestRegression2508(t *testing.T) { + w := NewWriter(ioutil.Discard, 1) + buf := make([]byte, 1024) + for i := 0; i < 131072; i++ { + if _, err := w.Write(buf); err != nil { + t.Fatalf("writer failed: %v", err) + } + } + w.Close() +} diff --git a/src/pkg/compress/flate/flate_test.go b/src/pkg/compress/flate/flate_test.go index bfd3b8381..94efc90ac 100644 --- a/src/pkg/compress/flate/flate_test.go +++ b/src/pkg/compress/flate/flate_test.go @@ -52,7 +52,7 @@ type InitDecoderTest struct { var initDecoderTests = []*InitDecoderTest{ // Example from Connell 1973, - &InitDecoderTest{ + { []int{3, 5, 2, 4, 3, 5, 5, 4, 4, 3, 4, 5}, huffmanDecoder{ 2, 5, @@ -68,7 +68,7 @@ var initDecoderTests = []*InitDecoderTest{ }, // Example from RFC 1951 section 3.2.2 - &InitDecoderTest{ + { []int{2, 1, 3, 3}, huffmanDecoder{ 1, 3, @@ -80,7 +80,7 @@ var initDecoderTests = []*InitDecoderTest{ }, // Second example from RFC 1951 section 3.2.2 - &InitDecoderTest{ + { []int{3, 3, 3, 3, 3, 2, 4, 4}, huffmanDecoder{ 2, 4, @@ -92,21 +92,21 @@ var initDecoderTests = []*InitDecoderTest{ }, // Static Huffman codes (RFC 1951 section 3.2.6) - &InitDecoderTest{ + { fixedHuffmanBits[0:], fixedHuffmanDecoder, true, }, // Illegal input. - &InitDecoderTest{ + { []int{}, huffmanDecoder{}, false, }, // Illegal input. - &InitDecoderTest{ + { []int{0, 0, 0, 0, 0, 0, 0}, huffmanDecoder{}, false, diff --git a/src/pkg/compress/flate/huffman_bit_writer.go b/src/pkg/compress/flate/huffman_bit_writer.go index 3981df5cb..57b56b5c9 100644 --- a/src/pkg/compress/flate/huffman_bit_writer.go +++ b/src/pkg/compress/flate/huffman_bit_writer.go @@ -7,7 +7,6 @@ package flate import ( "io" "math" - "os" "strconv" ) @@ -83,7 +82,7 @@ type huffmanBitWriter struct { literalEncoding *huffmanEncoder offsetEncoding *huffmanEncoder codegenEncoding *huffmanEncoder - err os.Error + err error } type WrongValueError struct { @@ -106,9 +105,9 @@ func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter { } } -func (err WrongValueError) String() string { - return "huffmanBitWriter: " + err.name + " should belong to [" + strconv.Itoa64(int64(err.from)) + ";" + - strconv.Itoa64(int64(err.to)) + "] but actual value is " + strconv.Itoa64(int64(err.value)) +func (err WrongValueError) Error() string { + return "huffmanBitWriter: " + err.name + " should belong to [" + strconv.FormatInt(int64(err.from), 10) + ";" + + strconv.FormatInt(int64(err.to), 10) + "] but actual value is " + strconv.FormatInt(int64(err.value), 10) } func (w *huffmanBitWriter) flushBits() { @@ -194,15 +193,17 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) { // numLiterals The number of literals in literalEncoding // numOffsets The number of offsets in offsetEncoding func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) { - fillInt32s(w.codegenFreq, 0) + for i := range w.codegenFreq { + w.codegenFreq[i] = 0 + } // Note that we are using codegen both as a temporary variable for holding // a copy of the frequencies, and as the place where we put the result. // This is fine because the output is always shorter than the input used // so far. codegen := w.codegen // cache // Copy the concatenated code sizes to codegen. Put a marker at the end. - copyUint8s(codegen[0:numLiterals], w.literalEncoding.codeBits) - copyUint8s(codegen[numLiterals:numLiterals+numOffsets], w.offsetEncoding.codeBits) + copy(codegen[0:numLiterals], w.literalEncoding.codeBits) + copy(codegen[numLiterals:numLiterals+numOffsets], w.offsetEncoding.codeBits) codegen[numLiterals+numOffsets] = badCode size := codegen[0] @@ -223,7 +224,10 @@ func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) { w.codegenFreq[size]++ count-- for count >= 3 { - n := min(count, 6) + n := 6 + if n > count { + n = count + } codegen[outIndex] = 16 outIndex++ codegen[outIndex] = uint8(n - 3) @@ -233,7 +237,10 @@ func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) { } } else { for count >= 11 { - n := min(count, 138) + n := 138 + if n > count { + n = count + } codegen[outIndex] = 18 outIndex++ codegen[outIndex] = uint8(n - 11) @@ -352,8 +359,12 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) { if w.err != nil { return } - fillInt32s(w.literalFreq, 0) - fillInt32s(w.offsetFreq, 0) + for i := range w.literalFreq { + w.literalFreq[i] = 0 + } + for i := range w.offsetFreq { + w.offsetFreq[i] = 0 + } n := len(tokens) tokens = tokens[0 : n+1] diff --git a/src/pkg/compress/flate/huffman_code.go b/src/pkg/compress/flate/huffman_code.go index 7ed603a4f..4873b0fce 100644 --- a/src/pkg/compress/flate/huffman_code.go +++ b/src/pkg/compress/flate/huffman_code.go @@ -195,7 +195,9 @@ func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 { // The tree can't have greater depth than n - 1, no matter what. This // saves a little bit of work in some small cases - maxBits = minInt32(maxBits, n-1) + if maxBits > n-1 { + maxBits = n - 1 + } // Create information about each of the levels. // A bogus "Level 0" whose sole purpose is so that diff --git a/src/pkg/compress/flate/inflate.go b/src/pkg/compress/flate/inflate.go index 3845f1204..3f2042bfe 100644 --- a/src/pkg/compress/flate/inflate.go +++ b/src/pkg/compress/flate/inflate.go @@ -10,7 +10,6 @@ package flate import ( "bufio" "io" - "os" "strconv" ) @@ -25,33 +24,33 @@ const ( // A CorruptInputError reports the presence of corrupt input at a given offset. type CorruptInputError int64 -func (e CorruptInputError) String() string { - return "flate: corrupt input before offset " + strconv.Itoa64(int64(e)) +func (e CorruptInputError) Error() string { + return "flate: corrupt input before offset " + strconv.FormatInt(int64(e), 10) } // An InternalError reports an error in the flate code itself. type InternalError string -func (e InternalError) String() string { return "flate: internal error: " + string(e) } +func (e InternalError) Error() string { return "flate: internal error: " + string(e) } // A ReadError reports an error encountered while reading input. type ReadError struct { - Offset int64 // byte offset where error occurred - Error os.Error // error returned by underlying Read + Offset int64 // byte offset where error occurred + Err error // error returned by underlying Read } -func (e *ReadError) String() string { - return "flate: read error at offset " + strconv.Itoa64(e.Offset) + ": " + e.Error.String() +func (e *ReadError) Error() string { + return "flate: read error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error() } // A WriteError reports an error encountered while writing output. type WriteError struct { - Offset int64 // byte offset where error occurred - Error os.Error // error returned by underlying Write + Offset int64 // byte offset where error occurred + Err error // error returned by underlying Write } -func (e *WriteError) String() string { - return "flate: write error at offset " + strconv.Itoa64(e.Offset) + ": " + e.Error.String() +func (e *WriteError) Error() string { + return "flate: write error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error() } // Huffman decoder is based on @@ -190,7 +189,7 @@ var fixedHuffmanDecoder = huffmanDecoder{ // the NewReader will introduce its own buffering. type Reader interface { io.Reader - ReadByte() (c byte, err os.Error) + ReadByte() (c byte, err error) } // Decompress state. @@ -224,7 +223,7 @@ type decompressor struct { // and decompression state. step func(*decompressor) final bool - err os.Error + err error toRead []byte hl, hd *huffmanDecoder copyLen int @@ -237,7 +236,7 @@ func (f *decompressor) nextBlock() { f.flush((*decompressor).nextBlock) return } - f.err = os.EOF + f.err = io.EOF return } for f.nb < 1+2 { @@ -272,7 +271,7 @@ func (f *decompressor) nextBlock() { } } -func (f *decompressor) Read(b []byte) (int, os.Error) { +func (f *decompressor) Read(b []byte) (int, error) { for { if len(f.toRead) > 0 { n := copy(b, f.toRead) @@ -287,8 +286,8 @@ func (f *decompressor) Read(b []byte) (int, os.Error) { panic("unreachable") } -func (f *decompressor) Close() os.Error { - if f.err == os.EOF { +func (f *decompressor) Close() error { + if f.err == io.EOF { return nil } return f.err @@ -299,7 +298,7 @@ func (f *decompressor) Close() os.Error { var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15} -func (f *decompressor) readHuffman() os.Error { +func (f *decompressor) readHuffman() error { // HLIT[5], HDIST[5], HCLEN[4]. for f.nb < 5+5+4 { if err := f.moreBits(); err != nil { @@ -625,10 +624,10 @@ func (f *decompressor) setDict(dict []byte) { f.hw = f.hp } -func (f *decompressor) moreBits() os.Error { +func (f *decompressor) moreBits() error { c, err := f.r.ReadByte() if err != nil { - if err == os.EOF { + if err == io.EOF { err = io.ErrUnexpectedEOF } return err @@ -640,7 +639,7 @@ func (f *decompressor) moreBits() os.Error { } // Read the next Huffman-encoded symbol from f according to h. -func (f *decompressor) huffSym(h *huffmanDecoder) (int, os.Error) { +func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) { for n := uint(h.min); n <= uint(h.max); n++ { lim := h.limit[n] if lim == -1 { diff --git a/src/pkg/compress/flate/util.go b/src/pkg/compress/flate/util.go deleted file mode 100644 index aca5c78b2..000000000 --- a/src/pkg/compress/flate/util.go +++ /dev/null @@ -1,72 +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 flate - -func min(left int, right int) int { - if left < right { - return left - } - return right -} - -func minInt32(left int32, right int32) int32 { - if left < right { - return left - } - return right -} - -func max(left int, right int) int { - if left > right { - return left - } - return right -} - -func fillInts(a []int, value int) { - for i := range a { - a[i] = value - } -} - -func fillInt32s(a []int32, value int32) { - for i := range a { - a[i] = value - } -} - -func fillBytes(a []byte, value byte) { - for i := range a { - a[i] = value - } -} - -func fillInt8s(a []int8, value int8) { - for i := range a { - a[i] = value - } -} - -func fillUint8s(a []uint8, value uint8) { - for i := range a { - a[i] = value - } -} - -func copyInt8s(dst []int8, src []int8) int { - cnt := min(len(dst), len(src)) - for i := 0; i < cnt; i++ { - dst[i] = src[i] - } - return cnt -} - -func copyUint8s(dst []uint8, src []uint8) int { - cnt := min(len(dst), len(src)) - for i := 0; i < cnt; i++ { - dst[i] = src[i] - } - return cnt -} |