src/platform/qt/VFileDevice.cpp (view raw)
1/* Copyright (c) 2013-2014 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#include "VFileDevice.h"
7
8#include <QBuffer>
9
10#include <mgba-util/vfs.h>
11
12using namespace QGBA;
13
14namespace QGBA {
15
16class VFileAbstractWrapper : public VFile {
17public:
18 VFileAbstractWrapper(QIODevice*);
19
20protected:
21 QIODevice* m_iodev;
22
23private:
24 static bool close(struct VFile* vf);
25 static off_t seek(struct VFile* vf, off_t offset, int whence);
26 static ssize_t read(struct VFile* vf, void* buffer, size_t size);
27 static ssize_t readline(struct VFile* vf, char* buffer, size_t size);
28 static ssize_t write(struct VFile* vf, const void* buffer, size_t size);
29 static void* map(struct VFile* vf, size_t size, int flags);
30 static void unmap(struct VFile* vf, void* memory, size_t size);
31 static void truncate(struct VFile* vf, size_t size);
32 static ssize_t size(struct VFile* vf);
33 static bool sync(struct VFile* vf, void* buffer, size_t size);
34
35};
36
37class VFileWrapper : public VFileAbstractWrapper {
38public:
39 VFileWrapper(QFileDevice*);
40
41protected:
42 QFileDevice* iodev() { return static_cast<QFileDevice*>(m_iodev); }
43
44private:
45 static bool close(struct VFile* vf);
46 static void* map(struct VFile* vf, size_t size, int flags);
47 static void unmap(struct VFile* vf, void* memory, size_t size);
48 static void truncate(struct VFile* vf, size_t size);
49 static bool sync(struct VFile* vf, void* buffer, size_t size);
50};
51
52class VFileBufferWrapper : public VFileAbstractWrapper {
53public:
54 VFileBufferWrapper(QBuffer*);
55
56protected:
57 QBuffer* iodev() { return static_cast<QBuffer*>(m_iodev); }
58
59private:
60 static bool close(struct VFile* vf);
61 static void* map(struct VFile* vf, size_t size, int flags);
62 static void unmap(struct VFile* vf, void* memory, size_t size);
63};
64
65}
66
67VFileDevice::VFileDevice(VFile* vf, QObject* parent)
68 : QIODevice(parent)
69 , m_vf(vf)
70{
71 // TODO: Correct mode
72 if (vf) {
73 setOpenMode(QIODevice::ReadWrite);
74 }
75}
76
77VFileDevice::VFileDevice(const QString& filename, QIODevice::OpenMode mode, QObject* parent)
78 : QIODevice(parent)
79{
80 int posixMode = 0;
81 if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
82 posixMode = O_RDWR;
83 } else if (mode & QIODevice::ReadOnly) {
84 posixMode = O_RDONLY;
85 } else if (mode & QIODevice::WriteOnly) {
86 posixMode = O_WRONLY;
87 }
88 m_vf = open(filename, posixMode);
89 if (m_vf) {
90 setOpenMode(mode);
91 }
92}
93
94VFileDevice::VFileDevice(const QByteArray& mem, QObject* parent)
95 : QIODevice(parent)
96 , m_vf(VFileMemChunk(mem.constData(), mem.size()))
97{
98 setOpenMode(QIODevice::ReadWrite);
99}
100
101VFileDevice::~VFileDevice() {
102 close();
103}
104
105void VFileDevice::close() {
106 if (!m_vf) {
107 return;
108 }
109 QIODevice::close();
110 m_vf->close(m_vf);
111 m_vf = nullptr;
112}
113
114bool VFileDevice::resize(qint64 sz) {
115 m_vf->truncate(m_vf, sz);
116 return true;
117}
118
119bool VFileDevice::seek(qint64 pos) {
120 QIODevice::seek(pos);
121 return m_vf->seek(m_vf, pos, SEEK_SET) == pos;
122}
123
124VFileDevice& VFileDevice::operator=(VFile* vf) {
125 close();
126 m_vf = vf;
127 setOpenMode(QIODevice::ReadWrite);
128 return *this;
129}
130
131VFile* VFileDevice::take() {
132 VFile* vf = m_vf;
133 m_vf = nullptr;
134 QIODevice::close();
135 return vf;
136}
137
138qint64 VFileDevice::readData(char* data, qint64 maxSize) {
139 return m_vf->read(m_vf, data, maxSize);
140}
141
142qint64 VFileDevice::writeData(const char* data, qint64 maxSize) {
143 return m_vf->write(m_vf, data, maxSize);
144}
145
146qint64 VFileDevice::size() const {
147 return m_vf->size(m_vf);
148}
149
150VFile* VFileDevice::wrap(QIODevice* iodev, QIODevice::OpenMode mode) {
151 if (!iodev->open(mode)) {
152 return nullptr;
153 }
154 return new VFileAbstractWrapper(iodev);
155}
156
157VFile* VFileDevice::wrap(QFileDevice* iodev, QIODevice::OpenMode mode) {
158 if (!iodev->open(mode)) {
159 return nullptr;
160 }
161 return new VFileWrapper(iodev);
162}
163
164VFile* VFileDevice::wrap(QBuffer* iodev, QIODevice::OpenMode mode) {
165 if (!iodev->open(mode)) {
166 return nullptr;
167 }
168 return new VFileBufferWrapper(iodev);
169}
170
171VFile* VFileDevice::open(const QString& path, int mode) {
172 return VFileOpen(path.toUtf8().constData(), mode);
173}
174
175VFile* VFileDevice::openMemory() {
176 return VFileMemChunk(nullptr, 0);
177}
178
179VDir* VFileDevice::openDir(const QString& path) {
180 return VDirOpen(path.toUtf8().constData());
181}
182
183VDir* VFileDevice::openArchive(const QString& path) {
184 return VDirOpenArchive(path.toUtf8().constData());
185}
186
187VFileAbstractWrapper::VFileAbstractWrapper(QIODevice* iodev)
188 : m_iodev(iodev)
189{
190 VFile::close = &VFileAbstractWrapper::close;
191 VFile::seek = &VFileAbstractWrapper::seek;
192 VFile::read = &VFileAbstractWrapper::read;
193 VFile::readline = &VFileAbstractWrapper::readline;
194 VFile::write = &VFileAbstractWrapper::write;
195 VFile::map = &VFileAbstractWrapper::map;
196 VFile::unmap = &VFileAbstractWrapper::unmap;
197 VFile::truncate = &VFileAbstractWrapper::truncate;
198 VFile::size = &VFileAbstractWrapper::size;
199 VFile::sync = &VFileAbstractWrapper::sync;
200}
201
202bool VFileAbstractWrapper::close(VFile* vf) {
203 QIODevice* iodev = static_cast<VFileAbstractWrapper*>(vf)->m_iodev;
204 iodev->close();
205 delete static_cast<VFileAbstractWrapper*>(vf);
206 return true;
207}
208
209off_t VFileAbstractWrapper::seek(VFile* vf, off_t offset, int whence) {
210 QIODevice* iodev = static_cast<VFileAbstractWrapper*>(vf)->m_iodev;
211 switch (whence) {
212 case SEEK_SET:
213 if (!iodev->seek(offset)) {
214 return -1;
215 }
216 break;
217 case SEEK_CUR:
218 if (!iodev->seek(iodev->pos() + offset)) {
219 return -1;
220 }
221 break;
222 case SEEK_END:
223 if (!iodev->seek(iodev->size() + offset)) {
224 return -1;
225 }
226 break;
227 }
228 return iodev->pos();
229}
230
231ssize_t VFileAbstractWrapper::read(VFile* vf, void* buffer, size_t size) {
232 QIODevice* iodev = static_cast<VFileAbstractWrapper*>(vf)->m_iodev;
233 return iodev->read(static_cast<char*>(buffer), size);
234}
235
236ssize_t VFileAbstractWrapper::readline(VFile* vf, char* buffer, size_t size) {
237 QIODevice* iodev = static_cast<VFileAbstractWrapper*>(vf)->m_iodev;
238 return iodev->readLine(static_cast<char*>(buffer), size);
239}
240
241ssize_t VFileAbstractWrapper::write(VFile* vf, const void* buffer, size_t size) {
242 QIODevice* iodev = static_cast<VFileAbstractWrapper*>(vf)->m_iodev;
243 return iodev->write(static_cast<const char*>(buffer), size);
244}
245
246void* VFileAbstractWrapper::map(VFile*, size_t, int) {
247 // Doesn't work on QIODevice base class
248 return nullptr;
249}
250
251void VFileAbstractWrapper::unmap(VFile*, void*, size_t) {
252 // Doesn't work on QIODevice base class
253}
254
255void VFileAbstractWrapper::truncate(VFile*, size_t) {
256 // Doesn't work on QIODevice base class
257}
258
259ssize_t VFileAbstractWrapper::size(VFile* vf) {
260 QIODevice* iodev = static_cast<VFileAbstractWrapper*>(vf)->m_iodev;
261 return iodev->size();
262}
263
264bool VFileAbstractWrapper::sync(VFile*, void*, size_t) {
265 // Doesn't work on QIODevice base class
266 return false;
267}
268
269VFileWrapper::VFileWrapper(QFileDevice* iodev)
270 : VFileAbstractWrapper(iodev)
271{
272 VFile::close = &VFileWrapper::close;
273 VFile::map = &VFileWrapper::map;
274 VFile::unmap = &VFileWrapper::unmap;
275 VFile::truncate = &VFileWrapper::truncate;
276 VFile::sync = &VFileWrapper::sync;
277}
278
279bool VFileWrapper::close(VFile* vf) {
280 QIODevice* iodev = static_cast<VFileWrapper*>(vf)->m_iodev;
281 iodev->close();
282 delete static_cast<VFileWrapper*>(vf);
283 return true;
284}
285
286void* VFileWrapper::map(VFile* vf, size_t size, int mode) {
287 QFileDevice* iodev = static_cast<VFileWrapper*>(vf)->iodev();
288 return iodev->map(0, size, mode == MAP_READ ? QFileDevice::MapPrivateOption : QFileDevice::NoOptions);
289}
290
291void VFileWrapper::unmap(VFile* vf, void* buffer, size_t) {
292 QFileDevice* iodev = static_cast<VFileWrapper*>(vf)->iodev();
293 iodev->unmap(static_cast<uchar*>(buffer));
294}
295
296void VFileWrapper::truncate(VFile* vf, size_t size) {
297 QFileDevice* iodev = static_cast<VFileWrapper*>(vf)->iodev();
298 iodev->resize(size);
299}
300
301bool VFileWrapper::sync(VFile* vf, void*, size_t) {
302 QFileDevice* iodev = static_cast<VFileWrapper*>(vf)->iodev();
303 return iodev->flush();
304}
305
306VFileBufferWrapper::VFileBufferWrapper(QBuffer* iodev)
307 : VFileAbstractWrapper(iodev)
308{
309 VFile::close = &VFileBufferWrapper::close;
310 VFile::map = &VFileBufferWrapper::map;
311}
312
313bool VFileBufferWrapper::close(VFile* vf) {
314 QIODevice* iodev = static_cast<VFileBufferWrapper*>(vf)->m_iodev;
315 iodev->close();
316 delete static_cast<VFileBufferWrapper*>(vf);
317 return true;
318}
319
320void* VFileBufferWrapper::map(VFile* vf, size_t, int) {
321 QBuffer* iodev = static_cast<VFileBufferWrapper*>(vf)->iodev();
322 QByteArray& buffer = iodev->buffer();
323 return static_cast<void*>(buffer.data());
324}