2 ******************************************************************************
4 * Copyright (C) 1999-2004, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 ******************************************************************************/
10 /*----------------------------------------------------------------------------
12 * Memory mapped file wrappers for use by the ICU Data Implementation
13 * All of the platform-specific implementation for mapping data files
14 * is here. The rest of the ICU Data implementation uses only the
17 *----------------------------------------------------------------------------*/
18 #include "unicode/putil.h"
25 /* memory-mapping base definitions ------------------------------------------ */
30 #define MAP_FILE_STREAM 3
34 # define WIN32_LEAN_AND_MEAN
42 typedef HANDLE MemoryMap
;
44 # define IS_MAP(map) ((map)!=NULL)
46 # define MAP_IMPLEMENTATION MAP_WIN32
48 /* ### Todo: properly auto detect mmap(). Until then, just add your platform here. */
49 #elif U_HAVE_MMAP || defined(U_AIX) || defined(U_HPUX) || defined(OS390) || defined(PTX)
50 typedef size_t MemoryMap
;
52 # define IS_MAP(map) ((map)!=0)
54 /* Needed by OSF to get the correct mmap version */
55 # ifndef _XOPEN_SOURCE_EXTENDED
56 # define _XOPEN_SOURCE_EXTENDED
60 # include <sys/mman.h>
61 # include <sys/stat.h>
65 # define MAP_FAILED ((void*)-1)
68 # if defined(OS390) && defined (OS390_STUBDATA)
69 /* No memory mapping for 390 batch mode. Fake it using dll loading. */
73 # include "unicode/udata.h"
74 # define LIB_PREFIX "lib"
75 # define LIB_SUFFIX ".dll"
76 # define MAP_IMPLEMENTATION MAP_390DLL
78 /* This is inconvienient until we figure out what to do with U_ICUDATA_NAME in utypes.h */
79 # define U_ICUDATA_ENTRY_NAME "icudt" U_ICU_VERSION_SHORT U_LIB_SUFFIX_C_NAME_STRING "_dat"
81 # define MAP_IMPLEMENTATION MAP_POSIX
84 #else /* unknown platform, no memory map implementation: use FileStream/uprv_malloc() instead */
86 # include "filestrm.h"
89 typedef void *MemoryMap
;
91 # define IS_MAP(map) ((map)!=NULL)
93 # define MAP_IMPLEMENTATION MAP_FILE_STREAM
100 /*----------------------------------------------------------------------------*
102 * Memory Mapped File support. Platform dependent implementation of *
103 * functions used by the rest of the implementation.*
105 *----------------------------------------------------------------------------*/
106 #if MAP_IMPLEMENTATION==MAP_WIN32
109 UDataMemory
*pData
, /* Fill in with info on the result doing the mapping. */
110 /* Output only; any original contents are cleared. */
111 const char *path
/* File path to be opened/mapped */
117 UDataMemory_init(pData
); /* Clear the output struct. */
119 /* open the input file */
120 file
=CreateFile(path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
122 FILE_ATTRIBUTE_NORMAL
|FILE_FLAG_RANDOM_ACCESS
, NULL
);
123 if(file
==INVALID_HANDLE_VALUE
) {
127 /* create an unnamed Windows file-mapping object for the specified file */
128 map
=CreateFileMapping(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
134 /* map a view of the file into our address space */
135 pData
->pHeader
=(const DataHeader
*)MapViewOfFile(map
, FILE_MAP_READ
, 0, 0, 0);
136 if(pData
->pHeader
==NULL
) {
146 uprv_unmapFile(UDataMemory
*pData
) {
147 if(pData
!=NULL
&& pData
->map
!=NULL
) {
148 UnmapViewOfFile(pData
->pHeader
);
149 CloseHandle(pData
->map
);
157 #elif MAP_IMPLEMENTATION==MAP_POSIX
159 uprv_mapFile(UDataMemory
*pData
, const char *path
) {
165 UDataMemory_init(pData
); /* Clear the output struct. */
167 /* determine the length of the file */
168 if(stat(path
, &mystat
)!=0 || mystat
.st_size
<=0) {
171 length
=mystat
.st_size
;
174 fd
=open(path
, O_RDONLY
);
179 /* get a view of the mapping */
181 data
=mmap(0, length
, PROT_READ
, MAP_SHARED
, fd
, 0);
183 data
=mmap(0, length
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
185 close(fd
); /* no longer needed */
186 if(data
==MAP_FAILED
) {
190 pData
->map
= (char *)data
+ length
;
191 pData
->pHeader
=(const DataHeader
*)data
;
192 pData
->mapAddr
= data
;
199 uprv_unmapFile(UDataMemory
*pData
) {
200 if(pData
!=NULL
&& pData
->map
!=NULL
) {
201 size_t dataLen
= (char *)pData
->map
- (char *)pData
->mapAddr
;
202 if(munmap(pData
->mapAddr
, dataLen
)==-1) {
212 #elif MAP_IMPLEMENTATION==MAP_FILE_STREAM
214 uprv_mapFile(UDataMemory
*pData
, const char *path
) {
219 UDataMemory_init(pData
); /* Clear the output struct. */
220 /* open the input file */
221 file
=T_FileStream_open(path
, "rb");
226 /* get the file length */
227 fileLength
=T_FileStream_size(file
);
228 if(T_FileStream_error(file
) || fileLength
<=20) {
229 T_FileStream_close(file
);
233 /* allocate the memory to hold the file data */
234 p
=uprv_malloc(fileLength
);
236 T_FileStream_close(file
);
241 if(fileLength
!=T_FileStream_read(file
, p
, fileLength
)) {
243 T_FileStream_close(file
);
247 T_FileStream_close(file
);
249 pData
->pHeader
=(const DataHeader
*)p
;
255 uprv_unmapFile(UDataMemory
*pData
) {
256 if(pData
!=NULL
&& pData
->map
!=NULL
) {
257 uprv_free(pData
->map
);
259 pData
->mapAddr
= NULL
;
260 pData
->pHeader
= NULL
;
265 #elif MAP_IMPLEMENTATION==MAP_390DLL
266 /* 390 specific Library Loading.
267 * This is the only platform left that dynamically loads an ICU Data Library.
268 * All other platforms use .data files when dynamic loading is required, but
269 * this turn out to be awkward to support in 390 batch mode.
271 * The idea here is to hide the fact that 390 is using dll loading from the
272 * rest of ICU, and make it look like there is file loading happening.
276 static char *strcpy_returnEnd(char *dest
, const char *src
)
278 while((*dest
=*src
)!=0) {
285 /*------------------------------------------------------------------------------
287 * computeDirPath given a user-supplied path of an item to be opened,
289 * - the full directory path to be used
290 * when opening the file.
291 * - Pointer to null at end of above returned path
294 * path: input path. Buffer is not altered.
295 * pathBuffer: Output buffer. Any contents are overwritten.
298 * Pointer to null termination in returned pathBuffer.
300 * TODO: This works the way ICU historically has, but the
301 * whole data fallback search path is so complicated that
302 * proabably almost no one will ever really understand it,
303 * the potential for confusion is large. (It's not just
304 * this one function, but the whole scheme.)
306 *------------------------------------------------------------------------------*/
307 static char *uprv_computeDirPath(const char *path
, char *pathBuffer
)
309 char *finalSlash
; /* Ptr to last dir separator in input path, or null if none. */
310 int32_t pathLen
; /* Length of the returned directory path */
314 finalSlash
= uprv_strrchr(path
, U_FILE_SEP_CHAR
);
318 if (finalSlash
== 0) {
319 /* No user-supplied path.
320 * Copy the ICU_DATA path to the path buffer and return that*/
321 const char *icuDataDir
;
322 icuDataDir
=u_getDataDirectory();
323 if(icuDataDir
!=NULL
&& *icuDataDir
!=0) {
324 return strcpy_returnEnd(pathBuffer
, icuDataDir
);
326 /* there is no icuDataDir either. Just return the empty pathBuffer. */
331 /* User supplied path did contain a directory portion.
332 * Copy it to the output path buffer */
333 pathLen
= (int32_t)(finalSlash
- path
+ 1);
334 uprv_memcpy(pathBuffer
, path
, pathLen
);
335 *(pathBuffer
+pathLen
) = 0;
336 return pathBuffer
+pathLen
;
340 # define DATA_TYPE "dat"
342 UBool
uprv_mapFile(UDataMemory
*pData
, const char *path
) {
343 const char *inBasename
;
345 char pathBuffer
[1024];
346 const DataHeader
*pHeader
;
350 inBasename
=uprv_strrchr(path
, U_FILE_SEP_CHAR
);
351 if(inBasename
==NULL
) {
356 basename
=uprv_computeDirPath(path
, pathBuffer
);
357 if(uprv_strcmp(inBasename
, U_ICUDATA_NAME
".dat") != 0) {
358 /* must mmap file... for build */
363 UDataMemory_init(pData
); /* Clear the output struct. */
365 /* determine the length of the file */
366 if(stat(path
, &mystat
)!=0 || mystat
.st_size
<=0) {
369 length
=mystat
.st_size
;
372 fd
=open(path
, O_RDONLY
);
377 /* get a view of the mapping */
378 data
=mmap(0, length
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
379 close(fd
); /* no longer needed */
380 if(data
==MAP_FAILED
) {
383 pData
->map
= (char *)data
+ length
;
384 pData
->pHeader
=(const DataHeader
*)data
;
385 pData
->mapAddr
= data
;
390 /* ### hack: we still need to get u_getDataDirectory() fixed
391 for OS/390 (batch mode - always return "//"? )
392 and this here straightened out with LIB_PREFIX and LIB_SUFFIX (both empty?!)
393 This is probably due to the strange file system on OS/390. It's more like
394 a database with short entry names than a typical file system. */
395 /* U_ICUDATA_NAME should always have the correct name */
396 /* BUT FOR BATCH MODE IT IS AN EXCEPTION BECAUSE */
397 /* THE FIRST THREE LETTERS ARE PREASSIGNED TO THE */
399 uprv_strcpy(pathBuffer
, "IXMI" U_ICU_VERSION_SHORT
"DA");
401 /* set up the library name */
402 uprv_strcpy(basename
, LIB_PREFIX U_LIBICUDATA_NAME U_ICU_VERSION_SHORT LIB_SUFFIX
);
406 fprintf(stderr
, "dllload: %s ", pathBuffer
);
409 handle
=dllload(pathBuffer
);
412 fprintf(stderr
, " -> %08X\n", handle
);
416 /* we have a data DLL - what kind of lookup do we need here? */
417 /* try to find the Table of Contents */
418 UDataMemory_init(pData
); /* Clear the output struct. */
419 val
=dllqueryvar((dllhandle
*)handle
, U_ICUDATA_ENTRY_NAME
);
421 /* failed... so keep looking */
425 fprintf(stderr
, "dllqueryvar(%08X, %s) -> %08X\n", handle
, U_ICUDATA_ENTRY_NAME
, val
);
428 pData
->pHeader
=(const DataHeader
*)val
;
431 return FALSE
; /* no handle */
437 void uprv_unmapFile(UDataMemory
*pData
) {
438 if(pData
!=NULL
&& pData
->map
!=NULL
) {
439 uprv_free(pData
->map
);
441 pData
->mapAddr
= NULL
;
442 pData
->pHeader
= NULL
;
447 # error MAP_IMPLEMENTATION is set incorrectly