Commit 4618dd87 authored by Nigel Tao's avatar Nigel Tao

image/gif: accept an out-of-bounds transparent color index.

This is an error according to the spec, but Firefox and Google Chrome
seem OK with this.

Fixes #15059.

Change-Id: I841cf44e96655e91a2481555f38fbd7055a32202
Reviewed-on: https://go-review.googlesource.com/22546Reviewed-by: default avatarRob Pike <r@golang.org>
parent ac0ee77d
......@@ -178,12 +178,25 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
}
m.Palette = d.globalColorTable
}
if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) {
if d.hasTransparentIndex {
if !useLocalColorTable {
// Clone the global color table.
m.Palette = append(color.Palette(nil), d.globalColorTable...)
}
m.Palette[d.transparentIndex] = color.RGBA{}
if ti := int(d.transparentIndex); ti < len(m.Palette) {
m.Palette[ti] = color.RGBA{}
} else {
// The transparentIndex is out of range, which is an error
// according to the spec, but Firefox and Google Chrome
// seem OK with this, so we enlarge the palette with
// transparent colors. See golang.org/issue/15059.
p := make(color.Palette, ti+1)
copy(p, m.Palette)
for i := len(m.Palette); i < len(p); i++ {
p[i] = color.RGBA{}
}
m.Palette = p
}
}
litWidth, err := d.r.ReadByte()
if err != nil {
......
......@@ -22,12 +22,16 @@ const (
trailerStr = "\x3b"
)
// lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes.
func lzwEncode(n int) []byte {
// lzwEncode returns an LZW encoding (with 2-bit literals) of in.
func lzwEncode(in []byte) []byte {
b := &bytes.Buffer{}
w := lzw.NewWriter(b, lzw.LSB, 2)
w.Write(make([]byte, n))
w.Close()
if _, err := w.Write(in); err != nil {
panic(err)
}
if err := w.Close(); err != nil {
panic(err)
}
return b.Bytes()
}
......@@ -53,7 +57,7 @@ func TestDecode(t *testing.T) {
// byte, and 2-bit LZW literals.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
if tc.nPix > 0 {
enc := lzwEncode(tc.nPix)
enc := lzwEncode(make([]byte, tc.nPix))
if len(enc) > 0xff {
t.Errorf("nPix=%d, extra=%t: compressed length %d is too large", tc.nPix, tc.extra, len(enc))
continue
......@@ -103,7 +107,7 @@ func TestTransparentIndex(t *testing.T) {
}
// Write an image with bounds 2x1, as per TestDecode.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
enc := lzwEncode(2)
enc := lzwEncode([]byte{0x00, 0x00})
if len(enc) > 0xff {
t.Fatalf("compressed length %d is too large", len(enc))
}
......@@ -196,21 +200,13 @@ func TestNoPalette(t *testing.T) {
b.WriteString(headerStr[:len(headerStr)-3])
b.WriteString("\x00\x00\x00") // No global palette.
// Image descriptor: 2x1, no local palette.
// Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
// Encode the pixels: neither is in range, because there is no palette.
pix := []byte{0, 3}
enc := &bytes.Buffer{}
w := lzw.NewWriter(enc, lzw.LSB, 2)
if _, err := w.Write(pix); err != nil {
t.Fatalf("Write: %v", err)
}
if err := w.Close(); err != nil {
t.Fatalf("Close: %v", err)
}
b.WriteByte(byte(len(enc.Bytes())))
b.Write(enc.Bytes())
enc := lzwEncode([]byte{0x00, 0x03})
b.WriteByte(byte(len(enc)))
b.Write(enc)
b.WriteByte(0x00) // An empty block signifies the end of the image data.
b.WriteString(trailerStr)
......@@ -226,21 +222,13 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
b.WriteString(headerStr)
b.WriteString(paletteStr)
// Image descriptor: 2x1, no local palette.
// Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
// Encode the pixels; some pvals trigger the expected error.
pix := []byte{pval, pval}
enc := &bytes.Buffer{}
w := lzw.NewWriter(enc, lzw.LSB, 2)
if _, err := w.Write(pix); err != nil {
t.Fatalf("Write: %v", err)
}
if err := w.Close(); err != nil {
t.Fatalf("Close: %v", err)
}
b.WriteByte(byte(len(enc.Bytes())))
b.Write(enc.Bytes())
enc := lzwEncode([]byte{pval, pval})
b.WriteByte(byte(len(enc)))
b.Write(enc)
b.WriteByte(0x00) // An empty block signifies the end of the image data.
b.WriteString(trailerStr)
......@@ -254,6 +242,36 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
}
}
func TestTransparentPixelOutsidePaletteRange(t *testing.T) {
b := &bytes.Buffer{}
// Manufacture a GIF with a 2 color palette.
b.WriteString(headerStr)
b.WriteString(paletteStr)
// Graphic Control Extension: transparency, transparent color index = 3.
//
// This index, 3, is out of range of the global palette and there is no
// local palette in the subsequent image descriptor. This is an error
// according to the spec, but Firefox and Google Chrome seem OK with this.
//
// See golang.org/issue/15059.
b.WriteString("\x21\xf9\x04\x01\x00\x00\x03\x00")
// Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
// Encode the pixels.
enc := lzwEncode([]byte{0x03, 0x03})
b.WriteByte(byte(len(enc)))
b.Write(enc)
b.WriteByte(0x00) // An empty block signifies the end of the image data.
b.WriteString(trailerStr)
try(t, b.Bytes(), "")
}
func TestLoopCount(t *testing.T) {
data := []byte("GIF89a000\x00000,0\x00\x00\x00\n\x00" +
"\n\x00\x80000000\x02\b\xf01u\xb9\xfdal\x05\x00;")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment