mirror of
https://github.com/golang/go.git
synced 2026-06-27 03:11:23 +00:00
compress/flate: clarify compatibility promise
By changing the encoder designs for each compression level in CL 707355, compress/flate writers no longer produce byte-for-byte equivalent output for the same input. This is fine, we don't consider the exact byte output of a compression algorithm to be covered by the Go 1 compatibilty promise (https://go.dev/doc/go1compat calls out "unspecified behavior"), and we have made these changes before, such as CL 22370 in Go 1.7. Still, this may not be obvious, and the relatively rare changes make it easy for golden tests depending on the output to creep into users tests. Add an explicit note about the compatibility promise to try to nudge users in the right direction. This also applies to archive/zip, compress/gzip, compress/zlib, and image/png, as they transitively use compress/flate. Updates #75532. Change-Id: I60e4624e5f45081d1c4696e6fb3a2b9d6a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/774300 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Russ Cox <rsc@golang.org> Reviewed-by: Klaus Post <klauspost@gmail.com>
This commit is contained in:
parent
714a94dd31
commit
2747d887eb
5 changed files with 40 additions and 0 deletions
|
|
@ -42,6 +42,10 @@ type header struct {
|
|||
}
|
||||
|
||||
// NewWriter returns a new [Writer] writing a zip file to w.
|
||||
//
|
||||
// Note that the exact bytes written to w are not covered by the Go 1
|
||||
// compatibility promise. Callers, including tests, should not depend on the
|
||||
// exact written bytes.
|
||||
func NewWriter(w io.Writer) *Writer {
|
||||
return &Writer{cw: &countWriter{w: bufio.NewWriter(w)}}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -818,6 +818,10 @@ func (d *compressor) close() error {
|
|||
//
|
||||
// If level is in the range [-2, 9] then the error returned will be nil.
|
||||
// Otherwise the error returned will be non-nil.
|
||||
//
|
||||
// Note that the exact bytes written to w are not covered by the Go 1
|
||||
// compatibility promise. Callers, including tests, should not depend on the
|
||||
// exact written bytes.
|
||||
func NewWriter(w io.Writer, level int) (*Writer, error) {
|
||||
var dw Writer
|
||||
if err := dw.d.init(w, level); err != nil {
|
||||
|
|
@ -832,6 +836,10 @@ func NewWriter(w io.Writer, level int) (*Writer, error) {
|
|||
// any compressed output. The compressed data written to w
|
||||
// can only be decompressed by a reader initialized with the
|
||||
// same dictionary (see [NewReaderDict]).
|
||||
//
|
||||
// Note that the exact bytes written to w are not covered by the Go 1
|
||||
// compatibility promise. Callers, including tests, should not depend on the
|
||||
// exact written bytes.
|
||||
func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, error) {
|
||||
zw, err := NewWriter(w, level)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,10 @@ type Writer struct {
|
|||
//
|
||||
// Callers that wish to set the fields in Writer.[Header] must do so before
|
||||
// the first call to Write, Flush, or Close.
|
||||
//
|
||||
// Note that the exact bytes written to w are not covered by the Go 1
|
||||
// compatibility promise. Callers, including tests, should not depend on the
|
||||
// exact written bytes.
|
||||
func NewWriter(w io.Writer) *Writer {
|
||||
z, _ := NewWriterLevel(w, DefaultCompression)
|
||||
return z
|
||||
|
|
@ -57,6 +61,10 @@ func NewWriter(w io.Writer) *Writer {
|
|||
// The compression level can be [DefaultCompression], [NoCompression], [HuffmanOnly]
|
||||
// or any integer value between [BestSpeed] and [BestCompression] inclusive.
|
||||
// The error returned will be nil if the level is valid.
|
||||
//
|
||||
// Note that the exact bytes written to w are not covered by the Go 1
|
||||
// compatibility promise. Callers, including tests, should not depend on the
|
||||
// exact written bytes.
|
||||
func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
|
||||
if level < HuffmanOnly || level > BestCompression {
|
||||
return nil, fmt.Errorf("gzip: invalid compression level: %d", level)
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ type Writer struct {
|
|||
//
|
||||
// It is the caller's responsibility to call Close on the Writer when done.
|
||||
// Writes may be buffered and not flushed until Close.
|
||||
//
|
||||
// Note that the exact bytes written to w are not covered by the Go 1
|
||||
// compatibility promise. Callers, including tests, should not depend on the
|
||||
// exact written bytes.
|
||||
func NewWriter(w io.Writer) *Writer {
|
||||
z, _ := NewWriterLevelDict(w, DefaultCompression, nil)
|
||||
return z
|
||||
|
|
@ -52,6 +56,10 @@ func NewWriter(w io.Writer) *Writer {
|
|||
// The compression level can be [DefaultCompression], [NoCompression], [HuffmanOnly]
|
||||
// or any integer value between [BestSpeed] and [BestCompression] inclusive.
|
||||
// The error returned will be nil if the level is valid.
|
||||
//
|
||||
// Note that the exact bytes written to w are not covered by the Go 1
|
||||
// compatibility promise. Callers, including tests, should not depend on the
|
||||
// exact written bytes.
|
||||
func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
|
||||
return NewWriterLevelDict(w, level, nil)
|
||||
}
|
||||
|
|
@ -61,6 +69,10 @@ func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
|
|||
//
|
||||
// The dictionary may be nil. If not, its contents should not be modified until
|
||||
// the Writer is closed.
|
||||
//
|
||||
// Note that the exact bytes written to w are not covered by the Go 1
|
||||
// compatibility promise. Callers, including tests, should not depend on the
|
||||
// exact written bytes.
|
||||
func NewWriterLevelDict(w io.Writer, level int, dict []byte) (*Writer, error) {
|
||||
if level < HuffmanOnly || level > BestCompression {
|
||||
return nil, fmt.Errorf("zlib: invalid compression level: %d", level)
|
||||
|
|
|
|||
|
|
@ -581,12 +581,20 @@ func (e *encoder) writeIEND() { e.writeChunk(nil, "IEND") }
|
|||
|
||||
// Encode writes the Image m to w in PNG format. Any Image may be
|
||||
// encoded, but images that are not [image.NRGBA] might be encoded lossily.
|
||||
//
|
||||
// Note that the exact bytes written to w are not covered by the Go 1
|
||||
// compatibility promise. Callers, including tests, should not depend on the
|
||||
// exact written bytes.
|
||||
func Encode(w io.Writer, m image.Image) error {
|
||||
var e Encoder
|
||||
return e.Encode(w, m)
|
||||
}
|
||||
|
||||
// Encode writes the Image m to w in PNG format.
|
||||
//
|
||||
// Note that the exact bytes written to w are not covered by the Go 1
|
||||
// compatibility promise. Callers, including tests, should not depend on the
|
||||
// exact written bytes.
|
||||
func (enc *Encoder) Encode(w io.Writer, m image.Image) error {
|
||||
// Obviously, negative widths and heights are invalid. Furthermore, the PNG
|
||||
// spec section 11.2.2 says that zero is invalid. Excessively large images are
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue