mirror of https://github.com/mgba-emu/mgba.git
Python: Add VFS bindings
This commit is contained in:
parent
0d1d5c988e
commit
606d35ba6c
|
@ -1,14 +1,15 @@
|
||||||
#define COMMON_H
|
#define COMMON_H
|
||||||
#define extern
|
|
||||||
#define _TIME_H_
|
#define _TIME_H_
|
||||||
#define _SYS_TIME_H_
|
#define _SYS_TIME_H_
|
||||||
#define ATTRIBUTE_FORMAT(X, Y, Z)
|
#define ATTRIBUTE_FORMAT(X, Y, Z)
|
||||||
#define DECL_BITFIELD(newtype, oldtype) typedef oldtype newtype
|
#define DECL_BITFIELD(newtype, oldtype) typedef oldtype newtype
|
||||||
#define DECL_BIT(type, name, bit)
|
#define DECL_BIT(type, name, bit)
|
||||||
#define DECL_BITS(type, name, bit, nbits)
|
#define DECL_BITS(type, name, bit, nbits)
|
||||||
typedef long time_t;
|
typedef int... time_t;
|
||||||
|
typedef int... off_t;
|
||||||
typedef ... va_list;
|
typedef ... va_list;
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include "platform/python/vfs-py.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#ifdef M_CORE_GBA
|
#ifdef M_CORE_GBA
|
||||||
#include "arm/arm.h"
|
#include "arm/arm.h"
|
||||||
|
|
|
@ -13,10 +13,19 @@ ffi.set_source("mgba._pylib", """
|
||||||
#include "gba/gba.h"
|
#include "gba/gba.h"
|
||||||
#include "lr35902/lr35902.h"
|
#include "lr35902/lr35902.h"
|
||||||
#include "gb/gb.h"
|
#include "gb/gb.h"
|
||||||
|
#include "util/vfs.h"
|
||||||
|
|
||||||
|
struct VFile* VFileFromPython(void* fileobj);
|
||||||
|
|
||||||
|
struct VFilePy {
|
||||||
|
struct VFile d;
|
||||||
|
void* fileobj;
|
||||||
|
};
|
||||||
""", include_dirs=[src],
|
""", include_dirs=[src],
|
||||||
extra_compile_args=sys.argv[1:],
|
extra_compile_args=sys.argv[1:],
|
||||||
libraries=["mgba"],
|
libraries=["mgba"],
|
||||||
library_dirs=[os.path.join(os.getcwd(), "..")])
|
library_dirs=[os.path.join(os.getcwd(), "..")],
|
||||||
|
sources=[os.path.join(os.path.dirname(__file__), path) for path in ["vfs-py.c"]])
|
||||||
|
|
||||||
with open(os.path.join(os.getcwd(), "_builder.h")) as core:
|
with open(os.path.join(os.getcwd(), "_builder.h")) as core:
|
||||||
lines = []
|
lines = []
|
||||||
|
|
|
@ -6,12 +6,24 @@ def find(path):
|
||||||
return None
|
return None
|
||||||
return Core(core)
|
return Core(core)
|
||||||
|
|
||||||
|
def findVF(vf):
|
||||||
|
core = lib.mCoreFindVF(vf.handle())
|
||||||
|
if core == ffi.NULL:
|
||||||
|
return None
|
||||||
|
return Core(core)
|
||||||
|
|
||||||
def loadPath(path):
|
def loadPath(path):
|
||||||
core = find(path)
|
core = find(path)
|
||||||
if not core or not core.loadFile(path):
|
if not core or not core.loadFile(path):
|
||||||
return None
|
return None
|
||||||
return core
|
return core
|
||||||
|
|
||||||
|
def loadVF(vf):
|
||||||
|
core = findVF(vf)
|
||||||
|
if not core or not core.loadROM(vf):
|
||||||
|
return None
|
||||||
|
return core
|
||||||
|
|
||||||
class Core:
|
class Core:
|
||||||
def __init__(self, native):
|
def __init__(self, native):
|
||||||
self._core = ffi.gc(native, self._deinit)
|
self._core = ffi.gc(native, self._deinit)
|
||||||
|
@ -32,6 +44,12 @@ class Core:
|
||||||
def loadFile(self, path):
|
def loadFile(self, path):
|
||||||
return bool(lib.mCoreLoadFile(self._core, path.encode('UTF-8')))
|
return bool(lib.mCoreLoadFile(self._core, path.encode('UTF-8')))
|
||||||
|
|
||||||
|
def isROM(self, vf):
|
||||||
|
return bool(self._core.isROM(vf.handle()))
|
||||||
|
|
||||||
|
def loadROM(self, vf):
|
||||||
|
return bool(self._core.loadROM(self._core, vf.handle()))
|
||||||
|
|
||||||
def autoloadSave(self):
|
def autoloadSave(self):
|
||||||
return bool(lib.mCoreAutoloadSave(self._core))
|
return bool(lib.mCoreAutoloadSave(self._core))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
from _pylib import ffi, lib
|
||||||
|
import mmap
|
||||||
|
import os
|
||||||
|
|
||||||
|
@ffi.def_extern()
|
||||||
|
def _vfpClose(vf):
|
||||||
|
vfp = ffi.cast("struct VFilePy*", vf)
|
||||||
|
ffi.from_handle(vfp.fileobj).close()
|
||||||
|
|
||||||
|
@ffi.def_extern()
|
||||||
|
def _vfpSeek(vf, offset, whence):
|
||||||
|
vfp = ffi.cast("struct VFilePy*", vf)
|
||||||
|
f = ffi.from_handle(vfp.fileobj)
|
||||||
|
f.seek(offset, whence)
|
||||||
|
return f.tell()
|
||||||
|
|
||||||
|
@ffi.def_extern()
|
||||||
|
def _vfpRead(vf, buffer, size):
|
||||||
|
vfp = ffi.cast("struct VFilePy*", vf)
|
||||||
|
pybuf = ffi.buffer(buffer, size)
|
||||||
|
return ffi.from_handle(vfp.fileobj).readinto(pybuf)
|
||||||
|
|
||||||
|
@ffi.def_extern()
|
||||||
|
def _vfpWrite(vf, buffer, size):
|
||||||
|
vfp = ffi.cast("struct VFilePy*", vf)
|
||||||
|
pybuf = ffi.buffer(buffer, size)
|
||||||
|
return ffi.from_handle(vfp.fileobj).write(pybuf)
|
||||||
|
|
||||||
|
@ffi.def_extern()
|
||||||
|
def _vfpMap(vf, size, flags):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@ffi.def_extern()
|
||||||
|
def _vfpUnmap(vf, memory, size):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@ffi.def_extern()
|
||||||
|
def _vfpTruncate(vf, size):
|
||||||
|
vfp = ffi.cast("struct VFilePy*", vf)
|
||||||
|
ffi.from_handle(vfp.fileobj).truncate(size)
|
||||||
|
|
||||||
|
@ffi.def_extern()
|
||||||
|
def _vfpSize(vf):
|
||||||
|
vfp = ffi.cast("struct VFilePy*", vf)
|
||||||
|
f = ffi.from_handle(vfp.fileobj)
|
||||||
|
pos = f.tell()
|
||||||
|
f.seek(0, os.SEEK_END)
|
||||||
|
size = f.tell()
|
||||||
|
f.seek(pos, os.SEEK_SET)
|
||||||
|
return size
|
||||||
|
|
||||||
|
@ffi.def_extern()
|
||||||
|
def _vfpSync(vf, buffer, size):
|
||||||
|
vfp = ffi.cast("struct VFilePy*", vf)
|
||||||
|
f = ffi.from_handle(vfp.fileobj)
|
||||||
|
if buffer and size:
|
||||||
|
pos = f.tell()
|
||||||
|
f.seek(0, os.SEEK_SET)
|
||||||
|
_vfpWrite(vf, buffer, size)
|
||||||
|
f.seek(pos, os.SEEK_SET)
|
||||||
|
f.flush()
|
||||||
|
os.fsync()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def open(f):
|
||||||
|
handle = ffi.new_handle(f)
|
||||||
|
vf = VFile(lib.VFileFromPython(handle))
|
||||||
|
# Prevent garbage collection
|
||||||
|
vf._fileobj = f
|
||||||
|
vf._handle = handle
|
||||||
|
return vf
|
||||||
|
|
||||||
|
def openPath(path, mode="r"):
|
||||||
|
flags = 0
|
||||||
|
if mode.startswith("r"):
|
||||||
|
flags |= os.O_RDONLY
|
||||||
|
elif mode.startswith("w"):
|
||||||
|
flags |= os.O_WRONLY | os.O_CREAT | os.O_TRUNC
|
||||||
|
elif mode.startswith("a"):
|
||||||
|
flags |= os.O_WRONLY | os.O_CREAT | os.O_APPEND
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if "+" in mode[1:]:
|
||||||
|
flags |= os.O_RDWR
|
||||||
|
if "x" in mode[1:]:
|
||||||
|
flags |= os.O_EXCL
|
||||||
|
|
||||||
|
return VFile(lib.VFileOpen(path.encode("UTF-8"), flags))
|
||||||
|
|
||||||
|
class VFile:
|
||||||
|
def __init__(self, vf):
|
||||||
|
self._vf = vf
|
||||||
|
|
||||||
|
def handle(self):
|
||||||
|
return self._vf
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
return self._vf.close(self._vf)
|
||||||
|
|
||||||
|
def seek(self, offset, whence):
|
||||||
|
return self._vf.seek(self._vf, offset, whence)
|
||||||
|
|
||||||
|
def read(self, buffer, size):
|
||||||
|
return self._vf.read(self._vf, buffer, size)
|
||||||
|
|
||||||
|
def readline(self, buffer, size):
|
||||||
|
return self._vf.readline(self._vf, buffer, size)
|
||||||
|
|
||||||
|
def write(self, buffer, size):
|
||||||
|
return self._vf.write(self._vf, buffer, size)
|
||||||
|
|
||||||
|
def map(self, size, flags):
|
||||||
|
return self._vf.map(self._vf, size, flags)
|
||||||
|
|
||||||
|
def unmap(self, memory, size):
|
||||||
|
self._vf.unmap(self._vf, memory, size)
|
||||||
|
|
||||||
|
def truncate(self, size):
|
||||||
|
self._vf.truncate(self._vf, size)
|
||||||
|
|
||||||
|
def size(self):
|
||||||
|
return self._vf.size(self._vf)
|
||||||
|
|
||||||
|
def sync(self, buffer, size):
|
||||||
|
return self._vf.sync(self._vf, buffer, size)
|
|
@ -1,4 +1,5 @@
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
import re
|
||||||
|
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Programming Language :: Python :: 2",
|
"Programming Language :: Python :: 2",
|
||||||
|
@ -6,9 +7,8 @@ classifiers = [
|
||||||
"License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)"
|
"License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
setup(name="${BINARY_NAME}",
|
setup(name="${BINARY_NAME}",
|
||||||
version="${VERSION_STRING}",
|
version=re.sub("/", "-", "${VERSION_STRING}"),
|
||||||
author="Jeffrey Pfau",
|
author="Jeffrey Pfau",
|
||||||
author_email="jeffrey@endrift.com",
|
author_email="jeffrey@endrift.com",
|
||||||
url="http://github.com/mgba-emu/mgba/",
|
url="http://github.com/mgba-emu/mgba/",
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#include "util/vfs.h"
|
||||||
|
|
||||||
|
struct VFilePy {
|
||||||
|
struct VFile d;
|
||||||
|
void* fileobj;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool _vfpClose(struct VFile* vf);
|
||||||
|
off_t _vfpSeek(struct VFile* vf, off_t offset, int whence);
|
||||||
|
ssize_t _vfpRead(struct VFile* vf, void* buffer, size_t size);
|
||||||
|
ssize_t _vfpWrite(struct VFile* vf, const void* buffer, size_t size);
|
||||||
|
void* _vfpMap(struct VFile* vf, size_t size, int flags);
|
||||||
|
void _vfpUnmap(struct VFile* vf, void* memory, size_t size);
|
||||||
|
void _vfpTruncate(struct VFile* vf, size_t size);
|
||||||
|
ssize_t _vfpSize(struct VFile* vf);
|
||||||
|
bool _vfpSync(struct VFile* vf, const void* buffer, size_t size);
|
||||||
|
|
||||||
|
struct VFile* VFileFromPython(void* fileobj) {
|
||||||
|
if (!fileobj) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VFilePy* vfp = malloc(sizeof(struct VFilePy));
|
||||||
|
if (!vfp) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfp->fileobj = fileobj;
|
||||||
|
vfp->d.close = _vfpClose;
|
||||||
|
vfp->d.seek = _vfpSeek;
|
||||||
|
vfp->d.read = _vfpRead;
|
||||||
|
vfp->d.readline = VFileReadline;
|
||||||
|
vfp->d.write = _vfpWrite;
|
||||||
|
vfp->d.map = _vfpMap;
|
||||||
|
vfp->d.unmap = _vfpUnmap;
|
||||||
|
vfp->d.truncate = _vfpTruncate;
|
||||||
|
vfp->d.size = _vfpSize;
|
||||||
|
vfp->d.sync = _vfpSync;
|
||||||
|
|
||||||
|
return &vfp->d;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "util/vfs.h"
|
||||||
|
|
||||||
|
struct VFilePy {
|
||||||
|
struct VFile d;
|
||||||
|
void* fileobj;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VFile* VFileFromPython(void* fileobj);
|
||||||
|
|
||||||
|
extern "Python+C" {
|
||||||
|
|
||||||
|
bool _vfpClose(struct VFile* vf);
|
||||||
|
off_t _vfpSeek(struct VFile* vf, off_t offset, int whence);
|
||||||
|
ssize_t _vfpRead(struct VFile* vf, void* buffer, size_t size);
|
||||||
|
ssize_t _vfpWrite(struct VFile* vf, const void* buffer, size_t size);
|
||||||
|
void* _vfpMap(struct VFile* vf, size_t size, int flags);
|
||||||
|
void _vfpUnmap(struct VFile* vf, void* memory, size_t size);
|
||||||
|
void _vfpTruncate(struct VFile* vf, size_t size);
|
||||||
|
ssize_t _vfpSize(struct VFile* vf);
|
||||||
|
bool _vfpSync(struct VFile* vf, const void* buffer, size_t size);
|
||||||
|
|
||||||
|
}
|
|
@ -65,12 +65,11 @@ struct VDir {
|
||||||
struct VFile* VFileOpen(const char* path, int flags);
|
struct VFile* VFileOpen(const char* path, int flags);
|
||||||
|
|
||||||
struct VFile* VFileOpenFD(const char* path, int flags);
|
struct VFile* VFileOpenFD(const char* path, int flags);
|
||||||
struct VFile* VFileFOpen(const char* path, const char* mode);
|
|
||||||
struct VFile* VFileFromFD(int fd);
|
struct VFile* VFileFromFD(int fd);
|
||||||
|
|
||||||
struct VFile* VFileFromMemory(void* mem, size_t size);
|
struct VFile* VFileFromMemory(void* mem, size_t size);
|
||||||
struct VFile* VFileFromConstMemory(const void* mem, size_t size);
|
struct VFile* VFileFromConstMemory(const void* mem, size_t size);
|
||||||
struct VFile* VFileMemChunk(const void* mem, size_t size);
|
struct VFile* VFileMemChunk(const void* mem, size_t size);
|
||||||
struct VFile* VFileFromFILE(FILE* file);
|
|
||||||
|
|
||||||
struct VDir* VDirOpen(const char* path);
|
struct VDir* VDirOpen(const char* path);
|
||||||
struct VDir* VDirOpenArchive(const char* path);
|
struct VDir* VDirOpenArchive(const char* path);
|
||||||
|
@ -83,7 +82,11 @@ struct VDir* VDirOpenZip(const char* path, int flags);
|
||||||
struct VDir* VDirOpen7z(const char* path, int flags);
|
struct VDir* VDirOpen7z(const char* path, int flags);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(WII) || defined(_3DS)
|
||||||
|
struct VFile* VFileFOpen(const char* path, const char* mode);
|
||||||
|
struct VFile* VFileFromFILE(FILE* file);
|
||||||
struct VDir* VDeviceList(void);
|
struct VDir* VDeviceList(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
void separatePath(const char* path, char* dirname, char* basename, char* extension);
|
void separatePath(const char* path, char* dirname, char* basename, char* extension);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue