2 ******************************************************************************
4 * Copyright (C) 1999-2013, 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 /* Defines _XOPEN_SOURCE for access to POSIX functions.
19 * Must be before any other #includes. */
20 #include "uposixdefs.h"
22 #include "unicode/putil.h"
26 /* memory-mapping base definitions ------------------------------------------ */
28 #if MAP_IMPLEMENTATION==MAP_WIN32
29 # define WIN32_LEAN_AND_MEAN
38 typedef HANDLE MemoryMap
;
40 # define IS_MAP(map) ((map)!=NULL)
41 #elif MAP_IMPLEMENTATION==MAP_POSIX || MAP_IMPLEMENTATION==MAP_390DLL
42 typedef size_t MemoryMap
;
44 # define IS_MAP(map) ((map)!=0)
47 # include <sys/mman.h>
48 # include <sys/stat.h>
52 # define MAP_FAILED ((void*)-1)
55 # if MAP_IMPLEMENTATION==MAP_390DLL
56 /* No memory mapping for 390 batch mode. Fake it using dll loading. */
60 # include "unicode/udata.h"
61 # define LIB_PREFIX "lib"
62 # define LIB_SUFFIX ".dll"
63 /* This is inconvienient until we figure out what to do with U_ICUDATA_NAME in utypes.h */
64 # define U_ICUDATA_ENTRY_NAME "icudt" U_ICU_VERSION_SHORT U_LIB_SUFFIX_C_NAME_STRING "_dat"
66 #elif MAP_IMPLEMENTATION==MAP_STDIO
70 typedef void *MemoryMap
;
72 # define IS_MAP(map) ((map)!=NULL)
75 /*----------------------------------------------------------------------------*
77 * Memory Mapped File support. Platform dependent implementation of *
78 * functions used by the rest of the implementation.*
80 *----------------------------------------------------------------------------*/
81 #if MAP_IMPLEMENTATION==MAP_NONE
83 uprv_mapFile(UDataMemory
*pData
, const char *path
) {
84 UDataMemory_init(pData
); /* Clear the output struct. */
85 return FALSE
; /* no file access */
88 U_CFUNC
void uprv_unmapFile(UDataMemory
*pData
) {
91 #elif MAP_IMPLEMENTATION==MAP_WIN32
94 UDataMemory
*pData
, /* Fill in with info on the result doing the mapping. */
95 /* Output only; any original contents are cleared. */
96 const char *path
/* File path to be opened/mapped */
101 SECURITY_ATTRIBUTES mappingAttributes
;
102 SECURITY_ATTRIBUTES
*mappingAttributesPtr
= NULL
;
103 SECURITY_DESCRIPTOR securityDesc
;
105 UDataMemory_init(pData
); /* Clear the output struct. */
107 /* open the input file */
108 file
=CreateFileA(path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
110 FILE_ATTRIBUTE_NORMAL
|FILE_FLAG_RANDOM_ACCESS
, NULL
);
111 if(file
==INVALID_HANDLE_VALUE
) {
115 /* Declare and initialize a security descriptor.
116 This is required for multiuser systems on Windows 2000 SP4 and beyond */
117 if (InitializeSecurityDescriptor(&securityDesc
, SECURITY_DESCRIPTOR_REVISION
)) {
118 /* give the security descriptor a Null Dacl done using the "TRUE, (PACL)NULL" here */
119 if (SetSecurityDescriptorDacl(&securityDesc
, TRUE
, (PACL
)NULL
, FALSE
)) {
120 /* Make the security attributes point to the security descriptor */
121 uprv_memset(&mappingAttributes
, 0, sizeof(mappingAttributes
));
122 mappingAttributes
.nLength
= sizeof(mappingAttributes
);
123 mappingAttributes
.lpSecurityDescriptor
= &securityDesc
;
124 mappingAttributes
.bInheritHandle
= FALSE
; /* object uninheritable */
125 mappingAttributesPtr
= &mappingAttributes
;
128 /* else creating security descriptors can fail when we are on Windows 98,
129 and mappingAttributesPtr == NULL for that case. */
131 /* create an unnamed Windows file-mapping object for the specified file */
132 map
=CreateFileMapping(file
, mappingAttributesPtr
, PAGE_READONLY
, 0, 0, NULL
);
138 /* map a view of the file into our address space */
139 pData
->pHeader
=(const DataHeader
*)MapViewOfFile(map
, FILE_MAP_READ
, 0, 0, 0);
140 if(pData
->pHeader
==NULL
) {
149 uprv_unmapFile(UDataMemory
*pData
) {
150 if(pData
!=NULL
&& pData
->map
!=NULL
) {
151 UnmapViewOfFile(pData
->pHeader
);
152 CloseHandle(pData
->map
);
160 #elif MAP_IMPLEMENTATION==MAP_POSIX
162 uprv_mapFile(UDataMemory
*pData
, const char *path
) {
168 UDataMemory_init(pData
); /* Clear the output struct. */
170 /* determine the length of the file */
171 if(stat(path
, &mystat
)!=0 || mystat
.st_size
<=0) {
174 length
=mystat
.st_size
;
177 fd
=open(path
, O_RDONLY
);
182 /* get a view of the mapping */
183 #if U_PLATFORM != U_PF_HPUX
184 data
=mmap(0, length
, PROT_READ
, MAP_SHARED
, fd
, 0);
186 data
=mmap(0, length
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
188 close(fd
); /* no longer needed */
189 if(data
==MAP_FAILED
) {
193 pData
->map
= (char *)data
+ length
;
194 pData
->pHeader
=(const DataHeader
*)data
;
195 pData
->mapAddr
= data
;
196 #if U_PLATFORM == U_PF_IPHONE
197 posix_madvise(data
, length
, POSIX_MADV_RANDOM
);
203 uprv_unmapFile(UDataMemory
*pData
) {
204 if(pData
!=NULL
&& pData
->map
!=NULL
) {
205 size_t dataLen
= (char *)pData
->map
- (char *)pData
->mapAddr
;
206 if(munmap(pData
->mapAddr
, dataLen
)==-1) {
216 #elif MAP_IMPLEMENTATION==MAP_STDIO
217 /* copy of the filestrm.c/T_FileStream_size() implementation */
219 umap_fsize(FILE *f
) {
220 int32_t savedPos
= ftell(f
);
223 /*Changes by Bertrand A. D. doesn't affect the current position
224 goes to the end of the file before ftell*/
225 fseek(f
, 0, SEEK_END
);
226 size
= (int32_t)ftell(f
);
227 fseek(f
, savedPos
, SEEK_SET
);
232 uprv_mapFile(UDataMemory
*pData
, const char *path
) {
237 UDataMemory_init(pData
); /* Clear the output struct. */
238 /* open the input file */
239 file
=fopen(path
, "rb");
244 /* get the file length */
245 fileLength
=umap_fsize(file
);
246 if(ferror(file
) || fileLength
<=20) {
251 /* allocate the memory to hold the file data */
252 p
=uprv_malloc(fileLength
);
259 if(fileLength
!=fread(p
, 1, fileLength
, file
)) {
267 pData
->pHeader
=(const DataHeader
*)p
;
273 uprv_unmapFile(UDataMemory
*pData
) {
274 if(pData
!=NULL
&& pData
->map
!=NULL
) {
275 uprv_free(pData
->map
);
277 pData
->mapAddr
= NULL
;
278 pData
->pHeader
= NULL
;
283 #elif MAP_IMPLEMENTATION==MAP_390DLL
284 /* 390 specific Library Loading.
285 * This is the only platform left that dynamically loads an ICU Data Library.
286 * All other platforms use .data files when dynamic loading is required, but
287 * this turn out to be awkward to support in 390 batch mode.
289 * The idea here is to hide the fact that 390 is using dll loading from the
290 * rest of ICU, and make it look like there is file loading happening.
294 static char *strcpy_returnEnd(char *dest
, const char *src
)
296 while((*dest
=*src
)!=0) {
303 /*------------------------------------------------------------------------------
305 * computeDirPath given a user-supplied path of an item to be opened,
307 * - the full directory path to be used
308 * when opening the file.
309 * - Pointer to null at end of above returned path
312 * path: input path. Buffer is not altered.
313 * pathBuffer: Output buffer. Any contents are overwritten.
316 * Pointer to null termination in returned pathBuffer.
318 * TODO: This works the way ICU historically has, but the
319 * whole data fallback search path is so complicated that
320 * proabably almost no one will ever really understand it,
321 * the potential for confusion is large. (It's not just
322 * this one function, but the whole scheme.)
324 *------------------------------------------------------------------------------*/
325 static char *uprv_computeDirPath(const char *path
, char *pathBuffer
)
327 char *finalSlash
; /* Ptr to last dir separator in input path, or null if none. */
328 int32_t pathLen
; /* Length of the returned directory path */
332 finalSlash
= uprv_strrchr(path
, U_FILE_SEP_CHAR
);
336 if (finalSlash
== 0) {
337 /* No user-supplied path.
338 * Copy the ICU_DATA path to the path buffer and return that*/
339 const char *icuDataDir
;
340 icuDataDir
=u_getDataDirectory();
341 if(icuDataDir
!=NULL
&& *icuDataDir
!=0) {
342 return strcpy_returnEnd(pathBuffer
, icuDataDir
);
344 /* there is no icuDataDir either. Just return the empty pathBuffer. */
349 /* User supplied path did contain a directory portion.
350 * Copy it to the output path buffer */
351 pathLen
= (int32_t)(finalSlash
- path
+ 1);
352 uprv_memcpy(pathBuffer
, path
, pathLen
);
353 *(pathBuffer
+pathLen
) = 0;
354 return pathBuffer
+pathLen
;
358 # define DATA_TYPE "dat"
360 U_CFUNC UBool
uprv_mapFile(UDataMemory
*pData
, const char *path
) {
361 const char *inBasename
;
363 char pathBuffer
[1024];
364 const DataHeader
*pHeader
;
368 inBasename
=uprv_strrchr(path
, U_FILE_SEP_CHAR
);
369 if(inBasename
==NULL
) {
374 basename
=uprv_computeDirPath(path
, pathBuffer
);
375 if(uprv_strcmp(inBasename
, U_ICUDATA_NAME
".dat") != 0) {
376 /* must mmap file... for build */
381 UDataMemory_init(pData
); /* Clear the output struct. */
383 /* determine the length of the file */
384 if(stat(path
, &mystat
)!=0 || mystat
.st_size
<=0) {
387 length
=mystat
.st_size
;
390 fd
=open(path
, O_RDONLY
);
395 /* get a view of the mapping */
396 data
=mmap(0, length
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
397 close(fd
); /* no longer needed */
398 if(data
==MAP_FAILED
) {
401 pData
->map
= (char *)data
+ length
;
402 pData
->pHeader
=(const DataHeader
*)data
;
403 pData
->mapAddr
= data
;
408 /* ### hack: we still need to get u_getDataDirectory() fixed
409 for OS/390 (batch mode - always return "//"? )
410 and this here straightened out with LIB_PREFIX and LIB_SUFFIX (both empty?!)
411 This is probably due to the strange file system on OS/390. It's more like
412 a database with short entry names than a typical file system. */
413 /* U_ICUDATA_NAME should always have the correct name */
414 /* BUT FOR BATCH MODE IT IS AN EXCEPTION BECAUSE */
415 /* THE FIRST THREE LETTERS ARE PREASSIGNED TO THE */
417 uprv_strcpy(pathBuffer
, "IXMI" U_ICU_VERSION_SHORT
"DA");
419 /* set up the library name */
420 uprv_strcpy(basename
, LIB_PREFIX U_LIBICUDATA_NAME U_ICU_VERSION_SHORT LIB_SUFFIX
);
424 fprintf(stderr
, "dllload: %s ", pathBuffer
);
427 handle
=dllload(pathBuffer
);
430 fprintf(stderr
, " -> %08X\n", handle
);
434 /* we have a data DLL - what kind of lookup do we need here? */
435 /* try to find the Table of Contents */
436 UDataMemory_init(pData
); /* Clear the output struct. */
437 val
=dllqueryvar((dllhandle
*)handle
, U_ICUDATA_ENTRY_NAME
);
439 /* failed... so keep looking */
443 fprintf(stderr
, "dllqueryvar(%08X, %s) -> %08X\n", handle
, U_ICUDATA_ENTRY_NAME
, val
);
446 pData
->pHeader
=(const DataHeader
*)val
;
449 return FALSE
; /* no handle */
453 U_CFUNC
void uprv_unmapFile(UDataMemory
*pData
) {
454 if(pData
!=NULL
&& pData
->map
!=NULL
) {
455 uprv_free(pData
->map
);
457 pData
->mapAddr
= NULL
;
458 pData
->pHeader
= NULL
;
463 # error MAP_IMPLEMENTATION is set incorrectly