]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/umapfile.c
ICU-461.12.tar.gz
[apple/icu.git] / icuSources / common / umapfile.c
1 /*
2 ******************************************************************************
3 *
4 * Copyright (C) 1999-2010, International Business Machines
5 * Corporation and others. All Rights Reserved.
6 *
7 ******************************************************************************/
8
9
10 /*----------------------------------------------------------------------------
11 *
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
15 * wrapper functions.
16 *
17 *----------------------------------------------------------------------------*/
18
19 #include "unicode/putil.h"
20 #include "udatamem.h"
21 #include "umapfile.h"
22
23 /* memory-mapping base definitions ------------------------------------------ */
24
25 #if MAP_IMPLEMENTATION==MAP_WIN32
26 # define WIN32_LEAN_AND_MEAN
27 # define VC_EXTRALEAN
28 # define NOUSER
29 # define NOSERVICE
30 # define NOIME
31 # define NOMCX
32 # include <windows.h>
33 # include "cmemory.h"
34
35 typedef HANDLE MemoryMap;
36
37 # define IS_MAP(map) ((map)!=NULL)
38 #elif MAP_IMPLEMENTATION==MAP_POSIX || MAP_IMPLEMENTATION==MAP_390DLL
39 typedef size_t MemoryMap;
40
41 # define IS_MAP(map) ((map)!=0)
42
43 # include <unistd.h>
44 # include <sys/mman.h>
45 # include <sys/stat.h>
46 # include <fcntl.h>
47
48 # ifndef MAP_FAILED
49 # define MAP_FAILED ((void*)-1)
50 # endif
51
52 # if MAP_IMPLEMENTATION==MAP_390DLL
53 /* No memory mapping for 390 batch mode. Fake it using dll loading. */
54 # include <dll.h>
55 # include "cstring.h"
56 # include "cmemory.h"
57 # include "unicode/udata.h"
58 # define LIB_PREFIX "lib"
59 # define LIB_SUFFIX ".dll"
60 /* This is inconvienient until we figure out what to do with U_ICUDATA_NAME in utypes.h */
61 # define U_ICUDATA_ENTRY_NAME "icudt" U_ICU_VERSION_SHORT U_LIB_SUFFIX_C_NAME_STRING "_dat"
62 # else
63 # if defined(U_DARWIN)
64 # include <TargetConditionals.h>
65 # endif
66 # endif
67 #elif MAP_IMPLEMENTATION==MAP_STDIO
68 # include <stdio.h>
69 # include "cmemory.h"
70
71 typedef void *MemoryMap;
72
73 # define IS_MAP(map) ((map)!=NULL)
74 #endif
75
76 /*----------------------------------------------------------------------------*
77 * *
78 * Memory Mapped File support. Platform dependent implementation of *
79 * functions used by the rest of the implementation.*
80 * *
81 *----------------------------------------------------------------------------*/
82 #if MAP_IMPLEMENTATION==MAP_NONE
83 U_CFUNC UBool
84 uprv_mapFile(UDataMemory *pData, const char *path) {
85 UDataMemory_init(pData); /* Clear the output struct. */
86 return FALSE; /* no file access */
87 }
88
89 U_CFUNC void uprv_unmapFile(UDataMemory *pData) {
90 /* nothing to do */
91 }
92 #elif MAP_IMPLEMENTATION==MAP_WIN32
93 U_CFUNC UBool
94 uprv_mapFile(
95 UDataMemory *pData, /* Fill in with info on the result doing the mapping. */
96 /* Output only; any original contents are cleared. */
97 const char *path /* File path to be opened/mapped */
98 )
99 {
100 HANDLE map;
101 HANDLE file;
102 SECURITY_ATTRIBUTES mappingAttributes;
103 SECURITY_ATTRIBUTES *mappingAttributesPtr = NULL;
104 SECURITY_DESCRIPTOR securityDesc;
105
106 UDataMemory_init(pData); /* Clear the output struct. */
107
108 /* open the input file */
109 file=CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL,
110 OPEN_EXISTING,
111 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL);
112 if(file==INVALID_HANDLE_VALUE) {
113 return FALSE;
114 }
115
116 /* Declare and initialize a security descriptor.
117 This is required for multiuser systems on Windows 2000 SP4 and beyond */
118 if (InitializeSecurityDescriptor(&securityDesc, SECURITY_DESCRIPTOR_REVISION)) {
119 /* give the security descriptor a Null Dacl done using the "TRUE, (PACL)NULL" here */
120 if (SetSecurityDescriptorDacl(&securityDesc, TRUE, (PACL)NULL, FALSE)) {
121 /* Make the security attributes point to the security descriptor */
122 uprv_memset(&mappingAttributes, 0, sizeof(mappingAttributes));
123 mappingAttributes.nLength = sizeof(mappingAttributes);
124 mappingAttributes.lpSecurityDescriptor = &securityDesc;
125 mappingAttributes.bInheritHandle = FALSE; /* object uninheritable */
126 mappingAttributesPtr = &mappingAttributes;
127 }
128 }
129 /* else creating security descriptors can fail when we are on Windows 98,
130 and mappingAttributesPtr == NULL for that case. */
131
132 /* create an unnamed Windows file-mapping object for the specified file */
133 map=CreateFileMapping(file, mappingAttributesPtr, PAGE_READONLY, 0, 0, NULL);
134 CloseHandle(file);
135 if(map==NULL) {
136 return FALSE;
137 }
138
139 /* map a view of the file into our address space */
140 pData->pHeader=(const DataHeader *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
141 if(pData->pHeader==NULL) {
142 CloseHandle(map);
143 return FALSE;
144 }
145 pData->map=map;
146 return TRUE;
147 }
148
149 U_CFUNC void
150 uprv_unmapFile(UDataMemory *pData) {
151 if(pData!=NULL && pData->map!=NULL) {
152 UnmapViewOfFile(pData->pHeader);
153 CloseHandle(pData->map);
154 pData->pHeader=NULL;
155 pData->map=NULL;
156 }
157 }
158
159
160
161 #elif MAP_IMPLEMENTATION==MAP_POSIX
162 U_CFUNC UBool
163 uprv_mapFile(UDataMemory *pData, const char *path) {
164 int fd;
165 int length;
166 struct stat mystat;
167 void *data;
168
169 UDataMemory_init(pData); /* Clear the output struct. */
170
171 /* determine the length of the file */
172 if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
173 return FALSE;
174 }
175 length=mystat.st_size;
176
177 /* open the file */
178 fd=open(path, O_RDONLY);
179 if(fd==-1) {
180 return FALSE;
181 }
182
183 /* get a view of the mapping */
184 #ifndef U_HPUX
185 data=mmap(0, length, PROT_READ, MAP_SHARED, fd, 0);
186 #else
187 data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0);
188 #endif
189 close(fd); /* no longer needed */
190 if(data==MAP_FAILED) {
191 return FALSE;
192 }
193
194 pData->map = (char *)data + length;
195 pData->pHeader=(const DataHeader *)data;
196 pData->mapAddr = data;
197 #if defined(U_DARWIN) && TARGET_OS_IPHONE
198 posix_madvise(data, length, POSIX_MADV_RANDOM);
199 #endif
200 return TRUE;
201 }
202
203 U_CFUNC void
204 uprv_unmapFile(UDataMemory *pData) {
205 if(pData!=NULL && pData->map!=NULL) {
206 size_t dataLen = (char *)pData->map - (char *)pData->mapAddr;
207 if(munmap(pData->mapAddr, dataLen)==-1) {
208 }
209 pData->pHeader=NULL;
210 pData->map=0;
211 pData->mapAddr=NULL;
212 }
213 }
214
215
216
217 #elif MAP_IMPLEMENTATION==MAP_STDIO
218 /* copy of the filestrm.c/T_FileStream_size() implementation */
219 static int32_t
220 umap_fsize(FILE *f) {
221 int32_t savedPos = ftell(f);
222 int32_t size = 0;
223
224 /*Changes by Bertrand A. D. doesn't affect the current position
225 goes to the end of the file before ftell*/
226 fseek(f, 0, SEEK_END);
227 size = (int32_t)ftell(f);
228 fseek(f, savedPos, SEEK_SET);
229 return size;
230 }
231
232 U_CFUNC UBool
233 uprv_mapFile(UDataMemory *pData, const char *path) {
234 FILE *file;
235 int32_t fileLength;
236 void *p;
237
238 UDataMemory_init(pData); /* Clear the output struct. */
239 /* open the input file */
240 file=fopen(path, "rb");
241 if(file==NULL) {
242 return FALSE;
243 }
244
245 /* get the file length */
246 fileLength=umap_fsize(file);
247 if(ferror(file) || fileLength<=20) {
248 fclose(file);
249 return FALSE;
250 }
251
252 /* allocate the memory to hold the file data */
253 p=uprv_malloc(fileLength);
254 if(p==NULL) {
255 fclose(file);
256 return FALSE;
257 }
258
259 /* read the file */
260 if(fileLength!=fread(p, 1, fileLength, file)) {
261 uprv_free(p);
262 fclose(file);
263 return FALSE;
264 }
265
266 fclose(file);
267 pData->map=p;
268 pData->pHeader=(const DataHeader *)p;
269 pData->mapAddr=p;
270 return TRUE;
271 }
272
273 U_CFUNC void
274 uprv_unmapFile(UDataMemory *pData) {
275 if(pData!=NULL && pData->map!=NULL) {
276 uprv_free(pData->map);
277 pData->map = NULL;
278 pData->mapAddr = NULL;
279 pData->pHeader = NULL;
280 }
281 }
282
283
284 #elif MAP_IMPLEMENTATION==MAP_390DLL
285 /* 390 specific Library Loading.
286 * This is the only platform left that dynamically loads an ICU Data Library.
287 * All other platforms use .data files when dynamic loading is required, but
288 * this turn out to be awkward to support in 390 batch mode.
289 *
290 * The idea here is to hide the fact that 390 is using dll loading from the
291 * rest of ICU, and make it look like there is file loading happening.
292 *
293 */
294
295 static char *strcpy_returnEnd(char *dest, const char *src)
296 {
297 while((*dest=*src)!=0) {
298 ++dest;
299 ++src;
300 }
301 return dest;
302 }
303
304 /*------------------------------------------------------------------------------
305 *
306 * computeDirPath given a user-supplied path of an item to be opened,
307 * compute and return
308 * - the full directory path to be used
309 * when opening the file.
310 * - Pointer to null at end of above returned path
311 *
312 * Parameters:
313 * path: input path. Buffer is not altered.
314 * pathBuffer: Output buffer. Any contents are overwritten.
315 *
316 * Returns:
317 * Pointer to null termination in returned pathBuffer.
318 *
319 * TODO: This works the way ICU historically has, but the
320 * whole data fallback search path is so complicated that
321 * proabably almost no one will ever really understand it,
322 * the potential for confusion is large. (It's not just
323 * this one function, but the whole scheme.)
324 *
325 *------------------------------------------------------------------------------*/
326 static char *uprv_computeDirPath(const char *path, char *pathBuffer)
327 {
328 char *finalSlash; /* Ptr to last dir separator in input path, or null if none. */
329 int32_t pathLen; /* Length of the returned directory path */
330
331 finalSlash = 0;
332 if (path != 0) {
333 finalSlash = uprv_strrchr(path, U_FILE_SEP_CHAR);
334 }
335
336 *pathBuffer = 0;
337 if (finalSlash == 0) {
338 /* No user-supplied path.
339 * Copy the ICU_DATA path to the path buffer and return that*/
340 const char *icuDataDir;
341 icuDataDir=u_getDataDirectory();
342 if(icuDataDir!=NULL && *icuDataDir!=0) {
343 return strcpy_returnEnd(pathBuffer, icuDataDir);
344 } else {
345 /* there is no icuDataDir either. Just return the empty pathBuffer. */
346 return pathBuffer;
347 }
348 }
349
350 /* User supplied path did contain a directory portion.
351 * Copy it to the output path buffer */
352 pathLen = (int32_t)(finalSlash - path + 1);
353 uprv_memcpy(pathBuffer, path, pathLen);
354 *(pathBuffer+pathLen) = 0;
355 return pathBuffer+pathLen;
356 }
357
358
359 # define DATA_TYPE "dat"
360
361 U_CFUNC UBool uprv_mapFile(UDataMemory *pData, const char *path) {
362 const char *inBasename;
363 char *basename;
364 char pathBuffer[1024];
365 const DataHeader *pHeader;
366 dllhandle *handle;
367 void *val=0;
368
369 inBasename=uprv_strrchr(path, U_FILE_SEP_CHAR);
370 if(inBasename==NULL) {
371 inBasename = path;
372 } else {
373 inBasename++;
374 }
375 basename=uprv_computeDirPath(path, pathBuffer);
376 if(uprv_strcmp(inBasename, U_ICUDATA_NAME".dat") != 0) {
377 /* must mmap file... for build */
378 int fd;
379 int length;
380 struct stat mystat;
381 void *data;
382 UDataMemory_init(pData); /* Clear the output struct. */
383
384 /* determine the length of the file */
385 if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
386 return FALSE;
387 }
388 length=mystat.st_size;
389
390 /* open the file */
391 fd=open(path, O_RDONLY);
392 if(fd==-1) {
393 return FALSE;
394 }
395
396 /* get a view of the mapping */
397 data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0);
398 close(fd); /* no longer needed */
399 if(data==MAP_FAILED) {
400 return FALSE;
401 }
402 pData->map = (char *)data + length;
403 pData->pHeader=(const DataHeader *)data;
404 pData->mapAddr = data;
405 return TRUE;
406 }
407
408 # ifdef OS390BATCH
409 /* ### hack: we still need to get u_getDataDirectory() fixed
410 for OS/390 (batch mode - always return "//"? )
411 and this here straightened out with LIB_PREFIX and LIB_SUFFIX (both empty?!)
412 This is probably due to the strange file system on OS/390. It's more like
413 a database with short entry names than a typical file system. */
414 /* U_ICUDATA_NAME should always have the correct name */
415 /* BUT FOR BATCH MODE IT IS AN EXCEPTION BECAUSE */
416 /* THE FIRST THREE LETTERS ARE PREASSIGNED TO THE */
417 /* PROJECT!!!!! */
418 uprv_strcpy(pathBuffer, "IXMI" U_ICU_VERSION_SHORT "DA");
419 # else
420 /* set up the library name */
421 uprv_strcpy(basename, LIB_PREFIX U_LIBICUDATA_NAME U_ICU_VERSION_SHORT LIB_SUFFIX);
422 # endif
423
424 # ifdef UDATA_DEBUG
425 fprintf(stderr, "dllload: %s ", pathBuffer);
426 # endif
427
428 handle=dllload(pathBuffer);
429
430 # ifdef UDATA_DEBUG
431 fprintf(stderr, " -> %08X\n", handle );
432 # endif
433
434 if(handle != NULL) {
435 /* we have a data DLL - what kind of lookup do we need here? */
436 /* try to find the Table of Contents */
437 UDataMemory_init(pData); /* Clear the output struct. */
438 val=dllqueryvar((dllhandle*)handle, U_ICUDATA_ENTRY_NAME);
439 if(val == 0) {
440 /* failed... so keep looking */
441 return FALSE;
442 }
443 # ifdef UDATA_DEBUG
444 fprintf(stderr, "dllqueryvar(%08X, %s) -> %08X\n", handle, U_ICUDATA_ENTRY_NAME, val);
445 # endif
446
447 pData->pHeader=(const DataHeader *)val;
448 return TRUE;
449 } else {
450 return FALSE; /* no handle */
451 }
452 }
453
454 U_CFUNC void uprv_unmapFile(UDataMemory *pData) {
455 if(pData!=NULL && pData->map!=NULL) {
456 uprv_free(pData->map);
457 pData->map = NULL;
458 pData->mapAddr = NULL;
459 pData->pHeader = NULL;
460 }
461 }
462
463 #else
464 # error MAP_IMPLEMENTATION is set incorrectly
465 #endif