]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/umapfile.c
ICU-6.2.22.tar.gz
[apple/icu.git] / icuSources / common / umapfile.c
1 /*
2 ******************************************************************************
3 *
4 * Copyright (C) 1999-2004, 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 #include "unicode/putil.h"
19
20
21 #include "udatamem.h"
22 #include "umapfile.h"
23
24
25 /* memory-mapping base definitions ------------------------------------------ */
26
27
28 #define MAP_WIN32 1
29 #define MAP_POSIX 2
30 #define MAP_FILE_STREAM 3
31 #define MAP_390DLL 4
32
33 #ifdef WIN32
34 # define WIN32_LEAN_AND_MEAN
35 # define VC_EXTRALEAN
36 # define NOUSER
37 # define NOSERVICE
38 # define NOIME
39 # define NOMCX
40 # include <windows.h>
41
42 typedef HANDLE MemoryMap;
43
44 # define IS_MAP(map) ((map)!=NULL)
45
46 # define MAP_IMPLEMENTATION MAP_WIN32
47
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;
51
52 # define IS_MAP(map) ((map)!=0)
53
54 /* Needed by OSF to get the correct mmap version */
55 # ifndef _XOPEN_SOURCE_EXTENDED
56 # define _XOPEN_SOURCE_EXTENDED
57 # endif
58
59 # include <unistd.h>
60 # include <sys/mman.h>
61 # include <sys/stat.h>
62 # include <fcntl.h>
63
64 # ifndef MAP_FAILED
65 # define MAP_FAILED ((void*)-1)
66 # endif
67
68 # if defined(OS390) && defined (OS390_STUBDATA)
69 /* No memory mapping for 390 batch mode. Fake it using dll loading. */
70 # include <dll.h>
71 # include "cstring.h"
72 # include "cmemory.h"
73 # include "unicode/udata.h"
74 # define LIB_PREFIX "lib"
75 # define LIB_SUFFIX ".dll"
76 # define MAP_IMPLEMENTATION MAP_390DLL
77
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"
80 # else
81 # define MAP_IMPLEMENTATION MAP_POSIX
82 # endif
83
84 #else /* unknown platform, no memory map implementation: use FileStream/uprv_malloc() instead */
85
86 # include "filestrm.h"
87 # include "cmemory.h"
88
89 typedef void *MemoryMap;
90
91 # define IS_MAP(map) ((map)!=NULL)
92
93 # define MAP_IMPLEMENTATION MAP_FILE_STREAM
94
95 #endif
96
97
98
99
100 /*----------------------------------------------------------------------------*
101 * *
102 * Memory Mapped File support. Platform dependent implementation of *
103 * functions used by the rest of the implementation.*
104 * *
105 *----------------------------------------------------------------------------*/
106 #if MAP_IMPLEMENTATION==MAP_WIN32
107 UBool
108 uprv_mapFile(
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 */
112 )
113 {
114 HANDLE map;
115 HANDLE file;
116
117 UDataMemory_init(pData); /* Clear the output struct. */
118
119 /* open the input file */
120 file=CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL,
121 OPEN_EXISTING,
122 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL);
123 if(file==INVALID_HANDLE_VALUE) {
124 return FALSE;
125 }
126
127 /* create an unnamed Windows file-mapping object for the specified file */
128 map=CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
129 CloseHandle(file);
130 if(map==NULL) {
131 return FALSE;
132 }
133
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) {
137 CloseHandle(map);
138 return FALSE;
139 }
140 pData->map=map;
141 return TRUE;
142 }
143
144
145 void
146 uprv_unmapFile(UDataMemory *pData) {
147 if(pData!=NULL && pData->map!=NULL) {
148 UnmapViewOfFile(pData->pHeader);
149 CloseHandle(pData->map);
150 pData->pHeader=NULL;
151 pData->map=NULL;
152 }
153 }
154
155
156
157 #elif MAP_IMPLEMENTATION==MAP_POSIX
158 UBool
159 uprv_mapFile(UDataMemory *pData, const char *path) {
160 int fd;
161 int length;
162 struct stat mystat;
163 void *data;
164
165 UDataMemory_init(pData); /* Clear the output struct. */
166
167 /* determine the length of the file */
168 if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
169 return FALSE;
170 }
171 length=mystat.st_size;
172
173 /* open the file */
174 fd=open(path, O_RDONLY);
175 if(fd==-1) {
176 return FALSE;
177 }
178
179 /* get a view of the mapping */
180 #ifndef U_HPUX
181 data=mmap(0, length, PROT_READ, MAP_SHARED, fd, 0);
182 #else
183 data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0);
184 #endif
185 close(fd); /* no longer needed */
186 if(data==MAP_FAILED) {
187 return FALSE;
188 }
189
190 pData->map = (char *)data + length;
191 pData->pHeader=(const DataHeader *)data;
192 pData->mapAddr = data;
193 return TRUE;
194 }
195
196
197
198 void
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) {
203 }
204 pData->pHeader=NULL;
205 pData->map=0;
206 pData->mapAddr=NULL;
207 }
208 }
209
210
211
212 #elif MAP_IMPLEMENTATION==MAP_FILE_STREAM
213 UBool
214 uprv_mapFile(UDataMemory *pData, const char *path) {
215 FileStream *file;
216 int32_t fileLength;
217 void *p;
218
219 UDataMemory_init(pData); /* Clear the output struct. */
220 /* open the input file */
221 file=T_FileStream_open(path, "rb");
222 if(file==NULL) {
223 return FALSE;
224 }
225
226 /* get the file length */
227 fileLength=T_FileStream_size(file);
228 if(T_FileStream_error(file) || fileLength<=20) {
229 T_FileStream_close(file);
230 return FALSE;
231 }
232
233 /* allocate the memory to hold the file data */
234 p=uprv_malloc(fileLength);
235 if(p==NULL) {
236 T_FileStream_close(file);
237 return FALSE;
238 }
239
240 /* read the file */
241 if(fileLength!=T_FileStream_read(file, p, fileLength)) {
242 uprv_free(p);
243 T_FileStream_close(file);
244 return FALSE;
245 }
246
247 T_FileStream_close(file);
248 pData->map=p;
249 pData->pHeader=(const DataHeader *)p;
250 pData->mapAddr=p;
251 return TRUE;
252 }
253
254 void
255 uprv_unmapFile(UDataMemory *pData) {
256 if(pData!=NULL && pData->map!=NULL) {
257 uprv_free(pData->map);
258 pData->map = NULL;
259 pData->mapAddr = NULL;
260 pData->pHeader = NULL;
261 }
262 }
263
264
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.
270 *
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.
273 *
274 */
275
276 static char *strcpy_returnEnd(char *dest, const char *src)
277 {
278 while((*dest=*src)!=0) {
279 ++dest;
280 ++src;
281 }
282 return dest;
283 }
284
285 /*------------------------------------------------------------------------------
286 *
287 * computeDirPath given a user-supplied path of an item to be opened,
288 * compute and return
289 * - the full directory path to be used
290 * when opening the file.
291 * - Pointer to null at end of above returned path
292 *
293 * Parameters:
294 * path: input path. Buffer is not altered.
295 * pathBuffer: Output buffer. Any contents are overwritten.
296 *
297 * Returns:
298 * Pointer to null termination in returned pathBuffer.
299 *
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.)
305 *
306 *------------------------------------------------------------------------------*/
307 static char *uprv_computeDirPath(const char *path, char *pathBuffer)
308 {
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 */
311
312 finalSlash = 0;
313 if (path != 0) {
314 finalSlash = uprv_strrchr(path, U_FILE_SEP_CHAR);
315 }
316
317 *pathBuffer = 0;
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);
325 } else {
326 /* there is no icuDataDir either. Just return the empty pathBuffer. */
327 return pathBuffer;
328 }
329 }
330
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;
337 }
338
339
340 # define DATA_TYPE "dat"
341
342 UBool uprv_mapFile(UDataMemory *pData, const char *path) {
343 const char *inBasename;
344 char *basename;
345 char pathBuffer[1024];
346 const DataHeader *pHeader;
347 dllhandle *handle;
348 void *val=0;
349
350 inBasename=uprv_strrchr(path, U_FILE_SEP_CHAR);
351 if(inBasename==NULL) {
352 inBasename = path;
353 } else {
354 inBasename++;
355 }
356 basename=uprv_computeDirPath(path, pathBuffer);
357 if(uprv_strcmp(inBasename, U_ICUDATA_NAME".dat") != 0) {
358 /* must mmap file... for build */
359 int fd;
360 int length;
361 struct stat mystat;
362 void *data;
363 UDataMemory_init(pData); /* Clear the output struct. */
364
365 /* determine the length of the file */
366 if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
367 return FALSE;
368 }
369 length=mystat.st_size;
370
371 /* open the file */
372 fd=open(path, O_RDONLY);
373 if(fd==-1) {
374 return FALSE;
375 }
376
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) {
381 return FALSE;
382 }
383 pData->map = (char *)data + length;
384 pData->pHeader=(const DataHeader *)data;
385 pData->mapAddr = data;
386 return TRUE;
387 }
388
389 # ifdef OS390BATCH
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 */
398 /* PROJECT!!!!! */
399 uprv_strcpy(pathBuffer, "IXMI" U_ICU_VERSION_SHORT "DA");
400 # else
401 /* set up the library name */
402 uprv_strcpy(basename, LIB_PREFIX U_LIBICUDATA_NAME U_ICU_VERSION_SHORT LIB_SUFFIX);
403 # endif
404
405 # ifdef UDATA_DEBUG
406 fprintf(stderr, "dllload: %s ", pathBuffer);
407 # endif
408
409 handle=dllload(pathBuffer);
410
411 # ifdef UDATA_DEBUG
412 fprintf(stderr, " -> %08X\n", handle );
413 # endif
414
415 if(handle != NULL) {
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);
420 if(val == 0) {
421 /* failed... so keep looking */
422 return FALSE;
423 }
424 # ifdef UDATA_DEBUG
425 fprintf(stderr, "dllqueryvar(%08X, %s) -> %08X\n", handle, U_ICUDATA_ENTRY_NAME, val);
426 # endif
427
428 pData->pHeader=(const DataHeader *)val;
429 return TRUE;
430 } else {
431 return FALSE; /* no handle */
432 }
433 }
434
435
436
437 void uprv_unmapFile(UDataMemory *pData) {
438 if(pData!=NULL && pData->map!=NULL) {
439 uprv_free(pData->map);
440 pData->map = NULL;
441 pData->mapAddr = NULL;
442 pData->pHeader = NULL;
443 }
444 }
445
446 #else
447 # error MAP_IMPLEMENTATION is set incorrectly
448 #endif
449
450