src/8svx.c | 3 +- src/adpcm.c | 1 + src/effects_i.c | 3 +- src/formats.c | 9 ++- src/libsox.c | 2 + src/libsox_i.c | 7 +- src/noiseprof.c | 3 +- src/sox.c | 37 +++++++--- src/unicode_support.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/unicode_support.h | 49 +++++++++++++ src/util.h | 5 ++ 11 files changed, 299 insertions(+), 19 deletions(-) diff --git a/src/8svx.c b/src/8svx.c index 63c30e6..fd712f4 100644 --- a/src/8svx.c +++ b/src/8svx.c @@ -1,6 +1,7 @@ /* Amiga 8SVX format handler: W V Neisius, February 1992 */ #include "sox_i.h" +#include "unicode_support.h" #include #include @@ -161,7 +162,7 @@ static int startread(sox_format_t * ft) chan1_pos = lsx_tell(ft); for (i = 1; i < channels; i++) { - if ((p->ch[i] = fopen(ft->filename, "rb")) == NULL) + if ((p->ch[i] = fopen_utf8(ft->filename, "rb")) == NULL) { lsx_fail_errno(ft,errno,"Can't open channel file '%s'", ft->filename); diff --git a/src/adpcm.c b/src/adpcm.c index 2e13867..15c27c2 100644 --- a/src/adpcm.c +++ b/src/adpcm.c @@ -33,6 +33,7 @@ #include "sox_i.h" #include "adpcm.h" +#include "unicode_support.h" #include #include diff --git a/src/effects_i.c b/src/effects_i.c index 7d72166..65d6a0b 100644 --- a/src/effects_i.c +++ b/src/effects_i.c @@ -20,6 +20,7 @@ #define LSX_EFF_ALIAS #include "sox_i.h" +#include "unicode_support.h" #include #include @@ -355,7 +356,7 @@ FILE * lsx_open_input_file(sox_effect_t * effp, char const * filename) effp->global_info->global_info->stdin_in_use_by = effp->handler.name; file = stdin; } - else if (!(file = fopen(filename, "r"))) { + else if (!(file = fopen_utf8(filename, "r"))) { lsx_fail("couldn't open file %s: %s", filename, strerror(errno)); return NULL; } diff --git a/src/formats.c b/src/formats.c index 785eca7..31993a5 100644 --- a/src/formats.c +++ b/src/formats.c @@ -19,6 +19,7 @@ */ #include "sox_i.h" +#include "unicode_support.h" #include #include @@ -397,7 +398,7 @@ static FILE * xfopen(char const * identifier, char const * mode, lsx_io_type * i #endif return f; } - return fopen(identifier, mode); + return fopen_utf8(identifier, mode); } /* Hack to rewind pipes (a small amount). @@ -848,8 +849,8 @@ static sox_format_t * open_write( ft->fp = stdout; } else { - struct stat st; - if (!stat(path, &st) && (st.st_mode & S_IFMT) == S_IFREG && + struct _stat st; + if (!stat_utf8(path, &st) && (st.st_mode & S_IFMT) == S_IFREG && (overwrite_permitted && !overwrite_permitted(path))) { lsx_fail("permission to overwrite `%s' denied", path); goto error; @@ -859,7 +860,7 @@ static sox_format_t * open_write( buffer? fmemopen(buffer, buffer_size, "w+b") : buffer_ptr? open_memstream(buffer_ptr, buffer_size_ptr) : #endif - fopen(path, "w+b"); + fopen_utf8(path, "w+b"); if (ft->fp == NULL) { lsx_fail("can't open output file `%s': %s", path, strerror(errno)); goto error; diff --git a/src/libsox.c b/src/libsox.c index 75354e4..a766aa9 100644 --- a/src/libsox.c +++ b/src/libsox.c @@ -19,6 +19,8 @@ */ #include "sox_i.h" +#include "unicode_support.h" + #include const char *sox_version(void) diff --git a/src/libsox_i.c b/src/libsox_i.c index 8a7074a..b498cc0 100644 --- a/src/libsox_i.c +++ b/src/libsox_i.c @@ -20,6 +20,7 @@ #include "sox_i.h" +#include "unicode_support.h" #ifdef HAVE_IO_H #include @@ -48,8 +49,8 @@ #ifdef WIN32 static int check_dir(char * buf, size_t buflen, char const * name) { - struct stat st; - if (!name || stat(name, &st) || (st.st_mode & S_IFMT) != S_IFDIR) + struct _stat st; + if (!name || stat_utf8(name, &st) || (st.st_mode & S_IFMT) != S_IFDIR) { return 0; } @@ -102,7 +103,7 @@ FILE * lsx_tmpfile(void) fildes = mkstemp(name); #ifdef HAVE_UNISTD_H lsx_debug(FAKE_MKSTEMP "mkstemp, name=%s (unlinked)", name); - unlink(name); + unlink_utf8(name); #else lsx_debug(FAKE_MKSTEMP "mkstemp, name=%s (O_TEMPORARY)", name); #endif diff --git a/src/noiseprof.c b/src/noiseprof.c index 603402f..d46c280 100644 --- a/src/noiseprof.c +++ b/src/noiseprof.c @@ -19,6 +19,7 @@ */ #include "noisered.h" +#include "unicode_support.h" #include #include @@ -75,7 +76,7 @@ static int sox_noiseprof_start(sox_effect_t * effp) effp->global_info->global_info->stdout_in_use_by = effp->handler.name; data->output_file = stdout; } - else if ((data->output_file = fopen(data->output_filename, "w")) == NULL) { + else if ((data->output_file = fopen_utf8(data->output_filename, "w")) == NULL) { lsx_fail("Couldn't open profile file %s: %s", data->output_filename, strerror(errno)); return SOX_EOF; } diff --git a/src/sox.c b/src/sox.c index 8160fc1..74cad4d 100644 --- a/src/sox.c +++ b/src/sox.c @@ -24,6 +24,7 @@ #include "soxconfig.h" #include "sox.h" #include "util.h" +#include "unicode_support.h" #include #include @@ -236,12 +237,12 @@ static void cleanup(void) if (file_count) { if (ofile->ft) { if (!success && ofile->ft->fp) { /* If we failed part way through */ - struct stat st; /* writing a normal file, remove it. */ - if (!stat(ofile->ft->filename, &st) && + struct _stat st; /* writing a normal file, remove it. */ + if (!stat_utf8(ofile->ft->filename, &st) && (st.st_mode & S_IFMT) == S_IFREG) - unlink(ofile->ft->filename); + unlink_utf8(ofile->ft->filename); } - sox_close(ofile->ft); /* Assume we can unlink a file before closing it. */ + sox_close(ofile->ft); /* Assume we can unlink_utf8 a file before closing it. */ } free(ofile->filename); free(ofile); @@ -293,8 +294,8 @@ static char const * str_time(double seconds) static char const * size_and_bitrate(sox_format_t * ft, char const * * text) { - struct stat st; /* ft->fp may validly be NULL, so stat not fstat */ - if (stat(ft->filename, &st) || (st.st_mode & S_IFMT) != S_IFREG) + struct _stat st; /* ft->fp may validly be NULL, so stat not fstat */ + if (stat_utf8(ft->filename, &st) || (st.st_mode & S_IFMT) != S_IFREG) return NULL; if (ft->signal.length && ft->signal.channels && ft->signal.rate && text) { double secs = ft->signal.length / ft->signal.channels / ft->signal.rate; @@ -906,7 +907,7 @@ static char * * strtoargv(char * s, int * argc) static void read_user_effects(char const *filename) { - FILE *file = fopen(filename, "rt"); + FILE *file = fopen_utf8(filename, "rt"); const size_t buffer_size_step = 1024; size_t buffer_size = buffer_size_step; char *s = lsx_malloc(buffer_size); /* buffer for one input line */ @@ -1269,6 +1270,7 @@ static void display_status(sox_bool all_done) lsx_sigfigs3((double)output_samples), vu(0), vu(1), headroom(), lsx_sigfigs3((double)total_clips())); } + fflush(stderr); if (all_done) fputc('\n', stderr); } @@ -2127,7 +2129,7 @@ static void read_comment_file(sox_comments_t * comments, char const * const file int c; size_t text_length = 100; char * text = lsx_malloc(text_length + 1); - FILE * file = fopen(filename, "rt"); + FILE * file = fopen_utf8(filename, "rt"); if (file == NULL) { lsx_fail("Cannot open comment file `%s'", filename); @@ -2853,7 +2855,7 @@ static sox_bool cmp_comment_text(char const * c1, char const * c2) return c1 && c2 && !strcasecmp(c1, c2); } -int main(int argc, char **argv) +static int sox_main(int argc, char **argv) { size_t i; char mybase[6]; @@ -3055,3 +3057,20 @@ int main(int argc, char **argv) return 0; } + +int main( int argc, char **argv ) +{ + int sox_argc; + char **sox_argv; + int exit_code; + + init_console_utf8(); + init_commandline_arguments_utf8(&sox_argc, &sox_argv); + + exit_code = sox_main(sox_argc, sox_argv); + + uninit_console_utf8(); + free_commandline_arguments_utf8(&sox_argc, &sox_argv); + + return exit_code; +} diff --git a/src/unicode_support.c b/src/unicode_support.c new file mode 100644 index 0000000..f2a0a9e --- /dev/null +++ b/src/unicode_support.c @@ -0,0 +1,199 @@ +/* Copyright (c) 2004-2012 LoRd_MuldeR + File: unicode_support.c + + This file was originally part of a patch included with LameXP, + released under the same license as the original audio tools. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64 + +#include "unicode_support.h" + +#include +#include + +static UINT g_old_output_cp = ((UINT)-1); + +char *utf16_to_utf8(const wchar_t *input) +{ + char *Buffer; + int BuffSize = 0, Result = 0; + + BuffSize = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL); + Buffer = (char*) malloc(sizeof(char) * BuffSize); + if(Buffer) + { + Result = WideCharToMultiByte(CP_UTF8, 0, input, -1, Buffer, BuffSize, NULL, NULL); + } + + return ((Result > 0) && (Result <= BuffSize)) ? Buffer : NULL; +} + +char *utf16_to_ansi(const wchar_t *input) +{ + char *Buffer; + int BuffSize = 0, Result = 0; + + BuffSize = WideCharToMultiByte(CP_ACP, 0, input, -1, NULL, 0, NULL, NULL); + Buffer = (char*) malloc(sizeof(char) * BuffSize); + if(Buffer) + { + Result = WideCharToMultiByte(CP_ACP, 0, input, -1, Buffer, BuffSize, NULL, NULL); + } + + return ((Result > 0) && (Result <= BuffSize)) ? Buffer : NULL; +} + +wchar_t *utf8_to_utf16(const char *input) +{ + wchar_t *Buffer; + int BuffSize = 0, Result = 0; + + BuffSize = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0); + Buffer = (wchar_t*) malloc(sizeof(wchar_t) * BuffSize); + if(Buffer) + { + Result = MultiByteToWideChar(CP_UTF8, 0, input, -1, Buffer, BuffSize); + } + + return ((Result > 0) && (Result <= BuffSize)) ? Buffer : NULL; +} + +void init_commandline_arguments_utf8(int *argc, char ***argv) +{ + int i, nArgs; + LPWSTR *szArglist; + + szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs); + + if(NULL == szArglist) + { + fprintf(stderr, "\nFATAL: CommandLineToArgvW failed\n\n"); + exit(-1); + } + + *argv = (char**) malloc(sizeof(char*) * nArgs); + *argc = nArgs; + + if(NULL == *argv) + { + fprintf(stderr, "\nFATAL: Malloc failed\n\n"); + exit(-1); + } + + for(i = 0; i < nArgs; i++) + { + (*argv)[i] = utf16_to_utf8(szArglist[i]); + if(NULL == (*argv)[i]) + { + fprintf(stderr, "\nFATAL: utf16_to_utf8 failed\n\n"); + exit(-1); + } + } + + LocalFree(szArglist); +} + +void free_commandline_arguments_utf8(int *argc, char ***argv) +{ + int i = 0; + + if(*argv != NULL) + { + for(i = 0; i < *argc; i++) + { + if((*argv)[i] != NULL) + { + free((*argv)[i]); + (*argv)[i] = NULL; + } + } + free(*argv); + *argv = NULL; + } +} + +FILE *fopen_utf8(const char *filename_utf8, const char *mode_utf8) +{ + FILE *ret = NULL; + wchar_t *filename_utf16 = utf8_to_utf16(filename_utf8); + wchar_t *mode_utf16 = utf8_to_utf16(mode_utf8); + + if(filename_utf16 && mode_utf16) + { + FILE *fh = NULL; + int err = _wfopen_s(&fh, filename_utf16, mode_utf16); + if(err == 0) ret = fh; + } + + if(filename_utf16) free(filename_utf16); + if(mode_utf16) free(mode_utf16); + + return ret; +} + +int stat_utf8(const char *path_utf8, struct _stat *buf) +{ + int ret = -1; + + wchar_t *path_utf16 = utf8_to_utf16(path_utf8); + if(path_utf16) + { + ret = _wstat(path_utf16, buf); + free(path_utf16); + } + + return ret; +} + +int unlink_utf8(const char *path_utf8) +{ + int ret = -1; + + wchar_t *path_utf16 = utf8_to_utf16(path_utf8); + if(path_utf16) + { + ret = _wunlink(path_utf16); + free(path_utf16); + } + + return ret; +} + +void init_console_utf8(void) +{ + g_old_output_cp = GetConsoleOutputCP(); + SetConsoleOutputCP(CP_UTF8); +} + +void uninit_console_utf8(void) +{ + if(g_old_output_cp != ((UINT)-1)) + { + SetConsoleOutputCP(g_old_output_cp); + } +} + +#endif \ No newline at end of file diff --git a/src/unicode_support.h b/src/unicode_support.h new file mode 100644 index 0000000..cf55719 --- /dev/null +++ b/src/unicode_support.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2004-2012 LoRd_MuldeR + File: unicode_support.h + + This file was originally part of a patch included with LameXP, + released under the same license as the original audio tools. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef UNICODE_SUPPORT_H_INCLUDED +#define UNICODE_SUPPORT_H_INCLUDED + +#include +#include + +#define WIN_UNICODE 1 + +char *utf16_to_utf8(const wchar_t *input); +char *utf16_to_ansi(const wchar_t *input); +wchar_t *utf8_to_utf16(const char *input); +void init_commandline_arguments_utf8(int *argc, char ***argv); +void free_commandline_arguments_utf8(int *argc, char ***argv); +FILE *fopen_utf8(const char *filename_utf8, const char *mode_utf8); +int stat_utf8(const char *path_utf8, struct _stat *buf); +int unlink_utf8(const char *path_utf8); +void init_console_utf8(void); +void uninit_console_utf8(void); + +#endif \ No newline at end of file diff --git a/src/util.h b/src/util.h index 89bbe75..941d727 100644 --- a/src/util.h +++ b/src/util.h @@ -91,6 +91,10 @@ #ifdef _MSC_VER +#define inline __inline +#define snprintf _snprintf + +/* #define __STDC__ 1 #define O_BINARY _O_BINARY #define O_CREAT _O_CREAT @@ -140,6 +144,7 @@ #define off_t __int64 #define HAVE_FSEEKO 1 #endif +*/ #elif defined(__MINGW32__)