diff --git a/examples/cwebp.c b/examples/cwebp.c index fa337b8e..e0284470 100644 --- a/examples/cwebp.c +++ b/examples/cwebp.c @@ -710,6 +710,7 @@ int main(int argc, const char *argv[]) { } for (c = 1; c < argc; ++c) { + int parse_error = 0; if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { HelpShort(); return 0; @@ -733,26 +734,27 @@ int main(int argc, const char *argv[]) { } else if (!strcmp(argv[c], "-short")) { ++short_output; } else if (!strcmp(argv[c], "-s") && c < argc - 2) { - picture.width = strtol(argv[++c], NULL, 0); - picture.height = strtol(argv[++c], NULL, 0); + picture.width = ExUtilGetInt(argv[++c], 0, &parse_error); + picture.height = ExUtilGetInt(argv[++c], 0, &parse_error); } else if (!strcmp(argv[c], "-m") && c < argc - 1) { - config.method = strtol(argv[++c], NULL, 0); + config.method = ExUtilGetInt(argv[++c], 0, &parse_error); use_lossless_preset = 0; // disable -z option } else if (!strcmp(argv[c], "-q") && c < argc - 1) { - config.quality = (float)strtod(argv[++c], NULL); + config.quality = ExUtilGetFloat(argv[++c], &parse_error); use_lossless_preset = 0; // disable -z option } 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; } 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) { - config.alpha_compression = strtol(argv[++c], NULL, 0); + config.alpha_compression = ExUtilGetInt(argv[++c], 0, &parse_error); } else if (!strcmp(argv[c], "-alpha_cleanup")) { keep_alpha = keep_alpha ? 2 : 0; } else if (!strcmp(argv[c], "-blend_alpha") && c < argc - 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; } else if (!strcmp(argv[c], "-alpha_filter") && c < argc - 1) { ++c; @@ -771,7 +773,7 @@ int main(int argc, const char *argv[]) { } else if (!strcmp(argv[c], "-lossless")) { config.lossless = 1; } else if (!strcmp(argv[c], "-near_lossless") && c < argc - 1) { - config.near_lossless = strtol(argv[++c], NULL, 0); + config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error); config.lossless = 1; // use near-lossless only with lossless } else if (!strcmp(argv[c], "-hint") && c < argc - 1) { ++c; @@ -786,13 +788,13 @@ int main(int argc, const char *argv[]) { goto Error; } } 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) { - 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) { - 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) { - config.filter_strength = strtol(argv[++c], NULL, 0); + config.filter_strength = ExUtilGetInt(argv[++c], 0, &parse_error); } else if (!strcmp(argv[c], "-af")) { config.autofilter = 1; } else if (!strcmp(argv[c], "-jpeg_like")) { @@ -806,26 +808,26 @@ int main(int argc, const char *argv[]) { } else if (!strcmp(argv[c], "-nostrong")) { config.filter_type = 0; } 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) { - config.pass = strtol(argv[++c], NULL, 0); + config.pass = ExUtilGetInt(argv[++c], 0, &parse_error); } 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) { - 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) { - 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) { - 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) { crop = 1; - crop_x = strtol(argv[++c], NULL, 0); - crop_y = strtol(argv[++c], NULL, 0); - crop_w = strtol(argv[++c], NULL, 0); - crop_h = strtol(argv[++c], NULL, 0); + crop_x = ExUtilGetInt(argv[++c], 0, &parse_error); + crop_y = ExUtilGetInt(argv[++c], 0, &parse_error); + crop_w = ExUtilGetInt(argv[++c], 0, &parse_error); + crop_h = ExUtilGetInt(argv[++c], 0, &parse_error); } else if (!strcmp(argv[c], "-resize") && c < argc - 2) { - resize_w = strtol(argv[++c], NULL, 0); - resize_h = strtol(argv[++c], NULL, 0); + resize_w = ExUtilGetInt(argv[++c], 0, &parse_error); + resize_h = ExUtilGetInt(argv[++c], 0, &parse_error); #ifndef WEBP_DLL } else if (!strcmp(argv[c], "-noasm")) { VP8GetCPUInfo = NULL; @@ -920,6 +922,11 @@ int main(int argc, const char *argv[]) { } else { in_file = argv[c]; } + + if (parse_error) { + HelpLong(); + return -1; + } } if (in_file == NULL) { fprintf(stderr, "No input file specified!\n"); diff --git a/examples/dwebp.c b/examples/dwebp.c index fe80dfe3..8c884577 100644 --- a/examples/dwebp.c +++ b/examples/dwebp.c @@ -582,6 +582,7 @@ int main(int argc, const char *argv[]) { } for (c = 1; c < argc; ++c) { + int parse_error = 0; if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { Help(); return 0; @@ -617,17 +618,18 @@ int main(int argc, const char *argv[]) { } else if (!strcmp(argv[c], "-nodither")) { config.options.dithering_strength = 0; } 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) { config.options.use_cropping = 1; - config.options.crop_left = strtol(argv[++c], NULL, 0); - config.options.crop_top = strtol(argv[++c], NULL, 0); - config.options.crop_width = strtol(argv[++c], NULL, 0); - config.options.crop_height = strtol(argv[++c], NULL, 0); + config.options.crop_left = ExUtilGetInt(argv[++c], 0, &parse_error); + config.options.crop_top = ExUtilGetInt(argv[++c], 0, &parse_error); + config.options.crop_width = ExUtilGetInt(argv[++c], 0, &parse_error); + config.options.crop_height = ExUtilGetInt(argv[++c], 0, &parse_error); } else if (!strcmp(argv[c], "-scale") && c < argc - 2) { config.options.use_scaling = 1; - config.options.scaled_width = strtol(argv[++c], NULL, 0); - config.options.scaled_height = strtol(argv[++c], NULL, 0); + config.options.scaled_width = ExUtilGetInt(argv[++c], 0, &parse_error); + config.options.scaled_height = ExUtilGetInt(argv[++c], 0, &parse_error); } else if (!strcmp(argv[c], "-flip")) { config.options.flip = 1; } else if (!strcmp(argv[c], "-v")) { @@ -648,6 +650,11 @@ int main(int argc, const char *argv[]) { } else { in_file = argv[c]; } + + if (parse_error) { + Help(); + return -1; + } } if (in_file == NULL) { diff --git a/examples/example_util.c b/examples/example_util.c index 5e34f305..f64cfd80 100644 --- a/examples/example_util.c +++ b/examples/example_util.c @@ -23,6 +23,35 @@ #include "webp/decode.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 diff --git a/examples/example_util.h b/examples/example_util.h index 4ef703da..8e8e8014 100644 --- a/examples/example_util.h +++ b/examples/example_util.h @@ -20,6 +20,19 @@ extern "C" { #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. // Returns 'file' on success, NULL otherwise. FILE* ExUtilSetBinaryMode(FILE* file); diff --git a/examples/gif2webp.c b/examples/gif2webp.c index 6cfe95ba..385f19cd 100644 --- a/examples/gif2webp.c +++ b/examples/gif2webp.c @@ -296,6 +296,7 @@ int main(int argc, const char *argv[]) { } for (c = 1; c < argc; ++c) { + int parse_error = 0; if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { Help(); return 0; @@ -307,17 +308,17 @@ int main(int argc, const char *argv[]) { allow_mixed = 1; config.lossless = 0; } 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) { - config.method = strtol(argv[++c], NULL, 0); + config.method = ExUtilGetInt(argv[++c], 0, &parse_error); } 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; } 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; } 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) { static const struct { const char* option; @@ -381,6 +382,11 @@ int main(int argc, const char *argv[]) { } else { in_file = argv[c]; } + + if (parse_error) { + Help(); + return -1; + } } // Appropriate default kmin, kmax values for lossy and lossless. diff --git a/examples/vwebp.c b/examples/vwebp.c index 589f0832..cc64dd56 100644 --- a/examples/vwebp.c +++ b/examples/vwebp.c @@ -404,6 +404,7 @@ int main(int argc, char *argv[]) { kParams.use_color_profile = 1; for (c = 1; c < argc; ++c) { + int parse_error = 0; if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { Help(); return 0; @@ -416,7 +417,8 @@ int main(int argc, char *argv[]) { } else if (!strcmp(argv[c], "-noalphadither")) { config->options.alpha_dithering_strength = 0; } 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")) { kParams.print_info = 1; } else if (!strcmp(argv[c], "-version")) { @@ -439,6 +441,11 @@ int main(int argc, char *argv[]) { } else { kParams.file_name = argv[c]; } + + if (parse_error) { + Help(); + return -1; + } } if (kParams.file_name == NULL) { diff --git a/examples/webpmux.c b/examples/webpmux.c index 8899ed8d..f3874920 100644 --- a/examples/webpmux.c +++ b/examples/webpmux.c @@ -839,14 +839,16 @@ static int GetFrameFragment(const WebPMux* mux, WebPMux* mux_single = NULL; long num = 0; int ok = 1; + int parse_error = 0; const WebPChunkId id = is_frame ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM; WebPMuxFrameInfo info; 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) { ERROR_GOTO1("ERROR: Frame/Fragment index must be non-negative.\n", ErrGet); } + if (parse_error) goto ErrGet; err = WebPMuxGetFrame(mux, num, &info); if (err == WEBP_MUX_OK && info.id != id) err = WEBP_MUX_NOT_FOUND; @@ -934,8 +936,9 @@ static int Process(const WebPMuxConfig* config) { break; } case SUBTYPE_LOOP: { - const long loop_count = - strtol(feature->args_[i].params_, NULL, 10); + int parse_error = 0; + const int loop_count = + ExUtilGetInt(feature->args_[i].params_, 10, &parse_error); if (loop_count != (int)loop_count) { // Note: This is only a 'necessary' condition for loop_count // 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 " "65535.\n", Err2); } + if (parse_error) goto Err2; params.loop_count = (int)loop_count; break; }