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