diff options
Diffstat (limited to 'pr/src/linking/prlink.c')
-rw-r--r-- | pr/src/linking/prlink.c | 298 |
1 files changed, 265 insertions, 33 deletions
diff --git a/pr/src/linking/prlink.c b/pr/src/linking/prlink.c index 55831bf7..5f83f257 100644 --- a/pr/src/linking/prlink.c +++ b/pr/src/linking/prlink.c @@ -1,36 +1,40 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * * The Original Code is the Netscape Portable Runtime (NSPR). - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Steve Streeter (Hewlett-Packard Company) - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Steve Streeter (Hewlett-Packard Company) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ #include "primpl.h" @@ -157,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 { @@ -204,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) @@ -244,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"); } @@ -556,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; @@ -744,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. @@ -752,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 * sizeof(PRUnichar)); + 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); @@ -793,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; @@ -996,10 +1102,135 @@ 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; + + utf8Len = WideCharToMultiByte(CP_UTF8, 0, wname, -1, name, len, + NULL, NULL); + /* + * Windows 95 and NT 3.51 don't support CP_UTF8. + * WideCharToMultiByte(CP_UTF8, ...) fails with the error code + * ERROR_INVALID_PARAMETER on Windows 95 and NT 3.51. + */ + if (utf8Len || GetLastError() != ERROR_INVALID_PARAMETER) + return utf8Len; + + 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 */ @@ -1036,7 +1267,8 @@ PR_UnloadLibrary(PRLibrary *lib) #elif defined(USE_HPSHL) result = shl_unload(lib->dlh); #elif defined(USE_MACH_DYLD) - result = NSUnLinkModule(lib->dlh, NSUNLINKMODULE_OPTION_NONE) ? 0 : -1; + if (lib->dlh) + result = NSUnLinkModule(lib->dlh, NSUNLINKMODULE_OPTION_NONE) ? 0 : -1; #else #error Configuration error #endif |