src/platform/python/mgba/vfs.py (view raw)
1# Copyright (c) 2013-2016 Jeffrey Pfau
2#
3# This Source Code Form is subject to the terms of the Mozilla Public
4# License, v. 2.0. If a copy of the MPL was not distributed with this
5# file, You can obtain one at http://mozilla.org/MPL/2.0/.
6# pylint: disable=invalid-name,unused-argument
7from ._pylib import ffi, lib # pylint: disable=no-name-in-module
8import os
9
10
11@ffi.def_extern()
12def _vfpClose(vf):
13 vfp = ffi.cast("struct VFilePy*", vf)
14 ffi.from_handle(vfp.fileobj).close()
15 return True
16
17
18@ffi.def_extern()
19def _vfpSeek(vf, offset, whence):
20 vfp = ffi.cast("struct VFilePy*", vf)
21 f = ffi.from_handle(vfp.fileobj)
22 f.seek(offset, whence)
23 return f.tell()
24
25
26@ffi.def_extern()
27def _vfpRead(vf, buffer, size):
28 vfp = ffi.cast("struct VFilePy*", vf)
29 pybuf = ffi.buffer(buffer, size)
30 ffi.from_handle(vfp.fileobj).readinto(pybuf)
31 return size
32
33
34@ffi.def_extern()
35def _vfpWrite(vf, buffer, size):
36 vfp = ffi.cast("struct VFilePy*", vf)
37 pybuf = ffi.buffer(buffer, size)
38 ffi.from_handle(vfp.fileobj).write(pybuf)
39 return size
40
41
42@ffi.def_extern()
43def _vfpMap(vf, size, flags):
44 pass
45
46
47@ffi.def_extern()
48def _vfpUnmap(vf, memory, size):
49 pass
50
51
52@ffi.def_extern()
53def _vfpTruncate(vf, size):
54 vfp = ffi.cast("struct VFilePy*", vf)
55 ffi.from_handle(vfp.fileobj).truncate(size)
56
57
58@ffi.def_extern()
59def _vfpSize(vf):
60 vfp = ffi.cast("struct VFilePy*", vf)
61 f = ffi.from_handle(vfp.fileobj)
62 pos = f.tell()
63 f.seek(0, os.SEEK_END)
64 size = f.tell()
65 f.seek(pos, os.SEEK_SET)
66 return size
67
68
69@ffi.def_extern()
70def _vfpSync(vf, buffer, size):
71 vfp = ffi.cast("struct VFilePy*", vf)
72 f = ffi.from_handle(vfp.fileobj)
73 if buffer and size:
74 pos = f.tell()
75 f.seek(0, os.SEEK_SET)
76 res = _vfpWrite(vf, buffer, size)
77 f.seek(pos, os.SEEK_SET)
78 return res == size
79 f.flush()
80 os.fsync()
81 return True
82
83
84def open(f): # pylint: disable=redefined-builtin
85 handle = ffi.new_handle(f)
86 vf = VFile(lib.VFileFromPython(handle), _no_gc=(f, handle))
87 return vf
88
89
90def open_path(path, mode="r"):
91 flags = 0
92 if mode.startswith("r"):
93 flags |= os.O_RDONLY
94 elif mode.startswith("w"):
95 flags |= os.O_WRONLY | os.O_CREAT | os.O_TRUNC
96 elif mode.startswith("a"):
97 flags |= os.O_WRONLY | os.O_CREAT | os.O_APPEND
98 else:
99 return None
100
101 if "+" in mode[1:]:
102 flags |= os.O_RDWR
103 if "x" in mode[1:]:
104 flags |= os.O_EXCL
105
106 vf = lib.VFileOpen(path.encode("UTF-8"), flags)
107 if vf == ffi.NULL:
108 return None
109 return VFile(vf)
110
111
112class VFile:
113 def __init__(self, vf, _no_gc=None):
114 self.handle = vf
115 self._no_gc = _no_gc
116 self._claimed = False
117
118 @staticmethod
119 def fromEmpty():
120 return VFile(lib.VFileMemChunk(ffi.NULL, 0))
121
122 def __del__(self):
123 if not self._claimed:
124 self.close()
125
126 def close(self):
127 if self._claimed:
128 return False
129 self._claimed = True
130 return bool(self.handle.close(self.handle))
131
132 def seek(self, offset, whence):
133 return self.handle.seek(self.handle, offset, whence)
134
135 def read(self, buffer, size):
136 return self.handle.read(self.handle, buffer, size)
137
138 def read_all(self, size=0):
139 if not size:
140 size = self.size()
141 buffer = ffi.new("char[%i]" % size)
142 size = self.handle.read(self.handle, buffer, size)
143 return ffi.unpack(buffer, size)
144
145 def readline(self, buffer, size):
146 return self.handle.readline(self.handle, buffer, size)
147
148 def write(self, buffer, size):
149 return self.handle.write(self.handle, buffer, size)
150
151 def map(self, size, flags):
152 return self.handle.map(self.handle, size, flags)
153
154 def unmap(self, memory, size):
155 self.handle.unmap(self.handle, memory, size)
156
157 def truncate(self, size):
158 self.handle.truncate(self.handle, size)
159
160 def size(self):
161 return self.handle.size(self.handle)
162
163 def sync(self, buffer, size):
164 return self.handle.sync(self.handle, buffer, size)