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