Skip to content

Instantly share code, notes, and snippets.

@ColonelThirtyTwo
Created January 29, 2013 20:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ColonelThirtyTwo/4667673 to your computer and use it in GitHub Desktop.
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.
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