summaryrefslogtreecommitdiff
path: root/src/pkg/compress/flate
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2012-01-30 15:38:19 +0100
committerOndřej Surý <ondrej@sury.org>2012-01-30 15:38:19 +0100
commit4cecda6c347bd6902b960c6a35a967add7070b0d (patch)
treea462e224ff41ec9f3eb1a0b6e815806f9e8804ad /src/pkg/compress/flate
parent6c7ca6e4d4e26e4c8cbe0d183966011b3b088a0a (diff)
downloadgolang-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/Makefile1
-rw-r--r--src/pkg/compress/flate/deflate.go132
-rw-r--r--src/pkg/compress/flate/deflate_test.go127
-rw-r--r--src/pkg/compress/flate/flate_test.go12
-rw-r--r--src/pkg/compress/flate/huffman_bit_writer.go35
-rw-r--r--src/pkg/compress/flate/huffman_code.go4
-rw-r--r--src/pkg/compress/flate/inflate.go43
-rw-r--r--src/pkg/compress/flate/util.go72
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
-}