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() {
95 close();
96}
97
98void VFileDevice::close() {
99 if (!m_vf) {
100 return;
101 }
102 QIODevice::close();
103 m_vf->close(m_vf);
104 m_vf = nullptr;
105}
106
107bool VFileDevice::resize(qint64 sz) {
108 m_vf->truncate(m_vf, sz);
109 return true;
110}
111
112bool VFileDevice::seek(qint64 pos) {
113 QIODevice::seek(pos);
114 return m_vf->seek(m_vf, pos, SEEK_SET) == pos;
115}
116
117VFileDevice& VFileDevice::operator=(VFile* vf) {
118 close();
119 m_vf = vf;
120 setOpenMode(QIODevice::ReadWrite);
121 return *this;
122}
123
124VFile* VFileDevice::take() {
125 VFile* vf = m_vf;
126 m_vf = nullptr;
127 QIODevice::close();
128 return vf;
129}
130
131qint64 VFileDevice::readData(char* data, qint64 maxSize) {
132 return m_vf->read(m_vf, data, maxSize);
133}
134
135qint64 VFileDevice::writeData(const char* data, qint64 maxSize) {
136 return m_vf->write(m_vf, data, maxSize);
137}
138
139qint64 VFileDevice::size() const {
140 return m_vf->size(m_vf);
141}
142
143VFile* VFileDevice::wrap(QIODevice* iodev, QIODevice::OpenMode mode) {
144 if (!iodev->open(mode)) {
145 return nullptr;
146 }
147 return new VFileAbstractWrapper(iodev);
148}
149
150VFile* VFileDevice::wrap(QFileDevice* iodev, QIODevice::OpenMode mode) {
151 if (!iodev->open(mode)) {
152 return nullptr;
153 }
154 return new VFileWrapper(iodev);
155}
156
157VFile* VFileDevice::wrap(QBuffer* iodev, QIODevice::OpenMode mode) {
158 if (!iodev->open(mode)) {
159 return nullptr;
160 }
161 return new VFileBufferWrapper(iodev);
162}
163
164VFile* VFileDevice::open(const QString& path, int mode) {
165 return VFileOpen(path.toUtf8().constData(), mode);
166}
167
168VFile* VFileDevice::openMemory() {
169 return VFileMemChunk(nullptr, 0);
170}
171
172VDir* VFileDevice::openDir(const QString& path) {
173 return VDirOpen(path.toUtf8().constData());
174}
175
176VDir* VFileDevice::openArchive(const QString& path) {
177 return VDirOpenArchive(path.toUtf8().constData());
178}
179
180VFileAbstractWrapper::VFileAbstractWrapper(QIODevice* iodev)
181 : m_iodev(iodev)
182{
183 VFile::close = &VFileAbstractWrapper::close;
184 VFile::seek = &VFileAbstractWrapper::seek;
185 VFile::read = &VFileAbstractWrapper::read;
186 VFile::readline = &VFileAbstractWrapper::readline;
187 VFile::write = &VFileAbstractWrapper::write;
188 VFile::map = &VFileAbstractWrapper::map;
189 VFile::unmap = &VFileAbstractWrapper::unmap;
190 VFile::truncate = &VFileAbstractWrapper::truncate;
191 VFile::size = &VFileAbstractWrapper::size;
192 VFile::sync = &VFileAbstractWrapper::sync;
193}
194
195bool VFileAbstractWrapper::close(VFile* vf) {
196 QIODevice* iodev = static_cast<VFileAbstractWrapper*>(vf)->m_iodev;
197 iodev->close();
198 delete static_cast<VFileAbstractWrapper*>(vf);
199 return true;
200}
201
202off_t VFileAbstractWrapper::seek(VFile* vf, off_t offset, int whence) {
203 QIODevice* iodev = static_cast<VFileAbstractWrapper*>(vf)->m_iodev;
204 switch (whence) {
205 case SEEK_SET:
206 if (!iodev->seek(offset)) {
207 return -1;
208 }
209 break;
210 case SEEK_CUR:
211 if (!iodev->seek(iodev->pos() + offset)) {
212 return -1;
213 }
214 break;
215 case SEEK_END:
216 if (!iodev->seek(iodev->size() + offset)) {
217 return -1;
218 }
219 break;
220 }
221 return iodev->pos();
222}
223
224ssize_t VFileAbstractWrapper::read(VFile* vf, void* buffer, size_t size) {
225 QIODevice* iodev = static_cast<VFileAbstractWrapper*>(vf)->m_iodev;
226 return iodev->read(static_cast<char*>(buffer), size);
227}
228
229ssize_t VFileAbstractWrapper::readline(VFile* vf, char* buffer, size_t size) {
230 QIODevice* iodev = static_cast<VFileAbstractWrapper*>(vf)->m_iodev;
231 return iodev->readLine(static_cast<char*>(buffer), size);
232}
233
234ssize_t VFileAbstractWrapper::write(VFile* vf, const void* buffer, size_t size) {
235 QIODevice* iodev = static_cast<VFileAbstractWrapper*>(vf)->m_iodev;
236 return iodev->write(static_cast<const char*>(buffer), size);
237}
238
239void* VFileAbstractWrapper::map(VFile*, size_t, int) {
240 // Doesn't work on QIODevice base class
241 return nullptr;
242}
243
244void VFileAbstractWrapper::unmap(VFile*, void*, size_t) {
245 // Doesn't work on QIODevice base class
246}
247
248void VFileAbstractWrapper::truncate(VFile*, size_t) {
249 // Doesn't work on QIODevice base class
250}
251
252ssize_t VFileAbstractWrapper::size(VFile* vf) {
253 QIODevice* iodev = static_cast<VFileAbstractWrapper*>(vf)->m_iodev;
254 return iodev->size();
255}
256
257bool VFileAbstractWrapper::sync(VFile*, void*, size_t) {
258 // Doesn't work on QIODevice base class
259 return false;
260}
261
262VFileWrapper::VFileWrapper(QFileDevice* iodev)
263 : VFileAbstractWrapper(iodev)
264{
265 VFile::close = &VFileWrapper::close;
266 VFile::map = &VFileWrapper::map;
267 VFile::unmap = &VFileWrapper::unmap;
268 VFile::truncate = &VFileWrapper::truncate;
269 VFile::sync = &VFileWrapper::sync;
270}
271
272bool VFileWrapper::close(VFile* vf) {
273 QIODevice* iodev = static_cast<VFileWrapper*>(vf)->m_iodev;
274 iodev->close();
275 delete static_cast<VFileWrapper*>(vf);
276 return true;
277}
278
279void* VFileWrapper::map(VFile* vf, size_t size, int mode) {
280 QFileDevice* iodev = static_cast<VFileWrapper*>(vf)->iodev();
281 return iodev->map(0, size, mode == MAP_READ ? QFileDevice::MapPrivateOption : QFileDevice::NoOptions);
282}
283
284void VFileWrapper::unmap(VFile* vf, void* buffer, size_t) {
285 QFileDevice* iodev = static_cast<VFileWrapper*>(vf)->iodev();
286 iodev->unmap(static_cast<uchar*>(buffer));
287}
288
289void VFileWrapper::truncate(VFile* vf, size_t size) {
290 QFileDevice* iodev = static_cast<VFileWrapper*>(vf)->iodev();
291 iodev->resize(size);
292}
293
294bool VFileWrapper::sync(VFile* vf, void*, size_t) {
295 QFileDevice* iodev = static_cast<VFileWrapper*>(vf)->iodev();
296 return iodev->flush();
297}
298
299VFileBufferWrapper::VFileBufferWrapper(QBuffer* iodev)
300 : VFileAbstractWrapper(iodev)
301{
302 VFile::close = &VFileBufferWrapper::close;
303 VFile::map = &VFileBufferWrapper::map;
304}
305
306bool VFileBufferWrapper::close(VFile* vf) {
307 QIODevice* iodev = static_cast<VFileBufferWrapper*>(vf)->m_iodev;
308 iodev->close();
309 delete static_cast<VFileBufferWrapper*>(vf);
310 return true;
311}
312
313void* VFileBufferWrapper::map(VFile* vf, size_t, int) {
314 QBuffer* iodev = static_cast<VFileBufferWrapper*>(vf)->iodev();
315 QByteArray& buffer = iodev->buffer();
316 return static_cast<void*>(buffer.data());
317}