summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwtchang%redhat.com <devnull@localhost>2006-04-05 21:44:01 +0000
committerwtchang%redhat.com <devnull@localhost>2006-04-05 21:44:01 +0000
commitfbef531f065535121984ec1e451f1953697a54a2 (patch)
tree7bf486792eb1b4717b49e3daec772123fc3ad558
parentb20438c667696d76a8027cc7f552824444773f80 (diff)
downloadnspr-hg-fbef531f065535121984ec1e451f1953697a54a2.tar.gz
fixes bug 326168 "Add a UTF-16 API to load a library" patch by
jshin1987@gmail.com r=wtc,darin. Bugzilla Bug 327448: it's not necessary to do dynamic lookup of the W functions because they are also defined (as stubs) on Windows 9x. The patch is contributed by Masatoshi Kimura (emk) <VYV03354@nifty.ne.jp>. r=wtc. Modified Files: prlink.h prtypes.h _win95.h prlink.c w95io.c win32_errors.c Tag: MOZILLA_1_8_BRANCH
-rw-r--r--pr/include/md/_win95.h3
-rw-r--r--pr/include/prlink.h13
-rw-r--r--pr/include/prtypes.h5
-rw-r--r--pr/src/linking/prlink.c225
-rw-r--r--pr/src/md/windows/w95io.c73
-rw-r--r--pr/src/md/windows/win32_errors.c3
6 files changed, 268 insertions, 54 deletions
diff --git a/pr/include/md/_win95.h b/pr/include/md/_win95.h
index cd26bd63..9033a524 100644
--- a/pr/include/md/_win95.h
+++ b/pr/include/md/_win95.h
@@ -265,8 +265,9 @@ extern PRInt32 _MD_CloseFile(PRInt32 osfd);
#define _MD_TLOCKFILE _PR_MD_TLOCKFILE
#define _MD_UNLOCKFILE _PR_MD_UNLOCKFILE
-#ifdef MOZ_UNICODE
/* --- UTF16 IO stuff --- */
+extern PRBool _pr_useUnicode;
+#ifdef MOZ_UNICODE
#define _MD_OPEN_FILE_UTF16 _PR_MD_OPEN_FILE_UTF16
#define _MD_OPEN_DIR_UTF16 _PR_MD_OPEN_DIR_UTF16
#define _MD_READ_DIR_UTF16 _PR_MD_READ_DIR_UTF16
diff --git a/pr/include/prlink.h b/pr/include/prlink.h
index b2eb5141..f0cea829 100644
--- a/pr/include/prlink.h
+++ b/pr/include/prlink.h
@@ -118,15 +118,16 @@ NSPR_API(PRLibrary*) PR_LoadLibrary(const char *name);
** in a library, if code fragments are supported by the OS.
** A code fragment can be specified by name or by an integer index.
**
-** Right now PRLibSpec supports three types of library specification:
-** a pathname, a Mac code fragment by name, and a Mac code fragment
-** by index.
+** Right now PRLibSpec supports four types of library specification:
+** a pathname in the native character encoding, a Mac code fragment
+** by name, a Mac code fragment by index, and a UTF-16 pathname.
*/
typedef enum PRLibSpecType {
PR_LibSpec_Pathname,
PR_LibSpec_MacNamedFragment, /* obsolete (for Mac OS Classic) */
- PR_LibSpec_MacIndexedFragment /* obsolete (for Mac OS Classic) */
+ PR_LibSpec_MacIndexedFragment, /* obsolete (for Mac OS Classic) */
+ PR_LibSpec_PathnameU /* supported only on Win32 */
} PRLibSpecType;
struct FSSpec; /* Mac OS FSSpec */
@@ -148,6 +149,9 @@ typedef struct PRLibSpec {
const struct FSSpec *fsspec;
PRUint32 index;
} mac_indexed_fragment; /* obsolete (for Mac OS Classic) */
+
+ /* if type is PR_LibSpec_PathnameU */
+ const PRUnichar *pathname_u; /* supported only on Win32 */
} value;
} PRLibSpec;
@@ -161,6 +165,7 @@ typedef struct PRLibSpec {
#define PR_LD_NOW 0x2 /* equivalent to RTLD_NOW on Unix */
#define PR_LD_GLOBAL 0x4 /* equivalent to RTLD_GLOBAL on Unix */
#define PR_LD_LOCAL 0x8 /* equivalent to RTLD_LOCAL on Unix */
+/* 0x8000 reserved for NSPR internal use */
/*
** Load the specified library, in the manner specified by 'flags'.
diff --git a/pr/include/prtypes.h b/pr/include/prtypes.h
index 1ed9f995..09fe032a 100644
--- a/pr/include/prtypes.h
+++ b/pr/include/prtypes.h
@@ -470,10 +470,6 @@ typedef PRUint8 PRPackedBool;
*/
typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus;
-#ifdef MOZ_UNICODE
-/*
- * EXPERIMENTAL: This type may be removed in a future release.
- */
#ifndef __PRUNICHAR__
#define __PRUNICHAR__
#if defined(WIN32) || defined(XP_MAC)
@@ -482,7 +478,6 @@ typedef wchar_t PRUnichar;
typedef PRUint16 PRUnichar;
#endif
#endif
-#endif /* MOZ_UNICODE */
/*
** WARNING: The undocumented data types PRWord and PRUword are
diff --git a/pr/src/linking/prlink.c b/pr/src/linking/prlink.c
index 37ccceb3..884983e6 100644
--- a/pr/src/linking/prlink.c
+++ b/pr/src/linking/prlink.c
@@ -161,6 +161,8 @@ struct _imcb *IAC$GL_IMAGE_LIST = NULL;
#define NEED_LEADING_UNDERSCORE
#endif
+#define PR_LD_PATHW 0x8000 /* for PR_LibSpec_PathnameU */
+
/************************************************************************/
struct PRLibrary {
@@ -208,6 +210,16 @@ static char* _pr_currentLibPath = NULL;
static PRLibrary *pr_LoadLibraryByPathname(const char *name, PRIntn flags);
+#ifdef WIN95
+typedef HMODULE (WINAPI *LoadLibraryWFn)(LPCWSTR);
+static HMODULE WINAPI EmulateLoadLibraryW(LPCWSTR);
+static LoadLibraryWFn loadLibraryW = LoadLibraryW;
+#endif
+
+#ifdef WIN32
+static int pr_ConvertUTF16toUTF8(LPCWSTR wname, LPSTR name, int len);
+#endif
+
/************************************************************************/
#if !defined(USE_DLFCN) && !defined(HAVE_STRERROR)
@@ -248,6 +260,12 @@ void _PR_InitLinker(void)
void *h;
#endif
+#ifdef WIN95
+ if (!_pr_useUnicode) {
+ loadLibraryW = EmulateLoadLibraryW;
+ }
+#endif
+
if (!pr_linker_lock) {
pr_linker_lock = PR_NewNamedMonitor("linker-lock");
}
@@ -560,6 +578,16 @@ PR_LoadLibraryWithFlags(PRLibSpec libSpec, PRIntn flags)
switch (libSpec.type) {
case PR_LibSpec_Pathname:
return pr_LoadLibraryByPathname(libSpec.value.pathname, flags);
+#ifdef WIN32
+ case PR_LibSpec_PathnameU:
+ /*
+ * cast to |char *| and set PR_LD_PATHW flag so that
+ * it can be cast back to PRUnichar* in the callee.
+ */
+ return pr_LoadLibraryByPathname((const char*)
+ libSpec.value.pathname_u,
+ flags | PR_LD_PATHW);
+#endif
default:
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
return NULL;
@@ -748,6 +776,25 @@ pr_LoadViaDyld(const char *name, PRLibrary *lm)
#endif /* XP_MACOSX */
+#ifdef WIN95
+static HMODULE WINAPI
+EmulateLoadLibraryW(LPCWSTR lpLibFileName)
+{
+ HMODULE h;
+ char nameA[MAX_PATH];
+
+ if (!WideCharToMultiByte(CP_ACP, 0, lpLibFileName, -1,
+ nameA, sizeof nameA, NULL, NULL)) {
+ return NULL;
+ }
+ /* Perhaps it's better to add a check for characters
+ * not representable in CP_ACP.
+ */
+ h = LoadLibraryA(nameA);
+ return h;
+}
+#endif /* WIN95 */
+
/*
** Dynamically load a library. Only load libraries once, so scan the load
** map first.
@@ -756,15 +803,52 @@ static PRLibrary*
pr_LoadLibraryByPathname(const char *name, PRIntn flags)
{
PRLibrary *lm;
- PRLibrary* result;
+ PRLibrary* result = NULL;
PRInt32 oserr;
+#ifdef WIN32
+ char utf8name_stack[MAX_PATH];
+ char *utf8name_malloc = NULL;
+ char *utf8name = utf8name_stack;
+ PRUnichar wname_stack[MAX_PATH];
+ PRUnichar *wname_malloc = NULL;
+ PRUnichar *wname = wname_stack;
+ int len;
+#endif
if (!_pr_initialized) _PR_ImplicitInitialization();
/* See if library is already loaded */
PR_EnterMonitor(pr_linker_lock);
+#ifdef WIN32
+ if (flags & PR_LD_PATHW) {
+ /* cast back what's cast to |char *| for the argument passing. */
+ wname = (LPWSTR) name;
+ } else {
+ int wlen = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
+ if (wlen > MAX_PATH)
+ wname = wname_malloc = PR_Malloc(wlen);
+ if (wname == NULL ||
+ !MultiByteToWideChar(CP_ACP, 0, name, -1, wname, wlen)) {
+ oserr = _MD_ERRNO();
+ goto unlock;
+ }
+ }
+ len = pr_ConvertUTF16toUTF8(wname, NULL, 0);
+ if (len > MAX_PATH)
+ utf8name = utf8name_malloc = PR_Malloc(len);
+ if (utf8name == NULL ||
+ !pr_ConvertUTF16toUTF8(wname, utf8name, len)) {
+ oserr = _MD_ERRNO();
+ goto unlock;
+ }
+ /* the list of loaded library names are always kept in UTF-8
+ * on Win32 platforms */
+ result = pr_UnlockedFindLibrary(utf8name);
+#else
result = pr_UnlockedFindLibrary(name);
+#endif
+
if (result != NULL) goto unlock;
lm = PR_NEWZAP(PRLibrary);
@@ -797,13 +881,31 @@ pr_LoadLibraryByPathname(const char *name, PRIntn flags)
{
HINSTANCE h;
+#ifdef WIN32
+#ifdef WIN95
+ if (flags & PR_LD_PATHW)
+ h = loadLibraryW(wname);
+ else
+ h = LoadLibraryA(name);
+#else
+ if (flags & PR_LD_PATHW)
+ h = LoadLibraryW(wname);
+ else
+ h = LoadLibraryA(name);
+#endif /* WIN95 */
+#else
h = LoadLibrary(name);
+#endif
if (h < (HINSTANCE)HINSTANCE_ERROR) {
oserr = _MD_ERRNO();
PR_DELETE(lm);
goto unlock;
}
+#ifdef WIN32
+ lm->name = strdup(utf8name);
+#else
lm->name = strdup(name);
+#endif
lm->dlh = h;
lm->next = pr_loadmap;
pr_loadmap = lm;
@@ -1000,10 +1102,131 @@ pr_LoadLibraryByPathname(const char *name, PRIntn flags)
PR_SetError(PR_LOAD_LIBRARY_ERROR, oserr);
DLLErrorInternal(oserr); /* sets error text */
}
+#ifdef WIN32
+ if (utf8name_malloc)
+ PR_Free(utf8name_malloc);
+ if (wname_malloc)
+ PR_Free(wname_malloc);
+#endif
PR_ExitMonitor(pr_linker_lock);
return result;
}
+#ifdef WIN32
+#ifdef WIN95
+/*
+ * CP_UTF8 is not supported by WideCharToMultiByte on Windows 95 so that
+ * we have to emulate it
+ */
+static PRStatus
+pr_ConvertSingleCharToUTF8(PRUint32 usv, PRUint16 offset, int bufLen,
+ int *utf8Len, char * *buf)
+{
+ char* p = *buf;
+ PR_ASSERT(!bufLen || *buf);
+ if (!bufLen) {
+ *utf8Len += offset;
+ return PR_SUCCESS;
+ }
+
+ if (*utf8Len + offset >= bufLen)
+ return PR_FAILURE;
+
+ *utf8Len += offset;
+ if (offset == 1) {
+ *p++ = (char) usv;
+ } else if (offset == 2) {
+ *p++ = (char)0xc0 | (usv >> 6);
+ *p++ = (char)0x80 | (usv & 0x003f);
+ } else if (offset == 3) {
+ *p++ = (char)0xe0 | (usv >> 12);
+ *p++ = (char)0x80 | ((usv >> 6) & 0x003f);
+ *p++ = (char)0x80 | (usv & 0x003f);
+ } else { /* offset = 4 */
+ *p++ = (char)0xf0 | (usv >> 18);
+ *p++ = (char)0x80 | ((usv >> 12) & 0x003f);
+ *p++ = (char)0x80 | ((usv >> 6) & 0x003f);
+ *p++ = (char)0x80 | (usv & 0x003f);
+ }
+
+ *buf = p;
+ return PR_SUCCESS;
+}
+
+static int pr_ConvertUTF16toUTF8(LPCWSTR wname, LPSTR name, int len)
+{
+ LPCWSTR pw = wname;
+ LPSTR p = name;
+ int utf8Len = 0;
+ PRBool highSurrogate = PR_FALSE;
+
+ /* Windows NT4/2k/XP supports CP_UTF8. So do Win 98/ME, but
+ * we don't bother to optimize for them. */
+ if (_pr_useUnicode)
+ return WideCharToMultiByte(CP_UTF8, 0, wname, -1, name, len,
+ NULL, NULL);
+
+ if (!wname || len < 0 || (len > 0 && !name)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ while (*pw) {
+ PRStatus status = PR_SUCCESS;
+ if (highSurrogate) {
+ if (*pw >= (PRUnichar) 0xDC00 && *pw < (PRUnichar) 0xE000) {
+ /* found a matching low surrogate */
+ /* convert a surrogate pair to UCS4 */
+ PRUint32 usv = ((*(pw-1) - (PRUnichar)0xD800) << 10) +
+ (*pw - (PRUnichar)0xDC00) + (PRUint32)0x10000;
+ if (pr_ConvertSingleCharToUTF8(usv, 4, len, &utf8Len, &p) ==
+ PR_FAILURE)
+ return 0;
+ highSurrogate = PR_FALSE;
+ ++pw;
+ continue;
+ } else {
+ /*
+ * silently ignore a lone high surrogate
+ * as is done by WideCharToMultiByte by default
+ */
+ highSurrogate = PR_FALSE;
+ }
+ }
+ if (*pw <= 0x7f)
+ status = pr_ConvertSingleCharToUTF8(*pw, 1, len, &utf8Len, &p);
+ else if (*pw <= 0x07ff)
+ status = pr_ConvertSingleCharToUTF8(*pw, 2, len, &utf8Len, &p);
+ else if (*pw < (PRUnichar) 0xD800 || *pw >= (PRUnichar) 0xE000)
+ status = pr_ConvertSingleCharToUTF8(*pw, 3, len, &utf8Len, &p);
+ else if (*pw < (PRUnichar) 0xDC00)
+ highSurrogate = PR_TRUE;
+ /* else */
+ /* silently ignore a lone low surrogate as is done by
+ * WideCharToMultiByte by default */
+
+ if (status == PR_FAILURE) {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
+ }
+ ++pw;
+ }
+
+ /* if we're concerned with a lone high surrogate,
+ * we have to take care of it here, but we just drop it
+ */
+ if (len > 0)
+ *p = '\0';
+ return utf8Len + 1;
+}
+#else
+static int pr_ConvertUTF16toUTF8(LPCWSTR wname, LPSTR name, int len)
+{
+ return WideCharToMultiByte(CP_UTF8, 0, wname, -1, name, len, NULL, NULL);
+}
+#endif /* WIN95 */
+#endif /* WIN32 */
+
/*
** Unload a shared library which was loaded via PR_LoadLibrary
*/
diff --git a/pr/src/md/windows/w95io.c b/pr/src/md/windows/w95io.c
index 88b33558..087eac19 100644
--- a/pr/src/md/windows/w95io.c
+++ b/pr/src/md/windows/w95io.c
@@ -81,9 +81,7 @@ static const PRTime _pr_filetime_offset = 116444736000000000LL;
static const PRTime _pr_filetime_offset = 116444736000000000i64;
#endif
-#ifdef MOZ_UNICODE
static void InitUnicodeSupport(void);
-#endif
static PRBool IsPrevCharSlash(const char *str, const char *current);
@@ -124,9 +122,7 @@ _PR_MD_INIT_IO()
_PR_NT_InitSids();
-#ifdef MOZ_UNICODE
InitUnicodeSupport();
-#endif
}
PRStatus
@@ -1120,38 +1116,49 @@ _PR_MD_PIPEAVAILABLE(PRFileDesc *fd)
#ifdef MOZ_UNICODE
typedef HANDLE (WINAPI *CreateFileWFn) (LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
-static CreateFileWFn createFileW = NULL;
+static CreateFileWFn createFileW = CreateFileW;
typedef HANDLE (WINAPI *FindFirstFileWFn) (LPCWSTR, LPWIN32_FIND_DATAW);
-static FindFirstFileWFn findFirstFileW = NULL;
+static FindFirstFileWFn findFirstFileW = FindFirstFileW;
typedef BOOL (WINAPI *FindNextFileWFn) (HANDLE, LPWIN32_FIND_DATAW);
-static FindNextFileWFn findNextFileW = NULL;
+static FindNextFileWFn findNextFileW = FindNextFileW;
typedef DWORD (WINAPI *GetFullPathNameWFn) (LPCWSTR, DWORD, LPWSTR, LPWSTR *);
-static GetFullPathNameWFn getFullPathNameW = NULL;
+static GetFullPathNameWFn getFullPathNameW = GetFullPathNameW;
typedef UINT (WINAPI *GetDriveTypeWFn) (LPCWSTR);
-static GetDriveTypeWFn getDriveTypeW = NULL;
+static GetDriveTypeWFn getDriveTypeW = GetDriveTypeW;
+
+#endif /* MOZ_UNICODE */
+
+PRBool _pr_useUnicode = PR_FALSE;
static void InitUnicodeSupport(void)
{
- HMODULE module;
-
/*
- * The W functions do not exist on Win9x. NSPR won't run on Win9x
- * if we call the W functions directly. Use GetProcAddress() to
- * look up their addresses at run time.
+ * The W functions exist on Win9x as stubs that fail with the
+ * ERROR_CALL_NOT_IMPLEMENTED error. We plan to emulate the
+ * MSLU W functions on Win9x in the future.
*/
- module = GetModuleHandle("Kernel32.dll");
- if (!module) {
- return;
- }
+ /* Find out if we are running on a Unicode enabled version of Windows */
+ OSVERSIONINFOA osvi = {0};
- createFileW = (CreateFileWFn)GetProcAddress(module, "CreateFileW");
- findFirstFileW = (FindFirstFileWFn)GetProcAddress(module, "FindFirstFileW");
- findNextFileW = (FindNextFileWFn)GetProcAddress(module, "FindNextFileW");
- getDriveTypeW = (GetDriveTypeWFn)GetProcAddress(module, "GetDriveTypeW");
- getFullPathNameW = (GetFullPathNameWFn)GetProcAddress(module, "GetFullPathNameW");
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+ if (GetVersionExA(&osvi)) {
+ _pr_useUnicode = (osvi.dwPlatformId >= VER_PLATFORM_WIN32_NT);
+ } else {
+ _pr_useUnicode = PR_FALSE;
+ }
+#ifdef DEBUG
+ /*
+ * In debug builds, allow explicit use of ANSI methods to simulate
+ * a Win9x environment for testing purposes.
+ */
+ if (getenv("WINAPI_USE_ANSI"))
+ _pr_useUnicode = PR_FALSE;
+#endif
}
+#ifdef MOZ_UNICODE
+
/* ================ UTF16 Interfaces ================================ */
void FlipSlashesW(PRUnichar *cp, int len)
{
@@ -1175,11 +1182,6 @@ _PR_MD_OPEN_FILE_UTF16(const PRUnichar *name, PRIntn osflags, int mode)
PSECURITY_DESCRIPTOR pSD = NULL;
PACL pACL = NULL;
- if (!createFileW) {
- PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
- return -1;
- }
-
if (osflags & PR_CREATE_FILE) {
if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable,
&pSD, &pACL) == PR_SUCCESS) {
@@ -1235,11 +1237,6 @@ _PR_MD_OPEN_DIR_UTF16(_MDDirUTF16 *d, const PRUnichar *name)
PRUnichar filename[ MAX_PATH ];
int len;
- if (!findFirstFileW) {
- PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
- return PR_FAILURE;
- }
-
len = wcslen(name);
/* Need 5 bytes for \*.* and the trailing null byte. */
if (len + 5 > MAX_PATH) {
@@ -1275,11 +1272,6 @@ _PR_MD_READ_DIR_UTF16(_MDDirUTF16 *d, PRIntn flags)
BOOL rv;
PRUnichar *fileName;
- if (!findNextFileW) {
- PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
- return NULL;
- }
-
if ( d ) {
while (1) {
if (d->firstEntry) {
@@ -1425,11 +1417,6 @@ _PR_MD_GETFILEINFO64_UTF16(const PRUnichar *fn, PRFileInfo64 *info)
WIN32_FIND_DATAW findFileData;
PRUnichar pathbuf[MAX_PATH + 1];
- if (!findFirstFileW || !getFullPathNameW || !getDriveTypeW) {
- PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
- return -1;
- }
-
if (NULL == fn || L'\0' == *fn) {
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
return -1;
diff --git a/pr/src/md/windows/win32_errors.c b/pr/src/md/windows/win32_errors.c
index 0cf1bb58..ced1b7aa 100644
--- a/pr/src/md/windows/win32_errors.c
+++ b/pr/src/md/windows/win32_errors.c
@@ -89,6 +89,9 @@ void _MD_win32_map_default_error(PRInt32 err)
case ERROR_ALREADY_EXISTS:
prError = PR_FILE_EXISTS_ERROR;
break;
+ case ERROR_CALL_NOT_IMPLEMENTED:
+ prError = PR_NOT_IMPLEMENTED_ERROR;
+ break;
case ERROR_DISK_CORRUPT:
prError = PR_IO_ERROR;
break;