all repos — mgba @ df082b46d9c9d0a31edc29d05f9c93fd5b17197e

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() {
 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}