all repos — mgba @ 5b8d64b0b5e5b3aa1edac7a98be6cbf471869dd0

mGBA Game Boy Advance Emulator

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}