diff options
author | wtchang%redhat.com <devnull@localhost> | 2006-04-05 21:44:01 +0000 |
---|---|---|
committer | wtchang%redhat.com <devnull@localhost> | 2006-04-05 21:44:01 +0000 |
commit | fbef531f065535121984ec1e451f1953697a54a2 (patch) | |
tree | 7bf486792eb1b4717b49e3daec772123fc3ad558 | |
parent | b20438c667696d76a8027cc7f552824444773f80 (diff) | |
download | nspr-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.h | 3 | ||||
-rw-r--r-- | pr/include/prlink.h | 13 | ||||
-rw-r--r-- | pr/include/prtypes.h | 5 | ||||
-rw-r--r-- | pr/src/linking/prlink.c | 225 | ||||
-rw-r--r-- | pr/src/md/windows/w95io.c | 73 | ||||
-rw-r--r-- | pr/src/md/windows/win32_errors.c | 3 |
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; |