2 ******************************************************************************
4 * Copyright (C) 1999-2006, 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"
24 /* memory-mapping base definitions ------------------------------------------ */
26 /* MAP_NONE: no memory mapping, no file access at all */
33 #if UCONFIG_NO_FILE_IO
34 # define MAP_IMPLEMENTATION MAP_NONE
35 #elif defined(U_WINDOWS)
36 # define WIN32_LEAN_AND_MEAN
45 typedef HANDLE MemoryMap
;
47 # define IS_MAP(map) ((map)!=NULL)
49 # define MAP_IMPLEMENTATION MAP_WIN32
51 /* ### Todo: properly auto detect mmap(). Until then, just add your platform here. */
52 #elif U_HAVE_MMAP || defined(U_AIX) || defined(U_HPUX) || defined(OS390)
53 typedef size_t MemoryMap
;
55 # define IS_MAP(map) ((map)!=0)
57 /* Needed by OSF to get the correct mmap version */
58 # ifndef _XOPEN_SOURCE_EXTENDED
59 # define _XOPEN_SOURCE_EXTENDED
63 # include <sys/mman.h>
64 # include <sys/stat.h>
68 # define MAP_FAILED ((void*)-1)
71 # if defined(OS390) && defined (OS390_STUBDATA)
72 /* No memory mapping for 390 batch mode. Fake it using dll loading. */
76 # include "unicode/udata.h"
77 # define LIB_PREFIX "lib"
78 # define LIB_SUFFIX ".dll"
79 # define MAP_IMPLEMENTATION MAP_390DLL
81 /* This is inconvienient until we figure out what to do with U_ICUDATA_NAME in utypes.h */
82 # define U_ICUDATA_ENTRY_NAME "icudt" U_ICU_VERSION_SHORT U_LIB_SUFFIX_C_NAME_STRING "_dat"
84 # define MAP_IMPLEMENTATION MAP_POSIX
87 #else /* unknown platform, no memory map implementation: use stdio.h and uprv_malloc() instead */
92 typedef void *MemoryMap
;
94 # define IS_MAP(map) ((map)!=NULL)
96 # define MAP_IMPLEMENTATION MAP_STDIO
103 /*----------------------------------------------------------------------------*
105 * Memory Mapped File support. Platform dependent implementation of *
106 * functions used by the rest of the implementation.*
108 *----------------------------------------------------------------------------*/
109 #if MAP_IMPLEMENTATION==MAP_NONE
111 uprv_mapFile(UDataMemory
*pData
, const char *path
) {
112 UDataMemory_init(pData
); /* Clear the output struct. */
113 return FALSE
; /* no file access */
116 void uprv_unmapFile(UDataMemory
*pData
) {
119 #elif MAP_IMPLEMENTATION==MAP_WIN32
122 UDataMemory
*pData
, /* Fill in with info on the result doing the mapping. */
123 /* Output only; any original contents are cleared. */
124 const char *path
/* File path to be opened/mapped */
129 SECURITY_ATTRIBUTES mappingAttributes
;
130 SECURITY_ATTRIBUTES
*mappingAttributesPtr
= NULL
;
131 SECURITY_DESCRIPTOR securityDesc
;
133 UDataMemory_init(pData
); /* Clear the output struct. */
135 /* open the input file */
136 file
=CreateFile(path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
138 FILE_ATTRIBUTE_NORMAL
|FILE_FLAG_RANDOM_ACCESS
, NULL
);
139 if(file
==INVALID_HANDLE_VALUE
) {
143 /* Declare and initialize a security descriptor.
144 This is required for multiuser systems on Windows 2000 SP4 and beyond */
145 if (InitializeSecurityDescriptor(&securityDesc
, SECURITY_DESCRIPTOR_REVISION
)) {
146 /* give the security descriptor a Null Dacl done using the "TRUE, (PACL)NULL" here */
147 if (SetSecurityDescriptorDacl(&securityDesc
, TRUE
, (PACL
)NULL
, FALSE
)) {
148 /* Make the security attributes point to the security descriptor */
149 uprv_memset(&mappingAttributes
, 0, sizeof(mappingAttributes
));
150 mappingAttributes
.nLength
= sizeof(mappingAttributes
);
151 mappingAttributes
.lpSecurityDescriptor
= &securityDesc
;
152 mappingAttributes
.bInheritHandle
= FALSE
; /* object uninheritable */
153 mappingAttributesPtr
= &mappingAttributes
;
156 /* else creating security descriptors can fail when we are on Windows 98,
157 and mappingAttributesPtr == NULL for that case. */
159 /* create an unnamed Windows file-mapping object for the specified file */
160 map
=CreateFileMapping(file
, mappingAttributesPtr
, PAGE_READONLY
, 0, 0, NULL
);
166 /* map a view of the file into our address space */
167 pData
->pHeader
=(const DataHeader
*)MapViewOfFile(map
, FILE_MAP_READ
, 0, 0, 0);
168 if(pData
->pHeader
==NULL
) {
178 uprv_unmapFile(UDataMemory
*pData
) {
179 if(pData
!=NULL
&& pData
->map
!=NULL
) {
180 UnmapViewOfFile(pData
->pHeader
);
181 CloseHandle(pData
->map
);
189 #elif MAP_IMPLEMENTATION==MAP_POSIX
191 uprv_mapFile(UDataMemory
*pData
, const char *path
) {
197 UDataMemory_init(pData
); /* Clear the output struct. */
199 /* determine the length of the file */
200 if(stat(path
, &mystat
)!=0 || mystat
.st_size
<=0) {
203 length
=mystat
.st_size
;
206 fd
=open(path
, O_RDONLY
);
211 /* get a view of the mapping */
213 data
=mmap(0, length
, PROT_READ
, MAP_SHARED
, fd
, 0);
215 data
=mmap(0, length
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
217 close(fd
); /* no longer needed */
218 if(data
==MAP_FAILED
) {
222 pData
->map
= (char *)data
+ length
;
223 pData
->pHeader
=(const DataHeader
*)data
;
224 pData
->mapAddr
= data
;
231 uprv_unmapFile(UDataMemory
*pData
) {
232 if(pData
!=NULL
&& pData
->map
!=NULL
) {
233 size_t dataLen
= (char *)pData
->map
- (char *)pData
->mapAddr
;
234 if(munmap(pData
->mapAddr
, dataLen
)==-1) {
244 #elif MAP_IMPLEMENTATION==MAP_STDIO
245 /* copy of the filestrm.c/T_FileStream_size() implementation */
247 umap_fsize(FILE *f
) {
248 int32_t savedPos
= ftell(f
);
251 /*Changes by Bertrand A. D. doesn't affect the current position
252 goes to the end of the file before ftell*/
253 fseek(f
, 0, SEEK_END
);
254 size
= (int32_t)ftell(f
);
255 fseek(f
, savedPos
, SEEK_SET
);
260 uprv_mapFile(UDataMemory
*pData
, const char *path
) {
265 UDataMemory_init(pData
); /* Clear the output struct. */
266 /* open the input file */
267 file
=fopen(path
, "rb");
272 /* get the file length */
273 fileLength
=umap_fsize(file
);
274 if(ferror(file
) || fileLength
<=20) {
279 /* allocate the memory to hold the file data */
280 p
=uprv_malloc(fileLength
);
287 if(fileLength
!=fread(p
, 1, fileLength
, file
)) {
295 pData
->pHeader
=(const DataHeader
*)p
;
301 uprv_unmapFile(UDataMemory
*pData
) {
302 if(pData
!=NULL
&& pData
->map
!=NULL
) {
303 uprv_free(pData
->map
);
305 pData
->mapAddr
= NULL
;
306 pData
->pHeader
= NULL
;
311 #elif MAP_IMPLEMENTATION==MAP_390DLL
312 /* 390 specific Library Loading.
313 * This is the only platform left that dynamically loads an ICU Data Library.
314 * All other platforms use .data files when dynamic loading is required, but
315 * this turn out to be awkward to support in 390 batch mode.
317 * The idea here is to hide the fact that 390 is using dll loading from the
318 * rest of ICU, and make it look like there is file loading happening.
322 static char *strcpy_returnEnd(char *dest
, const char *src
)
324 while((*dest
=*src
)!=0) {
331 /*------------------------------------------------------------------------------
333 * computeDirPath given a user-supplied path of an item to be opened,
335 * - the full directory path to be used
336 * when opening the file.
337 * - Pointer to null at end of above returned path
340 * path: input path. Buffer is not altered.
341 * pathBuffer: Output buffer. Any contents are overwritten.
344 * Pointer to null termination in returned pathBuffer.
346 * TODO: This works the way ICU historically has, but the
347 * whole data fallback search path is so complicated that
348 * proabably almost no one will ever really understand it,
349 * the potential for confusion is large. (It's not just
350 * this one function, but the whole scheme.)
352 *------------------------------------------------------------------------------*/
353 static char *uprv_computeDirPath(const char *path
, char *pathBuffer
)
355 char *finalSlash
; /* Ptr to last dir separator in input path, or null if none. */
356 int32_t pathLen
; /* Length of the returned directory path */
360 finalSlash
= uprv_strrchr(path
, U_FILE_SEP_CHAR
);
364 if (finalSlash
== 0) {
365 /* No user-supplied path.
366 * Copy the ICU_DATA path to the path buffer and return that*/
367 const char *icuDataDir
;
368 icuDataDir
=u_getDataDirectory();
369 if(icuDataDir
!=NULL
&& *icuDataDir
!=0) {
370 return strcpy_returnEnd(pathBuffer
, icuDataDir
);
372 /* there is no icuDataDir either. Just return the empty pathBuffer. */
377 /* User supplied path did contain a directory portion.
378 * Copy it to the output path buffer */
379 pathLen
= (int32_t)(finalSlash
- path
+ 1);
380 uprv_memcpy(pathBuffer
, path
, pathLen
);
381 *(pathBuffer
+pathLen
) = 0;
382 return pathBuffer
+pathLen
;
386 # define DATA_TYPE "dat"
388 UBool
uprv_mapFile(UDataMemory
*pData
, const char *path
) {
389 const char *inBasename
;
391 char pathBuffer
[1024];
392 const DataHeader
*pHeader
;
396 inBasename
=uprv_strrchr(path
, U_FILE_SEP_CHAR
);
397 if(inBasename
==NULL
) {
402 basename
=uprv_computeDirPath(path
, pathBuffer
);
403 if(uprv_strcmp(inBasename
, U_ICUDATA_NAME
".dat") != 0) {
404 /* must mmap file... for build */
409 UDataMemory_init(pData
); /* Clear the output struct. */
411 /* determine the length of the file */
412 if(stat(path
, &mystat
)!=0 || mystat
.st_size
<=0) {
415 length
=mystat
.st_size
;
418 fd
=open(path
, O_RDONLY
);
423 /* get a view of the mapping */
424 data
=mmap(0, length
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
425 close(fd
); /* no longer needed */
426 if(data
==MAP_FAILED
) {
429 pData
->map
= (char *)data
+ length
;
430 pData
->pHeader
=(const DataHeader
*)data
;
431 pData
->mapAddr
= data
;
436 /* ### hack: we still need to get u_getDataDirectory() fixed
437 for OS/390 (batch mode - always return "//"? )
438 and this here straightened out with LIB_PREFIX and LIB_SUFFIX (both empty?!)
439 This is probably due to the strange file system on OS/390. It's more like
440 a database with short entry names than a typical file system. */
441 /* U_ICUDATA_NAME should always have the correct name */
442 /* BUT FOR BATCH MODE IT IS AN EXCEPTION BECAUSE */
443 /* THE FIRST THREE LETTERS ARE PREASSIGNED TO THE */
445 uprv_strcpy(pathBuffer
, "IXMI" U_ICU_VERSION_SHORT
"DA");
447 /* set up the library name */
448 uprv_strcpy(basename
, LIB_PREFIX U_LIBICUDATA_NAME U_ICU_VERSION_SHORT LIB_SUFFIX
);
452 fprintf(stderr
, "dllload: %s ", pathBuffer
);
455 handle
=dllload(pathBuffer
);
458 fprintf(stderr
, " -> %08X\n", handle
);
462 /* we have a data DLL - what kind of lookup do we need here? */
463 /* try to find the Table of Contents */
464 UDataMemory_init(pData
); /* Clear the output struct. */
465 val
=dllqueryvar((dllhandle
*)handle
, U_ICUDATA_ENTRY_NAME
);
467 /* failed... so keep looking */
471 fprintf(stderr
, "dllqueryvar(%08X, %s) -> %08X\n", handle
, U_ICUDATA_ENTRY_NAME
, val
);
474 pData
->pHeader
=(const DataHeader
*)val
;
477 return FALSE
; /* no handle */
483 void uprv_unmapFile(UDataMemory
*pData
) {
484 if(pData
!=NULL
&& pData
->map
!=NULL
) {
485 uprv_free(pData
->map
);
487 pData
->mapAddr
= NULL
;
488 pData
->pHeader
= NULL
;
493 # error MAP_IMPLEMENTATION is set incorrectly