From 352d0dee997c8a47b1ee923394ac250580953681 Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Fri, 10 May 2013 14:25:00 -0700 Subject: [PATCH] GetFeatures: Detect invalid VP8X/VP8/VP8L data This facilitates early error detection during decode/render. Also, related refactoring. Change-Id: Ia6c7cd91dec202a2a68dae2118f5981cf1eaa83d --- src/mux/muxedit.c | 19 +++++++++-------- src/mux/muxi.h | 13 ++++-------- src/mux/muxinternal.c | 4 ---- src/mux/muxread.c | 47 ++++++++++++++----------------------------- src/webp/mux.h | 2 +- 5 files changed, 31 insertions(+), 54 deletions(-) diff --git a/src/mux/muxedit.c b/src/mux/muxedit.c index a486229c..32ce3d7b 100644 --- a/src/mux/muxedit.c +++ b/src/mux/muxedit.c @@ -422,20 +422,23 @@ static WebPMuxError GetFrameFragmentInfo( return WEBP_MUX_OK; } -WebPMuxError MuxGetImageWidthHeight(const WebPChunk* const image_chunk, - int* const width, int* const height) { +WebPMuxError MuxGetImageInfo(const WebPChunk* const image_chunk, + int* const width, int* const height, + int* const has_alpha) { const uint32_t tag = image_chunk->tag_; const WebPData* const data = &image_chunk->data_; int w, h; + int a = 0; int ok; assert(image_chunk != NULL); - assert(tag == kChunks[IDX_VP8].tag || tag == kChunks[IDX_VP8L].tag); + assert(tag == kChunks[IDX_VP8].tag || tag == kChunks[IDX_VP8L].tag); ok = (tag == kChunks[IDX_VP8].tag) ? VP8GetInfo(data->bytes, data->size, data->size, &w, &h) : - VP8LGetInfo(data->bytes, data->size, &w, &h, NULL); + VP8LGetInfo(data->bytes, data->size, &w, &h, &a); if (ok) { - *width = w; - *height = h; + if (width != NULL) *width = w; + if (height != NULL) *height = h; + if (has_alpha != NULL) *has_alpha = a; return WEBP_MUX_OK; } else { return WEBP_MUX_BAD_DATA; @@ -455,7 +458,7 @@ static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi, if (err != WEBP_MUX_OK) return err; // Get width and height from VP8/VP8L chunk. - return MuxGetImageWidthHeight(image_chunk, width, height); + return MuxGetImageInfo(image_chunk, width, height, NULL); } static WebPMuxError GetImageCanvasWidthHeight( @@ -503,7 +506,7 @@ static WebPMuxError GetImageCanvasWidthHeight( // For a single image, extract the width & height from VP8/VP8L image-data. int w, h; const WebPChunk* const image_chunk = wpi->img_; - const WebPMuxError err = MuxGetImageWidthHeight(image_chunk, &w, &h); + const WebPMuxError err = MuxGetImageInfo(image_chunk, &w, &h, NULL); if (err != WEBP_MUX_OK) return err; *width = w; *height = h; diff --git a/src/mux/muxi.h b/src/mux/muxi.h index 23f6be53..0aa89707 100644 --- a/src/mux/muxi.h +++ b/src/mux/muxi.h @@ -149,9 +149,10 @@ size_t ChunksListDiskSize(const WebPChunk* chunk_list); // Write out the given list of chunks into 'dst'. uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst); -// Get the width & height of image stored in 'image_chunk'. -WebPMuxError MuxGetImageWidthHeight(const WebPChunk* const image_chunk, - int* const width, int* const height); +// Get the width, height and has_alpha info of image stored in 'image_chunk'. +WebPMuxError MuxGetImageInfo(const WebPChunk* const image_chunk, + int* const width, int* const height, + int* const has_alpha); //------------------------------------------------------------------------------ // MuxImage object management. @@ -233,12 +234,6 @@ uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size); // or if 'id' is not known. WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id); -// Get the canvas width and height after validating that VP8X/VP8/VP8L chunk and -// canvas size are valid. This method can be used for validation-only purposes -// by passing 'width' and 'height' to be NULL. -WebPMuxError MuxGetCanvasSize(const WebPMux* const mux, int* width, - int* height); - // Validates the given mux object. WebPMuxError MuxValidate(const WebPMux* const mux); diff --git a/src/mux/muxinternal.c b/src/mux/muxinternal.c index 786357bf..2428c597 100644 --- a/src/mux/muxinternal.c +++ b/src/mux/muxinternal.c @@ -486,10 +486,6 @@ WebPMuxError MuxValidate(const WebPMux* const mux) { // Verify mux has at least one image. if (mux->images_ == NULL) return WEBP_MUX_INVALID_ARGUMENT; - // Validate that VP8X/VP8/VP8L chunk and canvas size are valid. - err = MuxGetCanvasSize(mux, NULL, NULL); - if (err != WEBP_MUX_OK) return err; - err = WebPMuxGetFeatures(mux, &flags); if (err != WEBP_MUX_OK) return err; diff --git a/src/mux/muxread.c b/src/mux/muxread.c index 69cf0f18..a7ce016e 100644 --- a/src/mux/muxread.c +++ b/src/mux/muxread.c @@ -278,27 +278,34 @@ static WebPMuxError ValidateForSingleImage(const WebPMux* const mux) { } } -WebPMuxError MuxGetCanvasSize(const WebPMux* const mux, int* width, - int* height) { +// Get the canvas width, height and flags after validating that VP8X/VP8/VP8L +// chunk and canvas size are valid. +static WebPMuxError MuxGetCanvasInfo(const WebPMux* const mux, + int* width, int* height, uint32_t* flags) { int w, h; + uint32_t f = 0; WebPData data; assert(mux != NULL); // Check if VP8X chunk is present. if (MuxGet(mux, IDX_VP8X, 1, &data) == WEBP_MUX_OK) { if (data.size < VP8X_CHUNK_SIZE) return WEBP_MUX_BAD_DATA; + f = GetLE32(data.bytes); w = GetLE24(data.bytes + 4) + 1; h = GetLE24(data.bytes + 7) + 1; } else { // Single image case. + int has_alpha; WebPMuxError err = ValidateForSingleImage(mux); if (err != WEBP_MUX_OK) return err; - err = MuxGetImageWidthHeight(mux->images_->img_, &w, &h); + err = MuxGetImageInfo(mux->images_->img_, &w, &h, &has_alpha); if (err != WEBP_MUX_OK) return err; + if (has_alpha) f |= ALPHA_FLAG; } if (w * (uint64_t)h >= MAX_IMAGE_AREA) return WEBP_MUX_BAD_DATA; - if (width) *width = w; - if (height) *height = h; + if (width != NULL) *width = w; + if (height != NULL) *height = h; + if (flags != NULL) *flags = f; return WEBP_MUX_OK; } @@ -306,36 +313,12 @@ WebPMuxError WebPMuxGetCanvasSize(const WebPMux* mux, int* width, int* height) { if (mux == NULL || width == NULL || height == NULL) { return WEBP_MUX_INVALID_ARGUMENT; } - return MuxGetCanvasSize(mux, width, height); + return MuxGetCanvasInfo(mux, width, height, NULL); } WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) { - WebPData data; - if (mux == NULL || flags == NULL) return WEBP_MUX_INVALID_ARGUMENT; - *flags = 0; - - // Check if VP8X chunk is present. - if (MuxGet(mux, IDX_VP8X, 1, &data) == WEBP_MUX_OK) { - if (data.size < CHUNK_SIZE_BYTES) return WEBP_MUX_BAD_DATA; - *flags = GetLE32(data.bytes); // All OK. Fill up flags. - } else { - WebPMuxError err = ValidateForSingleImage(mux); // Check for single image. - if (err != WEBP_MUX_OK) return err; - if (MuxHasLosslessImages(mux->images_)) { - const WebPData* const vp8l_data = &mux->images_->img_->data_; - int has_alpha = 0; - if (!VP8LGetInfo(vp8l_data->bytes, vp8l_data->size, NULL, NULL, - &has_alpha)) { - return WEBP_MUX_BAD_DATA; - } - if (has_alpha) { - *flags = ALPHA_FLAG; - } - } - } - - return WEBP_MUX_OK; + return MuxGetCanvasInfo(mux, NULL, NULL, flags); } static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width, @@ -374,7 +357,7 @@ static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi, int w, h; WebPMuxError err; assert(wpi->img_ != NULL); - err = MuxGetImageWidthHeight(wpi->img_, &w, &h); + err = MuxGetImageInfo(wpi->img_, &w, &h, NULL); if (err != WEBP_MUX_OK) { free(data); return err; diff --git a/src/webp/mux.h b/src/webp/mux.h index d1bcc11f..22be90f2 100644 --- a/src/webp/mux.h +++ b/src/webp/mux.h @@ -329,7 +329,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetCanvasSize(const WebPMux* mux, // Enum 'WebPFeatureFlags' can be used to test individual flag values. // Returns: // WEBP_MUX_INVALID_ARGUMENT - if mux or flags is NULL. -// WEBP_MUX_BAD_DATA - if VP8X/VP8L chunk in mux is invalid. +// WEBP_MUX_BAD_DATA - if VP8X/VP8/VP8L chunk or canvas size is invalid. // WEBP_MUX_OK - on success. WEBP_EXTERN(WebPMuxError) WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags);