Skip to content

Commit

Permalink
Merge pull request #237 from myd7349/fopen-utf8
Browse files Browse the repository at this point in the history
Patch edflib.c on Windows to enable opening UTF-8 encoded paths
  • Loading branch information
skjerns authored Nov 9, 2023
2 parents 95ae95b + beb533a commit 51f4db8
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 19 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pip-log.txt
# Project working files
_edflib.[ch]
_pyedflib.[ch]
edflib_utf8.c

edf.[ch]
cythonize.dat
Expand Down
17 changes: 0 additions & 17 deletions pyedflib/_extensions/_pyedflib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -519,23 +519,6 @@ def set_physical_maximum(handle, edfsignal, phys_max):
def open_file_writeonly(path, filetype, number_of_signals):
"""int edfopen_file_writeonly(char *path, int filetype, int number_of_signals)"""

if os.name=='nt' and contains_unicode(path):
default_enc = locale.getdefaultlocale()[1]
if default_enc is None:
default_enc = ''
else:
default_enc = default_enc.lower()
using_unicode = 'utf' in default_enc or 'unicode' in default_enc or \
'10646' in default_enc or default_enc=='cp65001'
# Check if we're on Windows and the file path contains Unicode.
# If so, use workaround to create file: In Python, create the file,
# then look up and pass the short file name to the C library
if not using_unicode:
warnings.warn('Attempting to write Unicode file {} on Windows. ' \
'Consider changing your locale to UTF8.'.format(path))
with open(path, 'wb'): pass
path = get_short_path_name(path)

py_byte_string = path.encode('utf_8','strict')
cdef char* path_str = py_byte_string
return c_edf.edfopen_file_writeonly(path_str, filetype, number_of_signals)
Expand Down
57 changes: 57 additions & 0 deletions pyedflib/_extensions/c/fopen_utf8.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#ifdef _WIN32

#include "fopen_utf8.h"

#include <stdlib.h>
#include <windows.h>


wchar_t* utf8_to_utf16(const char* str)
{
wchar_t* wstr;

int require = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
if (require == 0)
return NULL;

wstr = malloc(require * sizeof(wchar_t));
if (wstr == NULL)
return NULL;

if (MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, require) == 0)
{
free(wstr);
return NULL;
}

return wstr;
}


FILE* fopen_utf8(const char* filename, const char* mode)
{
errno_t error;
FILE* file;
wchar_t* wfilename;
wchar_t* wmode;

wfilename = utf8_to_utf16(filename);
if (wfilename == NULL)
return NULL;

wmode = utf8_to_utf16(mode);
if (wmode == NULL)
{
free(wfilename);
return NULL;
}

error = _wfopen_s(&file, wfilename, wmode);

free(wfilename);
free(wmode);

return error == 0 ? file : NULL;
}

#endif
20 changes: 20 additions & 0 deletions pyedflib/_extensions/c/fopen_utf8.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef FOPEN_UTF8_H_
#define FOPEN_UTF8_H_

#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32
FILE* fopen_utf8(const char* filename, const char* mode);
#else
#define fopen_utf8 fopen
#endif

#ifdef __cplusplus
}
#endif

#endif
25 changes: 23 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,30 @@ def write_version_py(filename='pyedflib/version.py'):

make_ext_path = partial(os.path.join, "pyedflib", "_extensions")

sources = ["c/edflib.c"]
if os.name == "nt":
# Patch edflib.c
with open(make_ext_path("c/edflib.c"), "rb") as fin:
with open(make_ext_path("c/edflib_utf8.c"), "wb") as fout:
for line in fin:
line = line.replace(
b'#include "edflib.h"',
b'#include "edflib.h"\r\n#include "fopen_utf8.h"')
line = line.replace(
b'file = fopeno(path, "rb");',
b'file = fopen_utf8(path, "rb");')
line = line.replace(
b'file = fopeno(path, "wb");',
b'file = fopen_utf8(path, "wb");')

fout.write(line)

sources = ["c/edflib_utf8.c", "c/fopen_utf8.c"]
headers = ["c/edflib.h", "c/fopen_utf8.h"]
else:
sources = ["c/edflib.c"]
headers = ["c/edflib.h"]

sources = list(map(make_ext_path, sources))
headers = ["c/edflib.h"]
headers = list(map(make_ext_path, headers))

cython_modules = ['_pyedflib']
Expand Down

0 comments on commit 51f4db8

Please sign in to comment.