Home | History | Annotate | Download | only in flate
      1 // Copyright 2016 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package flate_test
      6 
      7 import (
      8 	"bytes"
      9 	"compress/flate"
     10 	"fmt"
     11 	"io"
     12 	"log"
     13 	"os"
     14 	"strings"
     15 	"sync"
     16 )
     17 
     18 // In performance critical applications, Reset can be used to discard the
     19 // current compressor or decompressor state and reinitialize them quickly
     20 // by taking advantage of previously allocated memory.
     21 func Example_reset() {
     22 	proverbs := []string{
     23 		"Don't communicate by sharing memory, share memory by communicating.\n",
     24 		"Concurrency is not parallelism.\n",
     25 		"The bigger the interface, the weaker the abstraction.\n",
     26 		"Documentation is for users.\n",
     27 	}
     28 
     29 	var r strings.Reader
     30 	var b bytes.Buffer
     31 	buf := make([]byte, 32<<10)
     32 
     33 	zw, err := flate.NewWriter(nil, flate.DefaultCompression)
     34 	if err != nil {
     35 		log.Fatal(err)
     36 	}
     37 	zr := flate.NewReader(nil)
     38 
     39 	for _, s := range proverbs {
     40 		r.Reset(s)
     41 		b.Reset()
     42 
     43 		// Reset the compressor and encode from some input stream.
     44 		zw.Reset(&b)
     45 		if _, err := io.CopyBuffer(zw, &r, buf); err != nil {
     46 			log.Fatal(err)
     47 		}
     48 		if err := zw.Close(); err != nil {
     49 			log.Fatal(err)
     50 		}
     51 
     52 		// Reset the decompressor and decode to some output stream.
     53 		if err := zr.(flate.Resetter).Reset(&b, nil); err != nil {
     54 			log.Fatal(err)
     55 		}
     56 		if _, err := io.CopyBuffer(os.Stdout, zr, buf); err != nil {
     57 			log.Fatal(err)
     58 		}
     59 		if err := zr.Close(); err != nil {
     60 			log.Fatal(err)
     61 		}
     62 	}
     63 
     64 	// Output:
     65 	// Don't communicate by sharing memory, share memory by communicating.
     66 	// Concurrency is not parallelism.
     67 	// The bigger the interface, the weaker the abstraction.
     68 	// Documentation is for users.
     69 }
     70 
     71 // A preset dictionary can be used to improve the compression ratio.
     72 // The downside to using a dictionary is that the compressor and decompressor
     73 // must agree in advance what dictionary to use.
     74 func Example_dictionary() {
     75 	// The dictionary is a string of bytes. When compressing some input data,
     76 	// the compressor will attempt to substitute substrings with matches found
     77 	// in the dictionary. As such, the dictionary should only contain substrings
     78 	// that are expected to be found in the actual data stream.
     79 	const dict = `<?xml version="1.0"?>` + `<book>` + `<data>` + `<meta name="` + `" content="`
     80 
     81 	// The data to compress should (but is not required to) contain frequent
     82 	// substrings that match those in the dictionary.
     83 	const data = `<?xml version="1.0"?>
     84 <book>
     85 	<meta name="title" content="The Go Programming Language"/>
     86 	<meta name="authors" content="Alan Donovan and Brian Kernighan"/>
     87 	<meta name="published" content="2015-10-26"/>
     88 	<meta name="isbn" content="978-0134190440"/>
     89 	<data>...</data>
     90 </book>
     91 `
     92 
     93 	var b bytes.Buffer
     94 
     95 	// Compress the data using the specially crafted dictionary.
     96 	zw, err := flate.NewWriterDict(&b, flate.DefaultCompression, []byte(dict))
     97 	if err != nil {
     98 		log.Fatal(err)
     99 	}
    100 	if _, err := io.Copy(zw, strings.NewReader(data)); err != nil {
    101 		log.Fatal(err)
    102 	}
    103 	if err := zw.Close(); err != nil {
    104 		log.Fatal(err)
    105 	}
    106 
    107 	// The decompressor must use the same dictionary as the compressor.
    108 	// Otherwise, the input may appear as corrupted.
    109 	fmt.Println("Decompressed output using the dictionary:")
    110 	zr := flate.NewReaderDict(bytes.NewReader(b.Bytes()), []byte(dict))
    111 	if _, err := io.Copy(os.Stdout, zr); err != nil {
    112 		log.Fatal(err)
    113 	}
    114 	if err := zr.Close(); err != nil {
    115 		log.Fatal(err)
    116 	}
    117 
    118 	fmt.Println()
    119 
    120 	// Substitute all of the bytes in the dictionary with a '#' to visually
    121 	// demonstrate the approximate effectiveness of using a preset dictionary.
    122 	fmt.Println("Substrings matched by the dictionary are marked with #:")
    123 	hashDict := []byte(dict)
    124 	for i := range hashDict {
    125 		hashDict[i] = '#'
    126 	}
    127 	zr = flate.NewReaderDict(&b, hashDict)
    128 	if _, err := io.Copy(os.Stdout, zr); err != nil {
    129 		log.Fatal(err)
    130 	}
    131 	if err := zr.Close(); err != nil {
    132 		log.Fatal(err)
    133 	}
    134 
    135 	// Output:
    136 	// Decompressed output using the dictionary:
    137 	// <?xml version="1.0"?>
    138 	// <book>
    139 	// 	<meta name="title" content="The Go Programming Language"/>
    140 	// 	<meta name="authors" content="Alan Donovan and Brian Kernighan"/>
    141 	// 	<meta name="published" content="2015-10-26"/>
    142 	// 	<meta name="isbn" content="978-0134190440"/>
    143 	// 	<data>...</data>
    144 	// </book>
    145 	//
    146 	// Substrings matched by the dictionary are marked with #:
    147 	// #####################
    148 	// ######
    149 	// 	############title###########The Go Programming Language"/#
    150 	// 	############authors###########Alan Donovan and Brian Kernighan"/#
    151 	// 	############published###########2015-10-26"/#
    152 	// 	############isbn###########978-0134190440"/#
    153 	// 	######...</#####
    154 	// </#####
    155 }
    156 
    157 // DEFLATE is suitable for transmitting compressed data across the network.
    158 func Example_synchronization() {
    159 	var wg sync.WaitGroup
    160 	defer wg.Wait()
    161 
    162 	// Use io.Pipe to simulate a network connection.
    163 	// A real network application should take care to properly close the
    164 	// underlying connection.
    165 	rp, wp := io.Pipe()
    166 
    167 	// Start a goroutine to act as the transmitter.
    168 	wg.Add(1)
    169 	go func() {
    170 		defer wg.Done()
    171 
    172 		zw, err := flate.NewWriter(wp, flate.BestSpeed)
    173 		if err != nil {
    174 			log.Fatal(err)
    175 		}
    176 
    177 		b := make([]byte, 256)
    178 		for _, m := range strings.Fields("A long time ago in a galaxy far, far away...") {
    179 			// We use a simple framing format where the first byte is the
    180 			// message length, followed the message itself.
    181 			b[0] = uint8(copy(b[1:], m))
    182 
    183 			if _, err := zw.Write(b[:1+len(m)]); err != nil {
    184 				log.Fatal(err)
    185 			}
    186 
    187 			// Flush ensures that the receiver can read all data sent so far.
    188 			if err := zw.Flush(); err != nil {
    189 				log.Fatal(err)
    190 			}
    191 		}
    192 
    193 		if err := zw.Close(); err != nil {
    194 			log.Fatal(err)
    195 		}
    196 	}()
    197 
    198 	// Start a goroutine to act as the receiver.
    199 	wg.Add(1)
    200 	go func() {
    201 		defer wg.Done()
    202 
    203 		zr := flate.NewReader(rp)
    204 
    205 		b := make([]byte, 256)
    206 		for {
    207 			// Read the message length.
    208 			// This is guaranteed to return for every corresponding
    209 			// Flush and Close on the transmitter side.
    210 			if _, err := io.ReadFull(zr, b[:1]); err != nil {
    211 				if err == io.EOF {
    212 					break // The transmitter closed the stream
    213 				}
    214 				log.Fatal(err)
    215 			}
    216 
    217 			// Read the message content.
    218 			n := int(b[0])
    219 			if _, err := io.ReadFull(zr, b[:n]); err != nil {
    220 				log.Fatal(err)
    221 			}
    222 
    223 			fmt.Printf("Received %d bytes: %s\n", n, b[:n])
    224 		}
    225 		fmt.Println()
    226 
    227 		if err := zr.Close(); err != nil {
    228 			log.Fatal(err)
    229 		}
    230 	}()
    231 
    232 	// Output:
    233 	// Received 1 bytes: A
    234 	// Received 4 bytes: long
    235 	// Received 4 bytes: time
    236 	// Received 3 bytes: ago
    237 	// Received 2 bytes: in
    238 	// Received 1 bytes: a
    239 	// Received 6 bytes: galaxy
    240 	// Received 4 bytes: far,
    241 	// Received 3 bytes: far
    242 	// Received 7 bytes: away...
    243 }
    244