tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

udata.cpp (55048B)


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