diff --git a/libavcodec/rpza.c b/libavcodec/rpza.c index 5faf562f8a..315ad23de4 100644 --- a/libavcodec/rpza.c +++ b/libavcodec/rpza.c @@ -52,23 +52,25 @@ typedef struct RpzaContext { GetByteContext gb; } RpzaContext; -#define ADVANCE_BLOCK() \ -{ \ - pixel_ptr += 4; \ - if (pixel_ptr >= width) \ - { \ - pixel_ptr = 0; \ - row_ptr += stride * 4; \ - } \ - total_blocks--; \ - if (total_blocks < 0) \ - { \ - av_log(s->avctx, AV_LOG_ERROR, "warning: block counter just went negative (this should not happen)\n"); \ - return; \ - } \ -} +#define CHECK_BLOCK() \ + if (total_blocks < 1) { \ + av_log(s->avctx, AV_LOG_ERROR, \ + "Block counter just went negative (this should not happen)\n"); \ + return AVERROR_INVALIDDATA; \ + } \ -static void rpza_decode_stream(RpzaContext *s) +#define ADVANCE_BLOCK() \ + { \ + pixel_ptr += 4; \ + if (pixel_ptr >= width) \ + { \ + pixel_ptr = 0; \ + row_ptr += stride * 4; \ + } \ + total_blocks--; \ + } + +static int rpza_decode_stream(RpzaContext *s) { int width = s->avctx->width; int stride = s->frame->linesize[0] / 2; @@ -80,7 +82,7 @@ static void rpza_decode_stream(RpzaContext *s) uint16_t *pixels = (uint16_t *)s->frame->data[0]; int row_ptr = 0; - int pixel_ptr = -4; + int pixel_ptr = 0; int block_ptr; int pixel_x, pixel_y; int total_blocks; @@ -130,7 +132,8 @@ static void rpza_decode_stream(RpzaContext *s) /* Skip blocks */ case 0x80: while (n_blocks--) { - ADVANCE_BLOCK(); + CHECK_BLOCK(); + ADVANCE_BLOCK(); } break; @@ -138,7 +141,7 @@ static void rpza_decode_stream(RpzaContext *s) case 0xa0: colorA = bytestream2_get_be16(&s->gb); while (n_blocks--) { - ADVANCE_BLOCK() + CHECK_BLOCK(); block_ptr = row_ptr + pixel_ptr; for (pixel_y = 0; pixel_y < 4; pixel_y++) { for (pixel_x = 0; pixel_x < 4; pixel_x++){ @@ -147,6 +150,7 @@ static void rpza_decode_stream(RpzaContext *s) } block_ptr += row_inc; } + ADVANCE_BLOCK(); } break; @@ -181,9 +185,9 @@ static void rpza_decode_stream(RpzaContext *s) color4[2] |= ((21 * ta + 11 * tb) >> 5); if (bytestream2_get_bytes_left(&s->gb) < n_blocks * 4) - return; + return AVERROR_INVALIDDATA; while (n_blocks--) { - ADVANCE_BLOCK(); + CHECK_BLOCK(); block_ptr = row_ptr + pixel_ptr; for (pixel_y = 0; pixel_y < 4; pixel_y++) { uint8_t index = bytestream2_get_byteu(&s->gb); @@ -194,14 +198,15 @@ static void rpza_decode_stream(RpzaContext *s) } block_ptr += row_inc; } + ADVANCE_BLOCK(); } break; /* Fill block with 16 colors */ case 0x00: if (bytestream2_get_bytes_left(&s->gb) < 30) - return; - ADVANCE_BLOCK(); + return AVERROR_INVALIDDATA; + CHECK_BLOCK(); block_ptr = row_ptr + pixel_ptr; for (pixel_y = 0; pixel_y < 4; pixel_y++) { for (pixel_x = 0; pixel_x < 4; pixel_x++){ @@ -213,6 +218,7 @@ static void rpza_decode_stream(RpzaContext *s) } block_ptr += row_inc; } + ADVANCE_BLOCK(); break; /* Unknown opcode */ @@ -220,9 +226,11 @@ static void rpza_decode_stream(RpzaContext *s) av_log(s->avctx, AV_LOG_ERROR, "Unknown opcode %d in rpza chunk." " Skip remaining %d bytes of chunk data.\n", opcode, bytestream2_get_bytes_left(&s->gb)); - return; + return AVERROR_INVALIDDATA; } /* Opcode switch */ } + + return 0; } static av_cold int rpza_decode_init(AVCodecContext *avctx) @@ -251,7 +259,9 @@ static int rpza_decode_frame(AVCodecContext *avctx, if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) return ret; - rpza_decode_stream(s); + ret = rpza_decode_stream(s); + if (ret < 0) + return ret; if ((ret = av_frame_ref(data, s->frame)) < 0) return ret;