diff --git a/include/hdf5internal.h b/include/hdf5internal.h index e3215ae12..503827378 100644 --- a/include/hdf5internal.h +++ b/include/hdf5internal.h @@ -197,4 +197,23 @@ extern int NC4_isnetcdf4(struct NC_FILE_INFO*); /*libsrc4/nc4hdf.c*/ extern int nc4_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var); +#ifdef _WIN32 + +/* Maxinum length of a typical path in UTF-8. + * When converting from ANSI to UTF-8, the length will be up to 3 times, + * so round up 260*3 to 1024. (260=MAX_PATH) */ +#define MAX_PATHBUF_SIZE 1024 + +/* Struct for converting ANSI to UTF-8. */ +typedef struct pathbuf +{ + void *ptr; + char buffer[MAX_PATHBUF_SIZE]; +} pathbuf_t; + +const char *nc4_ndf5_ansi_to_utf8(pathbuf_t *pb, const char *path); +void nc4_hdf5_free_pathbuf(pathbuf_t *pb); + +#endif /* _WIN32 */ + #endif /* _HDF5INTERNAL_ */ diff --git a/libhdf5/hdf5create.c b/libhdf5/hdf5create.c index e3a791dcb..27a99405c 100644 --- a/libhdf5/hdf5create.c +++ b/libhdf5/hdf5create.c @@ -22,6 +22,12 @@ static const int ILLEGAL_CREATE_FLAGS = (NC_NOWRITE|NC_MMAP|NC_64BIT_OFFSET|NC_C /* From nc4mem.c */ extern int NC4_create_image_file(NC_FILE_INFO_T* h5, size_t); +#ifdef _WIN32 +static hid_t nc4_H5Fcreate(const char *filename, unsigned flags, hid_t fcpl_id, hid_t fapl_id); +#else +#define nc4_H5Fcreate H5Fcreate +#endif + /** * @internal Create a netCDF-4/HDF5 file. * @@ -217,13 +223,13 @@ nc4_create_file(const char *path, int cmode, size_t initialsz, /* Configure FAPL to use the core file driver */ if (H5Pset_fapl_core(fapl_id, alloc_incr, (nc4_info->mem.persist?1:0)) < 0) BAIL(NC_EHDFERR); - if ((hdf5_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0) + if ((hdf5_info->hdfid = nc4_H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0) BAIL(EACCES); } else /* Normal file */ { /* Create the HDF5 file. */ - if ((hdf5_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0) + if ((hdf5_info->hdfid = nc4_H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0) BAIL(EACCES); } @@ -306,3 +312,31 @@ NC4_create(const char* path, int cmode, size_t initialsz, int basepe, return res; } + +#ifdef _WIN32 + +/** + * Wrapper function for H5Fcreate. + * Converts the filename from ANSI to UTF-8 as needed before calling H5Fcreate. + * + * @param filename The filename encoded ANSI to access. + * @param flags File access flags. + * @param fcpl_id File creation property list identifier. + * @param fapl_id File access property list identifier. + * @return A file identifier if succeeded. A negative value if failed. + */ +static hid_t +nc4_H5Fcreate(const char *filename, unsigned flags, hid_t fcpl_id, hid_t fapl_id) +{ + pathbuf_t pb; + hid_t hid; + + filename = nc4_ndf5_ansi_to_utf8(&pb, filename); + if (!filename) + return H5I_INVALID_HID; + hid = H5Fcreate(filename, flags, fcpl_id, fapl_id); + nc4_hdf5_free_pathbuf(&pb); + return hid; +} + +#endif /* _WIN32 */ diff --git a/libhdf5/hdf5internal.c b/libhdf5/hdf5internal.c index 493f06cd5..1a3a42624 100644 --- a/libhdf5/hdf5internal.c +++ b/libhdf5/hdf5internal.c @@ -17,6 +17,9 @@ #include "config.h" #include "hdf5internal.h" #include "ncfilter.h" +#ifdef _WIN32 +#include +#endif #undef DEBUGH5 @@ -1027,3 +1030,91 @@ hdf5_set_log_level() return NC_NOERR; } #endif /* LOGGING */ + + +#ifdef _WIN32 + +/** + * Converts the filename from ANSI to UTF-8 if HDF5 >= 1.10.6. + * nc4_hdf5_free_pathbuf must be called to free pb. + * + * @param pb Pointer that conversion information is stored. + * @param path The filename to be converted. + * + * @return The converted filename if succeeded. NULL if failed. + */ +const char * +nc4_ndf5_ansi_to_utf8(pathbuf_t *pb, const char *path) +{ + const uint UTF8_MAJNUM = 1; + const uint UTF8_MINNUM = 10; + const uint UTF8_RELNUM = 6; + static enum {UNDEF, ANSI, UTF8} hdf5_encoding = UNDEF; + wchar_t wbuf[MAX_PATH]; + wchar_t *ws = NULL; + char *ns = NULL; + int n; + + if (hdf5_encoding == UNDEF) { + uint majnum, minnum, relnum; + H5get_libversion(&majnum, &minnum, &relnum); + hdf5_encoding = (((majnum == UTF8_MAJNUM && minnum == UTF8_MINNUM && relnum >= UTF8_RELNUM) + || (majnum == UTF8_MAJNUM && minnum > UTF8_MINNUM) + || majnum > UTF8_MAJNUM) + ? UTF8 : ANSI); + } + if (hdf5_encoding == ANSI) { + pb->ptr = NULL; + return path; + } + + n = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0); + if (!n) { + errno = EILSEQ; + goto done; + } + ws = n <= _countof(wbuf) ? wbuf : malloc(sizeof *ws * n); + if (!ws) + goto done; + if (!MultiByteToWideChar(CP_ACP, 0, path, -1, ws, n)) { + errno = EILSEQ; + goto done; + } + + n = WideCharToMultiByte(CP_UTF8, 0, ws, -1, NULL, 0, NULL, NULL); + if (!n) { + errno = EILSEQ; + goto done; + } + ns = n <= sizeof pb->buffer ? pb->buffer : malloc(n); + if (!ns) + goto done; + if (!WideCharToMultiByte(CP_UTF8, 0, ws, -1, ns, n, NULL, NULL)) { + if (ns != pb->buffer) + free(ns); + ns = NULL; + errno = EILSEQ; + goto done; + } + +done: + if (ws != wbuf) + free (ws); + + pb->ptr = ns; + return ns; +} + +/** + * Free the conversion information used by nc4_ndf5_ansi_to_utf8. + * + * @param pb Pointer that hold conversion information to be freed. + */ +void +nc4_hdf5_free_pathbuf(pathbuf_t *pb) +{ + if (pb->ptr && pb->ptr != pb->buffer) + free(pb->ptr); +} + +#endif /* _WIN32 */ diff --git a/libhdf5/hdf5open.c b/libhdf5/hdf5open.c index e492b4573..06b5adbae 100644 --- a/libhdf5/hdf5open.c +++ b/libhdf5/hdf5open.c @@ -62,6 +62,12 @@ extern int NC4_open_image_file(NC_FILE_INFO_T* h5); /* Defined later in this file. */ static int rec_read_metadata(NC_GRP_INFO_T *grp); +#ifdef _WIN32 +static hid_t nc4_H5Fopen(const char *filename, unsigned flags, hid_t fapl_id); +#else +#define nc4_H5Fopen H5Fopen +#endif + /** * @internal Struct to track HDF5 object info, for * 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) if (H5Pset_fapl_core(fapl_id, min_incr, (nc4_info->mem.persist?1:0)) < 0) BAIL(NC_EHDFERR); /* Open the HDF5 file. */ - if ((h5->hdfid = H5Fopen(path, flags, fapl_id)) < 0) + if ((h5->hdfid = nc4_H5Fopen(path, flags, fapl_id)) < 0) BAIL(NC_EHDFERR); } #ifdef ENABLE_BYTERANGE @@ -843,14 +849,14 @@ nc4_open_file(const char *path, int mode, void* parameters, int ncid) if (H5Pset_fapl_http(fapl_id) < 0) BAIL(NC_EHDFERR); /* Open the HDF5 file. */ - if ((h5->hdfid = H5Fopen(path, flags, fapl_id)) < 0) + if ((h5->hdfid = nc4_H5Fopen(path, flags, fapl_id)) < 0) BAIL(NC_EHDFERR); } #endif else { /* Open the HDF5 file. */ - if ((h5->hdfid = H5Fopen(path, flags, fapl_id)) < 0) + if ((h5->hdfid = nc4_H5Fopen(path, flags, fapl_id)) < 0) BAIL(NC_EHDFERR); } @@ -2707,3 +2713,30 @@ exit: return retval; } + +#ifdef _WIN32 + +/** + * Wrapper function for H5Fopen. + * Converts the filename from ANSI to UTF-8 as needed before calling H5Fopen. + * + * @param filename The filename encoded ANSI to access. + * @param flags File access flags. + * @param fapl_id File access property list identifier. + * @return A file identifier if succeeded. A negative value if failed. + */ +static hid_t +nc4_H5Fopen(const char *filename, unsigned flags, hid_t fapl_id) +{ + pathbuf_t pb; + hid_t hid; + + filename = nc4_ndf5_ansi_to_utf8(&pb, filename); + if (!filename) + return H5I_INVALID_HID; + hid = H5Fopen(filename, flags, fapl_id); + nc4_hdf5_free_pathbuf(&pb); + return hid; +} + +#endif /* _WIN32 */