]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/vmnc.c
fix decoding of ED-small-sample-file.ogg
[ffmpeg] / libavcodec / vmnc.c
index ac50221c2efc4570234b04227b92ce6429dfb276..07e2b3cf15d361ff42d57fe962d200d2d81025eb 100644 (file)
@@ -115,7 +115,7 @@ static void load_cursor(VmncContext *c, uint8_t *src)
 
 static void put_cursor(uint8_t *dst, int stride, VmncContext *c, int dx, int dy)
 {
-    int i, j, t;
+    int i, j;
     int w, h, x, y;
     w = c->cur_w;
     if(c->width < c->cur_x + c->cur_w) w = c->width - c->cur_x;
@@ -223,7 +223,7 @@ static always_inline void paint_raw(uint8_t *dst, int w, int h, uint8_t* src, in
     }
 }
 
-static int decode_hextile(VmncContext *c, uint8_t* dst, uint8_t* src, int w, int h, int stride)
+static int decode_hextile(VmncContext *c, uint8_t* dst, uint8_t* src, int ssize, int w, int h, int stride)
 {
     int i, j, k;
     int bg = 0, fg = 0, rects, color, flags, xy, wh;
@@ -237,9 +237,17 @@ static int decode_hextile(VmncContext *c, uint8_t* dst, uint8_t* src, int w, int
         bw = 16;
         if(j + 16 > h) bh = h - j;
         for(i = 0; i < w; i += 16, dst2 += 16 * bpp) {
+            if(src - ssrc >= ssize) {
+                av_log(c->avctx, AV_LOG_ERROR, "Premature end of data!\n");
+                return -1;
+            }
             if(i + 16 > w) bw = w - i;
             flags = *src++;
             if(flags & HT_RAW) {
+                if(src - ssrc > ssize - bw * bh * bpp) {
+                    av_log(c->avctx, AV_LOG_ERROR, "Premature end of data!\n");
+                    return -1;
+                }
                 paint_raw(dst2, bw, bh, src, bpp, c->bigendian, stride);
                 src += bw * bh * bpp;
             } else {
@@ -252,10 +260,14 @@ static int decode_hextile(VmncContext *c, uint8_t* dst, uint8_t* src, int w, int
                 rects = 0;
                 if(flags & HT_SUB)
                     rects = *src++;
-                color = (flags & HT_CLR);
+                color = !!(flags & HT_CLR);
 
                 paint_rect(dst2, 0, 0, bw, bh, bg, bpp, stride);
 
+                if(src - ssrc > ssize - rects * (color * bpp + 2)) {
+                    av_log(c->avctx, AV_LOG_ERROR, "Premature end of data!\n");
+                    return -1;
+                }
                 for(k = 0; k < rects; k++) {
                     if(color) {
                         fg = vmnc_get_pixel(src, bpp, c->bigendian); src += bpp;
@@ -276,7 +288,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8
     VmncContext * const c = (VmncContext *)avctx->priv_data;
     uint8_t *outptr;
     uint8_t *src = buf;
-    int dx, dy, w, h, depth, enc, chunks, res;
+    int dx, dy, w, h, depth, enc, chunks, res, size_left;
 
     c->pic.reference = 1;
     c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
@@ -322,8 +334,13 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8
         h  = BE_16(src); src += 2;
         enc = BE_32(src); src += 4;
         outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0];
+        size_left = buf_size - (src - buf);
         switch(enc) {
         case MAGIC_WMVd: // cursor
+            if(size_left < 2 + w * h * c->bpp2 * 2) {
+                av_log(avctx, AV_LOG_ERROR, "Premature end of data! (need %i got %i)\n", 2 + w * h * c->bpp2 * 2, size_left);
+                return -1;
+            }
             src += 2;
             c->cur_w = w;
             c->cur_h = h;
@@ -346,6 +363,12 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8
             c->cur_x = dx - c->cur_hx;
             c->cur_y = dy - c->cur_hy;
             break;
+        case MAGIC_WMVg: // unknown
+            src += 10;
+            break;
+        case MAGIC_WMVh: // unknown
+            src += 4;
+            break;
         case MAGIC_WMVi: // ServerInitialization struct
             c->pic.key_frame = 1;
             c->pic.pict_type = FF_I_TYPE;
@@ -362,11 +385,18 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8
             //skip the rest of pixel format data
             src += 13;
             break;
+        case MAGIC_WMVj: // unknown
+            src += 2;
+            break;
         case 0x00000000: // raw rectangle data
             if((dx + w > c->width) || (dy + h > c->height)) {
                 av_log(avctx, AV_LOG_ERROR, "Incorrect frame size: %ix%i+%ix%i of %ix%i\n", w, h, dx, dy, c->width, c->height);
                 return -1;
             }
+            if(size_left < w * h * c->bpp2) {
+                av_log(avctx, AV_LOG_ERROR, "Premature end of data! (need %i got %i)\n", w * h * c->bpp2, size_left);
+                return -1;
+            }
             paint_raw(outptr, w, h, src, c->bpp2, c->bigendian, c->pic.linesize[0]);
             src += w * h * c->bpp2;
             break;
@@ -375,7 +405,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8
                 av_log(avctx, AV_LOG_ERROR, "Incorrect frame size: %ix%i+%ix%i of %ix%i\n", w, h, dx, dy, c->width, c->height);
                 return -1;
             }
-            res = decode_hextile(c, outptr, src, w, h, c->pic.linesize[0]);
+            res = decode_hextile(c, outptr, src, size_left, w, h, c->pic.linesize[0]);
             if(res < 0)
                 return -1;
             src += res;
@@ -437,7 +467,7 @@ static int decode_init(AVCodecContext *avctx)
     c->width = avctx->width;
     c->height = avctx->height;
 
-    if (avcodec_check_dimensions(avctx, avctx->height, avctx->width) < 0) {
+    if (avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) {
         return 1;
     }
     c->bpp = avctx->bits_per_sample;