1/* 2****************************************************************************** 3* 4* Copyright (C) 1999-2014, International Business Machines 5* Corporation and others. All Rights Reserved. 6* 7****************************************************************************** 8* file name: udata.cpp 9* encoding: US-ASCII 10* tab size: 8 (not used) 11* indentation:4 12* 13* created on: 1999oct25 14* created by: Markus W. Scherer 15*/ 16 17#include "unicode/utypes.h" /* U_PLATFORM etc. */ 18 19#ifdef __GNUC__ 20/* if gcc 21#define ATTRIBUTE_WEAK __attribute__ ((weak)) 22might have to #include some other header 23*/ 24#endif 25 26#include "unicode/putil.h" 27#include "unicode/udata.h" 28#include "unicode/uversion.h" 29#include "charstr.h" 30#include "cmemory.h" 31#include "cstring.h" 32#include "putilimp.h" 33#include "uassert.h" 34#include "ucln_cmn.h" 35#include "ucmndata.h" 36#include "udatamem.h" 37#include "uhash.h" 38#include "umapfile.h" 39#include "umutex.h" 40 41/*********************************************************************** 42* 43* Notes on the organization of the ICU data implementation 44* 45* All of the public API is defined in udata.h 46* 47* The implementation is split into several files... 48* 49* - udata.c (this file) contains higher level code that knows about 50* the search paths for locating data, caching opened data, etc. 51* 52* - umapfile.c contains the low level platform-specific code for actually loading 53* (memory mapping, file reading, whatever) data into memory. 54* 55* - ucmndata.c deals with the tables of contents of ICU data items within 56* an ICU common format data file. The implementation includes 57* an abstract interface and support for multiple TOC formats. 58* All knowledge of any specific TOC format is encapsulated here. 59* 60* - udatamem.c has code for managing UDataMemory structs. These are little 61* descriptor objects for blocks of memory holding ICU data of 62* various types. 63*/ 64 65/* configuration ---------------------------------------------------------- */ 66 67/* If you are excruciatingly bored turn this on .. */ 68/* #define UDATA_DEBUG 1 */ 69 70#if defined(UDATA_DEBUG) 71# include <stdio.h> 72#endif 73 74U_NAMESPACE_USE 75 76/* 77 * Forward declarations 78 */ 79static UDataMemory *udata_findCachedData(const char *path); 80 81/*********************************************************************** 82* 83* static (Global) data 84* 85************************************************************************/ 86 87/* 88 * Pointers to the common ICU data. 89 * 90 * We store multiple pointers to ICU data packages and iterate through them 91 * when looking for a data item. 92 * 93 * It is possible to combine this with dependency inversion: 94 * One or more data package libraries may export 95 * functions that each return a pointer to their piece of the ICU data, 96 * and this file would import them as weak functions, without a 97 * strong linker dependency from the common library on the data library. 98 * 99 * Then we can have applications depend on only that part of ICU's data 100 * that they really need, reducing the size of binaries that take advantage 101 * of this. 102 */ 103static UDataMemory *gCommonICUDataArray[10] = { NULL }; 104 105static UBool gHaveTriedToLoadCommonData = FALSE; /* See extendICUData(). */ 106 107static UHashtable *gCommonDataCache = NULL; /* Global hash table of opened ICU data files. */ 108static icu::UInitOnce gCommonDataCacheInitOnce = U_INITONCE_INITIALIZER; 109 110static UDataFileAccess gDataFileAccess = UDATA_DEFAULT_ACCESS; 111 112static UBool U_CALLCONV 113udata_cleanup(void) 114{ 115 int32_t i; 116 117 if (gCommonDataCache) { /* Delete the cache of user data mappings. */ 118 uhash_close(gCommonDataCache); /* Table owns the contents, and will delete them. */ 119 gCommonDataCache = NULL; /* Cleanup is not thread safe. */ 120 } 121 gCommonDataCacheInitOnce.reset(); 122 123 for (i = 0; i < UPRV_LENGTHOF(gCommonICUDataArray) && gCommonICUDataArray[i] != NULL; ++i) { 124 udata_close(gCommonICUDataArray[i]); 125 gCommonICUDataArray[i] = NULL; 126 } 127 gHaveTriedToLoadCommonData = FALSE; 128 129 return TRUE; /* Everything was cleaned up */ 130} 131 132static UBool U_CALLCONV 133findCommonICUDataByName(const char *inBasename) 134{ 135 UBool found = FALSE; 136 int32_t i; 137 138 UDataMemory *pData = udata_findCachedData(inBasename); 139 if (pData == NULL) 140 return FALSE; 141 142 for (i = 0; i < UPRV_LENGTHOF(gCommonICUDataArray); ++i) { 143 if ((gCommonICUDataArray[i] != NULL) && (gCommonICUDataArray[i]->pHeader == pData->pHeader)) { 144 /* The data pointer is already in the array. */ 145 found = TRUE; 146 break; 147 } 148 } 149 150 return found; 151} 152 153 154/* 155 * setCommonICUData. Set a UDataMemory to be the global ICU Data 156 */ 157static UBool 158setCommonICUData(UDataMemory *pData, /* The new common data. Belongs to caller, we copy it. */ 159 UBool warn, /* If true, set USING_DEFAULT warning if ICUData was */ 160 /* changed by another thread before we got to it. */ 161 UErrorCode *pErr) 162{ 163 UDataMemory *newCommonData = UDataMemory_createNewInstance(pErr); 164 int32_t i; 165 UBool didUpdate = FALSE; 166 if (U_FAILURE(*pErr)) { 167 return FALSE; 168 } 169 170 /* For the assignment, other threads must cleanly see either the old */ 171 /* or the new, not some partially initialized new. The old can not be */ 172 /* deleted - someone may still have a pointer to it lying around in */ 173 /* their locals. */ 174 UDatamemory_assign(newCommonData, pData); 175 umtx_lock(NULL); 176 for (i = 0; i < UPRV_LENGTHOF(gCommonICUDataArray); ++i) { 177 if (gCommonICUDataArray[i] == NULL) { 178 gCommonICUDataArray[i] = newCommonData; 179 didUpdate = TRUE; 180 break; 181 } else if (gCommonICUDataArray[i]->pHeader == pData->pHeader) { 182 /* The same data pointer is already in the array. */ 183 break; 184 } 185 } 186 umtx_unlock(NULL); 187 188 if (i == UPRV_LENGTHOF(gCommonICUDataArray) && warn) { 189 *pErr = U_USING_DEFAULT_WARNING; 190 } 191 if (didUpdate) { 192 ucln_common_registerCleanup(UCLN_COMMON_UDATA, udata_cleanup); 193 } else { 194 uprv_free(newCommonData); 195 } 196 return didUpdate; 197} 198 199static UBool 200setCommonICUDataPointer(const void *pData, UBool /*warn*/, UErrorCode *pErrorCode) { 201 UDataMemory tData; 202 UDataMemory_init(&tData); 203 UDataMemory_setData(&tData, pData); 204 udata_checkCommonData(&tData, pErrorCode); 205 return setCommonICUData(&tData, FALSE, pErrorCode); 206} 207 208static const char * 209findBasename(const char *path) { 210 const char *basename=uprv_strrchr(path, U_FILE_SEP_CHAR); 211 if(basename==NULL) { 212 return path; 213 } else { 214 return basename+1; 215 } 216} 217 218#ifdef UDATA_DEBUG 219static const char * 220packageNameFromPath(const char *path) 221{ 222 if((path == NULL) || (*path == 0)) { 223 return U_ICUDATA_NAME; 224 } 225 226 path = findBasename(path); 227 228 if((path == NULL) || (*path == 0)) { 229 return U_ICUDATA_NAME; 230 } 231 232 return path; 233} 234#endif 235 236/*----------------------------------------------------------------------* 237 * * 238 * Cache for common data * 239 * Functions for looking up or adding entries to a cache of * 240 * data that has been previously opened. Avoids a potentially * 241 * expensive operation of re-opening the data for subsequent * 242 * uses. * 243 * * 244 * Data remains cached for the duration of the process. * 245 * * 246 *----------------------------------------------------------------------*/ 247 248typedef struct DataCacheElement { 249 char *name; 250 UDataMemory *item; 251} DataCacheElement; 252 253 254 255/* 256 * Deleter function for DataCacheElements. 257 * udata cleanup function closes the hash table; hash table in turn calls back to 258 * here for each entry. 259 */ 260static void U_CALLCONV DataCacheElement_deleter(void *pDCEl) { 261 DataCacheElement *p = (DataCacheElement *)pDCEl; 262 udata_close(p->item); /* unmaps storage */ 263 uprv_free(p->name); /* delete the hash key string. */ 264 uprv_free(pDCEl); /* delete 'this' */ 265} 266 267static void udata_initHashTable() { 268 UErrorCode err = U_ZERO_ERROR; 269 U_ASSERT(gCommonDataCache == NULL); 270 gCommonDataCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &err); 271 if (U_FAILURE(err)) { 272 // TODO: handle errors better. 273 gCommonDataCache = NULL; 274 } 275 if (gCommonDataCache != NULL) { 276 uhash_setValueDeleter(gCommonDataCache, DataCacheElement_deleter); 277 ucln_common_registerCleanup(UCLN_COMMON_UDATA, udata_cleanup); 278 } 279} 280 281 /* udata_getCacheHashTable() 282 * Get the hash table used to store the data cache entries. 283 * Lazy create it if it doesn't yet exist. 284 */ 285static UHashtable *udata_getHashTable() { 286 umtx_initOnce(gCommonDataCacheInitOnce, &udata_initHashTable); 287 return gCommonDataCache; 288} 289 290 291 292static UDataMemory *udata_findCachedData(const char *path) 293{ 294 UHashtable *htable; 295 UDataMemory *retVal = NULL; 296 DataCacheElement *el; 297 const char *baseName; 298 299 baseName = findBasename(path); /* Cache remembers only the base name, not the full path. */ 300 htable = udata_getHashTable(); 301 umtx_lock(NULL); 302 el = (DataCacheElement *)uhash_get(htable, baseName); 303 umtx_unlock(NULL); 304 if (el != NULL) { 305 retVal = el->item; 306 } 307#ifdef UDATA_DEBUG 308 fprintf(stderr, "Cache: [%s] -> %p\n", baseName, retVal); 309#endif 310 return retVal; 311} 312 313 314static UDataMemory *udata_cacheDataItem(const char *path, UDataMemory *item, UErrorCode *pErr) { 315 DataCacheElement *newElement; 316 const char *baseName; 317 int32_t nameLen; 318 UHashtable *htable; 319 DataCacheElement *oldValue = NULL; 320 UErrorCode subErr = U_ZERO_ERROR; 321 322 if (U_FAILURE(*pErr)) { 323 return NULL; 324 } 325 326 /* Create a new DataCacheElement - the thingy we store in the hash table - 327 * and copy the supplied path and UDataMemoryItems into it. 328 */ 329 newElement = (DataCacheElement *)uprv_malloc(sizeof(DataCacheElement)); 330 if (newElement == NULL) { 331 *pErr = U_MEMORY_ALLOCATION_ERROR; 332 return NULL; 333 } 334 newElement->item = UDataMemory_createNewInstance(pErr); 335 if (U_FAILURE(*pErr)) { 336 uprv_free(newElement); 337 return NULL; 338 } 339 UDatamemory_assign(newElement->item, item); 340 341 baseName = findBasename(path); 342 nameLen = (int32_t)uprv_strlen(baseName); 343 newElement->name = (char *)uprv_malloc(nameLen+1); 344 if (newElement->name == NULL) { 345 *pErr = U_MEMORY_ALLOCATION_ERROR; 346 uprv_free(newElement->item); 347 uprv_free(newElement); 348 return NULL; 349 } 350 uprv_strcpy(newElement->name, baseName); 351 352 /* Stick the new DataCacheElement into the hash table. 353 */ 354 htable = udata_getHashTable(); 355 umtx_lock(NULL); 356 oldValue = (DataCacheElement *)uhash_get(htable, path); 357 if (oldValue != NULL) { 358 subErr = U_USING_DEFAULT_WARNING; 359 } 360 else { 361 uhash_put( 362 htable, 363 newElement->name, /* Key */ 364 newElement, /* Value */ 365 &subErr); 366 } 367 umtx_unlock(NULL); 368 369#ifdef UDATA_DEBUG 370 fprintf(stderr, "Cache: [%s] <<< %p : %s. vFunc=%p\n", newElement->name, 371 newElement->item, u_errorName(subErr), newElement->item->vFuncs); 372#endif 373 374 if (subErr == U_USING_DEFAULT_WARNING || U_FAILURE(subErr)) { 375 *pErr = subErr; /* copy sub err unto fillin ONLY if something happens. */ 376 uprv_free(newElement->name); 377 uprv_free(newElement->item); 378 uprv_free(newElement); 379 return oldValue ? oldValue->item : NULL; 380 } 381 382 return newElement->item; 383} 384 385/*----------------------------------------------------------------------*============== 386 * * 387 * Path management. Could be shared with other tools/etc if need be * 388 * later on. * 389 * * 390 *----------------------------------------------------------------------*/ 391 392#define U_DATA_PATHITER_BUFSIZ 128 /* Size of local buffer for paths */ 393 /* Overflow causes malloc of larger buf */ 394 395U_NAMESPACE_BEGIN 396 397class UDataPathIterator 398{ 399public: 400 UDataPathIterator(const char *path, const char *pkg, 401 const char *item, const char *suffix, UBool doCheckLastFour, 402 UErrorCode *pErrorCode); 403 const char *next(UErrorCode *pErrorCode); 404 405private: 406 const char *path; /* working path (u_icudata_Dir) */ 407 const char *nextPath; /* path following this one */ 408 const char *basename; /* item's basename (icudt22e_mt.res)*/ 409 const char *suffix; /* item suffix (can be null) */ 410 411 uint32_t basenameLen; /* length of basename */ 412 413 CharString itemPath; /* path passed in with item name */ 414 CharString pathBuffer; /* output path for this it'ion */ 415 CharString packageStub; /* example: "/icudt28b". Will ignore that leaf in set paths. */ 416 417 UBool checkLastFour; /* if TRUE then allow paths such as '/foo/myapp.dat' 418 * to match, checks last 4 chars of suffix with 419 * last 4 of path, then previous chars. */ 420}; 421 422/** 423 * @param iter The iterator to be initialized. Its current state does not matter. 424 * @param path The full pathname to be iterated over. If NULL, defaults to U_ICUDATA_NAME 425 * @param pkg Package which is being searched for, ex "icudt28l". Will ignore leave directories such as /icudt28l 426 * @param item Item to be searched for. Can include full path, such as /a/b/foo.dat 427 * @param suffix Optional item suffix, if not-null (ex. ".dat") then 'path' can contain 'item' explicitly. 428 * Ex: 'stuff.dat' would be found in '/a/foo:/tmp/stuff.dat:/bar/baz' as item #2. 429 * '/blarg/stuff.dat' would also be found. 430 */ 431UDataPathIterator::UDataPathIterator(const char *inPath, const char *pkg, 432 const char *item, const char *inSuffix, UBool doCheckLastFour, 433 UErrorCode *pErrorCode) 434{ 435#ifdef UDATA_DEBUG 436 fprintf(stderr, "SUFFIX1=%s PATH=%s\n", inSuffix, inPath); 437#endif 438 /** Path **/ 439 if(inPath == NULL) { 440 path = u_getDataDirectory(); 441 } else { 442 path = inPath; 443 } 444 445 /** Package **/ 446 if(pkg != NULL) { 447 packageStub.append(U_FILE_SEP_CHAR, *pErrorCode).append(pkg, *pErrorCode); 448#ifdef UDATA_DEBUG 449 fprintf(stderr, "STUB=%s [%d]\n", packageStub.data(), packageStub.length()); 450#endif 451 } 452 453 /** Item **/ 454 basename = findBasename(item); 455 basenameLen = (int32_t)uprv_strlen(basename); 456 457 /** Item path **/ 458 if(basename == item) { 459 nextPath = path; 460 } else { 461 itemPath.append(item, (int32_t)(basename-item), *pErrorCode); 462 nextPath = itemPath.data(); 463 } 464#ifdef UDATA_DEBUG 465 fprintf(stderr, "SUFFIX=%s [%p]\n", inSuffix, inSuffix); 466#endif 467 468 /** Suffix **/ 469 if(inSuffix != NULL) { 470 suffix = inSuffix; 471 } else { 472 suffix = ""; 473 } 474 475 checkLastFour = doCheckLastFour; 476 477 /* pathBuffer will hold the output path strings returned by this iterator */ 478 479#ifdef UDATA_DEBUG 480 fprintf(stderr, "%p: init %s -> [path=%s], [base=%s], [suff=%s], [itempath=%s], [nextpath=%s], [checklast4=%s]\n", 481 iter, 482 item, 483 path, 484 basename, 485 suffix, 486 itemPath.data(), 487 nextPath, 488 checkLastFour?"TRUE":"false"); 489#endif 490} 491 492/** 493 * Get the next path on the list. 494 * 495 * @param iter The Iter to be used 496 * @param len If set, pointer to the length of the returned path, for convenience. 497 * @return Pointer to the next path segment, or NULL if there are no more. 498 */ 499const char *UDataPathIterator::next(UErrorCode *pErrorCode) 500{ 501 if(U_FAILURE(*pErrorCode)) { 502 return NULL; 503 } 504 505 const char *currentPath = NULL; 506 int32_t pathLen = 0; 507 const char *pathBasename; 508 509 do 510 { 511 if( nextPath == NULL ) { 512 break; 513 } 514 currentPath = nextPath; 515 516 if(nextPath == itemPath.data()) { /* we were processing item's path. */ 517 nextPath = path; /* start with regular path next tm. */ 518 pathLen = (int32_t)uprv_strlen(currentPath); 519 } else { 520 /* fix up next for next time */ 521 nextPath = uprv_strchr(currentPath, U_PATH_SEP_CHAR); 522 if(nextPath == NULL) { 523 /* segment: entire path */ 524 pathLen = (int32_t)uprv_strlen(currentPath); 525 } else { 526 /* segment: until next segment */ 527 pathLen = (int32_t)(nextPath - currentPath); 528 /* skip divider */ 529 nextPath ++; 530 } 531 } 532 533 if(pathLen == 0) { 534 continue; 535 } 536 537#ifdef UDATA_DEBUG 538 fprintf(stderr, "rest of path (IDD) = %s\n", currentPath); 539 fprintf(stderr, " "); 540 { 541 uint32_t qqq; 542 for(qqq=0;qqq<pathLen;qqq++) 543 { 544 fprintf(stderr, " "); 545 } 546 547 fprintf(stderr, "^\n"); 548 } 549#endif 550 pathBuffer.clear().append(currentPath, pathLen, *pErrorCode); 551 552 /* check for .dat files */ 553 pathBasename = findBasename(pathBuffer.data()); 554 555 if(checkLastFour == TRUE && 556 (pathLen>=4) && 557 uprv_strncmp(pathBuffer.data() +(pathLen-4), suffix, 4)==0 && /* suffix matches */ 558 uprv_strncmp(findBasename(pathBuffer.data()), basename, basenameLen)==0 && /* base matches */ 559 uprv_strlen(pathBasename)==(basenameLen+4)) { /* base+suffix = full len */ 560 561#ifdef UDATA_DEBUG 562 fprintf(stderr, "Have %s file on the path: %s\n", suffix, pathBuffer.data()); 563#endif 564 /* do nothing */ 565 } 566 else 567 { /* regular dir path */ 568 if(pathBuffer[pathLen-1] != U_FILE_SEP_CHAR) { 569 if((pathLen>=4) && 570 uprv_strncmp(pathBuffer.data()+(pathLen-4), ".dat", 4) == 0) 571 { 572#ifdef UDATA_DEBUG 573 fprintf(stderr, "skipping non-directory .dat file %s\n", pathBuffer.data()); 574#endif 575 continue; 576 } 577 578 /* Check if it is a directory with the same name as our package */ 579 if(!packageStub.isEmpty() && 580 (pathLen > packageStub.length()) && 581 !uprv_strcmp(pathBuffer.data() + pathLen - packageStub.length(), packageStub.data())) { 582#ifdef UDATA_DEBUG 583 fprintf(stderr, "Found stub %s (will add package %s of len %d)\n", packageStub.data(), basename, basenameLen); 584#endif 585 pathBuffer.truncate(pathLen - packageStub.length()); 586 } 587 pathBuffer.append(U_FILE_SEP_CHAR, *pErrorCode); 588 } 589 590 /* + basename */ 591 pathBuffer.append(packageStub.data()+1, packageStub.length()-1, *pErrorCode); 592 593 if(*suffix) /* tack on suffix */ 594 { 595 pathBuffer.append(suffix, *pErrorCode); 596 } 597 } 598 599#ifdef UDATA_DEBUG 600 fprintf(stderr, " --> %s\n", pathBuffer.data()); 601#endif 602 603 return pathBuffer.data(); 604 605 } while(path); 606 607 /* fell way off the end */ 608 return NULL; 609} 610 611U_NAMESPACE_END 612 613/* ==================================================================================*/ 614 615 616/*----------------------------------------------------------------------* 617 * * 618 * Add a static reference to the common data library * 619 * Unless overridden by an explicit udata_setCommonData, this will be * 620 * our common data. * 621 * * 622 *----------------------------------------------------------------------*/ 623extern "C" const DataHeader U_DATA_API U_ICUDATA_ENTRY_POINT; 624 625/* 626 * This would be a good place for weak-linkage declarations of 627 * partial-data-library access functions where each returns a pointer 628 * to its data package, if it is linked in. 629 */ 630/* 631extern const void *uprv_getICUData_collation(void) ATTRIBUTE_WEAK; 632extern const void *uprv_getICUData_conversion(void) ATTRIBUTE_WEAK; 633*/ 634 635/*----------------------------------------------------------------------* 636 * * 637 * openCommonData Attempt to open a common format (.dat) file * 638 * Map it into memory (if it's not there already) * 639 * and return a UDataMemory object for it. * 640 * * 641 * If the requested data is already open and cached * 642 * just return the cached UDataMem object. * 643 * * 644 *----------------------------------------------------------------------*/ 645static UDataMemory * 646openCommonData(const char *path, /* Path from OpenChoice? */ 647 int32_t commonDataIndex, /* ICU Data (index >= 0) if path == NULL */ 648 UErrorCode *pErrorCode) 649{ 650 UDataMemory tData; 651 const char *pathBuffer; 652 const char *inBasename; 653 654 if (U_FAILURE(*pErrorCode)) { 655 return NULL; 656 } 657 658 UDataMemory_init(&tData); 659 660 /* ??????? TODO revisit this */ 661 if (commonDataIndex >= 0) { 662 /* "mini-cache" for common ICU data */ 663 if(commonDataIndex >= UPRV_LENGTHOF(gCommonICUDataArray)) { 664 return NULL; 665 } 666 if(gCommonICUDataArray[commonDataIndex] == NULL) { 667 int32_t i; 668 for(i = 0; i < commonDataIndex; ++i) { 669 if(gCommonICUDataArray[i]->pHeader == &U_ICUDATA_ENTRY_POINT) { 670 /* The linked-in data is already in the list. */ 671 return NULL; 672 } 673 } 674 675 /* Add the linked-in data to the list. */ 676 /* 677 * This is where we would check and call weakly linked partial-data-library 678 * access functions. 679 */ 680 /* 681 if (uprv_getICUData_collation) { 682 setCommonICUDataPointer(uprv_getICUData_collation(), FALSE, pErrorCode); 683 } 684 if (uprv_getICUData_conversion) { 685 setCommonICUDataPointer(uprv_getICUData_conversion(), FALSE, pErrorCode); 686 } 687 */ 688 setCommonICUDataPointer(&U_ICUDATA_ENTRY_POINT, FALSE, pErrorCode); 689 } 690 return gCommonICUDataArray[commonDataIndex]; 691 } 692 693 694 /* request is NOT for ICU Data. */ 695 696 /* Find the base name portion of the supplied path. */ 697 /* inBasename will be left pointing somewhere within the original path string. */ 698 inBasename = findBasename(path); 699#ifdef UDATA_DEBUG 700 fprintf(stderr, "inBasename = %s\n", inBasename); 701#endif 702 703 if(*inBasename==0) { 704 /* no basename. This will happen if the original path was a directory name, */ 705 /* like "a/b/c/". (Fallback to separate files will still work.) */ 706#ifdef UDATA_DEBUG 707 fprintf(stderr, "ocd: no basename in %s, bailing.\n", path); 708#endif 709 *pErrorCode=U_FILE_ACCESS_ERROR; 710 return NULL; 711 } 712 713 /* Is the requested common data file already open and cached? */ 714 /* Note that the cache is keyed by the base name only. The rest of the path, */ 715 /* if any, is not considered. */ 716 { 717 UDataMemory *dataToReturn = udata_findCachedData(inBasename); 718 if (dataToReturn != NULL) { 719 return dataToReturn; 720 } 721 } 722 723 /* Requested item is not in the cache. 724 * Hunt it down, trying all the path locations 725 */ 726 727 UDataPathIterator iter(u_getDataDirectory(), inBasename, path, ".dat", TRUE, pErrorCode); 728 729 while((UDataMemory_isLoaded(&tData)==FALSE) && (pathBuffer = iter.next(pErrorCode)) != NULL) 730 { 731#ifdef UDATA_DEBUG 732 fprintf(stderr, "ocd: trying path %s - ", pathBuffer); 733#endif 734 uprv_mapFile(&tData, pathBuffer); 735#ifdef UDATA_DEBUG 736 fprintf(stderr, "%s\n", UDataMemory_isLoaded(&tData)?"LOADED":"not loaded"); 737#endif 738 } 739 740#if defined(OS390_STUBDATA) && defined(OS390BATCH) 741 if (!UDataMemory_isLoaded(&tData)) { 742 char ourPathBuffer[1024]; 743 /* One more chance, for extendCommonData() */ 744 uprv_strncpy(ourPathBuffer, path, 1019); 745 ourPathBuffer[1019]=0; 746 uprv_strcat(ourPathBuffer, ".dat"); 747 uprv_mapFile(&tData, ourPathBuffer); 748 } 749#endif 750 751 if (!UDataMemory_isLoaded(&tData)) { 752 /* no common data */ 753 *pErrorCode=U_FILE_ACCESS_ERROR; 754 return NULL; 755 } 756 757 /* we have mapped a file, check its header */ 758 udata_checkCommonData(&tData, pErrorCode); 759 760 761 /* Cache the UDataMemory struct for this .dat file, 762 * so we won't need to hunt it down and map it again next time 763 * something is needed from it. */ 764 return udata_cacheDataItem(inBasename, &tData, pErrorCode); 765} 766 767 768/*----------------------------------------------------------------------* 769 * * 770 * extendICUData If the full set of ICU data was not loaded at * 771 * program startup, load it now. This function will * 772 * be called when the lookup of an ICU data item in * 773 * the common ICU data fails. * 774 * * 775 * return true if new data is loaded, false otherwise.* 776 * * 777 *----------------------------------------------------------------------*/ 778static UBool extendICUData(UErrorCode *pErr) 779{ 780 UDataMemory *pData; 781 UDataMemory copyPData; 782 UBool didUpdate = FALSE; 783 784 /* 785 * There is a chance for a race condition here. 786 * Normally, ICU data is loaded from a DLL or via mmap() and 787 * setCommonICUData() will detect if the same address is set twice. 788 * If ICU is built with data loading via fread() then the address will 789 * be different each time the common data is loaded and we may add 790 * multiple copies of the data. 791 * In this case, use a mutex to prevent the race. 792 * Use a specific mutex to avoid nested locks of the global mutex. 793 */ 794#if MAP_IMPLEMENTATION==MAP_STDIO 795 static UMutex extendICUDataMutex = U_MUTEX_INITIALIZER; 796 umtx_lock(&extendICUDataMutex); 797#endif 798 if(!gHaveTriedToLoadCommonData) { 799 /* See if we can explicitly open a .dat file for the ICUData. */ 800 pData = openCommonData( 801 U_ICUDATA_NAME, /* "icudt20l" , for example. */ 802 -1, /* Pretend we're not opening ICUData */ 803 pErr); 804 805 /* How about if there is no pData, eh... */ 806 807 UDataMemory_init(©PData); 808 if(pData != NULL) { 809 UDatamemory_assign(©PData, pData); 810 copyPData.map = 0; /* The mapping for this data is owned by the hash table */ 811 copyPData.mapAddr = 0; /* which will unmap it when ICU is shut down. */ 812 /* CommonICUData is also unmapped when ICU is shut down.*/ 813 /* To avoid unmapping the data twice, zero out the map */ 814 /* fields in the UDataMemory that we're assigning */ 815 /* to CommonICUData. */ 816 817 didUpdate = /* no longer using this result */ 818 setCommonICUData(©PData,/* The new common data. */ 819 FALSE, /* No warnings if write didn't happen */ 820 pErr); /* setCommonICUData honors errors; NOP if error set */ 821 } 822 823 gHaveTriedToLoadCommonData = TRUE; 824 } 825 826 didUpdate = findCommonICUDataByName(U_ICUDATA_NAME); /* Return 'true' when a racing writes out the extended */ 827 /* data after another thread has failed to see it (in openCommonData), so */ 828 /* extended data can be examined. */ 829 /* Also handles a race through here before gHaveTriedToLoadCommonData is set. */ 830 831#if MAP_IMPLEMENTATION==MAP_STDIO 832 umtx_unlock(&extendICUDataMutex); 833#endif 834 return didUpdate; /* Return true if ICUData pointer was updated. */ 835 /* (Could potentialy have been done by another thread racing */ 836 /* us through here, but that's fine, we still return true */ 837 /* so that current thread will also examine extended data. */ 838} 839 840/*----------------------------------------------------------------------* 841 * * 842 * udata_setCommonData * 843 * * 844 *----------------------------------------------------------------------*/ 845U_CAPI void U_EXPORT2 846udata_setCommonData(const void *data, UErrorCode *pErrorCode) { 847 UDataMemory dataMemory; 848 849 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 850 return; 851 } 852 853 if(data==NULL) { 854 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 855 return; 856 } 857 858 /* set the data pointer and test for validity */ 859 UDataMemory_init(&dataMemory); 860 UDataMemory_setData(&dataMemory, data); 861 udata_checkCommonData(&dataMemory, pErrorCode); 862 if (U_FAILURE(*pErrorCode)) {return;} 863 864 /* we have good data */ 865 /* Set it up as the ICU Common Data. */ 866 setCommonICUData(&dataMemory, TRUE, pErrorCode); 867} 868 869/*--------------------------------------------------------------------------- 870 * 871 * udata_setAppData 872 * 873 *---------------------------------------------------------------------------- */ 874U_CAPI void U_EXPORT2 875udata_setAppData(const char *path, const void *data, UErrorCode *err) 876{ 877 UDataMemory udm; 878 879 if(err==NULL || U_FAILURE(*err)) { 880 return; 881 } 882 if(data==NULL) { 883 *err=U_ILLEGAL_ARGUMENT_ERROR; 884 return; 885 } 886 887 UDataMemory_init(&udm); 888 UDataMemory_setData(&udm, data); 889 udata_checkCommonData(&udm, err); 890 udata_cacheDataItem(path, &udm, err); 891} 892 893/*----------------------------------------------------------------------------* 894 * * 895 * checkDataItem Given a freshly located/loaded data item, either * 896 * an entry in a common file or a separately loaded file, * 897 * sanity check its header, and see if the data is * 898 * acceptable to the app. * 899 * If the data is good, create and return a UDataMemory * 900 * object that can be returned to the application. * 901 * Return NULL on any sort of failure. * 902 * * 903 *----------------------------------------------------------------------------*/ 904static UDataMemory * 905checkDataItem 906( 907 const DataHeader *pHeader, /* The data item to be checked. */ 908 UDataMemoryIsAcceptable *isAcceptable, /* App's call-back function */ 909 void *context, /* pass-thru param for above. */ 910 const char *type, /* pass-thru param for above. */ 911 const char *name, /* pass-thru param for above. */ 912 UErrorCode *nonFatalErr, /* Error code if this data was not acceptable */ 913 /* but openChoice should continue with */ 914 /* trying to get data from fallback path. */ 915 UErrorCode *fatalErr /* Bad error, caller should return immediately */ 916 ) 917{ 918 UDataMemory *rDataMem = NULL; /* the new UDataMemory, to be returned. */ 919 920 if (U_FAILURE(*fatalErr)) { 921 return NULL; 922 } 923 924 if(pHeader->dataHeader.magic1==0xda && 925 pHeader->dataHeader.magic2==0x27 && 926 (isAcceptable==NULL || isAcceptable(context, type, name, &pHeader->info)) 927 ) { 928 rDataMem=UDataMemory_createNewInstance(fatalErr); 929 if (U_FAILURE(*fatalErr)) { 930 return NULL; 931 } 932 rDataMem->pHeader = pHeader; 933 } else { 934 /* the data is not acceptable, look further */ 935 /* If we eventually find something good, this errorcode will be */ 936 /* cleared out. */ 937 *nonFatalErr=U_INVALID_FORMAT_ERROR; 938 } 939 return rDataMem; 940} 941 942/** 943 * @return 0 if not loaded, 1 if loaded or err 944 */ 945static UDataMemory *doLoadFromIndividualFiles(const char *pkgName, 946 const char *dataPath, const char *tocEntryPathSuffix, 947 /* following arguments are the same as doOpenChoice itself */ 948 const char *path, const char *type, const char *name, 949 UDataMemoryIsAcceptable *isAcceptable, void *context, 950 UErrorCode *subErrorCode, 951 UErrorCode *pErrorCode) 952{ 953 const char *pathBuffer; 954 UDataMemory dataMemory; 955 UDataMemory *pEntryData; 956 957 /* look in ind. files: package\nam.typ ========================= */ 958 /* init path iterator for individual files */ 959 UDataPathIterator iter(dataPath, pkgName, path, tocEntryPathSuffix, FALSE, pErrorCode); 960 961 while((pathBuffer = iter.next(pErrorCode))) 962 { 963#ifdef UDATA_DEBUG 964 fprintf(stderr, "UDATA: trying individual file %s\n", pathBuffer); 965#endif 966 if(uprv_mapFile(&dataMemory, pathBuffer)) 967 { 968 pEntryData = checkDataItem(dataMemory.pHeader, isAcceptable, context, type, name, subErrorCode, pErrorCode); 969 if (pEntryData != NULL) { 970 /* Data is good. 971 * Hand off ownership of the backing memory to the user's UDataMemory. 972 * and return it. */ 973 pEntryData->mapAddr = dataMemory.mapAddr; 974 pEntryData->map = dataMemory.map; 975 976#ifdef UDATA_DEBUG 977 fprintf(stderr, "** Mapped file: %s\n", pathBuffer); 978#endif 979 return pEntryData; 980 } 981 982 /* the data is not acceptable, or some error occured. Either way, unmap the memory */ 983 udata_close(&dataMemory); 984 985 /* If we had a nasty error, bail out completely. */ 986 if (U_FAILURE(*pErrorCode)) { 987 return NULL; 988 } 989 990 /* Otherwise remember that we found data but didn't like it for some reason */ 991 *subErrorCode=U_INVALID_FORMAT_ERROR; 992 } 993#ifdef UDATA_DEBUG 994 fprintf(stderr, "%s\n", UDataMemory_isLoaded(&dataMemory)?"LOADED":"not loaded"); 995#endif 996 } 997 return NULL; 998} 999 1000/** 1001 * @return 0 if not loaded, 1 if loaded or err 1002 */ 1003static UDataMemory *doLoadFromCommonData(UBool isICUData, const char * /*pkgName*/, 1004 const char * /*dataPath*/, const char * /*tocEntryPathSuffix*/, const char *tocEntryName, 1005 /* following arguments are the same as doOpenChoice itself */ 1006 const char *path, const char *type, const char *name, 1007 UDataMemoryIsAcceptable *isAcceptable, void *context, 1008 UErrorCode *subErrorCode, 1009 UErrorCode *pErrorCode) 1010{ 1011 UDataMemory *pEntryData; 1012 const DataHeader *pHeader; 1013 UDataMemory *pCommonData; 1014 int32_t commonDataIndex; 1015 UBool checkedExtendedICUData = FALSE; 1016 /* try to get common data. The loop is for platforms such as the 390 that do 1017 * not initially load the full set of ICU data. If the lookup of an ICU data item 1018 * fails, the full (but slower to load) set is loaded, the and the loop repeats, 1019 * trying the lookup again. Once the full set of ICU data is loaded, the loop wont 1020 * repeat because the full set will be checked the first time through. 1021 * 1022 * The loop also handles the fallback to a .dat file if the application linked 1023 * to the stub data library rather than a real library. 1024 */ 1025 for (commonDataIndex = isICUData ? 0 : -1;;) { 1026 pCommonData=openCommonData(path, commonDataIndex, subErrorCode); /** search for pkg **/ 1027 1028 if(U_SUCCESS(*subErrorCode) && pCommonData!=NULL) { 1029 int32_t length; 1030 1031 /* look up the data piece in the common data */ 1032 pHeader=pCommonData->vFuncs->Lookup(pCommonData, tocEntryName, &length, subErrorCode); 1033#ifdef UDATA_DEBUG 1034 fprintf(stderr, "%s: pHeader=%p - %s\n", tocEntryName, pHeader, u_errorName(*subErrorCode)); 1035#endif 1036 1037 if(pHeader!=NULL) { 1038 pEntryData = checkDataItem(pHeader, isAcceptable, context, type, name, subErrorCode, pErrorCode); 1039#ifdef UDATA_DEBUG 1040 fprintf(stderr, "pEntryData=%p\n", pEntryData); 1041#endif 1042 if (U_FAILURE(*pErrorCode)) { 1043 return NULL; 1044 } 1045 if (pEntryData != NULL) { 1046 pEntryData->length = length; 1047 return pEntryData; 1048 } 1049 } 1050 } 1051 /* Data wasn't found. If we were looking for an ICUData item and there is 1052 * more data available, load it and try again, 1053 * otherwise break out of this loop. */ 1054 if (!isICUData) { 1055 return NULL; 1056 } else if (pCommonData != NULL) { 1057 ++commonDataIndex; /* try the next data package */ 1058 } else if ((!checkedExtendedICUData) && extendICUData(subErrorCode)) { 1059 checkedExtendedICUData = TRUE; 1060 /* try this data package slot again: it changed from NULL to non-NULL */ 1061 } else { 1062 return NULL; 1063 } 1064 } 1065} 1066 1067/* 1068 * Identify the Time Zone resources that are subject to special override data loading. 1069 */ 1070static UBool isTimeZoneFile(const char *name, const char *type) { 1071 return ((uprv_strcmp(type, "res") == 0) && 1072 (uprv_strcmp(name, "zoneinfo64") == 0 || 1073 uprv_strcmp(name, "timezoneTypes") == 0 || 1074 uprv_strcmp(name, "windowsZones") == 0 || 1075 uprv_strcmp(name, "metaZones") == 0)); 1076} 1077 1078/* 1079 * A note on the ownership of Mapped Memory 1080 * 1081 * For common format files, ownership resides with the UDataMemory object 1082 * that lives in the cache of opened common data. These UDataMemorys are private 1083 * to the udata implementation, and are never seen directly by users. 1084 * 1085 * The UDataMemory objects returned to users will have the address of some desired 1086 * data within the mapped region, but they wont have the mapping info itself, and thus 1087 * won't cause anything to be removed from memory when they are closed. 1088 * 1089 * For individual data files, the UDataMemory returned to the user holds the 1090 * information necessary to unmap the data on close. If the user independently 1091 * opens the same data file twice, two completely independent mappings will be made. 1092 * (There is no cache of opened data items from individual files, only a cache of 1093 * opened Common Data files, that is, files containing a collection of data items.) 1094 * 1095 * For common data passed in from the user via udata_setAppData() or 1096 * udata_setCommonData(), ownership remains with the user. 1097 * 1098 * UDataMemory objects themselves, as opposed to the memory they describe, 1099 * can be anywhere - heap, stack/local or global. 1100 * They have a flag to indicate when they're heap allocated and thus 1101 * must be deleted when closed. 1102 */ 1103 1104 1105/*----------------------------------------------------------------------------* 1106 * * 1107 * main data loading functions * 1108 * * 1109 *----------------------------------------------------------------------------*/ 1110static UDataMemory * 1111doOpenChoice(const char *path, const char *type, const char *name, 1112 UDataMemoryIsAcceptable *isAcceptable, void *context, 1113 UErrorCode *pErrorCode) 1114{ 1115 UDataMemory *retVal = NULL; 1116 1117 const char *dataPath; 1118 1119 int32_t tocEntrySuffixIndex; 1120 const char *tocEntryPathSuffix; 1121 UErrorCode subErrorCode=U_ZERO_ERROR; 1122 const char *treeChar; 1123 1124 UBool isICUData = FALSE; 1125 1126 1127 /* Is this path ICU data? */ 1128 if(path == NULL || 1129 !strcmp(path, U_ICUDATA_ALIAS) || /* "ICUDATA" */ 1130 !uprv_strncmp(path, U_ICUDATA_NAME U_TREE_SEPARATOR_STRING, /* "icudt26e-" */ 1131 uprv_strlen(U_ICUDATA_NAME U_TREE_SEPARATOR_STRING)) || 1132 !uprv_strncmp(path, U_ICUDATA_ALIAS U_TREE_SEPARATOR_STRING, /* "ICUDATA-" */ 1133 uprv_strlen(U_ICUDATA_ALIAS U_TREE_SEPARATOR_STRING))) { 1134 isICUData = TRUE; 1135 } 1136 1137#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR) /* Windows: try "foo\bar" and "foo/bar" */ 1138 /* remap from alternate path char to the main one */ 1139 CharString altSepPath; 1140 if(path) { 1141 if(uprv_strchr(path,U_FILE_ALT_SEP_CHAR) != NULL) { 1142 altSepPath.append(path, *pErrorCode); 1143 char *p; 1144 while((p=uprv_strchr(altSepPath.data(), U_FILE_ALT_SEP_CHAR))) { 1145 *p = U_FILE_SEP_CHAR; 1146 } 1147#if defined (UDATA_DEBUG) 1148 fprintf(stderr, "Changed path from [%s] to [%s]\n", path, altSepPath.s); 1149#endif 1150 path = altSepPath.data(); 1151 } 1152 } 1153#endif 1154 1155 CharString tocEntryName; /* entry name in tree format. ex: 'icudt28b/coll/ar.res' */ 1156 CharString tocEntryPath; /* entry name in path format. ex: 'icudt28b\\coll\\ar.res' */ 1157 1158 CharString pkgName; 1159 CharString treeName; 1160 1161 /* ======= Set up strings */ 1162 if(path==NULL) { 1163 pkgName.append(U_ICUDATA_NAME, *pErrorCode); 1164 } else { 1165 const char *pkg; 1166 const char *first; 1167 pkg = uprv_strrchr(path, U_FILE_SEP_CHAR); 1168 first = uprv_strchr(path, U_FILE_SEP_CHAR); 1169 if(uprv_pathIsAbsolute(path) || (pkg != first)) { /* more than one slash in the path- not a tree name */ 1170 /* see if this is an /absolute/path/to/package path */ 1171 if(pkg) { 1172 pkgName.append(pkg+1, *pErrorCode); 1173 } else { 1174 pkgName.append(path, *pErrorCode); 1175 } 1176 } else { 1177 treeChar = uprv_strchr(path, U_TREE_SEPARATOR); 1178 if(treeChar) { 1179 treeName.append(treeChar+1, *pErrorCode); /* following '-' */ 1180 if(isICUData) { 1181 pkgName.append(U_ICUDATA_NAME, *pErrorCode); 1182 } else { 1183 pkgName.append(path, (int32_t)(treeChar-path), *pErrorCode); 1184 if (first == NULL) { 1185 /* 1186 This user data has no path, but there is a tree name. 1187 Look up the correct path from the data cache later. 1188 */ 1189 path = pkgName.data(); 1190 } 1191 } 1192 } else { 1193 if(isICUData) { 1194 pkgName.append(U_ICUDATA_NAME, *pErrorCode); 1195 } else { 1196 pkgName.append(path, *pErrorCode); 1197 } 1198 } 1199 } 1200 } 1201 1202#ifdef UDATA_DEBUG 1203 fprintf(stderr, " P=%s T=%s\n", pkgName.data(), treeName.data()); 1204#endif 1205 1206 /* setting up the entry name and file name 1207 * Make up a full name by appending the type to the supplied 1208 * name, assuming that a type was supplied. 1209 */ 1210 1211 /* prepend the package */ 1212 tocEntryName.append(pkgName, *pErrorCode); 1213 tocEntryPath.append(pkgName, *pErrorCode); 1214 tocEntrySuffixIndex = tocEntryName.length(); 1215 1216 if(!treeName.isEmpty()) { 1217 tocEntryName.append(U_TREE_ENTRY_SEP_CHAR, *pErrorCode).append(treeName, *pErrorCode); 1218 tocEntryPath.append(U_FILE_SEP_CHAR, *pErrorCode).append(treeName, *pErrorCode); 1219 } 1220 1221 tocEntryName.append(U_TREE_ENTRY_SEP_CHAR, *pErrorCode).append(name, *pErrorCode); 1222 tocEntryPath.append(U_FILE_SEP_CHAR, *pErrorCode).append(name, *pErrorCode); 1223 if(type!=NULL && *type!=0) { 1224 tocEntryName.append(".", *pErrorCode).append(type, *pErrorCode); 1225 tocEntryPath.append(".", *pErrorCode).append(type, *pErrorCode); 1226 } 1227 tocEntryPathSuffix = tocEntryPath.data()+tocEntrySuffixIndex; /* suffix starts here */ 1228 1229#ifdef UDATA_DEBUG 1230 fprintf(stderr, " tocEntryName = %s\n", tocEntryName.data()); 1231 fprintf(stderr, " tocEntryPath = %s\n", tocEntryName.data()); 1232#endif 1233 1234 if(path == NULL) { 1235 path = COMMON_DATA_NAME; /* "icudt26e" */ 1236 } 1237 1238 /************************ Begin loop looking for ind. files ***************/ 1239#ifdef UDATA_DEBUG 1240 fprintf(stderr, "IND: inBasename = %s, pkg=%s\n", "(n/a)", packageNameFromPath(path)); 1241#endif 1242 1243 /* End of dealing with a null basename */ 1244 dataPath = u_getDataDirectory(); 1245 1246 /**** Time zone individual files override */ 1247 if (isTimeZoneFile(name, type) && isICUData) { 1248 const char *tzFilesDir = u_getTimeZoneFilesDirectory(pErrorCode); 1249 if (tzFilesDir[0] != 0) { 1250#ifdef UDATA_DEBUG 1251 fprintf(stderr, "Trying Time Zone Files directory = %s\n", tzFilesDir); 1252#endif 1253 retVal = doLoadFromIndividualFiles(/* pkgName.data() */ "", tzFilesDir, tocEntryPathSuffix, 1254 /* path */ "", type, name, isAcceptable, context, &subErrorCode, pErrorCode); 1255 if((retVal != NULL) || U_FAILURE(*pErrorCode)) { 1256 return retVal; 1257 } 1258 } 1259 } 1260 1261 /**** COMMON PACKAGE - only if packages are first. */ 1262 if(gDataFileAccess == UDATA_PACKAGES_FIRST) { 1263#ifdef UDATA_DEBUG 1264 fprintf(stderr, "Trying packages (UDATA_PACKAGES_FIRST)\n"); 1265#endif 1266 /* #2 */ 1267 retVal = doLoadFromCommonData(isICUData, 1268 pkgName.data(), dataPath, tocEntryPathSuffix, tocEntryName.data(), 1269 path, type, name, isAcceptable, context, &subErrorCode, pErrorCode); 1270 if((retVal != NULL) || U_FAILURE(*pErrorCode)) { 1271 return retVal; 1272 } 1273 } 1274 1275 /**** INDIVIDUAL FILES */ 1276 if((gDataFileAccess==UDATA_PACKAGES_FIRST) || 1277 (gDataFileAccess==UDATA_FILES_FIRST)) { 1278#ifdef UDATA_DEBUG 1279 fprintf(stderr, "Trying individual files\n"); 1280#endif 1281 /* Check to make sure that there is a dataPath to iterate over */ 1282 if ((dataPath && *dataPath) || !isICUData) { 1283 retVal = doLoadFromIndividualFiles(pkgName.data(), dataPath, tocEntryPathSuffix, 1284 path, type, name, isAcceptable, context, &subErrorCode, pErrorCode); 1285 if((retVal != NULL) || U_FAILURE(*pErrorCode)) { 1286 return retVal; 1287 } 1288 } 1289 } 1290 1291 /**** COMMON PACKAGE */ 1292 if((gDataFileAccess==UDATA_ONLY_PACKAGES) || 1293 (gDataFileAccess==UDATA_FILES_FIRST)) { 1294#ifdef UDATA_DEBUG 1295 fprintf(stderr, "Trying packages (UDATA_ONLY_PACKAGES || UDATA_FILES_FIRST)\n"); 1296#endif 1297 retVal = doLoadFromCommonData(isICUData, 1298 pkgName.data(), dataPath, tocEntryPathSuffix, tocEntryName.data(), 1299 path, type, name, isAcceptable, context, &subErrorCode, pErrorCode); 1300 if((retVal != NULL) || U_FAILURE(*pErrorCode)) { 1301 return retVal; 1302 } 1303 } 1304 1305 /* Load from DLL. If we haven't attempted package load, we also haven't had any chance to 1306 try a DLL (static or setCommonData/etc) load. 1307 If we ever have a "UDATA_ONLY_FILES", add it to the or list here. */ 1308 if(gDataFileAccess==UDATA_NO_FILES) { 1309#ifdef UDATA_DEBUG 1310 fprintf(stderr, "Trying common data (UDATA_NO_FILES)\n"); 1311#endif 1312 retVal = doLoadFromCommonData(isICUData, 1313 pkgName.data(), "", tocEntryPathSuffix, tocEntryName.data(), 1314 path, type, name, isAcceptable, context, &subErrorCode, pErrorCode); 1315 if((retVal != NULL) || U_FAILURE(*pErrorCode)) { 1316 return retVal; 1317 } 1318 } 1319 1320 /* data not found */ 1321 if(U_SUCCESS(*pErrorCode)) { 1322 if(U_SUCCESS(subErrorCode)) { 1323 /* file not found */ 1324 *pErrorCode=U_FILE_ACCESS_ERROR; 1325 } else { 1326 /* entry point not found or rejected */ 1327 *pErrorCode=subErrorCode; 1328 } 1329 } 1330 return retVal; 1331} 1332 1333 1334 1335/* API ---------------------------------------------------------------------- */ 1336 1337U_CAPI UDataMemory * U_EXPORT2 1338udata_open(const char *path, const char *type, const char *name, 1339 UErrorCode *pErrorCode) { 1340#ifdef UDATA_DEBUG 1341 fprintf(stderr, "udata_open(): Opening: %s : %s . %s\n", (path?path:"NULL"), name, type); 1342 fflush(stderr); 1343#endif 1344 1345 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1346 return NULL; 1347 } else if(name==NULL || *name==0) { 1348 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1349 return NULL; 1350 } else { 1351 return doOpenChoice(path, type, name, NULL, NULL, pErrorCode); 1352 } 1353} 1354 1355 1356 1357U_CAPI UDataMemory * U_EXPORT2 1358udata_openChoice(const char *path, const char *type, const char *name, 1359 UDataMemoryIsAcceptable *isAcceptable, void *context, 1360 UErrorCode *pErrorCode) { 1361#ifdef UDATA_DEBUG 1362 fprintf(stderr, "udata_openChoice(): Opening: %s : %s . %s\n", (path?path:"NULL"), name, type); 1363#endif 1364 1365 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1366 return NULL; 1367 } else if(name==NULL || *name==0 || isAcceptable==NULL) { 1368 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1369 return NULL; 1370 } else { 1371 return doOpenChoice(path, type, name, isAcceptable, context, pErrorCode); 1372 } 1373} 1374 1375 1376 1377U_CAPI void U_EXPORT2 1378udata_getInfo(UDataMemory *pData, UDataInfo *pInfo) { 1379 if(pInfo!=NULL) { 1380 if(pData!=NULL && pData->pHeader!=NULL) { 1381 const UDataInfo *info=&pData->pHeader->info; 1382 uint16_t dataInfoSize=udata_getInfoSize(info); 1383 if(pInfo->size>dataInfoSize) { 1384 pInfo->size=dataInfoSize; 1385 } 1386 uprv_memcpy((uint16_t *)pInfo+1, (const uint16_t *)info+1, pInfo->size-2); 1387 if(info->isBigEndian!=U_IS_BIG_ENDIAN) { 1388 /* opposite endianness */ 1389 uint16_t x=info->reservedWord; 1390 pInfo->reservedWord=(uint16_t)((x<<8)|(x>>8)); 1391 } 1392 } else { 1393 pInfo->size=0; 1394 } 1395 } 1396} 1397 1398 1399U_CAPI void U_EXPORT2 udata_setFileAccess(UDataFileAccess access, UErrorCode * /*status*/) 1400{ 1401 gDataFileAccess = access; 1402} 1403