|  | // Copyright 2016 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_test | 
|  |  | 
|  | import ( | 
|  | "bytes" | 
|  | "compress/flate" | 
|  | "fmt" | 
|  | "io" | 
|  | "log" | 
|  | "os" | 
|  | "strings" | 
|  | "sync" | 
|  | ) | 
|  |  | 
|  | // In performance critical applications, Reset can be used to discard the | 
|  | // current compressor or decompressor state and reinitialize them quickly | 
|  | // by taking advantage of previously allocated memory. | 
|  | func Example_reset() { | 
|  | proverbs := []string{ | 
|  | "Don't communicate by sharing memory, share memory by communicating.\n", | 
|  | "Concurrency is not parallelism.\n", | 
|  | "The bigger the interface, the weaker the abstraction.\n", | 
|  | "Documentation is for users.\n", | 
|  | } | 
|  |  | 
|  | var r strings.Reader | 
|  | var b bytes.Buffer | 
|  | buf := make([]byte, 32<<10) | 
|  |  | 
|  | zw, err := flate.NewWriter(nil, flate.DefaultCompression) | 
|  | if err != nil { | 
|  | log.Fatal(err) | 
|  | } | 
|  | zr := flate.NewReader(nil) | 
|  |  | 
|  | for _, s := range proverbs { | 
|  | r.Reset(s) | 
|  | b.Reset() | 
|  |  | 
|  | // Reset the compressor and encode from some input stream. | 
|  | zw.Reset(&b) | 
|  | if _, err := io.CopyBuffer(zw, &r, buf); err != nil { | 
|  | log.Fatal(err) | 
|  | } | 
|  | if err := zw.Close(); err != nil { | 
|  | log.Fatal(err) | 
|  | } | 
|  |  | 
|  | // Reset the decompressor and decode to some output stream. | 
|  | if err := zr.(flate.Resetter).Reset(&b, nil); err != nil { | 
|  | log.Fatal(err) | 
|  | } | 
|  | if _, err := io.CopyBuffer(os.Stdout, zr, buf); err != nil { | 
|  | log.Fatal(err) | 
|  | } | 
|  | if err := zr.Close(); err != nil { | 
|  | log.Fatal(err) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Output: | 
|  | // Don't communicate by sharing memory, share memory by communicating. | 
|  | // Concurrency is not parallelism. | 
|  | // The bigger the interface, the weaker the abstraction. | 
|  | // Documentation is for users. | 
|  | } | 
|  |  | 
|  | // 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"/# | 
|  | // 	######...</##### | 
|  | // </##### | 
|  | } | 
|  |  | 
|  | // DEFLATE is suitable for transmitting compressed data across the network. | 
|  | func Example_synchronization() { | 
|  | var wg sync.WaitGroup | 
|  | defer wg.Wait() | 
|  |  | 
|  | // Use io.Pipe to simulate a network connection. | 
|  | // A real network application should take care to properly close the | 
|  | // underlying connection. | 
|  | rp, wp := io.Pipe() | 
|  |  | 
|  | // Start a goroutine to act as the transmitter. | 
|  | wg.Add(1) | 
|  | go func() { | 
|  | defer wg.Done() | 
|  |  | 
|  | zw, err := flate.NewWriter(wp, flate.BestSpeed) | 
|  | if err != nil { | 
|  | log.Fatal(err) | 
|  | } | 
|  |  | 
|  | b := make([]byte, 256) | 
|  | for _, m := range strings.Fields("A long time ago in a galaxy far, far away...") { | 
|  | // We use a simple framing format where the first byte is the | 
|  | // message length, followed the message itself. | 
|  | b[0] = uint8(copy(b[1:], m)) | 
|  |  | 
|  | if _, err := zw.Write(b[:1+len(m)]); err != nil { | 
|  | log.Fatal(err) | 
|  | } | 
|  |  | 
|  | // Flush ensures that the receiver can read all data sent so far. | 
|  | if err := zw.Flush(); err != nil { | 
|  | log.Fatal(err) | 
|  | } | 
|  | } | 
|  |  | 
|  | if err := zw.Close(); err != nil { | 
|  | log.Fatal(err) | 
|  | } | 
|  | }() | 
|  |  | 
|  | // Start a goroutine to act as the receiver. | 
|  | wg.Add(1) | 
|  | go func() { | 
|  | defer wg.Done() | 
|  |  | 
|  | zr := flate.NewReader(rp) | 
|  |  | 
|  | b := make([]byte, 256) | 
|  | for { | 
|  | // Read the message length. | 
|  | // This is guaranteed to return for every corresponding | 
|  | // Flush and Close on the transmitter side. | 
|  | if _, err := io.ReadFull(zr, b[:1]); err != nil { | 
|  | if err == io.EOF { | 
|  | break // The transmitter closed the stream | 
|  | } | 
|  | log.Fatal(err) | 
|  | } | 
|  |  | 
|  | // Read the message content. | 
|  | n := int(b[0]) | 
|  | if _, err := io.ReadFull(zr, b[:n]); err != nil { | 
|  | log.Fatal(err) | 
|  | } | 
|  |  | 
|  | fmt.Printf("Received %d bytes: %s\n", n, b[:n]) | 
|  | } | 
|  | fmt.Println() | 
|  |  | 
|  | if err := zr.Close(); err != nil { | 
|  | log.Fatal(err) | 
|  | } | 
|  | }() | 
|  |  | 
|  | // Output: | 
|  | // Received 1 bytes: A | 
|  | // Received 4 bytes: long | 
|  | // Received 4 bytes: time | 
|  | // Received 3 bytes: ago | 
|  | // Received 2 bytes: in | 
|  | // Received 1 bytes: a | 
|  | // Received 6 bytes: galaxy | 
|  | // Received 4 bytes: far, | 
|  | // Received 3 bytes: far | 
|  | // Received 7 bytes: away... | 
|  | } |