OSDN Git Service

Add Go frontend, libgo library, and Go testsuite.
[pf3gnuchains/gcc-fork.git] / libgo / go / 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 The zlib package implements reading and writing of zlib
7 format compressed data, 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         "hash"
30         "hash/adler32"
31         "io"
32         "os"
33 )
34
35 const zlibDeflate = 8
36
37 var ChecksumError os.Error = os.ErrorString("zlib checksum error")
38 var HeaderError os.Error = os.ErrorString("invalid zlib header")
39 var UnsupportedError os.Error = os.ErrorString("unsupported zlib format")
40
41 type reader struct {
42         r            flate.Reader
43         decompressor io.ReadCloser
44         digest       hash.Hash32
45         err          os.Error
46         scratch      [4]byte
47 }
48
49 // NewReader creates a new io.ReadCloser that satisfies reads by decompressing data read from r.
50 // The implementation buffers input and may read more data than necessary from r.
51 // It is the caller's responsibility to call Close on the ReadCloser when done.
52 func NewReader(r io.Reader) (io.ReadCloser, os.Error) {
53         z := new(reader)
54         if fr, ok := r.(flate.Reader); ok {
55                 z.r = fr
56         } else {
57                 z.r = bufio.NewReader(r)
58         }
59         _, err := io.ReadFull(z.r, z.scratch[0:2])
60         if err != nil {
61                 return nil, err
62         }
63         h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
64         if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
65                 return nil, HeaderError
66         }
67         if z.scratch[1]&0x20 != 0 {
68                 // BUG(nigeltao): The zlib package does not implement the FDICT flag.
69                 return nil, UnsupportedError
70         }
71         z.digest = adler32.New()
72         z.decompressor = flate.NewReader(z.r)
73         return z, nil
74 }
75
76 func (z *reader) Read(p []byte) (n int, err os.Error) {
77         if z.err != nil {
78                 return 0, z.err
79         }
80         if len(p) == 0 {
81                 return 0, nil
82         }
83
84         n, err = z.decompressor.Read(p)
85         z.digest.Write(p[0:n])
86         if n != 0 || err != os.EOF {
87                 z.err = err
88                 return
89         }
90
91         // Finished file; check checksum.
92         if _, err := io.ReadFull(z.r, z.scratch[0:4]); err != nil {
93                 z.err = err
94                 return 0, err
95         }
96         // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
97         checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
98         if checksum != z.digest.Sum32() {
99                 z.err = ChecksumError
100                 return 0, z.err
101         }
102         return
103 }
104
105 // Calling Close does not close the wrapped io.Reader originally passed to NewReader.
106 func (z *reader) Close() os.Error {
107         if z.err != nil {
108                 return z.err
109         }
110         z.err = z.decompressor.Close()
111         return z.err
112 }