From 9cf9841b5e1669cc6678991419cdcb7b5e879237 Mon Sep 17 00:00:00 2001 From: Yannis Guyon Date: Tue, 16 Oct 2018 11:03:18 +0200 Subject: [PATCH] libwebp: Unicode command tools on Windows Define macros in examples/unicode.h to use Unicode argv on Windows. Keep char everywhere on Unix since it handles UTF-8 without any change. Impact: - All fopen () and SHCreateStreamOnFile(), - All fprintf() printing file paths, - All strcmp() used with "-", - File path parsing, - Gif reading. Concerned executables from examples/ and extras/: anim_diff, anim_dump, vwebp, vwebp_sdl, cwebp, dwebp, gif2webp, img2webp, webpmux, webpinfo, webp_quality, get_disto When compiled on Windows with Unicode enabled, webpmux and img2webp will not work when used with an argument file and will print "Reading arguments from a file is a feature unavailable with Unicode binaries." BUG=webp:398 Change-Id: Ic55d222a3ce1a715f9c4cce57ecbe2705d5ce317 --- CMakeLists.txt | 10 ++++ Makefile.vc | 17 +++++-- README | 2 + examples/anim_diff.c | 34 ++++++++------ examples/anim_dump.c | 45 +++++++++--------- examples/anim_util.c | 44 ++++++++--------- examples/cwebp.c | 57 +++++++++++++---------- examples/dwebp.c | 43 +++++++++-------- examples/example_util.c | 8 ++++ examples/gif2webp.c | 47 +++++++++---------- examples/img2webp.c | 22 +++++---- examples/unicode.h | 101 ++++++++++++++++++++++++++++++++++++++++ examples/unicode_gif.h | 75 +++++++++++++++++++++++++++++ examples/vwebp.c | 23 +++++---- examples/webpinfo.c | 26 ++++++----- examples/webpmux.c | 50 ++++++++++++-------- extras/get_disto.c | 16 ++++--- extras/vwebp_sdl.c | 14 ++++-- extras/webp_quality.c | 12 +++-- imageio/image_enc.c | 17 ++++--- imageio/imageio_util.c | 22 +++++---- imageio/webpdec.c | 3 +- imageio/wicdec.c | 11 +++-- 23 files changed, 485 insertions(+), 214 deletions(-) create mode 100644 examples/unicode.h create mode 100644 examples/unicode_gif.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ccd1b48b..73c7067a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,11 @@ option(WEBP_NEAR_LOSSLESS "Enable near-lossless encoding" ON) option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces." OFF) +# Option needed for handling Unicode file names on Windows. +if(WIN32) + option(WEBP_UNICODE "Build Unicode executables." ON) +endif() + if(WEBP_BUILD_WEBP_JS) set(WEBP_ENABLE_SIMD OFF) endif() @@ -41,6 +46,11 @@ if(WEBP_ENABLE_SWAP_16BIT_CSP) add_definitions(-DWEBP_SWAP_16BIT_CSP=1) endif() +if(WEBP_UNICODE) + # Windows recommends setting both UNICODE and _UNICODE. + add_definitions(-DUNICODE -D_UNICODE) +endif() + set(prefix ${CMAKE_INSTALL_PREFIX}) set(exec_prefix "\$\{prefix\}") set(libdir "\$\{prefix\}/lib") diff --git a/Makefile.vc b/Makefile.vc index 5d1bf865..bcad5681 100644 --- a/Makefile.vc +++ b/Makefile.vc @@ -134,12 +134,16 @@ LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME)_dll.pdb CFGSET = TRUE !ENDIF +!IF "$(UNICODE)" == "1" +CFLAGS = $(CFLAGS) /D_UNICODE /DUNICODE +!ENDIF + ####################### # Usage # !IF "$(CFGSET)" == "FALSE" !MESSAGE Usage: nmake /f Makefile.vc [CFG=] -!MESSAGE . [OBJDIR=] [RTLIBCFG=] [] +!MESSAGE . [OBJDIR=] [RTLIBCFG=] [UNICODE=1] [] !MESSAGE !MESSAGE where is one of: !MESSAGE - release-static - release static library @@ -492,15 +496,18 @@ $(DIROBJ)\examples\gifdec.obj: examples\gifdec.c {src\utils}.c{$(DIROBJ)\utils}.obj:: $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\utils\ $< +LNKLIBS = ole32.lib windowscodecs.lib shlwapi.lib +!IF "$(UNICODE)" == "1" +LNKLIBS = $(LNKLIBS) Shell32.lib +!ENDIF + {$(DIROBJ)\examples}.obj{$(DIRBIN)}.exe: - $(LNKEXE) $(LDFLAGS) /OUT:$@ $** \ - ole32.lib windowscodecs.lib shlwapi.lib + $(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS) $(MT) -manifest $@.manifest -outputresource:$@;1 del $@.manifest {$(DIROBJ)\extras}.obj{$(DIRBIN)}.exe: - $(LNKEXE) $(LDFLAGS) /OUT:$@ $** \ - ole32.lib windowscodecs.lib shlwapi.lib + $(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS) $(MT) -manifest $@.manifest -outputresource:$@;1 del $@.manifest diff --git a/README b/README index 103b3ae8..2477879e 100644 --- a/README +++ b/README @@ -136,6 +136,8 @@ cmake -DWEBP_BUILD_CWEBP=ON -DWEBP_BUILD_DWEBP=ON ../ or through your favorite interface (like ccmake or cmake-qt-gui). +Use option -DWEBP_UNICODE=ON for Unicode support on Windows (with chcp 65001). + Finally, once installed, you can also use WebP in your CMake project by doing: find_package(WebP) diff --git a/examples/anim_diff.c b/examples/anim_diff.c index e0939434..7ffabc8f 100644 --- a/examples/anim_diff.c +++ b/examples/anim_diff.c @@ -21,6 +21,7 @@ #include "./anim_util.h" #include "./example_util.h" +#include "./unicode.h" #if defined(_MSC_VER) && _MSC_VER < 1900 #define snprintf _snprintf @@ -218,12 +219,14 @@ int main(int argc, const char* argv[]) { const char* files[2] = { NULL, NULL }; AnimatedImage images[2]; + INIT_WARGV(argc, argv); + for (c = 1; c < argc; ++c) { int parse_error = 0; if (!strcmp(argv[c], "-dump_frames")) { if (c < argc - 1) { dump_frames = 1; - dump_folder = argv[++c]; + dump_folder = (const char*)GET_WARGV(argv, ++c); } else { parse_error = 1; } @@ -243,7 +246,7 @@ int main(int argc, const char* argv[]) { } } else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { Help(); - return 0; + FREE_WARGV_AND_RETURN(0); } else if (!strcmp(argv[c], "-version")) { int dec_version, demux_version; GetAnimatedImageVersions(&dec_version, &demux_version); @@ -252,13 +255,13 @@ int main(int argc, const char* argv[]) { (dec_version >> 0) & 0xff, (demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff, (demux_version >> 0) & 0xff); - return 0; + FREE_WARGV_AND_RETURN(0); } else { if (!got_input1) { - files[0] = argv[c]; + files[0] = (const char*)GET_WARGV(argv, c); got_input1 = 1; } else if (!got_input2) { - files[1] = argv[c]; + files[1] = (const char*)GET_WARGV(argv, c); got_input2 = 1; } else { parse_error = 1; @@ -266,29 +269,30 @@ int main(int argc, const char* argv[]) { } if (parse_error) { Help(); - return -1; + FREE_WARGV_AND_RETURN(-1); } } if (argc < 3) { Help(); - return -1; + FREE_WARGV_AND_RETURN(-1); } if (!got_input2) { Help(); - return -1; + FREE_WARGV_AND_RETURN(-1); } if (dump_frames) { - printf("Dumping decoded frames in: %s\n", dump_folder); + WPRINTF("Dumping decoded frames in: %s\n", (const W_CHAR*)dump_folder); } memset(images, 0, sizeof(images)); for (i = 0; i < 2; ++i) { - printf("Decoding file: %s\n", files[i]); + WPRINTF("Decoding file: %s\n", (const W_CHAR*)files[i]); if (!ReadAnimatedImage(files[i], &images[i], dump_frames, dump_folder)) { - fprintf(stderr, "Error decoding file: %s\n Aborting.\n", files[i]); + WFPRINTF(stderr, "Error decoding file: %s\n Aborting.\n", + (const W_CHAR*)files[i]); return_code = -2; goto End; } else { @@ -298,14 +302,16 @@ int main(int argc, const char* argv[]) { if (!CompareAnimatedImagePair(&images[0], &images[1], premultiply, min_psnr)) { - fprintf(stderr, "\nFiles %s and %s differ.\n", files[0], files[1]); + WFPRINTF(stderr, "\nFiles %s and %s differ.\n", (const W_CHAR*)files[0], + (const W_CHAR*)files[1]); return_code = -3; } else { - printf("\nFiles %s and %s are identical.\n", files[0], files[1]); + WPRINTF("\nFiles %s and %s are identical.\n", (const W_CHAR*)files[0], + (const W_CHAR*)files[1]); return_code = 0; } End: ClearAnimatedImage(&images[0]); ClearAnimatedImage(&images[1]); - return return_code; + FREE_WARGV_AND_RETURN(return_code); } diff --git a/examples/anim_dump.c b/examples/anim_dump.c index 7b96cfec..e4473386 100644 --- a/examples/anim_dump.c +++ b/examples/anim_dump.c @@ -17,6 +17,7 @@ #include "./anim_util.h" #include "webp/decode.h" #include "../imageio/image_enc.h" +#include "./unicode.h" #if defined(_MSC_VER) && _MSC_VER < 1900 #define snprintf _snprintf @@ -36,15 +37,17 @@ static void Help(void) { int main(int argc, const char* argv[]) { int error = 0; - const char* dump_folder = "."; - const char* prefix = "dump_"; - const char* suffix = "png"; + const W_CHAR* dump_folder = TO_W_CHAR("."); + const W_CHAR* prefix = TO_W_CHAR("dump_"); + const W_CHAR* suffix = TO_W_CHAR("png"); WebPOutputFileFormat format = PNG; int c; + INIT_WARGV(argc, argv); + if (argc < 2) { Help(); - return -1; + FREE_WARGV_AND_RETURN(-1); } for (c = 1; !error && c < argc; ++c) { @@ -54,23 +57,23 @@ int main(int argc, const char* argv[]) { error = 1; break; } - dump_folder = argv[++c]; + dump_folder = GET_WARGV(argv, ++c); } else if (!strcmp(argv[c], "-prefix")) { if (c + 1 == argc) { fprintf(stderr, "missing argument after option '%s'\n", argv[c]); error = 1; break; } - prefix = argv[++c]; + prefix = GET_WARGV(argv, ++c); } else if (!strcmp(argv[c], "-tiff")) { format = TIFF; - suffix = "tiff"; + suffix = TO_W_CHAR("tiff"); } else if (!strcmp(argv[c], "-pam")) { format = PAM; - suffix = "pam"; + suffix = TO_W_CHAR("pam"); } else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { Help(); - return 0; + FREE_WARGV_AND_RETURN(0); } else if (!strcmp(argv[c], "-version")) { int dec_version, demux_version; GetAnimatedImageVersions(&dec_version, &demux_version); @@ -79,21 +82,21 @@ int main(int argc, const char* argv[]) { (dec_version >> 0) & 0xff, (demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff, (demux_version >> 0) & 0xff); - return 0; + FREE_WARGV_AND_RETURN(0); } else { uint32_t i; AnimatedImage image; - const char* const file = argv[c]; + const W_CHAR* const file = GET_WARGV(argv, c); memset(&image, 0, sizeof(image)); - printf("Decoding file: %s as %s/%sxxxx.%s\n", - file, dump_folder, prefix, suffix); - if (!ReadAnimatedImage(file, &image, 0, NULL)) { - fprintf(stderr, "Error decoding file: %s\n Aborting.\n", file); + WPRINTF("Decoding file: %s as %s/%sxxxx.%s\n", + file, dump_folder, prefix, suffix); + if (!ReadAnimatedImage((const char*)file, &image, 0, NULL)) { + WFPRINTF(stderr, "Error decoding file: %s\n Aborting.\n", file); error = 1; break; } for (i = 0; !error && i < image.num_frames; ++i) { - char out_file[1024]; + W_CHAR out_file[1024]; WebPDecBuffer buffer; WebPInitDecBuffer(&buffer); buffer.colorspace = MODE_RGBA; @@ -103,10 +106,10 @@ int main(int argc, const char* argv[]) { buffer.u.RGBA.rgba = image.frames[i].rgba; buffer.u.RGBA.stride = buffer.width * sizeof(uint32_t); buffer.u.RGBA.size = buffer.u.RGBA.stride * buffer.height; - snprintf(out_file, sizeof(out_file), "%s/%s%.4d.%s", - dump_folder, prefix, i, suffix); - if (!WebPSaveImage(&buffer, format, out_file)) { - fprintf(stderr, "Error while saving image '%s'\n", out_file); + WSNPRINTF(out_file, sizeof(out_file), "%s/%s%.4d.%s", + dump_folder, prefix, i, suffix); + if (!WebPSaveImage(&buffer, format, (const char*)out_file)) { + WFPRINTF(stderr, "Error while saving image '%s'\n", out_file); error = 1; } WebPFreeDecBuffer(&buffer); @@ -114,5 +117,5 @@ int main(int argc, const char* argv[]) { ClearAnimatedImage(&image); } } - return error ? 1 : 0; + FREE_WARGV_AND_RETURN(error ? 1 : 0); } diff --git a/examples/anim_util.c b/examples/anim_util.c index d1ecb58b..8eff8b11 100644 --- a/examples/anim_util.c +++ b/examples/anim_util.c @@ -24,6 +24,8 @@ #include "webp/demux.h" #include "../imageio/imageio_util.h" #include "./gifdec.h" +#include "./unicode.h" +#include "./unicode_gif.h" #if defined(_MSC_VER) && _MSC_VER < 1900 #define snprintf _snprintf @@ -152,42 +154,42 @@ static int DumpFrame(const char filename[], const char dump_folder[], int ok = 0; size_t max_len; int y; - const char* base_name = NULL; - char* file_name = NULL; + const W_CHAR* base_name = NULL; + W_CHAR* file_name = NULL; FILE* f = NULL; const char* row; - if (dump_folder == NULL) dump_folder = "."; + if (dump_folder == NULL) dump_folder = (const char*)TO_W_CHAR("."); - base_name = strrchr(filename, '/'); - base_name = (base_name == NULL) ? filename : base_name + 1; - max_len = strlen(dump_folder) + 1 + strlen(base_name) + base_name = WSTRRCHR(filename, '/'); + base_name = (base_name == NULL) ? (const W_CHAR*)filename : base_name + 1; + max_len = WSTRLEN(dump_folder) + 1 + WSTRLEN(base_name) + strlen("_frame_") + strlen(".pam") + 8; - file_name = (char*)malloc(max_len * sizeof(*file_name)); + file_name = (W_CHAR*)malloc(max_len * sizeof(*file_name)); if (file_name == NULL) goto End; - if (snprintf(file_name, max_len, "%s/%s_frame_%d.pam", - dump_folder, base_name, frame_num) < 0) { + if (WSNPRINTF(file_name, max_len, "%s/%s_frame_%d.pam", + (const W_CHAR*)dump_folder, base_name, frame_num) < 0) { fprintf(stderr, "Error while generating file name\n"); goto End; } - f = fopen(file_name, "wb"); + f = WFOPEN(file_name, "wb"); if (f == NULL) { - fprintf(stderr, "Error opening file for writing: %s\n", file_name); + WFPRINTF(stderr, "Error opening file for writing: %s\n", file_name); ok = 0; goto End; } if (fprintf(f, "P7\nWIDTH %d\nHEIGHT %d\n" "DEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n", canvas_width, canvas_height) < 0) { - fprintf(stderr, "Write error for file %s\n", file_name); + WFPRINTF(stderr, "Write error for file %s\n", file_name); goto End; } row = (const char*)rgba; for (y = 0; y < canvas_height; ++y) { if (fwrite(row, canvas_width * kNumChannels, 1, f) != 1) { - fprintf(stderr, "Error writing to file: %s\n", file_name); + WFPRINTF(stderr, "Error writing to file: %s\n", file_name); goto End; } row += canvas_width * kNumChannels; @@ -223,7 +225,7 @@ static int ReadAnimatedWebP(const char filename[], dec = WebPAnimDecoderNew(webp_data, NULL); if (dec == NULL) { - fprintf(stderr, "Error parsing image: %s\n", filename); + WFPRINTF(stderr, "Error parsing image: %s\n", (const W_CHAR*)filename); goto End; } @@ -511,15 +513,15 @@ static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image, int gif_error; GifFileType* gif; - gif = DGifOpenFileName(filename, NULL); + gif = DGifOpenFileUnicode((const W_CHAR*)filename, NULL); if (gif == NULL) { - fprintf(stderr, "Could not read file: %s.\n", filename); + WFPRINTF(stderr, "Could not read file: %s.\n", (const W_CHAR*)filename); return 0; } gif_error = DGifSlurp(gif); if (gif_error != GIF_OK) { - fprintf(stderr, "Could not parse image: %s.\n", filename); + WFPRINTF(stderr, "Could not parse image: %s.\n", (const W_CHAR*)filename); GIFDisplayError(gif, gif_error); DGifCloseFile(gif, NULL); return 0; @@ -705,7 +707,7 @@ int ReadAnimatedImage(const char filename[], AnimatedImage* const image, memset(image, 0, sizeof(*image)); if (!ImgIoUtilReadFile(filename, &webp_data.bytes, &webp_data.size)) { - fprintf(stderr, "Error reading file: %s\n", filename); + WFPRINTF(stderr, "Error reading file: %s\n", (const W_CHAR*)filename); return 0; } @@ -715,9 +717,9 @@ int ReadAnimatedImage(const char filename[], AnimatedImage* const image, } else if (IsGIF(&webp_data)) { ok = ReadAnimatedGIF(filename, image, dump_frames, dump_folder); } else { - fprintf(stderr, - "Unknown file type: %s. Supported file types are WebP and GIF\n", - filename); + WFPRINTF(stderr, + "Unknown file type: %s. Supported file types are WebP and GIF\n", + (const W_CHAR*)filename); ok = 0; } if (!ok) ClearAnimatedImage(image); diff --git a/examples/cwebp.c b/examples/cwebp.c index 7b1836d3..30e7ec1e 100644 --- a/examples/cwebp.c +++ b/examples/cwebp.c @@ -24,6 +24,7 @@ #include "../imageio/image_dec.h" #include "../imageio/imageio_util.h" #include "./stopwatch.h" +#include "./unicode.h" #include "webp/encode.h" #ifndef WEBP_DLL @@ -88,7 +89,8 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic, } } if (!ok) { - fprintf(stderr, "Error! Could not process file %s\n", filename); + WFPRINTF(stderr, "Error! Could not process file %s\n", + (const W_CHAR*)filename); } free((void*)data); return ok; @@ -114,7 +116,8 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic, } End: if (!ok) { - fprintf(stderr, "Error! Could not process file %s\n", filename); + WFPRINTF(stderr, "Error! Could not process file %s\n", + (const W_CHAR*)filename); } free((void*)data); return ok; @@ -185,7 +188,7 @@ static void PrintExtraInfoLossless(const WebPPicture* const pic, if (short_output) { fprintf(stderr, "%7d %2.2f\n", stats->coded_size, stats->PSNR[3]); } else { - fprintf(stderr, "File: %s\n", file_name); + WFPRINTF(stderr, "File: %s\n", (const W_CHAR*)file_name); fprintf(stderr, "Dimension: %d x %d\n", pic->width, pic->height); fprintf(stderr, "Output: %d bytes (%.2f bpp)\n", stats->coded_size, 8.f * stats->coded_size / pic->width / pic->height); @@ -204,7 +207,7 @@ static void PrintExtraInfoLossy(const WebPPicture* const pic, int short_output, const int num_i16 = stats->block_count[1]; const int num_skip = stats->block_count[2]; const int total = num_i4 + num_i16; - fprintf(stderr, "File: %s\n", file_name); + WFPRINTF(stderr, "File: %s\n", (const W_CHAR*)file_name); fprintf(stderr, "Dimension: %d x %d%s\n", pic->width, pic->height, stats->alpha_data_size ? " (with alpha)" : ""); @@ -309,7 +312,7 @@ static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) { const int alpha_height = WebPPictureHasTransparency(picture) ? picture->height : 0; const int height = picture->height + uv_height + alpha_height; - FILE* const f = fopen(PGM_name, "wb"); + FILE* const f = WFOPEN(PGM_name, "wb"); if (f == NULL) return 0; fprintf(f, "P5\n%d %d\n255\n", stride, height); for (y = 0; y < picture->height; ++y) { @@ -663,32 +666,34 @@ int main(int argc, const char *argv[]) { Metadata metadata; Stopwatch stop_watch; + INIT_WARGV(argc, argv); + MetadataInit(&metadata); WebPMemoryWriterInit(&memory_writer); if (!WebPPictureInit(&picture) || !WebPPictureInit(&original_picture) || !WebPConfigInit(&config)) { fprintf(stderr, "Error! Version mismatch!\n"); - return -1; + FREE_WARGV_AND_RETURN(-1); } if (argc == 1) { HelpShort(); - return 0; + FREE_WARGV_AND_RETURN(0); } for (c = 1; c < argc; ++c) { int parse_error = 0; if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { HelpShort(); - return 0; + FREE_WARGV_AND_RETURN(0); } else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) { HelpLong(); - return 0; + FREE_WARGV_AND_RETURN(0); } else if (!strcmp(argv[c], "-o") && c < argc - 1) { - out_file = argv[++c]; + out_file = (const char*)GET_WARGV(argv, ++c); } else if (!strcmp(argv[c], "-d") && c < argc - 1) { - dump_file = argv[++c]; + dump_file = (const char*)GET_WARGV(argv, ++c); config.show_compressed = 1; } else if (!strcmp(argv[c], "-print_psnr")) { config.show_compressed = 1; @@ -816,7 +821,7 @@ int main(int argc, const char *argv[]) { const int version = WebPGetEncoderVersion(); printf("%d.%d.%d\n", (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); - return 0; + FREE_WARGV_AND_RETURN(0); } else if (!strcmp(argv[c], "-progress")) { show_progress = 1; } else if (!strcmp(argv[c], "-quiet")) { @@ -878,8 +883,7 @@ int main(int argc, const char *argv[]) { if (i == kNumTokens) { fprintf(stderr, "Error! Unknown metadata type '%.*s'\n", (int)(token - start), start); - HelpLong(); - return -1; + FREE_WARGV_AND_RETURN(-1); } start = token + 1; } @@ -893,19 +897,19 @@ int main(int argc, const char *argv[]) { } else if (!strcmp(argv[c], "-v")) { verbose = 1; } else if (!strcmp(argv[c], "--")) { - if (c < argc - 1) in_file = argv[++c]; + if (c < argc - 1) in_file = (const char*)GET_WARGV(argv, ++c); break; } else if (argv[c][0] == '-') { fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]); HelpLong(); - return -1; + FREE_WARGV_AND_RETURN(-1); } else { - in_file = argv[c]; + in_file = (const char*)GET_WARGV(argv, c); } if (parse_error) { HelpLong(); - return -1; + FREE_WARGV_AND_RETURN(-1); } } if (in_file == NULL) { @@ -955,7 +959,8 @@ int main(int argc, const char *argv[]) { } if (!ReadPicture(in_file, &picture, keep_alpha, (keep_metadata == 0) ? NULL : &metadata)) { - fprintf(stderr, "Error! Cannot read input picture file '%s'\n", in_file); + WFPRINTF(stderr, "Error! Cannot read input picture file '%s'\n", + (const W_CHAR*)in_file); goto Error; } picture.progress_hook = (show_progress && !quiet) ? ProgressReport : NULL; @@ -971,14 +976,15 @@ int main(int argc, const char *argv[]) { // Open the output if (out_file != NULL) { - const int use_stdout = !strcmp(out_file, "-"); - out = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : fopen(out_file, "wb"); + const int use_stdout = !WSTRCMP(out_file, "-"); + out = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : WFOPEN(out_file, "wb"); if (out == NULL) { - fprintf(stderr, "Error! Cannot open output file '%s'\n", out_file); + WFPRINTF(stderr, "Error! Cannot open output file '%s'\n", + (const W_CHAR*)out_file); goto Error; } else { if (!short_output && !quiet) { - fprintf(stderr, "Saving file '%s'\n", out_file); + WFPRINTF(stderr, "Saving file '%s'\n", (const W_CHAR*)out_file); } } if (keep_metadata == 0) { @@ -1093,7 +1099,8 @@ int main(int argc, const char *argv[]) { fprintf(stderr, "Warning: can't dump file (-d option) " "in lossless mode.\n"); } else if (!DumpPicture(&picture, dump_file)) { - fprintf(stderr, "Warning, couldn't dump picture %s\n", dump_file); + WFPRINTF(stderr, "Warning, couldn't dump picture %s\n", + (const W_CHAR*)dump_file); } } @@ -1169,7 +1176,7 @@ int main(int argc, const char *argv[]) { fclose(out); } - return return_value; + FREE_WARGV_AND_RETURN(return_value); } //------------------------------------------------------------------------------ diff --git a/examples/dwebp.c b/examples/dwebp.c index 154069a7..7284f305 100644 --- a/examples/dwebp.c +++ b/examples/dwebp.c @@ -24,6 +24,7 @@ #include "../imageio/image_enc.h" #include "../imageio/webpdec.h" #include "./stopwatch.h" +#include "./unicode.h" static int verbose = 0; static int quiet = 0; @@ -42,7 +43,7 @@ extern void* VP8GetCPUInfo; // opaque forward declaration. static int SaveOutput(const WebPDecBuffer* const buffer, WebPOutputFileFormat format, const char* const out_file) { - const int use_stdout = (out_file != NULL) && !strcmp(out_file, "-"); + const int use_stdout = (out_file != NULL) && !WSTRCMP(out_file, "-"); int ok = 1; Stopwatch stop_watch; @@ -56,7 +57,7 @@ static int SaveOutput(const WebPDecBuffer* const buffer, if (use_stdout) { fprintf(stderr, "Saved to stdout\n"); } else { - fprintf(stderr, "Saved file %s\n", out_file); + WFPRINTF(stderr, "Saved file %s\n", (const W_CHAR*)out_file); } } if (verbose) { @@ -67,7 +68,7 @@ static int SaveOutput(const WebPDecBuffer* const buffer, if (use_stdout) { fprintf(stderr, "Error writing to stdout !!\n"); } else { - fprintf(stderr, "Error writing file %s !!\n", out_file); + WFPRINTF(stderr, "Error writing file %s !!\n", (const W_CHAR*)out_file); } } return ok; @@ -191,18 +192,20 @@ int main(int argc, const char *argv[]) { int incremental = 0; int c; + INIT_WARGV(argc, argv); + if (!WebPInitDecoderConfig(&config)) { fprintf(stderr, "Library version mismatch!\n"); - return -1; + FREE_WARGV_AND_RETURN(-1); } for (c = 1; c < argc; ++c) { int parse_error = 0; if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { Help(); - return 0; + FREE_WARGV_AND_RETURN(0); } else if (!strcmp(argv[c], "-o") && c < argc - 1) { - out_file = argv[++c]; + out_file = (const char*)GET_WARGV(argv, ++c); } else if (!strcmp(argv[c], "-alpha")) { format = ALPHA_PLANE_ONLY; } else if (!strcmp(argv[c], "-nofancy")) { @@ -223,7 +226,7 @@ int main(int argc, const char *argv[]) { const int version = WebPGetDecoderVersion(); printf("%d.%d.%d\n", (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); - return 0; + FREE_WARGV_AND_RETURN(0); } else if (!strcmp(argv[c], "-pgm")) { format = PGM; } else if (!strcmp(argv[c], "-yuv")) { @@ -284,26 +287,26 @@ int main(int argc, const char *argv[]) { } else if (!strcmp(argv[c], "-incremental")) { incremental = 1; } else if (!strcmp(argv[c], "--")) { - if (c < argc - 1) in_file = argv[++c]; + if (c < argc - 1) in_file = (const char*)GET_WARGV(argv, ++c); break; } else if (argv[c][0] == '-') { fprintf(stderr, "Unknown option '%s'\n", argv[c]); Help(); - return -1; + FREE_WARGV_AND_RETURN(-1); } else { - in_file = argv[c]; + in_file = (const char*)GET_WARGV(argv, c); } if (parse_error) { Help(); - return -1; + FREE_WARGV_AND_RETURN(-1); } } if (in_file == NULL) { fprintf(stderr, "missing input file!!\n"); Help(); - return -1; + FREE_WARGV_AND_RETURN(-1); } if (quiet) verbose = 0; @@ -312,7 +315,7 @@ int main(int argc, const char *argv[]) { VP8StatusCode status = VP8_STATUS_OK; size_t data_size = 0; if (!LoadWebP(in_file, &data, &data_size, bitstream)) { - return -1; + FREE_WARGV_AND_RETURN(-1); } switch (format) { @@ -389,18 +392,18 @@ int main(int argc, const char *argv[]) { if (out_file != NULL) { if (!quiet) { - fprintf(stderr, "Decoded %s. Dimensions: %d x %d %s. Format: %s. " - "Now saving...\n", - in_file, output_buffer->width, output_buffer->height, + WFPRINTF(stderr, "Decoded %s.", (const W_CHAR*)in_file); + fprintf(stderr, " Dimensions: %d x %d %s. Format: %s. Now saving...\n", + output_buffer->width, output_buffer->height, bitstream->has_alpha ? " (with alpha)" : "", kFormatType[bitstream->format]); } ok = SaveOutput(output_buffer, format, out_file); } else { if (!quiet) { - fprintf(stderr, "File %s can be decoded " - "(dimensions: %d x %d %s. Format: %s).\n", - in_file, output_buffer->width, output_buffer->height, + WFPRINTF(stderr, "File %s can be decoded ", (const W_CHAR*)in_file); + fprintf(stderr, "(dimensions: %d x %d %s. Format: %s).\n", + output_buffer->width, output_buffer->height, bitstream->has_alpha ? " (with alpha)" : "", kFormatType[bitstream->format]); fprintf(stderr, "Nothing written; " @@ -411,7 +414,7 @@ int main(int argc, const char *argv[]) { WebPFreeDecBuffer(output_buffer); free((void*)external_buffer); free((void*)data); - return ok ? 0 : -1; + FREE_WARGV_AND_RETURN(ok ? 0 : -1); } //------------------------------------------------------------------------------ diff --git a/examples/example_util.c b/examples/example_util.c index 825a1234..a1c84988 100644 --- a/examples/example_util.c +++ b/examples/example_util.c @@ -90,6 +90,14 @@ int ExUtilInitCommandLineArguments(int argc, const char* argv[], if (argc == 1 && argv[0][0] != '-') { char* cur; const char sep[] = " \t\r\n\f\v"; + +#if defined(_WIN32) && defined(_UNICODE) + fprintf(stderr, + "Error: Reading arguments from a file is a feature unavailable " + "with Unicode binaries.\n"); + return 0; +#endif + if (!ExUtilReadFileToWebPData(argv[0], &args->argv_data_)) { return 0; } diff --git a/examples/gif2webp.c b/examples/gif2webp.c index cf8392d4..40b9c401 100644 --- a/examples/gif2webp.c +++ b/examples/gif2webp.c @@ -33,6 +33,8 @@ #include "../examples/example_util.h" #include "../imageio/imageio_util.h" #include "./gifdec.h" +#include "./unicode.h" +#include "./unicode_gif.h" #if !defined(STDIN_FILENO) #define STDIN_FILENO 0 @@ -99,7 +101,7 @@ int main(int argc, const char *argv[]) { int gif_error = GIF_ERROR; WebPMuxError err = WEBP_MUX_OK; int ok = 0; - const char *in_file = NULL, *out_file = NULL; + const W_CHAR *in_file = NULL, *out_file = NULL; GifFileType* gif = NULL; int frame_duration = 0; int frame_timestamp = 0; @@ -132,11 +134,13 @@ int main(int argc, const char *argv[]) { int default_kmin = 1; // Whether to use default kmin value. int default_kmax = 1; + INIT_WARGV(argc, argv); + if (!WebPConfigInit(&config) || !WebPAnimEncoderOptionsInit(&enc_options) || !WebPPictureInit(&frame) || !WebPPictureInit(&curr_canvas) || !WebPPictureInit(&prev_canvas)) { fprintf(stderr, "Error! Version mismatch!\n"); - return -1; + FREE_WARGV_AND_RETURN(-1); } config.lossless = 1; // Use lossless compression by default. @@ -146,16 +150,16 @@ int main(int argc, const char *argv[]) { if (argc == 1) { Help(); - return 0; + FREE_WARGV_AND_RETURN(0); } for (c = 1; c < argc; ++c) { int parse_error = 0; if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { Help(); - return 0; + FREE_WARGV_AND_RETURN(0); } else if (!strcmp(argv[c], "-o") && c < argc - 1) { - out_file = argv[++c]; + out_file = GET_WARGV(argv, ++c); } else if (!strcmp(argv[c], "-lossy")) { config.lossless = 0; } else if (!strcmp(argv[c], "-mixed")) { @@ -212,7 +216,7 @@ int main(int argc, const char *argv[]) { fprintf(stderr, "Error! Unknown metadata type '%.*s'\n", (int)(token - start), start); Help(); - return -1; + FREE_WARGV_AND_RETURN(-1); } start = token + 1; } @@ -225,7 +229,7 @@ int main(int argc, const char *argv[]) { (enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff, enc_version & 0xff, (mux_version >> 16) & 0xff, (mux_version >> 8) & 0xff, mux_version & 0xff); - return 0; + FREE_WARGV_AND_RETURN(0); } else if (!strcmp(argv[c], "-quiet")) { quiet = 1; enc_options.verbose = 0; @@ -233,19 +237,19 @@ int main(int argc, const char *argv[]) { verbose = 1; enc_options.verbose = 1; } else if (!strcmp(argv[c], "--")) { - if (c < argc - 1) in_file = argv[++c]; + if (c < argc - 1) in_file = GET_WARGV(argv, ++c); break; } else if (argv[c][0] == '-') { fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]); Help(); - return -1; + FREE_WARGV_AND_RETURN(-1); } else { - in_file = argv[c]; + in_file = GET_WARGV(argv, c); } if (parse_error) { Help(); - return -1; + FREE_WARGV_AND_RETURN(-1); } } @@ -269,13 +273,7 @@ int main(int argc, const char *argv[]) { } // Start the decoder object -#if LOCAL_GIF_PREREQ(5,0) - gif = !strcmp(in_file, "-") ? DGifOpenFileHandle(STDIN_FILENO, &gif_error) - : DGifOpenFileName(in_file, &gif_error); -#else - gif = !strcmp(in_file, "-") ? DGifOpenFileHandle(STDIN_FILENO) - : DGifOpenFileName(in_file); -#endif + gif = DGifOpenFileUnicode(in_file, &gif_error); if (gif == NULL) goto End; // Loop over GIF images @@ -544,17 +542,18 @@ int main(int argc, const char *argv[]) { } if (out_file != NULL) { - if (!ImgIoUtilWriteFile(out_file, webp_data.bytes, webp_data.size)) { - fprintf(stderr, "Error writing output file: %s\n", out_file); + if (!ImgIoUtilWriteFile((const char*)out_file, webp_data.bytes, + webp_data.size)) { + WFPRINTF(stderr, "Error writing output file: %s\n", out_file); goto End; } if (!quiet) { - if (!strcmp(out_file, "-")) { + if (!WSTRCMP(out_file, "-")) { fprintf(stderr, "Saved %d bytes to STDIO\n", (int)webp_data.size); } else { - fprintf(stderr, "Saved output file (%d bytes): %s\n", - (int)webp_data.size, out_file); + WFPRINTF(stderr, "Saved output file (%d bytes): %s\n", + (int)webp_data.size, out_file); } } } else { @@ -589,7 +588,7 @@ int main(int argc, const char *argv[]) { #endif } - return !ok; + FREE_WARGV_AND_RETURN(!ok); } #else // !WEBP_HAVE_GIF diff --git a/examples/img2webp.c b/examples/img2webp.c index 2f750c59..51d83435 100644 --- a/examples/img2webp.c +++ b/examples/img2webp.c @@ -27,6 +27,7 @@ #include "../imageio/image_dec.h" #include "../imageio/imageio_util.h" #include "./stopwatch.h" +#include "./unicode.h" #include "webp/encode.h" #include "webp/mux.h" @@ -134,8 +135,13 @@ int main(int argc, const char* argv[]) { int c; int have_input = 0; CommandLineArguments cmd_args; - int ok = ExUtilInitCommandLineArguments(argc - 1, argv + 1, &cmd_args); - if (!ok) return 1; + int ok; + + INIT_WARGV(argc, argv); + + ok = ExUtilInitCommandLineArguments(argc - 1, argv + 1, &cmd_args); + if (!ok) FREE_WARGV_AND_RETURN(1); + argc = cmd_args.argc_; argv = cmd_args.argv_; @@ -154,7 +160,7 @@ int main(int argc, const char* argv[]) { int parse_error = 0; if (!strcmp(argv[c], "-o") && c + 1 < argc) { argv[c] = NULL; - output = argv[++c]; + output = (const char*)GET_WARGV_SHIFTED(argv, ++c); } else if (!strcmp(argv[c], "-kmin") && c + 1 < argc) { argv[c] = NULL; anim_config.kmin = ExUtilGetInt(argv[++c], 0, &parse_error); @@ -241,7 +247,7 @@ int main(int argc, const char* argv[]) { // read next input image pic.use_argb = 1; - ok = ReadImage(argv[c], &pic); + ok = ReadImage((const char*)GET_WARGV_SHIFTED(argv, c), &pic); if (!ok) goto End; if (enc == NULL) { @@ -273,8 +279,8 @@ int main(int argc, const char* argv[]) { if (!ok) goto End; if (verbose) { - fprintf(stderr, "Added frame #%3d at time %4d (file: %s)\n", - pic_num, timestamp_ms, argv[c]); + WFPRINTF(stderr, "Added frame #%3d at time %4d (file: %s)\n", + pic_num, timestamp_ms, GET_WARGV_SHIFTED(argv, c)); } timestamp_ms += duration; ++pic_num; @@ -298,7 +304,7 @@ int main(int argc, const char* argv[]) { if (ok) { if (output != NULL) { ok = ImgIoUtilWriteFile(output, webp_data.bytes, webp_data.size); - if (ok) fprintf(stderr, "output file: %s ", output); + if (ok) WFPRINTF(stderr, "output file: %s ", (const W_CHAR*)output); } else { fprintf(stderr, "[no output file specified] "); } @@ -310,5 +316,5 @@ int main(int argc, const char* argv[]) { } WebPDataClear(&webp_data); ExUtilDeleteCommandLineArguments(&cmd_args); - return ok ? 0 : 1; + FREE_WARGV_AND_RETURN(ok ? 0 : 1); } diff --git a/examples/unicode.h b/examples/unicode.h new file mode 100644 index 00000000..b7c7fbb5 --- /dev/null +++ b/examples/unicode.h @@ -0,0 +1,101 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Unicode support for Windows. The main idea is to maintain an array of Unicode +// arguments (wargv) and use it only for file paths. The regular argv is used +// for everything else. +// +// Author: Yannis Guyon (yguyon@google.com) + +#ifndef WEBP_EXAMPLES_UNICODE_H_ +#define WEBP_EXAMPLES_UNICODE_H_ + +#if defined(_WIN32) && defined(_UNICODE) + +// wchar_t is used instead of TCHAR because we only perform additional work when +// Unicode is enabled and because the output of CommandLineToArgvW() is wchar_t. + +#include +#include +#include + +// Create a wchar_t array containing Unicode parameters. +#define INIT_WARGV(ARGC, ARGV) \ + int wargc; \ + const W_CHAR** const wargv = CommandLineToArgvW(GetCommandLineW(), &wargc); \ + do { \ + if (wargv == NULL || wargc != (ARGC)) { \ + fprintf(stderr, "Error: Unable to get Unicode arguments.\n"); \ + FREE_WARGV_AND_RETURN(-1); \ + } \ + } while (0) + +// Use this to get a Unicode argument (e.g. file path). +#define GET_WARGV(UNUSED, C) wargv[C] +// For cases where argv is shifted by one compared to wargv. +#define GET_WARGV_SHIFTED(UNUSED, C) wargv[(C) + 1] +#define GET_WARGV_OR_NULL() wargv + +// Release resources. LocalFree() is needed after CommandLineToArgvW(). +#define FREE_WARGV() LOCAL_FREE((W_CHAR** const)wargv) +#define LOCAL_FREE(WARGV) \ + do { \ + if ((WARGV) != NULL) LocalFree(WARGV); \ + } while (0) + +#define W_CHAR wchar_t // WCHAR without underscore might already be defined. +#define TO_W_CHAR(STR) (L##STR) + +#define WFOPEN(ARG, OPT) _wfopen((const W_CHAR*)ARG, TO_W_CHAR(OPT)) + +#define WPRINTF(STR, ...) wprintf(TO_W_CHAR(STR), __VA_ARGS__) +#define WFPRINTF(STDERR, STR, ...) fwprintf(STDERR, TO_W_CHAR(STR), __VA_ARGS__) + +#define WSTRLEN(FILENAME) wcslen((const W_CHAR*)FILENAME) +#define WSTRCMP(FILENAME, STR) wcscmp((const W_CHAR*)FILENAME, TO_W_CHAR(STR)) +#define WSTRRCHR(FILENAME, STR) wcsrchr((const W_CHAR*)FILENAME, TO_W_CHAR(STR)) +#define WSNPRINTF(A, B, STR, ...) _snwprintf(A, B, TO_W_CHAR(STR), __VA_ARGS__) + +#else + +// Unicode file paths work as is on Unix platforms, and no extra work is done on +// Windows either if Unicode is disabled. + +#define INIT_WARGV(ARGC, ARGV) + +#define GET_WARGV(ARGV, C) (ARGV)[C] +#define GET_WARGV_SHIFTED(ARGV, C) (ARGV)[C] +#define GET_WARGV_OR_NULL() NULL + +#define FREE_WARGV() +#define LOCAL_FREE(WARGV) + +#define W_CHAR char +#define TO_W_CHAR(STR) (STR) + +#define WFOPEN(ARG, OPT) fopen(ARG, OPT) + +#define WPRINTF(STR, ...) printf(STR, __VA_ARGS__) +#define WFPRINTF(STDERR, STR, ...) fprintf(STDERR, STR, __VA_ARGS__) + +#define WSTRLEN(FILENAME) strlen(FILENAME) +#define WSTRCMP(FILENAME, STR) strcmp(FILENAME, STR) +#define WSTRRCHR(FILENAME, STR) strrchr(FILENAME, STR) +#define WSNPRINTF(A, B, STR, ...) snprintf(A, B, STR, __VA_ARGS__) + +#endif // defined(_WIN32) && defined(_UNICODE) + +// Don't forget to free wargv before returning (e.g. from main). +#define FREE_WARGV_AND_RETURN(VALUE) \ + do { \ + FREE_WARGV(); \ + return (VALUE); \ + } while (0) + +#endif // WEBP_EXAMPLES_UNICODE_H_ diff --git a/examples/unicode_gif.h b/examples/unicode_gif.h new file mode 100644 index 00000000..afcd46bd --- /dev/null +++ b/examples/unicode_gif.h @@ -0,0 +1,75 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// giflib doesn't have a Unicode DGifOpenFileName(). Let's make one. +// +// Author: Yannis Guyon (yguyon@google.com) + +#ifndef WEBP_EXAMPLES_UNICODE_GIF_H_ +#define WEBP_EXAMPLES_UNICODE_GIF_H_ + +#include "./unicode.h" +#ifdef HAVE_CONFIG_H +#include "webp/config.h" // For WEBP_HAVE_GIF +#endif + +#if defined(WEBP_HAVE_GIF) + +#ifdef _WIN32 +#include // Not standard, needed for _topen and flags. +#include +#endif + +#include +#include +#include "./gifdec.h" + +#if !defined(STDIN_FILENO) +#define STDIN_FILENO 0 +#endif + +static GifFileType* DGifOpenFileUnicode(const W_CHAR* file_name, int* error) { + if (!WSTRCMP(file_name, "-")) { +#if LOCAL_GIF_PREREQ(5, 0) + return DGifOpenFileHandle(STDIN_FILENO, error); +#else + (void)error; + return DGifOpenFileHandle(STDIN_FILENO); +#endif + } + +#if defined(_WIN32) && defined(_UNICODE) + + int file_handle = _wopen(file_name, _O_RDONLY | _O_BINARY); + if (file_handle == -1) { + if (error != NULL) *error = D_GIF_ERR_OPEN_FAILED; + return NULL; + } + +#if LOCAL_GIF_PREREQ(5, 0) + return DGifOpenFileHandle(file_handle, error); +#else + return DGifOpenFileHandle(file_handle); +#endif + +#else + +#if LOCAL_GIF_PREREQ(5, 0) + return DGifOpenFileName(file_name, error); +#else + return DGifOpenFileName(file_name); +#endif + +#endif // defined(_WIN32) && defined(_UNICODE) + // DGifCloseFile() is called later. +} + +#endif // defined(WEBP_HAVE_GIF) + +#endif // WEBP_EXAMPLES_UNICODE_GIF_H_ diff --git a/examples/vwebp.c b/examples/vwebp.c index 0777daa3..bcd202f5 100644 --- a/examples/vwebp.c +++ b/examples/vwebp.c @@ -42,6 +42,7 @@ #include "../examples/example_util.h" #include "../imageio/imageio_util.h" +#include "./unicode.h" #if defined(_MSC_VER) && _MSC_VER < 1900 #define snprintf _snprintf @@ -470,9 +471,11 @@ int main(int argc, char *argv[]) { WebPDecoderConfig* const config = &kParams.config; WebPIterator* const curr = &kParams.curr_frame; + INIT_WARGV(argc, argv); + if (!WebPInitDecoderConfig(config)) { fprintf(stderr, "Library version mismatch!\n"); - return -1; + FREE_WARGV_AND_RETURN(-1); } config->options.dithering_strength = 50; config->options.alpha_dithering_strength = 100; @@ -484,7 +487,7 @@ int main(int argc, char *argv[]) { int parse_error = 0; if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { Help(); - return 0; + FREE_WARGV_AND_RETURN(0); } else if (!strcmp(argv[c], "-noicc")) { kParams.use_color_profile = 0; } else if (!strcmp(argv[c], "-nofancy")) { @@ -507,30 +510,30 @@ int main(int argc, char *argv[]) { (dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff, dec_version & 0xff, (dmux_version >> 16) & 0xff, (dmux_version >> 8) & 0xff, dmux_version & 0xff); - return 0; + FREE_WARGV_AND_RETURN(0); } else if (!strcmp(argv[c], "-mt")) { config->options.use_threads = 1; } else if (!strcmp(argv[c], "--")) { - if (c < argc - 1) kParams.file_name = argv[++c]; + if (c < argc - 1) kParams.file_name = (const char*)GET_WARGV(argv, ++c); break; } else if (argv[c][0] == '-') { printf("Unknown option '%s'\n", argv[c]); Help(); - return -1; + FREE_WARGV_AND_RETURN(-1); } else { - kParams.file_name = argv[c]; + kParams.file_name = (const char*)GET_WARGV(argv, c); } if (parse_error) { Help(); - return -1; + FREE_WARGV_AND_RETURN(-1); } } if (kParams.file_name == NULL) { printf("missing input file!!\n"); Help(); - return 0; + FREE_WARGV_AND_RETURN(0); } if (!ImgIoUtilReadFile(kParams.file_name, @@ -605,11 +608,11 @@ int main(int argc, char *argv[]) { // Should only be reached when using FREEGLUT: ClearParams(); - return 0; + FREE_WARGV_AND_RETURN(0); Error: ClearParams(); - return -1; + FREE_WARGV_AND_RETURN(-1); } #else // !WEBP_HAVE_GL diff --git a/examples/webpinfo.c b/examples/webpinfo.c index 2dcd2775..eec47845 100644 --- a/examples/webpinfo.c +++ b/examples/webpinfo.c @@ -20,6 +20,7 @@ #endif #include "../imageio/imageio_util.h" +#include "./unicode.h" #include "webp/decode.h" #include "webp/format_constants.h" #include "webp/mux_types.h" @@ -1119,19 +1120,21 @@ int main(int argc, const char* argv[]) { WebPInfoStatus webp_info_status = WEBP_INFO_OK; WebPInfo webp_info; + INIT_WARGV(argc, argv); + if (argc == 1) { HelpShort(); - return WEBP_INFO_OK; + FREE_WARGV_AND_RETURN(WEBP_INFO_OK); } // Parse command-line input. for (c = 1; c < argc; ++c) { if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { HelpShort(); - return WEBP_INFO_OK; + FREE_WARGV_AND_RETURN(WEBP_INFO_OK); } else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) { HelpLong(); - return WEBP_INFO_OK; + FREE_WARGV_AND_RETURN(WEBP_INFO_OK); } else if (!strcmp(argv[c], "-quiet")) { quiet = 1; } else if (!strcmp(argv[c], "-diag")) { @@ -1144,7 +1147,7 @@ int main(int argc, const char* argv[]) { const int version = WebPGetDecoderVersion(); printf("WebP Decoder version: %d.%d.%d\n", (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); - return 0; + FREE_WARGV_AND_RETURN(0); } else { // Assume the remaining are all input files. break; } @@ -1152,27 +1155,28 @@ int main(int argc, const char* argv[]) { if (c == argc) { HelpShort(); - return WEBP_INFO_INVALID_COMMAND; + FREE_WARGV_AND_RETURN(WEBP_INFO_INVALID_COMMAND); } // Process input files one by one. for (; c < argc; ++c) { WebPData webp_data; - const char* in_file = NULL; + const W_CHAR* in_file = NULL; WebPInfoInit(&webp_info); webp_info.quiet_ = quiet; webp_info.show_diagnosis_ = show_diag; webp_info.show_summary_ = show_summary; webp_info.parse_bitstream_ = parse_bitstream; - in_file = argv[c]; - if (in_file == NULL || !ReadFileToWebPData(in_file, &webp_data)) { + in_file = GET_WARGV(argv, c); + if (in_file == NULL || + !ReadFileToWebPData((const char*)in_file, &webp_data)) { webp_info_status = WEBP_INFO_INVALID_COMMAND; - fprintf(stderr, "Failed to open input file %s.\n", in_file); + WFPRINTF(stderr, "Failed to open input file %s.\n", in_file); continue; } - if (!webp_info.quiet_) printf("File: %s\n", in_file); + if (!webp_info.quiet_) WPRINTF("File: %s\n", in_file); webp_info_status = AnalyzeWebP(&webp_info, &webp_data); WebPDataClear(&webp_data); } - return webp_info_status; + FREE_WARGV_AND_RETURN(webp_info_status); } diff --git a/examples/webpmux.c b/examples/webpmux.c index 2db4aaf6..ccea83ae 100644 --- a/examples/webpmux.c +++ b/examples/webpmux.c @@ -62,6 +62,7 @@ #include "webp/mux.h" #include "../examples/example_util.h" #include "../imageio/imageio_util.h" +#include "./unicode.h" //------------------------------------------------------------------------------ // Config object to parse command-line arguments. @@ -390,23 +391,25 @@ static int CreateMux(const char* const filename, WebPMux** mux) { *mux = WebPMuxCreate(&bitstream, 1); WebPDataClear(&bitstream); if (*mux != NULL) return 1; - fprintf(stderr, "Failed to create mux object from file %s.\n", filename); + WFPRINTF(stderr, "Failed to create mux object from file %s.\n", + (const W_CHAR*)filename); return 0; } static int WriteData(const char* filename, const WebPData* const webpdata) { int ok = 0; - FILE* fout = strcmp(filename, "-") ? fopen(filename, "wb") - : ImgIoUtilSetBinaryMode(stdout); + FILE* fout = WSTRCMP(filename, "-") ? WFOPEN(filename, "wb") + : ImgIoUtilSetBinaryMode(stdout); if (fout == NULL) { - fprintf(stderr, "Error opening output WebP file %s!\n", filename); + WFPRINTF(stderr, "Error opening output WebP file %s!\n", + (const W_CHAR*)filename); return 0; } if (fwrite(webpdata->bytes, webpdata->size, 1, fout) != 1) { - fprintf(stderr, "Error writing file %s!\n", filename); + WFPRINTF(stderr, "Error writing file %s!\n", (const W_CHAR*)filename); } else { - fprintf(stderr, "Saved file %s (%d bytes)\n", - filename, (int)webpdata->size); + WFPRINTF(stderr, "Saved file %s (%d bytes)\n", + (const W_CHAR*)filename, (int)webpdata->size); ok = 1; } if (fout != stdout) fclose(fout); @@ -612,13 +615,16 @@ static int ValidateCommandLine(const CommandLineArguments* const cmd_args, CHECK_NUM_ARGS_AT_MOST(NUM, LABEL); // Parses command-line arguments to fill up config object. Also performs some -// semantic checks. -static int ParseCommandLine(Config* config) { +// semantic checks. unicode_argv contains wchar_t arguments or is null. +static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) { int i = 0; int feature_arg_index = 0; int ok = 1; int argc = config->cmd_args_.argc_; const char* const* argv = config->cmd_args_.argv_; + // Unicode file paths will be used if available. + const char* const* wargv = + (unicode_argv != NULL) ? (const char**)(unicode_argv + 1) : argv; while (i < argc) { FeatureArg* const arg = &config->args_[feature_arg_index]; @@ -696,7 +702,7 @@ static int ParseCommandLine(Config* config) { i += 2; } else if (!strcmp(argv[i], "-o")) { CHECK_NUM_ARGS_AT_LEAST(2, ErrParse); - config->output_ = argv[i + 1]; + config->output_ = wargv[i + 1]; i += 2; } else if (!strcmp(argv[i], "-info")) { CHECK_NUM_ARGS_EXACTLY(2, ErrParse); @@ -705,24 +711,26 @@ static int ParseCommandLine(Config* config) { } else { config->action_type_ = ACTION_INFO; config->arg_count_ = 0; - config->input_ = argv[i + 1]; + config->input_ = wargv[i + 1]; } i += 2; } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help")) { PrintHelp(); DeleteConfig(config); + LOCAL_FREE((W_CHAR** const)unicode_argv); exit(0); } else if (!strcmp(argv[i], "-version")) { const int version = WebPGetMuxVersion(); printf("%d.%d.%d\n", (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); DeleteConfig(config); + LOCAL_FREE((W_CHAR** const)unicode_argv); exit(0); } else if (!strcmp(argv[i], "--")) { if (i < argc - 1) { ++i; if (config->input_ == NULL) { - config->input_ = argv[i]; + config->input_ = wargv[i]; } else { ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n", argv[i], ErrParse); @@ -747,7 +755,7 @@ static int ParseCommandLine(Config* config) { } if (config->action_type_ == ACTION_SET) { CHECK_NUM_ARGS_AT_LEAST(2, ErrParse); - arg->filename_ = argv[i + 1]; + arg->filename_ = wargv[i + 1]; ++feature_arg_index; i += 2; } else { @@ -762,7 +770,7 @@ static int ParseCommandLine(Config* config) { i += 2; } else { // Assume input file. if (config->input_ == NULL) { - config->input_ = argv[i]; + config->input_ = wargv[i]; } else { ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n", argv[i], ErrParse); @@ -808,8 +816,8 @@ static int ValidateConfig(Config* const config) { } // Create config object from command-line arguments. -static int InitializeConfig(int argc, const char* argv[], - Config* const config) { +static int InitializeConfig(int argc, const char* argv[], Config* const config, + const W_CHAR** const unicode_argv) { int num_feature_args = 0; int ok; @@ -830,7 +838,7 @@ static int InitializeConfig(int argc, const char* argv[], } // Parse command-line. - if (!ParseCommandLine(config) || !ValidateConfig(config)) { + if (!ParseCommandLine(config, unicode_argv) || !ValidateConfig(config)) { ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1); } @@ -1140,14 +1148,18 @@ static int Process(const Config* config) { int main(int argc, const char* argv[]) { Config config; - int ok = InitializeConfig(argc - 1, argv + 1, &config); + int ok; + + INIT_WARGV(argc, argv); + + ok = InitializeConfig(argc - 1, argv + 1, &config, GET_WARGV_OR_NULL()); if (ok) { ok = Process(&config); } else { PrintHelp(); } DeleteConfig(&config); - return !ok; + FREE_WARGV_AND_RETURN(!ok); } //------------------------------------------------------------------------------ diff --git a/extras/get_disto.c b/extras/get_disto.c index b4061477..646b6391 100644 --- a/extras/get_disto.c +++ b/extras/get_disto.c @@ -26,6 +26,7 @@ #include "webp/encode.h" #include "imageio/image_dec.h" #include "imageio/imageio_util.h" +#include "../examples/unicode.h" static size_t ReadPicture(const char* const filename, WebPPicture* const pic, int keep_alpha) { @@ -48,7 +49,8 @@ static size_t ReadPicture(const char* const filename, WebPPicture* const pic, End: if (!ok) { - fprintf(stderr, "Error! Could not process file %s\n", filename); + WFPRINTF(stderr, "Error! Could not process file %s\n", + (const W_CHAR*)filename); } free((void*)data); return ok ? data_size : 0; @@ -239,9 +241,11 @@ int main(int argc, const char *argv[]) { const char* name2 = NULL; const char* output = NULL; + INIT_WARGV(argc, argv); + if (!WebPPictureInit(&pic1) || !WebPPictureInit(&pic2)) { fprintf(stderr, "Can't init pictures\n"); - return 1; + FREE_WARGV_AND_RETURN(1); } for (c = 1; c < argc; ++c) { @@ -263,11 +267,11 @@ int main(int argc, const char *argv[]) { fprintf(stderr, "missing file name after %s option.\n", argv[c - 1]); goto End; } - output = argv[c]; + output = (const char*)GET_WARGV(argv, c); } else if (name1 == NULL) { - name1 = argv[c]; + name1 = (const char*)GET_WARGV(argv, c); } else { - name2 = argv[c]; + name2 = (const char*)GET_WARGV(argv, c); } } if (help || name1 == NULL || name2 == NULL) { @@ -347,5 +351,5 @@ int main(int argc, const char *argv[]) { End: WebPPictureFree(&pic1); WebPPictureFree(&pic2); - return ret; + FREE_WARGV_AND_RETURN(ret); } diff --git a/extras/vwebp_sdl.c b/extras/vwebp_sdl.c index 69171b9a..d1ee41f9 100644 --- a/extras/vwebp_sdl.c +++ b/extras/vwebp_sdl.c @@ -25,6 +25,7 @@ #include "webp_to_sdl.h" #include "webp/decode.h" #include "imageio/imageio_util.h" +#include "../examples/unicode.h" #if defined(WEBP_HAVE_JUST_SDL_H) #include @@ -51,19 +52,22 @@ static void ProcessEvents(void) { int main(int argc, char* argv[]) { int c; int ok = 0; + + INIT_WARGV(argc, argv); + for (c = 1; c < argc; ++c) { const char* file = NULL; const uint8_t* webp = NULL; size_t webp_size = 0; if (!strcmp(argv[c], "-h")) { printf("Usage: %s [-h] image.webp [more_files.webp...]\n", argv[0]); - return 0; + FREE_WARGV_AND_RETURN(0); } else { - file = argv[c]; + file = (const char*)GET_WARGV(argv, c); } if (file == NULL) continue; if (!ImgIoUtilReadFile(file, &webp, &webp_size)) { - fprintf(stderr, "Error opening file: %s\n", file); + WFPRINTF(stderr, "Error opening file: %s\n", (const W_CHAR*)file); goto Error; } if (webp_size != (size_t)(int)webp_size) { @@ -73,7 +77,7 @@ int main(int argc, char* argv[]) { ok = WebpToSDL((const char*)webp, (int)webp_size); free((void*)webp); if (!ok) { - fprintf(stderr, "Error decoding file %s\n", file); + WFPRINTF(stderr, "Error decoding file %s\n", (const W_CHAR*)file); goto Error; } ProcessEvents(); @@ -82,7 +86,7 @@ int main(int argc, char* argv[]) { Error: SDL_Quit(); - return ok ? 0 : 1; + FREE_WARGV_AND_RETURN(ok ? 0 : 1); } #else // !WEBP_HAVE_SDL diff --git a/extras/webp_quality.c b/extras/webp_quality.c index 3f6ba202..e76c061d 100644 --- a/extras/webp_quality.c +++ b/extras/webp_quality.c @@ -13,26 +13,30 @@ #include "extras/extras.h" #include "imageio/imageio_util.h" +#include "../examples/unicode.h" int main(int argc, const char *argv[]) { int c; int quiet = 0; int ok = 1; + + INIT_WARGV(argc, argv); + for (c = 1; ok && c < argc; ++c) { if (!strcmp(argv[c], "-quiet")) { quiet = 1; } else if (!strcmp(argv[c], "-help") || !strcmp(argv[c], "-h")) { printf("webp_quality [-h][-quiet] webp_files...\n"); - return 0; + FREE_WARGV_AND_RETURN(0); } else { - const char* const filename = argv[c]; + const char* const filename = (const char*)GET_WARGV(argv, c); const uint8_t* data = NULL; size_t data_size = 0; int q; ok = ImgIoUtilReadFile(filename, &data, &data_size); if (!ok) break; q = VP8EstimateQuality(data, data_size); - if (!quiet) printf("[%s] ", filename); + if (!quiet) WPRINTF("[%s] ", (const W_CHAR*)filename); if (q < 0) { fprintf(stderr, "Not a WebP file, or not a lossy WebP file.\n"); ok = 0; @@ -46,5 +50,5 @@ int main(int argc, const char *argv[]) { free((void*)data); } } - return ok ? 0 : 1; + FREE_WARGV_AND_RETURN(ok ? 0 : 1); } diff --git a/imageio/image_enc.c b/imageio/image_enc.c index d4134905..fccb92bf 100644 --- a/imageio/image_enc.c +++ b/imageio/image_enc.c @@ -29,11 +29,13 @@ // code with COBJMACROS. #include // CreateStreamOnHGlobal() #include +#include #include #include #endif #include "./imageio_util.h" +#include "../examples/unicode.h" //------------------------------------------------------------------------------ // PNG @@ -61,11 +63,12 @@ static HRESULT CreateOutputStream(const char* out_file_name, // Output to a memory buffer. This is freed when 'stream' is released. IFS(CreateStreamOnHGlobal(NULL, TRUE, stream)); } else { - IFS(SHCreateStreamOnFileA(out_file_name, STGM_WRITE | STGM_CREATE, stream)); + IFS(SHCreateStreamOnFile((const LPTSTR)out_file_name, + STGM_WRITE | STGM_CREATE, stream)); } if (FAILED(hr)) { - fprintf(stderr, "Error opening output file %s (%08lx)\n", - out_file_name, hr); + _ftprintf(stderr, _T("Error opening output file %s (%08lx)\n"), + (const LPTSTR)out_file_name, hr); } return hr; } @@ -549,7 +552,8 @@ int WebPSaveImage(const WebPDecBuffer* const buffer, const char* const out_file_name) { FILE* fout = NULL; int needs_open_file = 1; - const int use_stdout = (out_file_name != NULL) && !strcmp(out_file_name, "-"); + const int use_stdout = + (out_file_name != NULL) && !WSTRCMP(out_file_name, "-"); int ok = 1; if (buffer == NULL || out_file_name == NULL) return 0; @@ -560,9 +564,10 @@ int WebPSaveImage(const WebPDecBuffer* const buffer, if (needs_open_file) { fout = use_stdout ? ImgIoUtilSetBinaryMode(stdout) - : fopen(out_file_name, "wb"); + : WFOPEN(out_file_name, "wb"); if (fout == NULL) { - fprintf(stderr, "Error opening output file %s\n", out_file_name); + WFPRINTF(stderr, "Error opening output file %s\n", + (const W_CHAR*)out_file_name); return 0; } } diff --git a/imageio/imageio_util.c b/imageio/imageio_util.c index 3a4ade0d..9833dcbd 100644 --- a/imageio/imageio_util.c +++ b/imageio/imageio_util.c @@ -18,6 +18,7 @@ #endif #include #include +#include "../examples/unicode.h" // ----------------------------------------------------------------------------- // File I/O @@ -73,7 +74,7 @@ int ImgIoUtilReadFile(const char* const file_name, uint8_t* file_data; size_t file_size; FILE* in; - const int from_stdin = (file_name == NULL) || !strcmp(file_name, "-"); + const int from_stdin = (file_name == NULL) || !WSTRCMP(file_name, "-"); if (from_stdin) return ImgIoUtilReadFromStdin(data, data_size); @@ -81,9 +82,9 @@ int ImgIoUtilReadFile(const char* const file_name, *data = NULL; *data_size = 0; - in = fopen(file_name, "rb"); + in = WFOPEN(file_name, "rb"); if (in == NULL) { - fprintf(stderr, "cannot open input file '%s'\n", file_name); + WFPRINTF(stderr, "cannot open input file '%s'\n", (const W_CHAR*)file_name); return 0; } fseek(in, 0, SEEK_END); @@ -93,16 +94,16 @@ int ImgIoUtilReadFile(const char* const file_name, file_data = (uint8_t*)malloc(file_size + 1); if (file_data == NULL) { fclose(in); - fprintf(stderr, "memory allocation failure when reading file %s\n", - file_name); + WFPRINTF(stderr, "memory allocation failure when reading file %s\n", + (const W_CHAR*)file_name); return 0; } ok = (fread(file_data, file_size, 1, in) == 1); fclose(in); if (!ok) { - fprintf(stderr, "Could not read %d bytes of data from file %s\n", - (int)file_size, file_name); + WFPRINTF(stderr, "Could not read %d bytes of data from file %s\n", + (int)file_size, (const W_CHAR*)file_name); free(file_data); return 0; } @@ -118,14 +119,15 @@ int ImgIoUtilWriteFile(const char* const file_name, const uint8_t* data, size_t data_size) { int ok; FILE* out; - const int to_stdout = (file_name == NULL) || !strcmp(file_name, "-"); + const int to_stdout = (file_name == NULL) || !WSTRCMP(file_name, "-"); if (data == NULL) { return 0; } - out = to_stdout ? ImgIoUtilSetBinaryMode(stdout) : fopen(file_name, "wb"); + out = to_stdout ? ImgIoUtilSetBinaryMode(stdout) : WFOPEN(file_name, "wb"); if (out == NULL) { - fprintf(stderr, "Error! Cannot open output file '%s'\n", file_name); + WFPRINTF(stderr, "Error! Cannot open output file '%s'\n", + (const W_CHAR*)file_name); return 0; } ok = (fwrite(data, data_size, 1, out) == 1); diff --git a/imageio/webpdec.c b/imageio/webpdec.c index a9d06548..785eef39 100644 --- a/imageio/webpdec.c +++ b/imageio/webpdec.c @@ -22,6 +22,7 @@ #include "webp/decode.h" #include "webp/demux.h" #include "webp/encode.h" +#include "../examples/unicode.h" #include "./imageio_util.h" #include "./metadata.h" @@ -43,7 +44,7 @@ static void PrintAnimationWarning(const WebPDecoderConfig* const config) { } void PrintWebPError(const char* const in_file, int status) { - fprintf(stderr, "Decoding of %s failed.\n", in_file); + WFPRINTF(stderr, "Decoding of %s failed.\n", (const W_CHAR*)in_file); fprintf(stderr, "Status: %d", status); if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) { fprintf(stderr, "(%s)", kStatusMessages[status]); diff --git a/imageio/wicdec.c b/imageio/wicdec.c index 3ee72a89..249d1c21 100644 --- a/imageio/wicdec.c +++ b/imageio/wicdec.c @@ -29,12 +29,14 @@ // code with COBJMACROS. #include // CreateStreamOnHGlobal() #include +#include #include #include -#include "webp/encode.h" +#include "../examples/unicode.h" #include "./imageio_util.h" #include "./metadata.h" +#include "webp/encode.h" #define IFS(fn) \ do { \ @@ -85,7 +87,7 @@ WEBP_DEFINE_GUID(GUID_WICPixelFormat64bppRGBA_, static HRESULT OpenInputStream(const char* filename, IStream** stream) { HRESULT hr = S_OK; - if (!strcmp(filename, "-")) { + if (!WSTRCMP(filename, "-")) { const uint8_t* data = NULL; size_t data_size = 0; const int ok = ImgIoUtilReadFile(filename, &data, &data_size); @@ -108,11 +110,12 @@ static HRESULT OpenInputStream(const char* filename, IStream** stream) { hr = E_FAIL; } } else { - IFS(SHCreateStreamOnFileA(filename, STGM_READ, stream)); + IFS(SHCreateStreamOnFile((const LPTSTR)filename, STGM_READ, stream)); } if (FAILED(hr)) { - fprintf(stderr, "Error opening input file %s (%08lx)\n", filename, hr); + _ftprintf(stderr, _T("Error opening input file %s (%08lx)\n"), + (const LPTSTR)filename, hr); } return hr; }