diff --git a/src/dec/buffer_dec.c b/src/dec/buffer_dec.c index 11ce76f1..a61ed63c 100644 --- a/src/dec/buffer_dec.c +++ b/src/dec/buffer_dec.c @@ -26,10 +26,9 @@ static const uint8_t kModeBpp[MODE_LAST] = { 4, 4, 4, 2, // pre-multiplied modes 1, 1 }; -// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE. // Convert to an integer to handle both the unsigned/signed enum cases // without the need for casting to remove type limit warnings. -static int IsValidColorspace(int webp_csp_mode) { +int IsValidColorspace(int webp_csp_mode) { return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST); } diff --git a/src/dec/common_dec.h b/src/dec/common_dec.h index b158550a..4a581cb3 100644 --- a/src/dec/common_dec.h +++ b/src/dec/common_dec.h @@ -51,4 +51,7 @@ enum { MB_FEATURE_TREE_PROBS = 3, NUM_PROBAS = 11 }; +// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE. +int IsValidColorspace(int webp_csp_mode); + #endif // WEBP_DEC_COMMON_DEC_H_ diff --git a/src/dec/webp_dec.c b/src/dec/webp_dec.c index 49ef205c..ab5c360b 100644 --- a/src/dec/webp_dec.c +++ b/src/dec/webp_dec.c @@ -13,13 +13,15 @@ #include +#include "src/dec/common_dec.h" #include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" #include "src/dec/vp8li_dec.h" #include "src/dec/webpi_dec.h" +#include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" -#include "src/webp/mux_types.h" // ALPHA_FLAG #include "src/webp/decode.h" +#include "src/webp/mux_types.h" // ALPHA_FLAG #include "src/webp/types.h" //------------------------------------------------------------------------------ @@ -747,6 +749,61 @@ int WebPInitDecoderConfigInternal(WebPDecoderConfig* config, return 1; } +static int WebPCheckCropDimensionsBasic(int x, int y, int w, int h) { + return !(x < 0 || y < 0 || w <= 0 || h <= 0); +} + +int WebPValidateDecoderConfig(const WebPDecoderConfig* config) { + const WebPDecoderOptions* options; + if (config == NULL) return 0; + if (!IsValidColorspace(config->output.colorspace)) { + return 0; + } + + options = &config->options; + // bypass_filtering, no_fancy_upsampling, use_cropping, use_scaling, + // use_threads, flip can be any integer and are interpreted as boolean. + + // Check for cropping. + if (options->use_cropping && !WebPCheckCropDimensionsBasic( + options->crop_left, options->crop_top, + options->crop_width, options->crop_height)) { + return 0; + } + // Check for scaling. + if (options->use_scaling && + (options->scaled_width < 0 || options->scaled_height < 0 || + (options->scaled_width == 0 && options->scaled_height == 0))) { + return 0; + } + + // In case the WebPBitstreamFeatures has been filled in, check further. + if (config->input.width > 0 || config->input.height > 0) { + int scaled_width = options->scaled_width; + int scaled_height = options->scaled_height; + if (options->use_cropping && + !WebPCheckCropDimensions(config->input.width, config->input.height, + options->crop_left, options->crop_top, + options->crop_width, options->crop_height)) { + return 0; + } + if (options->use_scaling && !WebPRescalerGetScaledDimensions( + config->input.width, config->input.height, + &scaled_width, &scaled_height)) { + return 0; + } + } + + // Check for dithering. + if (options->dithering_strength < 0 || options->dithering_strength > 100 || + options->alpha_dithering_strength < 0 || + options->alpha_dithering_strength > 100) { + return 0; + } + + return 1; +} + VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size, WebPBitstreamFeatures* features, int version) { @@ -806,8 +863,8 @@ VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size, int WebPCheckCropDimensions(int image_width, int image_height, int x, int y, int w, int h) { - return !(x < 0 || y < 0 || w <= 0 || h <= 0 || - x >= image_width || w > image_width || w > image_width - x || + return WebPCheckCropDimensionsBasic(x, y, w, h) && + !(x >= image_width || w > image_width || w > image_width - x || y >= image_height || h > image_height || h > image_height - y); } diff --git a/src/webp/decode.h b/src/webp/decode.h index d6895f5c..b95cd10b 100644 --- a/src/webp/decode.h +++ b/src/webp/decode.h @@ -20,7 +20,7 @@ extern "C" { #endif -#define WEBP_DECODER_ABI_VERSION 0x0209 // MAJOR(8b) + MINOR(8b) +#define WEBP_DECODER_ABI_VERSION 0x0210 // MAJOR(8b) + MINOR(8b) // Note: forward declaring enumerations is not allowed in (strict) C and C++, // the types are left here for reference. @@ -451,7 +451,9 @@ struct WebPDecoderOptions { // Will be snapped to even values. int crop_width, crop_height; // dimension of the cropping area int use_scaling; // if true, scaling is applied _afterward_ - int scaled_width, scaled_height; // final resolution + int scaled_width, scaled_height; // final resolution. if one is 0, it is + // guessed from the other one to keep the + // original ratio. int use_threads; // if true, use multi-threaded decoding int dithering_strength; // dithering strength (0=Off, 100=full) int flip; // if true, flip output vertically @@ -479,6 +481,11 @@ WEBP_NODISCARD static WEBP_INLINE int WebPInitDecoderConfig( return WebPInitDecoderConfigInternal(config, WEBP_DECODER_ABI_VERSION); } +// Returns true if 'config' is non-NULL and all configuration parameters are +// within their valid ranges. +WEBP_NODISCARD WEBP_EXTERN int WebPValidateDecoderConfig( + const WebPDecoderConfig* config); + // Instantiate a new incremental decoder object with the requested // configuration. The bitstream can be passed using 'data' and 'data_size' // parameter, in which case the features will be parsed and stored into