all repos — mgba @ 606d35ba6cc6170f200dde15ba5c839a9c553474

mGBA Game Boy Advance Emulator

Python: Add VFS bindings
Jeffrey Pfau jeffrey@endrift.com
Fri, 14 Oct 2016 15:30:40 -0700
commit

606d35ba6cc6170f200dde15ba5c839a9c553474

parent

0d1d5c988e2f60abb5c05a8cd61bdd9ec16d94f1

M src/platform/python/_builder.hsrc/platform/python/_builder.h

@@ -1,14 +1,15 @@

#define COMMON_H -#define extern #define _TIME_H_ #define _SYS_TIME_H_ #define ATTRIBUTE_FORMAT(X, Y, Z) #define DECL_BITFIELD(newtype, oldtype) typedef oldtype newtype #define DECL_BIT(type, name, bit) #define DECL_BITS(type, name, bit, nbits) -typedef long time_t; +typedef int... time_t; +typedef int... off_t; typedef ... va_list; #include <limits.h> +#include "platform/python/vfs-py.h" #include "core/core.h" #ifdef M_CORE_GBA #include "arm/arm.h"
M src/platform/python/_builder.pysrc/platform/python/_builder.py

@@ -13,10 +13,19 @@ #include "arm/arm.h"

#include "gba/gba.h" #include "lr35902/lr35902.h" #include "gb/gb.h" +#include "util/vfs.h" + +struct VFile* VFileFromPython(void* fileobj); + +struct VFilePy { + struct VFile d; + void* fileobj; +}; """, include_dirs=[src], extra_compile_args=sys.argv[1:], 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: lines = []
M src/platform/python/mgba/core.pysrc/platform/python/mgba/core.py

@@ -6,9 +6,21 @@ if core == ffi.NULL:

return None return Core(core) +def findVF(vf): + core = lib.mCoreFindVF(vf.handle()) + if core == ffi.NULL: + return None + return Core(core) + def loadPath(path): core = find(path) if not core or not core.loadFile(path): + return None + return core + +def loadVF(vf): + core = findVF(vf) + if not core or not core.loadROM(vf): return None return core

@@ -31,6 +43,12 @@ self._core.deinit(self._core)

def loadFile(self, path): 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): return bool(lib.mCoreAutoloadSave(self._core))
A src/platform/python/mgba/vfs.py

@@ -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)
M src/platform/python/setup.py.insrc/platform/python/setup.py.in

@@ -1,4 +1,5 @@

from setuptools import setup +import re classifiers = [ "Programming Language :: Python :: 2",

@@ -6,9 +7,8 @@ # "Programming Language :: Python :: 3",

"License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)" ] - setup(name="${BINARY_NAME}", - version="${VERSION_STRING}", + version=re.sub("/", "-", "${VERSION_STRING}"), author="Jeffrey Pfau", author_email="jeffrey@endrift.com", url="http://github.com/mgba-emu/mgba/",
A src/platform/python/vfs-py.c

@@ -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; +}
A src/platform/python/vfs-py.h

@@ -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); + +}
M src/util/vfs.hsrc/util/vfs.h

@@ -65,12 +65,11 @@

struct VFile* VFileOpen(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* VFileFromMemory(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* VFileFromFILE(FILE* file); struct VDir* VDirOpen(const char* path); struct VDir* VDirOpenArchive(const char* path);

@@ -83,7 +82,11 @@ #ifdef USE_LZMA

struct VDir* VDirOpen7z(const char* path, int flags); #endif +#if defined(WII) || defined(_3DS) +struct VFile* VFileFOpen(const char* path, const char* mode); +struct VFile* VFileFromFILE(FILE* file); struct VDir* VDeviceList(void); +#endif void separatePath(const char* path, char* dirname, char* basename, char* extension);