lavc/libaribb24: protect handled value with parenthesis in RGB_TO_BGR
[ffmpeg.git] / libavcodec / movtextdec.c
index 923e582..c38c5ed 100644 (file)
@@ -116,6 +116,8 @@ static void mov_text_cleanup(MovTextContext *m)
             av_freep(&m->s[i]);
         }
         av_freep(&m->s);
+        m->count_s = 0;
+        m->style_entries = 0;
     }
 }
 
@@ -279,12 +281,14 @@ static int decode_hclr(const uint8_t *tsmb, MovTextContext *m, AVPacket *avpkt)
 static int decode_styl(const uint8_t *tsmb, MovTextContext *m, AVPacket *avpkt)
 {
     int i;
-    m->style_entries = AV_RB16(tsmb);
+    int style_entries = AV_RB16(tsmb);
     tsmb += 2;
     // A single style record is of length 12 bytes.
-    if (m->tracksize + m->size_var + 2 + m->style_entries * 12 > avpkt->size)
+    if (m->tracksize + m->size_var + 2 + style_entries * 12 > avpkt->size)
         return -1;
 
+    m->style_entries = style_entries;
+
     m->box_flags |= STYL_BOX;
     for(i = 0; i < m->style_entries; i++) {
         m->s_temp = av_malloc(sizeof(*m->s_temp));
@@ -295,6 +299,14 @@ static int decode_styl(const uint8_t *tsmb, MovTextContext *m, AVPacket *avpkt)
         m->s_temp->style_start = AV_RB16(tsmb);
         tsmb += 2;
         m->s_temp->style_end = AV_RB16(tsmb);
+
+        if (   m->s_temp->style_end < m->s_temp->style_start
+            || (m->count_s && m->s_temp->style_start < m->s[m->count_s - 1]->style_end)) {
+            av_freep(&m->s_temp);
+            mov_text_cleanup(m);
+            return AVERROR(ENOMEM);
+        }
+
         tsmb += 2;
         m->s_temp->style_fontID = AV_RB16(tsmb);
         tsmb += 2;
@@ -322,9 +334,24 @@ static const Box box_types[] = {
 
 const static size_t box_count = FF_ARRAY_ELEMS(box_types);
 
+// Return byte length of the UTF-8 sequence starting at text[0]. 0 on error.
+static int get_utf8_length_at(const char *text, const char *text_end)
+{
+    const char *start = text;
+    int err = 0;
+    uint32_t c;
+    GET_UTF8(c, text < text_end ? (uint8_t)*text++ : (err = 1, 0), goto error;);
+    if (err)
+        goto error;
+    return text - start;
+error:
+    return 0;
+}
+
 static int text_to_ass(AVBPrint *buf, const char *text, const char *text_end,
-                        MovTextContext *m)
+                       AVCodecContext *avctx)
 {
+    MovTextContext *m = avctx->priv_data;
     int i = 0;
     int j = 0;
     int text_pos = 0;
@@ -338,6 +365,8 @@ static int text_to_ass(AVBPrint *buf, const char *text, const char *text_end,
     }
 
     while (text < text_end) {
+        int len;
+
         if (m->box_flags & STYL_BOX) {
             for (i = 0; i < m->style_entries; i++) {
                 if (m->s[i]->style_flag && text_pos == m->s[i]->style_end) {
@@ -384,17 +413,24 @@ static int text_to_ass(AVBPrint *buf, const char *text, const char *text_end,
             }
         }
 
-        switch (*text) {
-        case '\r':
-            break;
-        case '\n':
-            av_bprintf(buf, "\\N");
-            break;
-        default:
-            av_bprint_chars(buf, *text, 1);
-            break;
+        len = get_utf8_length_at(text, text_end);
+        if (len < 1) {
+            av_log(avctx, AV_LOG_ERROR, "invalid UTF-8 byte in subtitle\n");
+            len = 1;
+        }
+        for (i = 0; i < len; i++) {
+            switch (*text) {
+            case '\r':
+                break;
+            case '\n':
+                av_bprintf(buf, "\\N");
+                break;
+            default:
+                av_bprint_chars(buf, *text, 1);
+                break;
+            }
+            text++;
         }
-        text++;
         text_pos++;
     }
 
@@ -432,6 +468,7 @@ static int mov_text_decode_frame(AVCodecContext *avctx,
     int text_length, tsmb_type, ret_tsmb;
     uint64_t tsmb_size;
     const uint8_t *tsmb;
+    size_t i;
 
     if (!ptr || avpkt->size < 2)
         return AVERROR_INVALIDDATA;
@@ -455,6 +492,8 @@ static int mov_text_decode_frame(AVCodecContext *avctx,
     end = ptr + FFMIN(2 + text_length, avpkt->size);
     ptr += 2;
 
+    mov_text_cleanup(m);
+
     tsmb_size = 0;
     m->tracksize = 2 + text_length;
     m->style_entries = 0;
@@ -471,10 +510,6 @@ static int mov_text_decode_frame(AVCodecContext *avctx,
             tsmb_type = AV_RB32(tsmb);
             tsmb += 4;
 
-            if (tsmb_size == 0) {
-              return AVERROR_INVALIDDATA;
-            }
-
             if (tsmb_size == 1) {
                 if (m->tracksize + 16 > avpkt->size)
                     break;
@@ -485,10 +520,15 @@ static int mov_text_decode_frame(AVCodecContext *avctx,
                 m->size_var = 8;
             //size_var is equal to 8 or 16 depending on the size of box
 
+            if (tsmb_size == 0) {
+                av_log(avctx, AV_LOG_ERROR, "tsmb_size is 0\n");
+                return AVERROR_INVALIDDATA;
+            }
+
             if (tsmb_size > avpkt->size - m->tracksize)
                 break;
 
-            for (size_t i = 0; i < box_count; i++) {
+            for (i = 0; i < box_count; i++) {
                 if (tsmb_type == box_types[i].type) {
                     if (m->tracksize + m->size_var + box_types[i].base_size > avpkt->size)
                         break;
@@ -499,10 +539,10 @@ static int mov_text_decode_frame(AVCodecContext *avctx,
             }
             m->tracksize = m->tracksize + tsmb_size;
         }
-        text_to_ass(&buf, ptr, end, m);
+        text_to_ass(&buf, ptr, end, avctx);
         mov_text_cleanup(m);
     } else
-        text_to_ass(&buf, ptr, end, m);
+        text_to_ass(&buf, ptr, end, avctx);
 
     ret = ff_ass_add_rect(sub, buf.str, m->readorder++, 0, NULL, NULL);
     av_bprint_finalize(&buf, NULL);
@@ -516,6 +556,7 @@ static int mov_text_decode_close(AVCodecContext *avctx)
 {
     MovTextContext *m = avctx->priv_data;
     mov_text_cleanup_ftab(m);
+    mov_text_cleanup(m);
     return 0;
 }