fixes bug 326168 "Add a UTF-16 API to load a library" patch by jshin1987@gmail.com r=wtc,darin
git-svn-id: svn://10.0.0.236/trunk@192138 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -273,8 +273,9 @@ extern PRInt32 _MD_CloseFile(PROsfd 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
|
||||
|
||||
@@ -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 charset, 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 */
|
||||
/* 0x400 reserved for NSPR internal use */
|
||||
|
||||
/*
|
||||
** Load the specified library, in the manner specified by 'flags'.
|
||||
|
||||
@@ -474,19 +474,14 @@ 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)
|
||||
#if (defined(__MWERKS__) || defined(_MSC_VER)) && defined(WIN32)
|
||||
typedef wchar_t PRUnichar;
|
||||
#else
|
||||
typedef PRUint16 PRUnichar;
|
||||
#endif
|
||||
#endif
|
||||
#endif /* MOZ_UNICODE */
|
||||
|
||||
/*
|
||||
** WARNING: The undocumented data types PRWord and PRUword are
|
||||
|
||||
@@ -157,6 +157,10 @@ struct _imcb *IAC$GL_IMAGE_LIST = NULL;
|
||||
#define NEED_LEADING_UNDERSCORE
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define PR_LD_PATHW 0x400 /* for PR_LibSpec_PathnameU */
|
||||
#endif
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
struct PRLibrary {
|
||||
@@ -204,6 +208,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)
|
||||
@@ -244,6 +258,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");
|
||||
}
|
||||
@@ -556,6 +576,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;
|
||||
@@ -752,6 +782,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.
|
||||
@@ -762,13 +811,48 @@ pr_LoadLibraryByPathname(const char *name, PRIntn flags)
|
||||
PRLibrary *lm;
|
||||
PRLibrary* result;
|
||||
PRInt32 oserr;
|
||||
#ifdef WIN32
|
||||
char utf8name_stack[MAX_PATH];
|
||||
PRUnichar wname_stack[MAX_PATH];
|
||||
char *utf8name = utf8name_stack;
|
||||
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 = 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 = 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);
|
||||
@@ -801,13 +885,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;
|
||||
@@ -1008,10 +1110,132 @@ pr_LoadLibraryByPathname(const char *name, PRIntn flags)
|
||||
PR_SetError(PR_LOAD_LIBRARY_ERROR, oserr);
|
||||
DLLErrorInternal(oserr); /* sets error text */
|
||||
}
|
||||
#ifdef WIN32
|
||||
if (utf8name && utf8name != utf8name_stack)
|
||||
PR_Free(utf8name);
|
||||
if (!(flags & PR_LD_PATHW) && wname && wname != wname_stack)
|
||||
PR_Free(wname);
|
||||
#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)
|
||||
{
|
||||
/* XXX No error checking. Add it for debug build */
|
||||
char* p = *buf;
|
||||
/*if (!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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -1130,6 +1126,10 @@ static GetFullPathNameWFn getFullPathNameW = GetFullPathNameW;
|
||||
typedef UINT (WINAPI *GetDriveTypeWFn) (LPCWSTR);
|
||||
static GetDriveTypeWFn getDriveTypeW = GetDriveTypeW;
|
||||
|
||||
#endif /* MOZ_UNICODE */
|
||||
|
||||
PRBool _pr_useUnicode = PR_FALSE;
|
||||
|
||||
static void InitUnicodeSupport(void)
|
||||
{
|
||||
/*
|
||||
@@ -1137,8 +1137,25 @@ static void InitUnicodeSupport(void)
|
||||
* ERROR_CALL_NOT_IMPLEMENTED error. We plan to emulate the
|
||||
* MSLU W functions on Win9x in the future.
|
||||
*/
|
||||
|
||||
/* Find out if we are running on a Unicode enabled version of Windows */
|
||||
OSVERSIONINFOA osvi = {0};
|
||||
|
||||
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 for testing. */
|
||||
if (getenv("WINAPI_USE_ANSI"))
|
||||
_pr_useUnicode = PR_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MOZ_UNICODE
|
||||
|
||||
/* ================ UTF16 Interfaces ================================ */
|
||||
void FlipSlashesW(PRUnichar *cp, size_t len)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user