1999-11-22 19:43:01 +00:00
/*
2001-03-21 20:44:20 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2000-01-13 23:54:23 +00:00
*
2003-06-03 06:44:40 +00:00
* Copyright ( C ) 1999 - 2003 , International Business Machines
2000-01-13 23:54:23 +00:00
* Corporation and others . All Rights Reserved .
*
2001-03-21 20:44:20 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1999-11-22 19:43:01 +00:00
* file name : udata . c
* encoding : US - ASCII
* tab size : 8 ( not used )
* indentation : 4
*
* created on : 1999 oct25
* created by : Markus W . Scherer
*/
1999-12-28 23:39:02 +00:00
# include "unicode/utypes.h"
# include "unicode/putil.h"
1999-11-22 19:43:01 +00:00
# include "umutex.h"
# include "cmemory.h"
# include "cstring.h"
1999-12-28 23:39:02 +00:00
# include "unicode/udata.h"
2001-07-26 21:55:49 +00:00
# include "unicode/uversion.h"
2001-08-10 20:50:07 +00:00
# include "uhash.h"
2001-08-17 00:18:49 +00:00
# include "ucln_cmn.h"
1999-11-22 19:43:01 +00:00
2001-09-07 18:42:29 +00:00
# include "udatamem.h"
# include "umapfile.h"
# include "ucmndata.h"
2000-11-22 01:24:40 +00:00
2001-09-07 18:42:29 +00:00
/***********************************************************************
*
* Notes on the organization of the ICU data implementation
*
* All of the public API is defined in udata . h
*
* The implementation is split into several files . . .
*
* - udata . c ( this file ) contains higher level code that knows about
* the search paths for locating data , caching opened data , etc .
*
* - umapfile . c contains the low level platform - specific code for actually loading
* ( memory mapping , file reading , whatever ) data into memory .
*
* - ucmndata . c deals with the tables of contents of ICU data items within
* an ICU common format data file . The implementation includes
* an abstract interface and support for multiple TOC formats .
* All knowledge of any specific TOC format is encapsulated here .
*
* - udatamem . c has code for managing UDataMemory structs . These are little
* descriptor objects for blocks of memory holding ICU data of
* various types .
2001-09-25 16:43:20 +00:00
*/
2000-12-05 02:28:32 +00:00
2001-09-07 18:42:29 +00:00
/* configuration ---------------------------------------------------------- */
1999-11-22 19:43:01 +00:00
2000-01-19 07:23:50 +00:00
/* If you are excruciatingly bored turn this on .. */
2000-05-03 23:11:04 +00:00
/* #define UDATA_DEBUG 1 */
1999-11-22 19:43:01 +00:00
2002-07-17 03:01:45 +00:00
1999-11-22 19:43:01 +00:00
# if defined(UDATA_DEBUG)
2000-05-03 23:11:04 +00:00
# include <stdio.h>
1999-11-22 19:43:01 +00:00
# endif
2001-08-10 20:50:07 +00:00
2001-09-07 18:42:29 +00:00
/***********************************************************************
*
* static ( Global ) data
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-09-17 22:57:38 +00:00
static UDataMemory * gCommonICUData = NULL ; /* Pointer to the common ICU data. */
/* May be updated once, if we started with */
/* a stub or subset library. */
2001-08-10 20:50:07 +00:00
2001-09-17 22:57:38 +00:00
static UDataMemory * gStubICUData = NULL ; /* If gCommonICUData does get updated, remember */
/* the original one so that it can be cleaned */
/* up when ICU is shut down. */
static UHashtable * gCommonDataCache = NULL ; /* Global hash table of opened ICU data files. */
2000-11-04 02:16:12 +00:00
1999-11-22 19:43:01 +00:00
2001-09-07 18:42:29 +00:00
UBool
udata_cleanup ( )
{
2001-10-10 18:05:10 +00:00
if ( gCommonDataCache ) { /* Delete the cache of user data mappings. */
uhash_close ( gCommonDataCache ) ; /* Table owns the contents, and will delete them. */
gCommonDataCache = NULL ; /* Cleanup is not thread safe. */
1999-11-22 19:43:01 +00:00
}
2001-09-17 22:57:38 +00:00
if ( gCommonICUData ! = NULL ) {
2001-10-10 18:05:10 +00:00
udata_close ( gCommonICUData ) ; /* Clean up common ICU Data */
gCommonICUData = NULL ;
2001-09-17 22:57:38 +00:00
}
if ( gStubICUData ! = NULL ) {
2001-10-10 18:05:10 +00:00
udata_close ( gStubICUData ) ; /* Clean up the stub ICU Data */
2001-09-17 22:57:38 +00:00
gStubICUData = NULL ;
}
2000-11-04 02:16:12 +00:00
2001-09-07 18:42:29 +00:00
return TRUE ; /* Everything was cleaned up */
1999-11-22 19:43:01 +00:00
}
2001-08-30 18:41:30 +00:00
/*
* setCommonICUData . Set a UDataMemory to be the global ICU Data
*/
static void
setCommonICUData ( UDataMemory * pData , /* The new common data. Belongs to caller, we copy it. */
UDataMemory * oldData , /* Old ICUData ptr. Overwrite of this value is ok, */
/* of any others is not. */
UBool warn , /* If true, set USING_DEFAULT warning if ICUData was */
/* changed by another thread before we got to it. */
UErrorCode * pErr )
{
UDataMemory * newCommonData = UDataMemory_createNewInstance ( pErr ) ;
if ( U_FAILURE ( * pErr ) ) {
return ;
}
1999-11-22 19:43:01 +00:00
2001-08-30 18:41:30 +00:00
/* For the assignment, other threads must cleanly see either the old */
/* or the new, not some partially initialized new. The old can not be */
/* deleted - someone may still have a pointer to it lying around in */
/* their locals. */
UDatamemory_assign ( newCommonData , pData ) ;
2000-05-03 23:11:04 +00:00
umtx_lock ( NULL ) ;
2001-09-07 18:42:29 +00:00
if ( gCommonICUData = = oldData ) {
2001-09-17 22:57:38 +00:00
gStubICUData = gCommonICUData ; /* remember the old Common Data, so it can be cleaned up. */
2001-09-07 18:42:29 +00:00
gCommonICUData = newCommonData ;
2001-08-30 18:41:30 +00:00
}
else {
if ( warn = = TRUE ) {
* pErr = U_USING_DEFAULT_WARNING ;
}
uprv_free ( newCommonData ) ;
2000-05-03 23:11:04 +00:00
}
umtx_unlock ( NULL ) ;
2001-08-30 18:41:30 +00:00
return ;
1999-12-01 01:02:06 +00:00
}
2000-05-03 23:11:04 +00:00
static const char *
findBasename ( const char * path ) {
const char * basename = uprv_strrchr ( path , U_FILE_SEP_CHAR ) ;
if ( basename = = NULL ) {
return path ;
} else {
return basename + 1 ;
1999-12-01 01:02:06 +00:00
}
}
2002-07-17 03:01:45 +00:00
static const char *
packageNameFromPath ( const char * path )
{
if ( ( path = = NULL ) | | ( * path = = 0 ) ) {
return U_ICUDATA_NAME ;
}
path = findBasename ( path ) ;
if ( ( path = = NULL ) | | ( * path = = 0 ) ) {
return U_ICUDATA_NAME ;
}
return path ;
}
2001-07-26 21:55:49 +00:00
2001-08-10 20:50:07 +00:00
/*----------------------------------------------------------------------*
* *
* Cache for common data *
* Functions for looking up or adding entries to a cache of *
* data that has been previously opened . Avoids a potentially *
* expensive operation of re - opening the data for subsequent *
* uses . *
* *
* Data remains cached for the duration of the process . *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
typedef struct DataCacheElement {
2001-08-29 22:57:37 +00:00
char * name ;
2001-09-07 18:42:29 +00:00
UDataMemory * item ;
2001-08-10 20:50:07 +00:00
} DataCacheElement ;
2001-08-15 23:27:38 +00:00
2001-08-15 22:39:42 +00:00
/*
2001-08-15 23:27:38 +00:00
* Deleter function for DataCacheElements .
2001-08-15 22:39:42 +00:00
* udata cleanup function closes the hash table ; hash table in turn calls back to
* here for each entry .
*/
2001-11-21 01:02:11 +00:00
static void U_EXPORT2 U_CALLCONV DataCacheElement_deleter ( void * pDCEl ) {
2001-08-15 22:39:42 +00:00
DataCacheElement * p = ( DataCacheElement * ) pDCEl ;
2001-09-07 18:42:29 +00:00
udata_close ( p - > item ) ; /* unmaps storage */
2001-08-29 22:57:37 +00:00
uprv_free ( p - > name ) ; /* delete the hash key string. */
2001-08-15 22:39:42 +00:00
uprv_free ( pDCEl ) ; /* delete 'this' */
}
2001-08-10 20:50:07 +00:00
/* udata_getCacheHashTable()
* Get the hash table used to store the data cache entries .
* Lazy create it if it doesn ' t yet exist .
2001-08-15 23:27:38 +00:00
*/
2001-08-10 20:50:07 +00:00
static UHashtable * udata_getHashTable ( ) {
UErrorCode err = U_ZERO_ERROR ;
2001-09-07 18:42:29 +00:00
if ( gCommonDataCache ! = NULL ) {
return gCommonDataCache ;
2001-08-10 20:50:07 +00:00
}
2001-08-15 23:27:38 +00:00
umtx_lock ( NULL ) ;
2001-09-07 18:42:29 +00:00
if ( gCommonDataCache = = NULL ) {
gCommonDataCache = uhash_open ( uhash_hashChars , uhash_compareChars , & err ) ;
uhash_setValueDeleter ( gCommonDataCache , DataCacheElement_deleter ) ;
2001-08-10 20:50:07 +00:00
}
umtx_unlock ( NULL ) ;
2001-08-30 02:59:19 +00:00
if ( U_FAILURE ( err ) ) {
2001-08-15 22:39:42 +00:00
return NULL ; /* TODO: handle this error better. */
2001-08-10 20:50:07 +00:00
}
2001-09-07 18:42:29 +00:00
return gCommonDataCache ;
2001-08-10 20:50:07 +00:00
}
static UDataMemory * udata_findCachedData ( const char * path )
{
2001-08-15 22:39:42 +00:00
UHashtable * htable ;
UDataMemory * retVal = NULL ;
DataCacheElement * el ;
2001-08-29 22:57:37 +00:00
const char * baseName ;
2001-08-10 20:50:07 +00:00
2001-08-30 02:59:19 +00:00
baseName = findBasename ( path ) ; /* Cache remembers only the base name, not the full path. */
2001-08-10 20:50:07 +00:00
htable = udata_getHashTable ( ) ;
2001-08-15 23:27:38 +00:00
umtx_lock ( NULL ) ;
2001-08-29 22:57:37 +00:00
el = ( DataCacheElement * ) uhash_get ( htable , baseName ) ;
2001-08-10 20:50:07 +00:00
umtx_unlock ( NULL ) ;
2001-08-15 22:39:42 +00:00
if ( el ! = NULL ) {
2001-09-07 18:42:29 +00:00
retVal = el - > item ;
2001-08-15 22:39:42 +00:00
}
2002-07-17 03:01:45 +00:00
# ifdef UDATA_DEBUG
fprintf ( stderr , " Cache: [%s] -> %p \n " , baseName , retVal ) ;
# endif
2001-08-10 20:50:07 +00:00
return retVal ;
}
2001-08-15 22:39:42 +00:00
static UDataMemory * udata_cacheDataItem ( const char * path , UDataMemory * item , UErrorCode * pErr ) {
2001-08-10 20:50:07 +00:00
DataCacheElement * newElement ;
2001-08-29 22:57:37 +00:00
const char * baseName ;
2002-04-30 21:03:00 +00:00
int32_t nameLen ;
2001-08-15 22:39:42 +00:00
UHashtable * htable ;
UDataMemory * oldValue = NULL ;
if ( U_FAILURE ( * pErr ) ) {
return NULL ;
}
2001-08-10 20:50:07 +00:00
/* Create a new DataCacheElement - the thingy we store in the hash table -
* and copy the supplied path and UDataMemoryItems into it .
*/
newElement = uprv_malloc ( sizeof ( DataCacheElement ) ) ;
2001-08-15 22:39:42 +00:00
if ( newElement = = NULL ) {
* pErr = U_MEMORY_ALLOCATION_ERROR ;
return NULL ;
}
2001-09-07 18:42:29 +00:00
newElement - > item = UDataMemory_createNewInstance ( pErr ) ;
if ( U_FAILURE ( * pErr ) ) {
return NULL ;
}
UDatamemory_assign ( newElement - > item , item ) ;
2001-08-29 22:57:37 +00:00
baseName = findBasename ( path ) ;
2002-04-30 21:03:00 +00:00
nameLen = ( int32_t ) uprv_strlen ( baseName ) ;
2001-08-29 22:57:37 +00:00
newElement - > name = uprv_malloc ( nameLen + 1 ) ;
if ( newElement - > name = = NULL ) {
2001-08-15 22:39:42 +00:00
* pErr = U_MEMORY_ALLOCATION_ERROR ;
return NULL ;
}
2001-08-29 22:57:37 +00:00
uprv_strcpy ( newElement - > name , baseName ) ;
2001-08-10 20:50:07 +00:00
/* Stick the new DataCacheElement into the hash table.
*/
2001-08-15 22:39:42 +00:00
htable = udata_getHashTable ( ) ;
2001-08-15 23:27:38 +00:00
umtx_lock ( NULL ) ;
2001-08-15 22:39:42 +00:00
oldValue = uhash_get ( htable , path ) ;
if ( oldValue ! = NULL ) {
* pErr = U_USING_DEFAULT_WARNING ; }
else {
2001-08-15 23:27:38 +00:00
uhash_put (
2001-08-15 22:39:42 +00:00
htable ,
2001-08-29 22:57:37 +00:00
newElement - > name , /* Key */
2001-08-15 22:39:42 +00:00
newElement , /* Value */
pErr ) ;
}
2001-08-10 20:50:07 +00:00
umtx_unlock ( NULL ) ;
2001-08-15 22:39:42 +00:00
2002-07-17 03:01:45 +00:00
# ifdef UDATA_DEBUG
fprintf ( stderr , " Cache: [%s] <<< %p : %s \n " , newElement - > name ,
newElement - > item , u_errorName ( * pErr ) ) ;
# endif
2001-08-15 22:39:42 +00:00
if ( * pErr = = U_USING_DEFAULT_WARNING | | U_FAILURE ( * pErr ) ) {
2001-08-29 22:57:37 +00:00
uprv_free ( newElement - > name ) ;
2001-11-28 23:19:56 +00:00
uprv_free ( newElement - > item ) ;
2001-08-15 22:39:42 +00:00
uprv_free ( newElement ) ;
return oldValue ;
}
2001-08-10 20:50:07 +00:00
2001-09-07 18:42:29 +00:00
return newElement - > item ;
2001-08-10 20:50:07 +00:00
}
2001-09-07 18:42:29 +00:00
2002-07-17 03:01:45 +00:00
/*----------------------------------------------------------------------*==============
* *
* Path management . Could be shared with other tools / etc if need be *
* later on . *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
# define U_DATA_PATHITER_BUFSIZ 1024 /* paths can't be longer than this */
typedef struct
{
const char * path ; /* working path (u_icudata_Dir) */
const char * nextPath ; /* path following this one */
const char * basename ; /* item's basename (icudt22e_mt.res)*/
const char * suffix ; /* item suffix (can be null) */
uint32_t basenameLen ; /* length of basename */
char itemPath [ U_DATA_PATHITER_BUFSIZ ] ; /* path passed in with item name */
char pathBuffer [ U_DATA_PATHITER_BUFSIZ ] ; /* output path for this it'ion */
UBool checkLastFour ; /* if TRUE then allow paths such as '/foo/myapp.dat' to match, checks last 4 chars of suffix with last 4 of path, then previous chars. */
} UDataPathIterator ;
/**
* Initialize ( or re - initialize ) a user - supplied UDataPathIterator
* Note : UDataPathIterator does not allocate storage , so it doesn ' t need to be closed .
*
* @ param iter The iterator to be initialized . Its current state does not matter .
* @ param path The full pathname to be iterated over . If NULL , defaults to U_ICUDATA_NAME
* @ param item Item to be searched for . Can include full path , such as / a / b / foo . dat
* @ param suffix Optional item suffix , if not - null ( ex . " .dat " ) then ' path ' can contain ' item ' explicitly . Ex : ' stuff . dat ' would be found in ' / a / foo : / tmp / stuff . dat : / bar / baz ' as item # 2. ' / blarg / stuff . dat ' would also be found .
*/
static void udata_pathiter_init ( UDataPathIterator * iter , const char * path , const char * item , const char * suffix , UBool doCheckLastFour )
{
# ifdef UDATA_DEBUG
fprintf ( stderr , " SUFFIX1=%s [%p] \n " , suffix , suffix ) ;
# endif
/** Path **/
if ( path = = NULL ) {
iter - > path = u_getDataDirectory ( ) ;
} else {
iter - > path = path ;
}
/** Item **/
iter - > basename = findBasename ( item ) ;
iter - > basenameLen = uprv_strlen ( iter - > basename ) ;
if ( iter - > basename = = NULL ) {
iter - > nextPath = NULL ;
return ;
}
/** Item path **/
if ( iter - > basename = = item ) {
iter - > itemPath [ 0 ] = 0 ;
iter - > nextPath = iter - > path ;
} else {
uprv_strncpy ( iter - > itemPath , item , iter - > basename - item ) ;
iter - > itemPath [ iter - > basename - item ] = 0 ;
iter - > nextPath = iter - > itemPath ;
}
# ifdef UDATA_DEBUG
fprintf ( stderr , " SUFFIX=%s [%p] \n " , suffix , suffix ) ;
# endif
if ( suffix ! = NULL ) {
iter - > suffix = suffix ;
} else {
iter - > suffix = " " ;
}
iter - > checkLastFour = doCheckLastFour ;
# ifdef UDATA_DEBUG
fprintf ( stderr , " %p: init %s -> [path=%s], [base=%s], [suff=%s], [itempath=%s], [nextpath=%s], [checklast4=%s] \n " ,
iter ,
item ,
iter - > path ,
iter - > basename ,
iter - > suffix ,
iter - > itemPath ,
iter - > nextPath ,
iter - > checkLastFour ? " TRUE " : " false " ) ;
# endif
}
/**
* Get the next path on the list .
*
* @ param iter The Iter to be used
* @ param len If set , pointer to the length of the returned path , for convenience .
* @ return Pointer to the next path segment , or NULL if there are no more .
*/
static const char * udata_pathiter_next ( UDataPathIterator * iter , int32_t * outPathLen )
{
const char * path = NULL ;
int32_t pathLen = 0 ;
const char * pathBasename ;
if ( outPathLen ! = NULL ) {
* outPathLen = 0 ;
}
do
{
if ( iter - > nextPath = = NULL ) {
return NULL ;
}
path = iter - > nextPath ;
if ( iter - > nextPath = = iter - > itemPath ) { /* we were processing item's path. */
iter - > nextPath = iter - > path ; /* start with regular path next tm. */
pathLen = uprv_strlen ( path ) ;
} else {
/* fix up next for next time */
iter - > nextPath = uprv_strchr ( path , U_PATH_SEP_CHAR ) ;
if ( iter - > nextPath = = NULL ) {
/* segment: entire path */
pathLen = uprv_strlen ( path ) ;
} else {
/* segment: until next segment */
pathLen = iter - > nextPath - path ;
if ( * iter - > nextPath ) { /* skip divider */
iter - > nextPath + + ;
}
}
}
if ( pathLen = = 0 ) {
continue ;
}
# ifdef UDATA_DEBUG
fprintf ( stderr , " rest of path (IDD) = %s \n " , path ) ;
fprintf ( stderr , " " ) ;
{
int qqq ;
for ( qqq = 0 ; qqq < pathLen ; qqq + + )
{
fprintf ( stderr , " " ) ;
}
fprintf ( stderr , " ^ \n " ) ;
}
# endif
uprv_strncpy ( iter - > pathBuffer , path , pathLen ) ;
iter - > pathBuffer [ pathLen ] = 0 ;
/* check for .dat files */
pathBasename = findBasename ( iter - > pathBuffer ) ;
2003-04-18 00:15:33 +00:00
if ( iter - > checkLastFour = = TRUE & &
( pathLen > = 4 ) & &
2002-07-17 03:01:45 +00:00
uprv_strncmp ( iter - > pathBuffer + ( pathLen - 4 ) , iter - > suffix , 4 ) = = 0 & & /* suffix matches */
uprv_strncmp ( findBasename ( iter - > pathBuffer ) , iter - > basename , iter - > basenameLen ) = = 0 & & /* base matches */
uprv_strlen ( pathBasename ) = = ( iter - > basenameLen + 4 ) ) { /* base+suffix = full len */
# ifdef UDATA_DEBUG
fprintf ( stderr , " Have %s file on the path: %s \n " , iter - > suffix , iter - > pathBuffer ) ;
# endif
/* do nothing */
}
else
{ /* regular dir path */
if ( iter - > pathBuffer [ pathLen - 1 ] ! = U_FILE_SEP_CHAR ) /* trailing sep */
{
2003-04-18 00:15:33 +00:00
if ( ( pathLen > = 4 ) & &
uprv_strncmp ( iter - > pathBuffer + ( pathLen - 4 ) , " .dat " , 4 ) = = 0 )
{
# ifdef UDATA_DEBUG
fprintf ( stderr , " skipping non-directory .dat file %s \n " , iter - > pathBuffer ) ;
continue ;
# endif
}
2002-07-17 03:01:45 +00:00
iter - > pathBuffer [ pathLen + + ] = U_FILE_SEP_CHAR ;
2003-04-18 00:15:33 +00:00
}
2002-07-17 03:01:45 +00:00
uprv_strncpy ( iter - > pathBuffer + pathLen , /* + basename */
iter - > basename ,
iter - > basenameLen ) ;
pathLen + = iter - > basenameLen ;
if ( * iter - > suffix ) /* tack on suffix */
{
uprv_strcpy ( iter - > pathBuffer + pathLen ,
iter - > suffix ) ;
pathLen + = uprv_strlen ( iter - > suffix ) ;
}
}
/* return value of path size */
if ( outPathLen ) {
* outPathLen = pathLen ;
}
# ifdef UDATA_DEBUG
fprintf ( stderr , " --> %s \n " , iter - > pathBuffer ) ;
# endif
return iter - > pathBuffer ;
} while ( iter - > path ) ;
/* fell way off the end */
return NULL ;
}
/* ==================================================================================*/
2001-08-15 22:39:42 +00:00
/*----------------------------------------------------------------------*
* *
2001-09-07 18:42:29 +00:00
* Add a static reference to the common data library *
2002-12-20 16:41:57 +00:00
* Unless overridden by an explicit udata_setCommonData , this will be *
2001-09-07 18:42:29 +00:00
* our common data . *
2001-08-15 22:39:42 +00:00
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2001-08-06 22:53:11 +00:00
extern const DataHeader U_IMPORT U_ICUDATA_ENTRY_POINT ;
2001-07-26 21:55:49 +00:00
2001-08-10 20:50:07 +00:00
/*----------------------------------------------------------------------*
* *
* openCommonData Attempt to open a common format ( . dat ) file *
* Map it into memory ( if it ' s not there already ) *
* and return a UDataMemory object for it . *
2001-09-07 18:42:29 +00:00
* *
* If the requested data is already open and cached *
* just return the cached UDataMem object . *
2001-08-10 20:50:07 +00:00
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1999-11-22 19:43:01 +00:00
static UDataMemory *
2002-07-17 03:01:45 +00:00
openCommonData ( const char * path , /* Path from OpenCHoice? */
2001-08-10 20:50:07 +00:00
UBool isICUData , /* ICU Data true if path == NULL */
UErrorCode * pErrorCode )
2001-08-15 22:39:42 +00:00
{
2002-07-17 03:01:45 +00:00
UDataMemory tData ;
UDataPathIterator iter ;
const char * pathBuffer ;
int32_t pathLen ;
2000-05-03 23:11:04 +00:00
const char * inBasename ;
2001-08-10 20:50:07 +00:00
2001-08-15 22:39:42 +00:00
if ( U_FAILURE ( * pErrorCode ) ) {
return NULL ;
}
2001-08-15 23:27:38 +00:00
2001-08-10 20:50:07 +00:00
UDataMemory_init ( & tData ) ;
2001-08-15 23:27:38 +00:00
2002-07-17 03:01:45 +00:00
/* ??????? TODO revisit this */
2001-08-15 22:39:42 +00:00
if ( isICUData ) {
/* "mini-cache" for common ICU data */
2001-09-07 18:42:29 +00:00
if ( gCommonICUData ! = NULL ) {
return gCommonICUData ;
2001-08-15 22:39:42 +00:00
}
2001-08-15 23:27:38 +00:00
2001-08-15 22:39:42 +00:00
tData . pHeader = & U_ICUDATA_ENTRY_POINT ;
2001-10-05 21:46:52 +00:00
udata_checkCommonData ( & tData , pErrorCode ) ;
2001-08-30 18:41:30 +00:00
setCommonICUData ( & tData , NULL , FALSE , pErrorCode ) ;
2001-09-07 18:42:29 +00:00
return gCommonICUData ;
2000-05-03 23:11:04 +00:00
}
2001-08-15 23:27:38 +00:00
2001-10-18 16:36:48 +00:00
/* request is NOT for ICU Data. */
/* Find the base name portion of the supplied path. */
/* inBasename will be left pointing somewhere within the original path string. */
2002-07-17 03:01:45 +00:00
inBasename = findBasename ( path ) ;
# ifdef UDATA_DEBUG
fprintf ( stderr , " inBasename = %s \n " , inBasename ) ;
# endif
2001-10-18 16:36:48 +00:00
if ( * inBasename = = 0 ) {
/* no basename. This will happen if the original path was a directory name, */
/* like "a/b/c/". (Fallback to separate files will still work.) */
2002-07-17 03:01:45 +00:00
# ifdef UDATA_DEBUG
fprintf ( stderr , " ocd: no basename in %s, bailing. \n " , path ) ;
# endif
2001-10-18 16:36:48 +00:00
* pErrorCode = U_FILE_ACCESS_ERROR ;
return NULL ;
}
/* Is the requested common data file already open and cached? */
/* Note that the cache is keyed by the base name only. The rest of the path, */
/* if any, is not considered. */
{
2001-09-07 18:42:29 +00:00
UDataMemory * dataToReturn = udata_findCachedData ( inBasename ) ;
2001-08-10 20:50:07 +00:00
if ( dataToReturn ! = NULL ) {
return dataToReturn ;
}
}
2001-08-15 23:27:38 +00:00
2001-08-15 22:39:42 +00:00
/* Requested item is not in the cache.
2002-07-17 03:01:45 +00:00
* Hunt it down , trying all the path locations
2001-08-15 22:39:42 +00:00
*/
2001-08-15 23:27:38 +00:00
2002-07-17 03:01:45 +00:00
udata_pathiter_init ( & iter , u_getDataDirectory ( ) , path , " .dat " , TRUE ) ;
2001-10-18 16:36:48 +00:00
2002-07-17 03:01:45 +00:00
while ( ( UDataMemory_isLoaded ( & tData ) = = FALSE ) & &
( pathBuffer = udata_pathiter_next ( & iter , & pathLen ) ) ! = NULL )
{
# ifdef UDATA_DEBUG
fprintf ( stderr , " ocd: trying path %s - " , pathBuffer ) ;
# endif
uprv_mapFile ( & tData , pathBuffer ) ;
# ifdef UDATA_DEBUG
fprintf ( stderr , " %s \n " , UDataMemory_isLoaded ( & tData ) ? " LOADED " : " not loaded " ) ;
# endif
1999-11-22 19:43:01 +00:00
}
2001-08-15 23:27:38 +00:00
2002-08-09 18:17:39 +00:00
# if defined(OS390_STUBDATA) && defined(OS390BATCH)
if ( ! UDataMemory_isLoaded ( & tData ) ) {
char ourPathBuffer [ 1024 ] ;
/* One more chance, for extendCommonData() */
uprv_strncpy ( ourPathBuffer , path , 1019 ) ;
ourPathBuffer [ 1019 ] = 0 ;
uprv_strcat ( ourPathBuffer , " .dat " ) ;
uprv_mapFile ( & tData , ourPathBuffer ) ;
}
# endif
2001-09-07 18:42:29 +00:00
if ( ! UDataMemory_isLoaded ( & tData ) ) {
2001-08-15 22:39:42 +00:00
/* no common data */
* pErrorCode = U_FILE_ACCESS_ERROR ;
return NULL ;
}
2001-08-15 23:27:38 +00:00
2001-08-15 22:39:42 +00:00
/* we have mapped a file, check its header */
2001-10-05 21:46:52 +00:00
udata_checkCommonData ( & tData , pErrorCode ) ;
2001-08-15 23:27:38 +00:00
2001-08-15 22:39:42 +00:00
/* Cache the UDataMemory struct for this .dat file,
* so we won ' t need to hunt it down and map it again next time
* something is needed from it . */
2001-09-07 18:42:29 +00:00
return udata_cacheDataItem ( inBasename , & tData , pErrorCode ) ;
2001-08-15 22:39:42 +00:00
}
1999-11-22 19:43:01 +00:00
1999-12-01 01:02:06 +00:00
2001-11-02 23:42:10 +00:00
# ifdef OS390
2003-01-16 17:17:16 +00:00
# define MAX_STUB_ENTRIES 8
2001-11-02 23:42:10 +00:00
# else
# define MAX_STUB_ENTRIES 0
# endif
1999-12-01 01:02:06 +00:00
2001-08-17 00:00:55 +00:00
/*----------------------------------------------------------------------*
* *
* extendICUData If the full set of ICU data was not loaded at *
* program startup , load it now . This function will *
* be called when the lookup of an ICU data item in *
* the common ICU data fails . *
* *
2001-08-30 18:41:30 +00:00
* The parameter is the UDataMemory in which the *
* search for a requested item failed . *
* *
2001-08-17 00:00:55 +00:00
* return true if new data is loaded , false otherwise . *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2001-08-30 18:41:30 +00:00
static UBool extendICUData ( UDataMemory * failedData , UErrorCode * pErr )
2001-08-17 00:00:55 +00:00
{
2001-09-07 18:42:29 +00:00
/* If the data library that we are running with turns out to be the
* stub library ( or , on the 390 , the subset library ) , we will try to
2001-08-30 18:41:30 +00:00
* load a . dat file instead . The stub library has no entries in its
* TOC , which is how we identify it here .
*/
UDataMemory * pData ;
2001-10-08 17:41:04 +00:00
UDataMemory copyPData ;
2001-08-30 18:41:30 +00:00
2001-11-02 23:42:10 +00:00
if ( failedData - > vFuncs - > NumEntries ( failedData ) > MAX_STUB_ENTRIES ) {
2001-08-30 18:41:30 +00:00
/* Not the stub. We can't extend. */
return FALSE ;
}
/* See if we can explicitly open a .dat file for the ICUData. */
pData = openCommonData (
U_ICUDATA_NAME , /* "icudt20l" , for example. */
FALSE , /* Pretend we're not opening ICUData */
pErr ) ;
2001-10-06 04:54:29 +00:00
/* How about if there is no pData, eh... */
2001-10-08 17:41:04 +00:00
UDataMemory_init ( & copyPData ) ;
if ( pData ! = NULL ) {
UDatamemory_assign ( & copyPData , pData ) ;
copyPData . map = 0 ; /* The mapping for this data is owned by the hash table */
copyPData . mapAddr = 0 ; /* which will unmap it when ICU is shut down. */
2001-10-06 04:54:29 +00:00
/* CommonICUData is also unmapped when ICU is shut down.*/
/* To avoid unmapping the data twice, zero out the map */
/* fields in the UDataMemory that we're assigning */
/* to CommonICUData. */
2001-10-08 17:41:04 +00:00
setCommonICUData ( & copyPData , /* The new common data. */
failedData , /* Old ICUData ptr. Overwrite of this value is ok, */
FALSE , /* No warnings if write didn't happen */
pErr ) ; /* setCommonICUData honors errors; NOP if error set */
2001-10-06 04:54:29 +00:00
}
2001-10-05 21:46:52 +00:00
2001-09-07 18:42:29 +00:00
return gCommonICUData ! = failedData ; /* Return true if ICUData pointer was updated. */
2001-08-30 18:41:30 +00:00
/* (Could potentialy have been done by another thread racing */
/* us through here, but that's fine, we still return true */
/* so that current thread will also examine extended data. */
2001-08-17 00:00:55 +00:00
}
2001-09-07 18:42:29 +00:00
/*----------------------------------------------------------------------*
* *
* udata_setCommonData *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2000-05-03 23:11:04 +00:00
U_CAPI void U_EXPORT2
udata_setCommonData ( const void * data , UErrorCode * pErrorCode ) {
2001-08-15 22:39:42 +00:00
UDataMemory dataMemory ;
2000-05-03 23:11:04 +00:00
if ( pErrorCode = = NULL | | U_FAILURE ( * pErrorCode ) ) {
return ;
}
1999-12-01 01:02:06 +00:00
2000-05-03 23:11:04 +00:00
if ( data = = NULL ) {
* pErrorCode = U_ILLEGAL_ARGUMENT_ERROR ;
return ;
1999-11-22 19:43:01 +00:00
}
2000-05-03 23:11:04 +00:00
/* do we already have common ICU data set? */
2001-09-07 18:42:29 +00:00
if ( gCommonICUData ! = NULL ) {
2002-08-21 19:12:24 +00:00
* pErrorCode = U_USING_DEFAULT_WARNING ;
2000-05-03 23:11:04 +00:00
return ;
2001-08-15 22:39:42 +00:00
}
2001-08-15 23:27:38 +00:00
2001-09-07 18:42:29 +00:00
/* set the data pointer and test for validity */
2001-08-15 22:39:42 +00:00
UDataMemory_init ( & dataMemory ) ;
2001-09-07 18:42:29 +00:00
UDataMemory_setData ( & dataMemory , data ) ;
2001-10-05 21:46:52 +00:00
udata_checkCommonData ( & dataMemory , pErrorCode ) ;
2001-08-15 22:39:42 +00:00
if ( U_FAILURE ( * pErrorCode ) ) { return ; }
2001-08-15 23:27:38 +00:00
2001-08-30 18:41:30 +00:00
/* we have good data */
/* Set it up as the ICU Common Data. */
setCommonICUData ( & dataMemory , NULL , TRUE , pErrorCode ) ;
2000-05-03 23:11:04 +00:00
}
1999-11-22 19:43:01 +00:00
2001-08-10 20:50:07 +00:00
/*---------------------------------------------------------------------------
*
* udata_setAppData
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2001-08-15 23:27:38 +00:00
U_CAPI void U_EXPORT2
2001-08-10 20:50:07 +00:00
udata_setAppData ( const char * path , const void * data , UErrorCode * err )
{
2001-08-15 22:39:42 +00:00
UDataMemory udm ;
2001-08-15 23:27:38 +00:00
2001-08-15 22:39:42 +00:00
if ( err = = NULL | | U_FAILURE ( * err ) ) {
return ;
}
if ( data = = NULL ) {
* err = U_ILLEGAL_ARGUMENT_ERROR ;
return ;
}
2001-08-15 23:27:38 +00:00
2001-08-15 22:39:42 +00:00
UDataMemory_init ( & udm ) ;
udm . pHeader = data ;
2001-10-05 21:46:52 +00:00
udata_checkCommonData ( & udm , err ) ;
2001-08-15 22:39:42 +00:00
udata_cacheDataItem ( path , & udm , err ) ;
2001-08-17 00:18:49 +00:00
}
2001-08-10 20:50:07 +00:00
2001-08-17 00:18:49 +00:00
/*----------------------------------------------------------------------------*
* *
* checkDataItem Given a freshly located / loaded data item , either *
* an entry in a common file or a separately loaded file , *
* sanity check its header , and see if the data is *
* acceptable to the app . *
* If the data is good , create and return a UDataMemory *
* object that can be returned to the application . *
* Return NULL on any sort of failure . *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2001-08-15 22:39:42 +00:00
static UDataMemory *
2001-08-15 23:27:38 +00:00
checkDataItem
2001-08-15 22:39:42 +00:00
(
const DataHeader * pHeader , /* The data item to be checked. */
UDataMemoryIsAcceptable * isAcceptable , /* App's call-back function */
void * context , /* pass-thru param for above. */
const char * type , /* pass-thru param for above. */
const char * name , /* pass-thru param for above. */
UErrorCode * nonFatalErr , /* Error code if this data was not acceptable */
/* but openChoice should continue with */
/* trying to get data from fallback path. */
UErrorCode * fatalErr /* Bad error, caller should return immediately */
)
{
UDataMemory * rDataMem = NULL ; /* the new UDataMemory, to be returned. */
2001-08-15 23:27:38 +00:00
2001-08-15 22:39:42 +00:00
if ( U_FAILURE ( * fatalErr ) ) {
return NULL ;
}
if ( pHeader - > dataHeader . magic1 = = 0xda & &
pHeader - > dataHeader . magic2 = = 0x27 & &
pHeader - > info . isBigEndian = = U_IS_BIG_ENDIAN & &
( isAcceptable = = NULL | | isAcceptable ( context , type , name , & pHeader - > info ) )
) {
rDataMem = UDataMemory_createNewInstance ( fatalErr ) ;
if ( U_FAILURE ( * fatalErr ) ) {
return NULL ;
}
rDataMem - > pHeader = pHeader ;
} else {
/* the data is not acceptable, look further */
/* If we eventually find something good, this errorcode will be */
/* cleared out. */
* nonFatalErr = U_INVALID_FORMAT_ERROR ;
}
return rDataMem ;
}
2001-08-10 20:50:07 +00:00
1999-11-22 19:43:01 +00:00
2001-08-15 22:39:42 +00:00
/*
* A note on the ownership of Mapped Memory
*
* For common format files , ownership resides with the UDataMemory object
* that lives in the cache of opened common data . These UDataMemorys are private
* to the udata implementation , and are never seen directly by users .
*
* The UDataMemory objects returned to users will have the address of some desired
* data within the mapped region , but they wont have the mapping info itself , and thus
* won ' t cause anything to be removed from memory when they are closed .
*
* For individual data files , the UDataMemory returned to the user holds the
* information necessary to unmap the data on close . If the user independently
* opens the same data file twice , two completely independent mappings will be made .
2001-09-07 18:42:29 +00:00
* ( There is no cache of opened data items from individual files , only a cache of
* opened Common Data files , that is , files containing a collection of data items . )
2001-08-15 22:39:42 +00:00
*
* For common data passed in from the user via udata_setAppData ( ) or
* udata_setCommonData ( ) , ownership remains with the user .
*
* UDataMemory objects themselves , as opposed to the memory they describe ,
2001-08-15 23:27:38 +00:00
* can be anywhere - heap , stack / local or global .
2001-09-07 18:42:29 +00:00
* They have a flag to indicate when they ' re heap allocated and thus
2001-08-15 22:39:42 +00:00
* must be deleted when closed .
*/
2001-08-15 23:27:38 +00:00
2001-08-15 22:39:42 +00:00
2001-09-07 18:42:29 +00:00
/*----------------------------------------------------------------------------*
* *
* main data loading functions *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2000-05-03 23:11:04 +00:00
static UDataMemory *
doOpenChoice ( const char * path , const char * type , const char * name ,
UDataMemoryIsAcceptable * isAcceptable , void * context ,
2001-08-15 23:27:38 +00:00
UErrorCode * pErrorCode )
2001-08-15 22:39:42 +00:00
{
2002-07-17 03:01:45 +00:00
UDataPathIterator iter ;
const char * pathBuffer ;
int32_t pathLen ;
2001-08-15 22:39:42 +00:00
char tocEntryName [ 100 ] ;
2002-07-17 03:01:45 +00:00
char oldStylePath [ 1024 ] ;
char oldStylePathBasename [ 100 ] ;
const char * dataPath ;
const char * tocEntrySuffix ;
2001-08-15 22:39:42 +00:00
UDataMemory dataMemory ;
2001-08-15 23:27:38 +00:00
UDataMemory * pCommonData ;
2001-08-15 22:39:42 +00:00
UDataMemory * pEntryData ;
const DataHeader * pHeader ;
const char * inBasename ;
UErrorCode errorCode = U_ZERO_ERROR ;
UBool isICUData = ( UBool ) ( path = = NULL ) ;
2001-09-07 18:42:29 +00:00
/* Make up a full mame by appending the type to the supplied
* name , assuming that a type was supplied .
*/
2002-07-17 03:01:45 +00:00
/* prepend the package */
uprv_strcpy ( tocEntryName , packageNameFromPath ( path ) ) ;
tocEntrySuffix = tocEntryName + uprv_strlen ( tocEntryName ) ; /* suffix starts here */
uprv_strcat ( tocEntryName , " _ " ) ;
uprv_strcat ( tocEntryName , name ) ;
2001-09-07 18:42:29 +00:00
if ( type ! = NULL & & * type ! = 0 ) {
uprv_strcat ( tocEntryName , " . " ) ;
uprv_strcat ( tocEntryName , type ) ;
}
2000-12-05 02:28:32 +00:00
2002-07-17 03:01:45 +00:00
# ifdef UDATA_DEBUG
fprintf ( stderr , " tocEntryName = %s \n " , tocEntryName ) ;
# endif
2001-08-15 23:27:38 +00:00
2001-08-15 22:39:42 +00:00
2001-09-07 18:42:29 +00:00
/* the data was not found in the common data, look further, */
2000-05-03 23:11:04 +00:00
/* try to get an individual data file */
2002-07-17 03:01:45 +00:00
if ( path = = NULL ) {
path = COMMON_DATA_NAME ;
inBasename = COMMON_DATA_NAME ;
2000-05-03 23:11:04 +00:00
} else {
2002-07-17 03:01:45 +00:00
if ( isICUData ) {
inBasename = COMMON_DATA_NAME ;
} else {
inBasename = findBasename ( path ) ;
}
2000-05-03 23:11:04 +00:00
}
1999-11-22 19:43:01 +00:00
2002-07-17 03:01:45 +00:00
/************************ Begin loop looking for ind. files ***************/
2000-11-04 02:16:12 +00:00
# ifdef UDATA_DEBUG
2002-07-17 03:01:45 +00:00
fprintf ( stderr , " IND: inBasename = %s \n " , inBasename ) ;
2000-11-04 02:16:12 +00:00
# endif
2002-07-17 03:01:45 +00:00
/* Deal with a null basename */
if ( ( * inBasename = = 0 ) & & ( uprv_strlen ( path ) > 3 ) ) {
/* the purpose of this exercise is to turn /tmp/foo/bar/ into
path = / tmp / foo / bar / bar and basename = bar
( i . e . / tmp / foo / bar / bar . dat or / tmp / foo / bar / bar_en_US . res )
*/
char * rightSlash ;
uprv_strcpy ( oldStylePath , path ) ;
oldStylePath [ uprv_strlen ( path ) - 1 ] = 0 ; /* chop off trailing slash */
rightSlash = ( char * ) uprv_strrchr ( oldStylePath , U_FILE_SEP_CHAR ) ;
if ( rightSlash ! = NULL ) {
rightSlash + + ;
inBasename = uprv_strcpy ( oldStylePathBasename , rightSlash ) ;
uprv_strcat ( oldStylePath , U_FILE_SEP_STRING ) ;
uprv_strcat ( oldStylePath , inBasename ) ; /* one more time, for the base name */
path = oldStylePath ;
} else {
* pErrorCode = U_FILE_ACCESS_ERROR ; /* hopelessly bad case */
return NULL ;
}
}
/* End of dealing with a null basename */
dataPath = u_getDataDirectory ( ) ;
2000-05-03 23:11:04 +00:00
2002-07-17 03:01:45 +00:00
/* #1 look in ind. files ================================== */
/* init path iterator for individual files */
2002-08-09 21:18:31 +00:00
udata_pathiter_init ( & iter , dataPath , path , tocEntrySuffix , FALSE ) ;
2002-07-17 03:01:45 +00:00
while ( ( pathBuffer = udata_pathiter_next ( & iter , & pathLen ) ) )
{
# ifdef UDATA_DEBUG
fprintf ( stderr , " UDATA: trying individual file %s \n " , pathBuffer ) ;
# endif
2001-08-10 20:50:07 +00:00
if ( uprv_mapFile ( & dataMemory , pathBuffer ) | |
2002-07-17 03:01:45 +00:00
( inBasename ! = pathBuffer & & uprv_mapFile ( & dataMemory , inBasename ) ) )
2001-08-15 22:39:42 +00:00
{
pEntryData = checkDataItem ( dataMemory . pHeader , isAcceptable , context , type , name , & errorCode , pErrorCode ) ;
2002-07-17 03:01:45 +00:00
if ( pEntryData ! = NULL ) {
/* Data is good.
* Hand off ownership of the backing memory to the user ' s UDataMemory .
* and return it . */
2001-08-15 23:27:38 +00:00
pEntryData - > mapAddr = dataMemory . mapAddr ;
2001-08-15 22:39:42 +00:00
pEntryData - > map = dataMemory . map ;
2002-07-17 03:01:45 +00:00
# ifdef UDATA_DEBUG
fprintf ( stderr , " ** Mapped file: %s \n " , pathBuffer ) ;
# endif
2000-05-03 23:11:04 +00:00
return pEntryData ;
1999-11-22 19:43:01 +00:00
}
2002-07-17 03:01:45 +00:00
2001-08-15 22:39:42 +00:00
/* the data is not acceptable, or some error occured. Either way, unmap the memory */
2001-09-07 18:42:29 +00:00
udata_close ( & dataMemory ) ;
2002-07-17 03:01:45 +00:00
2001-08-15 22:39:42 +00:00
/* If we had a nasty error, bail out completely. */
if ( U_FAILURE ( * pErrorCode ) ) {
return NULL ;
}
2002-07-17 03:01:45 +00:00
/* Otherwise remember that we found data but didn't like it for some reason */
2001-08-15 22:39:42 +00:00
errorCode = U_INVALID_FORMAT_ERROR ;
1999-11-22 19:43:01 +00:00
}
2002-07-17 03:01:45 +00:00
# ifdef UDATA_DEBUG
fprintf ( stderr , " %s \n " , UDataMemory_isLoaded ( & dataMemory ) ? " LOADED " : " not loaded " ) ;
# endif
1999-11-22 19:43:01 +00:00
}
2002-07-17 03:01:45 +00:00
/* #2 */
2001-08-15 23:27:38 +00:00
2002-07-17 03:01:45 +00:00
/* try to get common data. The loop is for platforms such as the 390 that do
* not initially load the full set of ICU data . If the lookup of an ICU data item
* fails , the full ( but slower to load ) set is loaded , the and the loop repeats ,
* trying the lookup again . Once the full set of ICU data is loaded , the loop wont
* repeat because the full set will be checked the first time through .
*
* The loop also handles the fallback to a . dat file if the application linked
* to the stub data library rather than a real library .
*/
for ( ; ; ) {
pCommonData = openCommonData ( path , isICUData , & errorCode ) ; /** search for pkg **/
2001-08-15 23:27:38 +00:00
2002-07-17 03:01:45 +00:00
if ( U_SUCCESS ( errorCode ) ) {
/* look up the data piece in the common data */
pHeader = pCommonData - > vFuncs - > Lookup ( pCommonData , tocEntryName , & errorCode ) ;
# ifdef UDATA_DEBUG
fprintf ( stderr , " pHeader=%p \n " , pHeader ) ;
# endif
if ( pHeader ! = NULL ) {
pEntryData = checkDataItem ( pHeader , isAcceptable , context , type , name , & errorCode , pErrorCode ) ;
# ifdef UDATA_DEBUG
fprintf ( stderr , " pEntryData=%p \n " , pEntryData ) ;
# endif
if ( U_FAILURE ( * pErrorCode ) ) {
return NULL ;
}
if ( pEntryData ! = NULL ) {
return pEntryData ;
}
}
2001-08-15 22:39:42 +00:00
}
2002-07-17 03:01:45 +00:00
/* Data wasn't found. If we were looking for an ICUData item and there is
* more data available , load it and try again ,
* otherwise break out of this loop . */
if ( ! ( isICUData & & pCommonData & & extendICUData ( pCommonData , & errorCode ) ) ) {
break ;
}
2002-11-30 04:41:53 +00:00
}
1999-11-22 19:43:01 +00:00
/* data not found */
if ( U_SUCCESS ( * pErrorCode ) ) {
1999-11-22 19:53:19 +00:00
if ( U_SUCCESS ( errorCode ) ) {
/* file not found */
* pErrorCode = U_FILE_ACCESS_ERROR ;
} else {
/* entry point not found or rejected */
* pErrorCode = errorCode ;
}
1999-11-22 19:43:01 +00:00
}
return NULL ;
}
2001-08-15 22:39:42 +00:00
2000-05-03 23:11:04 +00:00
/* API ---------------------------------------------------------------------- */
U_CAPI UDataMemory * U_EXPORT2
udata_open ( const char * path , const char * type , const char * name ,
UErrorCode * pErrorCode ) {
2000-05-30 21:47:19 +00:00
# ifdef UDATA_DEBUG
2000-12-05 02:28:32 +00:00
fprintf ( stderr , " udata_open(): Opening: %s . %s \n " , name , type ) ;
fflush ( stderr ) ;
2000-05-30 21:47:19 +00:00
# endif
2000-05-03 23:11:04 +00:00
if ( pErrorCode = = NULL | | U_FAILURE ( * pErrorCode ) ) {
return NULL ;
} else if ( name = = NULL | | * name = = 0 ) {
* pErrorCode = U_ILLEGAL_ARGUMENT_ERROR ;
return NULL ;
} else {
return doOpenChoice ( path , type , name , NULL , NULL , pErrorCode ) ;
}
}
2001-09-07 18:42:29 +00:00
2000-05-03 23:11:04 +00:00
U_CAPI UDataMemory * U_EXPORT2
udata_openChoice ( const char * path , const char * type , const char * name ,
UDataMemoryIsAcceptable * isAcceptable , void * context ,
UErrorCode * pErrorCode ) {
2000-11-04 02:16:12 +00:00
# ifdef UDATA_DEBUG
fprintf ( stderr , " udata_openChoice(): Opening: %s . %s \n " , name , type ) ; fflush ( stderr ) ;
# endif
2000-05-03 23:11:04 +00:00
if ( pErrorCode = = NULL | | U_FAILURE ( * pErrorCode ) ) {
return NULL ;
} else if ( name = = NULL | | * name = = 0 | | isAcceptable = = NULL ) {
* pErrorCode = U_ILLEGAL_ARGUMENT_ERROR ;
1999-11-22 19:43:01 +00:00
return NULL ;
2000-05-03 23:11:04 +00:00
} else {
return doOpenChoice ( path , type , name , isAcceptable , context , pErrorCode ) ;
1999-11-22 19:43:01 +00:00
}
2000-05-03 23:11:04 +00:00
}
1999-11-22 19:43:01 +00:00
2000-05-03 23:11:04 +00:00
U_CAPI void U_EXPORT2
udata_getInfo ( UDataMemory * pData , UDataInfo * pInfo ) {
if ( pInfo ! = NULL ) {
if ( pData ! = NULL & & pData - > pHeader ! = NULL ) {
const UDataInfo * info = & pData - > pHeader - > info ;
2001-05-25 21:50:10 +00:00
if ( pInfo - > size > info - > size ) {
2000-05-03 23:11:04 +00:00
pInfo - > size = info - > size ;
}
2001-05-25 21:50:10 +00:00
uprv_memcpy ( ( uint16_t * ) pInfo + 1 , ( uint16_t * ) info + 1 , pInfo - > size - 2 ) ;
2000-05-03 23:11:04 +00:00
} else {
pInfo - > size = 0 ;
}
}
1999-11-22 19:43:01 +00:00
}