summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/libwebp/src/demux/anim_decode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/libwebp/src/demux/anim_decode.c')
-rw-r--r--src/3rdparty/libwebp/src/demux/anim_decode.c63
1 files changed, 41 insertions, 22 deletions
diff --git a/src/3rdparty/libwebp/src/demux/anim_decode.c b/src/3rdparty/libwebp/src/demux/anim_decode.c
index 05dd707..e077ffb 100644
--- a/src/3rdparty/libwebp/src/demux/anim_decode.c
+++ b/src/3rdparty/libwebp/src/demux/anim_decode.c
@@ -23,6 +23,14 @@
#define NUM_CHANNELS 4
+// Channel extraction from a uint32_t representation of a uint8_t RGBA/BGRA
+// buffer.
+#ifdef WORDS_BIGENDIAN
+#define CHANNEL_SHIFT(i) (24 - (i) * 8)
+#else
+#define CHANNEL_SHIFT(i) ((i) * 8)
+#endif
+
typedef void (*BlendRowFunc)(uint32_t* const, const uint32_t* const, int);
static void BlendPixelRowNonPremult(uint32_t* const src,
const uint32_t* const dst, int num_pixels);
@@ -87,11 +95,19 @@ WebPAnimDecoder* WebPAnimDecoderNewInternal(
int abi_version) {
WebPAnimDecoderOptions options;
WebPAnimDecoder* dec = NULL;
+ WebPBitstreamFeatures features;
if (webp_data == NULL ||
WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_DEMUX_ABI_VERSION)) {
return NULL;
}
+ // Validate the bitstream before doing expensive allocations. The demuxer may
+ // be more tolerant than the decoder.
+ if (WebPGetFeatures(webp_data->bytes, webp_data->size, &features) !=
+ VP8_STATUS_OK) {
+ return NULL;
+ }
+
// Note: calloc() so that the pointer members are initialized to NULL.
dec = (WebPAnimDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
if (dec == NULL) goto Error;
@@ -145,7 +161,7 @@ static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
uint32_t canvas_height) {
const uint64_t size =
(uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf);
- if (size != (size_t)size) return 0;
+ if (!CheckSizeOverflow(size)) return 0;
memset(buf, 0, (size_t)size);
return 1;
}
@@ -166,7 +182,7 @@ static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset,
static int CopyCanvas(const uint8_t* src, uint8_t* dst,
uint32_t width, uint32_t height) {
const uint64_t size = (uint64_t)width * height * NUM_CHANNELS;
- if (size != (size_t)size) return 0;
+ if (!CheckSizeOverflow(size)) return 0;
assert(src != NULL && dst != NULL);
memcpy(dst, src, (size_t)size);
return 1;
@@ -201,35 +217,35 @@ static uint8_t BlendChannelNonPremult(uint32_t src, uint8_t src_a,
const uint8_t dst_channel = (dst >> shift) & 0xff;
const uint32_t blend_unscaled = src_channel * src_a + dst_channel * dst_a;
assert(blend_unscaled < (1ULL << 32) / scale);
- return (blend_unscaled * scale) >> 24;
+ return (blend_unscaled * scale) >> CHANNEL_SHIFT(3);
}
// Blend 'src' over 'dst' assuming they are NOT pre-multiplied by alpha.
static uint32_t BlendPixelNonPremult(uint32_t src, uint32_t dst) {
- const uint8_t src_a = (src >> 24) & 0xff;
+ const uint8_t src_a = (src >> CHANNEL_SHIFT(3)) & 0xff;
if (src_a == 0) {
return dst;
} else {
- const uint8_t dst_a = (dst >> 24) & 0xff;
+ const uint8_t dst_a = (dst >> CHANNEL_SHIFT(3)) & 0xff;
// This is the approximate integer arithmetic for the actual formula:
// dst_factor_a = (dst_a * (255 - src_a)) / 255.
const uint8_t dst_factor_a = (dst_a * (256 - src_a)) >> 8;
const uint8_t blend_a = src_a + dst_factor_a;
const uint32_t scale = (1UL << 24) / blend_a;
- const uint8_t blend_r =
- BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 0);
- const uint8_t blend_g =
- BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 8);
- const uint8_t blend_b =
- BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 16);
+ const uint8_t blend_r = BlendChannelNonPremult(
+ src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(0));
+ const uint8_t blend_g = BlendChannelNonPremult(
+ src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(1));
+ const uint8_t blend_b = BlendChannelNonPremult(
+ src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(2));
assert(src_a + dst_factor_a < 256);
- return (blend_r << 0) |
- (blend_g << 8) |
- (blend_b << 16) |
- ((uint32_t)blend_a << 24);
+ return ((uint32_t)blend_r << CHANNEL_SHIFT(0)) |
+ ((uint32_t)blend_g << CHANNEL_SHIFT(1)) |
+ ((uint32_t)blend_b << CHANNEL_SHIFT(2)) |
+ ((uint32_t)blend_a << CHANNEL_SHIFT(3));
}
}
@@ -239,7 +255,7 @@ static void BlendPixelRowNonPremult(uint32_t* const src,
const uint32_t* const dst, int num_pixels) {
int i;
for (i = 0; i < num_pixels; ++i) {
- const uint8_t src_alpha = (src[i] >> 24) & 0xff;
+ const uint8_t src_alpha = (src[i] >> CHANNEL_SHIFT(3)) & 0xff;
if (src_alpha != 0xff) {
src[i] = BlendPixelNonPremult(src[i], dst[i]);
}
@@ -256,7 +272,7 @@ static WEBP_INLINE uint32_t ChannelwiseMultiply(uint32_t pix, uint32_t scale) {
// Blend 'src' over 'dst' assuming they are pre-multiplied by alpha.
static uint32_t BlendPixelPremult(uint32_t src, uint32_t dst) {
- const uint8_t src_a = (src >> 24) & 0xff;
+ const uint8_t src_a = (src >> CHANNEL_SHIFT(3)) & 0xff;
return src + ChannelwiseMultiply(dst, 256 - src_a);
}
@@ -266,7 +282,7 @@ static void BlendPixelRowPremult(uint32_t* const src, const uint32_t* const dst,
int num_pixels) {
int i;
for (i = 0; i < num_pixels; ++i) {
- const uint8_t src_alpha = (src[i] >> 24) & 0xff;
+ const uint8_t src_alpha = (src[i] >> CHANNEL_SHIFT(3)) & 0xff;
if (src_alpha != 0xff) {
src[i] = BlendPixelPremult(src[i], dst[i]);
}
@@ -346,12 +362,15 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
{
const uint8_t* in = iter.fragment.bytes;
const size_t in_size = iter.fragment.size;
- const size_t out_offset =
- (iter.y_offset * width + iter.x_offset) * NUM_CHANNELS;
+ const uint32_t stride = width * NUM_CHANNELS; // at most 25 + 2 bits
+ const uint64_t out_offset = (uint64_t)iter.y_offset * stride +
+ (uint64_t)iter.x_offset * NUM_CHANNELS; // 53b
+ const uint64_t size = (uint64_t)iter.height * stride; // at most 25 + 27b
WebPDecoderConfig* const config = &dec->config_;
WebPRGBABuffer* const buf = &config->output.u.RGBA;
- buf->stride = NUM_CHANNELS * width;
- buf->size = buf->stride * iter.height;
+ if ((size_t)size != size) goto Error;
+ buf->stride = (int)stride;
+ buf->size = (size_t)size;
buf->rgba = dec->curr_frame_ + out_offset;
if (WebPDecode(in, in_size, config) != VP8_STATUS_OK) {