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