From 412f48860eab32e92f953661381913c0edde0d84 Mon Sep 17 00:00:00 2001 From: Andy Heninger Date: Fri, 7 Sep 2001 18:42:29 +0000 Subject: [PATCH] ICU-1075 udata.c restructured, split into separate files, hopefully making code clearer, dependencies clearer. Functionality pretty much unchanged. X-SVN-Rev: 5716 --- icu4c/source/common/common.dsp | 25 + icu4c/source/common/ucmndata.c | 223 ++++++++ icu4c/source/common/ucmndata.h | 81 +++ icu4c/source/common/udata.c | 902 +++++---------------------------- icu4c/source/common/udatamem.c | 99 ++++ icu4c/source/common/udatamem.h | 47 ++ icu4c/source/common/umapfile.c | 379 ++++++++++++++ icu4c/source/common/umapfile.h | 32 ++ 8 files changed, 1002 insertions(+), 786 deletions(-) create mode 100644 icu4c/source/common/ucmndata.c create mode 100644 icu4c/source/common/ucmndata.h create mode 100644 icu4c/source/common/udatamem.c create mode 100644 icu4c/source/common/udatamem.h create mode 100644 icu4c/source/common/umapfile.c create mode 100644 icu4c/source/common/umapfile.h diff --git a/icu4c/source/common/common.dsp b/icu4c/source/common/common.dsp index 2a806da9241..3379a10a1a8 100644 --- a/icu4c/source/common/common.dsp +++ b/icu4c/source/common/common.dsp @@ -181,6 +181,10 @@ SOURCE=.\ucln_cmn.c # End Source File # Begin Source File +SOURCE=.\ucmndata.c +# End Source File +# Begin Source File + SOURCE=.\ucmp16.c # End Source File # Begin Source File @@ -258,6 +262,10 @@ SOURCE=.\udata.c # End Source File # Begin Source File +SOURCE=.\udatamem.c +# End Source File +# Begin Source File + SOURCE=.\uhash.c # End Source File # Begin Source File @@ -270,6 +278,11 @@ SOURCE=.\uloc.c # End Source File # Begin Source File +SOURCE=.\umapfile.c +# ADD CPP /Ze +# End Source File +# Begin Source File + SOURCE=.\umemstrm.c # End Source File # Begin Source File @@ -784,6 +797,10 @@ SOURCE=.\ucln_cmn.h # End Source File # Begin Source File +SOURCE=.\ucmndata.h +# End Source File +# Begin Source File + SOURCE=.\ucmp16.h # End Source File # Begin Source File @@ -928,6 +945,10 @@ InputPath=.\unicode\udata.h # End Source File # Begin Source File +SOURCE=.\udatamem.h +# End Source File +# Begin Source File + SOURCE=.\uhash.h # End Source File # Begin Source File @@ -986,6 +1007,10 @@ InputPath=.\unicode\umachine.h # End Source File # Begin Source File +SOURCE=.\umapfile.h +# End Source File +# Begin Source File + SOURCE=.\umemstrm.h # End Source File # Begin Source File diff --git a/icu4c/source/common/ucmndata.c b/icu4c/source/common/ucmndata.c new file mode 100644 index 00000000000..62f90ff63a1 --- /dev/null +++ b/icu4c/source/common/ucmndata.c @@ -0,0 +1,223 @@ +/* +****************************************************************************** +* +* Copyright (C) 1999-2001, International Business Machines +* Corporation and others. All Rights Reserved. +* +****************************************************************************** + + +/*---------------------------------------------------------------------------------- + * + * UCommonData An abstract interface for dealing with ICU Common Data Files. + * ICU Common Data Files are a grouping of a number of individual + * data items (resources, converters, tables, anything) into a + * single file or dll. The combined format includes a table of + * contents for locating the individual items by name. + * + * Two formats for the table of contents are supported, which is + * why there is an abstract inteface involved. + * + */ + +#include "unicode/utypes.h" +#include "unicode/udata.h" +#include "cstring.h" +#include "ucmndata.h" +#include "udatamem.h" + + +/*----------------------------------------------------------------------------------* + * * + * Pointer TOCs. TODO: This form of table-of-contents should be removed because * + * DLLs must be relocated on loading to correct the pointer values * + * and this operation makes shared memory mapping of the data * + * much less likely to work. * + * * + *----------------------------------------------------------------------------------*/ +typedef struct { + const char *entryName; + const DataHeader *pHeader; +} PointerTOCEntry; + + +/*----------------------------------------------------------------------------------* + * * + * entry point lookup implementations * + * * + *----------------------------------------------------------------------------------*/ +static uint32_t offsetTOCEntryCount(const UDataMemory *pData) { + uint32_t count = *(const uint32_t *)pData->toc; + return count; +} + + +static const DataHeader * +offsetTOCLookupFn(const UDataMemory *pData, + const char *tocEntryName, + UErrorCode *pErrorCode) { + + if(pData->toc!=NULL) { + const char *base=(const char *)pData->toc; + uint32_t *toc=(uint32_t *)pData->toc; + uint32_t start, limit, number; + + /* perform a binary search for the data in the common data's table of contents */ + start=0; + limit=*toc++; /* number of names in this table of contents */ + if (limit == 0) { /* Stub common data library used during build is empty. */ + return NULL; + } + while(startpHeader; + } +} + + +static uint32_t pointerTOCEntryCount(const UDataMemory *pData) { + uint32_t count = *(const uint32_t *)pData->toc; + return count; +} + + +static const DataHeader *pointerTOCLookupFn(const UDataMemory *pData, + const char *tocEntryName, + UErrorCode *pErrorCode) { +#ifdef UDATA_DEBUG + fprintf(stderr, "ptrTOC[%p] looking for %s/%s\n", + pData, + tocEntryName,dllEntryName); +#endif + if(pData->toc!=NULL) { + const PointerTOCEntry *toc=(const PointerTOCEntry *)((const uint32_t *)pData->toc+2); + uint32_t start, limit, number; + + /* perform a binary search for the data in the common data's table of contents */ + start=0; + limit=*(const uint32_t *)pData->toc; /* number of names in this table of contents */ + +#ifdef UDATA_DEBUG + fprintf(stderr, " # of ents: %d\n", limit); + fflush(stderr); +#endif + + if (limit == 0) { /* Stub common data library used during build is empty. */ + return NULL; + } + + while(startpHeader; + } +} + +static commonDataFuncs CmnDFuncs = {offsetTOCLookupFn, offsetTOCEntryCount}; +static commonDataFuncs ToCPFuncs = {pointerTOCLookupFn, pointerTOCEntryCount}; + + + +/*----------------------------------------------------------------------* + * * + * checkCommonData Validate the format of a common data file. * + * Fill in the virtual function ptr based on TOC type * + * If the data is invalid, close the UDataMemory * + * and set the appropriate error code. * + * * + *----------------------------------------------------------------------*/ +void checkCommonData(UDataMemory *udm, UErrorCode *err) { + if (U_FAILURE(*err)) { + return; + } + + if(!(udm->pHeader->dataHeader.magic1==0xda && + udm->pHeader->dataHeader.magic2==0x27 && + udm->pHeader->info.isBigEndian==U_IS_BIG_ENDIAN && + udm->pHeader->info.charsetFamily==U_CHARSET_FAMILY) + ) { + /* header not valid */ + *err=U_INVALID_FORMAT_ERROR; + } + else if (udm->pHeader->info.dataFormat[0]==0x43 && + udm->pHeader->info.dataFormat[1]==0x6d && + udm->pHeader->info.dataFormat[2]==0x6e && + udm->pHeader->info.dataFormat[3]==0x44 && + udm->pHeader->info.formatVersion[0]==1 + ) { + /* dataFormat="CmnD" */ + udm->vFuncs = &CmnDFuncs; + udm->toc=(const char *)udm->pHeader+udm->pHeader->dataHeader.headerSize; + } + else if(udm->pHeader->info.dataFormat[0]==0x54 && + udm->pHeader->info.dataFormat[1]==0x6f && + udm->pHeader->info.dataFormat[2]==0x43 && + udm->pHeader->info.dataFormat[3]==0x50 && + udm->pHeader->info.formatVersion[0]==1 + ) { + /* dataFormat="ToCP" */ + udm->vFuncs = &ToCPFuncs; + udm->toc=(const char *)udm->pHeader+udm->pHeader->dataHeader.headerSize; + } + else { + /* dataFormat not recognized */ + *err=U_INVALID_FORMAT_ERROR; + } + + if (U_FAILURE(*err)) { + /* If the data is no good and we memory-mapped it ourselves, + * close the memory mapping so it doesn't leak. Note that this has + * no effect on non-memory mapped data, other than clearing fields in udm. + */ + udata_close(udm); + } +} + diff --git a/icu4c/source/common/ucmndata.h b/icu4c/source/common/ucmndata.h new file mode 100644 index 00000000000..389cbcabcbc --- /dev/null +++ b/icu4c/source/common/ucmndata.h @@ -0,0 +1,81 @@ +/* +****************************************************************************** +* +* Copyright (C) 1999-2001, International Business Machines +* Corporation and others. All Rights Reserved. +* +****************************************************************************** + + +/*---------------------------------------------------------------------------------- + * + * UCommonData An abstract interface for dealing with ICU Common Data Files. + * ICU Common Data Files are a grouping of a number of individual + * data items (resources, converters, tables, anything) into a + * single file or dll. The combined format includes a table of + * contents for locating the individual items by name. + * + * Two formats for the table of contents are supported, which is + * why there is an abstract inteface involved. + * + * These functions are part of the ICU internal implementation, and + * are not inteded to be used directly by applications. + */ + +#ifndef __UCMNDATA_H__ +#define __UCMNDATA_H__ + +#include "unicode/udata.h" +#include "umapfile.h" + + +#define COMMON_DATA_NAME U_ICUDATA_NAME + +typedef struct { + uint16_t headerSize; + uint8_t magic1; + uint8_t magic2; +} MappedData; + + +typedef struct { + MappedData dataHeader; + UDataInfo info; +} DataHeader; + + +/* + * "Virtual" functions for data lookup. + * To call one, given a UDataMemory *p, the code looks like this: + * p->vFuncs.Lookup(p, tocEntryName, pErrorCode); + * (I sure do wish this was written in C++, not C) + */ + +typedef const DataHeader * +(* LookupFn)(const UDataMemory *pData, + const char *tocEntryName, + UErrorCode *pErrorCode); + +typedef uint32_t +(* NumEntriesFn)(const UDataMemory *pData); + +typedef struct { + LookupFn Lookup; + NumEntriesFn NumEntries; +} commonDataFuncs; + + +/* + * Functions to check whether a UDataMemory refers to memory containing + * a recognizable header and table of contents a Common Data Format + * + * If a valid header and TOC are found, + * set the CommonDataFuncs function dispatch vector in the UDataMemory + * to point to the right functions for the TOC type. + * otherwise + * set an errorcode. + */ +void checkCommonData(UDataMemory *pData, UErrorCode *pErrorCode); + + +#endif diff --git a/icu4c/source/common/udata.c b/icu4c/source/common/udata.c index 36f5ab4cd42..0fc54f9ca95 100644 --- a/icu4c/source/common/udata.c +++ b/icu4c/source/common/udata.c @@ -24,25 +24,35 @@ #include "uhash.h" #include "ucln_cmn.h" -#ifdef OS390 -#include -#endif +#include "udatamem.h" +#include "umapfile.h" +#include "ucmndata.h" + +/*********************************************************************** +* +* 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. /* configuration ---------------------------------------------------------- */ - -#define COMMON_DATA_NAME U_ICUDATA_NAME -#define COMMON_DATA_NAME_LENGTH 8 -/* Tests must verify that it remains 8 characters. */ - -#ifdef OS390 -#define COMMON_DATA1_NAME U_ICUDATA_NAME"_390" -#define COMMON_DATA1_NAME_LENGTH (COMMON_DATA_NAME_LENGTH + 4) -static UBool s390dll = TRUE; -#endif - -#define DATA_TYPE "dat" - /* If you are excruciatingly bored turn this on .. */ /* #define UDATA_DEBUG 1 */ @@ -50,513 +60,35 @@ static UBool s390dll = TRUE; # include #endif -/* DLL/shared library base functions ---------------------------------------- */ -/* TODO: Dynamic loading of DLLs is no longer supported. */ -/* 390 is a special case, since it can not support file loading. */ -/* Need to abstract 390 library loading so that it appears to the rest */ -/* ICU as file loading. */ - - -#ifdef OS390 -# include - -# define RTLD_LAZY 0 -# define RTLD_GLOBAL 0 - - void *dlopen(const char *filename, int flag) { - dllhandle *handle; - -# ifdef UDATA_DEBUG - fprintf(stderr, "dllload: %s ", filename); -# endif - handle=dllload(filename); -# ifdef UDATA_DEBUG - fprintf(stderr, " -> %08X\n", handle ); -# endif - return handle; - } - - void *dlsym(void *h, const char *symbol) { - void *val=0; - val=dllqueryvar((dllhandle*)h,symbol); -# ifdef UDATA_DEBUG - fprintf(stderr, "dllqueryvar(%08X, %s) -> %08X\n", h, symbol, val); -# endif - return val; - } - - int dlclose(void *handle) { -# ifdef UDATA_DEBUG - fprintf(stderr, "dllfree: %08X\n", handle); -# endif - return dllfree((dllhandle*)handle); - } -#endif /* OS390: */ - -/* memory-mapping base definitions ------------------------------------------ */ - -/* we need these definitions before the common ones because - MemoryMap is a field of UDataMemory; - however, the mapping functions use UDataMemory, - therefore they are defined later - */ - -#define MAP_WIN32 1 -#define MAP_POSIX 2 -#define MAP_FILE_STREAM 3 - -#ifdef WIN32 -# define WIN32_LEAN_AND_MEAN -# define NOGDI -# define NOUSER -# define NOSERVICE -# define NOIME -# define NOMCX -# include - - typedef HANDLE MemoryMap; - -# define IS_MAP(map) ((map)!=NULL) - -# define MAP_IMPLEMENTATION MAP_WIN32 - -/* ### Todo: auto detect mmap(). Until then, just add your platform here. */ -#elif HAVE_MMAP || defined(U_LINUX) || defined(POSIX) || defined(U_SOLARIS) || defined(AIX) || defined(HPUX) || defined(OS390) || defined(PTX) - typedef size_t MemoryMap; - -# define IS_MAP(map) ((map)!=0) - -# include -# include -# include -# include - -# ifndef MAP_FAILED -# define MAP_FAILED ((void*)-1) -# endif - -# define MAP_IMPLEMENTATION MAP_POSIX - -#else /* unknown platform, no memory map implementation: use FileStream/uprv_malloc() instead */ - -# include "filestrm.h" - - typedef void *MemoryMap; - -# define IS_MAP(map) ((map)!=NULL) - -# define MAP_IMPLEMENTATION MAP_FILE_STREAM - -#endif - -/* common definitions ------------------------------------------------------- */ +/*********************************************************************** +* +* static (Global) data +* +************************************************************************/ +static UDataMemory *gCommonICUData = NULL; +static UHashtable *gCommonDataCache = NULL; -typedef struct { - uint16_t headerSize; - uint8_t magic1; - uint8_t magic2; -} MappedData; +UBool +udata_cleanup() +{ + if (gCommonDataCache) { /* Delete the cache of user data mappings. */ + uhash_close(gCommonDataCache); /* Table owns the contents, and will delete them. */ + gCommonDataCache = 0; /* Cleanup is not thread safe. */ + } -typedef struct { - MappedData dataHeader; - UDataInfo info; -} DataHeader; + udata_close(gCommonICUData); /* Clean up common ICU Data */ + gCommonICUData = NULL; -typedef const DataHeader * -LookupFn(const UDataMemory *pData, - const char *tocEntryName, - const char *dllEntryName, - UErrorCode *pErrorCode); - -/*----------------------------------------------------------------------------------* - * * - * UDataMemory Very Important Struct. Pointers to these are returned * - * to callers from the various data open functions. * - * These keep track of everything about the memeory * - * * - *----------------------------------------------------------------------------------*/ -struct UDataMemory { - MemoryMap map; /* Handle, or whatever. OS dependent. */ - /* Only set if a close operation should unmap the */ - /* associated data. */ - LookupFn *lookupFn; - const void *toc; /* For common memory, to find pieces within. */ - const DataHeader *pHeader; /* Header. For common data, header is at top of file */ - const void *mapAddr; /* For mapped or allocated memory, the start addr. */ - /* Will be above pHeader in some cases. */ - /* Needed to allow unmapping. */ - uint32_t flags; /* Memory format, TOC type, Allocation type, etc. */ -}; - -/* constants for UDataMemory flags */ -#define MALLOCED_UDATAMEMORY_FLAG 0x80000000 /* Set flag if UDataMemory object itself - * is on heap, and must be freed when - * it is closed. - */ - -#define TOC_HAS_CONTENTS_FLAG 0x40000000 /* Flag set if UDataMemory is for a - * something with a non-empty TOC. - * An empty TOC means this is the stub - * library. - */ - -#define IS_DATA_MEMORY_LOADED(pData) ((pData)->pHeader!=NULL) - - -static void UDataMemory_init(UDataMemory *This) { - uprv_memset(This, 0, sizeof(UDataMemory)); + return TRUE; /* Everything was cleaned up */ } -static void UDatamemory_assign(UDataMemory *dest, UDataMemory *source) { - /* UDataMemory Assignment. Destination UDataMemory must be initialized first. - * Malloced flag of the destination is preserved, - * since it indicates where the UDataMemory struct itself - * is allocated. */ - uint32_t dest_MALLOCED_UDATAMEMORY_FLAG = dest->flags & MALLOCED_UDATAMEMORY_FLAG; - uprv_memcpy(dest, source, sizeof(UDataMemory)); - dest->flags &= ~MALLOCED_UDATAMEMORY_FLAG; - dest->flags |= dest_MALLOCED_UDATAMEMORY_FLAG; -} -static UDataMemory *UDataMemory_createNewInstance(UErrorCode *pErr) { - UDataMemory *This; - - if (U_FAILURE(*pErr)) { - return NULL; - } - This = uprv_malloc(sizeof(UDataMemory)); - if (This == NULL) { - *pErr = U_MEMORY_ALLOCATION_ERROR; } - else { - UDataMemory_init(This); - This->flags |= MALLOCED_UDATAMEMORY_FLAG; - } - return This; -} - -/*----------------------------------------------------------------------------------* - * * - * Pointer TOCs. This form of table-of-contents should be removed because * - * DLLs must be relocated on loading to correct the pointer values * - * and this operation makes shared memory mapping of the data * - * much less likely to work. * - * * - *----------------------------------------------------------------------------------*/ -typedef struct { - const char *entryName; - const DataHeader *pHeader; -} PointerTOCEntry; - - -/*----------------------------------------------------------------------------------* - * * - * Memory Mapped File support. Platform dependent implementation of functions * - * used by the rest of the implementation. * - * * - *----------------------------------------------------------------------------------*/ -#if MAP_IMPLEMENTATION==MAP_WIN32 - static UBool - uprv_mapFile( - UDataMemory *pData, /* Fill in with info on the result doing the mapping. */ - /* Output only; any original contents are cleared. */ - const char *path /* File path to be opened/mapped */ - ) - { - HANDLE map; - HANDLE file; - - UDataMemory_init(pData); /* Clear the output struct. */ - - /* open the input file */ - file=CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL); - if(file==INVALID_HANDLE_VALUE) { - return FALSE; - } - - /* create an unnamed Windows file-mapping object for the specified file */ - map=CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL); - CloseHandle(file); - if(map==NULL) { - return FALSE; - } - - /* map a view of the file into our address space */ - pData->pHeader=(const DataHeader *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0); - if(pData->pHeader==NULL) { - CloseHandle(map); - return FALSE; - } - pData->map=map; - return TRUE; - } - - - static void - uprv_unmapFile(UDataMemory *pData) { - if(pData!=NULL && pData->map!=NULL) { - UnmapViewOfFile(pData->pHeader); - CloseHandle(pData->map); - pData->pHeader=NULL; - pData->map=NULL; - } - } - -#elif MAP_IMPLEMENTATION==MAP_POSIX - static UBool - uprv_mapFile(UDataMemory *pData, const char *path) { - int fd; - int length; - struct stat mystat; - const void *data; - - UDataMemory_init(pData); /* Clear the output struct. */ - - /* determine the length of the file */ - if(stat(path, &mystat)!=0 || mystat.st_size<=0) { - return FALSE; - } - length=mystat.st_size; - - /* open the file */ - fd=open(path, O_RDONLY); - if(fd==-1) { - return FALSE; - } - - /* get a view of the mapping */ -#ifndef HPUX - data=mmap(0, length, PROT_READ, MAP_SHARED, fd, 0); -#else - data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0); -#endif - close(fd); /* no longer needed */ - if(data==MAP_FAILED) { - -# ifdef UDATA_DEBUG - perror("mmap"); -# endif - - return FALSE; - } - -# ifdef UDATA_DEBUG - fprintf(stderr, "mmap of %s [%d bytes] succeeded, -> 0x%X\n", path, length, data); - fflush(stderr); -# endif - - pData->map=length; - pData->pHeader=(const DataHeader *)data; - pData->mapAddr = data; - return TRUE; - } - - static void - uprv_unmapFile(UDataMemory *pData) { - if(pData!=NULL && pData->map>0) { - if(munmap((void *)pData->mapAddr, pData->map)==-1) { -# ifdef UDATA_DEBUG - perror("munmap"); -# endif - } - pData->pHeader=NULL; - pData->map=0; - pData->mapAddr=NULL; - } - } - -#elif MAP_IMPLEMENTATION==MAP_FILE_STREAM - static UBool - uprv_mapFile(UDataMemory *pData, const char *path) { - FileStream *file; - int32_t fileLength; - void *p; - - UDataMemory_init(pData); /* Clear the output struct. */ - /* open the input file */ - file=T_FileStream_open(path, "rb"); - if(file==NULL) { - return FALSE; - } - - /* get the file length */ - fileLength=T_FileStream_size(file); - if(T_FileStream_error(file) || fileLength<=20) { - T_FileStream_close(file); - return FALSE; - } - - /* allocate the data structure */ - p=uprv_malloc(fileLength); - if(p==NULL) { - T_FileStream_close(file); - return FALSE; - } - - /* read the file */ - if(fileLength!=T_FileStream_read(file, p, fileLength)) { - uprv_free(p); - T_FileStream_close(file); - return FALSE; - } - - T_FileStream_close(file); - pData->map=p; - pData->pHeader=(const DataHeader *)p; - pData->mapAddr=p; - return TRUE; - } - - static void - uprv_unmapFile(UDataMemory *pData) { - if(pData!=NULL && pData->map!=NULL) { - uprv_free(pData->map); - pData->map = NULL; - pData->mapAddr = NULL; - pData->pHeader = NULL; - } - } - -#else -# error MAP_IMPLEMENTATION is set incorrectly -#endif - - - -/*----------------------------------------------------------------------------------* - * * - * entry point lookup implementations * - * * - *----------------------------------------------------------------------------------*/ -static const DataHeader * -normalizeDataPointer(const DataHeader *p) { - /* allow the data to be optionally prepended with an alignment-forcing double value */ - if(p==NULL || (p->dataHeader.magic1==0xda && p->dataHeader.magic2==0x27)) { - return p; - } else { - return (const DataHeader *)((const double *)p+1); - } -} - -static const DataHeader * -offsetTOCLookupFn(const UDataMemory *pData, - const char *tocEntryName, - const char *dllEntryName, - UErrorCode *pErrorCode) { - -#ifdef UDATA_DEBUG - fprintf(stderr, "offsetTOC[%p] looking for %s/%s\n", - pData, - tocEntryName,dllEntryName); -#endif - - if(pData->toc!=NULL) { - const char *base=(const char *)pData->toc; - uint32_t *toc=(uint32_t *)pData->toc; - uint32_t start, limit, number; - - /* perform a binary search for the data in the common data's table of contents */ - start=0; - limit=*toc++; /* number of names in this table of contents */ - while(startpHeader; - } -} - -static const DataHeader * -pointerTOCLookupFn(const UDataMemory *pData, - const char *tocEntryName, - const char *dllEntryName, - UErrorCode *pErrorCode) { -#ifdef UDATA_DEBUG - fprintf(stderr, "ptrTOC[%p] looking for %s/%s\n", - pData, - tocEntryName,dllEntryName); -#endif - if(pData->toc!=NULL) { - const PointerTOCEntry *toc=(const PointerTOCEntry *)((const uint32_t *)pData->toc+2); - uint32_t start, limit, number; - - /* perform a binary search for the data in the common data's table of contents */ - start=0; - limit=*(const uint32_t *)pData->toc; /* number of names in this table of contents */ - -#ifdef UDATA_DEBUG - fprintf(stderr, " # of ents: %d\n", limit); - fflush(stderr); -#endif - - if (limit == 0) { /* Stub common data library used during build is empty. */ - return NULL; - } - - while(startpHeader; - } -} - - -/* common library functions ------------------------------------------------- */ - -static UDataMemory *commonICUData = NULL; /* * setCommonICUData. Set a UDataMemory to be the global ICU Data @@ -580,8 +112,8 @@ setCommonICUData(UDataMemory *pData, /* The new common data. Belongs to ca /* their locals. */ UDatamemory_assign(newCommonData, pData); umtx_lock(NULL); - if (commonICUData==oldData) { - commonICUData = newCommonData; + if (gCommonICUData==oldData) { + gCommonICUData = newCommonData; } else { if (warn==TRUE) { @@ -673,10 +205,9 @@ findBasename(const char *path) { typedef struct DataCacheElement { char *name; - UDataMemory item; + UDataMemory *item; } DataCacheElement; -static UHashtable *gHashTable = NULL; /* @@ -686,7 +217,7 @@ static UHashtable *gHashTable = NULL; */ static void U_CALLCONV DataCacheElement_deleter(void *pDCEl) { DataCacheElement *p = (DataCacheElement *)pDCEl; - udata_close(&p->item); /* unmaps storage */ + udata_close(p->item); /* unmaps storage */ uprv_free(p->name); /* delete the hash key string. */ uprv_free(pDCEl); /* delete 'this' */ } @@ -699,20 +230,20 @@ static void U_CALLCONV DataCacheElement_deleter(void *pDCEl) { static UHashtable *udata_getHashTable() { UErrorCode err = U_ZERO_ERROR; - if (gHashTable != NULL) { - return gHashTable; + if (gCommonDataCache != NULL) { + return gCommonDataCache; } umtx_lock(NULL); - if (gHashTable == NULL) { - gHashTable = uhash_open(uhash_hashChars, uhash_compareChars, &err); - uhash_setValueDeleter(gHashTable, DataCacheElement_deleter); + if (gCommonDataCache == NULL) { + gCommonDataCache = uhash_open(uhash_hashChars, uhash_compareChars, &err); + uhash_setValueDeleter(gCommonDataCache, DataCacheElement_deleter); } umtx_unlock(NULL); if (U_FAILURE(err)) { return NULL; /* TODO: handle this error better. */ } - return gHashTable; + return gCommonDataCache; } @@ -730,7 +261,7 @@ static UDataMemory *udata_findCachedData(const char *path) el = (DataCacheElement *)uhash_get(htable, baseName); umtx_unlock(NULL); if (el != NULL) { - retVal = &el->item; + retVal = el->item; } return retVal; } @@ -755,8 +286,11 @@ static UDataMemory *udata_cacheDataItem(const char *path, UDataMemory *item, UEr *pErr = U_MEMORY_ALLOCATION_ERROR; return NULL; } - UDataMemory_init(&newElement->item); /*Need separte init + copy to get flags right. */ - UDatamemory_assign(&newElement->item, item); /* They're not all copied. */ + newElement->item = UDataMemory_createNewInstance(pErr); + if (U_FAILURE(*pErr)) { + return NULL; + } + UDatamemory_assign(newElement->item, item); baseName = findBasename(path); nameLen = uprv_strlen(baseName); @@ -789,92 +323,19 @@ static UDataMemory *udata_cacheDataItem(const char *path, UDataMemory *item, UEr return oldValue; } - return &newElement->item; + return newElement->item; } + + /*----------------------------------------------------------------------* * * - * checkCommonData Validate the format of a common data file. * - * Fill in the TOC type in the UDataMemory * - * If the data is invalid, close the UDataMemory * - * and set the appropriate error code. * + * Add a static reference to the common data library * + * Unless overridden by an explicit u_setCommonData, this will be * + * our common data. * * * *----------------------------------------------------------------------*/ -static void checkCommonData(UDataMemory *udm, UErrorCode *err) { - if (U_FAILURE(*err)) { - return; - } - - if(!(udm->pHeader->dataHeader.magic1==0xda && - udm->pHeader->dataHeader.magic2==0x27 && - udm->pHeader->info.isBigEndian==U_IS_BIG_ENDIAN && - udm->pHeader->info.charsetFamily==U_CHARSET_FAMILY) - ) { - /* header not valid */ - *err=U_INVALID_FORMAT_ERROR; - } - else if (udm->pHeader->info.dataFormat[0]==0x43 && - udm->pHeader->info.dataFormat[1]==0x6d && - udm->pHeader->info.dataFormat[2]==0x6e && - udm->pHeader->info.dataFormat[3]==0x44 && - udm->pHeader->info.formatVersion[0]==1 - ) { - /* dataFormat="CmnD" */ - udm->lookupFn=offsetTOCLookupFn; - udm->toc=(const char *)udm->pHeader+udm->pHeader->dataHeader.headerSize; - if (*(const uint32_t *)udm->toc > 0) { - udm->flags |= TOC_HAS_CONTENTS_FLAG; - } - } - else if(udm->pHeader->info.dataFormat[0]==0x54 && - udm->pHeader->info.dataFormat[1]==0x6f && - udm->pHeader->info.dataFormat[2]==0x43 && - udm->pHeader->info.dataFormat[3]==0x50 && - udm->pHeader->info.formatVersion[0]==1 - ) { - /* dataFormat="ToCP" */ - udm->lookupFn=pointerTOCLookupFn; - udm->toc=(const char *)udm->pHeader+udm->pHeader->dataHeader.headerSize; - if (*(const uint32_t *)udm->toc > 0) { - udm->flags |= TOC_HAS_CONTENTS_FLAG; - } - } - else { - /* dataFormat not recognized */ - *err=U_INVALID_FORMAT_ERROR; - } - - if (U_FAILURE(*err)) { - /* If the data is no good and we memory-mapped it ourselves, - * close the memory mapping so it doesn't leak. Note that this has - * no effect on non-memory mapped data, other than clearing fields in udm. - */ - uprv_unmapFile(udm); - } -} - - -UBool -udata_cleanup() -{ - if (gHashTable) { /* Delete the cache of user data mappings. */ - uhash_close(gHashTable); /* Table owns the contents, and will delete them. */ - gHashTable = 0; /* Cleanup is not thread safe. */ - } - - udata_close(commonICUData); /* Clean up common ICU Data */ - commonICUData = NULL; - - return TRUE; /* Everything was cleaned up */ -} - - -/* */ -/* Add a static reference to the common data from a library if the */ -/* build options are set to request it. */ -/* Unless overridden by an explicit u_setCommonData, this will be */ -/* our common data. */ #if defined(UDATA_STATIC_LIB) || defined(UDATA_DLL) extern const DataHeader U_IMPORT U_ICUDATA_ENTRY_POINT; #endif @@ -885,9 +346,9 @@ extern const DataHeader U_IMPORT U_ICUDATA_ENTRY_POINT; * 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. * - * The UDataMemory object will either be heap or * - * global - in either case, it is permanent and can * - * be safely passed back the chain of callers. * + * * + * If the requested data is already open and cached * + * just return the cached UDataMem object. * * * *----------------------------------------------------------------------*/ static UDataMemory * @@ -909,21 +370,22 @@ openCommonData( if (isICUData) { /* "mini-cache" for common ICU data */ - if(commonICUData != NULL) { - return commonICUData; + if(gCommonICUData != NULL) { + return gCommonICUData; } tData.pHeader = &U_ICUDATA_ENTRY_POINT; checkCommonData(&tData, pErrorCode); setCommonICUData(&tData, NULL, FALSE, pErrorCode); - return commonICUData; + return gCommonICUData; } /* request is NOT for ICU Data. * Is the requested data already cached? */ + inBasename=findBasename(path); { - UDataMemory *dataToReturn = udata_findCachedData(path); + UDataMemory *dataToReturn = udata_findCachedData(inBasename); if (dataToReturn != NULL) { return dataToReturn; } @@ -933,7 +395,6 @@ openCommonData( * Hunt it down, trying all the fall back locations. */ basename=setPathGetBasename(path, pathBuffer); - inBasename=findBasename(path); if(*inBasename==0) { /* no basename, no common data */ *pErrorCode=U_FILE_ACCESS_ERROR; @@ -943,32 +404,31 @@ openCommonData( /* set up the file name */ suffix=strcpy_returnEnd(basename, inBasename); - uprv_strcpy(suffix, "." DATA_TYPE); /* DATA_TYPE is ".dat" */ + uprv_strcpy(suffix, ".dat"); /* try path/basename first, then basename only */ uprv_mapFile(&tData, pathBuffer); - if (!IS_DATA_MEMORY_LOADED(&tData)) { + if (!UDataMemory_isLoaded(&tData)) { if (basename!=pathBuffer) { uprv_mapFile(&tData, basename); } } - if (!IS_DATA_MEMORY_LOADED(&tData)) { + if (!UDataMemory_isLoaded(&tData)) { /* no common data */ *pErrorCode=U_FILE_ACCESS_ERROR; return NULL; } /* we have mapped a file, check its header */ - tData.pHeader=tData.pHeader; checkCommonData(&tData, pErrorCode); /* 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. */ - return udata_cacheDataItem(path, &tData, pErrorCode); + return udata_cacheDataItem(inBasename, &tData, pErrorCode); } @@ -989,15 +449,14 @@ openCommonData( *----------------------------------------------------------------------*/ static UBool extendICUData(UDataMemory *failedData, UErrorCode *pErr) { -#ifndef OS390 - /* For most platforms (all except 390), if the data library that - * we are running with turned out to be the stub library, we will try to + /* 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 * load a .dat file instead. The stub library has no entries in its * TOC, which is how we identify it here. */ UDataMemory *pData; - if (failedData->flags & TOC_HAS_CONTENTS_FLAG) { + if (failedData->vFuncs->NumEntries(failedData) > 0) { /* Not the stub. We can't extend. */ return FALSE; } @@ -1014,93 +473,20 @@ static UBool extendICUData(UDataMemory *failedData, UErrorCode *pErr) FALSE, /* No warnings if write didn't happen */ pErr); /* setCommonICUData honors errors; NOP if error set */ - return commonICUData != failedData; /* Return true if ICUData pointer was updated. */ + return gCommonICUData != failedData; /* Return true if ICUData pointer was updated. */ /* (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. */ -#else - - /* 390 specific Library Loading. - * This is the only platform left that dynamically loads an ICU Data Library. - * All other platforms use .data files when dynamic loading is required, but - * this turn out to be awkward to support in 390 batch mode. - */ - static UBool isLibLoaded; - - if (isLibLoaded == TRUE) { - /* We've already been through here once and loaded the full ICU Data library. - * Nothing more left to load. */ - return false; - } - - - /* Need to do loading in a mutex-protected section of code because we - * don't want to load it twice because of a race. - */ - umtx_lock(NULL); - if (isLibLoaded) { - return FALSE; /* Watch that unlock */ - } - - /* TODO: the following code is just a mish-mash of pieces from the - * previous data library loading code that might be useful - * in putting together something that works. - */ - - Library lib; - inBasename=U_ICUDATA_NAME"_390"; - suffix=strcpy_returnEnd(basename, inBasename); - uprv_strcpy(suffix, LIB_SUFFIX); - - if (uprv_isOS390BatchMode()) { - /* ### hack: we still need to get u_getDataDirectory() fixed - for OS/390 (batch mode - always return "//"? ) - and this here straightened out with LIB_PREFIX and LIB_SUFFIX (both empty?!) - This is probably due to the strange file system on OS/390. It's more like - a database with short entry names than a typical file system. */ - if (s390dll) { - lib=LOAD_LIBRARY("//IXMICUD1", "//IXMICUD1"); - } - else { - /* U_ICUDATA_NAME should always have the correct name */ - /* 390port: BUT FOR BATCH MODE IT IS AN EXCEPTION ... */ - /* 390port: THE NEXT LINE OF CODE WILL NOT WORK !!!!! */ - /*lib=LOAD_LIBRARY("//" U_ICUDATA_NAME, "//" U_ICUDATA_NAME);*/ - lib=LOAD_LIBRARY("//IXMICUDA", "//IXMICUDA"); /*390port*/ - } - } - - lib=LOAD_LIBRARY(pathBuffer, basename); - if(!IS_LIBRARY(lib) && basename!=pathBuffer) { - /* try basename only next */ - lib=LOAD_LIBRARY(basename, basename); - } - - if(IS_LIBRARY(lib)) { - /* we have a data DLL - what kind of lookup do we need here? */ - char entryName[100]; - const DataHeader *pHeader; - *basename=0; - } - - checkCommonData(&tData, pErrorCode); - if (U_SUCCESS(*pErrorCode)) { - /* Don't close the old data - someone might be using it - * May need to change the global to be a pointer rather than a static struct - * to get a clean switch-over. - */ - setCommonICUData(&tData); - - } - - umtx_unlock(NULL); - return TRUE; /* SUCCESS? */ -#endif /* OS390 */ } +/*----------------------------------------------------------------------* + * * + * udata_setCommonData * + * * + *----------------------------------------------------------------------*/ U_CAPI void U_EXPORT2 udata_setCommonData(const void *data, UErrorCode *pErrorCode) { UDataMemory dataMemory; @@ -1115,14 +501,14 @@ udata_setCommonData(const void *data, UErrorCode *pErrorCode) { } /* do we already have common ICU data set? */ - if(commonICUData != NULL) { + if(gCommonICUData != NULL) { *pErrorCode=U_USING_DEFAULT_ERROR; return; } - /* normalize the data pointer and test for validity */ + /* set the data pointer and test for validity */ UDataMemory_init(&dataMemory); - dataMemory.pHeader = normalizeDataPointer((const DataHeader *)data); + UDataMemory_setData(&dataMemory, data); checkCommonData(&dataMemory, pErrorCode); if (U_FAILURE(*pErrorCode)) {return;} @@ -1198,9 +584,6 @@ checkDataItem if (U_FAILURE(*fatalErr)) { return NULL; } -/* // rDataMem is already initialized - UDataMemory_init(rDataMem); -*/ rDataMem->pHeader = pHeader; } else { /* the data is not acceptable, look further */ @@ -1213,40 +596,6 @@ checkDataItem -/*------------------------------------------------------------------------------* - * * - * setEntryNames Files Names and DLL entry point names have different * - * rules for what's valid. For a DLL entry point name, * - " change all '.' or '-'s to '_'. For both, append * - * '.typeName' (or _typeName) to the name * - * * - *------------------------------------------------------------------------------*/ -static void -setEntryNames(const char *type, const char *name, - char *tocEntryName, char *dllEntryName) { - while(*name!=0) { - *tocEntryName=*name; - if(*name=='.' || *name=='-') { - *dllEntryName='_'; - } else { - *dllEntryName=*name; - } - ++tocEntryName; - ++dllEntryName; - ++name; - } - - if(type!=NULL && *type!=0) { - *tocEntryName++='.'; - *dllEntryName++='_'; - do { - *tocEntryName++=*dllEntryName++=*type++; - } while(*type!=0); - } - - *tocEntryName=*dllEntryName=0; -} - /* * A note on the ownership of Mapped Memory @@ -1262,19 +611,24 @@ setEntryNames(const char *type, const char *name, * 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. + * (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.) * * 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, * can be anywhere - heap, stack/local or global. - * They have a flag bit to indicate when they're heap allocated and thus + * They have a flag to indicate when they're heap allocated and thus * must be deleted when closed. */ -/* main data loading function ----------------------------------------------- */ - +/*----------------------------------------------------------------------------* + * * + * main data loading functions * + * * + *----------------------------------------------------------------------------*/ static UDataMemory * doOpenChoice(const char *path, const char *type, const char *name, UDataMemoryIsAcceptable *isAcceptable, void *context, @@ -1282,7 +636,6 @@ doOpenChoice(const char *path, const char *type, const char *name, { char pathBuffer[1024]; char tocEntryName[100]; - char dllEntryName[100]; UDataMemory dataMemory; UDataMemory *pCommonData; UDataMemory *pEntryData; @@ -1293,28 +646,31 @@ doOpenChoice(const char *path, const char *type, const char *name, UErrorCode errorCode=U_ZERO_ERROR; UBool isICUData= (UBool)(path==NULL); - /* set up the ToC names for DLL and offset-ToC lookups */ - setEntryNames(type, name, tocEntryName, dllEntryName); + /* Make up a full mame by appending the type to the supplied + * name, assuming that a type was supplied. + */ + uprv_strcpy(tocEntryName, name); + if(type!=NULL && *type!=0) { + uprv_strcat(tocEntryName, "."); + uprv_strcat(tocEntryName, type); + } /* 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. */ + * 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); -#ifdef UDATA_DEBUG - fprintf(stderr, "commonData;%p\n", pCommonData); - fflush(stderr); -#endif if(U_SUCCESS(errorCode)) { /* look up the data piece in the common data */ - pHeader=pCommonData->lookupFn(pCommonData, tocEntryName, dllEntryName, &errorCode); -#ifdef UDATA_DEBUG - fprintf(stderr, "Common found: %p\n", pHeader); -#endif + pHeader=pCommonData->vFuncs->Lookup(pCommonData, tocEntryName, &errorCode); if(pHeader!=NULL) { pEntryData = checkDataItem(pHeader, isAcceptable, context, type, name, &errorCode, pErrorCode); if (U_FAILURE(*pErrorCode)) { @@ -1334,7 +690,7 @@ doOpenChoice(const char *path, const char *type, const char *name, }; - /* the data was not found in the common data, look further */ + /* the data was not found in the common data, look further, */ /* try to get an individual data file */ basename=setPathGetBasename(path, pathBuffer); if(isICUData) { @@ -1369,7 +725,7 @@ doOpenChoice(const char *path, const char *type, const char *name, } /* the data is not acceptable, or some error occured. Either way, unmap the memory */ - uprv_unmapFile(&dataMemory); + udata_close(&dataMemory); /* If we had a nasty error, bail out completely. */ if (U_FAILURE(*pErrorCode)) { @@ -1399,7 +755,7 @@ doOpenChoice(const char *path, const char *type, const char *name, } /* the data is not acceptable, or some error occured. Either way, unmap the memory */ - uprv_unmapFile(&dataMemory); + udata_close(&dataMemory); /* If we had a nasty error, bail out completely. */ if (U_FAILURE(*pErrorCode)) { @@ -1423,11 +779,6 @@ doOpenChoice(const char *path, const char *type, const char *name, return NULL; } -static void -unloadDataMemory(UDataMemory *pData) { - uprv_unmapFile(pData); -} - /* API ---------------------------------------------------------------------- */ @@ -1450,6 +801,8 @@ udata_open(const char *path, const char *type, const char *name, } } + + U_CAPI UDataMemory * U_EXPORT2 udata_openChoice(const char *path, const char *type, const char *name, UDataMemoryIsAcceptable *isAcceptable, void *context, @@ -1468,30 +821,7 @@ udata_openChoice(const char *path, const char *type, const char *name, } } -U_CAPI void U_EXPORT2 -udata_close(UDataMemory *pData) { -#ifdef UDATA_DEBUG - fprintf(stderr, "udata_close()\n");fflush(stderr); -#endif - if(pData!=NULL) { - unloadDataMemory(pData); - if(pData->flags & MALLOCED_UDATAMEMORY_FLAG ) { - uprv_free(pData); - } else { - UDataMemory_init(pData); - } - } -} - -U_CAPI const void * U_EXPORT2 -udata_getMemory(UDataMemory *pData) { - if(pData!=NULL && pData->pHeader!=NULL) { - return (char *)(pData->pHeader)+pData->pHeader->dataHeader.headerSize; - } else { - return NULL; - } -} U_CAPI void U_EXPORT2 udata_getInfo(UDataMemory *pData, UDataInfo *pInfo) { diff --git a/icu4c/source/common/udatamem.c b/icu4c/source/common/udatamem.c new file mode 100644 index 00000000000..848ae132a22 --- /dev/null +++ b/icu4c/source/common/udatamem.c @@ -0,0 +1,99 @@ +/* +****************************************************************************** +* +* Copyright (C) 1999-2001, International Business Machines +* Corporation and others. All Rights Reserved. +* +****************************************************************************** + + +/*---------------------------------------------------------------------------------- + * + * UDataMemory A class-like struct that serves as a handle to a piece of memory + * that contains some ICU data (resource, converters, whatever.) + * + * When an application opens ICU data (with udata_open, for example, + * a UDataMemory * is returned. + * + *----------------------------------------------------------------------------------*/ + +#include "unicode/utypes.h" +#include "unicode/putil.h" +#include "cmemory.h" +#include "cstring.h" +#include "unicode/udata.h" + +#include "udatamem.h" + +void UDataMemory_init(UDataMemory *This) { + uprv_memset(This, 0, sizeof(UDataMemory)); +} + + +void UDatamemory_assign(UDataMemory *dest, UDataMemory *source) { + /* UDataMemory Assignment. Destination UDataMemory must be initialized first. */ + UBool mallocedFlag = dest->heapAllocated; + uprv_memcpy(dest, source, sizeof(UDataMemory)); + dest->heapAllocated = mallocedFlag; +} + +UDataMemory *UDataMemory_createNewInstance(UErrorCode *pErr) { + UDataMemory *This; + + if (U_FAILURE(*pErr)) { + return NULL; + } + This = uprv_malloc(sizeof(UDataMemory)); + if (This == NULL) { + *pErr = U_MEMORY_ALLOCATION_ERROR; } + else { + UDataMemory_init(This); + This->heapAllocated = TRUE; + } + return This; +} + + +const DataHeader * +normalizeDataPointer(const void *p) { + /* allow the data to be optionally prepended with an alignment-forcing double value */ + const DataHeader *pdh = (const DataHeader *)p; + if(pdh==NULL || (pdh->dataHeader.magic1==0xda && pdh->dataHeader.magic2==0x27)) { + return pdh; + } else { + return (const DataHeader *)((const double *)p+1); + } +} + + +void UDataMemory_setData (UDataMemory *This, const void *dataAddr) { + This->pHeader = normalizeDataPointer(dataAddr); +} + + +U_CAPI void U_EXPORT2 +udata_close(UDataMemory *pData) { + if(pData!=NULL) { + uprv_unmapFile(pData); + if(pData->heapAllocated ) { + uprv_free(pData); + } else { + UDataMemory_init(pData); + } + } +} + +U_CAPI const void * U_EXPORT2 +udata_getMemory(UDataMemory *pData) { + if(pData!=NULL && pData->pHeader!=NULL) { + return (char *)(pData->pHeader)+pData->pHeader->dataHeader.headerSize; + } else { + return NULL; + } +} + + +UBool UDataMemory_isLoaded(UDataMemory *This) { + return This->pHeader != NULL; +} + diff --git a/icu4c/source/common/udatamem.h b/icu4c/source/common/udatamem.h new file mode 100644 index 00000000000..dc8943e2e3d --- /dev/null +++ b/icu4c/source/common/udatamem.h @@ -0,0 +1,47 @@ +/* +****************************************************************************** +* +* Copyright (C) 1999-2001, International Business Machines +* Corporation and others. All Rights Reserved. +* +******************************************************************************/ + + +/*---------------------------------------------------------------------------------- + * + * UDataMemory A class-like struct that serves as a handle to a piece of memory + * that contains some ICU data (resource, converters, whatever.) + * + * When an application opens ICU data (with udata_open, for example, + * a UDataMemory * is returned. + * + *----------------------------------------------------------------------------------*/ +#ifndef __UDATAMEM_H__ +#define __UDATAMEM_H__ + +#include "ucmndata.h" + +typedef struct UDataMemory { + void *map; /* Handle, or whatever. OS dependent. */ + /* Only set if a close operation should unmap the */ + /* associated data. */ + const void *mapAddr; /* For mapped or allocated memory, the start addr. */ + /* Needed to allow unmapping. */ + + + commonDataFuncs *vFuncs; /* Function Pointers for accessing TOC */ + const void *toc; /* For common memory, to find pieces within. */ + const DataHeader *pHeader; /* Header. For common data, header is at top of file */ + UBool heapAllocated; /* True if this UDataMemObject is on the heap */ + /* and thus needs to be deleted when closed. */ +} UDataMemory; + +UDataMemory *UDataMemory_createNewInstance(UErrorCode *pErr); +void UDatamemory_assign (UDataMemory *dest, UDataMemory *source); +void UDataMemory_init (UDataMemory *This); +UBool UDataMemory_isLoaded(UDataMemory *This); +void UDataMemory_setData (UDataMemory *This, const void *dataAddr); + + +const DataHeader *normalizeDataPointer(const void *p); +#endif diff --git a/icu4c/source/common/umapfile.c b/icu4c/source/common/umapfile.c new file mode 100644 index 00000000000..00e918f616b --- /dev/null +++ b/icu4c/source/common/umapfile.c @@ -0,0 +1,379 @@ +/* +****************************************************************************** +* +* Copyright (C) 1999-2001, International Business Machines +* Corporation and others. All Rights Reserved. +* +****************************************************************************** + + +/*---------------------------------------------------------------------------------- + * + * Memory mapped file wrappers for use by the ICU Data Implementation + * All of the platform-specific implementation for mapping data files + * is here. The rest of the ICU Data implementation uses only the + * wrapper functions. + * + *----------------------------------------------------------------------------------*/ +#include "unicode/utypes.h" + + +#include "udatamem.h" +#include "umapfile.h" + + +/* memory-mapping base definitions ------------------------------------------ */ + + +#define MAP_WIN32 1 +#define MAP_POSIX 2 +#define MAP_FILE_STREAM 3 +#define MAP_390DLL 4 + +#ifdef WIN32 +# define WIN32_LEAN_AND_MEAN +# define NOGDI +# define NOUSER +# define NOSERVICE +# define NOIME +# define NOMCX +# include + + typedef HANDLE MemoryMap; + +# define IS_MAP(map) ((map)!=NULL) + +# define MAP_IMPLEMENTATION MAP_WIN32 + +/* ### Todo: auto detect mmap(). Until then, just add your platform here. */ +#elif HAVE_MMAP || defined(U_LINUX) || defined(POSIX) || defined(U_SOLARIS) || defined(AIX) || defined(HPUX) || defined(OS390) || defined(PTX) + typedef size_t MemoryMap; + +# define IS_MAP(map) ((map)!=0) + +# include +# include +# include +# include + +# ifndef MAP_FAILED +# define MAP_FAILED ((void*)-1) +# endif + +# define MAP_IMPLEMENTATION MAP_POSIX + +#elif OS390 + /* No memory mapping for 390 batch mode. Fake it using dll loading. */ +# include +# define MAP_IMPLEMENTATION MAP_390DLL + +#else /* unknown platform, no memory map implementation: use FileStream/uprv_malloc() instead */ + +# include "filestrm.h" + + typedef void *MemoryMap; + +# define IS_MAP(map) ((map)!=NULL) + +# define MAP_IMPLEMENTATION MAP_FILE_STREAM + +#endif + + + + +/*----------------------------------------------------------------------------------* + * * + * Memory Mapped File support. Platform dependent implementation of functions * + * used by the rest of the implementation. * + * * + *----------------------------------------------------------------------------------*/ +#if MAP_IMPLEMENTATION==MAP_WIN32 + UBool + uprv_mapFile( + UDataMemory *pData, /* Fill in with info on the result doing the mapping. */ + /* Output only; any original contents are cleared. */ + const char *path /* File path to be opened/mapped */ + ) + { + HANDLE map; + HANDLE file; + + UDataMemory_init(pData); /* Clear the output struct. */ + + /* open the input file */ + file=CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL); + if(file==INVALID_HANDLE_VALUE) { + return FALSE; + } + + /* create an unnamed Windows file-mapping object for the specified file */ + map=CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL); + CloseHandle(file); + if(map==NULL) { + return FALSE; + } + + /* map a view of the file into our address space */ + pData->pHeader=(const DataHeader *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0); + if(pData->pHeader==NULL) { + CloseHandle(map); + return FALSE; + } + pData->map=map; + return TRUE; + } + + + void + uprv_unmapFile(UDataMemory *pData) { + if(pData!=NULL && pData->map!=NULL) { + UnmapViewOfFile(pData->pHeader); + CloseHandle(pData->map); + pData->pHeader=NULL; + pData->map=NULL; + } + } + +#elif MAP_IMPLEMENTATION==MAP_POSIX + static UBool + uprv_mapFile(UDataMemory *pData, const char *path) { + int fd; + int length; + struct stat mystat; + const void *data; + + UDataMemory_init(pData); /* Clear the output struct. */ + + /* determine the length of the file */ + if(stat(path, &mystat)!=0 || mystat.st_size<=0) { + return FALSE; + } + length=mystat.st_size; + + /* open the file */ + fd=open(path, O_RDONLY); + if(fd==-1) { + return FALSE; + } + + /* get a view of the mapping */ +#ifndef HPUX + data=mmap(0, length, PROT_READ, MAP_SHARED, fd, 0); +#else + data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0); +#endif + close(fd); /* no longer needed */ + if(data==MAP_FAILED) { + +# ifdef UDATA_DEBUG + perror("mmap"); +# endif + + return FALSE; + } + +# ifdef UDATA_DEBUG + fprintf(stderr, "mmap of %s [%d bytes] succeeded, -> 0x%X\n", path, length, data); + fflush(stderr); +# endif + + pData->map=length; + pData->pHeader=(const DataHeader *)data; + pData->mapAddr = data; + return TRUE; + } + + static void + uprv_unmapFile(UDataMemory *pData) { + if(pData!=NULL && pData->map>0) { + if(munmap((void *)pData->mapAddr, pData->map)==-1) { +# ifdef UDATA_DEBUG + perror("munmap"); +# endif + } + pData->pHeader=NULL; + pData->map=0; + pData->mapAddr=NULL; + } + } + +#elif MAP_IMPLEMENTATION==MAP_FILE_STREAM + static UBool + uprv_mapFile(UDataMemory *pData, const char *path) { + FileStream *file; + int32_t fileLength; + void *p; + + UDataMemory_init(pData); /* Clear the output struct. */ + /* open the input file */ + file=T_FileStream_open(path, "rb"); + if(file==NULL) { + return FALSE; + } + + /* get the file length */ + fileLength=T_FileStream_size(file); + if(T_FileStream_error(file) || fileLength<=20) { + T_FileStream_close(file); + return FALSE; + } + + /* allocate the data structure */ + p=uprv_malloc(fileLength); + if(p==NULL) { + T_FileStream_close(file); + return FALSE; + } + + /* read the file */ + if(fileLength!=T_FileStream_read(file, p, fileLength)) { + uprv_free(p); + T_FileStream_close(file); + return FALSE; + } + + T_FileStream_close(file); + pData->map=p; + pData->pHeader=(const DataHeader *)p; + pData->mapAddr=p; + return TRUE; + } + + static void + uprv_unmapFile(UDataMemory *pData) { + if(pData!=NULL && pData->map!=NULL) { + uprv_free(pData->map); + pData->map = NULL; + pData->mapAddr = NULL; + pData->pHeader = NULL; + } + } + + +#elif MAP_IMPLEMENTATION==MAP_390DLL + /* 390 specific Library Loading. + * This is the only platform left that dynamically loads an ICU Data Library. + * All other platforms use .data files when dynamic loading is required, but + * this turn out to be awkward to support in 390 batch mode. + * + * The idea here is to hide the fact that 390 is using dll loading from the + * rest of ICU, and make it look like there is file loading happening. + * + */ + + uprv_mapFile(UDataMemory *pData, const char *path) { + /* TODO: turn the path into a dll name, try to load it, + * if successful, set the the pHeader field of the UDataMemory + * to the data address. + * + * (If path has a ".dat" extension, take it off and add on whatever + * the standard shared library extension is?) + */ + } + + + + void uprv_unmapFile(UDataMemory *pData) { + if(pData!=NULL && pData->map!=NULL) { + /* TODO: whatever. Doesn't really need to do anything. */ + } + } + +# define RTLD_LAZY 0 +# define RTLD_GLOBAL 0 + +static void *dlopen(const char *filename, int flag) { + dllhandle *handle; + +# ifdef UDATA_DEBUG + fprintf(stderr, "dllload: %s ", filename); +# endif + handle=dllload(filename); +# ifdef UDATA_DEBUG + fprintf(stderr, " -> %08X\n", handle ); +# endif + return handle; + } + +static void *dlsym(void *h, const char *symbol) { + void *val=0; + val=dllqueryvar((dllhandle*)h,symbol); +# ifdef UDATA_DEBUG + fprintf(stderr, "dllqueryvar(%08X, %s) -> %08X\n", h, symbol, val); +# endif + return val; + } + +static int dlclose(void *handle) { +# ifdef UDATA_DEBUG + fprintf(stderr, "dllfree: %08X\n", handle); +# endif + return dllfree((dllhandle*)handle); + } + + + + /* TODO: the following code is just a mish-mash of pieces from the + * previous OS390 data library loading code that might be useful + * in putting together something that works. + */ + +#if 0 + Library lib; + inBasename=U_ICUDATA_NAME"_390"; + suffix=strcpy_returnEnd(basename, inBasename); + uprv_strcpy(suffix, LIB_SUFFIX); + + if (uprv_isOS390BatchMode()) { + /* ### hack: we still need to get u_getDataDirectory() fixed + for OS/390 (batch mode - always return "//"? ) + and this here straightened out with LIB_PREFIX and LIB_SUFFIX (both empty?!) + This is probably due to the strange file system on OS/390. It's more like + a database with short entry names than a typical file system. */ + if (s390dll) { + lib=LOAD_LIBRARY("//IXMICUD1", "//IXMICUD1"); + } + else { + /* U_ICUDATA_NAME should always have the correct name */ + /* 390port: BUT FOR BATCH MODE IT IS AN EXCEPTION ... */ + /* 390port: THE NEXT LINE OF CODE WILL NOT WORK !!!!! */ + /*lib=LOAD_LIBRARY("//" U_ICUDATA_NAME, "//" U_ICUDATA_NAME);*/ + lib=LOAD_LIBRARY("//IXMICUDA", "//IXMICUDA"); /*390port*/ + } + } + + lib=LOAD_LIBRARY(pathBuffer, basename); + if(!IS_LIBRARY(lib) && basename!=pathBuffer) { + /* try basename only next */ + lib=LOAD_LIBRARY(basename, basename); + } + + if(IS_LIBRARY(lib)) { + /* we have a data DLL - what kind of lookup do we need here? */ + char entryName[100]; + const DataHeader *pHeader; + *basename=0; + } + + checkCommonData(&tData, pErrorCode); + if (U_SUCCESS(*pErrorCode)) { + /* Don't close the old data - someone might be using it + * May need to change the global to be a pointer rather than a static struct + * to get a clean switch-over. + */ + setCommonICUData(&tData); + + } + + umtx_unlock(NULL); + return TRUE; /* SUCCESS? */ +#endif + +#else +# error MAP_IMPLEMENTATION is set incorrectly +#endif + + diff --git a/icu4c/source/common/umapfile.h b/icu4c/source/common/umapfile.h new file mode 100644 index 00000000000..421790615d1 --- /dev/null +++ b/icu4c/source/common/umapfile.h @@ -0,0 +1,32 @@ +/* +****************************************************************************** +* +* Copyright (C) 1999-2001, International Business Machines +* Corporation and others. All Rights Reserved. +* +****************************************************************************** + + +/*---------------------------------------------------------------------------------- + * + * Memory mapped file wrappers for use by the ICU Data Implementation + * + * Porting note: The implementation of these functions is very platform specific. + * Not all platforms can do real memory mapping. Those that can't + * still must implement these functions, getting the data into memory using + * whatever means are available. + * + * These functions are part of the ICU internal implementation, and + * are not inteded to be used directly by applications. + * + *----------------------------------------------------------------------------------*/ + +#ifndef __UMAPFILE_H__ +#define __UMAPFILE_H__ + +typedef struct UDataMemory UDataMemory; + +UBool uprv_mapFile(UDataMemory *pdm, const char *path); +void uprv_unmapFile(UDataMemory *pData); + +#endif