diff --git a/include/share/grabbag/file.h b/include/share/grabbag/file.h index df72537787..a3818fccfa 100644 --- a/include/share/grabbag/file.h +++ b/include/share/grabbag/file.h @@ -58,6 +58,23 @@ FLAC__bool grabbag__file_remove_file(const char *filename); FILE *grabbag__file_get_binary_stdin(void); FILE *grabbag__file_get_binary_stdout(void); +/* input/stdin reader that works correctly on Windows console */ +struct grabbag__file_input_reader { + FILE *stream; + char *buf; + size_t pos; + size_t size; + size_t maxsize; + wchar_t surrogate_buffer; + FLAC__bool eof; + FLAC__bool force_utf8; + FLAC__bool error; +}; +typedef struct grabbag__file_input_reader grabbag__file_input_reader; +void grabbag__file_input_reader_open(grabbag__file_input_reader *input_reader, FILE *stream); +void grabbag__file_input_reader_close(grabbag__file_input_reader *input_reader); +FLAC__bool grabbag__file_input_reader_next_line(grabbag__file_input_reader *input_reader, char **line); + #ifdef __cplusplus } #endif diff --git a/src/flac/main.c b/src/flac/main.c index f45488d180..8c5993aa8a 100644 --- a/src/flac/main.c +++ b/src/flac/main.c @@ -326,8 +326,6 @@ static int main_to_fuzz(int argc, char *argv[]) fprintf(stderr, "ERROR: failed to convert command line parameters to UTF-8\n"); return 1; } - SetConsoleOutputCP(CP_UTF8); - _setmode(fileno(stderr),_O_U8TEXT); #endif #ifdef HAVE_SYS_TIME_H diff --git a/src/flac/vorbiscomment.c b/src/flac/vorbiscomment.c index 41f42b7411..5fcb574b74 100644 --- a/src/flac/vorbiscomment.c +++ b/src/flac/vorbiscomment.c @@ -142,6 +142,9 @@ static FLAC__bool set_vc_field(FLAC__StreamMetadata *block, const Argument_VcFie } /* move 'data' into 'converted', converting to UTF-8 if necessary */ +#ifdef _WIN32 + converted = data; +#else if(raw) { converted = data; } @@ -153,6 +156,7 @@ static FLAC__bool set_vc_field(FLAC__StreamMetadata *block, const Argument_VcFie *violation = "error converting file contents to UTF-8 for tag value"; return false; } +#endif /* create and entry and append it */ if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, field->field_name, converted)) { diff --git a/src/metaflac/operations.c b/src/metaflac/operations.c index 060c0c98e8..5426f2eb17 100644 --- a/src/metaflac/operations.c +++ b/src/metaflac/operations.c @@ -72,10 +72,11 @@ FLAC__bool do_operations(const CommandLineOptions *options) FLAC__bool ok = true; #ifdef _WIN32 - if(options->utf8_convert) { - _setmode(fileno(stdout),_O_U8TEXT); - SetConsoleOutputCP(CP_UTF8); - } + fflush(stdout); + fflush(stderr); + _setmode(fileno(stdin), _O_BINARY); + _setmode(fileno(stdout), _O_BINARY); + _setmode(fileno(stderr), _O_BINARY); #endif if(options->show_long_help) { @@ -215,12 +216,6 @@ FLAC__bool do_major_operation__list(const char *filename, FLAC__Metadata_Chain * return false; } write_metadata_binary(block, block_raw, options->data_format_is_binary_headerless); -#ifdef _WIN32 - if(options->utf8_convert) - _setmode(fileno(stdout),_O_U8TEXT); - else - _setmode(fileno(stdin),_O_TEXT); -#endif free(block_raw); } } @@ -276,10 +271,6 @@ FLAC__bool do_major_operation__append(FLAC__Metadata_Chain *chain, const Command break; } -#ifdef _WIN32 - _setmode(fileno(stdin),_O_BINARY); -#endif - /* Read header from stdin */ while(fread(header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, stdin) == FLAC__STREAM_METADATA_HEADER_LENGTH) { @@ -342,13 +333,6 @@ FLAC__bool do_major_operation__append(FLAC__Metadata_Chain *chain, const Command } } -#ifdef _WIN32 - if(options->utf8_convert) - _setmode(fileno(stdout),_O_U8TEXT); - else - _setmode(fileno(stdin),_O_TEXT); -#endif - if(num_objects == 0) flac_fprintf(stderr, "ERROR: unable to find a metadata block in the supplied input\n"); @@ -852,17 +836,10 @@ void write_metadata(const char *filename, FLAC__StreamMetadata *block, unsigned void write_metadata_binary(FLAC__StreamMetadata *block, FLAC__byte *block_raw, FLAC__bool headerless) { -#ifdef _WIN32 - fflush(stdout); - _setmode(fileno(stdout),_O_BINARY); -#endif if(!headerless) local_fwrite(block_raw, 1, block->length+FLAC__STREAM_METADATA_HEADER_LENGTH, stdout); else if(block->type == FLAC__METADATA_TYPE_APPLICATION && block->length > 3) local_fwrite(block_raw+FLAC__STREAM_METADATA_HEADER_LENGTH+4, 1, block->length-4, stdout); else local_fwrite(block_raw+FLAC__STREAM_METADATA_HEADER_LENGTH, 1, block->length, stdout); -#ifdef _WIN32 - fflush(stdout); -#endif } diff --git a/src/metaflac/operations_shorthand_vorbiscomment.c b/src/metaflac/operations_shorthand_vorbiscomment.c index 4a0a8faa8e..0eef450f55 100644 --- a/src/metaflac/operations_shorthand_vorbiscomment.c +++ b/src/metaflac/operations_shorthand_vorbiscomment.c @@ -232,7 +232,7 @@ FLAC__bool remove_vc_firstfield(const char *filename, FLAC__StreamMetadata *bloc FLAC__bool set_vc_field(const char *filename, FLAC__StreamMetadata *block, const Argument_VcField *field, FLAC__bool *needs_write, FLAC__bool raw) { FLAC__StreamMetadata_VorbisComment_Entry entry; - char *converted; + char *converted = NULL; FLAC__ASSERT(0 != block); FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); @@ -270,6 +270,9 @@ FLAC__bool set_vc_field(const char *filename, FLAC__StreamMetadata *block, const } /* move 'data' into 'converted', converting to UTF-8 if necessary */ +#if defined _WIN32 + converted = data; +#else if(raw) { converted = data; } @@ -281,6 +284,7 @@ FLAC__bool set_vc_field(const char *filename, FLAC__StreamMetadata *block, const flac_fprintf(stderr, "%s: ERROR: converting file '%s' contents to UTF-8 for tag value\n", filename, field->field_value); return false; } +#endif /* create and entry and append it */ if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, field->field_name, converted)) { @@ -300,6 +304,7 @@ FLAC__bool set_vc_field(const char *filename, FLAC__StreamMetadata *block, const else { FLAC__bool needs_free = false; entry.entry = (FLAC__byte *)field->field; +#if !defined _WIN32 if(raw) { entry.entry = (FLAC__byte *)field->field; } @@ -311,6 +316,7 @@ FLAC__bool set_vc_field(const char *filename, FLAC__StreamMetadata *block, const flac_fprintf(stderr, "%s: ERROR: converting comment '%s' to UTF-8\n", filename, field->field); return false; } +#endif entry.length = strlen((const char *)entry.entry); if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) { if(needs_free) @@ -340,7 +346,8 @@ FLAC__bool set_vc_field(const char *filename, FLAC__StreamMetadata *block, const FLAC__bool import_vc_from(const char *filename, FLAC__StreamMetadata *block, const Argument_String *vc_filename, FLAC__bool *needs_write, FLAC__bool raw) { FILE *f; - char line[65536]; + char* line = NULL; + grabbag__file_input_reader input_reader[1]; FLAC__bool ret; if(0 == vc_filename->value || strlen(vc_filename->value) == 0) { @@ -348,7 +355,7 @@ FLAC__bool import_vc_from(const char *filename, FLAC__StreamMetadata *block, con return false; } if(0 == strcmp(vc_filename->value, "-")) - f = stdin; + f = grabbag__file_get_binary_stdin(); else f = flac_fopen(vc_filename->value, "r"); @@ -358,42 +365,38 @@ FLAC__bool import_vc_from(const char *filename, FLAC__StreamMetadata *block, con } ret = true; - while(ret && !feof(f) && fgets(line, sizeof(line), f) != NULL) { - char *p = strpbrk(line, "\r\n"); - if(0 == p) { - const size_t len = strlen(line); - if(len < (sizeof(line) - 1)) { - /* Likely missing newline in the last line, allow this */ - p = &line[len]; - } - else { - flac_fprintf(stderr, "%s: ERROR: line too long, aborting\n", vc_filename->value); - ret = false; - } - } - if(ret) { - const char *violation; - Argument_VcField field; - *p = '\0'; - memset(&field, 0, sizeof(Argument_VcField)); - field.field_value_from_file = false; - if(!parse_vorbis_comment_field(line, &field.field, &field.field_name, &field.field_value, &field.field_value_length, &violation)) { - FLAC__ASSERT(0 != violation); - flac_fprintf(stderr, "%s: ERROR: malformed vorbis comment field \"%s\",\n %s\n", vc_filename->value, line, violation); - ret = false; - } - else { - ret = set_vc_field(filename, block, &field, needs_write, raw); - } - if(0 != field.field) - free(field.field); - if(0 != field.field_name) - free(field.field_name); - if(0 != field.field_value) - free(field.field_value); + grabbag__file_input_reader_open(input_reader, f); + input_reader->force_utf8 = raw; + + while(grabbag__file_input_reader_next_line(input_reader, &line)) { + const char *violation; + Argument_VcField field; + memset(&field, 0, sizeof(Argument_VcField)); + field.field_value_from_file = false; + if(!parse_vorbis_comment_field(line, &field.field, &field.field_name, &field.field_value, &field.field_value_length, &violation)) { + FLAC__ASSERT(0 != violation); + flac_fprintf(stderr, "%s: ERROR: malformed vorbis comment field \"%s\",\n %s\n", vc_filename->value, line, violation); + ret = false; } - }; + else { + ret = set_vc_field(filename, block, &field, needs_write, raw); + } + if(0 != field.field) + free(field.field); + if(0 != field.field_name) + free(field.field_name); + if(0 != field.field_value) + free(field.field_value); + } + + if(input_reader->error) + { + flac_fprintf(stderr, "%s: ERROR: line too long, aborting\n", vc_filename->value); + ret = false; + } + + grabbag__file_input_reader_close(input_reader); if(f != stdin) fclose(f); diff --git a/src/share/grabbag/file.c b/src/share/grabbag/file.c index 2ef9d6f4a7..459c5adab1 100644 --- a/src/share/grabbag/file.c +++ b/src/share/grabbag/file.c @@ -205,3 +205,257 @@ FILE *grabbag__file_get_binary_stdout(void) return stdout; } + +void grabbag__file_input_reader_open(grabbag__file_input_reader *input_reader, FILE *stream) +{ + memset(input_reader, 0, sizeof(*input_reader)); + input_reader->stream = stream; + input_reader->buf = NULL; + input_reader->pos = 0; + input_reader->size = 0; + input_reader->maxsize = 0; + input_reader->surrogate_buffer = 0; + input_reader->eof = 0; + input_reader->error = 0; +} + +void grabbag__file_input_reader_close(grabbag__file_input_reader *input_reader) +{ + input_reader->stream = NULL; + free(input_reader->buf); + input_reader->buf = NULL; + input_reader->pos = 0; + input_reader->size = 0; + input_reader->maxsize = 0; + input_reader->surrogate_buffer = 0; + input_reader->eof = 0; + input_reader->error = 0; +} + +#if defined _WIN32 && !defined __CYGWIN__ +static inline FLAC__bool is_high_surrogate(const wchar_t wc) +{ + return ((unsigned)wc >= (unsigned)HIGH_SURROGATE_START) && + ((unsigned)wc <= (unsigned)HIGH_SURROGATE_END); +} +#endif + +#if defined _WIN32 && !defined __CYGWIN__ +static FLAC__bool console_cp_stdin_to_utf8(const char *from, char **to) +{ + wchar_t *unicode = NULL; + char *utf8 = NULL; + FLAC__bool ret = 0; + /* Don't use CP_ACP or CP_OEMCP here since the actual console codepage in use can be different */ + const UINT console_cp_stdin = GetConsoleCP(); + + do { + int len; + + len = MultiByteToWideChar(console_cp_stdin, 0, from, -1, NULL, 0); + if(len == 0) + break; + unicode = (wchar_t *)malloc((size_t)len * sizeof(wchar_t)); + if(unicode == NULL) + break; + len = MultiByteToWideChar(console_cp_stdin, 0, from, -1, unicode, len); + if(len == 0) + break; + + len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, NULL, 0, NULL, NULL); + if(len == 0) + break; + utf8 = (char *)malloc((size_t)len * sizeof(char)); + if(utf8 == NULL) + break; + len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, utf8, len, NULL, NULL); + if(len == 0) + break; + + ret = 1; + + } while(0); + + free(unicode); + + if(ret == 1) { + *to = utf8; + } + else { + free(utf8); + *to = NULL; + } + return ret; +} +#endif + +static size_t grabbag__file_input_reader_refill(grabbag__file_input_reader *input_reader) +{ +#if defined _WIN32 && !defined __CYGWIN__ + HANDLE handle; + + /* Convert from standard stream into handle */ + if(input_reader->stream == stdin) { + handle = GetStdHandle(STD_INPUT_HANDLE); + } + else { + handle = INVALID_HANDLE_VALUE; + } + + if(input_reader->buf == NULL) { + input_reader->maxsize = 65536U; + input_reader->buf = malloc(input_reader->maxsize); + if(input_reader->buf == NULL) { + return 0; + } + } + + /* Move remaining part of buffer to the beginning of the buffer */ + { + size_t bytes_left = input_reader->size - input_reader->pos; + if(bytes_left > 0) { + memmove(&input_reader->buf[0], &input_reader->buf[input_reader->pos], bytes_left); + } + input_reader->pos = 0; + input_reader->size = bytes_left; + } + + if((handle != INVALID_HANDLE_VALUE) && (handle != NULL)) { + const DWORD fileType = GetFileType(handle); + if(fileType == FILE_TYPE_CHAR) { + /* Reading from the console, must use UTF-16 */ + wchar_t wstr[32768]; + size_t bytes_left = input_reader->maxsize - input_reader->size; + DWORD wchars_to_read = (bytes_left / 2); + DWORD wchars_read = 0; + size_t wpos = 0; + + /* Put back buffered surrogate */ + if(input_reader->surrogate_buffer != 0) { + wstr[wpos++] = input_reader->surrogate_buffer; + input_reader->surrogate_buffer = 0; + if(wchars_to_read > 0) { + --wchars_to_read; + } + } + + if(ReadConsoleW(handle, &wstr[wpos], wchars_to_read, &wchars_read, NULL)) { + int utf8_size = 0; + wchars_read += wpos; + + /* Check if start of surrogate pair, then back up one character to avoid splitting it. */ + if((wchars_read > 0) && is_high_surrogate(wstr[wchars_read - 1])) { + input_reader->surrogate_buffer = wstr[wchars_read - 1]; + --wchars_read; + } + + utf8_size = WideCharToMultiByte(CP_UTF8, 0, wstr, wchars_read, &input_reader->buf[input_reader->size], bytes_left, NULL, NULL); + if(utf8_size == 0) { + /* failed */ + input_reader->eof = true; + } + input_reader->size += utf8_size; + return utf8_size; + } + else + { + return 0; + } + } + else if((fileType == FILE_TYPE_PIPE) && (!input_reader->force_utf8)) { + /* Redirect from pipe, convert from current console input codepage. */ + char buffer[65537]; + DWORD chars_to_read = (DWORD)(sizeof(buffer) - 1); + DWORD chars_read = 0; + + if(ReadFile(handle, &buffer[0], chars_to_read, &chars_read, NULL) != 0) { + size_t i; + char *utf8_str = NULL; + buffer[chars_read] = '\0'; + if (console_cp_stdin_to_utf8(&buffer[0], &utf8_str) == 1) { + size_t utf8_size = strlen(utf8_str); + memcpy(&input_reader->buf[input_reader->size], utf8_str, utf8_size); + input_reader->size += utf8_size; + free(utf8_str); + return utf8_size; + } + else + { + /* fail */ + } + + free(utf8_str); + } + } + else { + /* Redirect from file, assume it is already UTF-8. */ + size_t bytes_left = input_reader->maxsize - input_reader->size; + DWORD chars_read = 0; + + if(ReadFile(handle, &input_reader->buf[input_reader->size], (DWORD)bytes_left, &chars_read, NULL) != 0) { + input_reader->size += chars_read; + return chars_read; + } + } + } + else { + /* regular file on disk */ + size_t bytes_left = input_reader->maxsize - input_reader->size; + size_t chars_read = fread(&input_reader->buf[input_reader->size], 1, bytes_left, input_reader->stream); + input_reader->size += chars_read; + return chars_read; + } +#endif + return 0; +} + +FLAC__bool grabbag__file_input_reader_next_line(grabbag__file_input_reader *input_reader, char **line) +{ + if(input_reader->eof) { + return false; + } + + do { + const size_t start_pos = input_reader->pos; + size_t pos = input_reader->pos; + size_t end = 0; + + while(pos < input_reader->size) { + /* accept any of \r \n \r\n \n\r as the line ending */ + const char c = input_reader->buf[pos]; + if((c == '\r') || (c == '\n')) { + input_reader->buf[pos] = '\0'; + ++pos; + if((pos < input_reader->size) && (c != input_reader->buf[pos]) && ((input_reader->buf[pos] == '\r') || (input_reader->buf[pos] == '\n'))) { + ++pos; + } + *line = &input_reader->buf[input_reader->pos]; + input_reader->pos = pos; + return true; + } + + ++pos; + } + + /* No newline found, try to read more data into buffer */ + if(grabbag__file_input_reader_refill(input_reader) == 0) { + /* No more data, end of stream */ + input_reader->eof = true; + + if((input_reader->pos < input_reader->size) && (input_reader->size < input_reader->maxsize)) { + /* Last line didn't have ending newline, accept this anyway */ + input_reader->buf[input_reader->size] = '\0'; + *line = &input_reader->buf[input_reader->pos]; + input_reader->pos = pos; + return true; + } + else { + /* Line too long */ + return false; + } + } + + } while(true); + + return false; +} diff --git a/src/share/win_utf8_io/win_utf8_io.c b/src/share/win_utf8_io/win_utf8_io.c index 0d75cbf9b3..58c324f30a 100644 --- a/src/share/win_utf8_io/win_utf8_io.c +++ b/src/share/win_utf8_io/win_utf8_io.c @@ -109,6 +109,42 @@ static wchar_t *wchar_from_utf8(const char *str) return widestr; } +/* convert UTF-8 to console output cp. Caller is responsible for freeing memory */ +static char *console_cp_stdout_from_utf8(const char *str) +{ + char *cpstr; + wchar_t *widestr; + int len; + const UINT console_output_cp = GetConsoleOutputCP(); + + if(!str) + return NULL; + if((len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) == 0) + return NULL; + if((widestr = (wchar_t *)malloc(len * sizeof(wchar_t))) == NULL) + return NULL; + if(MultiByteToWideChar(CP_UTF8, 0, str, -1, widestr, len) == 0) { + free(widestr); + return NULL; + } + + if((len = WideCharToMultiByte(console_output_cp, 0, widestr, -1, NULL, 0, NULL, NULL)) == 0) { + free(widestr); + return NULL; + } + if((cpstr = (char *)malloc(len * sizeof(char))) == NULL) { + free(widestr); + return NULL; + } + if(WideCharToMultiByte(console_output_cp, 0, widestr, -1, cpstr, len, NULL, NULL) == 0) { + free(widestr); + free(cpstr); + cpstr = NULL; + } + + return cpstr; +} + /* retrieve WCHAR commandline, expand wildcards and convert everything to UTF-8 */ int get_utf8_argv(int *argc, char ***argv) { @@ -221,37 +257,109 @@ int win_get_console_width(void) return width; } +static FLAC__bool is_low_surrogate(const wchar_t wc) +{ + return ((unsigned)wc >= (unsigned)LOW_SURROGATE_START) && + ((unsigned)wc <= (unsigned)LOW_SURROGATE_END); +} + /* print functions */ #if !FLAC_WINDOWS_APP -static int wprint_console(FILE *stream, const wchar_t *text, size_t len) +static int wprint_console(FILE *stream, const char *utf8_text, size_t len) { - DWORD out; - int ret; + HANDLE handle; - do { - if (stream == stdout) { - HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); - if (hOut == INVALID_HANDLE_VALUE || hOut == NULL || GetFileType(hOut) != FILE_TYPE_CHAR) - break; - if (WriteConsoleW(hOut, text, len, &out, NULL) == 0) + /* Convert from standard stream into handle */ + if(stream == stdout) { + handle = GetStdHandle(STD_OUTPUT_HANDLE); + } + else if(stream == stderr) { + handle = GetStdHandle(STD_ERROR_HANDLE); + } + else { + handle = INVALID_HANDLE_VALUE; + } + + if((handle != INVALID_HANDLE_VALUE) && (handle != NULL)) { + const UINT file_type = GetFileType(handle); + if(file_type == FILE_TYPE_CHAR) { + /* Printing to the console, must use UTF-16 */ + wchar_t *wout = NULL; + size_t wsize = 0; + if(!(wout = wchar_from_utf8(utf8_text))) { return -1; - return out; + } + + { + /* Prior to Windows 8, there was a max buffer size for console writes. + So we need to split up the console writes. + https://github.com/python/cpython/issues/121940 + https://github.com/python/cpython/issues/55604 + https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232 + https://www.mail-archive.com/log4net-dev@logging.apache.org/msg00661.html + */ + size_t chars_left = wcslen(wout); + wchar_t *wptr = wout; + while(chars_left > 0) { + const size_t MAX_CHARS_TO_WRITE = 16384; + size_t chars_to_write = (chars_left > MAX_CHARS_TO_WRITE) ? MAX_CHARS_TO_WRITE : chars_left; + DWORD chars_written = 0; + + /* Check if end of surrogate pair, then back up one character to avoid splitting it. */ + if(is_low_surrogate(wptr[chars_to_write - 1])) { + --chars_to_write; + } + + if(WriteConsoleW(handle, wptr, chars_to_write, &chars_written, NULL) == 0) { + return -1; + } + if(chars_written == 0) { + return -1; + } + + wptr += chars_written; + chars_left -= chars_written; + } + } + + return len; } - if (stream == stderr) { - HANDLE hErr = GetStdHandle(STD_ERROR_HANDLE); - if (hErr == INVALID_HANDLE_VALUE || hErr == NULL || GetFileType(hErr) != FILE_TYPE_CHAR) - break; - if (WriteConsoleW(hErr, text, len, &out, NULL) == 0) + else if(file_type == FILE_TYPE_PIPE) { + /* Redirect to pipe, use console CP. */ + char *cp_text = console_cp_stdout_from_utf8(utf8_text); + if(cp_text != NULL) { + DWORD chars_written = 0; + DWORD len = strlen(cp_text); + if(WriteFile(handle, cp_text, len, &chars_written, NULL) == 0) { + return -1; + } + + if(chars_written != len) { + return -1; + } + + return len; + } + } + else { + /* Redirect to file, use UTF-8. */ + DWORD chars_written = 0; + if(WriteFile(handle, utf8_text, len, &chars_written, NULL) == 0) { + return -1; + } + + if(chars_written != len) { return -1; - return out; + } + + return len; } - } while(0); + } - ret = fputws(text, stream); - if (ret < 0) - return ret; - return len; + /* If we en up here we are writing to another file that is neither stdout nor stderr */ + /* TODO: Should this be an assert instead? */ + return (int)fwrite(utf8_text, len, 1, stream); } #endif // !FLAC_WINDOWS_APP @@ -290,13 +398,13 @@ int vfprintf_utf8(FILE *stream, const char *format, va_list argptr) do { if (!(utmp = (char *)malloc(UTF8_BUFFER_SIZE))) break; if ((ret = local_vsnprintf(utmp, UTF8_BUFFER_SIZE, format, argptr)) <= 0) break; +#if !FLAC_WINDOWS_APP + ret = wprint_console(stream, utmp, strlen(utmp)); +#else // FLAC_WINDOWS_APP if (!(wout = wchar_from_utf8(utmp))) { ret = -1; break; } -#if !FLAC_WINDOWS_APP - ret = wprint_console(stream, wout, wcslen(wout)); -#else // FLAC_WINDOWS_APP OutputDebugStringW(wout); ret = 0; #endif // FLAC_WINDOWS_APP