]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/tiff.c
Set Electronic Arts TGV palette opaque.
[ffmpeg] / libavcodec / tiff.c
index e2c80eff829f8e7389b090866c63be96202be974..8d0bb98689d55c24ac63583b1310e88e14618602 100644 (file)
@@ -129,6 +129,16 @@ static void av_always_inline horizontal_fill(unsigned int bpp, uint8_t* dst,
     }
 }
 
+static void av_always_inline split_nibbles(uint8_t *dst, const uint8_t *src,
+                                           int width)
+{
+    while (--width >= 0) {
+        // src == dst for LZW
+        dst[width * 2 + 1] = src[width] & 0xF;
+        dst[width * 2 + 0] = src[width] >> 4;
+    }
+}
+
 static int tiff_unpack_strip(TiffContext *s, uint8_t* dst, int stride, const uint8_t *src, int size, int lines){
     int c, line, pixels, code;
     const uint8_t *ssrc = src;
@@ -148,7 +158,11 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t* dst, int stride, const uin
         }
         src = zbuf;
         for(line = 0; line < lines; line++){
-            memcpy(dst, src, width);
+            if(s->bpp == 4){
+                split_nibbles(dst, src, width);
+            }else{
+                memcpy(dst, src, width);
+            }
             dst += stride;
             src += width;
         }
@@ -199,6 +213,8 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t* dst, int stride, const uin
         }
         switch(s->compr){
         case TIFF_RAW:
+            if (ssrc + size - src < width)
+                return AVERROR_INVALIDDATA;
             if (!s->fill_order) {
                 horizontal_fill(s->bpp, dst, 1, src, 0, width, 0);
             } else {
@@ -238,6 +254,8 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t* dst, int stride, const uin
                 av_log(s->avctx, AV_LOG_ERROR, "Decoded only %i bytes of %i\n", pixels, width);
                 return -1;
             }
+            if(s->bpp == 4)
+                split_nibbles(dst, dst, width);
             break;
         }
         dst += stride;
@@ -308,6 +326,8 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start, const uint8_t *
     uint32_t *pal;
     const uint8_t *rp, *gp, *bp;
 
+    if (end_buf - buf < 12)
+        return -1;
     tag = tget_short(&buf, s->le);
     type = tget_short(&buf, s->le);
     count = tget_long(&buf, s->le);
@@ -367,7 +387,7 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start, const uint8_t *
             case TIFF_SHORT:
             case TIFF_LONG:
                 s->bpp = 0;
-                for(i = 0; i < count; i++) s->bpp += tget(&buf, type, s->le);
+                for(i = 0; i < count && buf < end_buf; i++) s->bpp += tget(&buf, type, s->le);
                 break;
             default:
                 s->bpp = -1;
@@ -481,6 +501,8 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start, const uint8_t *
     case TIFF_PAL:
         pal = (uint32_t *) s->palette;
         off = type_sizes[type];
+        if (count / 3 > 256 || end_buf - buf < count / 3 * off * 3)
+            return -1;
         rp = buf;
         gp = buf + count / 3 * off;
         bp = buf + count / 3 * off * 2;
@@ -524,12 +546,16 @@ static int decode_frame(AVCodecContext *avctx,
     AVFrame *picture = data;
     AVFrame * const p= (AVFrame*)&s->picture;
     const uint8_t *orig_buf = buf, *end_buf = buf + buf_size;
-    int id, le, off, ret;
+    unsigned off;
+    int id, le, ret;
     int i, j, entries;
-    int stride, soff, ssize;
+    int stride;
+    unsigned soff, ssize;
     uint8_t *dst;
 
     //parse image header
+    if (end_buf - buf < 8)
+        return AVERROR_INVALIDDATA;
     id = AV_RL16(buf); buf += 2;
     if(id == 0x4949) le = 1;
     else if(id == 0x4D4D) le = 0;
@@ -549,9 +575,9 @@ static int decode_frame(AVCodecContext *avctx,
     }
     /* parse image file directory */
     off = tget_long(&buf, le);
-    if(orig_buf + off + 14 >= end_buf){
+    if (off >= UINT_MAX - 14 || end_buf - orig_buf < off + 14) {
         av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n");
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
     buf = orig_buf + off;
     entries = tget_short(&buf, le);
@@ -575,23 +601,23 @@ static int decode_frame(AVCodecContext *avctx,
     stride = p->linesize[0];
     dst = p->data[0];
     for(i = 0; i < s->height; i += s->rps){
-        if(s->stripsizes)
+        if(s->stripsizes) {
+            if (s->stripsizes >= end_buf)
+                return AVERROR_INVALIDDATA;
             ssize = tget(&s->stripsizes, s->sstype, s->le);
-        else
+        else
             ssize = s->stripsize;
 
-        if (ssize > buf_size) {
-            av_log(avctx, AV_LOG_ERROR, "Buffer size is smaller than strip size\n");
-            return -1;
-        }
-
         if(s->stripdata){
+            if (s->stripdata >= end_buf)
+                return AVERROR_INVALIDDATA;
             soff = tget(&s->stripdata, s->sot, s->le);
         }else
             soff = s->stripoff;
-        if (soff < 0) {
-            av_log(avctx, AV_LOG_ERROR, "Invalid stripoff: %d\n", soff);
-            return AVERROR(EINVAL);
+
+        if (soff > buf_size || ssize > buf_size - soff) {
+            av_log(avctx, AV_LOG_ERROR, "Invalid strip size/offset\n");
+            return -1;
         }
         if(tiff_unpack_strip(s, dst, stride, orig_buf + soff, ssize, FFMIN(s->rps, s->height - i)) < 0)
             break;
@@ -601,22 +627,33 @@ static int decode_frame(AVCodecContext *avctx,
         dst = p->data[0];
         soff = s->bpp >> 3;
         ssize = s->width * soff;
-        for(i = 0; i < s->height; i++) {
-            for(j = soff; j < ssize; j++)
-                dst[j] += dst[j - soff];
-            dst += stride;
+        if (s->avctx->pix_fmt == PIX_FMT_RGB48LE) {
+            for (i = 0; i < s->height; i++) {
+                for (j = soff; j < ssize; j += 2)
+                    AV_WL16(dst + j, AV_RL16(dst + j) + AV_RL16(dst + j - soff));
+                dst += stride;
+            }
+        } else if (s->avctx->pix_fmt == PIX_FMT_RGB48BE) {
+            for (i = 0; i < s->height; i++) {
+                for (j = soff; j < ssize; j += 2)
+                    AV_WB16(dst + j, AV_RB16(dst + j) + AV_RB16(dst + j - soff));
+                dst += stride;
+            }
+        } else {
+            for(i = 0; i < s->height; i++) {
+                for(j = soff; j < ssize; j++)
+                    dst[j] += dst[j - soff];
+                dst += stride;
+            }
         }
     }
 
     if(s->invert){
-        uint8_t *src;
-        int j;
-
-        src = s->picture.data[0];
-        for(j = 0; j < s->height; j++){
-            for(i = 0; i < s->picture.linesize[0]; i++)
-                src[i] = (s->avctx->pix_fmt == PIX_FMT_PAL8 ? (1<<s->bpp) - 1 : 255) - src[i];
-            src += s->picture.linesize[0];
+        dst = s->picture.data[0];
+        for(i = 0; i < s->height; i++){
+            for(j = 0; j < s->picture.linesize[0]; j++)
+                dst[j] = (s->avctx->pix_fmt == PIX_FMT_PAL8 ? (1<<s->bpp) - 1 : 255) - dst[j];
+            dst += s->picture.linesize[0];
         }
     }
     *picture= *(AVFrame*)&s->picture;