examples: warn on invalid numeric parameters

add ExUtilGet[U]Int / ExUtilGetFloat which print an error message on
parse failure.
fixes issue #219.

(cherry picked from commit 96d43a873a)

Conflicts:
	examples/cwebp.c
	examples/dwebp.c

Change-Id: Ie537f5aebd138925bf1a48289b6b5e261b3af2ca
This commit is contained in:
James Zern 2014-09-10 23:35:48 -07:00
parent b7d209a448
commit 40b3a618ec
7 changed files with 113 additions and 40 deletions

View File

@ -710,6 +710,7 @@ int main(int argc, const char *argv[]) {
} }
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
HelpShort(); HelpShort();
return 0; return 0;
@ -733,30 +734,31 @@ int main(int argc, const char *argv[]) {
} else if (!strcmp(argv[c], "-short")) { } else if (!strcmp(argv[c], "-short")) {
++short_output; ++short_output;
} else if (!strcmp(argv[c], "-s") && c < argc - 2) { } else if (!strcmp(argv[c], "-s") && c < argc - 2) {
picture.width = strtol(argv[++c], NULL, 0); picture.width = ExUtilGetInt(argv[++c], 0, &parse_error);
picture.height = strtol(argv[++c], NULL, 0); picture.height = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-m") && c < argc - 1) { } else if (!strcmp(argv[c], "-m") && c < argc - 1) {
config.method = strtol(argv[++c], NULL, 0); config.method = ExUtilGetInt(argv[++c], 0, &parse_error);
#if WEBP_ENCODER_ABI_VERSION > 0x0202 #if WEBP_ENCODER_ABI_VERSION > 0x0202
use_lossless_preset = 0; // disable -z option use_lossless_preset = 0; // disable -z option
#endif #endif
} else if (!strcmp(argv[c], "-q") && c < argc - 1) { } else if (!strcmp(argv[c], "-q") && c < argc - 1) {
config.quality = (float)strtod(argv[++c], NULL); config.quality = ExUtilGetFloat(argv[++c], &parse_error);
#if WEBP_ENCODER_ABI_VERSION > 0x0202 #if WEBP_ENCODER_ABI_VERSION > 0x0202
use_lossless_preset = 0; // disable -z option use_lossless_preset = 0; // disable -z option
} else if (!strcmp(argv[c], "-z") && c < argc - 1) { } else if (!strcmp(argv[c], "-z") && c < argc - 1) {
lossless_preset = strtol(argv[++c], NULL, 0); lossless_preset = ExUtilGetInt(argv[++c], 0, &parse_error);
if (use_lossless_preset != 0) use_lossless_preset = 1; if (use_lossless_preset != 0) use_lossless_preset = 1;
#endif #endif
} else if (!strcmp(argv[c], "-alpha_q") && c < argc - 1) { } else if (!strcmp(argv[c], "-alpha_q") && c < argc - 1) {
config.alpha_quality = strtol(argv[++c], NULL, 0); config.alpha_quality = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-alpha_method") && c < argc - 1) { } else if (!strcmp(argv[c], "-alpha_method") && c < argc - 1) {
config.alpha_compression = strtol(argv[++c], NULL, 0); config.alpha_compression = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-alpha_cleanup")) { } else if (!strcmp(argv[c], "-alpha_cleanup")) {
keep_alpha = keep_alpha ? 2 : 0; keep_alpha = keep_alpha ? 2 : 0;
} else if (!strcmp(argv[c], "-blend_alpha") && c < argc - 1) { } else if (!strcmp(argv[c], "-blend_alpha") && c < argc - 1) {
blend_alpha = 1; blend_alpha = 1;
background_color = strtol(argv[++c], NULL, 16); // <- parses '0x' prefix // background color is given in hex with an optional '0x' prefix
background_color = ExUtilGetInt(argv[++c], 16, &parse_error);
background_color = background_color & 0x00ffffffu; background_color = background_color & 0x00ffffffu;
} else if (!strcmp(argv[c], "-alpha_filter") && c < argc - 1) { } else if (!strcmp(argv[c], "-alpha_filter") && c < argc - 1) {
++c; ++c;
@ -787,13 +789,13 @@ int main(int argc, const char *argv[]) {
goto Error; goto Error;
} }
} else if (!strcmp(argv[c], "-size") && c < argc - 1) { } else if (!strcmp(argv[c], "-size") && c < argc - 1) {
config.target_size = strtol(argv[++c], NULL, 0); config.target_size = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-psnr") && c < argc - 1) { } else if (!strcmp(argv[c], "-psnr") && c < argc - 1) {
config.target_PSNR = (float)strtod(argv[++c], NULL); config.target_PSNR = ExUtilGetFloat(argv[++c], &parse_error);
} else if (!strcmp(argv[c], "-sns") && c < argc - 1) { } else if (!strcmp(argv[c], "-sns") && c < argc - 1) {
config.sns_strength = strtol(argv[++c], NULL, 0); config.sns_strength = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-f") && c < argc - 1) { } else if (!strcmp(argv[c], "-f") && c < argc - 1) {
config.filter_strength = strtol(argv[++c], NULL, 0); config.filter_strength = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-af")) { } else if (!strcmp(argv[c], "-af")) {
config.autofilter = 1; config.autofilter = 1;
} else if (!strcmp(argv[c], "-jpeg_like")) { } else if (!strcmp(argv[c], "-jpeg_like")) {
@ -807,26 +809,26 @@ int main(int argc, const char *argv[]) {
} else if (!strcmp(argv[c], "-nostrong")) { } else if (!strcmp(argv[c], "-nostrong")) {
config.filter_type = 0; config.filter_type = 0;
} else if (!strcmp(argv[c], "-sharpness") && c < argc - 1) { } else if (!strcmp(argv[c], "-sharpness") && c < argc - 1) {
config.filter_sharpness = strtol(argv[++c], NULL, 0); config.filter_sharpness = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-pass") && c < argc - 1) { } else if (!strcmp(argv[c], "-pass") && c < argc - 1) {
config.pass = strtol(argv[++c], NULL, 0); config.pass = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-pre") && c < argc - 1) { } else if (!strcmp(argv[c], "-pre") && c < argc - 1) {
config.preprocessing = strtol(argv[++c], NULL, 0); config.preprocessing = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-segments") && c < argc - 1) { } else if (!strcmp(argv[c], "-segments") && c < argc - 1) {
config.segments = strtol(argv[++c], NULL, 0); config.segments = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-partition_limit") && c < argc - 1) { } else if (!strcmp(argv[c], "-partition_limit") && c < argc - 1) {
config.partition_limit = strtol(argv[++c], NULL, 0); config.partition_limit = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-map") && c < argc - 1) { } else if (!strcmp(argv[c], "-map") && c < argc - 1) {
picture.extra_info_type = strtol(argv[++c], NULL, 0); picture.extra_info_type = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-crop") && c < argc - 4) { } else if (!strcmp(argv[c], "-crop") && c < argc - 4) {
crop = 1; crop = 1;
crop_x = strtol(argv[++c], NULL, 0); crop_x = ExUtilGetInt(argv[++c], 0, &parse_error);
crop_y = strtol(argv[++c], NULL, 0); crop_y = ExUtilGetInt(argv[++c], 0, &parse_error);
crop_w = strtol(argv[++c], NULL, 0); crop_w = ExUtilGetInt(argv[++c], 0, &parse_error);
crop_h = strtol(argv[++c], NULL, 0); crop_h = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-resize") && c < argc - 2) { } else if (!strcmp(argv[c], "-resize") && c < argc - 2) {
resize_w = strtol(argv[++c], NULL, 0); resize_w = ExUtilGetInt(argv[++c], 0, &parse_error);
resize_h = strtol(argv[++c], NULL, 0); resize_h = ExUtilGetInt(argv[++c], 0, &parse_error);
#ifndef WEBP_DLL #ifndef WEBP_DLL
} else if (!strcmp(argv[c], "-noasm")) { } else if (!strcmp(argv[c], "-noasm")) {
VP8GetCPUInfo = NULL; VP8GetCPUInfo = NULL;
@ -921,6 +923,11 @@ int main(int argc, const char *argv[]) {
} else { } else {
in_file = argv[c]; in_file = argv[c];
} }
if (parse_error) {
HelpLong();
return -1;
}
} }
if (in_file == NULL) { if (in_file == NULL) {
fprintf(stderr, "No input file specified!\n"); fprintf(stderr, "No input file specified!\n");

View File

@ -586,6 +586,7 @@ int main(int argc, const char *argv[]) {
} }
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help(); Help();
return 0; return 0;
@ -623,17 +624,18 @@ int main(int argc, const char *argv[]) {
} else if (!strcmp(argv[c], "-nodither")) { } else if (!strcmp(argv[c], "-nodither")) {
config.options.dithering_strength = 0; config.options.dithering_strength = 0;
} else if (!strcmp(argv[c], "-dither") && c < argc - 1) { } else if (!strcmp(argv[c], "-dither") && c < argc - 1) {
config.options.dithering_strength = strtol(argv[++c], NULL, 0); config.options.dithering_strength =
ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-crop") && c < argc - 4) { } else if (!strcmp(argv[c], "-crop") && c < argc - 4) {
config.options.use_cropping = 1; config.options.use_cropping = 1;
config.options.crop_left = strtol(argv[++c], NULL, 0); config.options.crop_left = ExUtilGetInt(argv[++c], 0, &parse_error);
config.options.crop_top = strtol(argv[++c], NULL, 0); config.options.crop_top = ExUtilGetInt(argv[++c], 0, &parse_error);
config.options.crop_width = strtol(argv[++c], NULL, 0); config.options.crop_width = ExUtilGetInt(argv[++c], 0, &parse_error);
config.options.crop_height = strtol(argv[++c], NULL, 0); config.options.crop_height = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-scale") && c < argc - 2) { } else if (!strcmp(argv[c], "-scale") && c < argc - 2) {
config.options.use_scaling = 1; config.options.use_scaling = 1;
config.options.scaled_width = strtol(argv[++c], NULL, 0); config.options.scaled_width = ExUtilGetInt(argv[++c], 0, &parse_error);
config.options.scaled_height = strtol(argv[++c], NULL, 0); config.options.scaled_height = ExUtilGetInt(argv[++c], 0, &parse_error);
#if WEBP_DECODER_ABI_VERSION > 0x0203 #if WEBP_DECODER_ABI_VERSION > 0x0203
} else if (!strcmp(argv[c], "-flip")) { } else if (!strcmp(argv[c], "-flip")) {
config.options.flip = 1; config.options.flip = 1;
@ -656,6 +658,11 @@ int main(int argc, const char *argv[]) {
} else { } else {
in_file = argv[c]; in_file = argv[c];
} }
if (parse_error) {
Help();
return -1;
}
} }
if (in_file == NULL) { if (in_file == NULL) {

View File

@ -23,6 +23,35 @@
#include "webp/decode.h" #include "webp/decode.h"
#include "./stopwatch.h" #include "./stopwatch.h"
//------------------------------------------------------------------------------
// String parsing
uint32_t ExUtilGetUInt(const char* const v, int base, int* const error) {
char* end = NULL;
const uint32_t n = (v != NULL) ? (uint32_t)strtoul(v, &end, base) : 0u;
if (end == v && error != NULL && !*error) {
*error = 1;
fprintf(stderr, "Error! '%s' is not an integer.\n",
(v != NULL) ? v : "(null)");
}
return n;
}
int ExUtilGetInt(const char* const v, int base, int* const error) {
return (int)ExUtilGetUInt(v, base, error);
}
float ExUtilGetFloat(const char* const v, int* const error) {
char* end = NULL;
const float f = (v != NULL) ? (float)strtod(v, &end) : 0.f;
if (end == v && error != NULL && !*error) {
*error = 1;
fprintf(stderr, "Error! '%s' is not a floating point number.\n",
(v != NULL) ? v : "(null)");
}
return f;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// File I/O // File I/O

View File

@ -20,6 +20,19 @@
extern "C" { extern "C" {
#endif #endif
//------------------------------------------------------------------------------
// String parsing
// Parses 'v' using strto(ul|l|d)(). If error is non-NULL, '*error' is set to
// true on failure while on success it is left unmodified to allow chaining of
// calls. An error is only printed on the first occurrence.
uint32_t ExUtilGetUInt(const char* const v, int base, int* const error);
int ExUtilGetInt(const char* const v, int base, int* const error);
float ExUtilGetFloat(const char* const v, int* const error);
//------------------------------------------------------------------------------
// File I/O
// Reopen file in binary (O_BINARY) mode. // Reopen file in binary (O_BINARY) mode.
// Returns 'file' on success, NULL otherwise. // Returns 'file' on success, NULL otherwise.
FILE* ExUtilSetBinaryMode(FILE* file); FILE* ExUtilSetBinaryMode(FILE* file);

View File

@ -304,6 +304,7 @@ int main(int argc, const char *argv[]) {
} }
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help(); Help();
return 0; return 0;
@ -315,17 +316,17 @@ int main(int argc, const char *argv[]) {
allow_mixed = 1; allow_mixed = 1;
config.lossless = 0; config.lossless = 0;
} else if (!strcmp(argv[c], "-q") && c < argc - 1) { } else if (!strcmp(argv[c], "-q") && c < argc - 1) {
config.quality = (float)strtod(argv[++c], NULL); config.quality = ExUtilGetFloat(argv[++c], &parse_error);
} else if (!strcmp(argv[c], "-m") && c < argc - 1) { } else if (!strcmp(argv[c], "-m") && c < argc - 1) {
config.method = strtol(argv[++c], NULL, 0); config.method = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-kmax") && c < argc - 1) { } else if (!strcmp(argv[c], "-kmax") && c < argc - 1) {
kmax = strtoul(argv[++c], NULL, 0); kmax = ExUtilGetUInt(argv[++c], 0, &parse_error);
default_kmax = 0; default_kmax = 0;
} else if (!strcmp(argv[c], "-kmin") && c < argc - 1) { } else if (!strcmp(argv[c], "-kmin") && c < argc - 1) {
kmin = strtoul(argv[++c], NULL, 0); kmin = ExUtilGetUInt(argv[++c], 0, &parse_error);
default_kmin = 0; default_kmin = 0;
} else if (!strcmp(argv[c], "-f") && c < argc - 1) { } else if (!strcmp(argv[c], "-f") && c < argc - 1) {
config.filter_strength = strtol(argv[++c], NULL, 0); config.filter_strength = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-metadata") && c < argc - 1) { } else if (!strcmp(argv[c], "-metadata") && c < argc - 1) {
static const struct { static const struct {
const char* option; const char* option;
@ -389,6 +390,11 @@ int main(int argc, const char *argv[]) {
} else { } else {
in_file = argv[c]; in_file = argv[c];
} }
if (parse_error) {
Help();
return -1;
}
} }
// Appropriate default kmin, kmax values for lossy and lossless. // Appropriate default kmin, kmax values for lossy and lossless.

View File

@ -408,6 +408,7 @@ int main(int argc, char *argv[]) {
kParams.use_color_profile = 1; kParams.use_color_profile = 1;
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help(); Help();
return 0; return 0;
@ -422,7 +423,8 @@ int main(int argc, char *argv[]) {
config->options.alpha_dithering_strength = 0; config->options.alpha_dithering_strength = 0;
#endif #endif
} else if (!strcmp(argv[c], "-dither") && c + 1 < argc) { } else if (!strcmp(argv[c], "-dither") && c + 1 < argc) {
config->options.dithering_strength = strtol(argv[++c], NULL, 0); config->options.dithering_strength =
ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-info")) { } else if (!strcmp(argv[c], "-info")) {
kParams.print_info = 1; kParams.print_info = 1;
} else if (!strcmp(argv[c], "-version")) { } else if (!strcmp(argv[c], "-version")) {
@ -445,6 +447,11 @@ int main(int argc, char *argv[]) {
} else { } else {
kParams.file_name = argv[c]; kParams.file_name = argv[c];
} }
if (parse_error) {
Help();
return -1;
}
} }
if (kParams.file_name == NULL) { if (kParams.file_name == NULL) {

View File

@ -839,14 +839,16 @@ static int GetFrameFragment(const WebPMux* mux,
WebPMux* mux_single = NULL; WebPMux* mux_single = NULL;
long num = 0; long num = 0;
int ok = 1; int ok = 1;
int parse_error = 0;
const WebPChunkId id = is_frame ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM; const WebPChunkId id = is_frame ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM;
WebPMuxFrameInfo info; WebPMuxFrameInfo info;
WebPDataInit(&info.bitstream); WebPDataInit(&info.bitstream);
num = strtol(config->feature_.args_[0].params_, NULL, 10); num = ExUtilGetInt(config->feature_.args_[0].params_, 10, &parse_error);
if (num < 0) { if (num < 0) {
ERROR_GOTO1("ERROR: Frame/Fragment index must be non-negative.\n", ErrGet); ERROR_GOTO1("ERROR: Frame/Fragment index must be non-negative.\n", ErrGet);
} }
if (parse_error) goto ErrGet;
err = WebPMuxGetFrame(mux, num, &info); err = WebPMuxGetFrame(mux, num, &info);
if (err == WEBP_MUX_OK && info.id != id) err = WEBP_MUX_NOT_FOUND; if (err == WEBP_MUX_OK && info.id != id) err = WEBP_MUX_NOT_FOUND;
@ -934,8 +936,9 @@ static int Process(const WebPMuxConfig* config) {
break; break;
} }
case SUBTYPE_LOOP: { case SUBTYPE_LOOP: {
const long loop_count = int parse_error = 0;
strtol(feature->args_[i].params_, NULL, 10); const int loop_count =
ExUtilGetInt(feature->args_[i].params_, 10, &parse_error);
if (loop_count != (int)loop_count) { if (loop_count != (int)loop_count) {
// Note: This is only a 'necessary' condition for loop_count // Note: This is only a 'necessary' condition for loop_count
// to be valid. The 'sufficient' conditioned in checked in // to be valid. The 'sufficient' conditioned in checked in
@ -943,6 +946,7 @@ static int Process(const WebPMuxConfig* config) {
ERROR_GOTO1("ERROR: Loop count must be in the range 0 to " ERROR_GOTO1("ERROR: Loop count must be in the range 0 to "
"65535.\n", Err2); "65535.\n", Err2);
} }
if (parse_error) goto Err2;
params.loop_count = (int)loop_count; params.loop_count = (int)loop_count;
break; break;
} }