/* ******************************************************************************* * * Copyright (C) 1999, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* * file name: udata.c * encoding: US-ASCII * tab size: 8 (not used) * indentation:4 * * created on: 1999oct25 * created by: Markus W. Scherer */ #include "unicode/utypes.h" #include "unicode/putil.h" #include "umutex.h" #include "cmemory.h" #include "cstring.h" #include "filestrm.h" #include "unicode/udata.h" #if !defined(HAVE_DLOPEN) # define HAVE_DLOPEN 0 #endif #if !defined(UDATA_DLL) && !defined(UDATA_MAP) # define UDATA_DLL #endif #define COMMON_DATA_NAME "icudata" #define COMMON_DATA_NAME_LENGTH 7 #define DATA_TYPE "dat" static UDataMemory * doOpenChoice(const char *path, const char *type, const char *name, UDataMemoryIsAcceptable *isAcceptable, void *context, UErrorCode *pErrorCode); U_CAPI UDataMemory * U_EXPORT2 udata_open(const char *path, const char *type, const char *name, UErrorCode *pErrorCode) { 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); } } U_CAPI UDataMemory * U_EXPORT2 udata_openChoice(const char *path, const char *type, const char *name, UDataMemoryIsAcceptable *isAcceptable, void *context, UErrorCode *pErrorCode) { if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { return NULL; } else if(name==NULL || *name==0 || isAcceptable==NULL) { *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; return NULL; } else { return doOpenChoice(path, type, name, isAcceptable, context, pErrorCode); } } /* platform-specific implementation ----------------------------------------- */ /* * Most implementations define a MappedData struct * and have a MappedData *p; in UDataMemory. * They share the source code for some functions. * Other implementations need to #undef the following #define. * See after the platform-specific code. */ #define UDATA_INDIRECT static bool_t isCommonDataAcceptable(void *context, const char *type, const char *name, UDataInfo *pInfo); #if defined(WIN32) /* Win32 implementations --------------------------------- */ #include typedef struct { uint16_t headerSize; uint8_t magic1, magic2; } MappedData; # if defined(UDATA_DLL) /* Win32 dll implementation ----------------------- */ struct UDataMemory { HINSTANCE lib; MappedData *p; }; typedef HINSTANCE Library; static MappedData * getChoice(Library lib, const char *entry, const char *type, const char *name, UDataMemoryIsAcceptable *isAcceptable, void *context, UErrorCode *pErrorCode); #define LIB_SUFFIX ".dll" /* skip the bogus double */ #define GET_ENTRY(lib, entryName) getWIN32Entry(lib, entryName) /*(MappedData *)(((double*)GetProcAddress(lib, entryName))+1)*/ static MappedData *getWIN32Entry(Library lib, const char *entryName) { MappedData *m; m = (MappedData *)GetProcAddress(lib, entryName); return (MappedData *)(m==NULL?NULL:((double*)m)+1); } #define NO_LIBRARY NULL #define IS_LIBRARY(lib) ((lib)!=NULL) #define LOAD_LIBRARY(path, basename, isCommon) LoadLibrary(path); #define UNLOAD_LIBRARY(lib) FreeLibrary(lib) # else /* Win32 memory map implementation --------------------------------- */ struct UDataMemory { HANDLE map; MappedData *p; }; typedef UDataMemory *Library; static MappedData * getChoice(Library lib, const char *entry, const char *type, const char *name, UDataMemoryIsAcceptable *isAcceptable, void *context, UErrorCode *pErrorCode); #define LIB_SUFFIX ".dat" #define GET_ENTRY(lib, entryName) getCommonMapData(lib, entryName) #define NO_LIBRARY NULL #define IS_LIBRARY(lib) ((lib)!=NULL) #define UNLOAD_LIBRARY(lib) udata_close((UDataMemory *)(lib)) static Library LOAD_LIBRARY(const char *path, const char *basename, bool_t isCommon) { char buffer[40]; UDataMemory *pData; MappedData *p; HANDLE map; UErrorCode errorCode=U_ZERO_ERROR; /* set up the mapping name and the filename */ uprv_strcpy(buffer, "icu "); uprv_strcat(buffer, basename); /* open the mapping */ map=OpenFileMapping(FILE_MAP_READ, FALSE, buffer); if(map==NULL) { /* the mapping has not been created */ HANDLE file; /* 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 NULL; } /* create the mapping */ map=CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, buffer); CloseHandle(file); if(map==NULL) { return NULL; } } /* get a view of the mapping */ p=(MappedData *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0); if(p==NULL) { CloseHandle(map); return NULL; } /* allocate the data structure */ pData=(UDataMemory *)uprv_malloc(sizeof(UDataMemory)); if(pData==NULL) { UnmapViewOfFile(pData->p); CloseHandle(map); return NULL; } pData->map=map; pData->p=p; /* is it acceptable? */ if(NULL==getChoice(pData, NULL, DATA_TYPE, COMMON_DATA_NAME, isCommon ? isCommonDataAcceptable : NULL, NULL, &errorCode) ) { udata_close(pData); return NULL; } return (Library)pData; } U_CAPI void U_EXPORT2 udata_close(UDataMemory *pData) { if(pData!=NULL) { if(pData->map!=NULL) { UnmapViewOfFile(pData->p); CloseHandle(pData->map); } uprv_free(pData); } } # endif /* POSIX implementations ---------------------------------------------------- */ #elif defined (LINUX)||defined(POSIX)||defined(SOLARIS)||defined(AIX)||defined(HPUX) /* If you are excruciatingly bored turn this on .. */ /* #define UDATA_DEBUG 1 */ typedef struct { uint16_t headerSize; uint8_t magic1, magic2; } MappedData; #if defined(UDATA_DEBUG) #include #endif /* add more to this list as more platform's dll support is written */ # if defined(UDATA_DLL) && (HAVE_DLOPEN) struct UDataMemory { void *lib; MappedData *p; }; #ifndef UDATA_SO_SUFFIX # error Please define UDATA_SO_SUFFIX to the shlib suffix (i.e. '.so' ) #endif #define LIB_PREFIX "lib" #define LIB_PREFIX_LENGTH 3 #define LIB_SUFFIX UDATA_SO_SUFFIX /* Do we need to check the platform here? */ #if defined(ICU_USE_SHL_LOAD) # include /* HPUX compatibility stubs: shl_load, etc.. */ #define RTLD_LAZY 0 #define RTLD_GLOBAL 0 void *dlopen (const char *filename, int flag) { void *handle; /* real type: 'shl_t' */ #ifdef UDATA_DEBUG fprintf(stderr, "shl_load: %s ", filename); #endif handle = shl_load(filename, BIND_NONFATAL | BIND_DEFERRED | DYNAMIC_PATH , 0L); #ifdef UDATA_DEBUG fprintf(stderr, " -> %08X\n", handle ); #endif return handle; } void *dlsym(void *h, char *symbol) { void *val = 0; int rv; shl_t mysh; mysh = (shl_t)h; /* real type */ rv = shl_findsym(&mysh,symbol,TYPE_DATA,(void*)&val); #ifdef UDATA_DEBUG fprintf(stderr, "shl_findsym(%08X, %s) -> %08X [%d]\n", h, symbol, val, rv); #endif return val; } int dlclose (void *handle) { #ifdef UDATA_DEBUG fprintf(stderr, "shl_unload: %08X\n", handle); #endif return shl_unload((shl_t)handle); } #else /* 'de facto standard' dlopen etc */ # include #endif typedef void *Library; static MappedData * getChoice(Library lib, const char *entry, const char *type, const char *name, UDataMemoryIsAcceptable *isAcceptable, void *context, UErrorCode *pErrorCode); #define GET_ENTRY(lib, entryName) getPOSIXEntry(lib, entryName) /*(MappedData *)(((double*)dlsym(lib, entryName))+1)*/ static MappedData *getPOSIXEntry(Library lib, const char *entryName) { MappedData *m; m = dlsym(lib, entryName); return (MappedData *)(m==NULL?NULL:((double *)m)+1); } #define NO_LIBRARY NULL #define IS_LIBRARY(lib) ((lib)!=NULL) #define LOAD_LIBRARY(path, basename, isCommon) dlopen(path, RTLD_LAZY|RTLD_GLOBAL); #define UNLOAD_LIBRARY(lib) dlclose(lib) # else /* POSIX memory map implementation --------------------------------- */ #ifdef UDATA_DLL #undef UDATA_DLL #endif #ifndef UDATA_MAP #define UDATA_MAP #endif #include #include #include #include #ifndef MAP_FAILED #define MAP_FAILED ((void*)-1) #endif struct UDataMemory { size_t length; MappedData *p; }; typedef UDataMemory *Library; static MappedData * getChoice(Library lib, const char *entry, const char *type, const char *name, UDataMemoryIsAcceptable *isAcceptable, void *context, UErrorCode *pErrorCode); #define LIB_SUFFIX ".dat" #define GET_ENTRY(lib, entryName) getCommonMapData(lib, entryName) #define NO_LIBRARY NULL #define IS_LIBRARY(lib) ((lib)!=NULL) #define UNLOAD_LIBRARY(lib) udata_close((UDataMemory *)(lib)) static Library LOAD_LIBRARY(const char *path, const char *basename, bool_t isCommon) { UDataMemory *pData; UDataInfo *info; int fd; int length; const char *dataDir; struct stat mystat; void *data; UErrorCode errorCode = U_ZERO_ERROR; /* determine the length of the file */ if(stat(path, &mystat)) { return NULL; } length = mystat.st_size; fd = open(path, O_RDONLY); if(fd == -1) { return NULL; } /* get a view of the mapping */ data = mmap(0, length, PROT_READ, MAP_SHARED, fd, 0); close(fd); /* no longer needed */ if(data == MAP_FAILED) { perror("mmap"); return NULL; } #ifdef UDATA_DEBUG fprintf(stderr, "mmap of %s [%d bytes] succeeded, -> 0x%X\n", path, length, data); fflush(stderr); #endif /* allocate the data structure */ pData=(UDataMemory *)uprv_malloc(sizeof(UDataMemory)); if(pData==NULL) { munmap(data, length); return NULL; } pData->length = length; pData->p =(MappedData *)data; /* is it acceptable? */ if(NULL==getChoice(pData, NULL, DATA_TYPE, COMMON_DATA_NAME, isCommon ? isCommonDataAcceptable : NULL, NULL, &errorCode) ) { udata_close(pData); return NULL; } return pData; } U_CAPI void U_EXPORT2 udata_close(UDataMemory *pData) { if(pData!=NULL) { if(pData->length!=0 && munmap(pData->p, pData->length)==-1) { perror("munmap"); } uprv_free(pData); } } # endif #else /* unknown platform - stdio fopen()/fread() implementation ------------ */ #include #undef UDATA_INDIRECT #undef UDATA_DLL #ifndef UDATA_MAP # define UDATA_MAP #endif struct UDataMemory { uint16_t headerSize; uint8_t magic1, magic2; }; typedef UDataMemory MappedData; typedef UDataMemory *Library; static MappedData * getChoice(Library lib, const char *entry, const char *type, const char *name, UDataMemoryIsAcceptable *isAcceptable, void *context, UErrorCode *pErrorCode); #define GET_ENTRY(lib, entryName) (lib) #define NO_LIBRARY NULL #define IS_LIBRARY(lib) ((lib)!=NULL) #define UNLOAD_LIBRARY(lib) uprv_free(lib) static Library LOAD_LIBRARY(const char *path, const char *basename, bool_t isCommon) { FileStream *file; UDataMemory *pData; int32_t fileLength; /* open the input file */ file=T_FileStream_open(path, "rb"); if(file==NULL) { return NULL; } /* get the file length */ fileLength=T_FileStream_size(file); if(T_FileStream_error(file) || fileLength<=20) { T_FileStream_close(file); return NULL; } /* allocate the data structure */ pData=(UDataMemory *)uprv_malloc(fileLength); if(pData==NULL) { T_FileStream_close(file); return NULL; } /* read the file */ if(fileLength!=T_FileStream_read(file, pData, fileLength)) { uprv_free(pData); T_FileStream_close(file); return NULL; } T_FileStream_close(file); return pData; } U_CAPI void U_EXPORT2 udata_close(UDataMemory *pData) { if(pData!=NULL) { uprv_free(pData); } } U_CAPI const void * U_EXPORT2 udata_getMemory(UDataMemory *pData) { if(pData!=NULL) { return (char *)pData+pData->headerSize; } else { return NULL; } } U_CAPI void U_EXPORT2 udata_getInfo(UDataMemory *pData, UDataInfo *pInfo) { if(pInfo!=NULL) { if(pData!=NULL) { UDataInfo *info=(UDataInfo *)(pData+1); uint16_t size=pInfo->size; if(size>info->size) { pInfo->size=info->size; } uprv_memcpy((uint16_t *)pInfo+1, (uint16_t *)info+1, size-2); } else { pInfo->size=0; } } } #endif /* common function implementations ------------------------------------------ */ #ifdef UDATA_INDIRECT # ifdef UDATA_DLL /* common DLL implementations */ U_CAPI void U_EXPORT2 udata_close(UDataMemory *pData) { if(pData!=NULL) { if(IS_LIBRARY(pData->lib)) { UNLOAD_LIBRARY(pData->lib); } uprv_free(pData); } } # else /* common implementation of use of common memory map */ /* this is the memory-map version of GET_ENTRY(), used by getChoice() */ static MappedData * getCommonMapData(const UDataMemory *data, const char *dataName) { /* dataName==NULL if no lookup in a table of contents is necessary */ if(dataName!=NULL) { const char *base=(const char *)(data->p)+data->p->headerSize; uint32_t *toc=(uint32_t *)base; 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(startp; } } static bool_t isCommonDataAcceptable(void *context, const char *type, const char *name, UDataInfo *pInfo) { return pInfo->size>=20 && pInfo->isBigEndian==U_IS_BIG_ENDIAN && pInfo->charsetFamily==U_CHARSET_FAMILY && pInfo->sizeofUChar==sizeof(UChar) && pInfo->dataFormat[0]==0x43 && /* dataFormat="CmnD" */ pInfo->dataFormat[1]==0x6d && pInfo->dataFormat[2]==0x6e && pInfo->dataFormat[3]==0x44 && pInfo->formatVersion[0]==1; } # endif /* common implementations of other functions for indirect mappings */ U_CAPI const void * U_EXPORT2 udata_getMemory(UDataMemory *pData) { if(pData!=NULL) { return (char *)(pData->p)+pData->p->headerSize; } else { return NULL; } } U_CAPI void U_EXPORT2 udata_getInfo(UDataMemory *pData, UDataInfo *pInfo) { if(pInfo!=NULL) { if(pData!=NULL) { UDataInfo *info=(UDataInfo *)(pData->p+1); uint16_t size=pInfo->size; if(size>info->size) { pInfo->size=info->size; } uprv_memcpy((uint16_t *)pInfo+1, (uint16_t *)info+1, size-2); } else { pInfo->size=0; } } } #endif /* function implementations for all platforms ------------------------------- */ static Library commonLib=NO_LIBRARY; static const char *strcpy_dllentry(char *target, const char *src) { int i, length; uprv_strcpy(target,src); length = uprv_strlen(target); for(i=0;ip=p; return pData; } # endif /* allocate the data structure */ pData=(UDataMemory *)uprv_malloc(sizeof(UDataMemory)); if(pData==NULL) { if(IS_LIBRARY(lib)) { UNLOAD_LIBRARY(lib); } *pErrorCode=U_MEMORY_ALLOCATION_ERROR; return NULL; } # ifdef UDATA_DLL pData->lib=lib; # else /* defined(UDATA_MAP) && !IS_LIBRARY(lib) */ uprv_memset(pData, 0, sizeof(pData)); # endif pData->p=p; return pData; # endif } /* data not found */ if(U_SUCCESS(*pErrorCode)) { if(U_SUCCESS(errorCode)) { /* file not found */ *pErrorCode=U_FILE_ACCESS_ERROR; } else { /* entry point not found or rejected */ *pErrorCode=errorCode; } } return NULL; } static MappedData * getChoice(Library lib, const char *entry, const char *type, const char *name, UDataMemoryIsAcceptable *isAcceptable, void *context, UErrorCode *pErrorCode) { MappedData *p; UDataInfo *info; /* get the data pointer */ p=GET_ENTRY(lib, entry); if(p==NULL) { *pErrorCode=U_FILE_ACCESS_ERROR; return NULL; } info=(UDataInfo *)(p+1); /* check magic1 & magic2 */ /* check for the byte ordering */ /* is this acceptable? */ if( p->magic1!=0xda || p->magic2!=0x27 || info->isBigEndian!=U_IS_BIG_ENDIAN || isAcceptable!=NULL && !isAcceptable(context, type, name, info) ) { *pErrorCode=U_INVALID_FORMAT_ERROR; return NULL; } return p; }