X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fpcx.c;h=61c971e073f2e400dba95482c9862f2e344de284;hb=3aca10bf762a94d7de555cedf1ff0e4f6792bf41;hp=0a18acd486eed2ff5849cf0845ea42e20f74a29f;hpb=36ef5369ee9b336febc2c270f8718cec4476cb85;p=ffmpeg diff --git a/libavcodec/pcx.c b/libavcodec/pcx.c index 0a18acd486e..61c971e073f 100644 --- a/libavcodec/pcx.c +++ b/libavcodec/pcx.c @@ -26,37 +26,29 @@ #include "avcodec.h" #include "bytestream.h" #include "get_bits.h" - -typedef struct PCXContext { - AVFrame picture; -} PCXContext; - -static av_cold int pcx_init(AVCodecContext *avctx) { - PCXContext *s = avctx->priv_data; - - avcodec_get_frame_defaults(&s->picture); - avctx->coded_frame= &s->picture; - - return 0; -} +#include "internal.h" /** * @return advanced src pointer */ -static const uint8_t *pcx_rle_decode(const uint8_t *src, uint8_t *dst, - unsigned int bytes_per_scanline, int compressed) { +static const uint8_t *pcx_rle_decode(const uint8_t *src, + const uint8_t *end, + uint8_t *dst, + unsigned int bytes_per_scanline, + int compressed) +{ unsigned int i = 0; unsigned char run, value; if (compressed) { - while (i= 0xc0) { - run = value & 0x3f; + if (value >= 0xc0 && src < end) { + run = value & 0x3f; value = *src++; } - while (idata; - int buf_size = avpkt->size; - PCXContext * const s = avctx->priv_data; - AVFrame *picture = data; - AVFrame * const p = &s->picture; + int buf_size = avpkt->size; + AVFrame *const p = data; int compressed, xmin, ymin, xmax, ymax; unsigned int w, h, bits_per_pixel, bytes_per_line, nplanes, stride, y, x, bytes_per_scanline; uint8_t *ptr; + const uint8_t *buf_end = buf + buf_size; uint8_t const *bufstart = buf; uint8_t *scanline; int ret = -1; if (buf[0] != 0x0a || buf[1] > 5) { av_log(avctx, AV_LOG_ERROR, "this is not PCX encoded data\n"); - return -1; + return AVERROR_INVALIDDATA; } compressed = buf[2]; - xmin = AV_RL16(buf+ 4); - ymin = AV_RL16(buf+ 6); - xmax = AV_RL16(buf+ 8); - ymax = AV_RL16(buf+10); + xmin = AV_RL16(buf + 4); + ymin = AV_RL16(buf + 6); + xmax = AV_RL16(buf + 8); + ymax = AV_RL16(buf + 10); if (xmax < xmin || ymax < ymin) { av_log(avctx, AV_LOG_ERROR, "invalid image dimensions\n"); - return -1; + return AVERROR_INVALIDDATA; } w = xmax - xmin + 1; h = ymax - ymin + 1; bits_per_pixel = buf[3]; - bytes_per_line = AV_RL16(buf+66); + bytes_per_line = AV_RL16(buf + 66); nplanes = buf[65]; bytes_per_scanline = nplanes * bytes_per_line; - if (bytes_per_scanline < w * bits_per_pixel * nplanes / 8) { + if (bytes_per_scanline < (w * bits_per_pixel * nplanes + 7) / 8 || + (!compressed && bytes_per_scanline > buf_size / h)) { av_log(avctx, AV_LOG_ERROR, "PCX data is corrupted\n"); - return -1; + return AVERROR_INVALIDDATA; } - switch ((nplanes<<8) + bits_per_pixel) { - case 0x0308: - avctx->pix_fmt = PIX_FMT_RGB24; - break; - case 0x0108: - case 0x0104: - case 0x0102: - case 0x0101: - case 0x0401: - case 0x0301: - case 0x0201: - avctx->pix_fmt = PIX_FMT_PAL8; - break; - default: - av_log(avctx, AV_LOG_ERROR, "invalid PCX file\n"); - return -1; + switch ((nplanes << 8) + bits_per_pixel) { + case 0x0308: + avctx->pix_fmt = AV_PIX_FMT_RGB24; + break; + case 0x0108: + case 0x0104: + case 0x0102: + case 0x0101: + case 0x0401: + case 0x0301: + case 0x0201: + avctx->pix_fmt = AV_PIX_FMT_PAL8; + break; + default: + av_log(avctx, AV_LOG_ERROR, "invalid PCX file\n"); + return AVERROR_INVALIDDATA; } buf += 128; - if (p->data[0]) - avctx->release_buffer(avctx, p); + if ((ret = ff_set_dimensions(avctx, w, h)) < 0) + return ret; - if (av_image_check_size(w, h, 0, avctx)) - return -1; - if (w != avctx->width || h != avctx->height) - avcodec_set_dimensions(avctx, w, h); - if (avctx->get_buffer(avctx, p) < 0) { + if ((ret = ff_get_buffer(avctx, p, 0)) < 0) { av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); - return -1; + return ret; } p->pict_type = AV_PICTURE_TYPE_I; @@ -162,23 +153,31 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *data_size, return AVERROR(ENOMEM); if (nplanes == 3 && bits_per_pixel == 8) { - for (y=0; yerr_recognition & AV_EF_EXPLODE ? + AVERROR_INVALIDDATA : buf_size; + goto end; + } + + for (y = 0; y < h; y++, ptr += stride) { + buf = pcx_rle_decode(buf, buf_end, + scanline, bytes_per_scanline, compressed); memcpy(ptr, scanline, w); } @@ -188,33 +187,35 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *data_size, } if (*buf++ != 12) { av_log(avctx, AV_LOG_ERROR, "expected palette after image data\n"); + ret = avctx->err_recognition & AV_EF_EXPLODE ? + AVERROR_INVALIDDATA : buf_size; goto end; } - } else if (nplanes == 1) { /* all packed formats, max. 16 colors */ GetBitContext s; - for (y=0; y> (x&7), v = 0; - for (i=nplanes - 1; i>=0; i--) { + for (x = 0; x < w; x++) { + int m = 0x80 >> (x & 7), v = 0; + for (i = nplanes - 1; i >= 0; i--) { v <<= 1; - v += !!(scanline[i*bytes_per_line + (x>>3)] & m); + v += !!(scanline[i * bytes_per_line + (x >> 3)] & m); } ptr[x] = v; } @@ -223,14 +224,13 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *data_size, } if (nplanes == 1 && bits_per_pixel == 8) { - pcx_palette(&buf, (uint32_t *) p->data[1], 256); + pcx_palette(&buf, (uint32_t *)p->data[1], 256); } else if (bits_per_pixel < 8) { - const uint8_t *palette = bufstart+16; - pcx_palette(&palette, (uint32_t *) p->data[1], 16); + const uint8_t *palette = bufstart + 16; + pcx_palette(&palette, (uint32_t *)p->data[1], 16); } - *picture = s->picture; - *data_size = sizeof(AVFrame); + *got_frame = 1; ret = buf - bufstart; end: @@ -238,23 +238,11 @@ end: return ret; } -static av_cold int pcx_end(AVCodecContext *avctx) { - PCXContext *s = avctx->priv_data; - - if(s->picture.data[0]) - avctx->release_buffer(avctx, &s->picture); - - return 0; -} - AVCodec ff_pcx_decoder = { - .name = "pcx", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_PCX, - .priv_data_size = sizeof(PCXContext), - .init = pcx_init, - .close = pcx_end, - .decode = pcx_decode_frame, - .capabilities = CODEC_CAP_DR1, - .long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"), + .name = "pcx", + .long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_PCX, + .decode = pcx_decode_frame, + .capabilities = CODEC_CAP_DR1, };