all repos — mgba @ 517aa353caaa6484a2607d93265c4aafc14997ae

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
 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}