[PATCH 2/8] Files: add wrappers for open(), fopen(), sqlite3_open()

Lubomir I. Ivanov neolit123 at gmail.com
Wed Dec 18 16:03:29 UTC 2013


From: "Lubomir I. Ivanov" <neolit123 at gmail.com>

Win32 has troubles opening paths with special chacters.
To work around that we convert UTF-8 strings to UTF-16
and use functions like _wopen() and _wfopen().

The new wrapper functions have the subsurface_ prefix.

Signed-off-by: Lubomir I. Ivanov <neolit123 at gmail.com>
---
thiago suggested that we optimize the _wfopen call a little
by skipping one utf8_to_utf16_fl() call.

and also to assert in utf8_to_utf16_fl(), when some of the
arguments are bogus.

the utf8_to_utf16_fl() function itself calls MultiByteToWideChar()
only once now.
---
 dive.h    |  5 +++++
 linux.c   | 19 +++++++++++++++++
 macos.c   | 19 +++++++++++++++++
 windows.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 116 insertions(+)

diff --git a/dive.h b/dive.h
index 46c42fc..faacd28 100644
--- a/dive.h
+++ b/dive.h
@@ -5,6 +5,7 @@
 #include <stdint.h>
 #include <time.h>
 #include <math.h>
+#include <sqlite3.h>
 
 /* Windows has no MIN/MAX macros - so let's just roll our own */
 #define MIN(x, y) ({                \
@@ -633,6 +634,10 @@ extern void save_dives_logic(const char *filename, bool select_only);
 extern void save_dive(FILE *f, struct dive *dive);
 extern void export_dives_uddf(const char *filename, const bool selected);
 
+extern int subsurface_open(const char *path, int oflags, mode_t mode);
+extern FILE *subsurface_fopen(const char *path, const char *mode);
+extern int subsurface_sqlite3_open(const char *path, sqlite3 **handle);
+
 extern void shift_times(const timestamp_t amount);
 
 extern xsltStylesheetPtr get_stylesheet(const char *name);
diff --git a/linux.c b/linux.c
index 5006ca0..6c760ac 100644
--- a/linux.c
+++ b/linux.c
@@ -6,6 +6,9 @@
 #include <sys/types.h>
 #include <dirent.h>
 #include <fnmatch.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sqlite3.h>
 
 const char system_divelist_default_font[] = "Sans 8";
 
@@ -97,3 +100,19 @@ int enumerate_devices (device_callback_t callback, void *userdata)
 
 	return index;
 }
+
+/* NOP wrappers to comform with windows.c */
+int subsurface_open(const char *path, int oflags, mode_t mode)
+{
+	return open(path, oflags, mode);
+}
+
+FILE *subsurface_fopen(const char *path, const char *mode)
+{
+	return fopen(path, mode);
+}
+
+int subsurface_sqlite3_open(const char *path, sqlite3 **handle)
+{
+	return sqlite3_open(path, handle);
+}
diff --git a/macos.c b/macos.c
index 64b23a7..eda291d 100644
--- a/macos.c
+++ b/macos.c
@@ -9,6 +9,9 @@
 #include <CoreServices/CoreServices.h>
 #include <mach-o/dyld.h>
 #include <sys/syslimits.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sqlite3.h>
 
 /* macos defines CFSTR to create a CFString object from a constant,
  * but no similar macros if a C string variable is supposed to be
@@ -77,3 +80,19 @@ int enumerate_devices (device_callback_t callback, void *userdata)
 	closedir (dp);
 	return index;
 }
+
+/* NOP wrappers to comform with windows.c */
+int subsurface_open(const char *path, int oflags, mode_t mode)
+{
+	return open(path, oflags, mode);
+}
+
+FILE *subsurface_fopen(const char *path, const char *mode)
+{
+	return fopen(path, mode);
+}
+
+int subsurface_sqlite3_open(const char *path, sqlite3 **handle)
+{
+	return sqlite3_open(path, handle);
+}
diff --git a/windows.c b/windows.c
index ff6e2e0..7783ea1 100644
--- a/windows.c
+++ b/windows.c
@@ -4,6 +4,10 @@
 #include "display.h"
 #include <windows.h>
 #include <shlobj.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sqlite3.h>
+#include <assert.h>
 
 const char system_divelist_default_font[] = "Sans 8";
 
@@ -78,3 +82,72 @@ int enumerate_devices (device_callback_t callback, void *userdata)
 	RegCloseKey(hKey);
 	return index;
 }
+
+/* this function converts a utf-8 string to win32's utf-16 2 byte string.
+ * the caller function should manage the allocated memory.
+ */
+static wchar_t *utf8_to_utf16_fl(const char *utf8, char *file, int line)
+{
+	assert(utf8 != NULL);
+	assert(file != NULL);
+	assert(line);
+	/* estimate buffer size */
+	const int sz = strlen(utf8) + 1;
+	wchar_t *utf16 = (wchar_t *)malloc(sizeof(wchar_t) * sz);
+	if (!utf16) {
+		fprintf(stderr, "%s:%d: %s %d.", file, line, "cannot allocate buffer of size", sz);
+		return NULL;
+	}
+	if (MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, sz))
+		return utf16;
+	fprintf(stderr, "%s:%d: %s", file, line, "cannot convert string.");
+	free((void *)utf16);
+	return NULL;
+}
+
+#define utf8_to_utf16(s) utf8_to_utf16_fl(s, __FILE__, __LINE__)
+
+/* bellow we provide a set of wrappers for some I/O functions to use wchar_t.
+ * on win32 this solves the issue that we need paths to be utf-16 encoded.
+ */
+int subsurface_open(const char *path, int oflags, mode_t mode)
+{
+	int ret = -1;
+	wchar_t *wpath = utf8_to_utf16(path);
+	if (wpath) {
+		ret = _wopen(wpath, oflags, mode);
+		free((void *)wpath);
+		return ret;
+	}
+	return ret;
+}
+
+FILE *subsurface_fopen(const char *path, const char *mode)
+{
+	FILE *ret = NULL;
+	wchar_t *wpath = utf8_to_utf16(path);
+	if (wpath) {
+		const int len = strlen(mode);
+		wchar_t wmode[len + 1];
+		for (int i = 0; i < len; i++)
+			wmode[i] = (wchar_t)mode[i];
+		wmode[len] = 0;
+		ret = _wfopen(wpath, wmode);
+		free((void *)wpath);
+		return ret;
+	}
+	return ret;
+}
+
+int subsurface_sqlite3_open(const char *path, sqlite3 **handle)
+{
+	int ret = SQLITE_ERROR;
+	wchar_t *wpath = utf8_to_utf16(path);
+	if (wpath) {
+		/* try to use _open16 here */
+		ret = sqlite3_open16((const void *)wpath, handle);
+		free((void *)wpath);
+		return ret;
+	}
+	return ret;
+}
-- 
1.7.11.msysgit.0



More information about the subsurface mailing list