Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replaces the command line interface from ANSI to UNICODE on Windows. #1411

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/bindings/fluid_filerenderer.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,32 @@ new_fluid_file_renderer(fluid_synth_t *synth)
goto error_recovery;
}

#ifdef _WIN32
if (0 == FLUID_STRCMP("-", filename))
dev->sndfile = sf_open(filename, SFM_WRITE, &info); // pipe open
else
{
int u16_count;
LPWSTR filename_wchar;
dev->sndfile = NULL;

// utf-8 filename to utf-16 filename_wchar
if (1 > (u16_count = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename, -1, NULL, 0)))
FLUID_LOG(FLUID_ERR, "Failed to convert UTF8 string to wide char string");
else if (NULL == (filename_wchar = (LPWSTR)FLUID_ARRAY(WCHAR, u16_count)))
FLUID_LOG(FLUID_ERR, "Out of memory");
else
{
if (u16_count != MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename, -1, filename_wchar, u16_count))
FLUID_LOG(FLUID_ERR, "Failed to convert UTF8 string to wide char string");
else
dev->sndfile = sf_wchar_open(filename_wchar, SFM_WRITE, &info); // file open
FLUID_FREE(filename_wchar);
}
}
#else
dev->sndfile = sf_open(filename, SFM_WRITE, &info);
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in http://libsndfile.github.io/libsndfile/api.html#open :

The sf_open() function opens the sound file at the specified path. The filename is byte encoded, but may be utf-8 on Linux, while on Mac OS X it will use the filesystem character set. On Windows, there is also a Windows specific sf_wchar_open() that takes a UTF16_BE encoded filename.

It is quite absurd that libsndfile does not allow UTF-8 file names in Windows like it does on Linux. It may be acceptable this workaround in Fluidsynth, but this should be fixed upstream (libsndfile) as well.

Even more funny: in 1.1.0 you may find this change:

Use UTF-8 as internal path encoding on Windows platform.

This is an internal change to unify and simplify the handling of file paths.

On the Windows platform, the file path is always converted to UTF-8 and converted to UTF-16 only for calls to WinAPI functions.

The behavior of the functions for opening files on other platforms does notchange.


if(!dev->sndfile)
{
Expand Down
160 changes: 73 additions & 87 deletions src/fluidsynth.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,6 @@ void print_help(fluid_settings_t *settings);
void print_welcome(void);
void print_configure(void);
void fluid_wasapi_device_enumerate(void);
#ifdef _WIN32
static char* win32_ansi_to_utf8(const char* ansi_null_terminated_string);
#endif

/*
* the globals
Expand Down Expand Up @@ -125,21 +122,11 @@ int process_o_cmd_line_option(fluid_settings_t *settings, char *optarg)
break;

case FLUID_STR_TYPE: {
char *u8_val = val;
#if defined(_WIN32)
u8_val = win32_ansi_to_utf8(val);
#endif
if(fluid_settings_setstr(settings, optarg, u8_val) != FLUID_OK)
if(fluid_settings_setstr(settings, optarg, val) != FLUID_OK)
{
fprintf(stderr, "Failed to set string parameter '%s'\n", optarg);
#if defined(_WIN32)
free(u8_val);
#endif
return FLUID_FAILED;
}
#if defined(_WIN32)
free(u8_val);
#endif
break;
}
default:
Expand Down Expand Up @@ -167,45 +154,6 @@ print_pretty_int(int i)
}
}

#ifdef _WIN32
/* Function using win32 api to convert ANSI encoding string to UTF8 encoding string */
static char*
win32_ansi_to_utf8(const char* ansi_null_terminated_string)
{
LPWSTR u16_buf = NULL;
char *u8_buf = NULL;
fluid_return_val_if_fail(ansi_null_terminated_string != NULL, NULL);
do
{
int u16_count, u8_byte_count;
u16_count = MultiByteToWideChar(CP_ACP, 0, ansi_null_terminated_string, -1, NULL, 0);
if (u16_count == 0)
{
fprintf(stderr, "Failed to convert ANSI string to wide char string\n");
break;
}
u16_buf = malloc(u16_count * sizeof(WCHAR));
if (u16_buf == NULL)
{
fprintf(stderr, "Out of memory\n");
break;
}
u16_count = MultiByteToWideChar(CP_ACP, 0, ansi_null_terminated_string, -1, u16_buf, u16_count);
u8_byte_count = WideCharToMultiByte(CP_UTF8, 0, u16_buf, u16_count, NULL, 0, NULL, NULL);

u8_buf = malloc(u8_byte_count);
if (u8_buf == NULL)
{
fprintf(stderr, "Out of memory\n");
break;
}
WideCharToMultiByte(CP_UTF8, 0, u16_buf, u16_count, u8_buf, u8_byte_count, NULL, NULL);
} while (0);
free(u16_buf);
return u8_buf;
}
#endif

typedef struct
{
int count; /* Total count of options */
Expand Down Expand Up @@ -378,7 +326,7 @@ fast_render_loop(fluid_settings_t *settings, fluid_synth_t *synth, fluid_player_
*/
int main(int argc, char **argv)
{
fluid_settings_t *settings;
fluid_settings_t *settings = NULL;
int result = -1;
int arg1 = 1;
char buf[512];
Expand All @@ -404,10 +352,64 @@ int main(int argc, char **argv)
static const char optchars[] = "a:C:c:dE:f:F:G:g:hijK:L:lm:nO:o:p:QqR:r:sT:Vvz:";

#ifdef _WIN32
int argc_dup = 0;
char **argv_dup = NULL;

// console output will be utf-8
SetConsoleOutputCP(CP_UTF8);
// console input, too
SetConsoleCP(CP_UTF8);

// overwrite argc and argv: utf-16 command line string to utf-8 arguments
argv = NULL;
{
LPWSTR *argv_wchar;

// parses a unicode command line string.
if (NULL == (argv_wchar = CommandLineToArgvW(GetCommandLineW(), &argc)))
fprintf(stderr, "Failed to parses a unicode command line string\n");
else
{
if (1 > argc)
fprintf(stderr, "Failed to parses a unicode command line string\n");
else
{
// allocates a new argv array
if (NULL == (argv = argv_dup = (char **)malloc(sizeof(char *) * (size_t)(1 + argc))))
fprintf(stderr, "Out of memory\n");
else
{
argc_dup = argc;

// initialize a new argv array
for (i = 0; argc >= i; i++)
argv[i] = NULL;

// utf-16 to utf-8
for (i = 0; argc > i; i++)
{
int u8_count;

if (1 > (u8_count = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, argv_wchar[i], -1, NULL, 0, NULL, NULL)))
fprintf(stderr, "Failed to convert wide char string to UTF8 string\n");
else if (NULL == (argv[i] = (char *)malloc(sizeof(char) * (size_t)u8_count)))
fprintf(stderr, "Out of memory\n");
else if (u8_count != WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, argv_wchar[i], -1, argv[i], u8_count, NULL, NULL))
fprintf(stderr, "Failed to convert wide char string to UTF8 string\n");
else
continue;
argv = NULL;
break;
}
}
}
// release argv_wchar
LocalFree(argv_wchar);
}
}
// if failed, goto cleanup
if (NULL == argv)
goto cleanup;
#endif

#if SDL2_SUPPORT
Expand Down Expand Up @@ -938,25 +940,14 @@ int main(int argc, char **argv)
/* load the soundfonts (check that all non options are SoundFont or MIDI files) */
for(i = arg1; i < argc; i++)
{
const char *u8_path = argv[i];
#if defined(_WIN32)
/* try to convert ANSI encoding path to UTF8 encoding path */
char *u8_buf = win32_ansi_to_utf8(argv[i]);
if (u8_buf == NULL)
{
// error msg. already printed
goto cleanup;
}
u8_path = u8_buf;
#endif
if(fluid_is_midifile(u8_path))
if(fluid_is_midifile(argv[i]))
{
continue;
}

if(fluid_is_soundfont(u8_path))
if(fluid_is_soundfont(argv[i]))
{
if(fluid_synth_sfload(synth, u8_path, 1) == -1)
if(fluid_synth_sfload(synth, argv[i], 1) == -1)
{
fprintf(stderr, "Failed to load the SoundFont %s\n", argv[i]);
}
Expand All @@ -965,9 +956,6 @@ int main(int argc, char **argv)
{
fprintf(stderr, "Parameter '%s' not a SoundFont or MIDI file or error occurred identifying it.\n", argv[i]);
}
#if defined(_WIN32)
free(u8_buf);
#endif
}

/* Try to load the default soundfont, if no soundfont specified */
Expand Down Expand Up @@ -1022,18 +1010,7 @@ int main(int argc, char **argv)
/* create the player and add any midi files, if requested */
for(i = arg1; i < argc; i++)
{
const char *u8_path = argv[i];
#if defined(_WIN32)
/* try to convert ANSI encoding path to UTF8 encoding path */
char *u8_buf = win32_ansi_to_utf8(argv[i]);
if (u8_buf == NULL)
{
// error msg. already printed
goto cleanup;
}
u8_path = u8_buf;
#endif
if((u8_path[0] != '-') && fluid_is_midifile(u8_path))
if((argv[i][0] != '-') && fluid_is_midifile(argv[i]))
{
if(player == NULL)
{
Expand All @@ -1052,11 +1029,8 @@ int main(int argc, char **argv)
}
}

fluid_player_add(player, u8_path);
fluid_player_add(player, argv[i]);
}
#if defined(_WIN32)
free(u8_buf);
#endif
}

/* try to load and execute the user or system configuration file */
Expand Down Expand Up @@ -1204,6 +1178,18 @@ int main(int argc, char **argv)
delete_fluid_synth(synth);
delete_fluid_settings(settings);

#ifdef _WIN32
if (NULL != argv_dup)
{
for (i = 0; argc_dup > i; i++)
{
if (NULL != argv_dup[i])
free(argv_dup[i]);
}
free(argv_dup);
}
#endif

return result;
}

Expand Down
Loading