udata.cpp revision f9878a236aa0d9662d8e40cafdaf2e04cd615835
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 setCommonICUDataPointer(&U_ICUDATA_ENTRY_POINT, FALSE, pErrorCode); 681 } 682 return gCommonICUDataArray[commonDataIndex]; 683 } 684 685 686 /* request is NOT for ICU Data. */ 687 688 /* Find the base name portion of the supplied path. */ 689 /* inBasename will be left pointing somewhere within the original path string. */ 690 inBasename = findBasename(path); 691#ifdef UDATA_DEBUG 692 fprintf(stderr, "inBasename = %s\n", inBasename); 693#endif 694 695 if(*inBasename==0) { 696 /* no basename. This will happen if the original path was a directory name, */ 697 /* like "a/b/c/". (Fallback to separate files will still work.) */ 698#ifdef UDATA_DEBUG 699 fprintf(stderr, "ocd: no basename in %s, bailing.\n", path); 700#endif 701 *pErrorCode=U_FILE_ACCESS_ERROR; 702 return NULL; 703 } 704 705 /* Is the requested common data file already open and cached? */ 706 /* Note that the cache is keyed by the base name only. The rest of the path, */ 707 /* if any, is not considered. */ 708 { 709 UDataMemory *dataToReturn = udata_findCachedData(inBasename); 710 if (dataToReturn != NULL) { 711 return dataToReturn; 712 } 713 } 714 715 /* Requested item is not in the cache. 716 * Hunt it down, trying all the path locations 717 */ 718 719 UDataPathIterator iter(u_getDataDirectory(), inBasename, path, ".dat", TRUE, pErrorCode); 720 721 while((UDataMemory_isLoaded(&tData)==FALSE) && (pathBuffer = iter.next(pErrorCode)) != NULL) 722 { 723#ifdef UDATA_DEBUG 724 fprintf(stderr, "ocd: trying path %s - ", pathBuffer); 725#endif 726 uprv_mapFile(&tData, pathBuffer); 727#ifdef UDATA_DEBUG 728 fprintf(stderr, "%s\n", UDataMemory_isLoaded(&tData)?"LOADED":"not loaded"); 729#endif 730 } 731 732#if defined(OS390_STUBDATA) && defined(OS390BATCH) 733 if (!UDataMemory_isLoaded(&tData)) { 734 char ourPathBuffer[1024]; 735 /* One more chance, for extendCommonData() */ 736 uprv_strncpy(ourPathBuffer, path, 1019); 737 ourPathBuffer[1019]=0; 738 uprv_strcat(ourPathBuffer, ".dat"); 739 uprv_mapFile(&tData, ourPathBuffer); 740 } 741#endif 742 743 if (!UDataMemory_isLoaded(&tData)) { 744 /* no common data */ 745 *pErrorCode=U_FILE_ACCESS_ERROR; 746 return NULL; 747 } 748 749 /* we have mapped a file, check its header */ 750 udata_checkCommonData(&tData, pErrorCode); 751 752 753 /* Cache the UDataMemory struct for this .dat file, 754 * so we won't need to hunt it down and map it again next time 755 * something is needed from it. */ 756 return udata_cacheDataItem(inBasename, &tData, pErrorCode); 757} 758 759 760/*----------------------------------------------------------------------* 761 * * 762 * extendICUData If the full set of ICU data was not loaded at * 763 * program startup, load it now. This function will * 764 * be called when the lookup of an ICU data item in * 765 * the common ICU data fails. * 766 * * 767 * return true if new data is loaded, false otherwise.* 768 * * 769 *----------------------------------------------------------------------*/ 770static UBool extendICUData(UErrorCode *pErr) 771{ 772 UDataMemory *pData; 773 UDataMemory copyPData; 774 UBool didUpdate = FALSE; 775 776 /* 777 * There is a chance for a race condition here. 778 * Normally, ICU data is loaded from a DLL or via mmap() and 779 * setCommonICUData() will detect if the same address is set twice. 780 * If ICU is built with data loading via fread() then the address will 781 * be different each time the common data is loaded and we may add 782 * multiple copies of the data. 783 * In this case, use a mutex to prevent the race. 784 * Use a specific mutex to avoid nested locks of the global mutex. 785 */ 786#if MAP_IMPLEMENTATION==MAP_STDIO 787 static UMutex extendICUDataMutex = U_MUTEX_INITIALIZER; 788 umtx_lock(&extendICUDataMutex); 789#endif 790 if(!gHaveTriedToLoadCommonData) { 791 /* See if we can explicitly open a .dat file for the ICUData. */ 792 pData = openCommonData( 793 U_ICUDATA_NAME, /* "icudt20l" , for example. */ 794 -1, /* Pretend we're not opening ICUData */ 795 pErr); 796 797 /* How about if there is no pData, eh... */ 798 799 UDataMemory_init(©PData); 800 if(pData != NULL) { 801 UDatamemory_assign(©PData, pData); 802 copyPData.map = 0; /* The mapping for this data is owned by the hash table */ 803 copyPData.mapAddr = 0; /* which will unmap it when ICU is shut down. */ 804 /* CommonICUData is also unmapped when ICU is shut down.*/ 805 /* To avoid unmapping the data twice, zero out the map */ 806 /* fields in the UDataMemory that we're assigning */ 807 /* to CommonICUData. */ 808 809 didUpdate = /* no longer using this result */ 810 setCommonICUData(©PData,/* The new common data. */ 811 FALSE, /* No warnings if write didn't happen */ 812 pErr); /* setCommonICUData honors errors; NOP if error set */ 813 } 814 815 gHaveTriedToLoadCommonData = TRUE; 816 } 817 818 didUpdate = findCommonICUDataByName(U_ICUDATA_NAME); /* Return 'true' when a racing writes out the extended */ 819 /* data after another thread has failed to see it (in openCommonData), so */ 820 /* extended data can be examined. */ 821 /* Also handles a race through here before gHaveTriedToLoadCommonData is set. */ 822 823#if MAP_IMPLEMENTATION==MAP_STDIO 824 umtx_unlock(&extendICUDataMutex); 825#endif 826 return didUpdate; /* Return true if ICUData pointer was updated. */ 827 /* (Could potentialy have been done by another thread racing */ 828 /* us through here, but that's fine, we still return true */ 829 /* so that current thread will also examine extended data. */ 830} 831 832/*----------------------------------------------------------------------* 833 * * 834 * udata_setCommonData * 835 * * 836 *----------------------------------------------------------------------*/ 837U_CAPI void U_EXPORT2 838udata_setCommonData(const void *data, UErrorCode *pErrorCode) { 839 UDataMemory dataMemory; 840 841 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 842 return; 843 } 844 845 if(data==NULL) { 846 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 847 return; 848 } 849 850 /* set the data pointer and test for validity */ 851 UDataMemory_init(&dataMemory); 852 UDataMemory_setData(&dataMemory, data); 853 udata_checkCommonData(&dataMemory, pErrorCode); 854 if (U_FAILURE(*pErrorCode)) {return;} 855 856 /* we have good data */ 857 /* Set it up as the ICU Common Data. */ 858 setCommonICUData(&dataMemory, TRUE, pErrorCode); 859} 860 861/*--------------------------------------------------------------------------- 862 * 863 * udata_setAppData 864 * 865 *---------------------------------------------------------------------------- */ 866U_CAPI void U_EXPORT2 867udata_setAppData(const char *path, const void *data, UErrorCode *err) 868{ 869 UDataMemory udm; 870 871 if(err==NULL || U_FAILURE(*err)) { 872 return; 873 } 874 if(data==NULL) { 875 *err=U_ILLEGAL_ARGUMENT_ERROR; 876 return; 877 } 878 879 UDataMemory_init(&udm); 880 UDataMemory_setData(&udm, data); 881 udata_checkCommonData(&udm, err); 882 udata_cacheDataItem(path, &udm, err); 883} 884 885/*----------------------------------------------------------------------------* 886 * * 887 * checkDataItem Given a freshly located/loaded data item, either * 888 * an entry in a common file or a separately loaded file, * 889 * sanity check its header, and see if the data is * 890 * acceptable to the app. * 891 * If the data is good, create and return a UDataMemory * 892 * object that can be returned to the application. * 893 * Return NULL on any sort of failure. * 894 * * 895 *----------------------------------------------------------------------------*/ 896static UDataMemory * 897checkDataItem 898( 899 const DataHeader *pHeader, /* The data item to be checked. */ 900 UDataMemoryIsAcceptable *isAcceptable, /* App's call-back function */ 901 void *context, /* pass-thru param for above. */ 902 const char *type, /* pass-thru param for above. */ 903 const char *name, /* pass-thru param for above. */ 904 UErrorCode *nonFatalErr, /* Error code if this data was not acceptable */ 905 /* but openChoice should continue with */ 906 /* trying to get data from fallback path. */ 907 UErrorCode *fatalErr /* Bad error, caller should return immediately */ 908 ) 909{ 910 UDataMemory *rDataMem = NULL; /* the new UDataMemory, to be returned. */ 911 912 if (U_FAILURE(*fatalErr)) { 913 return NULL; 914 } 915 916 if(pHeader->dataHeader.magic1==0xda && 917 pHeader->dataHeader.magic2==0x27 && 918 (isAcceptable==NULL || isAcceptable(context, type, name, &pHeader->info)) 919 ) { 920 rDataMem=UDataMemory_createNewInstance(fatalErr); 921 if (U_FAILURE(*fatalErr)) { 922 return NULL; 923 } 924 rDataMem->pHeader = pHeader; 925 } else { 926 /* the data is not acceptable, look further */ 927 /* If we eventually find something good, this errorcode will be */ 928 /* cleared out. */ 929 *nonFatalErr=U_INVALID_FORMAT_ERROR; 930 } 931 return rDataMem; 932} 933 934/** 935 * @return 0 if not loaded, 1 if loaded or err 936 */ 937static UDataMemory *doLoadFromIndividualFiles(const char *pkgName, 938 const char *dataPath, const char *tocEntryPathSuffix, 939 /* following arguments are the same as doOpenChoice itself */ 940 const char *path, const char *type, const char *name, 941 UDataMemoryIsAcceptable *isAcceptable, void *context, 942 UErrorCode *subErrorCode, 943 UErrorCode *pErrorCode) 944{ 945 const char *pathBuffer; 946 UDataMemory dataMemory; 947 UDataMemory *pEntryData; 948 949 /* look in ind. files: package\nam.typ ========================= */ 950 /* init path iterator for individual files */ 951 UDataPathIterator iter(dataPath, pkgName, path, tocEntryPathSuffix, FALSE, pErrorCode); 952 953 while((pathBuffer = iter.next(pErrorCode))) 954 { 955#ifdef UDATA_DEBUG 956 fprintf(stderr, "UDATA: trying individual file %s\n", pathBuffer); 957#endif 958 if(uprv_mapFile(&dataMemory, pathBuffer)) 959 { 960 pEntryData = checkDataItem(dataMemory.pHeader, isAcceptable, context, type, name, subErrorCode, pErrorCode); 961 if (pEntryData != NULL) { 962 /* Data is good. 963 * Hand off ownership of the backing memory to the user's UDataMemory. 964 * and return it. */ 965 pEntryData->mapAddr = dataMemory.mapAddr; 966 pEntryData->map = dataMemory.map; 967 968#ifdef UDATA_DEBUG 969 fprintf(stderr, "** Mapped file: %s\n", pathBuffer); 970#endif 971 return pEntryData; 972 } 973 974 /* the data is not acceptable, or some error occured. Either way, unmap the memory */ 975 udata_close(&dataMemory); 976 977 /* If we had a nasty error, bail out completely. */ 978 if (U_FAILURE(*pErrorCode)) { 979 return NULL; 980 } 981 982 /* Otherwise remember that we found data but didn't like it for some reason */ 983 *subErrorCode=U_INVALID_FORMAT_ERROR; 984 } 985#ifdef UDATA_DEBUG 986 fprintf(stderr, "%s\n", UDataMemory_isLoaded(&dataMemory)?"LOADED":"not loaded"); 987#endif 988 } 989 return NULL; 990} 991 992/** 993 * @return 0 if not loaded, 1 if loaded or err 994 */ 995static UDataMemory *doLoadFromCommonData(UBool isICUData, const char * /*pkgName*/, 996 const char * /*dataPath*/, const char * /*tocEntryPathSuffix*/, const char *tocEntryName, 997 /* following arguments are the same as doOpenChoice itself */ 998 const char *path, const char *type, const char *name, 999 UDataMemoryIsAcceptable *isAcceptable, void *context, 1000 UErrorCode *subErrorCode, 1001 UErrorCode *pErrorCode) 1002{ 1003 UDataMemory *pEntryData; 1004 const DataHeader *pHeader; 1005 UDataMemory *pCommonData; 1006 int32_t commonDataIndex; 1007 UBool checkedExtendedICUData = FALSE; 1008 /* try to get common data. The loop is for platforms such as the 390 that do 1009 * not initially load the full set of ICU data. If the lookup of an ICU data item 1010 * fails, the full (but slower to load) set is loaded, the and the loop repeats, 1011 * trying the lookup again. Once the full set of ICU data is loaded, the loop wont 1012 * repeat because the full set will be checked the first time through. 1013 * 1014 * The loop also handles the fallback to a .dat file if the application linked 1015 * to the stub data library rather than a real library. 1016 */ 1017 for (commonDataIndex = isICUData ? 0 : -1;;) { 1018 pCommonData=openCommonData(path, commonDataIndex, subErrorCode); /** search for pkg **/ 1019 1020 if(U_SUCCESS(*subErrorCode) && pCommonData!=NULL) { 1021 int32_t length; 1022 1023 /* look up the data piece in the common data */ 1024 pHeader=pCommonData->vFuncs->Lookup(pCommonData, tocEntryName, &length, subErrorCode); 1025#ifdef UDATA_DEBUG 1026 fprintf(stderr, "%s: pHeader=%p - %s\n", tocEntryName, pHeader, u_errorName(*subErrorCode)); 1027#endif 1028 1029 if(pHeader!=NULL) { 1030 pEntryData = checkDataItem(pHeader, isAcceptable, context, type, name, subErrorCode, pErrorCode); 1031#ifdef UDATA_DEBUG 1032 fprintf(stderr, "pEntryData=%p\n", pEntryData); 1033#endif 1034 if (U_FAILURE(*pErrorCode)) { 1035 return NULL; 1036 } 1037 if (pEntryData != NULL) { 1038 pEntryData->length = length; 1039 return pEntryData; 1040 } 1041 } 1042 } 1043 /* Data wasn't found. If we were looking for an ICUData item and there is 1044 * more data available, load it and try again, 1045 * otherwise break out of this loop. */ 1046 if (!isICUData) { 1047 return NULL; 1048 } else if (pCommonData != NULL) { 1049 ++commonDataIndex; /* try the next data package */ 1050 } else if ((!checkedExtendedICUData) && extendICUData(subErrorCode)) { 1051 checkedExtendedICUData = TRUE; 1052 /* try this data package slot again: it changed from NULL to non-NULL */ 1053 } else { 1054 return NULL; 1055 } 1056 } 1057} 1058 1059/* 1060 * Identify the Time Zone resources that are subject to special override data loading. 1061 */ 1062static UBool isTimeZoneFile(const char *name, const char *type) { 1063 return ((uprv_strcmp(type, "res") == 0) && 1064 (uprv_strcmp(name, "zoneinfo64") == 0 || 1065 uprv_strcmp(name, "timezoneTypes") == 0 || 1066 uprv_strcmp(name, "windowsZones") == 0 || 1067 uprv_strcmp(name, "metaZones") == 0)); 1068} 1069 1070/* 1071 * A note on the ownership of Mapped Memory 1072 * 1073 * For common format files, ownership resides with the UDataMemory object 1074 * that lives in the cache of opened common data. These UDataMemorys are private 1075 * to the udata implementation, and are never seen directly by users. 1076 * 1077 * The UDataMemory objects returned to users will have the address of some desired 1078 * data within the mapped region, but they wont have the mapping info itself, and thus 1079 * won't cause anything to be removed from memory when they are closed. 1080 * 1081 * For individual data files, the UDataMemory returned to the user holds the 1082 * information necessary to unmap the data on close. If the user independently 1083 * opens the same data file twice, two completely independent mappings will be made. 1084 * (There is no cache of opened data items from individual files, only a cache of 1085 * opened Common Data files, that is, files containing a collection of data items.) 1086 * 1087 * For common data passed in from the user via udata_setAppData() or 1088 * udata_setCommonData(), ownership remains with the user. 1089 * 1090 * UDataMemory objects themselves, as opposed to the memory they describe, 1091 * can be anywhere - heap, stack/local or global. 1092 * They have a flag to indicate when they're heap allocated and thus 1093 * must be deleted when closed. 1094 */ 1095 1096 1097/*----------------------------------------------------------------------------* 1098 * * 1099 * main data loading functions * 1100 * * 1101 *----------------------------------------------------------------------------*/ 1102static UDataMemory * 1103doOpenChoice(const char *path, const char *type, const char *name, 1104 UDataMemoryIsAcceptable *isAcceptable, void *context, 1105 UErrorCode *pErrorCode) 1106{ 1107 UDataMemory *retVal = NULL; 1108 1109 const char *dataPath; 1110 1111 int32_t tocEntrySuffixIndex; 1112 const char *tocEntryPathSuffix; 1113 UErrorCode subErrorCode=U_ZERO_ERROR; 1114 const char *treeChar; 1115 1116 UBool isICUData = FALSE; 1117 1118 1119 /* Is this path ICU data? */ 1120 if(path == NULL || 1121 !strcmp(path, U_ICUDATA_ALIAS) || /* "ICUDATA" */ 1122 !uprv_strncmp(path, U_ICUDATA_NAME U_TREE_SEPARATOR_STRING, /* "icudt26e-" */ 1123 uprv_strlen(U_ICUDATA_NAME U_TREE_SEPARATOR_STRING)) || 1124 !uprv_strncmp(path, U_ICUDATA_ALIAS U_TREE_SEPARATOR_STRING, /* "ICUDATA-" */ 1125 uprv_strlen(U_ICUDATA_ALIAS U_TREE_SEPARATOR_STRING))) { 1126 isICUData = TRUE; 1127 } 1128 1129#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR) /* Windows: try "foo\bar" and "foo/bar" */ 1130 /* remap from alternate path char to the main one */ 1131 CharString altSepPath; 1132 if(path) { 1133 if(uprv_strchr(path,U_FILE_ALT_SEP_CHAR) != NULL) { 1134 altSepPath.append(path, *pErrorCode); 1135 char *p; 1136 while((p=uprv_strchr(altSepPath.data(), U_FILE_ALT_SEP_CHAR))) { 1137 *p = U_FILE_SEP_CHAR; 1138 } 1139#if defined (UDATA_DEBUG) 1140 fprintf(stderr, "Changed path from [%s] to [%s]\n", path, altSepPath.s); 1141#endif 1142 path = altSepPath.data(); 1143 } 1144 } 1145#endif 1146 1147 CharString tocEntryName; /* entry name in tree format. ex: 'icudt28b/coll/ar.res' */ 1148 CharString tocEntryPath; /* entry name in path format. ex: 'icudt28b\\coll\\ar.res' */ 1149 1150 CharString pkgName; 1151 CharString treeName; 1152 1153 /* ======= Set up strings */ 1154 if(path==NULL) { 1155 pkgName.append(U_ICUDATA_NAME, *pErrorCode); 1156 } else { 1157 const char *pkg; 1158 const char *first; 1159 pkg = uprv_strrchr(path, U_FILE_SEP_CHAR); 1160 first = uprv_strchr(path, U_FILE_SEP_CHAR); 1161 if(uprv_pathIsAbsolute(path) || (pkg != first)) { /* more than one slash in the path- not a tree name */ 1162 /* see if this is an /absolute/path/to/package path */ 1163 if(pkg) { 1164 pkgName.append(pkg+1, *pErrorCode); 1165 } else { 1166 pkgName.append(path, *pErrorCode); 1167 } 1168 } else { 1169 treeChar = uprv_strchr(path, U_TREE_SEPARATOR); 1170 if(treeChar) { 1171 treeName.append(treeChar+1, *pErrorCode); /* following '-' */ 1172 if(isICUData) { 1173 pkgName.append(U_ICUDATA_NAME, *pErrorCode); 1174 } else { 1175 pkgName.append(path, (int32_t)(treeChar-path), *pErrorCode); 1176 if (first == NULL) { 1177 /* 1178 This user data has no path, but there is a tree name. 1179 Look up the correct path from the data cache later. 1180 */ 1181 path = pkgName.data(); 1182 } 1183 } 1184 } else { 1185 if(isICUData) { 1186 pkgName.append(U_ICUDATA_NAME, *pErrorCode); 1187 } else { 1188 pkgName.append(path, *pErrorCode); 1189 } 1190 } 1191 } 1192 } 1193 1194#ifdef UDATA_DEBUG 1195 fprintf(stderr, " P=%s T=%s\n", pkgName.data(), treeName.data()); 1196#endif 1197 1198 /* setting up the entry name and file name 1199 * Make up a full name by appending the type to the supplied 1200 * name, assuming that a type was supplied. 1201 */ 1202 1203 /* prepend the package */ 1204 tocEntryName.append(pkgName, *pErrorCode); 1205 tocEntryPath.append(pkgName, *pErrorCode); 1206 tocEntrySuffixIndex = tocEntryName.length(); 1207 1208 if(!treeName.isEmpty()) { 1209 tocEntryName.append(U_TREE_ENTRY_SEP_CHAR, *pErrorCode).append(treeName, *pErrorCode); 1210 tocEntryPath.append(U_FILE_SEP_CHAR, *pErrorCode).append(treeName, *pErrorCode); 1211 } 1212 1213 tocEntryName.append(U_TREE_ENTRY_SEP_CHAR, *pErrorCode).append(name, *pErrorCode); 1214 tocEntryPath.append(U_FILE_SEP_CHAR, *pErrorCode).append(name, *pErrorCode); 1215 if(type!=NULL && *type!=0) { 1216 tocEntryName.append(".", *pErrorCode).append(type, *pErrorCode); 1217 tocEntryPath.append(".", *pErrorCode).append(type, *pErrorCode); 1218 } 1219 tocEntryPathSuffix = tocEntryPath.data()+tocEntrySuffixIndex; /* suffix starts here */ 1220 1221#ifdef UDATA_DEBUG 1222 fprintf(stderr, " tocEntryName = %s\n", tocEntryName.data()); 1223 fprintf(stderr, " tocEntryPath = %s\n", tocEntryName.data()); 1224#endif 1225 1226 if(path == NULL) { 1227 path = COMMON_DATA_NAME; /* "icudt26e" */ 1228 } 1229 1230 /************************ Begin loop looking for ind. files ***************/ 1231#ifdef UDATA_DEBUG 1232 fprintf(stderr, "IND: inBasename = %s, pkg=%s\n", "(n/a)", packageNameFromPath(path)); 1233#endif 1234 1235 /* End of dealing with a null basename */ 1236 dataPath = u_getDataDirectory(); 1237 1238 /**** Time zone individual files override */ 1239 if (isTimeZoneFile(name, type) && isICUData) { 1240 const char *tzFilesDir = u_getTimeZoneFilesDirectory(pErrorCode); 1241 if (tzFilesDir[0] != 0) { 1242#ifdef UDATA_DEBUG 1243 fprintf(stderr, "Trying Time Zone Files directory = %s\n", tzFilesDir); 1244#endif 1245 retVal = doLoadFromIndividualFiles(/* pkgName.data() */ "", tzFilesDir, tocEntryPathSuffix, 1246 /* path */ "", type, name, isAcceptable, context, &subErrorCode, pErrorCode); 1247 if((retVal != NULL) || U_FAILURE(*pErrorCode)) { 1248 return retVal; 1249 } 1250 } 1251 } 1252 1253 /**** COMMON PACKAGE - only if packages are first. */ 1254 if(gDataFileAccess == UDATA_PACKAGES_FIRST) { 1255#ifdef UDATA_DEBUG 1256 fprintf(stderr, "Trying packages (UDATA_PACKAGES_FIRST)\n"); 1257#endif 1258 /* #2 */ 1259 retVal = doLoadFromCommonData(isICUData, 1260 pkgName.data(), dataPath, tocEntryPathSuffix, tocEntryName.data(), 1261 path, type, name, isAcceptable, context, &subErrorCode, pErrorCode); 1262 if((retVal != NULL) || U_FAILURE(*pErrorCode)) { 1263 return retVal; 1264 } 1265 } 1266 1267 /**** INDIVIDUAL FILES */ 1268 if((gDataFileAccess==UDATA_PACKAGES_FIRST) || 1269 (gDataFileAccess==UDATA_FILES_FIRST)) { 1270#ifdef UDATA_DEBUG 1271 fprintf(stderr, "Trying individual files\n"); 1272#endif 1273 /* Check to make sure that there is a dataPath to iterate over */ 1274 if ((dataPath && *dataPath) || !isICUData) { 1275 retVal = doLoadFromIndividualFiles(pkgName.data(), dataPath, tocEntryPathSuffix, 1276 path, type, name, isAcceptable, context, &subErrorCode, pErrorCode); 1277 if((retVal != NULL) || U_FAILURE(*pErrorCode)) { 1278 return retVal; 1279 } 1280 } 1281 } 1282 1283 /**** COMMON PACKAGE */ 1284 if((gDataFileAccess==UDATA_ONLY_PACKAGES) || 1285 (gDataFileAccess==UDATA_FILES_FIRST)) { 1286#ifdef UDATA_DEBUG 1287 fprintf(stderr, "Trying packages (UDATA_ONLY_PACKAGES || UDATA_FILES_FIRST)\n"); 1288#endif 1289 retVal = doLoadFromCommonData(isICUData, 1290 pkgName.data(), dataPath, tocEntryPathSuffix, tocEntryName.data(), 1291 path, type, name, isAcceptable, context, &subErrorCode, pErrorCode); 1292 if((retVal != NULL) || U_FAILURE(*pErrorCode)) { 1293 return retVal; 1294 } 1295 } 1296 1297 /* Load from DLL. If we haven't attempted package load, we also haven't had any chance to 1298 try a DLL (static or setCommonData/etc) load. 1299 If we ever have a "UDATA_ONLY_FILES", add it to the or list here. */ 1300 if(gDataFileAccess==UDATA_NO_FILES) { 1301#ifdef UDATA_DEBUG 1302 fprintf(stderr, "Trying common data (UDATA_NO_FILES)\n"); 1303#endif 1304 retVal = doLoadFromCommonData(isICUData, 1305 pkgName.data(), "", tocEntryPathSuffix, tocEntryName.data(), 1306 path, type, name, isAcceptable, context, &subErrorCode, pErrorCode); 1307 if((retVal != NULL) || U_FAILURE(*pErrorCode)) { 1308 return retVal; 1309 } 1310 } 1311 1312 /* data not found */ 1313 if(U_SUCCESS(*pErrorCode)) { 1314 if(U_SUCCESS(subErrorCode)) { 1315 /* file not found */ 1316 *pErrorCode=U_FILE_ACCESS_ERROR; 1317 } else { 1318 /* entry point not found or rejected */ 1319 *pErrorCode=subErrorCode; 1320 } 1321 } 1322 return retVal; 1323} 1324 1325 1326 1327/* API ---------------------------------------------------------------------- */ 1328 1329U_CAPI UDataMemory * U_EXPORT2 1330udata_open(const char *path, const char *type, const char *name, 1331 UErrorCode *pErrorCode) { 1332#ifdef UDATA_DEBUG 1333 fprintf(stderr, "udata_open(): Opening: %s : %s . %s\n", (path?path:"NULL"), name, type); 1334 fflush(stderr); 1335#endif 1336 1337 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1338 return NULL; 1339 } else if(name==NULL || *name==0) { 1340 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1341 return NULL; 1342 } else { 1343 return doOpenChoice(path, type, name, NULL, NULL, pErrorCode); 1344 } 1345} 1346 1347 1348 1349U_CAPI UDataMemory * U_EXPORT2 1350udata_openChoice(const char *path, const char *type, const char *name, 1351 UDataMemoryIsAcceptable *isAcceptable, void *context, 1352 UErrorCode *pErrorCode) { 1353#ifdef UDATA_DEBUG 1354 fprintf(stderr, "udata_openChoice(): Opening: %s : %s . %s\n", (path?path:"NULL"), name, type); 1355#endif 1356 1357 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1358 return NULL; 1359 } else if(name==NULL || *name==0 || isAcceptable==NULL) { 1360 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1361 return NULL; 1362 } else { 1363 return doOpenChoice(path, type, name, isAcceptable, context, pErrorCode); 1364 } 1365} 1366 1367 1368 1369U_CAPI void U_EXPORT2 1370udata_getInfo(UDataMemory *pData, UDataInfo *pInfo) { 1371 if(pInfo!=NULL) { 1372 if(pData!=NULL && pData->pHeader!=NULL) { 1373 const UDataInfo *info=&pData->pHeader->info; 1374 uint16_t dataInfoSize=udata_getInfoSize(info); 1375 if(pInfo->size>dataInfoSize) { 1376 pInfo->size=dataInfoSize; 1377 } 1378 uprv_memcpy((uint16_t *)pInfo+1, (const uint16_t *)info+1, pInfo->size-2); 1379 if(info->isBigEndian!=U_IS_BIG_ENDIAN) { 1380 /* opposite endianness */ 1381 uint16_t x=info->reservedWord; 1382 pInfo->reservedWord=(uint16_t)((x<<8)|(x>>8)); 1383 } 1384 } else { 1385 pInfo->size=0; 1386 } 1387 } 1388} 1389 1390 1391U_CAPI void U_EXPORT2 udata_setFileAccess(UDataFileAccess access, UErrorCode * /*status*/) 1392{ 1393 gDataFileAccess = access; 1394} 1395