src/pkg/compress/zlib/reader.go - The Go Programming Language

Golang

Source file src/pkg/compress/zlib/reader.go

     1	// Copyright 2009 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	/*
     6	Package zlib implements reading and writing of zlib format compressed data,
     7	as specified in RFC 1950.
     8	
     9	The implementation provides filters that uncompress during reading
    10	and compress during writing.  For example, to write compressed data
    11	to a buffer:
    12	
    13		var b bytes.Buffer
    14		w, err := zlib.NewWriter(&b)
    15		w.Write([]byte("hello, world\n"))
    16		w.Close()
    17	
    18	and to read that data back:
    19	
    20		r, err := zlib.NewReader(&b)
    21		io.Copy(os.Stdout, r)
    22		r.Close()
    23	*/
    24	package zlib
    25	
    26	import (
    27		"bufio"
    28		"compress/flate"
    29		"errors"
    30		"hash"
    31		"hash/adler32"
    32		"io"
    33	)
    34	
    35	const zlibDeflate = 8
    36	
    37	var (
    38		// ErrChecksum is returned when reading ZLIB data that has an invalid checksum.
    39		ErrChecksum = errors.New("zlib: invalid checksum")
    40		// ErrDictionary is returned when reading ZLIB data that has an invalid dictionary.
    41		ErrDictionary = errors.New("zlib: invalid dictionary")
    42		// ErrHeader is returned when reading ZLIB data that has an invalid header.
    43		ErrHeader = errors.New("zlib: invalid header")
    44	)
    45	
    46	type reader struct {
    47		r            flate.Reader
    48		decompressor io.ReadCloser
    49		digest       hash.Hash32
    50		err          error
    51		scratch      [4]byte
    52	}
    53	
    54	// NewReader creates a new io.ReadCloser that satisfies reads by decompressing data read from r.
    55	// The implementation buffers input and may read more data than necessary from r.
    56	// It is the caller's responsibility to call Close on the ReadCloser when done.
    57	func NewReader(r io.Reader) (io.ReadCloser, error) {
    58		return NewReaderDict(r, nil)
    59	}
    60	
    61	// NewReaderDict is like NewReader but uses a preset dictionary.
    62	// NewReaderDict ignores the dictionary if the compressed data does not refer to it.
    63	func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) {
    64		z := new(reader)
    65		if fr, ok := r.(flate.Reader); ok {
    66			z.r = fr
    67		} else {
    68			z.r = bufio.NewReader(r)
    69		}
    70		_, err := io.ReadFull(z.r, z.scratch[0:2])
    71		if err != nil {
    72			return nil, err
    73		}
    74		h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
    75		if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
    76			return nil, ErrHeader
    77		}
    78		if z.scratch[1]&0x20 != 0 {
    79			_, err = io.ReadFull(z.r, z.scratch[0:4])
    80			if err != nil {
    81				return nil, err
    82			}
    83			checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
    84			if checksum != adler32.Checksum(dict) {
    85				return nil, ErrDictionary
    86			}
    87			z.decompressor = flate.NewReaderDict(z.r, dict)
    88		} else {
    89			z.decompressor = flate.NewReader(z.r)
    90		}
    91		z.digest = adler32.New()
    92		return z, nil
    93	}
    94	
    95	func (z *reader) Read(p []byte) (n int, err error) {
    96		if z.err != nil {
    97			return 0, z.err
    98		}
    99		if len(p) == 0 {
   100			return 0, nil
   101		}
   102	
   103		n, err = z.decompressor.Read(p)
   104		z.digest.Write(p[0:n])
   105		if n != 0 || err != io.EOF {
   106			z.err = err
   107			return
   108		}
   109	
   110		// Finished file; check checksum.
   111		if _, err := io.ReadFull(z.r, z.scratch[0:4]); err != nil {
   112			z.err = err
   113			return 0, err
   114		}
   115		// ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
   116		checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
   117		if checksum != z.digest.Sum32() {
   118			z.err = ErrChecksum
   119			return 0, z.err
   120		}
   121		return
   122	}
   123	
   124	// Calling Close does not close the wrapped io.Reader originally passed to NewReader.
   125	func (z *reader) Close() error {
   126		if z.err != nil {
   127			return z.err
   128		}
   129		z.err = z.decompressor.Close()
   130		return z.err
   131	}