mirror of
https://git.code.sf.net/p/zint/code
synced 2025-05-24 20:14:28 -04:00
For Windows, assume outfile
& API filename args are in UTF-8,
& use xxxW() APIs accordingly, ticket #288, props Marcel **Backwards-incompatible change**
This commit is contained in:
parent
cc69c86129
commit
15fdca2a03
12 changed files with 151 additions and 47 deletions
|
@ -38,6 +38,7 @@
|
|||
#include "common.h"
|
||||
#include "eci.h"
|
||||
#include "gs1.h"
|
||||
#include "output.h"
|
||||
#include "zfiletypes.h"
|
||||
|
||||
/* It's assumed that int is at least 32 bits, the following will compile-time fail if not
|
||||
|
@ -257,7 +258,11 @@ static int dump_plot(struct zint_symbol *symbol) {
|
|||
if (output_to_stdout) {
|
||||
f = stdout;
|
||||
} else {
|
||||
#ifdef _WIN32
|
||||
f = out_win_fopen(symbol->outfile, "w");
|
||||
#else
|
||||
f = fopen(symbol->outfile, "w");
|
||||
#endif
|
||||
if (!f) {
|
||||
strcpy(symbol->errtxt, "201: Could not open output file");
|
||||
return ZINT_ERROR_FILE_ACCESS;
|
||||
|
@ -1453,7 +1458,11 @@ int ZBarcode_Encode_File(struct zint_symbol *symbol, const char *filename) {
|
|||
file = stdin;
|
||||
fileLen = ZINT_MAX_DATA_LEN;
|
||||
} else {
|
||||
#ifdef _WIN32
|
||||
file = out_win_fopen(filename, "rb");
|
||||
#else
|
||||
file = fopen(filename, "rb");
|
||||
#endif
|
||||
if (!file) {
|
||||
sprintf(symbol->errtxt, "229: Unable to read input file (%d: %.30s)", errno, strerror(errno));
|
||||
return error_tag(symbol, ZINT_ERROR_INVALID_DATA, NULL);
|
||||
|
|
|
@ -871,15 +871,40 @@ INTERNAL void out_upcean_split_text(const int upceanflag, const unsigned char te
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Convert UTF-8 to Windows wide chars. Ticket #288, props Marcel */
|
||||
#define utf8_to_wide(u, w, r) \
|
||||
{ \
|
||||
int lenW; /* Includes NUL terminator */ \
|
||||
if ((lenW = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u, -1, NULL, 0)) == 0) return r; \
|
||||
w = (wchar_t *) z_alloca(sizeof(wchar_t) * lenW); \
|
||||
if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u, -1, w, lenW) == 0) return r; \
|
||||
}
|
||||
|
||||
/* Do `fopen()` on Windows, assuming `filename` is UTF-8 encoded. Ticket #288, props Marcel */
|
||||
INTERNAL FILE *out_win_fopen(const char *filename, const char *mode) {
|
||||
wchar_t *filenameW, *modeW;
|
||||
|
||||
utf8_to_wide(filename, filenameW, NULL);
|
||||
utf8_to_wide(mode, modeW, NULL);
|
||||
|
||||
return _wfopen(filenameW, modeW);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Make a directory; already existing dir okay */
|
||||
/* Adapted from https://gist.github.com/JonathonReinhart/8c0d90191c38af2dcadb102c4e202950 and
|
||||
https://nachtimwald.com/2019/07/10/recursive-create-directory-in-c-revisited/ */
|
||||
static int out_maybe_mkdir(const char* path) {
|
||||
static int out_maybe_mkdir(const char *path) {
|
||||
#ifdef _WIN32
|
||||
DWORD dwAttrib;
|
||||
wchar_t *pathW;
|
||||
|
||||
/* Assumes `path` is UTF-8 encoded */
|
||||
utf8_to_wide(path, pathW, 0);
|
||||
|
||||
/* Try to make the directory */
|
||||
if (CreateDirectoryA(path, NULL) != 0) { /* Non-zero on success */
|
||||
if (CreateDirectoryW(pathW, NULL) != 0) { /* Non-zero on success */
|
||||
return 0;
|
||||
}
|
||||
/* If it fails for any reason but already exists, fail */
|
||||
|
@ -887,7 +912,7 @@ static int out_maybe_mkdir(const char* path) {
|
|||
return -1;
|
||||
}
|
||||
/* Check if the existing path is a directory */
|
||||
if ((dwAttrib = GetFileAttributesA(path)) == (DWORD) -1 || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
if ((dwAttrib = GetFileAttributesW(pathW)) == (DWORD) -1 || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
|
@ -914,7 +939,11 @@ static int out_maybe_mkdir(const char* path) {
|
|||
INTERNAL FILE *out_fopen(const char filename[256], const char *mode) {
|
||||
FILE *outfile;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!(outfile = out_win_fopen(filename, mode))) {
|
||||
#else
|
||||
if (!(outfile = fopen(filename, mode))) {
|
||||
#endif
|
||||
char dirname[256];
|
||||
char *d;
|
||||
#ifdef _WIN32
|
||||
|
@ -950,7 +979,11 @@ INTERNAL FILE *out_fopen(const char filename[256], const char *mode) {
|
|||
*d = '/'; /* Restore */
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
outfile = out_win_fopen(filename, mode);
|
||||
#else
|
||||
outfile = fopen(filename, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
return outfile;
|
||||
|
|
|
@ -71,6 +71,11 @@ INTERNAL void out_upcean_split_text(const int upceanflag, const unsigned char te
|
|||
/* Create output file, creating sub-directories if necessary. Returns `fopen()` FILE pointer */
|
||||
INTERNAL FILE *out_fopen(const char filename[256], const char *mode);
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Do `fopen()` on Windows, assuming `filename` is UTF-8 encoded. Props Marcel, ticket #288 */
|
||||
INTERNAL FILE *out_win_fopen(const char *filename, const char *mode);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
|
|
@ -259,6 +259,8 @@ static void test_fopen(const testCtx *const p_ctx) {
|
|||
/* 11*/ { "out_test//", "", "out.png", 1 },
|
||||
/* 12*/ { "out_test/", "/out_test_subdir/", "out.png", 1 },
|
||||
/* 13*/ { "out_test\\", "\\out_test_subdir\\", "out.png", 1 },
|
||||
/* 14*/ { "", "", "outé.png", 1 },
|
||||
/* 15*/ { "outé_test", "", "outé.png", 1 },
|
||||
};
|
||||
int data_size = ARRAY_SIZE(data);
|
||||
int i, len;
|
||||
|
@ -305,7 +307,7 @@ static void test_fopen(const testCtx *const p_ctx) {
|
|||
if (data[i].dir[0]) {
|
||||
assert_nonzero(testUtilDirExists(dirname), "i:%d testUtilDirExists(%s) != 0 (%d: %s)\n", i, dirname, errno, strerror(errno));
|
||||
}
|
||||
assert_zero(remove(outfile), "i:%d remove(%s) != 0 (%d: %s)\n", i, outfile, errno, strerror(errno));
|
||||
assert_zero(testUtilRemove(outfile), "i:%d testUtilRemove(%s) != 0 (%d: %s)\n", i, outfile, errno, strerror(errno));
|
||||
if (data[i].dir[0]) {
|
||||
if (data[i].subdir[0] && !subdir_exists) {
|
||||
assert_zero(testUtilRmDir(subdirname), "i:%d rmdir(%s) != 0 (%d: %s)\n", i, subdirname, errno, strerror(errno));
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
|
||||
#include "testcommon.h"
|
||||
#include "../eci.h"
|
||||
#include "../output.h"
|
||||
|
||||
static int tests = 0;
|
||||
static int failed = 0;
|
||||
|
@ -107,6 +108,16 @@ void assert_notequal(int e1, int e2, const char *fmt, ...) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define utf8_to_wide(u, w) \
|
||||
{ \
|
||||
int lenW; /* Includes NUL terminator */ \
|
||||
if ((lenW = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u, -1, NULL, 0)) == 0) return 0; \
|
||||
w = (wchar_t *) z_alloca(sizeof(wchar_t) * lenW); \
|
||||
if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u, -1, w, lenW) == 0) return 0; \
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Begin individual test function */
|
||||
void testStartReal(const char *func, const char *name) {
|
||||
tests++;
|
||||
|
@ -1325,7 +1336,11 @@ int testUtilDataPath(char *buffer, int buffer_size, const char *subdir, const ch
|
|||
|
||||
/* Does file exist? */
|
||||
int testUtilExists(const char *filename) {
|
||||
#ifdef _WIN32
|
||||
FILE *fp = out_win_fopen(filename, "r");
|
||||
#else
|
||||
FILE *fp = fopen(filename, "r");
|
||||
#endif
|
||||
if (fp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1333,10 +1348,24 @@ int testUtilExists(const char *filename) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Remove a file (Windows compatibility). Returns 0 if successful, non-zero if not */
|
||||
int testUtilRemove(const char *filename) {
|
||||
#ifdef _WIN32
|
||||
wchar_t *filenameW;
|
||||
utf8_to_wide(filename, filenameW);
|
||||
return DeleteFileW(filenameW) == 0; /* Non-zero on success */
|
||||
#else
|
||||
return remove(filename);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Does directory exist? (Windows compatibility) */
|
||||
int testUtilDirExists(const char *dirname) {
|
||||
#ifdef _WIN32
|
||||
DWORD dwAttrib = GetFileAttributes(dirname);
|
||||
DWORD dwAttrib;
|
||||
wchar_t *dirnameW;
|
||||
utf8_to_wide(dirname, dirnameW);
|
||||
dwAttrib = GetFileAttributesW(dirnameW);
|
||||
return dwAttrib != (DWORD) -1 && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
|
||||
#else
|
||||
return testUtilExists(dirname);
|
||||
|
@ -1346,7 +1375,9 @@ int testUtilDirExists(const char *dirname) {
|
|||
/* Make a directory (Windows compatibility). Returns 0 if successful, non-zero if not */
|
||||
int testUtilMkDir(const char *dirname) {
|
||||
#ifdef _WIN32
|
||||
return CreateDirectory(dirname, NULL) == 0;
|
||||
wchar_t *dirnameW;
|
||||
utf8_to_wide(dirname, dirnameW);
|
||||
return CreateDirectoryW(dirnameW, NULL) == 0;
|
||||
#else
|
||||
return mkdir(dirname, S_IRWXU);
|
||||
#endif
|
||||
|
@ -1355,7 +1386,9 @@ int testUtilMkDir(const char *dirname) {
|
|||
/* Remove a directory (Windows compatibility). Returns 0 if successful, non-zero if not */
|
||||
int testUtilRmDir(const char *dirname) {
|
||||
#ifdef _WIN32
|
||||
return RemoveDirectory(dirname) == 0;
|
||||
wchar_t *dirnameW;
|
||||
utf8_to_wide(dirname, dirnameW);
|
||||
return RemoveDirectoryW(dirnameW) == 0;
|
||||
#else
|
||||
return rmdir(dirname);
|
||||
#endif
|
||||
|
@ -1364,15 +1397,25 @@ int testUtilRmDir(const char *dirname) {
|
|||
/* Rename a file (Windows compatibility) */
|
||||
int testUtilRename(const char *oldpath, const char *newpath) {
|
||||
#ifdef _MSVC
|
||||
int ret = remove(newpath);
|
||||
wchar_t *oldpathW, *newpathW;
|
||||
int ret = testUtilRemove(newpath);
|
||||
if (ret != 0) return ret;
|
||||
#endif
|
||||
utf8_to_wide(oldpath, oldpathW);
|
||||
utf8_to_wide(newpath, newpathW);
|
||||
return _wrename(oldpathW, newpathW);
|
||||
#else
|
||||
return rename(oldpath, newpath);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Create read-only file */
|
||||
int testUtilCreateROFile(const char *filename) {
|
||||
#ifdef _WIN32
|
||||
wchar_t *filenameW;
|
||||
FILE *fp = out_win_fopen(filename, "w+");
|
||||
#else
|
||||
FILE *fp = fopen(filename, "w+");
|
||||
#endif
|
||||
if (fp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1380,7 +1423,8 @@ int testUtilCreateROFile(const char *filename) {
|
|||
return 0;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (SetFileAttributesA(filename, GetFileAttributesA(filename) | FILE_ATTRIBUTE_READONLY) == 0) {
|
||||
utf8_to_wide(filename, filenameW);
|
||||
if (SetFileAttributesW(filenameW, GetFileAttributesW(filenameW) | FILE_ATTRIBUTE_READONLY) == 0) {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
@ -1394,11 +1438,13 @@ int testUtilCreateROFile(const char *filename) {
|
|||
/* Remove read-only file (Windows compatibility) */
|
||||
int testUtilRmROFile(const char *filename) {
|
||||
#ifdef _WIN32
|
||||
if (SetFileAttributesA(filename, GetFileAttributesA(filename) & ~FILE_ATTRIBUTE_READONLY) == 0) {
|
||||
wchar_t *filenameW;
|
||||
utf8_to_wide(filename, filenameW);
|
||||
if (SetFileAttributesW(filenameW, GetFileAttributesW(filenameW) & ~FILE_ATTRIBUTE_READONLY) == 0) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return remove(filename);
|
||||
return testUtilRemove(filename);
|
||||
}
|
||||
|
||||
/* Compare 2 PNG files */
|
||||
|
|
|
@ -160,6 +160,7 @@ int testUtilBitmapCmp(const struct zint_symbol *symbol, const char *expected, in
|
|||
|
||||
int testUtilDataPath(char *buffer, int buffer_size, const char *subdir, const char *filename);
|
||||
int testUtilExists(const char *filename);
|
||||
int testUtilRemove(const char *filename);
|
||||
int testUtilDirExists(const char *dirname);
|
||||
int testUtilMkDir(const char *dirname);
|
||||
int testUtilRmDir(const char *dirname);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue