Skip to content

Commit dc49604

Browse files
committed
tool+lib: handle non-ASCII filenames [Win]
If file name contains non-ASCII characters, the only reasonable way how to handle it is to use wide charactes in MSW. getopt for Win replaced with <https://github.com/darealshinji/getopt-for-windows> supporting wchar_t. refer to GH-93
1 parent 761964f commit dc49604

File tree

8 files changed

+838
-711
lines changed

8 files changed

+838
-711
lines changed

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ message(STATUS "Configured options: ${COMPILED_OPTIONS}")
148148
file(GLOB H_FILES libgpujpeg/*.h ${CMAKE_CURRENT_BINARY_DIR}/libgpujpeg/gpujpeg_version.h)
149149
file(GLOB_RECURSE C_FILES src/*.c src/*.cu)
150150
list(REMOVE_ITEM C_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/main.c")
151+
list(REMOVE_ITEM C_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/utils/getopt.c")
151152
add_library(gpujpeg ${H_FILES} ${C_FILES})
152153
target_include_directories(${PROJECT_NAME}
153154
PUBLIC ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}
@@ -165,6 +166,10 @@ endif()
165166

166167
# GPUJPEG commmand-line application
167168
add_executable(gpujpeg-bin src/main.c)
169+
if(NOT UNIX)
170+
target_sources(gpujpeg-bin PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/utils/getopt.c")
171+
target_compile_options(gpujpeg-bin PRIVATE $<$<COMPILE_LANGUAGE:C>:/D_UNICODE>)
172+
endif()
168173
target_compile_features(gpujpeg-bin PRIVATE ${NEEDED_COMPILER_FEATURES})
169174
set_property(TARGET gpujpeg-bin PROPERTY C_STANDARD 99)
170175
target_link_libraries(gpujpeg-bin gpujpeg)

NEWS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
next
2+
----------
3+
4+
- support for non-ASCII characters in filename (tool+_load/_save)
5+
16
2025-05-23 - 0.27.4
27
----------
38

libgpujpeg/gpujpeg_common.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,8 @@ gpujpeg_image_calculate_size(struct gpujpeg_image_parameters* param);
400400
*
401401
* Allocated image must be freed by gpujpeg_image_load_from_file().
402402
*
403+
* Non-ASCII symbols in filename should be UTF-8 encoded.
404+
*
403405
* @param filaname Image filename
404406
* @param[out] image Image data buffer allocated as CUDA host buffer
405407
* @param[in,out] image_size Image data buffer size (can be specified for verification or 0 for retrieval)
@@ -411,6 +413,8 @@ gpujpeg_image_load_from_file(const char* filename, uint8_t** image, size_t* imag
411413
/**
412414
* Save image to a file
413415
*
416+
* Non-ASCII symbols in filename should be UTF-8 encoded.
417+
*
414418
* File format is deduced from the filename extension (if any).
415419
*
416420
* Use the extension "XXX" (eg. "image.XXX") to automatically select the

src/gpujpeg_common.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,25 @@
108108
(name).started = 0; \
109109
} while ( 0 )
110110

111+
#ifdef _WIN32
112+
static wchar_t*
113+
mbs_to_wstr_helper(const char* mbstr, wchar_t* wstr_buf, size_t wstr_len)
114+
{
115+
const int size_needed = MultiByteToWideChar(CP_UTF8, 0, mbstr, -1, NULL, 0);
116+
if (size_needed <= 0) {
117+
ERROR_MSG("MultiByteToWideChar returned: %d (0x%x)!\n", size_needed, size_needed);
118+
return NULL;
119+
}
120+
if (size_needed > (int) wstr_len) {
121+
ERROR_MSG("buffer provided to %s too short - needed %d, got %zu!\n", __func__, size_needed, wstr_len);
122+
return NULL;
123+
}
124+
MultiByteToWideChar(CP_UTF8, 0, mbstr, -1, wstr_buf, size_needed);
125+
return wstr_buf;
126+
}
127+
#define mbs_to_wstr(tstr) mbs_to_wstr_helper(tstr, (wchar_t[1024]){0}, 1024)
128+
#endif
129+
111130
#define PLANAR 1u
112131
static const struct {
113132
enum gpujpeg_pixel_format pixel_format;
@@ -1201,7 +1220,11 @@ gpujpeg_image_load_from_file(const char* filename, uint8_t** image, size_t* imag
12011220
}
12021221

12031222
FILE* file;
1223+
#ifdef _WIN32
1224+
file = _wfopen(mbs_to_wstr(filename), L"rb");
1225+
#else
12041226
file = fopen(filename, "rb");
1227+
#endif
12051228
if ( !file ) {
12061229
fprintf(stderr, "[GPUJPEG] [Error] Failed open %s for reading: %s\n", filename, strerror(errno));
12071230
return -1;
@@ -1264,7 +1287,11 @@ gpujpeg_image_save_to_file(const char* filename, const uint8_t* image, size_t im
12641287
}
12651288

12661289
FILE* file;
1290+
#ifdef _WIN32
1291+
file = _wfopen(mbs_to_wstr(filename), L"wb");
1292+
#else
12671293
file = fopen(filename, "wb");
1294+
#endif
12681295
if ( !file ) {
12691296
fprintf(stderr, "[GPUJPEG] [Error] Failed open %s for writing: %s\n", filename, strerror(errno));
12701297
return -1;

0 commit comments

Comments
 (0)