ICU-157 add udata implementation

X-SVN-Rev: 216
This commit is contained in:
Markus Scherer 1999-11-22 19:43:01 +00:00
parent d3c9e756f1
commit 77586e9d8b
2 changed files with 881 additions and 0 deletions

View File

@ -227,6 +227,11 @@ SOURCE=.\ucnv_io.c
# End Source File
# Begin Source File
SOURCE=.\udata.c
# ADD CPP /Ze
# End Source File
# Begin Source File
SOURCE=.\uhash.c
# End Source File
# Begin Source File
@ -240,6 +245,10 @@ SOURCE=.\umutex.c
# End Source File
# Begin Source File
SOURCE=.\unames.c
# End Source File
# Begin Source File
SOURCE=.\unicode.cpp
# End Source File
# Begin Source File

872
icu4c/source/common/udata.c Normal file
View File

@ -0,0 +1,872 @@
/*
*******************************************************************************
* *
* COPYRIGHT: *
* (C) Copyright International Business Machines Corporation, 1999 *
* Licensed Material - Program-Property of IBM - All Rights Reserved. *
* US Government Users Restricted Rights - Use, duplication, or disclosure *
* restricted by GSA ADP Schedule Contract with IBM Corp. *
* *
*******************************************************************************
* file name: udata.c
* encoding: US-ASCII
* tab size: 8 (not used)
* indentation:4
*
* created on: 1999oct25
* created by: Markus W. Scherer
*/
#include "utypes.h"
#include "putil.h"
#include "umutex.h"
#include "cmemory.h"
#include "cstring.h"
#include "filestrm.h"
#include "udata.h"
#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 <windows.h>
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"
#define GET_ENTRY(lib, entryName) (MappedData *)GetProcAddress(lib, entry)
#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, entry)
#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 */
icu_strcpy(buffer, "icu ");
icu_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 *)icu_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, isCommonDataAcceptable, 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);
}
icu_free(pData);
}
}
# endif
/* POSIX implementations ---------------------------------------------------- */
#elif defined (LINUX)||defined(POSIX)||defined(SOLARIS)||defined(AIX)||defined(HPUX)
typedef struct {
uint16_t headerSize;
uint8_t magic1, magic2;
} MappedData;
#if defined(UDATA_DEBUG)
#include <stdio.h>
#endif
# if defined(UDATA_DLL) /* POSIX dll implementation ----------------------- */
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? */
#include <dlfcn.h>
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) (MappedData *)dlsym(lib, entry)
#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 --------------------------------- */
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
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, entry)
#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;
/* 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 *)icu_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, isCommonDataAcceptable, 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");
}
icu_free(pData);
}
}
# endif
#else /* unknown platform - stdio fopen()/fread() implementation ------------ */
#include <stdio.h>
#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) icu_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 *)icu_malloc(fileLength);
if(pData==NULL) {
T_FileStream_close(file);
return NULL;
}
/* read the file */
if(fileLength!=T_FileStream_read(file, pData, fileLength)) {
icu_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) {
icu_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;
}
icu_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);
}
icu_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(start<limit-1) {
number=(start+limit)/2;
if(icu_strcmp(dataName, (const char *)(base+toc[2*number]))<0) {
limit=number;
} else {
start=number;
}
}
if(icu_strcmp(dataName, (const char *)(base+toc[2*start]))==0) {
/* found it */
return (MappedData *)(base+toc[2*start+1]);
} else {
return NULL;
}
} else {
return data->p;
}
}
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;
}
icu_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 UDataMemory *
doOpenChoice(const char *path, const char *type, const char *name,
UDataMemoryIsAcceptable *isAcceptable, void *context,
UErrorCode *pErrorCode) {
char pathBuffer[512];
char entryNameBuffer[40];
char *basename, *suffix;
const char *entryName;
bool_t isICUData, hasPath, hasBasename;
Library lib;
MappedData *p;
UErrorCode errorCode=U_ZERO_ERROR;
/* set up path and basename */
if(path==NULL) {
isICUData=TRUE;
basename=pathBuffer;
/* copy the path to the path buffer */
path=u_getDataDirectory();
if(path!=NULL && *path!=0) {
int length=icu_strlen(path);
icu_memcpy(pathBuffer, path, length);
basename+=length;
hasPath=TRUE;
} else {
hasPath=FALSE;
}
/* add (prefix and) basename */
# ifndef LIB_PREFIX
icu_strcpy(basename, COMMON_DATA_NAME);
suffix=basename+COMMON_DATA_NAME_LENGTH;
# else
icu_memcpy(basename, LIB_PREFIX, LIB_PREFIX_LENGTH);
icu_strcpy(basename+LIB_PREFIX_LENGTH, COMMON_DATA_NAME);
suffix=basename+LIB_PREFIX_LENGTH+COMMON_DATA_NAME_LENGTH;
# endif
hasBasename=TRUE;
} else {
char *basename2;
isICUData=FALSE;
/* find the last file sepator */
basename=icu_strrchr(path, '/');
if(basename==NULL) {
basename=(char *)path;
} else {
++basename;
}
basename2=icu_strrchr(basename, '\\');
if(basename2!=NULL) {
basename=basename2+1;
}
if(path!=basename) {
# ifndef LIB_PREFIX
/* copy the path/basename to the path buffer */
icu_strcpy(pathBuffer, path);
basename=pathBuffer+(basename-path);
# else
/* copy the path to the path buffer */
icu_memcpy(pathBuffer, path, basename-path);
/* add prefix and basename */
suffix=pathBuffer+(basename-path);
icu_memcpy(suffix, LIB_PREFIX, LIB_PREFIX_LENGTH);
icu_strcpy(suffix+LIB_PREFIX_LENGTH, basename);
basename=suffix;
# endif
hasPath=TRUE;
} else {
/* copy the path to the path buffer */
path=u_getDataDirectory();
if(path!=NULL && *path!=0) {
int length=icu_strlen(path);
icu_memcpy(pathBuffer, path, length);
suffix=pathBuffer+length;
hasPath=TRUE;
} else {
suffix=pathBuffer;
hasPath=FALSE;
}
/* add (prefix and) basename */
# ifndef LIB_PREFIX
icu_strcpy(suffix, basename);
# else
icu_memcpy(suffix, LIB_PREFIX, LIB_PREFIX_LENGTH);
icu_strcpy(suffix+LIB_PREFIX_LENGTH, basename);
# endif
basename=suffix;
}
hasBasename= *basename!=0;
if(hasBasename) {
suffix=basename+icu_strlen(basename);
}
}
path=pathBuffer;
/* set up the entry point name */
if(type!=NULL && *type!=0) {
icu_strcpy(entryNameBuffer, name);
# ifdef UDATA_DLL
icu_strcat(entryNameBuffer, "_");
# else
icu_strcat(entryNameBuffer, ".");
# endif
icu_strcat(entryNameBuffer, type);
entryName=entryNameBuffer;
} else {
entryName=name;
}
/* try the common data first */
p=NULL;
# ifdef UDATA_INDIRECT
if(hasBasename) {
/* get the common data */
/* do we have it cached? */
if(isICUData) {
lib=commonLib;
} else {
lib=NO_LIBRARY;
}
/* load the common data if neccessary */
if(!IS_LIBRARY(lib)) {
/* try path/basename first */
icu_strcpy(suffix, LIB_SUFFIX);
lib=LOAD_LIBRARY(path, basename, TRUE);
if(!IS_LIBRARY(lib)) {
/* try basename only next */
lib=LOAD_LIBRARY(basename, basename, TRUE);
}
/* set the cache if appropriate */
if(isICUData && IS_LIBRARY(lib)) {
bool_t setThisLib=FALSE;
/* in the mutex block, set the common library for this process */
umtx_lock(NULL);
if(!IS_LIBRARY(commonLib)) {
commonLib=lib;
setThisLib=TRUE;
}
umtx_unlock(NULL);
/* if a different thread set it first, then free the extra library instance */
if(!setThisLib) {
UNLOAD_LIBRARY(lib);
lib=commonLib;
}
}
}
if(IS_LIBRARY(lib)) {
/* look for the entry point in this common data */
p=getChoice(lib, entryName, type, name, isAcceptable, context, &errorCode);
if(p!=NULL) {
if(isICUData) {
lib=NO_LIBRARY;
}
} else {
*pErrorCode=errorCode;
if(!isICUData) {
UNLOAD_LIBRARY(lib);
}
}
}
}
# endif
/* if the data is not found in the common data, then look for a separate library */
/* try basename+"_"+entryName[+LIB_SUFFIX] first */
if(p==NULL && hasBasename) {
*suffix='_';
icu_strcpy(suffix+1, entryName);
# ifdef UDATA_DLL
icu_strcat(suffix+1, LIB_SUFFIX);
# endif
/* try path/basename first */
lib=LOAD_LIBRARY(path, basename, FALSE);
if(!IS_LIBRARY(lib)) {
/* try basename only next */
lib=LOAD_LIBRARY(basename, basename, FALSE);
}
if(IS_LIBRARY(lib)) {
/* look for the entry point */
p=getChoice(lib, entryName, type, name, isAcceptable, context, &errorCode);
if(p==NULL) {
*pErrorCode=errorCode;
UNLOAD_LIBRARY(lib);
}
}
}
/* try entryName[+LIB_SUFFIX] next */
if(p==NULL) {
# ifndef LIB_PREFIX
icu_strcpy(basename, entryName);
# else
icu_strcpy(basename+LIB_PREFIX_LENGTH, entryName);
# endif
# ifdef UDATA_DLL
icu_strcat(basename, LIB_SUFFIX);
# endif
/* try path/basename first */
lib=LOAD_LIBRARY(path, basename, FALSE);
if(!IS_LIBRARY(lib)) {
/* try basename only next */
lib=LOAD_LIBRARY(basename, basename, FALSE);
}
if(IS_LIBRARY(lib)) {
/* look for the entry point */
p=getChoice(lib, entryName, type, name, isAcceptable, context, &errorCode);
if(p==NULL) {
*pErrorCode=errorCode;
UNLOAD_LIBRARY(lib);
}
}
}
/* return the data if found */
if(p!=NULL) {
# ifndef UDATA_INDIRECT
/* for direct mappings, Library==UDataMemory==MappedData */
return (UDataMemory *)lib;
# else
UDataMemory *pData;
# ifdef UDATA_MAP
if(IS_LIBRARY(lib)) {
/* for mapped files, Library==UDataMemory */
pData=(UDataMemory *)lib;
pData->p=p;
return pData;
}
# endif
/* allocate the data structure */
pData=(UDataMemory *)icu_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) */
icu_memset(pData, 0, sizeof(pData));
# endif
pData->p=p;
return pData;
# endif
}
/* data not found */
if(U_SUCCESS(*pErrorCode)) {
*pErrorCode=U_FILE_ACCESS_ERROR;
}
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;
}