mirror of
https://github.com/golang/go
synced 2024-11-22 09:34:54 -07:00
compress/flate: dictionary support
R=bradfitzwork CC=golang-dev https://golang.org/cl/4397043
This commit is contained in:
parent
bd77eedacf
commit
36713a2a53
@ -477,6 +477,33 @@ func NewWriter(w io.Writer, level int) *Writer {
|
|||||||
return &Writer{pw, &d}
|
return &Writer{pw, &d}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewWriterDict is like NewWriter but initializes the new
|
||||||
|
// Writer with a preset dictionary. The returned Writer behaves
|
||||||
|
// as if the dictionary had been written to it without producing
|
||||||
|
// any compressed output. The compressed data written to w
|
||||||
|
// can only be decompressed by a Reader initialized with the
|
||||||
|
// same dictionary.
|
||||||
|
func NewWriterDict(w io.Writer, level int, dict []byte) *Writer {
|
||||||
|
dw := &dictWriter{w, false}
|
||||||
|
zw := NewWriter(dw, level)
|
||||||
|
zw.Write(dict)
|
||||||
|
zw.Flush()
|
||||||
|
dw.enabled = true
|
||||||
|
return zw
|
||||||
|
}
|
||||||
|
|
||||||
|
type dictWriter struct {
|
||||||
|
w io.Writer
|
||||||
|
enabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *dictWriter) Write(b []byte) (n int, err os.Error) {
|
||||||
|
if w.enabled {
|
||||||
|
return w.w.Write(b)
|
||||||
|
}
|
||||||
|
return len(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
// A Writer takes data written to it and writes the compressed
|
// A Writer takes data written to it and writes the compressed
|
||||||
// form of that data to an underlying writer (see NewWriter).
|
// form of that data to an underlying writer (see NewWriter).
|
||||||
type Writer struct {
|
type Writer struct {
|
||||||
|
@ -275,3 +275,49 @@ func TestDeflateInflateString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
testToFromWithLevel(t, 1, gold, "2.718281828...")
|
testToFromWithLevel(t, 1, gold, "2.718281828...")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReaderDict(t *testing.T) {
|
||||||
|
const (
|
||||||
|
dict = "hello world"
|
||||||
|
text = "hello again world"
|
||||||
|
)
|
||||||
|
var b bytes.Buffer
|
||||||
|
w := NewWriter(&b, 5)
|
||||||
|
w.Write([]byte(dict))
|
||||||
|
w.Flush()
|
||||||
|
b.Reset()
|
||||||
|
w.Write([]byte(text))
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
r := NewReaderDict(&b, []byte(dict))
|
||||||
|
data, err := ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if string(data) != "hello again world" {
|
||||||
|
t.Fatalf("read returned %q want %q", string(data), text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriterDict(t *testing.T) {
|
||||||
|
const (
|
||||||
|
dict = "hello world"
|
||||||
|
text = "hello again world"
|
||||||
|
)
|
||||||
|
var b bytes.Buffer
|
||||||
|
w := NewWriter(&b, 5)
|
||||||
|
w.Write([]byte(dict))
|
||||||
|
w.Flush()
|
||||||
|
b.Reset()
|
||||||
|
w.Write([]byte(text))
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
var b1 bytes.Buffer
|
||||||
|
w = NewWriterDict(&b1, 5, []byte(dict))
|
||||||
|
w.Write([]byte(text))
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
if !bytes.Equal(b1.Bytes(), b.Bytes()) {
|
||||||
|
t.Fatalf("writer wrote %q want %q", b1.Bytes(), b.Bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -526,6 +526,20 @@ func (f *decompressor) dataBlock() os.Error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *decompressor) setDict(dict []byte) {
|
||||||
|
if len(dict) > len(f.hist) {
|
||||||
|
// Will only remember the tail.
|
||||||
|
dict = dict[len(dict)-len(f.hist):]
|
||||||
|
}
|
||||||
|
|
||||||
|
f.hp = copy(f.hist[:], dict)
|
||||||
|
if f.hp == len(f.hist) {
|
||||||
|
f.hp = 0
|
||||||
|
f.hfull = true
|
||||||
|
}
|
||||||
|
f.hw = f.hp
|
||||||
|
}
|
||||||
|
|
||||||
func (f *decompressor) moreBits() os.Error {
|
func (f *decompressor) moreBits() os.Error {
|
||||||
c, err := f.r.ReadByte()
|
c, err := f.r.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -618,3 +632,16 @@ func NewReader(r io.Reader) io.ReadCloser {
|
|||||||
go func() { pw.CloseWithError(f.decompress(r, pw)) }()
|
go func() { pw.CloseWithError(f.decompress(r, pw)) }()
|
||||||
return pr
|
return pr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewReaderDict is like NewReader but initializes the reader
|
||||||
|
// with a preset dictionary. The returned Reader behaves as if
|
||||||
|
// the uncompressed data stream started with the given dictionary,
|
||||||
|
// which has already been read. NewReaderDict is typically used
|
||||||
|
// to read data compressed by NewWriterDict.
|
||||||
|
func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser {
|
||||||
|
var f decompressor
|
||||||
|
f.setDict(dict)
|
||||||
|
pr, pw := io.Pipe()
|
||||||
|
go func() { pw.CloseWithError(f.decompress(r, pw)) }()
|
||||||
|
return pr
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user