Skip to content

Commit

Permalink
don't panic on reading short block data.
Browse files Browse the repository at this point in the history
  • Loading branch information
chai2010 committed Apr 28, 2015
1 parent b9d8cfc commit de4394a
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 8 deletions.
7 changes: 5 additions & 2 deletions bits_io.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,20 @@ func newBitsReader(data []byte) *bitsReader {
}

// readBits reads n bits from the internal buffer starting at the current offset.
func (p *bitsReader) ReadBits(n uint) uint32 {
func (p *bitsReader) ReadBits(n uint) (v uint32, ok bool) {
for p.nbits < n {
p.v <<= 8
if p.off >= len(p.buf) {
return 0, false
}
p.v |= uint32(p.buf[p.off])
p.off++
p.nbits += 8
}
p.nbits -= n
rv := p.v >> p.nbits
p.v &^= rv << p.nbits
return rv
return rv, true
}

// flushBits discards the unread bits in the buffer used by readBits.
Expand Down
26 changes: 26 additions & 0 deletions decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,32 @@ func TestUnpackBits(t *testing.T) {
}
}

func TestShortBlockData(t *testing.T) {
b, err := ioutil.ReadFile("./testdata/bw-uncompressed.tiff")
if err != nil {
t.Fatal(err)
}
// The bw-uncompressed.tiff image is a 153x55 bi-level image. This is 1 bit
// per pixel, or 20 bytes per row, times 55 rows, or 1100 bytes of pixel
// data. 1100 in hex is 0x44c, or "\x4c\x04" in little-endian. We replace
// that byte count (StripByteCounts-tagged data) by something less than
// that, so that there is not enough pixel data.
old := []byte{0x4c, 0x04}
new := []byte{0x01, 0x01}
i := bytes.Index(b, old)
if i < 0 {
t.Fatal(`could not find "\x4c\x04" byte count`)
}
if bytes.Contains(b[i+len(old):], old) {
t.Fatal(`too many occurrences of "\x4c\x04"`)
}
b[i+0] = new[0]
b[i+1] = new[1]
if _, err = Decode(bytes.NewReader(b)); err == nil {
t.Fatal("got nil error, want non-nil")
}
}

func compare(t *testing.T, img0, img1 image.Image) {
b0 := img0.Bounds()
b1 := img1.Bounds()
Expand Down
66 changes: 60 additions & 6 deletions tiff_ifd_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ func (p *IFD) decodePredictor(data []byte, r image.Rectangle) (out []byte, err e
for y := r.Min.Y; y < r.Max.Y; y++ {
off += spp * 2
for x := 0; x < (r.Dx()-1)*spp*2; x += 2 {
if off+2 > len(data) {
err = fmt.Errorf("tiff: IFD.decodePredictor, not enough pixel data")
return
}
v0 := p.Header.ByteOrder.Uint16(data[off-spp*2 : off-spp*2+2])
v1 := p.Header.ByteOrder.Uint16(data[off : off+2])
p.Header.ByteOrder.PutUint16(data[off:off+2], v1+v0)
Expand All @@ -177,6 +181,10 @@ func (p *IFD) decodePredictor(data []byte, r image.Rectangle) (out []byte, err e
for y := r.Min.Y; y < r.Max.Y; y++ {
off += spp
for x := 0; x < (r.Dx()-1)*spp; x++ {
if off >= len(data) {
err = fmt.Errorf("tiff: IFD.decodePredictor, not enough pixel data")
return
}
data[off] += data[off-spp]
off++
}
Expand All @@ -197,12 +205,16 @@ func (p *IFD) decodeBlock(buf []byte, dst image.Image, r image.Rectangle) (err e
rMaxY := minInt(ymax, dst.Bounds().Max.Y)

switch p.ImageType() {
case ImageType_Gray, ImageType_GrayInvert:
case ImageType_Gray, ImageType_GrayInvert, ImageType_Bilevel, ImageType_BilevelInvert:
if p.Depth() == 16 {
var off int
img := dst.(*image.Gray16)
for y := ymin; y < rMaxY; y++ {
for x := xmin; x < rMaxX; x++ {
if off+2 > len(buf) {
err = fmt.Errorf("tiff: IFD.decodeBlock, not enough pixel data")
return
}
v := p.Header.ByteOrder.Uint16(buf[off : off+2])
off += 2
if p.ImageType() == ImageType_GrayInvert {
Expand All @@ -212,25 +224,38 @@ func (p *IFD) decodeBlock(buf []byte, dst image.Image, r image.Rectangle) (err e
}
}
} else {
bpp := uint(p.Depth())
bitReader := newBitsReader(buf)
img := dst.(*image.Gray)
max := uint32((1 << uint(p.Depth())) - 1)
for y := ymin; y < rMaxY; y++ {
for x := xmin; x < rMaxX; x++ {
v := uint8(bitReader.ReadBits(uint(p.Depth())) * 0xff / max)
v, ok := bitReader.ReadBits(bpp)
if !ok {
err = fmt.Errorf("tiff: IFD.decodeBlock, not enough pixel data")
return
}
v = v * 0xff / max
if p.ImageType() == ImageType_GrayInvert {
v = 0xff - v
}
img.SetGray(x, y, color.Gray{v})
img.SetGray(x, y, color.Gray{uint8(v)})
}
bitReader.flushBits()
}
}
case ImageType_Paletted:
bpp := uint(p.Depth())
bitReader := newBitsReader(buf)
img := dst.(*image.Paletted)
for y := ymin; y < rMaxY; y++ {
for x := xmin; x < rMaxX; x++ {
img.SetColorIndex(x, y, uint8(bitReader.ReadBits(uint(p.Depth()))))
v, ok := bitReader.ReadBits(bpp)
if !ok {
err = fmt.Errorf("tiff: IFD.decodeBlock, not enough pixel data")
return
}
img.SetColorIndex(x, y, uint8(v))
}
bitReader.flushBits()
}
Expand All @@ -240,6 +265,10 @@ func (p *IFD) decodeBlock(buf []byte, dst image.Image, r image.Rectangle) (err e
img := dst.(*image.RGBA64)
for y := ymin; y < rMaxY; y++ {
for x := xmin; x < rMaxX; x++ {
if off+6 > len(buf) {
err = fmt.Errorf("tiff: IFD.decodeBlock, not enough pixel data")
return
}
r := p.Header.ByteOrder.Uint16(buf[off+0 : off+2])
g := p.Header.ByteOrder.Uint16(buf[off+2 : off+4])
b := p.Header.ByteOrder.Uint16(buf[off+4 : off+6])
Expand All @@ -254,6 +283,10 @@ func (p *IFD) decodeBlock(buf []byte, dst image.Image, r image.Rectangle) (err e
max := img.PixOffset(rMaxX, y)
off := (y - ymin) * (xmax - xmin) * 3
for i := min; i < max; i += 4 {
if off+3 > len(buf) {
err = fmt.Errorf("tiff: IFD.decodeBlock, not enough pixel data")
return
}
img.Pix[i+0] = buf[off+0]
img.Pix[i+1] = buf[off+1]
img.Pix[i+2] = buf[off+2]
Expand All @@ -268,6 +301,10 @@ func (p *IFD) decodeBlock(buf []byte, dst image.Image, r image.Rectangle) (err e
img := dst.(*image.NRGBA64)
for y := ymin; y < rMaxY; y++ {
for x := xmin; x < rMaxX; x++ {
if off+8 > len(buf) {
err = fmt.Errorf("tiff: IFD.decodeBlock, not enough pixel data")
return
}
r := p.Header.ByteOrder.Uint16(buf[off+0 : off+2])
g := p.Header.ByteOrder.Uint16(buf[off+2 : off+4])
b := p.Header.ByteOrder.Uint16(buf[off+4 : off+6])
Expand All @@ -281,7 +318,12 @@ func (p *IFD) decodeBlock(buf []byte, dst image.Image, r image.Rectangle) (err e
for y := ymin; y < rMaxY; y++ {
min := img.PixOffset(xmin, y)
max := img.PixOffset(rMaxX, y)
copy(img.Pix[min:max], buf[(y-ymin)*(xmax-xmin)*4:(y-ymin+1)*(xmax-xmin)*4])
i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4
if i1 > len(buf) {
err = fmt.Errorf("tiff: IFD.decodeBlock, not enough pixel data")
return
}
copy(img.Pix[min:max], buf[i0:i1])
}
}
case ImageType_RGBA:
Expand All @@ -290,6 +332,10 @@ func (p *IFD) decodeBlock(buf []byte, dst image.Image, r image.Rectangle) (err e
img := dst.(*image.RGBA64)
for y := ymin; y < rMaxY; y++ {
for x := xmin; x < rMaxX; x++ {
if off+8 > len(buf) {
err = fmt.Errorf("tiff: IFD.decodeBlock, not enough pixel data")
return
}
r := p.Header.ByteOrder.Uint16(buf[off+0 : off+2])
g := p.Header.ByteOrder.Uint16(buf[off+2 : off+4])
b := p.Header.ByteOrder.Uint16(buf[off+4 : off+6])
Expand All @@ -303,9 +349,17 @@ func (p *IFD) decodeBlock(buf []byte, dst image.Image, r image.Rectangle) (err e
for y := ymin; y < rMaxY; y++ {
min := img.PixOffset(xmin, y)
max := img.PixOffset(rMaxX, y)
copy(img.Pix[min:max], buf[(y-ymin)*(xmax-xmin)*4:(y-ymin+1)*(xmax-xmin)*4])
i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4
if i1 > len(buf) {
err = fmt.Errorf("tiff: IFD.decodeBlock, not enough pixel data")
return
}
copy(img.Pix[min:max], buf[i0:i1])
}
}
default:
err = fmt.Errorf("tiff: IFD.decodeBlock, unknown imageType: %v", p.ImageType())
return
}

return
Expand Down

0 comments on commit de4394a

Please sign in to comment.