umapfile.cpp 11 KB

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