import (
"archive/zip"
"bytes"
+ "compress/flate"
"fmt"
"io"
"log"
// Contents of README:
// This is the source code repository for the Go programming language.
}
+
+func ExampleWriter_RegisterCompressor() {
+ // Override the default Deflate compressor with a higher compression
+ // level.
+
+ // Create a buffer to write our archive to.
+ buf := new(bytes.Buffer)
+
+ // Create a new zip archive.
+ w := zip.NewWriter(buf)
+
+ var fw *flate.Writer
+
+ // Register the deflator.
+ w.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) {
+ var err error
+ if fw == nil {
+ // Creating a flate compressor for every file is
+ // expensive, create one and reuse it.
+ fw, err = flate.NewWriter(out, flate.BestCompression)
+ } else {
+ fw.Reset(out)
+ }
+ return fw, err
+ })
+
+ // Proceed to add files to w.
+}
)
type Reader struct {
- r io.ReaderAt
- File []*File
- Comment string
+ r io.ReaderAt
+ File []*File
+ Comment string
+ decompressors map[uint16]Decompressor
}
type ReadCloser struct {
type File struct {
FileHeader
+ zip *Reader
zipr io.ReaderAt
zipsize int64
headerOffset int64
// a bad one, and then only report a ErrFormat or UnexpectedEOF if
// the file count modulo 65536 is incorrect.
for {
- f := &File{zipr: r, zipsize: size}
+ f := &File{zip: z, zipr: r, zipsize: size}
err = readDirectoryHeader(f, buf)
if err == ErrFormat || err == io.ErrUnexpectedEOF {
break
return nil
}
+// RegisterDecompressor registers or overrides a custom decompressor for a
+// specific method ID. If a decompressor for a given method is not found,
+// Reader will default to looking up the decompressor at the package level.
+//
+// Must not be called concurrently with Open on any Files in the Reader.
+func (z *Reader) RegisterDecompressor(method uint16, dcomp Decompressor) {
+ if z.decompressors == nil {
+ z.decompressors = make(map[uint16]Decompressor)
+ }
+ z.decompressors[method] = dcomp
+}
+
+func (z *Reader) decompressor(method uint16) Decompressor {
+ dcomp := z.decompressors[method]
+ if dcomp == nil {
+ dcomp = decompressor(method)
+ }
+ return dcomp
+}
+
// Close closes the Zip file, rendering it unusable for I/O.
func (rc *ReadCloser) Close() error {
return rc.f.Close()
}
size := int64(f.CompressedSize64)
r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size)
- dcomp := decompressor(f.Method)
+ dcomp := f.zip.decompressor(f.Method)
if dcomp == nil {
err = ErrAlgorithm
return
)
// TODO(adg): support zip file comments
-// TODO(adg): support specifying deflate level
// Writer implements a zip file writer.
type Writer struct {
- cw *countWriter
- dir []*header
- last *fileWriter
- closed bool
+ cw *countWriter
+ dir []*header
+ last *fileWriter
+ closed bool
+ compressors map[uint16]Compressor
}
type header struct {
compCount: &countWriter{w: w.cw},
crc32: crc32.NewIEEE(),
}
- comp := compressor(fh.Method)
+ comp := w.compressor(fh.Method)
if comp == nil {
return nil, ErrAlgorithm
}
return err
}
+// RegisterCompressor registers or overrides a custom compressor for a specific
+// method ID. If a compressor for a given method is not found, Writer will
+// default to looking up the compressor at the package level.
+func (w *Writer) RegisterCompressor(method uint16, comp Compressor) {
+ if w.compressors == nil {
+ w.compressors = make(map[uint16]Compressor)
+ }
+ w.compressors[method] = comp
+}
+
+func (w *Writer) compressor(method uint16) Compressor {
+ comp := w.compressors[method]
+ if comp == nil {
+ comp = compressor(method)
+ }
+ return comp
+}
+
type fileWriter struct {
*header
zipw io.Writer