#include "uposixdefs.h"
#include "unicode/putil.h"
#include "unicode/ustring.h"
#include "udatamem.h"
#include "umapfile.h"
#if MAP_IMPLEMENTATION==MAP_WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#define VC_EXTRALEAN
#define NOUSER
#define NOSERVICE
#define NOIME
#define NOMCX
# if U_PLATFORM_HAS_WINUWP_API == 1
# include <winapifamily.h>
# if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM))
# pragma push_macro("WINAPI_PARTITION_DESKTOP")
# undef WINAPI_PARTITION_DESKTOP
#define WINAPI_PARTITION_DESKTOP …
#define CHANGED_WINAPI_PARTITION_DESKTOP_VALUE
# endif
# endif
# include <windows.h>
# if U_PLATFORM_HAS_WINUWP_API == 1 && defined(CHANGED_WINAPI_PARTITION_DESKTOP_VALUE)
# pragma pop_macro("WINAPI_PARTITION_DESKTOP")
# endif
# include "cmemory.h"
typedef HANDLE MemoryMap;
#define IS_MAP …
#elif MAP_IMPLEMENTATION==MAP_POSIX
typedef size_t MemoryMap;
#define IS_MAP …
# include <unistd.h>
# include <sys/mman.h>
# include <sys/stat.h>
# include <fcntl.h>
# ifndef MAP_FAILED
#define MAP_FAILED …
# endif
#elif MAP_IMPLEMENTATION==MAP_STDIO
# include <stdio.h>
# include "cmemory.h"
typedef void *MemoryMap;
#define IS_MAP …
#endif
#if MAP_IMPLEMENTATION==MAP_NONE
U_CFUNC UBool
uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) { … }
U_CFUNC void uprv_unmapFile(UDataMemory *pData) { … }
#elif MAP_IMPLEMENTATION==MAP_WIN32
U_CFUNC UBool
uprv_mapFile(
UDataMemory *pData,
const char *path,
UErrorCode *status
)
{
if (U_FAILURE(*status)) {
return false;
}
HANDLE map = nullptr;
HANDLE file = INVALID_HANDLE_VALUE;
UDataMemory_init(pData);
#if U_PLATFORM_HAS_WINUWP_API == 0
file=CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, nullptr);
#else
wchar_t utf16Path[MAX_PATH];
int32_t pathUtf16Len = 0;
u_strFromUTF8(reinterpret_cast<char16_t*>(utf16Path), static_cast<int32_t>(UPRV_LENGTHOF(utf16Path)), &pathUtf16Len, path, -1, status);
if (U_FAILURE(*status)) {
return false;
}
if (*status == U_STRING_NOT_TERMINATED_WARNING) {
*status = U_BUFFER_OVERFLOW_ERROR;
return false;
}
file = CreateFileW(utf16Path, GENERIC_READ, FILE_SHARE_READ, nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr);
#endif
if (file == INVALID_HANDLE_VALUE) {
if (HRESULT_FROM_WIN32(GetLastError()) == E_OUTOFMEMORY) {
*status = U_MEMORY_ALLOCATION_ERROR;
}
return false;
}
map = CreateFileMappingW(file, nullptr, PAGE_READONLY, 0, 0, nullptr);
CloseHandle(file);
if (map == nullptr) {
if (HRESULT_FROM_WIN32(GetLastError()) == E_OUTOFMEMORY) {
*status = U_MEMORY_ALLOCATION_ERROR;
}
return false;
}
pData->pHeader = reinterpret_cast<const DataHeader *>(MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0));
if (pData->pHeader == nullptr) {
CloseHandle(map);
return false;
}
pData->map = map;
return true;
}
U_CFUNC void
uprv_unmapFile(UDataMemory *pData) {
if (pData != nullptr && pData->map != nullptr) {
UnmapViewOfFile(pData->pHeader);
CloseHandle(pData->map);
pData->pHeader = nullptr;
pData->map = nullptr;
}
}
#elif MAP_IMPLEMENTATION==MAP_POSIX
U_CFUNC UBool
uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) {
int fd;
int length;
struct stat mystat;
void *data;
if (U_FAILURE(*status)) {
return false;
}
UDataMemory_init(pData);
if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
return false;
}
length=mystat.st_size;
fd=open(path, O_RDONLY);
if(fd==-1) {
return false;
}
#if U_PLATFORM != U_PF_HPUX
data=mmap(nullptr, length, PROT_READ, MAP_SHARED, fd, 0);
#else
data=mmap(nullptr, length, PROT_READ, MAP_PRIVATE, fd, 0);
#endif
close(fd);
if(data==MAP_FAILED) {
return false;
}
pData->map = (char *)data + length;
pData->pHeader=(const DataHeader *)data;
pData->mapAddr = data;
#if U_PLATFORM == U_PF_IPHONE
posix_madvise(data, length, POSIX_MADV_RANDOM);
#endif
return true;
}
U_CFUNC void
uprv_unmapFile(UDataMemory *pData) {
if(pData!=nullptr && pData->map!=nullptr) {
size_t dataLen = (char *)pData->map - (char *)pData->mapAddr;
if(munmap(pData->mapAddr, dataLen)==-1) {
}
pData->pHeader=nullptr;
pData->map=nullptr;
pData->mapAddr=nullptr;
}
}
#elif MAP_IMPLEMENTATION==MAP_STDIO
static int32_t
umap_fsize(FILE *f) {
int32_t savedPos = ftell(f);
int32_t size = 0;
fseek(f, 0, SEEK_END);
size = (int32_t)ftell(f);
fseek(f, savedPos, SEEK_SET);
return size;
}
U_CFUNC UBool
uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) {
FILE *file;
int32_t fileLength;
void *p;
if (U_FAILURE(*status)) {
return false;
}
UDataMemory_init(pData);
file=fopen(path, "rb");
if(file==nullptr) {
return false;
}
fileLength=umap_fsize(file);
if(ferror(file) || fileLength<=20) {
fclose(file);
return false;
}
p=uprv_malloc(fileLength);
if(p==nullptr) {
fclose(file);
*status = U_MEMORY_ALLOCATION_ERROR;
return false;
}
if(fileLength!=fread(p, 1, fileLength, file)) {
uprv_free(p);
fclose(file);
return false;
}
fclose(file);
pData->map=p;
pData->pHeader=(const DataHeader *)p;
pData->mapAddr=p;
return true;
}
U_CFUNC void
uprv_unmapFile(UDataMemory *pData) {
if(pData!=nullptr && pData->map!=nullptr) {
uprv_free(pData->map);
pData->map = nullptr;
pData->mapAddr = nullptr;
pData->pHeader = nullptr;
}
}
#else
# error MAP_IMPLEMENTATION is set incorrectly
#endif