]> git.sesse.net Git - ffmpeg/blob - libavcodec/pcx.c
mpegvideo_parser: fix buffer access beyond end
[ffmpeg] / libavcodec / pcx.c
1 /*
2  * PC Paintbrush PCX (.pcx) image decoder
3  * Copyright (c) 2007, 2008 Ivo van Poorten
4  *
5  * This decoder does not support CGA palettes. I am unable to find samples
6  * and Netpbm cannot generate them.
7  *
8  * This file is part of FFmpeg.
9  *
10  * FFmpeg is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * FFmpeg is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with FFmpeg; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  */
24
25 #include "libavutil/imgutils.h"
26 #include "avcodec.h"
27 #include "bytestream.h"
28 #include "get_bits.h"
29 #include "internal.h"
30
31 typedef struct PCXContext {
32     AVFrame picture;
33 } PCXContext;
34
35 static av_cold int pcx_init(AVCodecContext *avctx)
36 {
37     PCXContext *s = avctx->priv_data;
38
39     avcodec_get_frame_defaults(&s->picture);
40     avctx->coded_frame= &s->picture;
41
42     return 0;
43 }
44
45 static void pcx_rle_decode(GetByteContext *gb, uint8_t *dst,
46                            unsigned int bytes_per_scanline, int compressed)
47 {
48     unsigned int i = 0;
49     unsigned char run, value;
50
51     if (compressed) {
52         while (i<bytes_per_scanline) {
53             run = 1;
54             value = bytestream2_get_byte(gb);
55             if (value >= 0xc0) {
56                 run = value & 0x3f;
57                 value = bytestream2_get_byte(gb);
58             }
59             while (i<bytes_per_scanline && run--)
60                 dst[i++] = value;
61         }
62     } else {
63         bytestream2_get_buffer(gb, dst, bytes_per_scanline);
64     }
65 }
66
67 static void pcx_palette(GetByteContext *gb, uint32_t *dst, int pallen)
68 {
69     int i;
70
71     pallen = FFMIN(pallen, bytestream2_get_bytes_left(gb) / 3);
72     for (i=0; i<pallen; i++)
73         *dst++ = 0xFF000000 | bytestream2_get_be24u(gb);
74     if (pallen < 256)
75         memset(dst, 0, (256 - pallen) * sizeof(*dst));
76 }
77
78 static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
79                             AVPacket *avpkt)
80 {
81     PCXContext * const s = avctx->priv_data;
82     AVFrame *picture = data;
83     AVFrame * const p = &s->picture;
84     GetByteContext gb;
85     int compressed, xmin, ymin, xmax, ymax, ret;
86     unsigned int w, h, bits_per_pixel, bytes_per_line, nplanes, stride, y, x,
87                  bytes_per_scanline;
88     uint8_t *ptr, *scanline;
89
90     if (avpkt->size < 128)
91         return AVERROR_INVALIDDATA;
92
93     bytestream2_init(&gb, avpkt->data, avpkt->size);
94
95     if (bytestream2_get_byteu(&gb) != 0x0a || bytestream2_get_byteu(&gb) > 5) {
96         av_log(avctx, AV_LOG_ERROR, "this is not PCX encoded data\n");
97         return AVERROR_INVALIDDATA;
98     }
99
100     compressed = bytestream2_get_byteu(&gb);
101     bits_per_pixel = bytestream2_get_byteu(&gb);
102     xmin = bytestream2_get_le16u(&gb);
103     ymin = bytestream2_get_le16u(&gb);
104     xmax = bytestream2_get_le16u(&gb);
105     ymax = bytestream2_get_le16u(&gb);
106     avctx->sample_aspect_ratio.num = bytestream2_get_le16u(&gb);
107     avctx->sample_aspect_ratio.den = bytestream2_get_le16u(&gb);
108
109     if (xmax < xmin || ymax < ymin) {
110         av_log(avctx, AV_LOG_ERROR, "invalid image dimensions\n");
111         return AVERROR_INVALIDDATA;
112     }
113
114     w = xmax - xmin + 1;
115     h = ymax - ymin + 1;
116
117     bytestream2_skipu(&gb, 49);
118     nplanes            = bytestream2_get_byteu(&gb);
119     bytes_per_line     = bytestream2_get_le16u(&gb);
120     bytes_per_scanline = nplanes * bytes_per_line;
121
122     if (bytes_per_scanline < w * bits_per_pixel * nplanes / 8) {
123         av_log(avctx, AV_LOG_ERROR, "PCX data is corrupted\n");
124         return AVERROR_INVALIDDATA;
125     }
126
127     switch ((nplanes<<8) + bits_per_pixel) {
128         case 0x0308:
129             avctx->pix_fmt = AV_PIX_FMT_RGB24;
130             break;
131         case 0x0108:
132         case 0x0104:
133         case 0x0102:
134         case 0x0101:
135         case 0x0401:
136         case 0x0301:
137         case 0x0201:
138             avctx->pix_fmt = AV_PIX_FMT_PAL8;
139             break;
140         default:
141             av_log(avctx, AV_LOG_ERROR, "invalid PCX file\n");
142             return AVERROR_INVALIDDATA;
143     }
144
145     bytestream2_skipu(&gb, 60);
146
147     if (p->data[0])
148         avctx->release_buffer(avctx, p);
149
150     if (av_image_check_size(w, h, 0, avctx))
151         return AVERROR_INVALIDDATA;
152     if (w != avctx->width || h != avctx->height)
153         avcodec_set_dimensions(avctx, w, h);
154     if ((ret = ff_get_buffer(avctx, p)) < 0) {
155         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
156         return ret;
157     }
158
159     p->pict_type = AV_PICTURE_TYPE_I;
160
161     ptr    = p->data[0];
162     stride = p->linesize[0];
163
164     scanline = av_malloc(bytes_per_scanline);
165     if (!scanline)
166         return AVERROR(ENOMEM);
167
168     if (nplanes == 3 && bits_per_pixel == 8) {
169         for (y=0; y<h; y++) {
170             pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
171
172             for (x=0; x<w; x++) {
173                 ptr[3*x  ] = scanline[x                    ];
174                 ptr[3*x+1] = scanline[x+ bytes_per_line    ];
175                 ptr[3*x+2] = scanline[x+(bytes_per_line<<1)];
176             }
177
178             ptr += stride;
179         }
180
181     } else if (nplanes == 1 && bits_per_pixel == 8) {
182         int palstart = avpkt->size - 769;
183
184         for (y=0; y<h; y++, ptr+=stride) {
185             pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
186             memcpy(ptr, scanline, w);
187         }
188
189         if (bytestream2_tell(&gb) != palstart) {
190             av_log(avctx, AV_LOG_WARNING, "image data possibly corrupted\n");
191             bytestream2_seek(&gb, palstart, SEEK_SET);
192         }
193         if (bytestream2_get_byte(&gb) != 12) {
194             av_log(avctx, AV_LOG_ERROR, "expected palette after image data\n");
195             ret = AVERROR_INVALIDDATA;
196             goto end;
197         }
198
199     } else if (nplanes == 1) {   /* all packed formats, max. 16 colors */
200         GetBitContext s;
201
202         for (y=0; y<h; y++) {
203             init_get_bits(&s, scanline, bytes_per_scanline<<3);
204
205             pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
206
207             for (x=0; x<w; x++)
208                 ptr[x] = get_bits(&s, bits_per_pixel);
209             ptr += stride;
210         }
211
212     } else {    /* planar, 4, 8 or 16 colors */
213         int i;
214
215         for (y=0; y<h; y++) {
216             pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
217
218             for (x=0; x<w; x++) {
219                 int m = 0x80 >> (x&7), v = 0;
220                 for (i=nplanes - 1; i>=0; i--) {
221                     v <<= 1;
222                     v  += !!(scanline[i*bytes_per_line + (x>>3)] & m);
223                 }
224                 ptr[x] = v;
225             }
226             ptr += stride;
227         }
228     }
229
230     ret = bytestream2_tell(&gb);
231     if (nplanes == 1 && bits_per_pixel == 8) {
232         pcx_palette(&gb, (uint32_t *) p->data[1], 256);
233         ret += 256 * 3;
234     } else if (bits_per_pixel * nplanes == 1) {
235         AV_WN32A(p->data[1]  , 0xFF000000);
236         AV_WN32A(p->data[1]+4, 0xFFFFFFFF);
237     } else if (bits_per_pixel < 8) {
238         bytestream2_seek(&gb, 16, SEEK_SET);
239         pcx_palette(&gb, (uint32_t *) p->data[1], 16);
240     }
241
242     *picture = s->picture;
243     *got_frame = 1;
244
245 end:
246     av_free(scanline);
247     return ret;
248 }
249
250 static av_cold int pcx_end(AVCodecContext *avctx)
251 {
252     PCXContext *s = avctx->priv_data;
253
254     if(s->picture.data[0])
255         avctx->release_buffer(avctx, &s->picture);
256
257     return 0;
258 }
259
260 AVCodec ff_pcx_decoder = {
261     .name           = "pcx",
262     .type           = AVMEDIA_TYPE_VIDEO,
263     .id             = AV_CODEC_ID_PCX,
264     .priv_data_size = sizeof(PCXContext),
265     .init           = pcx_init,
266     .close          = pcx_end,
267     .decode         = pcx_decode_frame,
268     .capabilities   = CODEC_CAP_DR1,
269     .long_name      = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"),
270 };