1/* 2Copyright 1985, 1986, 1987, 1991, 1998 The Open Group 3 4Permission is hereby granted, free of charge, to any person obtaining a 5copy of this software and associated documentation files (the 6"Software"), to deal in the Software without restriction, including 7without limitation the rights to use, copy, modify, merge, publish, 8distribute, sublicense, and/or sell copies of the Software, and to 9permit persons to whom the Software is furnished to do so, subject to 10the following conditions: The above copyright notice and this 11permission notice shall be included in all copies or substantial 12portions of the Software. 13 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE 21EVEN IF ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES. 22 23 24Except as contained in this notice, the name of The Open Group shall not be 25used in advertising or otherwise to promote the sale, use or other dealings 26in this Software without prior written authorization from The Open Group. 27 28 29X Window System is a trademark of The Open Group 30 31OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF 32logo, LBX, X Window System, and Xinerama are trademarks of the Open 33Group. All other trademarks and registered trademarks mentioned herein 34are the property of their respective owners. No right, title or 35interest in or to any trademark, service mark, logo or trade name of 36Sun Microsystems, Inc. or its licensors is granted. 37 38*/ 39/* 40 * Copyright (c) 2000, Oracle and/or its affiliates. 41 * 42 * Permission is hereby granted, free of charge, to any person obtaining a 43 * copy of this software and associated documentation files (the "Software"), 44 * to deal in the Software without restriction, including without limitation 45 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 46 * and/or sell copies of the Software, and to permit persons to whom the 47 * Software is furnished to do so, subject to the following conditions: 48 * 49 * The above copyright notice and this permission notice (including the next 50 * paragraph) shall be included in all copies or substantial portions of the 51 * Software. 52 * 53 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 54 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 55 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 56 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 57 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 58 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 59 * DEALINGS IN THE SOFTWARE. 60 */ 61 62 63#ifdef HAVE_CONFIG_H 64# include <config.h> 65#else 66# define HAVE_DLFCN_H 67#endif 68 69#include <stdio.h> 70 71#ifdef HAVE_DLFCN_H 72#include <dlfcn.h> 73#endif 74 75#include <ctype.h> 76 77#include "Xlibint.h" 78#include "XlcPublic.h" 79#include "XlcPubI.h" 80#include "reallocarray.h" 81 82#define XI18N_DLREL 2 83 84#define iscomment(ch) ((ch) == '\0' || (ch) == '#') 85 86typedef enum { 87 XLC_OBJECT, 88 XIM_OBJECT, 89 XOM_OBJECT 90} XI18NDLType; 91 92typedef struct { 93 XI18NDLType type; 94 int locale_name_len; 95 char *locale_name; 96 char *dl_name; 97 char *open; 98 char *im_register; 99 char *im_unregister; 100 int dl_release; 101 unsigned int refcount; 102 void *dl_module; 103} XI18NObjectsListRec, *XI18NObjectsList; 104 105#define OBJECT_INIT_LEN 8 106#define OBJECT_INC_LEN 4 107static int lc_len = 0; 108static XI18NObjectsListRec *xi18n_objects_list = NULL; 109static int lc_count = 0; 110 111static int 112parse_line(char *line, char **argv, int argsize) 113{ 114 int argc = 0; 115 char *p = line; 116 117 while (argc < argsize) { 118 while (isspace(*p)) { 119 ++p; 120 } 121 if (iscomment(*p)){ 122 break; 123 } 124 argv[argc++] = p; 125 while (!isspace(*p)) { 126 ++p; 127 } 128 if (iscomment(*p)) { 129 break; 130 } 131 *p++ = '\0'; 132 } 133 return argc; 134} 135 136static char * 137strdup_with_underscore(const char *symbol) 138{ 139 char *result; 140 141 if ((result = malloc(strlen(symbol) + 2)) == NULL) 142 return NULL; 143 result[0] = '_'; 144 strcpy(result + 1, symbol); 145 return result; 146} 147 148static void * 149try_both_dlsym (void *handle, char *name) 150{ 151 void *ret; 152 153 ret = dlsym (handle, name); 154 if (!ret) 155 { 156 name = strdup_with_underscore (name); 157 if (name) 158 { 159 ret = dlsym (handle, name); 160 free (name); 161 } 162 } 163 return ret; 164} 165 166static void 167resolve_object(char *path, const char *lc_name) 168{ 169 char filename[BUFSIZ]; 170 FILE *fp; 171 char buf[BUFSIZ]; 172 173 if (lc_len == 0) { /* True only for the 1st time */ 174 lc_len = OBJECT_INIT_LEN; 175 xi18n_objects_list = Xmallocarray(lc_len, sizeof(XI18NObjectsListRec)); 176 if (!xi18n_objects_list) return; 177 } 178 snprintf(filename, sizeof(filename), "%s/%s", path, "XI18N_OBJS"); 179 fp = fopen(filename, "r"); 180 if (fp == (FILE *)NULL){ 181 return; 182 } 183 184 while (fgets(buf, BUFSIZ, fp) != NULL){ 185 char *p = buf; 186 int n; 187 char *args[6]; 188 while (isspace(*p)){ 189 ++p; 190 } 191 if (iscomment(*p)){ 192 continue; 193 } 194 195 if (lc_count == lc_len) { 196 int new_len = lc_len + OBJECT_INC_LEN; 197 XI18NObjectsListRec *tmp = 198 Xreallocarray(xi18n_objects_list, new_len, 199 sizeof(XI18NObjectsListRec)); 200 if (tmp == NULL) 201 goto done; 202 xi18n_objects_list = tmp; 203 lc_len = new_len; 204 } 205 n = parse_line(p, args, 6); 206 207 if (n == 3 || n == 5) { 208 if (!strcmp(args[0], "XLC")){ 209 xi18n_objects_list[lc_count].type = XLC_OBJECT; 210 } else if (!strcmp(args[0], "XOM")){ 211 xi18n_objects_list[lc_count].type = XOM_OBJECT; 212 } else if (!strcmp(args[0], "XIM")){ 213 xi18n_objects_list[lc_count].type = XIM_OBJECT; 214 } 215 xi18n_objects_list[lc_count].dl_name = strdup(args[1]); 216 xi18n_objects_list[lc_count].open = strdup(args[2]); 217 xi18n_objects_list[lc_count].dl_release = XI18N_DLREL; 218 xi18n_objects_list[lc_count].locale_name = strdup(lc_name); 219 xi18n_objects_list[lc_count].refcount = 0; 220 xi18n_objects_list[lc_count].dl_module = (void*)NULL; 221 if (n == 5) { 222 xi18n_objects_list[lc_count].im_register = strdup(args[3]); 223 xi18n_objects_list[lc_count].im_unregister = strdup(args[4]); 224 } else { 225 xi18n_objects_list[lc_count].im_register = NULL; 226 xi18n_objects_list[lc_count].im_unregister = NULL; 227 } 228 lc_count++; 229 } 230 } 231 done: 232 fclose(fp); 233} 234 235static char* 236__lc_path(const char *dl_name, const char *lc_dir) 237{ 238 char *path; 239 size_t len; 240 char *slash_p; 241 242 /* 243 * reject this for possible security issue 244 */ 245 if (strstr (dl_name, "../")) 246 return NULL; 247 248 len = (lc_dir ? strlen(lc_dir) : 0 ) + 249 (dl_name ? strlen(dl_name) : 0) + 10; 250#if defined POSTLOCALELIBDIR 251 len += (strlen(POSTLOCALELIBDIR) + 1); 252#endif 253 path = Xmalloc(len + 1); 254 255 if (strchr(dl_name, '/') != NULL) { 256 slash_p = strrchr(lc_dir, '/'); 257 *slash_p = '\0'; 258 } else 259 slash_p = NULL; 260 261#if defined POSTLOCALELIBDIR 262 snprintf(path, len + 1, "%s/%s/%s.so.2", 263 lc_dir, POSTLOCALELIBDIR, dl_name); 264#else 265 snprintf(path, len + 1, "%s/%s.so.2", lc_dir, dl_name); 266#endif 267 268 if (slash_p != NULL) 269 *slash_p = '/'; 270 271 return path; 272} 273 274/* We reference count dlopen() and dlclose() of modules; unfortunately, 275 * since XCloseIM, XCloseOM, XlcClose aren't wrapped, but directly 276 * call the close method of the object, we leak a reference count every 277 * time we open then close a module. Fixing this would require 278 * either creating proxy objects or hooks for close_im/close_om 279 * in XLCd 280 */ 281static Bool 282open_object( 283 XI18NObjectsList object, 284 char *lc_dir) 285{ 286 char *path; 287 288 if (object->refcount == 0) { 289 path = __lc_path(object->dl_name, lc_dir); 290 if (!path) 291 return False; 292 object->dl_module = dlopen(path, RTLD_LAZY); 293 Xfree(path); 294 295 if (!object->dl_module) 296 return False; 297 } 298 299 object->refcount++; 300 return True; 301} 302 303static void * 304fetch_symbol( 305 XI18NObjectsList object, 306 char *symbol) 307{ 308 void *result = NULL; 309 310 if (symbol == NULL) 311 return NULL; 312 313 result = try_both_dlsym(object->dl_module, symbol); 314 315 return result; 316} 317 318static void 319close_object(XI18NObjectsList object) 320{ 321 object->refcount--; 322 if (object->refcount == 0) 323 { 324 dlclose(object->dl_module); 325 object->dl_module = NULL; 326 } 327} 328 329 330typedef XLCd (*dynamicLoadProc)(const char *); 331 332XLCd 333_XlcDynamicLoad(const char *lc_name) 334{ 335 XLCd lcd = (XLCd)NULL; 336 dynamicLoadProc lc_loader = (dynamicLoadProc)NULL; 337 int count; 338 XI18NObjectsList objects_list; 339 char lc_dir[BUFSIZE], lc_lib_dir[BUFSIZE]; 340 341 if (lc_name == NULL) return (XLCd)NULL; 342 343 if (_XlcLocaleDirName(lc_dir, BUFSIZE, lc_name) == NULL) 344 return (XLCd)NULL; 345 if (_XlcLocaleLibDirName(lc_lib_dir, BUFSIZE, lc_name) == NULL) 346 return (XLCd)NULL; 347 348 resolve_object(lc_dir, lc_name); 349 resolve_object(lc_lib_dir, lc_name); 350 351 objects_list = xi18n_objects_list; 352 count = lc_count; 353 for (; count-- > 0; objects_list++) { 354 if (objects_list->type != XLC_OBJECT || 355 strcmp(objects_list->locale_name, lc_name)) continue; 356 if (!open_object (objects_list, lc_dir) && \ 357 !open_object (objects_list, lc_lib_dir)) 358 continue; 359 360 lc_loader = (dynamicLoadProc)fetch_symbol (objects_list, objects_list->open); 361 if (!lc_loader) continue; 362 lcd = (*lc_loader)(lc_name); 363 if (lcd != (XLCd)NULL) { 364 break; 365 } 366 367 close_object (objects_list); 368 } 369 return (XLCd)lcd; 370} 371 372 373typedef XIM (*dynamicOpenProcp)(XLCd, Display *, XrmDatabase, char *, char *); 374 375static XIM 376_XDynamicOpenIM(XLCd lcd, Display *display, XrmDatabase rdb, 377 char *res_name, char *res_class) 378{ 379 XIM im = (XIM)NULL; 380 char lc_dir[BUFSIZE]; 381 char *lc_name; 382 dynamicOpenProcp im_openIM = (dynamicOpenProcp)NULL; 383 int count; 384 XI18NObjectsList objects_list = xi18n_objects_list; 385 386 lc_name = lcd->core->name; 387 388 if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return (XIM)0; 389 390 count = lc_count; 391 for (; count-- > 0; objects_list++) { 392 if (objects_list->type != XIM_OBJECT || 393 strcmp(objects_list->locale_name, lc_name)) continue; 394 395 if (!open_object (objects_list, lc_dir)) 396 continue; 397 398 im_openIM = (dynamicOpenProcp)fetch_symbol(objects_list, objects_list->open); 399 if (!im_openIM) continue; 400 im = (*im_openIM)(lcd, display, rdb, res_name, res_class); 401 if (im != (XIM)NULL) { 402 break; 403 } 404 405 close_object (objects_list); 406 } 407 return (XIM)im; 408} 409 410typedef Bool (*dynamicRegisterCBProcp)( 411 XLCd, Display *, XrmDatabase, char *, char *, XIDProc, XPointer); 412 413static Bool 414_XDynamicRegisterIMInstantiateCallback( 415 XLCd lcd, 416 Display *display, 417 XrmDatabase rdb, 418 char *res_name, 419 char *res_class, 420 XIDProc callback, 421 XPointer client_data) 422{ 423 char lc_dir[BUFSIZE]; 424 char *lc_name; 425 dynamicRegisterCBProcp im_registerIM = (dynamicRegisterCBProcp)NULL; 426 Bool ret_flag = False; 427 int count; 428 XI18NObjectsList objects_list = xi18n_objects_list; 429 430 lc_name = lcd->core->name; 431 432 if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return False; 433 434 count = lc_count; 435 for (; count-- > 0; objects_list++) { 436 if (objects_list->type != XIM_OBJECT || 437 strcmp(objects_list->locale_name, lc_name)) continue; 438 439 if (!open_object (objects_list, lc_dir)) 440 continue; 441 im_registerIM = (dynamicRegisterCBProcp)fetch_symbol(objects_list, 442 objects_list->im_register); 443 if (!im_registerIM) continue; 444 ret_flag = (*im_registerIM)(lcd, display, rdb, 445 res_name, res_class, 446 callback, client_data); 447 if (ret_flag) break; 448 449 close_object (objects_list); 450 } 451 return (Bool)ret_flag; 452} 453 454typedef Bool (*dynamicUnregisterProcp)( 455 XLCd, Display *, XrmDatabase, char *, char *, XIDProc, XPointer); 456 457static Bool 458_XDynamicUnRegisterIMInstantiateCallback( 459 XLCd lcd, 460 Display *display, 461 XrmDatabase rdb, 462 char *res_name, 463 char *res_class, 464 XIDProc callback, 465 XPointer client_data) 466{ 467 char lc_dir[BUFSIZE]; 468 const char *lc_name; 469 dynamicUnregisterProcp im_unregisterIM = (dynamicUnregisterProcp)NULL; 470 Bool ret_flag = False; 471 int count; 472 XI18NObjectsList objects_list = xi18n_objects_list; 473 474 lc_name = lcd->core->name; 475 if (_XlcLocaleDirName(lc_dir, BUFSIZE, lc_name) == NULL) return False; 476 477 count = lc_count; 478 for (; count-- > 0; objects_list++) { 479 if (objects_list->type != XIM_OBJECT || 480 strcmp(objects_list->locale_name, lc_name)) continue; 481 482 if (!objects_list->refcount) /* Must already be opened */ 483 continue; 484 485 im_unregisterIM = (dynamicUnregisterProcp)fetch_symbol(objects_list, 486 objects_list->im_unregister); 487 488 if (!im_unregisterIM) continue; 489 ret_flag = (*im_unregisterIM)(lcd, display, rdb, 490 res_name, res_class, 491 callback, client_data); 492 if (ret_flag) { 493 close_object (objects_list); /* opened in RegisterIMInstantiateCallback */ 494 break; 495 } 496 } 497 return (Bool)ret_flag; 498} 499 500Bool 501_XInitDynamicIM(XLCd lcd) 502{ 503 if(lcd == (XLCd)NULL) 504 return False; 505 lcd->methods->open_im = _XDynamicOpenIM; 506 lcd->methods->register_callback = _XDynamicRegisterIMInstantiateCallback; 507 lcd->methods->unregister_callback = _XDynamicUnRegisterIMInstantiateCallback; 508 return True; 509} 510 511 512typedef XOM (*dynamicIOpenProcp)( 513 XLCd, Display *, XrmDatabase, _Xconst char *, _Xconst char *); 514 515static XOM 516_XDynamicOpenOM(XLCd lcd, Display *display, XrmDatabase rdb, 517 _Xconst char *res_name, _Xconst char *res_class) 518{ 519 XOM om = (XOM)NULL; 520 int count; 521 char lc_dir[BUFSIZE]; 522 char *lc_name; 523 dynamicIOpenProcp om_openOM = (dynamicIOpenProcp)NULL; 524 XI18NObjectsList objects_list = xi18n_objects_list; 525 526 lc_name = lcd->core->name; 527 528 if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return (XOM)0; 529 530 count = lc_count; 531 for (; count-- > 0; objects_list++) { 532 if (objects_list->type != XOM_OBJECT || 533 strcmp(objects_list->locale_name, lc_name)) continue; 534 if (!open_object (objects_list, lc_dir)) 535 continue; 536 537 om_openOM = (dynamicIOpenProcp)fetch_symbol(objects_list, objects_list->open); 538 if (!om_openOM) continue; 539 om = (*om_openOM)(lcd, display, rdb, res_name, res_class); 540 if (om != (XOM)NULL) { 541 break; 542 } 543 close_object(objects_list); 544 } 545 return (XOM)om; 546} 547 548Bool 549_XInitDynamicOM(XLCd lcd) 550{ 551 if(lcd == (XLCd)NULL) 552 return False; 553 554 lcd->methods->open_om = _XDynamicOpenOM; 555 556 return True; 557} 558