Created
January 29, 2013 20:46
-
-
Save ColonelThirtyTwo/4667673 to your computer and use it in GitHub Desktop.
Windows file to memory mapping structure for LuaJIT, which I was going to use for my game but discovered a better solution.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local mmap = {} | |
mmap.__index = mmap | |
local new_map | |
local ffi = require "ffi" | |
ffi.cdef[[ | |
unsigned long GetLastError(); | |
void* CreateFileA( | |
const char* lpFileName, | |
unsigned long dwDesiredAccess, | |
unsigned long dwShareMode, | |
void* lpSecurityAttributes, | |
unsigned long dwCreationDisposition, | |
unsigned long dwFlagsAndAttributes, | |
void* hTemplateFile | |
); | |
unsigned long GetFileSize( | |
void* hFile, | |
unsigned long* lpFileSizeHigh | |
); | |
long WriteFile( | |
void* hFile, | |
void* lpBuffer, | |
unsigned long nNumberOfBytesToWrite, | |
unsigned long* lpNumberOfBytesWritten, | |
void* lpOverlapped | |
); | |
unsigned long SetFilePointer( | |
void* hFile, | |
long lDistanceToMove, | |
long* lpDistanceToMoveHigh, | |
unsigned long dwMoveMethod | |
); | |
void* CreateFileMappingA( | |
void* hFile, | |
void* lpAttributes, | |
unsigned long flProtect, | |
unsigned long dwMaximumSizeHigh, | |
unsigned long dwMaximumSizeLow, | |
const char* lpName | |
); | |
void* MapViewOfFile( | |
void* hFileMappingObject, | |
unsigned long dwDesiredAccess, | |
unsigned long dwFileOffsetHigh, | |
unsigned long dwFileOffsetLow, | |
size_t dwNumberOfBytesToMap | |
); | |
long UnmapViewOfFile(void* lpBaseAddress); | |
long CloseHandle(void* hObject); | |
long DeleteFileA(const char* lpFileName); | |
]] | |
local C = ffi.C | |
local bit = require "bit" | |
local ERROR_ALREADY_EXISTS = 183 | |
local GENERIC_READ = 0x80000000 | |
local GENERIC_WRITE = 0x40000000 | |
local OPEN_ALWAYS = 4 | |
local FILE_ATTRIBUTE_ARCHIVE = 0x20 | |
local FILE_FLAG_RANDOM_ACCESS = 0x10000000 | |
local FILE_BEGIN = 0 | |
local PAGE_READWRITE = 0x4 | |
local FILE_MAP_ALL_ACCESS = 0xf001f | |
function mmap:__new(filename, newsize) | |
local m = ffi.new(self, #filename+1) | |
-- Open file | |
m.filehandle = C.CreateFileA(filename, bit.bor(GENERIC_READ, GENERIC_WRITE), 0, nil, | |
OPEN_ALWAYS, bit.bor(FILE_ATTRIBUTE_ARCHIVE, FILE_FLAG_RANDOM_ACCESS), nil) | |
if m.filehandle == nil then | |
error("Could not create/open file for mmap: "..tostring(C.GetLastError())) | |
end | |
-- Set file size if new | |
local exists = C.GetLastError() == ERROR_ALREADY_EXISTS | |
if exists then | |
local fsize = C.GetFileSize(m.filehandle, nil) | |
if fsize == 0 then | |
-- Windows will error if mapping a 0-length file, fake a new one | |
exists = false | |
m.size = newsize | |
else | |
m.size = fsize | |
end | |
else | |
m.size = newsize | |
end | |
m.existed = exists | |
-- Open mapping | |
m.maphandle = C.CreateFileMappingA(m.filehandle, nil, PAGE_READWRITE, 0, m.size, nil) | |
if m.maphandle == nil then | |
error("Could not create file map: "..tostring(C.GetLastError())) | |
end | |
-- Open view | |
m.map = C.MapViewOfFile(m.maphandle, FILE_MAP_ALL_ACCESS, 0, 0, 0) | |
if m.map == nil then | |
error("Could not map: "..tostring(C.GetLastError())) | |
end | |
-- Copy filename (for delete) | |
ffi.copy(m.filename, filename) | |
return m | |
end | |
function mmap:getMap() | |
return self.map | |
end | |
function mmap:__len() | |
return self.size | |
end | |
function mmap:close(no_ungc) | |
if self.map ~= nil then | |
C.UnmapViewOfFile(self.map) | |
self.map = nil | |
end | |
if self.maphandle ~= nil then | |
C.CloseHandle(self.maphandle) | |
self.maphandle = nil | |
end | |
if self.filehandle ~= nil then | |
C.CloseHandle(self.filehandle) | |
self.filehandle = nil | |
end | |
if not no_ungc then ffi.gc(self, nil) end | |
end | |
function mmap:__gc() | |
self:close(true) | |
end | |
function mmap:delete() | |
self:close() | |
C.DeleteFileA(self.filename) | |
end | |
new_map = ffi.metatype([[struct { | |
short existed; | |
void* filehandle; | |
void* maphandle; | |
void* map; | |
int size; | |
char filename[?]; | |
}]], mmap) | |
return new_map |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment