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