From: Nigel Tao Date: Sat, 9 Oct 2021 05:52:19 +0000 (+1100) Subject: compress/lzw: output a Clear code first, per GIF spec X-Git-Tag: go1.18beta1~939 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=9c1dbdf60edbffeff10f58af21fa055eb0fdd29f;p=gostls13.git compress/lzw: output a Clear code first, per GIF spec The TestStartsWithClearCode test is new, but if it existed beforehand, the want strings would be "\x81" and "Hi\x81" without a starting "\x80". Fixes #26108 Fixes #33748 Updates makeworld-the-better-one/didder#7 Updates nothings/stb#1222 Change-Id: I35ac0ed862ba6ee921ba9aee257bc19828abaa82 Reviewed-on: https://go-review.googlesource.com/c/go/+/354710 Trust: Nigel Tao Run-TryBot: Nigel Tao TryBot-Result: Go Bot Reviewed-by: Andrew Gerrand --- diff --git a/src/compress/lzw/writer.go b/src/compress/lzw/writer.go index 552bdc2ce1..cf06ea80c7 100644 --- a/src/compress/lzw/writer.go +++ b/src/compress/lzw/writer.go @@ -137,7 +137,19 @@ func (w *Writer) Write(p []byte) (n int, err error) { n = len(p) code := w.savedCode if code == invalidCode { - // The first code sent is always a literal code. + // This is the first write; send a clear code. + // https://www.w3.org/Graphics/GIF/spec-gif89a.txt Appendix F + // "Variable-Length-Code LZW Compression" says that "Encoders should + // output a Clear code as the first code of each image data stream". + // + // LZW compression isn't only used by GIF, but it's cheap to follow + // that directive unconditionally. + clear := uint32(1) << w.litWidth + if err := w.write(w, clear); err != nil { + return 0, err + } + // After the starting clear code, the next code sent (for non-empty + // input) is always a literal code. code, p = uint32(p[0]), p[1:] } loop: @@ -202,6 +214,12 @@ func (w *Writer) Close() error { if err := w.incHi(); err != nil && err != errOutOfCodes { return err } + } else { + // Write the starting clear code, as w.Write did not. + clear := uint32(1) << w.litWidth + if err := w.write(w, clear); err != nil { + return err + } } // Write the eof code. eof := uint32(1)<