// writeHeader writes the ZLIB header. func (z *Writer) writeHeader() (err error) { z.wroteHeader = true // ZLIB has a two-byte header (as documented in RFC 1950). // The first four bits is the CINFO (compression info), which is 7 for the default deflate window size. // The next four bits is the CM (compression method), which is 8 for deflate. z.scratch[0] = 0x78 // The next two bits is the FLEVEL (compression level). The four values are: // 0=fastest, 1=fast, 2=default, 3=best. // The next bit, FDICT, is set if a dictionary is given. // The final five FCHECK bits form a mod-31 checksum. switch z.level { case 0, 1: z.scratch[1] = 0 << 6 case 2, 3, 4, 5: z.scratch[1] = 1 << 6 case 6, -1: z.scratch[1] = 2 << 6 case 7, 8, 9: z.scratch[1] = 3 << 6 default: panic("unreachable") } if z.dict != nil { z.scratch[1] |= 1 << 5 } z.scratch[1] += uint8(31 - (uint16(z.scratch[0])<<8+uint16(z.scratch[1]))%31) if _, err = z.w.Write(z.scratch[0:2]); err != nil { return err } if z.dict != nil { // The next four bytes are the Adler-32 checksum of the dictionary. checksum := adler32.Checksum(z.dict) z.scratch[0] = uint8(checksum >> 24) z.scratch[1] = uint8(checksum >> 16) z.scratch[2] = uint8(checksum >> 8) z.scratch[3] = uint8(checksum >> 0) if _, err = z.w.Write(z.scratch[0:4]); err != nil { return err } } if z.compressor == nil { // Initialize deflater unless the Writer is being reused // after a Reset call. z.compressor, err = flate.NewWriterDict(z.w, z.level, z.dict) if err != nil { return err } z.digest = adler32.New() } return nil }
// NewWriterDict creates a new io.WriteCloser that satisfies writes by compressing data written to w. // It is the caller's responsibility to call Close on the WriteCloser when done. // level is the compression level, which can be DefaultCompression, NoCompression, // or any integer value between BestSpeed and BestCompression (inclusive). // dict is the preset dictionary to compress with, or nil to use no dictionary. func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, os.Error) { z := new(Writer) // ZLIB has a two-byte header (as documented in RFC 1950). // The first four bits is the CINFO (compression info), which is 7 for the default deflate window size. // The next four bits is the CM (compression method), which is 8 for deflate. z.scratch[0] = 0x78 // The next two bits is the FLEVEL (compression level). The four values are: // 0=fastest, 1=fast, 2=default, 3=best. // The next bit, FDICT, is set if a dictionary is given. // The final five FCHECK bits form a mod-31 checksum. switch level { case 0, 1: z.scratch[1] = 0 << 6 case 2, 3, 4, 5: z.scratch[1] = 1 << 6 case 6, -1: z.scratch[1] = 2 << 6 case 7, 8, 9: z.scratch[1] = 3 << 6 default: return nil, os.NewError("level out of range") } if dict != nil { z.scratch[1] |= 1 << 5 } z.scratch[1] += uint8(31 - (uint16(z.scratch[0])<<8+uint16(z.scratch[1]))%31) _, err := w.Write(z.scratch[0:2]) if err != nil { return nil, err } if dict != nil { // The next four bytes are the Adler-32 checksum of the dictionary. checksum := adler32.Checksum(dict) z.scratch[0] = uint8(checksum >> 24) z.scratch[1] = uint8(checksum >> 16) z.scratch[2] = uint8(checksum >> 8) z.scratch[3] = uint8(checksum >> 0) _, err = w.Write(z.scratch[0:4]) if err != nil { return nil, err } } z.w = w z.compressor = flate.NewWriterDict(w, level, dict) z.digest = adler32.New() return z, nil }
func (self *FlateCompressor) Compress(src []byte) ([]byte, error) { var err error var compressor *flate.Writer cdest := bytes.NewBuffer(make([]byte, 0, len(src))) if self.dict == nil { compressor, err = flate.NewWriter(cdest, self.level) } else { compressor, err = flate.NewWriterDict(cdest, self.level, self.dict) } //compressor.Reset(cdest) compressor.Write(src) err = compressor.Close() if err != nil { fmt.Println("Compress Close err:%s", err.Error()) } return cdest.Bytes(), err }
func marshalPacket(local *localNode) (data []byte, err error) { var buf bytes.Buffer buf.WriteByte(byte(local.mode.Id)) inflater, err := flate.NewWriterDict(&buf, flate.DefaultCompression, PacketCompressionDict) if err != nil { return } if err = local.encodeForPacket(inflater); err != nil { return } inflater.Close() mac := hmac.New(sha1.New, local.mode.Secret) mac.Write(buf.Bytes()) buf.Write(mac.Sum(nil)) data = buf.Bytes() return }
func compressdict(src []byte, dest io.Writer, level int, dict []byte) { compressor, _ := flate.NewWriterDict(dest, level, dict) compressor.Write(src) compressor.Close() }
// A preset dictionary can be used to improve the compression ratio. // The downside to using a dictionary is that the compressor and decompressor // must agree in advance what dictionary to use. func Example_dictionary() { // The dictionary is a string of bytes. When compressing some input data, // the compressor will attempt to substitute substrings with matches found // in the dictionary. As such, the dictionary should only contain substrings // that are expected to be found in the actual data stream. const dict = `<?xml version="1.0"?>` + `<book>` + `<data>` + `<meta name="` + `" content="` // The data to compress should (but is not required to) contain frequent // substrings that match those in the dictionary. const data = `<?xml version="1.0"?> <book> <meta name="title" content="The Go Programming Language"/> <meta name="authors" content="Alan Donovan and Brian Kernighan"/> <meta name="published" content="2015-10-26"/> <meta name="isbn" content="978-0134190440"/> <data>...</data> </book> ` var b bytes.Buffer // Compress the data using the specially crafted dictionary. zw, err := flate.NewWriterDict(&b, flate.DefaultCompression, []byte(dict)) if err != nil { log.Fatal(err) } if _, err := io.Copy(zw, strings.NewReader(data)); err != nil { log.Fatal(err) } if err := zw.Close(); err != nil { log.Fatal(err) } // The decompressor must use the same dictionary as the compressor. // Otherwise, the input may appear as corrupted. fmt.Println("Decompressed output using the dictionary:") zr := flate.NewReaderDict(bytes.NewReader(b.Bytes()), []byte(dict)) if _, err := io.Copy(os.Stdout, zr); err != nil { log.Fatal(err) } if err := zr.Close(); err != nil { log.Fatal(err) } fmt.Println() // Substitute all of the bytes in the dictionary with a '#' to visually // demonstrate the approximate effectiveness of using a preset dictionary. fmt.Println("Substrings matched by the dictionary are marked with #:") hashDict := []byte(dict) for i := range hashDict { hashDict[i] = '#' } zr = flate.NewReaderDict(&b, hashDict) if _, err := io.Copy(os.Stdout, zr); err != nil { log.Fatal(err) } if err := zr.Close(); err != nil { log.Fatal(err) } // Output: // Decompressed output using the dictionary: // <?xml version="1.0"?> // <book> // <meta name="title" content="The Go Programming Language"/> // <meta name="authors" content="Alan Donovan and Brian Kernighan"/> // <meta name="published" content="2015-10-26"/> // <meta name="isbn" content="978-0134190440"/> // <data>...</data> // </book> // // Substrings matched by the dictionary are marked with #: // ##################### // ###### // ############title###########The Go Programming Language"/# // ############authors###########Alan Donovan and Brian Kernighan"/# // ############published###########2015-10-26"/# // ############isbn###########978-0134190440"/# // ######...</##### // </##### }