Skip to content

Commit 03eeea5

Browse files
authored
Merge pull request #1794 from bombipappoo/filename-encoding
Convert filename from ANSI to UTF-8 before calling HDF5.
2 parents 3afce17 + ecbb0f5 commit 03eeea5

File tree

4 files changed

+182
-5
lines changed

4 files changed

+182
-5
lines changed

include/hdf5internal.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,4 +197,23 @@ extern int NC4_isnetcdf4(struct NC_FILE_INFO*); /*libsrc4/nc4hdf.c*/
197197

198198
extern int nc4_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var);
199199

200+
#ifdef _WIN32
201+
202+
/* Maxinum length of a typical path in UTF-8.
203+
* When converting from ANSI to UTF-8, the length will be up to 3 times,
204+
* so round up 260*3 to 1024. (260=MAX_PATH) */
205+
#define MAX_PATHBUF_SIZE 1024
206+
207+
/* Struct for converting ANSI to UTF-8. */
208+
typedef struct pathbuf
209+
{
210+
void *ptr;
211+
char buffer[MAX_PATHBUF_SIZE];
212+
} pathbuf_t;
213+
214+
const char *nc4_ndf5_ansi_to_utf8(pathbuf_t *pb, const char *path);
215+
void nc4_hdf5_free_pathbuf(pathbuf_t *pb);
216+
217+
#endif /* _WIN32 */
218+
200219
#endif /* _HDF5INTERNAL_ */

libhdf5/hdf5create.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ static const int ILLEGAL_CREATE_FLAGS = (NC_NOWRITE|NC_MMAP|NC_64BIT_OFFSET|NC_C
2222
/* From nc4mem.c */
2323
extern int NC4_create_image_file(NC_FILE_INFO_T* h5, size_t);
2424

25+
#ifdef _WIN32
26+
static hid_t nc4_H5Fcreate(const char *filename, unsigned flags, hid_t fcpl_id, hid_t fapl_id);
27+
#else
28+
#define nc4_H5Fcreate H5Fcreate
29+
#endif
30+
2531
/**
2632
* @internal Create a netCDF-4/HDF5 file.
2733
*
@@ -217,13 +223,13 @@ nc4_create_file(const char *path, int cmode, size_t initialsz,
217223
/* Configure FAPL to use the core file driver */
218224
if (H5Pset_fapl_core(fapl_id, alloc_incr, (nc4_info->mem.persist?1:0)) < 0)
219225
BAIL(NC_EHDFERR);
220-
if ((hdf5_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
226+
if ((hdf5_info->hdfid = nc4_H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
221227
BAIL(EACCES);
222228
}
223229
else /* Normal file */
224230
{
225231
/* Create the HDF5 file. */
226-
if ((hdf5_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
232+
if ((hdf5_info->hdfid = nc4_H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
227233
BAIL(EACCES);
228234
}
229235

@@ -306,3 +312,31 @@ NC4_create(const char* path, int cmode, size_t initialsz, int basepe,
306312

307313
return res;
308314
}
315+
316+
#ifdef _WIN32
317+
318+
/**
319+
* Wrapper function for H5Fcreate.
320+
* Converts the filename from ANSI to UTF-8 as needed before calling H5Fcreate.
321+
*
322+
* @param filename The filename encoded ANSI to access.
323+
* @param flags File access flags.
324+
* @param fcpl_id File creation property list identifier.
325+
* @param fapl_id File access property list identifier.
326+
* @return A file identifier if succeeded. A negative value if failed.
327+
*/
328+
static hid_t
329+
nc4_H5Fcreate(const char *filename, unsigned flags, hid_t fcpl_id, hid_t fapl_id)
330+
{
331+
pathbuf_t pb;
332+
hid_t hid;
333+
334+
filename = nc4_ndf5_ansi_to_utf8(&pb, filename);
335+
if (!filename)
336+
return H5I_INVALID_HID;
337+
hid = H5Fcreate(filename, flags, fcpl_id, fapl_id);
338+
nc4_hdf5_free_pathbuf(&pb);
339+
return hid;
340+
}
341+
342+
#endif /* _WIN32 */

libhdf5/hdf5internal.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
#include "config.h"
1818
#include "hdf5internal.h"
1919
#include "ncfilter.h"
20+
#ifdef _WIN32
21+
#include <windows.h>
22+
#endif
2023

2124
#undef DEBUGH5
2225

@@ -1027,3 +1030,91 @@ hdf5_set_log_level()
10271030
return NC_NOERR;
10281031
}
10291032
#endif /* LOGGING */
1033+
1034+
1035+
#ifdef _WIN32
1036+
1037+
/**
1038+
* Converts the filename from ANSI to UTF-8 if HDF5 >= 1.10.6.
1039+
* nc4_hdf5_free_pathbuf must be called to free pb.
1040+
*
1041+
* @param pb Pointer that conversion information is stored.
1042+
* @param path The filename to be converted.
1043+
*
1044+
* @return The converted filename if succeeded. NULL if failed.
1045+
*/
1046+
const char *
1047+
nc4_ndf5_ansi_to_utf8(pathbuf_t *pb, const char *path)
1048+
{
1049+
const uint UTF8_MAJNUM = 1;
1050+
const uint UTF8_MINNUM = 10;
1051+
const uint UTF8_RELNUM = 6;
1052+
static enum {UNDEF, ANSI, UTF8} hdf5_encoding = UNDEF;
1053+
wchar_t wbuf[MAX_PATH];
1054+
wchar_t *ws = NULL;
1055+
char *ns = NULL;
1056+
int n;
1057+
1058+
if (hdf5_encoding == UNDEF) {
1059+
uint majnum, minnum, relnum;
1060+
H5get_libversion(&majnum, &minnum, &relnum);
1061+
hdf5_encoding = (((majnum == UTF8_MAJNUM && minnum == UTF8_MINNUM && relnum >= UTF8_RELNUM)
1062+
|| (majnum == UTF8_MAJNUM && minnum > UTF8_MINNUM)
1063+
|| majnum > UTF8_MAJNUM)
1064+
? UTF8 : ANSI);
1065+
}
1066+
if (hdf5_encoding == ANSI) {
1067+
pb->ptr = NULL;
1068+
return path;
1069+
}
1070+
1071+
n = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1072+
if (!n) {
1073+
errno = EILSEQ;
1074+
goto done;
1075+
}
1076+
ws = n <= _countof(wbuf) ? wbuf : malloc(sizeof *ws * n);
1077+
if (!ws)
1078+
goto done;
1079+
if (!MultiByteToWideChar(CP_ACP, 0, path, -1, ws, n)) {
1080+
errno = EILSEQ;
1081+
goto done;
1082+
}
1083+
1084+
n = WideCharToMultiByte(CP_UTF8, 0, ws, -1, NULL, 0, NULL, NULL);
1085+
if (!n) {
1086+
errno = EILSEQ;
1087+
goto done;
1088+
}
1089+
ns = n <= sizeof pb->buffer ? pb->buffer : malloc(n);
1090+
if (!ns)
1091+
goto done;
1092+
if (!WideCharToMultiByte(CP_UTF8, 0, ws, -1, ns, n, NULL, NULL)) {
1093+
if (ns != pb->buffer)
1094+
free(ns);
1095+
ns = NULL;
1096+
errno = EILSEQ;
1097+
goto done;
1098+
}
1099+
1100+
done:
1101+
if (ws != wbuf)
1102+
free (ws);
1103+
1104+
pb->ptr = ns;
1105+
return ns;
1106+
}
1107+
1108+
/**
1109+
* Free the conversion information used by nc4_ndf5_ansi_to_utf8.
1110+
*
1111+
* @param pb Pointer that hold conversion information to be freed.
1112+
*/
1113+
void
1114+
nc4_hdf5_free_pathbuf(pathbuf_t *pb)
1115+
{
1116+
if (pb->ptr && pb->ptr != pb->buffer)
1117+
free(pb->ptr);
1118+
}
1119+
1120+
#endif /* _WIN32 */

libhdf5/hdf5open.c

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ extern int NC4_open_image_file(NC_FILE_INFO_T* h5);
6262
/* Defined later in this file. */
6363
static int rec_read_metadata(NC_GRP_INFO_T *grp);
6464

65+
#ifdef _WIN32
66+
static hid_t nc4_H5Fopen(const char *filename, unsigned flags, hid_t fapl_id);
67+
#else
68+
#define nc4_H5Fopen H5Fopen
69+
#endif
70+
6571
/**
6672
* @internal Struct to track HDF5 object info, for
6773
* rec_read_metadata(). We get this info for every object in the
@@ -833,7 +839,7 @@ nc4_open_file(const char *path, int mode, void* parameters, int ncid)
833839
if (H5Pset_fapl_core(fapl_id, min_incr, (nc4_info->mem.persist?1:0)) < 0)
834840
BAIL(NC_EHDFERR);
835841
/* Open the HDF5 file. */
836-
if ((h5->hdfid = H5Fopen(path, flags, fapl_id)) < 0)
842+
if ((h5->hdfid = nc4_H5Fopen(path, flags, fapl_id)) < 0)
837843
BAIL(NC_EHDFERR);
838844
}
839845
#ifdef ENABLE_BYTERANGE
@@ -843,14 +849,14 @@ nc4_open_file(const char *path, int mode, void* parameters, int ncid)
843849
if (H5Pset_fapl_http(fapl_id) < 0)
844850
BAIL(NC_EHDFERR);
845851
/* Open the HDF5 file. */
846-
if ((h5->hdfid = H5Fopen(path, flags, fapl_id)) < 0)
852+
if ((h5->hdfid = nc4_H5Fopen(path, flags, fapl_id)) < 0)
847853
BAIL(NC_EHDFERR);
848854
}
849855
#endif
850856
else
851857
{
852858
/* Open the HDF5 file. */
853-
if ((h5->hdfid = H5Fopen(path, flags, fapl_id)) < 0)
859+
if ((h5->hdfid = nc4_H5Fopen(path, flags, fapl_id)) < 0)
854860
BAIL(NC_EHDFERR);
855861
}
856862

@@ -2707,3 +2713,30 @@ rec_read_metadata(NC_GRP_INFO_T *grp)
27072713

27082714
return retval;
27092715
}
2716+
2717+
#ifdef _WIN32
2718+
2719+
/**
2720+
* Wrapper function for H5Fopen.
2721+
* Converts the filename from ANSI to UTF-8 as needed before calling H5Fopen.
2722+
*
2723+
* @param filename The filename encoded ANSI to access.
2724+
* @param flags File access flags.
2725+
* @param fapl_id File access property list identifier.
2726+
* @return A file identifier if succeeded. A negative value if failed.
2727+
*/
2728+
static hid_t
2729+
nc4_H5Fopen(const char *filename, unsigned flags, hid_t fapl_id)
2730+
{
2731+
pathbuf_t pb;
2732+
hid_t hid;
2733+
2734+
filename = nc4_ndf5_ansi_to_utf8(&pb, filename);
2735+
if (!filename)
2736+
return H5I_INVALID_HID;
2737+
hid = H5Fopen(filename, flags, fapl_id);
2738+
nc4_hdf5_free_pathbuf(&pb);
2739+
return hid;
2740+
}
2741+
2742+
#endif /* _WIN32 */

0 commit comments

Comments
 (0)