• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 ******************************************************************************
5 *
6 *   Copyright (C) 1999-2013, International Business Machines
7 *   Corporation and others.  All Rights Reserved.
8 *
9 ******************************************************************************/
10 
11 
12 /*----------------------------------------------------------------------------
13  *
14  *       Memory mapped file wrappers for use by the ICU Data Implementation
15  *       All of the platform-specific implementation for mapping data files
16  *         is here.  The rest of the ICU Data implementation uses only the
17  *         wrapper functions.
18  *
19  *----------------------------------------------------------------------------*/
20 /* Defines _XOPEN_SOURCE for access to POSIX functions.
21  * Must be before any other #includes. */
22 #include "uposixdefs.h"
23 
24 #include "unicode/putil.h"
25 #include "unicode/ustring.h"
26 #include "udatamem.h"
27 #include "umapfile.h"
28 
29 /* memory-mapping base definitions ------------------------------------------ */
30 
31 #if MAP_IMPLEMENTATION==MAP_WIN32
32 #ifndef WIN32_LEAN_AND_MEAN
33 #   define WIN32_LEAN_AND_MEAN
34 #endif
35 #   define VC_EXTRALEAN
36 #   define NOUSER
37 #   define NOSERVICE
38 #   define NOIME
39 #   define NOMCX
40 
41 #   if U_PLATFORM_HAS_WINUWP_API == 1
42         // Some previous versions of the Windows 10 SDK don't expose various APIs for UWP applications
43         // to use, even though UWP apps are allowed to call and use them.  Temporarily change the
44         // WINAPI family partition below to Desktop, so that function declarations are visible for UWP.
45 #       include <winapifamily.h>
46 #       if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM))
47 #           pragma push_macro("WINAPI_PARTITION_DESKTOP")
48 #           undef WINAPI_PARTITION_DESKTOP
49 #           define WINAPI_PARTITION_DESKTOP 1
50 #           define CHANGED_WINAPI_PARTITION_DESKTOP_VALUE
51 #       endif
52 #   endif
53 
54 #   include <windows.h>
55 
56 #   if U_PLATFORM_HAS_WINUWP_API == 1 && defined(CHANGED_WINAPI_PARTITION_DESKTOP_VALUE)
57 #       pragma pop_macro("WINAPI_PARTITION_DESKTOP")
58 #   endif
59 
60 #   include "cmemory.h"
61 
62 typedef HANDLE MemoryMap;
63 
64 #   define IS_MAP(map) ((map)!=nullptr)
65 
66 #elif MAP_IMPLEMENTATION==MAP_POSIX
67     typedef size_t MemoryMap;
68 
69 #   define IS_MAP(map) ((map)!=0)
70 
71 #   include <unistd.h>
72 #   include <sys/mman.h>
73 #   include <sys/stat.h>
74 #   include <fcntl.h>
75 
76 #   ifndef MAP_FAILED
77 #       define MAP_FAILED ((void*)-1)
78 #   endif
79 #elif MAP_IMPLEMENTATION==MAP_STDIO
80 #   include <stdio.h>
81 #   include "cmemory.h"
82 
83     typedef void *MemoryMap;
84 
85 #   define IS_MAP(map) ((map)!=nullptr)
86 #endif
87 
88 /*----------------------------------------------------------------------------*
89  *                                                                            *
90  *   Memory Mapped File support.  Platform dependent implementation of        *
91  *                           functions used by the rest of the implementation.*
92  *                                                                            *
93  *----------------------------------------------------------------------------*/
94 #if MAP_IMPLEMENTATION==MAP_NONE
95     U_CFUNC UBool
uprv_mapFile(UDataMemory * pData,const char * path,UErrorCode * status)96     uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) {
97         if (U_FAILURE(*status)) {
98             return false;
99         }
100         UDataMemory_init(pData); /* Clear the output struct. */
101         return false;            /* no file access */
102     }
103 
uprv_unmapFile(UDataMemory * pData)104     U_CFUNC void uprv_unmapFile(UDataMemory *pData) {
105         /* nothing to do */
106     }
107 #elif MAP_IMPLEMENTATION==MAP_WIN32
108     U_CFUNC UBool
uprv_mapFile(UDataMemory * pData,const char * path,UErrorCode * status)109     uprv_mapFile(
110          UDataMemory *pData,    /* Fill in with info on the result doing the mapping. */
111                                 /*   Output only; any original contents are cleared.  */
112          const char *path,      /* File path to be opened/mapped.                     */
113          UErrorCode *status     /* Error status, used to report out-of-memory errors. */
114          )
115     {
116         if (U_FAILURE(*status)) {
117             return false;
118         }
119 
120         HANDLE map = nullptr;
121         HANDLE file = INVALID_HANDLE_VALUE;
122 
123         UDataMemory_init(pData); /* Clear the output struct.        */
124 
125         /* open the input file */
126 #if U_PLATFORM_HAS_WINUWP_API == 0
127         // Note: In the non-UWP code-path (ie: Win32), the value of the path variable might have come from
128         // the CRT 'getenv' function, and would be therefore be encoded in the default ANSI code page.
129         // This means that we can't call the *W version of API below, whereas in the UWP code-path
130         // there is no 'getenv' call, and thus the string will be only UTF-8/Invariant characters.
131         file=CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, nullptr,
132             OPEN_EXISTING,
133             FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, nullptr);
134 #else
135         // Convert from UTF-8 string to UTF-16 string.
136         wchar_t utf16Path[MAX_PATH];
137         int32_t pathUtf16Len = 0;
138         u_strFromUTF8(reinterpret_cast<char16_t*>(utf16Path), static_cast<int32_t>(UPRV_LENGTHOF(utf16Path)), &pathUtf16Len, path, -1, status);
139 
140         if (U_FAILURE(*status)) {
141             return false;
142         }
143         if (*status == U_STRING_NOT_TERMINATED_WARNING) {
144             // Report back an error instead of a warning.
145             *status = U_BUFFER_OVERFLOW_ERROR;
146             return false;
147         }
148 
149         file = CreateFileW(utf16Path, GENERIC_READ, FILE_SHARE_READ, nullptr,
150             OPEN_EXISTING,
151             FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr);
152 #endif
153         if (file == INVALID_HANDLE_VALUE) {
154             // If we failed to open the file due to an out-of-memory error, then we want
155             // to report that error back to the caller.
156             if (HRESULT_FROM_WIN32(GetLastError()) == E_OUTOFMEMORY) {
157                 *status = U_MEMORY_ALLOCATION_ERROR;
158             }
159             return false;
160         }
161 
162         // Note: We use nullptr/nullptr for lpAttributes parameter below.
163         // This means our handle cannot be inherited and we will get the default security descriptor.
164         /* create an unnamed Windows file-mapping object for the specified file */
165         map = CreateFileMappingW(file, nullptr, PAGE_READONLY, 0, 0, nullptr);
166 
167         CloseHandle(file);
168         if (map == nullptr) {
169             // If we failed to create the mapping due to an out-of-memory error, then
170             // we want to report that error back to the caller.
171             if (HRESULT_FROM_WIN32(GetLastError()) == E_OUTOFMEMORY) {
172                 *status = U_MEMORY_ALLOCATION_ERROR;
173             }
174             return false;
175         }
176 
177         /* map a view of the file into our address space */
178         pData->pHeader = reinterpret_cast<const DataHeader *>(MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0));
179         if (pData->pHeader == nullptr) {
180             CloseHandle(map);
181             return false;
182         }
183         pData->map = map;
184         return true;
185     }
186 
187     U_CFUNC void
uprv_unmapFile(UDataMemory * pData)188     uprv_unmapFile(UDataMemory *pData) {
189         if (pData != nullptr && pData->map != nullptr) {
190             UnmapViewOfFile(pData->pHeader);
191             CloseHandle(pData->map);
192             pData->pHeader = nullptr;
193             pData->map = nullptr;
194         }
195     }
196 
197 
198 
199 #elif MAP_IMPLEMENTATION==MAP_POSIX
200     U_CFUNC UBool
uprv_mapFile(UDataMemory * pData,const char * path,UErrorCode * status)201     uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) {
202         int fd;
203         int length;
204         struct stat mystat;
205         void *data;
206 
207         if (U_FAILURE(*status)) {
208             return false;
209         }
210 
211         UDataMemory_init(pData); /* Clear the output struct.        */
212 
213         /* determine the length of the file */
214         if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
215             return false;
216         }
217         length=mystat.st_size;
218 
219         /* open the file */
220         fd=open(path, O_RDONLY);
221         if(fd==-1) {
222             return false;
223         }
224 
225         /* get a view of the mapping */
226 #if U_PLATFORM != U_PF_HPUX
227         data=mmap(nullptr, length, PROT_READ, MAP_SHARED, fd, 0);
228 #else
229         data=mmap(nullptr, length, PROT_READ, MAP_PRIVATE, fd, 0);
230 #endif
231         close(fd); /* no longer needed */
232         if(data==MAP_FAILED) {
233             // Possibly check the errno value for ENOMEM, and report U_MEMORY_ALLOCATION_ERROR?
234             return false;
235         }
236 
237         pData->map = (char *)data + length;
238         pData->pHeader=(const DataHeader *)data;
239         pData->mapAddr = data;
240         // Android-changed: madvise on Android for performance reason.
241 #if U_PLATFORM == U_PF_IPHONE || U_PLATFORM == U_PF_ANDROID
242         posix_madvise(data, length, POSIX_MADV_RANDOM);
243 #endif
244         return true;
245     }
246 
247     U_CFUNC void
uprv_unmapFile(UDataMemory * pData)248     uprv_unmapFile(UDataMemory *pData) {
249         if(pData!=nullptr && pData->map!=nullptr) {
250             size_t dataLen = (char *)pData->map - (char *)pData->mapAddr;
251             if(munmap(pData->mapAddr, dataLen)==-1) {
252             }
253             pData->pHeader=nullptr;
254             pData->map=nullptr;
255             pData->mapAddr=nullptr;
256         }
257     }
258 
259 
260 
261 #elif MAP_IMPLEMENTATION==MAP_STDIO
262     /* copy of the filestrm.c/T_FileStream_size() implementation */
263     static int32_t
umap_fsize(FILE * f)264     umap_fsize(FILE *f) {
265         int32_t savedPos = ftell(f);
266         int32_t size = 0;
267 
268         /*Changes by Bertrand A. D. doesn't affect the current position
269         goes to the end of the file before ftell*/
270         fseek(f, 0, SEEK_END);
271         size = (int32_t)ftell(f);
272         fseek(f, savedPos, SEEK_SET);
273         return size;
274     }
275 
276     U_CFUNC UBool
uprv_mapFile(UDataMemory * pData,const char * path,UErrorCode * status)277     uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) {
278         FILE *file;
279         int32_t fileLength;
280         void *p;
281 
282         if (U_FAILURE(*status)) {
283             return false;
284         }
285 
286         UDataMemory_init(pData); /* Clear the output struct.        */
287         /* open the input file */
288         file=fopen(path, "rb");
289         if(file==nullptr) {
290             return false;
291         }
292 
293         /* get the file length */
294         fileLength=umap_fsize(file);
295         if(ferror(file) || fileLength<=20) {
296             fclose(file);
297             return false;
298         }
299 
300         /* allocate the memory to hold the file data */
301         p=uprv_malloc(fileLength);
302         if(p==nullptr) {
303             fclose(file);
304             *status = U_MEMORY_ALLOCATION_ERROR;
305             return false;
306         }
307 
308         /* read the file */
309         if(fileLength!=fread(p, 1, fileLength, file)) {
310             uprv_free(p);
311             fclose(file);
312             return false;
313         }
314 
315         fclose(file);
316         pData->map=p;
317         pData->pHeader=(const DataHeader *)p;
318         pData->mapAddr=p;
319         return true;
320     }
321 
322     U_CFUNC void
uprv_unmapFile(UDataMemory * pData)323     uprv_unmapFile(UDataMemory *pData) {
324         if(pData!=nullptr && pData->map!=nullptr) {
325             uprv_free(pData->map);
326             pData->map     = nullptr;
327             pData->mapAddr = nullptr;
328             pData->pHeader = nullptr;
329         }
330     }
331 #else
332 #   error MAP_IMPLEMENTATION is set incorrectly
333 #endif
334