1package zip
2
3import (
4	"archive/zip"
5	"io"
6	"os"
7)
8
9// Reader provides sequential access to the contents of a zip archive.
10type Reader struct {
11	zip.Reader
12	unread []*zip.File
13	rc     io.ReadCloser
14}
15
16// NewReader returns a new Reader reading from r, which is assumed to have the
17// given size in bytes.
18func NewReader(r io.ReaderAt, size int64) (*Reader, error) {
19	zr, err := zip.NewReader(r, size)
20	if err != nil {
21		return nil, err
22	}
23	return &Reader{Reader: *zr}, nil
24}
25
26// NextFile advances to the next file in the zip archive.
27func (r *Reader) NextFile() (name string, err error) {
28	// Initialize unread
29	if r.unread == nil {
30		r.unread = r.Files()[:]
31	}
32
33	// Close previous file
34	if r.rc != nil {
35		r.rc.Close() // Read-only
36	}
37
38	if len(r.unread) == 0 {
39		return "", io.EOF
40	}
41
42	// Open and return next unread
43	f := r.unread[0]
44	name, r.unread = f.Name, r.unread[1:]
45	r.rc, err = f.Open()
46	if err != nil {
47		return "", err
48	}
49	return name, nil
50}
51
52func (r *Reader) Read(p []byte) (n int, err error) {
53	return r.rc.Read(p)
54}
55
56// Files returns the full list of files in the zip archive.
57func (r *Reader) Files() []*zip.File {
58	return r.File
59}
60
61// Writer provides sequential writing of a zip archive.1 format.
62type Writer struct {
63	zip.Writer
64	w io.Writer
65}
66
67// NewWriter returns a new Writer writing to w.
68func NewWriter(w io.Writer) *Writer {
69	return &Writer{Writer: *zip.NewWriter(w)}
70}
71
72// NextFile computes and writes a header and prepares to accept the file's
73// contents.
74func (w *Writer) NextFile(name string, fi os.FileInfo) error {
75	if name == "" {
76		name = fi.Name()
77	}
78	hdr, err := zip.FileInfoHeader(fi)
79	if err != nil {
80		return err
81	}
82	hdr.Name = name
83	w.w, err = w.CreateHeader(hdr)
84	return err
85}
86
87func (w *Writer) Write(p []byte) (n int, err error) {
88	return w.w.Write(p)
89}
90