Example #1
0
File: writer.go Project: ds2dev/gcc
// 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
}
Example #2
0
// 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
}
Example #3
0
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
}
Example #4
0
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
}
Example #5
0
func compressdict(src []byte, dest io.Writer, level int, dict []byte) {
	compressor, _ := flate.NewWriterDict(dest, level, dict)
	compressor.Write(src)
	compressor.Close()
}
Example #6
0
// 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"/#
	// 	######...</#####
	// </#####
}