GetFeatures: Detect invalid VP8X/VP8/VP8L data
This facilitates early error detection during decode/render. Also, related refactoring. Change-Id: Ia6c7cd91dec202a2a68dae2118f5981cf1eaa83d
This commit is contained in:
parent
5818cff770
commit
352d0dee99
@ -422,20 +422,23 @@ static WebPMuxError GetFrameFragmentInfo(
|
|||||||
return WEBP_MUX_OK;
|
return WEBP_MUX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebPMuxError MuxGetImageWidthHeight(const WebPChunk* const image_chunk,
|
WebPMuxError MuxGetImageInfo(const WebPChunk* const image_chunk,
|
||||||
int* const width, int* const height) {
|
int* const width, int* const height,
|
||||||
|
int* const has_alpha) {
|
||||||
const uint32_t tag = image_chunk->tag_;
|
const uint32_t tag = image_chunk->tag_;
|
||||||
const WebPData* const data = &image_chunk->data_;
|
const WebPData* const data = &image_chunk->data_;
|
||||||
int w, h;
|
int w, h;
|
||||||
|
int a = 0;
|
||||||
int ok;
|
int ok;
|
||||||
assert(image_chunk != NULL);
|
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) ?
|
ok = (tag == kChunks[IDX_VP8].tag) ?
|
||||||
VP8GetInfo(data->bytes, data->size, data->size, &w, &h) :
|
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) {
|
if (ok) {
|
||||||
*width = w;
|
if (width != NULL) *width = w;
|
||||||
*height = h;
|
if (height != NULL) *height = h;
|
||||||
|
if (has_alpha != NULL) *has_alpha = a;
|
||||||
return WEBP_MUX_OK;
|
return WEBP_MUX_OK;
|
||||||
} else {
|
} else {
|
||||||
return WEBP_MUX_BAD_DATA;
|
return WEBP_MUX_BAD_DATA;
|
||||||
@ -455,7 +458,7 @@ static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi,
|
|||||||
if (err != WEBP_MUX_OK) return err;
|
if (err != WEBP_MUX_OK) return err;
|
||||||
|
|
||||||
// Get width and height from VP8/VP8L chunk.
|
// Get width and height from VP8/VP8L chunk.
|
||||||
return MuxGetImageWidthHeight(image_chunk, width, height);
|
return MuxGetImageInfo(image_chunk, width, height, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WebPMuxError GetImageCanvasWidthHeight(
|
static WebPMuxError GetImageCanvasWidthHeight(
|
||||||
@ -503,7 +506,7 @@ static WebPMuxError GetImageCanvasWidthHeight(
|
|||||||
// For a single image, extract the width & height from VP8/VP8L image-data.
|
// For a single image, extract the width & height from VP8/VP8L image-data.
|
||||||
int w, h;
|
int w, h;
|
||||||
const WebPChunk* const image_chunk = wpi->img_;
|
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;
|
if (err != WEBP_MUX_OK) return err;
|
||||||
*width = w;
|
*width = w;
|
||||||
*height = h;
|
*height = h;
|
||||||
|
@ -149,9 +149,10 @@ size_t ChunksListDiskSize(const WebPChunk* chunk_list);
|
|||||||
// Write out the given list of chunks into 'dst'.
|
// Write out the given list of chunks into 'dst'.
|
||||||
uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst);
|
uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst);
|
||||||
|
|
||||||
// Get the width & height of image stored in 'image_chunk'.
|
// Get the width, height and has_alpha info of image stored in 'image_chunk'.
|
||||||
WebPMuxError MuxGetImageWidthHeight(const WebPChunk* const image_chunk,
|
WebPMuxError MuxGetImageInfo(const WebPChunk* const image_chunk,
|
||||||
int* const width, int* const height);
|
int* const width, int* const height,
|
||||||
|
int* const has_alpha);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// MuxImage object management.
|
// MuxImage object management.
|
||||||
@ -233,12 +234,6 @@ uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size);
|
|||||||
// or if 'id' is not known.
|
// or if 'id' is not known.
|
||||||
WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id);
|
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.
|
// Validates the given mux object.
|
||||||
WebPMuxError MuxValidate(const WebPMux* const mux);
|
WebPMuxError MuxValidate(const WebPMux* const mux);
|
||||||
|
|
||||||
|
@ -486,10 +486,6 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
|
|||||||
// Verify mux has at least one image.
|
// Verify mux has at least one image.
|
||||||
if (mux->images_ == NULL) return WEBP_MUX_INVALID_ARGUMENT;
|
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);
|
err = WebPMuxGetFeatures(mux, &flags);
|
||||||
if (err != WEBP_MUX_OK) return err;
|
if (err != WEBP_MUX_OK) return err;
|
||||||
|
|
||||||
|
@ -278,27 +278,34 @@ static WebPMuxError ValidateForSingleImage(const WebPMux* const mux) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WebPMuxError MuxGetCanvasSize(const WebPMux* const mux, int* width,
|
// Get the canvas width, height and flags after validating that VP8X/VP8/VP8L
|
||||||
int* height) {
|
// chunk and canvas size are valid.
|
||||||
|
static WebPMuxError MuxGetCanvasInfo(const WebPMux* const mux,
|
||||||
|
int* width, int* height, uint32_t* flags) {
|
||||||
int w, h;
|
int w, h;
|
||||||
|
uint32_t f = 0;
|
||||||
WebPData data;
|
WebPData data;
|
||||||
assert(mux != NULL);
|
assert(mux != NULL);
|
||||||
|
|
||||||
// Check if VP8X chunk is present.
|
// Check if VP8X chunk is present.
|
||||||
if (MuxGet(mux, IDX_VP8X, 1, &data) == WEBP_MUX_OK) {
|
if (MuxGet(mux, IDX_VP8X, 1, &data) == WEBP_MUX_OK) {
|
||||||
if (data.size < VP8X_CHUNK_SIZE) return WEBP_MUX_BAD_DATA;
|
if (data.size < VP8X_CHUNK_SIZE) return WEBP_MUX_BAD_DATA;
|
||||||
|
f = GetLE32(data.bytes);
|
||||||
w = GetLE24(data.bytes + 4) + 1;
|
w = GetLE24(data.bytes + 4) + 1;
|
||||||
h = GetLE24(data.bytes + 7) + 1;
|
h = GetLE24(data.bytes + 7) + 1;
|
||||||
} else { // Single image case.
|
} else { // Single image case.
|
||||||
|
int has_alpha;
|
||||||
WebPMuxError err = ValidateForSingleImage(mux);
|
WebPMuxError err = ValidateForSingleImage(mux);
|
||||||
if (err != WEBP_MUX_OK) return err;
|
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 (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 (w * (uint64_t)h >= MAX_IMAGE_AREA) return WEBP_MUX_BAD_DATA;
|
||||||
|
|
||||||
if (width) *width = w;
|
if (width != NULL) *width = w;
|
||||||
if (height) *height = h;
|
if (height != NULL) *height = h;
|
||||||
|
if (flags != NULL) *flags = f;
|
||||||
return WEBP_MUX_OK;
|
return WEBP_MUX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,36 +313,12 @@ WebPMuxError WebPMuxGetCanvasSize(const WebPMux* mux, int* width, int* height) {
|
|||||||
if (mux == NULL || width == NULL || height == NULL) {
|
if (mux == NULL || width == NULL || height == NULL) {
|
||||||
return WEBP_MUX_INVALID_ARGUMENT;
|
return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
return MuxGetCanvasSize(mux, width, height);
|
return MuxGetCanvasInfo(mux, width, height, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) {
|
WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) {
|
||||||
WebPData data;
|
|
||||||
|
|
||||||
if (mux == NULL || flags == NULL) return WEBP_MUX_INVALID_ARGUMENT;
|
if (mux == NULL || flags == NULL) return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
*flags = 0;
|
return MuxGetCanvasInfo(mux, NULL, NULL, flags);
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width,
|
static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width,
|
||||||
@ -374,7 +357,7 @@ static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi,
|
|||||||
int w, h;
|
int w, h;
|
||||||
WebPMuxError err;
|
WebPMuxError err;
|
||||||
assert(wpi->img_ != NULL);
|
assert(wpi->img_ != NULL);
|
||||||
err = MuxGetImageWidthHeight(wpi->img_, &w, &h);
|
err = MuxGetImageInfo(wpi->img_, &w, &h, NULL);
|
||||||
if (err != WEBP_MUX_OK) {
|
if (err != WEBP_MUX_OK) {
|
||||||
free(data);
|
free(data);
|
||||||
return err;
|
return err;
|
||||||
|
@ -329,7 +329,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetCanvasSize(const WebPMux* mux,
|
|||||||
// Enum 'WebPFeatureFlags' can be used to test individual flag values.
|
// Enum 'WebPFeatureFlags' can be used to test individual flag values.
|
||||||
// Returns:
|
// Returns:
|
||||||
// WEBP_MUX_INVALID_ARGUMENT - if mux or flags is NULL.
|
// 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_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxGetFeatures(const WebPMux* mux,
|
WEBP_EXTERN(WebPMuxError) WebPMuxGetFeatures(const WebPMux* mux,
|
||||||
uint32_t* flags);
|
uint32_t* flags);
|
||||||
|
Loading…
Reference in New Issue
Block a user