* Sierra VMD Audio & Video Decoders
* Copyright (C) 2004 the ffmpeg project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define QUEUE_SIZE 0x1000
#define QUEUE_MASK 0x0FFF
-static void lz_unpack(const unsigned char *src, unsigned char *dest, int dest_len)
+static void lz_unpack(const unsigned char *src, int src_len,
+ unsigned char *dest, int dest_len)
{
const unsigned char *s;
+ const unsigned char *s_end;
unsigned char *d;
unsigned char *d_end;
unsigned char queue[QUEUE_SIZE];
unsigned int i, j;
s = src;
+ s_end = src + src_len;
d = dest;
d_end = d + dest_len;
+
+ if (s_end - s < 8)
+ return;
dataleft = AV_RL32(s);
s += 4;
memset(queue, 0x20, QUEUE_SIZE);
speclen = 100; /* no speclen */
}
- while (dataleft > 0) {
+ while (s_end - s > 0 && dataleft > 0) {
tag = *s++;
if ((tag == 0xFF) && (dataleft > 8)) {
- if (d + 8 > d_end)
+ if (d_end - d < 8 || s_end - s < 8)
return;
for (i = 0; i < 8; i++) {
queue[qpos++] = *d++ = *s++;
if (dataleft == 0)
break;
if (tag & 0x01) {
- if (d + 1 > d_end)
+ if (d_end - d < 1 || s_end - s < 1)
return;
queue[qpos++] = *d++ = *s++;
qpos &= QUEUE_MASK;
dataleft--;
} else {
+ if (s_end - s < 2)
+ return;
chainofs = *s++;
chainofs |= ((*s & 0xF0) << 4);
chainlen = (*s++ & 0x0F) + 3;
- if (chainlen == speclen)
+ if (chainlen == speclen) {
+ if (s_end - s < 1)
+ return;
chainlen = *s++ + 0xF + 3;
- if (d + chainlen > d_end)
+ }
+ if (d_end - d < chainlen)
return;
for (j = 0; j < chainlen; j++) {
*d = queue[chainofs++ & QUEUE_MASK];
}
}
-static int rle_unpack(const unsigned char *src, unsigned char *dest,
- int src_len, int dest_len)
+static int rle_unpack(const unsigned char *src, int src_len, int src_count,
+ unsigned char *dest, int dest_len)
{
const unsigned char *ps;
+ const unsigned char *ps_end;
unsigned char *pd;
int i, l;
unsigned char *dest_end = dest + dest_len;
ps = src;
+ ps_end = src + src_len;
pd = dest;
- if (src_len & 1)
+ if (src_count & 1) {
+ if (ps_end - ps < 1)
+ return 0;
*pd++ = *ps++;
+ }
- src_len >>= 1;
+ src_count >>= 1;
i = 0;
do {
+ if (ps_end - ps < 1)
+ break;
l = *ps++;
if (l & 0x80) {
l = (l & 0x7F) * 2;
- if (pd + l > dest_end)
+ if (dest_end - pd < l || ps_end - ps < l)
return ps - src;
memcpy(pd, ps, l);
ps += l;
pd += l;
} else {
- if (pd + i > dest_end)
+ if (dest_end - pd < i || ps_end - ps < 2)
return ps - src;
for (i = 0; i < l; i++) {
*pd++ = ps[0];
ps += 2;
}
i += l;
- } while (i < src_len);
+ } while (i < src_count);
return ps - src;
}
/* point to the start of the encoded data */
const unsigned char *p = s->buf + 16;
+ const unsigned char *p_end = s->buf + s->size;
const unsigned char *pb;
+ const unsigned char *pb_end;
unsigned char meth;
unsigned char *dp; /* pointer to current frame */
unsigned char *pp; /* pointer to previous frame */
frame_y = AV_RL16(&s->buf[8]);
frame_width = AV_RL16(&s->buf[10]) - frame_x + 1;
frame_height = AV_RL16(&s->buf[12]) - frame_y + 1;
+ if (frame_x < 0 || frame_width < 0 ||
+ frame_x >= s->avctx->width ||
+ frame_width > s->avctx->width ||
+ frame_x + frame_width > s->avctx->width)
+ return;
+ if (frame_y < 0 || frame_height < 0 ||
+ frame_y >= s->avctx->height ||
+ frame_height > s->avctx->height ||
+ frame_y + frame_height > s->avctx->height)
+ return;
if ((frame_width == s->avctx->width && frame_height == s->avctx->height) &&
(frame_x || frame_y)) {
/* if only a certain region will be updated, copy the entire previous
* frame before the decode */
- if (frame_x || frame_y || (frame_width != s->avctx->width) ||
- (frame_height != s->avctx->height)) {
+ if (s->prev_frame.data[0] &&
+ (frame_x || frame_y || (frame_width != s->avctx->width) ||
+ (frame_height != s->avctx->height))) {
memcpy(s->frame.data[0], s->prev_frame.data[0],
s->avctx->height * s->frame.linesize[0]);
/* check if there is a new palette */
if (s->buf[15] & 0x02) {
+ if (p_end - p < 2 + 3 * PALETTE_COUNT)
+ return;
p += 2;
palette32 = (unsigned int *)s->palette;
for (i = 0; i < PALETTE_COUNT; i++) {
b = *p++ * 4;
palette32[i] = (r << 16) | (g << 8) | (b);
}
- s->size -= (256 * 3 + 2);
}
- if (s->size >= 0) {
+ if (p < p_end) {
/* originally UnpackFrame in VAG's code */
pb = p;
+ pb_end = p_end;
meth = *pb++;
if (meth & 0x80) {
- lz_unpack(pb, s->unpack_buffer, s->unpack_buffer_size);
+ lz_unpack(pb, p_end - pb, s->unpack_buffer, s->unpack_buffer_size);
meth &= 0x7F;
pb = s->unpack_buffer;
+ pb_end = s->unpack_buffer + s->unpack_buffer_size;
}
dp = &s->frame.data[0][frame_y * s->frame.linesize[0] + frame_x];
for (i = 0; i < frame_height; i++) {
ofs = 0;
do {
+ if (pb_end - pb < 1)
+ return;
len = *pb++;
if (len & 0x80) {
len = (len & 0x7F) + 1;
- if (ofs + len > frame_width)
+ if (ofs + len > frame_width || pb_end - pb < len)
return;
memcpy(&dp[ofs], pb, len);
pb += len;
ofs += len;
} else {
/* interframe pixel copy */
- if (ofs + len + 1 > frame_width)
+ if (ofs + len + 1 > frame_width || !s->prev_frame.data[0])
return;
memcpy(&dp[ofs], &pp[ofs], len + 1);
ofs += len + 1;
case 2:
for (i = 0; i < frame_height; i++) {
+ if (pb_end -pb < frame_width)
+ return;
memcpy(dp, pb, frame_width);
pb += frame_width;
dp += s->frame.linesize[0];
for (i = 0; i < frame_height; i++) {
ofs = 0;
do {
+ if (pb_end - pb < 1)
+ return;
len = *pb++;
if (len & 0x80) {
len = (len & 0x7F) + 1;
+ if (pb_end - pb < 1)
+ return;
if (*pb++ == 0xFF)
- len = rle_unpack(pb, &dp[ofs], len, frame_width - ofs);
- else
+ len = rle_unpack(pb, pb_end - pb, len, &dp[ofs], frame_width - ofs);
+ else {
+ if (pb_end - pb < len)
+ return;
memcpy(&dp[ofs], pb, len);
+ }
pb += len;
ofs += len;
} else {
/* interframe pixel copy */
- if (ofs + len + 1 > frame_width)
+ if (ofs + len + 1 > frame_width || !s->prev_frame.data[0])
return;
memcpy(&dp[ofs], &pp[ofs], len + 1);
ofs += len + 1;
palette32[i] = (r << 16) | (g << 8) | (b);
}
+ avcodec_get_frame_defaults(&s->frame);
+ avcodec_get_frame_defaults(&s->prev_frame);
+
return 0;
}