Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

udata.c

00001 /*
00002 *******************************************************************************
00003 *
00004 *   Copyright (C) 1999-2000, International Business Machines
00005 *   Corporation and others.  All Rights Reserved.
00006 *
00007 *******************************************************************************
00008 *   file name:  udata.c
00009 *   encoding:   US-ASCII
00010 *   tab size:   8 (not used)
00011 *   indentation:4
00012 *
00013 *   created on: 1999oct25
00014 *   created by: Markus W. Scherer
00015 */
00016 
00017 #include "unicode/utypes.h"
00018 #include "unicode/putil.h"
00019 #include "umutex.h"
00020 #include "cmemory.h"
00021 #include "cstring.h"
00022 #include "unicode/udata.h"
00023 
00024 /* configuration ------------------------------------------------------------ */
00025 
00026 #if !defined(HAVE_DLOPEN)
00027 # define HAVE_DLOPEN 0
00028 #endif
00029  
00030 #if !defined(UDATA_DLL) && !defined(UDATA_MAP)
00031 #   define UDATA_DLL
00032 #endif
00033 
00034 #define COMMON_DATA_NAME U_ICUDATA_NAME
00035 #define COMMON_DATA_NAME_LENGTH 8
00036 /* Tests must verify that it remains 8 characters. */
00037 
00038 #define DATA_TYPE "dat"
00039 
00040 /* If you are excruciatingly bored turn this on .. */
00041 /* #define UDATA_DEBUG 1 */
00042 
00043 #if defined(UDATA_DEBUG)
00044 #   include <stdio.h>
00045 #endif
00046 
00047 /* DLL/shared library base functions ---------------------------------------- */
00048 
00049 #ifdef WIN32
00050 #   include <windows.h>
00051 
00052     typedef HINSTANCE Library;
00053 
00054 #   define LIB_SUFFIX ".dll"
00055 
00056 #   define NO_LIBRARY NULL
00057 #   define IS_LIBRARY(lib) ((lib)!=NULL)
00058 #   define LOAD_LIBRARY(path, basename) LoadLibrary(path)
00059 #   define UNLOAD_LIBRARY(lib) FreeLibrary(lib)
00060 
00061 #   define GET_LIBRARY_ENTRY(lib, entryName) GetProcAddress(lib, entryName)
00062 
00063 #elif HAVE_DLOPEN  /* POSIX-y shared library environment. dlopen() or equivalent.. */
00064 #   ifndef UDATA_SO_SUFFIX
00065 #       error Please define UDATA_SO_SUFFIX to the shlib suffix (i.e. '.so' )
00066 #   endif
00067 
00068 #   define LIB_PREFIX "lib"
00069 #   define LIB_PREFIX_LENGTH 3
00070 #   define LIB_SUFFIX UDATA_SO_SUFFIX
00071 
00072 #   ifdef ICU_USE_SHL_LOAD  /* Some sort of compatibility stub:
00073                              * HPUX shl_load
00074                              * OS390 dllload */
00075 
00076 #       define  RTLD_LAZY 0
00077 #       define  RTLD_GLOBAL 0
00078 
00079 #       ifdef OS390
00080 #           include <dll.h>
00081 
00082 #           define  RTLD_LAZY 0
00083 #           define  RTLD_GLOBAL 0
00084 
00085             void *dlopen(const char *filename, int flag) {
00086                 dllhandle *handle; 
00087 
00088 #               ifdef UDATA_DEBUG
00089                     fprintf(stderr, "dllload: %s ", filename);
00090 #               endif
00091                 handle=dllload(filename);
00092 #               ifdef UDATA_DEBUG
00093                     fprintf(stderr, " -> %08X\n", handle );
00094 #               endif
00095                     return handle;
00096             }
00097 
00098             void *dlsym(void *h, const char *symbol) {
00099                 void *val=0;
00100                 val=dllqueryvar((dllhandle*)h,symbol);
00101 #               ifdef UDATA_DEBUG
00102                     fprintf(stderr, "dllqueryvar(%08X, %s) -> %08X\n", h, symbol, val);
00103 #               endif
00104                 return val;
00105             }
00106 
00107             int dlclose(void *handle) {
00108 #               ifdef UDATA_DEBUG
00109                     fprintf(stderr, "dllfree: %08X\n", handle);
00110 #               endif
00111                 return dllfree((dllhandle*)handle);
00112             }
00113 #       else /* not OS390:  HPUX shl_load  */
00114 #           include <dl.h>
00115 
00116             void *dlopen (const char *filename, int flag) {
00117                     void *handle; /* real type: 'shl_t' */
00118 #               ifdef UDATA_DEBUG
00119                         fprintf(stderr, "shl_load: %s ", filename);
00120 #               endif
00121                     handle=shl_load(filename, BIND_NONFATAL | BIND_DEFERRED | DYNAMIC_PATH, 0L);
00122 #               ifdef UDATA_DEBUG
00123                         fprintf(stderr, " -> %08X\n", handle );
00124 #               endif
00125                     return handle;
00126             }
00127 
00128             void *dlsym(void *h, char *symbol) {
00129                     void *val=0;
00130                     int rv;
00131                     shl_t mysh;
00132 
00133                     mysh=(shl_t)h; /* real type */
00134 
00135                     rv=shl_findsym(&mysh, symbol, TYPE_DATA, (void*)&val);
00136 #               ifdef UDATA_DEBUG
00137                     fprintf(stderr, "shl_findsym(%08X, %s) -> %08X [%d]\n", h, symbol, val, rv);
00138 #               endif
00139                     return val;
00140             }
00141 
00142             int dlclose (void *handle) {
00143 #  ifndef HPUX
00144 #               ifdef UDATA_DEBUG
00145                     fprintf(stderr, "shl_unload: %08X\n", handle);
00146 #               endif
00147                     return shl_unload((shl_t)handle);
00148 #  else
00149                     /* "shl_unload .. always unloads the library.. no refcount is kept on PA32"  
00150                        -- HPUX man pages [v. 11] 
00151 
00152                        Fine, we'll leak! [for now.. Jitterbug 414 has been filed ]
00153                     */
00154                     return 0;
00155 #  endif /* HPUX */
00156             }
00157 #       endif /* HPUX shl_load */
00158 #   else /* not ICU_USE_SHL_LOAD */
00159         /* 'de facto standard' dlopen etc. */
00160 #       include <dlfcn.h>
00161 #ifndef RTLD_GLOBAL
00162 #define RTLD_GLOBAL 0
00163 #endif
00164 #   endif
00165 
00166     typedef void *Library;
00167 
00168 #   define NO_LIBRARY NULL
00169 #   define IS_LIBRARY(lib) ((lib)!=NULL)
00170 
00171 
00172 #ifndef UDATA_DEBUG
00173 #   define LOAD_LIBRARY(path, basename) dlopen(path, RTLD_LAZY|RTLD_GLOBAL)
00174 #   define UNLOAD_LIBRARY(lib) dlclose(lib)
00175 #   define GET_LIBRARY_ENTRY(lib, entryName) dlsym(lib, entryName)
00176 #else
00177   void *LOAD_LIBRARY(const char *path, const char *basename)
00178   {
00179     void *rc;
00180     rc = dlopen(path, RTLD_LAZY|RTLD_GLOBAL);
00181     fprintf(stderr, "Load [%s|%s] -> %p\n", path, basename, rc);
00182     return rc;
00183   }
00184   void  UNLOAD_LIBRARY(void *lib)
00185   {
00186     dlclose(lib);
00187     fprintf(stderr, "Unload [%p]\n", lib);
00188   }
00189   void * GET_LIBRARY_ENTRY(void *lib, const char *entryName)
00190   {
00191     void *rc;
00192     rc = dlsym(lib, entryName);
00193     fprintf(stderr, "Get[%p] %s->%p\n", lib, entryName, rc);
00194     return rc;
00195   }
00196 #endif
00197   /* End of dlopen or compatible functions */
00198 
00199 #else /* unknown platform, no DLL implementation */
00200 #   ifndef UDATA_NO_DLL
00201 #       define UDATA_NO_DLL 1
00202 #   endif
00203     typedef const void *Library;
00204 
00205 #   define NO_LIBRARY NULL
00206 #   define IS_LIBRARY(lib) ((lib)!=NULL)
00207 #   define LOAD_LIBRARY(path, basename) NULL
00208 #   define UNLOAD_LIBRARY(lib) ;
00209 
00210 #   define GET_LIBRARY_ENTRY(lib, entryName) NULL
00211 
00212 #endif
00213 
00214 /* memory-mapping base definitions ------------------------------------------ */
00215 
00216 /* we need these definitions before the common ones because
00217    MemoryMap is a field of UDataMemory;
00218    however, the mapping functions use UDataMemory,
00219    therefore they are defined later
00220  */
00221 
00222 #define MAP_WIN32 1
00223 #define MAP_POSIX 2
00224 #define MAP_FILE_STREAM 3
00225 
00226 #ifdef WIN32
00227     typedef HANDLE MemoryMap;
00228 
00229 #   define NO_MAP NULL
00230 #   define IS_MAP(map) ((map)!=NULL)
00231 
00232 #   define MAP_IMPLEMENTATION MAP_WIN32
00233 
00234 /* ### Todo: auto detect mmap(). Until then, just add your platform here. */
00235 #elif HAVE_MMAP || defined(U_LINUX) || defined(POSIX) || defined(U_SOLARIS) || defined(AIX) || defined(HPUX) || defined(OS390) || defined(PTX)
00236     typedef size_t MemoryMap;
00237 
00238 #   define NO_MAP 0
00239 #   define IS_MAP(map) ((map)!=0)
00240 
00241 #   include <unistd.h>
00242 #   include <sys/mman.h>
00243 #   include <sys/stat.h>
00244 #   include <fcntl.h>
00245 
00246 #   ifndef MAP_FAILED
00247 #       define MAP_FAILED ((void*)-1)
00248 #   endif
00249 
00250 #   define MAP_IMPLEMENTATION MAP_POSIX
00251 
00252 #else /* unknown platform, no memory map implementation: use FileStream/uprv_malloc() instead */
00253 
00254 #   include "filestrm.h"
00255 
00256     typedef void *MemoryMap;
00257 
00258 #   define NO_MAP NULL
00259 #   define IS_MAP(map) ((map)!=NULL)
00260 
00261 #   define MAP_IMPLEMENTATION MAP_FILE_STREAM
00262 
00263 #endif
00264 
00265 /* common definitions ------------------------------------------------------- */
00266 
00267 /* constants for UDataMemory flags: type of data memory */
00268 enum {
00269     NO_DATA_MEMORY,
00270     FLAT_DATA_MEMORY,
00271     DLL_DATA_MEMORY
00272 };
00273 
00274 /* constants for UDataMemory flags: type of TOC */
00275 enum {
00276     NO_TOC,
00277     OFFSET_TOC,
00278     POINTER_TOC,
00279     DLL_INTRINSIC_TOC
00280 };
00281 
00282 /* constants for UDataMemory flags: type of TOC */
00283 #define DATA_MEMORY_TYPE_MASK 0xf
00284 #define TOC_TYPE_SHIFT 4
00285 #define TOC_TYPE_MASK 0xf
00286 #define SET_DATA_POINTER_SHIFT 30
00287 #define DYNAMIC_DATA_MEMORY_SHIFT 31
00288 
00289 typedef struct {
00290     uint16_t headerSize;
00291     uint8_t magic1, magic2;
00292 } MappedData;
00293 
00294 typedef struct {
00295     MappedData dataHeader;
00296     UDataInfo info;
00297 } DataHeader;
00298 
00299 typedef const DataHeader *
00300 LookupFn(const UDataMemory *pData,
00301          const char *tocEntryName,
00302          const char *dllEntryName,
00303          UErrorCode *pErrorCode);
00304 
00305 struct UDataMemory {
00306     UDataMemory *parent;
00307     Library lib;
00308     MemoryMap map;
00309     LookupFn *lookupFn;
00310     const void *toc;
00311     const DataHeader *pHeader;
00312     uint32_t flags;
00313     int32_t refCount;
00314 };
00315 
00316 #define IS_DATA_MEMORY_LOADED(pData) ((pData)->flags!=0)
00317 
00318 typedef struct {
00319     const char *entryName;
00320     const DataHeader *pHeader;
00321 } PointerTOCEntry;
00322 
00323 /* memory-mapping base functions -------------------------------------------- */
00324 
00325 #if MAP_IMPLEMENTATION==MAP_WIN32
00326     static UBool
00327     uprv_mapFile(UDataMemory *pData, const char *path, const char *basename) {
00328         char buffer[200];
00329         HANDLE map;
00330                 char *p;
00331 
00332         /* set up the mapping name and the filename */
00333         uprv_strcpy(buffer, "icu" U_ICU_VERSION " ");
00334         uprv_strcat(buffer, path);
00335         
00336                 /* replace in buffer \ with /   */
00337                 for(p=buffer; *p; p++) {
00338                         if (*p == '\\') {
00339                                 *p = '/';
00340                         }
00341                 }
00342 
00343         /* open the mapping */
00344         map=OpenFileMapping(FILE_MAP_READ, FALSE, buffer);
00345         if(map==NULL) {
00346             /* the mapping has not been created */
00347             HANDLE file;
00348 
00349             /* open the input file */
00350             file=CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL,
00351                             OPEN_EXISTING,
00352                             FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL);
00353             if(file==INVALID_HANDLE_VALUE) {
00354                 return FALSE;
00355             }
00356 
00357             /* create the mapping */
00358             map=CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, buffer);
00359             CloseHandle(file);
00360             if(map==NULL) {
00361                 return FALSE;
00362             }
00363         }
00364 
00365         /* get a view of the mapping */
00366         pData->pHeader=(const DataHeader *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
00367         if(pData->pHeader==NULL) {
00368             CloseHandle(map);
00369             return FALSE;
00370         }
00371         pData->map=map;
00372         pData->flags=FLAT_DATA_MEMORY;
00373         return TRUE;
00374     }
00375 
00376     static void
00377     uprv_unmapFile(UDataMemory *pData) {
00378         if(pData!=NULL && pData->map!=NULL) {
00379             UnmapViewOfFile(pData->pHeader);
00380             CloseHandle(pData->map);
00381             pData->pHeader=NULL;
00382             pData->map=NULL;
00383         }
00384     }
00385 
00386 #elif MAP_IMPLEMENTATION==MAP_POSIX
00387     static UBool
00388     uprv_mapFile(UDataMemory *pData, const char *path, const char *basename) {
00389         int fd;
00390         int length;
00391         const char *dataDir;
00392         struct stat mystat;
00393         const void *data;
00394 
00395         /* determine the length of the file */
00396         if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
00397             return FALSE;
00398         }
00399         length=mystat.st_size;
00400 
00401         /* open the file */
00402         fd=open(path, O_RDONLY);
00403         if(fd==-1) {
00404             return FALSE;
00405         }
00406 
00407         /* get a view of the mapping */
00408 #ifndef HPUX
00409         data=mmap(0, length, PROT_READ, MAP_SHARED,  fd, 0);
00410 #else
00411         data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0);
00412 #endif
00413         close(fd); /* no longer needed */
00414         if(data==MAP_FAILED) {
00415 
00416 #       ifdef UDATA_DEBUG
00417               perror("mmap");
00418 #       endif
00419 
00420             return FALSE;
00421         }
00422 
00423 #       ifdef UDATA_DEBUG
00424             fprintf(stderr, "mmap of %s [%d bytes] succeeded, -> 0x%X\n", path, length, data);
00425             fflush(stderr);
00426 #       endif
00427     
00428         pData->map=length;
00429         pData->pHeader=(const DataHeader *)data;
00430         pData->flags=FLAT_DATA_MEMORY;
00431         return TRUE;
00432     }
00433 
00434     static void
00435     uprv_unmapFile(UDataMemory *pData) {
00436         if(pData!=NULL && pData->map>0) {
00437             if(munmap((void *)pData->pHeader, pData->map)==-1) {
00438 #               ifdef UDATA_DEBUG
00439                     perror("munmap");
00440 #               endif
00441             }
00442             pData->pHeader=NULL;
00443             pData->map=0;
00444         }
00445     }
00446 
00447 #elif MAP_IMPLEMENTATION==MAP_FILE_STREAM
00448     static UBool
00449     uprv_mapFile(UDataMemory *pData, const char *path, const char *basename) {
00450         FileStream *file;
00451         int32_t fileLength;
00452         void *p;
00453 
00454         /* open the input file */
00455         file=T_FileStream_open(path, "rb");
00456         if(file==NULL) {
00457             return FALSE;
00458         }
00459 
00460         /* get the file length */
00461         fileLength=T_FileStream_size(file);
00462         if(T_FileStream_error(file) || fileLength<=20) {
00463             T_FileStream_close(file);
00464             return FALSE;
00465         }
00466 
00467         /* allocate the data structure */
00468         p=uprv_malloc(fileLength);
00469         if(p==NULL) {
00470             T_FileStream_close(file);
00471             return FALSE;
00472         }
00473 
00474         /* read the file */
00475         if(fileLength!=T_FileStream_read(file, p, fileLength)) {
00476             uprv_free(p);
00477             T_FileStream_close(file);
00478             return FALSE;
00479         }
00480 
00481         T_FileStream_close(file);
00482         pData->map=p;
00483         pData->pHeader=(const DataHeader *)p;
00484         pData->flags=FLAT_DATA_MEMORY;
00485         return TRUE;
00486     }
00487 
00488     static void
00489     uprv_unmapFile(UDataMemory *pData) {
00490         if(pData!=NULL && pData->map!=NULL) {
00491             uprv_free(pData->map);
00492             pData->map=NULL;
00493         }
00494     }
00495 
00496 #else
00497 #   error MAP_IMPLEMENTATION is set incorrectly
00498 #endif
00499 
00500 /* entry point lookup implementations --------------------------------------- */
00501 
00502 static const DataHeader *
00503 normalizeDataPointer(const DataHeader *p) {
00504     /* allow the data to be optionally prepended with an alignment-forcing double value */
00505     if(p==NULL || (p->dataHeader.magic1==0xda && p->dataHeader.magic2==0x27)) {
00506         return p;
00507     } else {
00508         return (const DataHeader *)((const double *)p+1);
00509     }
00510 }
00511 
00512 static const DataHeader *
00513 offsetTOCLookupFn(const UDataMemory *pData,
00514                   const char *tocEntryName,
00515                   const char *dllEntryName,
00516                   UErrorCode *pErrorCode) {
00517 #ifdef UDATA_DEBUG
00518   fprintf(stderr, "offsetTOC[%p] looking for %s/%s\n",
00519           pData,
00520           tocEntryName,dllEntryName);
00521 #endif
00522 
00523     if(pData->toc!=NULL) {
00524         const char *base=(const char *)pData->toc;
00525         uint32_t *toc=(uint32_t *)pData->toc;
00526         uint32_t start, limit, number;
00527 
00528         /* perform a binary search for the data in the common data's table of contents */
00529         start=0;
00530         limit=*toc++;   /* number of names in this table of contents */
00531         while(start<limit-1) {
00532             number=(start+limit)/2;
00533             if(uprv_strcmp(tocEntryName, base+toc[2*number])<0) {
00534                 limit=number;
00535             } else {
00536                 start=number;
00537             }
00538         }
00539 
00540         if(uprv_strcmp(tocEntryName, base+toc[2*start])==0) {
00541             /* found it */
00542 #ifdef UDATA_DEBUG
00543           fprintf(stderr, "Found: %p\n",(base+toc[2*start+1]));
00544 #endif
00545             return (const DataHeader *)(base+toc[2*start+1]);
00546         } else {
00547 #ifdef UDATA_DEBUG
00548           fprintf(stderr, "Not found.\n");
00549 #endif
00550             return NULL;
00551         }
00552     } else {
00553 #ifdef UDATA_DEBUG
00554       fprintf(stderr, "returning header\n");
00555 #endif
00556 
00557         return pData->pHeader;
00558     }
00559 }
00560 
00561 static const DataHeader *
00562 pointerTOCLookupFn(const UDataMemory *pData,
00563                    const char *tocEntryName,
00564                    const char *dllEntryName,
00565                    UErrorCode *pErrorCode) {
00566 #ifdef UDATA_DEBUG
00567   fprintf(stderr, "ptrTOC[%p] looking for %s/%s\n",
00568           pData,
00569           tocEntryName,dllEntryName);
00570 #endif
00571     if(pData->toc!=NULL) {
00572         const PointerTOCEntry *toc=(const PointerTOCEntry *)((const uint32_t *)pData->toc+2);
00573         uint32_t start, limit, number;
00574 
00575         /* perform a binary search for the data in the common data's table of contents */
00576         start=0;
00577         limit=*(const uint32_t *)pData->toc; /* number of names in this table of contents */
00578 
00579 #ifdef UDATA_DEBUG
00580         fprintf(stderr, "  # of ents: %d\n", limit);
00581         fflush(stderr);
00582 #endif
00583 
00584         while(start<limit-1) {
00585             number=(start+limit)/2;
00586             if(uprv_strcmp(tocEntryName, toc[number].entryName)<0) {
00587                 limit=number;
00588             } else {
00589                 start=number;
00590             }
00591         }
00592 
00593         if(uprv_strcmp(tocEntryName, toc[start].entryName)==0) {
00594             /* found it */
00595 #ifdef UDATA_DEBUG
00596           fprintf(stderr, "FOUND: %p\n", 
00597                   normalizeDataPointer(toc[start].pHeader));
00598 #endif
00599 
00600              return normalizeDataPointer(toc[start].pHeader);
00601         } else {
00602 #ifdef UDATA_DEBUG
00603           fprintf(stderr, "NOT found\n");
00604 #endif
00605             return NULL;
00606         }
00607     } else {
00608 #ifdef UDATA_DEBUG
00609          fprintf(stderr, "Returning header\n");
00610 #endif
00611          return pData->pHeader;
00612     }
00613 }
00614 
00615 static const DataHeader *
00616 dllTOCLookupFn(const UDataMemory *pData,
00617                const char *tocEntryName,
00618                const char *dllEntryName,
00619                UErrorCode *pErrorCode) {
00620 #ifndef UDATA_NO_DLL
00621     if(pData->lib!=NULL) {
00622         return normalizeDataPointer((const DataHeader *)GET_LIBRARY_ENTRY(pData->lib, dllEntryName));
00623     }
00624 #endif
00625     return NULL;
00626 }
00627 
00628 /* common library functions ------------------------------------------------- */
00629 
00630  static UDataMemory commonICUData={ NULL }; 
00631 
00632 static void
00633 setCommonICUData(UDataMemory *pData) {
00634     UBool setThisLib=FALSE;
00635 
00636     /* in the mutex block, set the common library for this process */
00637     umtx_lock(NULL);
00638     if(!IS_DATA_MEMORY_LOADED(&commonICUData)) {
00639         uprv_memcpy(&commonICUData, pData, sizeof(UDataMemory));
00640         commonICUData.flags&=~(1UL<<DYNAMIC_DATA_MEMORY_SHIFT);
00641         uprv_memset(pData, 0, sizeof(UDataMemory));
00642         setThisLib=TRUE;
00643     }
00644     umtx_unlock(NULL);
00645 
00646     /* if a different thread set it first, then free the extra library instance */
00647     if(!setThisLib) {
00648         udata_close(pData);
00649     }
00650 }
00651 
00652 static char *
00653 strcpy_returnEnd(char *dest, const char *src) {
00654     while((*dest=*src)!=0) {
00655         ++dest;
00656         ++src;
00657     }
00658     return dest;
00659 }
00660 
00661 static char *
00662 setPathGetBasename(const char *path, char *pathBuffer) {
00663     /* set up the path in the pathBuffer and return a pointer behind its end,
00664        to where the basename will go */
00665     if(*pathBuffer!=0) {
00666         /* the pathBuffer is already filled,
00667            we just need to find the basename position;
00668            assume that the last filling function removed the basename from the buffer */
00669         return pathBuffer+uprv_strlen(pathBuffer);
00670     } else if(path==NULL) {
00671         /* copy the ICU_DATA path to the path buffer */
00672         path=u_getDataDirectory();
00673         if(path!=NULL && *path!=0) {
00674             return strcpy_returnEnd(pathBuffer, path);
00675         } else {
00676             /* there is no path */
00677             return pathBuffer;
00678         }
00679     } else {
00680         /* find the last file sepator in the input path */
00681         char *basename=uprv_strrchr(path, U_FILE_SEP_CHAR);
00682         if(basename==NULL) {
00683             /* copy the ICU_DATA path to the path buffer */
00684             path=u_getDataDirectory();
00685             if(path!=NULL && *path!=0) {
00686                 return strcpy_returnEnd(pathBuffer, path);
00687             } else {
00688                 /* there is no path */
00689                 return pathBuffer;
00690             }
00691         } else {
00692             /* copy the path to the path buffer */
00693             ++basename;
00694             uprv_memcpy(pathBuffer, path, basename-path);
00695             basename=pathBuffer+(basename-path);
00696             *basename=0;
00697             return basename;
00698         }
00699     }
00700 }
00701 
00702 static const char *
00703 findBasename(const char *path) {
00704     const char *basename=uprv_strrchr(path, U_FILE_SEP_CHAR);
00705     if(basename==NULL) {
00706         return path;
00707     } else {
00708         return basename+1;
00709     }
00710 }
00711 
00712 static UDataMemory *
00713 openCommonData(UDataMemory *pData,
00714                const char *path, UBool isICUData,
00715                char *pathBuffer,
00716                UErrorCode *pErrorCode) {
00717 #   if !UDATA_NO_DLL
00718         Library lib;
00719 #   endif
00720     const char *inBasename;
00721     char *basename, *suffix;
00722 
00723     /* "mini-cache" for common ICU data */
00724     if(isICUData && IS_DATA_MEMORY_LOADED(&commonICUData)) {
00725         return &commonICUData;
00726     }
00727 
00728     /* ### we should have a real cache with a UHashTable and the path as the key */
00729 
00730     /* set up path and basename */
00731     basename=setPathGetBasename(path, pathBuffer);
00732     if(isICUData) {
00733         inBasename=COMMON_DATA_NAME;
00734     } else {
00735         inBasename=findBasename(path);
00736         if(*inBasename==0) {
00737             /* no basename, no common data */
00738             *pErrorCode=U_FILE_ACCESS_ERROR;
00739             return NULL;
00740         }
00741     }
00742 
00743     /* try to load a common data DLL */
00744 #   if !UDATA_NO_DLL
00745         /* set up the library name */
00746 #       ifndef LIB_PREFIX
00747             suffix=strcpy_returnEnd(basename, inBasename);
00748 #       else
00749             uprv_memcpy(basename, LIB_PREFIX, LIB_PREFIX_LENGTH);
00750             suffix=strcpy_returnEnd(basename+LIB_PREFIX_LENGTH, inBasename);
00751 #       endif
00752         uprv_strcpy(suffix, LIB_SUFFIX);
00753 
00754         /* try path/basename first */
00755 #       ifdef OS390BATCH
00756             /* ### hack: we still need to get u_getDataDirectory() fixed
00757                for OS/390 (batch mode - always return "//"? )
00758                and this here straightened out with LIB_PREFIX and LIB_SUFFIX (both empty?!) */
00759             lib=LOAD_LIBRARY("//" U_ICUDATA_NAME, "//" U_ICUDATA_NAME);
00760 #       else
00761             lib=LOAD_LIBRARY(pathBuffer, basename);
00762 #       endif
00763         if(!IS_LIBRARY(lib) && basename!=pathBuffer) {
00764             /* try basename only next */
00765             lib=LOAD_LIBRARY(basename, basename);
00766         }
00767 
00768         if(IS_LIBRARY(lib)) {
00769             /* we have a data DLL - what kind of lookup do we need here? */
00770             char entryName[100];
00771             const DataHeader *pHeader;
00772             *basename=0;
00773 
00774             /* try to find the Table of Contents */
00775             uprv_strcpy(entryName, inBasename);
00776             uprv_strcat(entryName, "_" DATA_TYPE);
00777             pHeader=normalizeDataPointer((const DataHeader *)GET_LIBRARY_ENTRY(lib, entryName));
00778             if(pHeader==NULL) {
00779                 /* no TOC: assume DLL-intrinsic lookup */
00780                 pData->lib=lib;
00781                 pData->lookupFn=dllTOCLookupFn;
00782                 pData->flags=DLL_DATA_MEMORY|DLL_INTRINSIC_TOC<<TOC_TYPE_SHIFT;
00783             } else if(!(pHeader->dataHeader.magic1==0xda && pHeader->dataHeader.magic2==0x27 &&
00784                         pHeader->info.isBigEndian==U_IS_BIG_ENDIAN &&
00785                         pHeader->info.charsetFamily==U_CHARSET_FAMILY)
00786             ) {
00787                 /* header not valid */
00788                 UNLOAD_LIBRARY(lib);
00789                 *pErrorCode=U_INVALID_FORMAT_ERROR;
00790                 return NULL;
00791 
00792                 /* which TOC type? */
00793             } else if(pHeader->info.dataFormat[0]==0x43 &&
00794                       pHeader->info.dataFormat[1]==0x6d &&
00795                       pHeader->info.dataFormat[2]==0x6e &&
00796                       pHeader->info.dataFormat[3]==0x44 &&
00797                       pHeader->info.formatVersion[0]==1
00798             ) {
00799                 /* dataFormat="CmnD" */
00800                 pData->lib=lib;
00801                 pData->lookupFn=offsetTOCLookupFn;
00802                 pData->toc=(const char *)pHeader+pHeader->dataHeader.headerSize;
00803                 pData->flags=DLL_DATA_MEMORY|OFFSET_TOC<<TOC_TYPE_SHIFT;
00804             } else if(pHeader->info.dataFormat[0]==0x54 &&
00805                       pHeader->info.dataFormat[1]==0x6f &&
00806                       pHeader->info.dataFormat[2]==0x43 &&
00807                       pHeader->info.dataFormat[3]==0x50 &&
00808                       pHeader->info.formatVersion[0]==1
00809             ) {
00810                 /* dataFormat="ToCP" */
00811                 pData->lib=lib;
00812                 pData->lookupFn=pointerTOCLookupFn;
00813                 pData->toc=(const char *)pHeader+pHeader->dataHeader.headerSize;
00814                 pData->flags=DLL_DATA_MEMORY|POINTER_TOC<<TOC_TYPE_SHIFT;
00815             } else {
00816                 /* dataFormat not recognized */
00817                 UNLOAD_LIBRARY(lib);
00818                 *pErrorCode=U_INVALID_FORMAT_ERROR;
00819                 return NULL;
00820             }
00821 
00822             /* we have common data from a DLL */
00823             if(isICUData) {
00824                 setCommonICUData(pData);
00825                 return &commonICUData;
00826             } else {
00827                 return pData;
00828             }
00829         }
00830 #   endif
00831 
00832     /* try to map a common data file */
00833 
00834     /* set up the file name */
00835     suffix=strcpy_returnEnd(basename, inBasename);
00836     uprv_strcpy(suffix, "." DATA_TYPE);
00837 
00838     /* try path/basename first, then basename only */
00839     if( uprv_mapFile(pData, pathBuffer, basename) ||
00840         (basename!=pathBuffer && uprv_mapFile(pData, basename, basename))
00841     ) {
00842         const DataHeader *pHeader;
00843         *basename=0;
00844 
00845         /* we have mapped a file, check its header */
00846         pHeader=pData->pHeader;
00847         if(!(pHeader->dataHeader.magic1==0xda && pHeader->dataHeader.magic2==0x27 &&
00848              pHeader->info.isBigEndian==U_IS_BIG_ENDIAN &&
00849              pHeader->info.charsetFamily==U_CHARSET_FAMILY &&
00850              pHeader->info.dataFormat[0]==0x43 &&
00851              pHeader->info.dataFormat[1]==0x6d &&
00852              pHeader->info.dataFormat[2]==0x6e &&
00853              pHeader->info.dataFormat[3]==0x44 &&
00854              pHeader->info.formatVersion[0]==1)
00855         ) {
00856             uprv_unmapFile(pData);
00857             pData->flags=0;
00858             *pErrorCode=U_INVALID_FORMAT_ERROR;
00859             return NULL;
00860         }
00861 
00862         /* we have common data from a mapped file */
00863         pData->lookupFn=offsetTOCLookupFn;
00864         pData->toc=(const char *)pHeader+pHeader->dataHeader.headerSize;
00865         pData->flags|=OFFSET_TOC<<TOC_TYPE_SHIFT;
00866         if(isICUData) {
00867             setCommonICUData(pData);
00868             return &commonICUData;
00869         } else {
00870             return pData;
00871         }
00872     }
00873 
00874     /* cleanup for the caller, to keep setPathGetBasename() consistent */
00875     *basename=0;
00876 
00877     /* no common data */
00878     *pErrorCode=U_FILE_ACCESS_ERROR;
00879     return NULL;
00880 }
00881 
00882 U_CAPI void U_EXPORT2
00883 udata_setCommonData(const void *data, UErrorCode *pErrorCode) {
00884     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
00885         return;
00886     }
00887 
00888     if(data==NULL) {
00889         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
00890         return;
00891     }
00892 
00893     /* do we already have common ICU data set? */
00894     if(IS_DATA_MEMORY_LOADED(&commonICUData)) {
00895         *pErrorCode=U_USING_DEFAULT_ERROR;
00896         return;
00897     } else {
00898         /* normalize the data pointer and test for validity */
00899         UDataMemory dataMemory={ NULL };
00900         const DataHeader *pHeader=normalizeDataPointer((const DataHeader *)data);
00901         if(!(pHeader->dataHeader.magic1==0xda && pHeader->dataHeader.magic2==0x27 &&
00902              pHeader->info.isBigEndian==U_IS_BIG_ENDIAN &&
00903              pHeader->info.charsetFamily==U_CHARSET_FAMILY)
00904         ) {
00905             /* header not valid */
00906             *pErrorCode=U_INVALID_FORMAT_ERROR;
00907             return;
00908 
00909             /* which TOC type? */
00910         } else if(pHeader->info.dataFormat[0]==0x43 &&
00911                   pHeader->info.dataFormat[1]==0x6d &&
00912                   pHeader->info.dataFormat[2]==0x6e &&
00913                   pHeader->info.dataFormat[3]==0x44 &&
00914                   pHeader->info.formatVersion[0]==1
00915         ) {
00916             /* dataFormat="CmnD" */
00917             dataMemory.lookupFn=offsetTOCLookupFn;
00918             dataMemory.toc=(const char *)pHeader+pHeader->dataHeader.headerSize;
00919             dataMemory.flags=DLL_DATA_MEMORY|OFFSET_TOC<<TOC_TYPE_SHIFT;
00920         } else if(pHeader->info.dataFormat[0]==0x54 &&
00921                   pHeader->info.dataFormat[1]==0x6f &&
00922                   pHeader->info.dataFormat[2]==0x43 &&
00923                   pHeader->info.dataFormat[3]==0x50 &&
00924                   pHeader->info.formatVersion[0]==1
00925         ) {
00926             /* dataFormat="ToCP" */
00927             dataMemory.lookupFn=pointerTOCLookupFn;
00928             dataMemory.toc=(const char *)pHeader+pHeader->dataHeader.headerSize;
00929             dataMemory.flags=DLL_DATA_MEMORY|POINTER_TOC<<TOC_TYPE_SHIFT;
00930         } else {
00931             /* dataFormat not recognized */
00932             *pErrorCode=U_INVALID_FORMAT_ERROR;
00933             return;
00934         }
00935 
00936         /* we have common data */
00937         dataMemory.flags|=1UL<<SET_DATA_POINTER_SHIFT;
00938         setCommonICUData(&dataMemory);
00939         if(dataMemory.flags!=0) {
00940             /* some thread passed us */
00941             *pErrorCode=U_USING_DEFAULT_ERROR;
00942         }
00943     }
00944 }
00945 
00946 /* main data loading function ----------------------------------------------- */
00947 
00948 static void
00949 setEntryNames(const char *type, const char *name,
00950               char *tocEntryName, char *dllEntryName) {
00951     while(*name!=0) {
00952         *tocEntryName=*name;
00953         if(*name=='.' || *name=='-') {
00954             *dllEntryName='_';
00955         } else {
00956             *dllEntryName=*name;
00957         }
00958         ++tocEntryName;
00959         ++dllEntryName;
00960         ++name;
00961     }
00962 
00963     if(type!=NULL && *type!=0) {
00964         *tocEntryName++='.';
00965         *dllEntryName++='_';
00966         do {
00967             *tocEntryName++=*dllEntryName++=*type++;
00968         } while(*type!=0);
00969     }
00970 
00971     *tocEntryName=*dllEntryName=0;
00972 }
00973 
00974 static UDataMemory *
00975 doOpenChoice(const char *path, const char *type, const char *name,
00976              UDataMemoryIsAcceptable *isAcceptable, void *context,
00977              UErrorCode *pErrorCode) {
00978     char pathBuffer[1024];
00979     char tocEntryName[100], dllEntryName[100];
00980     UDataMemory dataMemory;
00981     UDataMemory *pCommonData, *pEntryData;
00982     const DataHeader *pHeader;
00983     const char *inBasename;
00984     char *basename, *suffix;
00985     UErrorCode errorCode=U_ZERO_ERROR;
00986     UBool isICUData= (UBool)(path==NULL);
00987 
00988     /* set up the ToC names for DLL and offset-ToC lookups */
00989     setEntryNames(type, name, tocEntryName, dllEntryName);
00990 
00991     /* try to get common data */
00992     uprv_memset(&dataMemory, 0, sizeof(UDataMemory));
00993     pathBuffer[0]=0;
00994     pCommonData=openCommonData(&dataMemory, path, isICUData, pathBuffer, &errorCode);
00995 #ifdef UDATA_DEBUG
00996     fprintf(stderr, "commonData;%p\n", pCommonData);
00997     fflush(stderr);
00998 #endif
00999 
01000     if(U_SUCCESS(errorCode)) {
01001         /* look up the data piece in the common data */
01002         pHeader=pCommonData->lookupFn(pCommonData, tocEntryName, dllEntryName, &errorCode);
01003 #ifdef UDATA_DEBUG
01004         fprintf(stderr, "Common found: %p\n", pHeader);
01005 #endif
01006         if(pHeader!=NULL) {
01007             /* data found in the common data, test it */
01008             if(pHeader->dataHeader.magic1==0xda && pHeader->dataHeader.magic2==0x27 &&
01009                pHeader->info.isBigEndian==U_IS_BIG_ENDIAN &&
01010                (isAcceptable==NULL || isAcceptable(context, type, name, &pHeader->info))
01011             ) {
01012                 /* acceptable - allocate parent, too, if necessary */
01013                 if(pCommonData==&dataMemory) {
01014                     /* trick: do one malloc for both the common and the entry */
01015                     pEntryData=(UDataMemory *)uprv_malloc(2*sizeof(UDataMemory));
01016                     if(pEntryData!=NULL) {
01017                         pCommonData=pEntryData+1;
01018                         uprv_memcpy(pCommonData, &dataMemory, sizeof(UDataMemory));
01019                     }
01020                 } else {
01021                     pEntryData=(UDataMemory *)uprv_malloc(sizeof(UDataMemory));
01022                 }
01023                 if(pEntryData==NULL) {
01024                     *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
01025                     return NULL;
01026                 }
01027                 uprv_memset(pEntryData, 0, sizeof(UDataMemory));
01028                 pEntryData->parent=pCommonData;
01029                 pEntryData->pHeader=pHeader;
01030                 pEntryData->flags=(pCommonData->flags&DATA_MEMORY_TYPE_MASK)|1UL<<DYNAMIC_DATA_MEMORY_SHIFT;
01031 #ifdef UDATA_DEBUG
01032                 fprintf(stderr, " made data @%p\n", pEntryData);
01033 #endif
01034                 return pEntryData;
01035             } else {
01036                 /* the data is not acceptable, look further */
01037 #ifdef UDATA_DEBUG
01038               fprintf(stderr, "Not acceptable\n");
01039 #endif
01040                 errorCode=U_INVALID_FORMAT_ERROR;
01041             }
01042         }
01043 
01044         /* the data is not in the common data, close that and look further */
01045         if(pCommonData==&dataMemory) {
01046             udata_close(&dataMemory);
01047         }
01048     }
01049 
01050     /* try to get an individual data file */
01051     basename=setPathGetBasename(path, pathBuffer);
01052     if(isICUData) {
01053         inBasename=COMMON_DATA_NAME;
01054     } else {
01055         inBasename=findBasename(path);
01056     }
01057 
01058 #ifdef UDATA_DEBUG
01059     fprintf(stderr, "looking for ind. file\n");
01060 #endif
01061 
01062     /* try path+basename+"_"+entryName first */
01063     if(*inBasename!=0) {
01064         suffix=strcpy_returnEnd(basename, inBasename);
01065         *suffix++='_';
01066         uprv_strcpy(suffix, tocEntryName);
01067 
01068         if( uprv_mapFile(&dataMemory, pathBuffer, basename) ||
01069             (basename!=pathBuffer && uprv_mapFile(&dataMemory, basename, basename))
01070         ) {
01071             pHeader=dataMemory.pHeader;
01072             if(pHeader->dataHeader.magic1==0xda && pHeader->dataHeader.magic2==0x27 &&
01073                pHeader->info.isBigEndian==U_IS_BIG_ENDIAN &&
01074                (isAcceptable==NULL || isAcceptable(context, type, name, &pHeader->info))
01075             ) {
01076                 /* acceptable */
01077                 pEntryData=(UDataMemory *)uprv_malloc(sizeof(UDataMemory));
01078                 if(pEntryData==NULL) {
01079                     uprv_unmapFile(&dataMemory);
01080                     *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
01081                     return NULL;
01082                 }
01083                 dataMemory.flags|=1UL<<DYNAMIC_DATA_MEMORY_SHIFT;
01084                 uprv_memcpy(pEntryData, &dataMemory, sizeof(UDataMemory));
01085                 return pEntryData;
01086             } else {
01087                 /* the data is not acceptable, look further */
01088                 uprv_unmapFile(&dataMemory);
01089                 errorCode=U_INVALID_FORMAT_ERROR;
01090             }
01091         }
01092     }
01093 
01094     /* try path+entryName next */
01095     uprv_strcpy(basename, tocEntryName);
01096     if( uprv_mapFile(&dataMemory, pathBuffer, basename) ||
01097         (basename!=pathBuffer && uprv_mapFile(&dataMemory, basename, basename))
01098     ) {
01099         pHeader=dataMemory.pHeader;
01100         if(pHeader->dataHeader.magic1==0xda && pHeader->dataHeader.magic2==0x27 &&
01101            pHeader->info.isBigEndian==U_IS_BIG_ENDIAN &&
01102            (isAcceptable==NULL || isAcceptable(context, type, name, &pHeader->info))
01103         ) {
01104             /* acceptable */
01105             pEntryData=(UDataMemory *)uprv_malloc(sizeof(UDataMemory));
01106             if(pEntryData==NULL) {
01107                 uprv_unmapFile(&dataMemory);
01108                 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
01109                 return NULL;
01110             }
01111             dataMemory.flags|=1UL<<DYNAMIC_DATA_MEMORY_SHIFT;
01112             uprv_memcpy(pEntryData, &dataMemory, sizeof(UDataMemory));
01113             return pEntryData;
01114         } else {
01115             /* the data is not acceptable, look further */
01116             uprv_unmapFile(&dataMemory);
01117             errorCode=U_INVALID_FORMAT_ERROR;
01118         }
01119     }
01120 
01121     /* data not found */
01122     if(U_SUCCESS(*pErrorCode)) {
01123         if(U_SUCCESS(errorCode)) {
01124             /* file not found */
01125             *pErrorCode=U_FILE_ACCESS_ERROR;
01126         } else {
01127             /* entry point not found or rejected */
01128             *pErrorCode=errorCode;
01129         }
01130     }
01131     return NULL;
01132 }
01133 
01134 static void
01135 unloadDataMemory(UDataMemory *pData) {
01136     if(!(pData->flags&(1UL<<SET_DATA_POINTER_SHIFT))) {
01137         switch(pData->flags&DATA_MEMORY_TYPE_MASK) {
01138         case FLAT_DATA_MEMORY:
01139             if(IS_MAP(pData->map)) {
01140                 uprv_unmapFile(pData);
01141             }
01142             break;
01143         case DLL_DATA_MEMORY:
01144             if(IS_LIBRARY(pData->lib)) {
01145                 UNLOAD_LIBRARY(pData->lib);
01146             }
01147             break;
01148         default:
01149             break;
01150         }
01151     }
01152 }
01153 
01154 /* API ---------------------------------------------------------------------- */
01155 
01156 U_CAPI UDataMemory * U_EXPORT2
01157 udata_open(const char *path, const char *type, const char *name,
01158            UErrorCode *pErrorCode) {
01159 #ifdef UDATA_DEBUG
01160   fprintf(stderr, "udata_open(): Opening: %s . %s\n", name, type);fflush(stderr);
01161 #endif
01162 
01163     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
01164         return NULL;
01165     } else if(name==NULL || *name==0) {
01166         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
01167         return NULL;
01168     } else {
01169         return doOpenChoice(path, type, name, NULL, NULL, pErrorCode);
01170     }
01171 }
01172 
01173 U_CAPI UDataMemory * U_EXPORT2
01174 udata_openChoice(const char *path, const char *type, const char *name,
01175                  UDataMemoryIsAcceptable *isAcceptable, void *context,
01176                  UErrorCode *pErrorCode) {
01177 #ifdef UDATA_DEBUG
01178   fprintf(stderr, "udata_openChoice(): Opening: %s . %s\n", name, type);fflush(stderr);
01179 #endif
01180 
01181     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
01182         return NULL;
01183     } else if(name==NULL || *name==0 || isAcceptable==NULL) {
01184         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
01185         return NULL;
01186     } else {
01187         return doOpenChoice(path, type, name, isAcceptable, context, pErrorCode);
01188     }
01189 }
01190 
01191 U_CAPI void U_EXPORT2
01192 udata_close(UDataMemory *pData) {
01193 #ifdef UDATA_DEBUG
01194   fprintf(stderr, "udata_close()\n");fflush(stderr);
01195 #endif
01196 
01197     if(pData!=NULL && IS_DATA_MEMORY_LOADED(pData)) {
01198         unloadDataMemory(pData);
01199         if(pData->flags&(1UL<<DYNAMIC_DATA_MEMORY_SHIFT)) {
01200             if(pData->parent==pData+1) {
01201                 /* this data entry was allocated together with its parent */
01202                 unloadDataMemory(pData+1);
01203             }
01204             uprv_free(pData);
01205         } else {
01206             pData->flags=0;
01207         }
01208     }
01209 }
01210 
01211 U_CAPI const void * U_EXPORT2
01212 udata_getMemory(UDataMemory *pData) {
01213     if(pData!=NULL && pData->pHeader!=NULL) {
01214         return (char *)(pData->pHeader)+pData->pHeader->dataHeader.headerSize;
01215     } else {
01216         return NULL;
01217     }
01218 }
01219 
01220 U_CAPI void U_EXPORT2
01221 udata_getInfo(UDataMemory *pData, UDataInfo *pInfo) {
01222     if(pInfo!=NULL) {
01223         if(pData!=NULL && pData->pHeader!=NULL) {
01224             const UDataInfo *info=&pData->pHeader->info;
01225             uint16_t size=pInfo->size;
01226             if(size>info->size) {
01227                 pInfo->size=info->size;
01228             }
01229             uprv_memcpy((uint16_t *)pInfo+1, (uint16_t *)info+1, size-2);
01230         } else {
01231             pInfo->size=0;
01232         }
01233     }
01234 }

Generated at Tue Dec 5 10:48:05 2000 for ICU by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000