all repos — mgba @ bda43168394b3edf785ef916186d131f871e4029

mGBA Game Boy Advance Emulator

src/util/vfs/vfs-lzma.c (view raw)

  1/* Copyright (c) 2013-2015 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 <mgba-util/vfs.h>
  7
  8#ifdef USE_LZMA
  9
 10#include <mgba-util/string.h>
 11
 12#include "third-party/lzma/7z.h"
 13#include "third-party/lzma/7zAlloc.h"
 14#include "third-party/lzma/7zBuf.h"
 15#include "third-party/lzma/7zCrc.h"
 16#include "third-party/lzma/7zFile.h"
 17#include "third-party/lzma/7zVersion.h"
 18
 19#define BUFFER_SIZE 0x2000
 20
 21struct VDirEntry7z {
 22	struct VDirEntry d;
 23
 24	struct VDir7z* vd;
 25	UInt32 index;
 26	char* utf8;
 27};
 28
 29struct VDir7z {
 30	struct VDir d;
 31	struct VDirEntry7z dirent;
 32
 33	// What is all this garbage?
 34	CFileInStream archiveStream;
 35	CLookToRead2 lookStream;
 36	CSzArEx db;
 37	ISzAlloc allocImp;
 38	ISzAlloc allocTempImp;
 39};
 40
 41struct VFile7z {
 42	struct VFile d;
 43
 44	struct VDir7z* vd;
 45
 46	size_t offset;
 47
 48	Byte* outBuffer;
 49	size_t bufferOffset;
 50	size_t size;
 51};
 52
 53static bool _vf7zClose(struct VFile* vf);
 54static off_t _vf7zSeek(struct VFile* vf, off_t offset, int whence);
 55static ssize_t _vf7zRead(struct VFile* vf, void* buffer, size_t size);
 56static ssize_t _vf7zWrite(struct VFile* vf, const void* buffer, size_t size);
 57static void* _vf7zMap(struct VFile* vf, size_t size, int flags);
 58static void _vf7zUnmap(struct VFile* vf, void* memory, size_t size);
 59static void _vf7zTruncate(struct VFile* vf, size_t size);
 60static ssize_t _vf7zSize(struct VFile* vf);
 61static bool _vf7zSync(struct VFile* vf, void* buffer, size_t size);
 62
 63static bool _vd7zClose(struct VDir* vd);
 64static void _vd7zRewind(struct VDir* vd);
 65static struct VDirEntry* _vd7zListNext(struct VDir* vd);
 66static struct VFile* _vd7zOpenFile(struct VDir* vd, const char* path, int mode);
 67static struct VDir* _vd7zOpenDir(struct VDir* vd, const char* path);
 68static bool _vd7zDeleteFile(struct VDir* vd, const char* path);
 69
 70static const char* _vde7zName(struct VDirEntry* vde);
 71static enum VFSType _vde7zType(struct VDirEntry* vde);
 72
 73struct VDir* VDirOpen7z(const char* path, int flags) {
 74	if (flags & O_WRONLY || flags & O_CREAT) {
 75		return 0;
 76	}
 77
 78	struct VDir7z* vd = malloc(sizeof(struct VDir7z));
 79
 80	// What does any of this mean, Igor?
 81	if (InFile_Open(&vd->archiveStream.file, path)) {
 82		free(vd);
 83		return 0;
 84	}
 85
 86	vd->allocImp.Alloc = SzAlloc;
 87	vd->allocImp.Free = SzFree;
 88
 89	vd->allocTempImp.Alloc = SzAllocTemp;
 90	vd->allocTempImp.Free = SzFreeTemp;
 91
 92	FileInStream_CreateVTable(&vd->archiveStream);
 93	LookToRead2_CreateVTable(&vd->lookStream, False);
 94
 95	vd->lookStream.realStream = &vd->archiveStream.vt;
 96	vd->lookStream.buf = malloc(BUFFER_SIZE);
 97	vd->lookStream.bufSize = BUFFER_SIZE;
 98
 99	LookToRead2_Init(&vd->lookStream);
100
101	CrcGenerateTable();
102
103	SzArEx_Init(&vd->db);
104	SRes res = SzArEx_Open(&vd->db, &vd->lookStream.vt, &vd->allocImp, &vd->allocTempImp);
105	if (res != SZ_OK) {
106		SzArEx_Free(&vd->db, &vd->allocImp);
107		File_Close(&vd->archiveStream.file);
108		free(vd->lookStream.buf);
109		free(vd);
110		return 0;
111	}
112
113	vd->dirent.index = -1;
114	vd->dirent.utf8 = 0;
115	vd->dirent.vd = vd;
116	vd->dirent.d.name = _vde7zName;
117	vd->dirent.d.type = _vde7zType;
118
119	vd->d.close = _vd7zClose;
120	vd->d.rewind = _vd7zRewind;
121	vd->d.listNext = _vd7zListNext;
122	vd->d.openFile = _vd7zOpenFile;
123	vd->d.openDir = _vd7zOpenDir;
124	vd->d.deleteFile = _vd7zDeleteFile;
125
126	return &vd->d;
127}
128
129bool _vf7zClose(struct VFile* vf) {
130	struct VFile7z* vf7z = (struct VFile7z*) vf;
131	IAlloc_Free(&vf7z->vd->allocImp, vf7z->outBuffer);
132	free(vf7z);
133	return true;
134}
135
136off_t _vf7zSeek(struct VFile* vf, off_t offset, int whence) {
137	struct VFile7z* vf7z = (struct VFile7z*) vf;
138
139	size_t position;
140	switch (whence) {
141	case SEEK_SET:
142		position = offset;
143		break;
144	case SEEK_CUR:
145		if (offset < 0 && ((vf7z->offset < (size_t) -offset) || (offset == INT_MIN))) {
146			return -1;
147		}
148		position = vf7z->offset + offset;
149		break;
150	case SEEK_END:
151		if (offset < 0 && ((vf7z->size < (size_t) -offset) || (offset == INT_MIN))) {
152			return -1;
153		}
154		position = vf7z->size + offset;
155		break;
156	default:
157		return -1;
158	}
159
160	if (position > vf7z->size) {
161		return -1;
162	}
163
164	vf7z->offset = position;
165	return position;
166}
167
168ssize_t _vf7zRead(struct VFile* vf, void* buffer, size_t size) {
169	struct VFile7z* vf7z = (struct VFile7z*) vf;
170
171	if (size + vf7z->offset >= vf7z->size) {
172		size = vf7z->size - vf7z->offset;
173	}
174
175	memcpy(buffer, vf7z->outBuffer + vf7z->offset + vf7z->bufferOffset, size);
176	vf7z->offset += size;
177	return size;
178}
179
180ssize_t _vf7zWrite(struct VFile* vf, const void* buffer, size_t size) {
181	// TODO
182	UNUSED(vf);
183	UNUSED(buffer);
184	UNUSED(size);
185	return -1;
186}
187
188void* _vf7zMap(struct VFile* vf, size_t size, int flags) {
189	struct VFile7z* vf7z = (struct VFile7z*) vf;
190
191	UNUSED(flags);
192	if (size > vf7z->size) {
193		return 0;
194	}
195
196	return vf7z->outBuffer + vf7z->bufferOffset;
197}
198
199void _vf7zUnmap(struct VFile* vf, void* memory, size_t size) {
200	UNUSED(vf);
201	UNUSED(memory);
202	UNUSED(size);
203}
204
205void _vf7zTruncate(struct VFile* vf, size_t size) {
206	// TODO
207	UNUSED(vf);
208	UNUSED(size);
209}
210
211ssize_t _vf7zSize(struct VFile* vf) {
212	struct VFile7z* vf7z = (struct VFile7z*) vf;
213	return vf7z->size;
214}
215
216bool _vd7zClose(struct VDir* vd) {
217	struct VDir7z* vd7z = (struct VDir7z*) vd;
218	SzArEx_Free(&vd7z->db, &vd7z->allocImp);
219	File_Close(&vd7z->archiveStream.file);
220
221	free(vd7z->lookStream.buf);
222	free(vd7z->dirent.utf8);
223	vd7z->dirent.utf8 = 0;
224
225	free(vd7z);
226	return true;
227}
228
229void _vd7zRewind(struct VDir* vd) {
230	struct VDir7z* vd7z = (struct VDir7z*) vd;
231	free(vd7z->dirent.utf8);
232	vd7z->dirent.utf8 = 0;
233	vd7z->dirent.index = -1;
234}
235
236struct VDirEntry* _vd7zListNext(struct VDir* vd) {
237	struct VDir7z* vd7z = (struct VDir7z*) vd;
238	if (vd7z->db.NumFiles <= vd7z->dirent.index + 1) {
239		return 0;
240	}
241	free(vd7z->dirent.utf8);
242	vd7z->dirent.utf8 = 0;
243	++vd7z->dirent.index;
244	return &vd7z->dirent.d;
245}
246
247struct VFile* _vd7zOpenFile(struct VDir* vd, const char* path, int mode) {
248	UNUSED(mode);
249	// TODO: support truncating, appending and creating, and write
250	struct VDir7z* vd7z = (struct VDir7z*) vd;
251
252	if ((mode & O_RDWR) == O_RDWR) {
253		// Read/Write support is not yet implemented.
254		return 0;
255	}
256
257	if (mode & O_WRONLY) {
258		// Write support is not yet implemented.
259		return 0;
260	}
261
262	size_t pathLength = strlen(path);
263
264	UInt32 i;
265	for (i = 0; i < vd7z->db.NumFiles; ++i) {
266		if (SzArEx_IsDir(&vd7z->db, i)) {
267			continue;
268		}
269		size_t nameLength = SzArEx_GetFileNameUtf16(&vd7z->db, i, 0) * sizeof(UInt16);
270		UInt16* name = malloc(nameLength);
271		SzArEx_GetFileNameUtf16(&vd7z->db, i, name);
272
273		if (utfcmp(name, path, nameLength - sizeof(UInt16), pathLength) == 0) {
274			free(name);
275			break;
276		}
277
278		free(name);
279	}
280
281	if (i == vd7z->db.NumFiles) {
282		return 0; // No file found
283	}
284
285	struct VFile7z* vf = malloc(sizeof(struct VFile7z));
286	vf->vd = vd7z;
287
288	size_t outBufferSize;
289	UInt32 blockIndex;
290
291	vf->outBuffer = 0;
292	SRes res = SzArEx_Extract(&vd7z->db, &vd7z->lookStream.vt, i, &blockIndex,
293		&vf->outBuffer, &outBufferSize,
294		&vf->bufferOffset, &vf->size,
295		&vd7z->allocImp, &vd7z->allocTempImp);
296
297	if (res != SZ_OK) {
298		free(vf);
299		return 0;
300	}
301
302	vf->d.close = _vf7zClose;
303	vf->d.seek = _vf7zSeek;
304	vf->d.read = _vf7zRead;
305	vf->d.readline = VFileReadline;
306	vf->d.write = _vf7zWrite;
307	vf->d.map = _vf7zMap;
308	vf->d.unmap = _vf7zUnmap;
309	vf->d.truncate = _vf7zTruncate;
310	vf->d.size = _vf7zSize;
311	vf->d.sync = _vf7zSync;
312	vf->offset = 0;
313
314	return &vf->d;
315}
316
317struct VDir* _vd7zOpenDir(struct VDir* vd, const char* path) {
318	UNUSED(vd);
319	UNUSED(path);
320	return 0;
321}
322
323bool _vd7zDeleteFile(struct VDir* vd, const char* path) {
324	UNUSED(vd);
325	UNUSED(path);
326	// TODO
327	return false;
328}
329
330bool _vf7zSync(struct VFile* vf, void* memory, size_t size) {
331	UNUSED(vf);
332	UNUSED(memory);
333	UNUSED(size);
334	return false;
335}
336
337const char* _vde7zName(struct VDirEntry* vde) {
338	struct VDirEntry7z* vde7z = (struct VDirEntry7z*) vde;
339	if (!vde7z->utf8) {
340		size_t nameLength = SzArEx_GetFileNameUtf16(&vde7z->vd->db, vde7z->index, 0) * sizeof(UInt16);
341		UInt16* name = malloc(nameLength);
342		SzArEx_GetFileNameUtf16(&vde7z->vd->db, vde7z->index, name);
343		vde7z->utf8 = utf16to8(name, nameLength - sizeof(UInt16));
344		free(name);
345	}
346
347	return vde7z->utf8;
348}
349
350static enum VFSType _vde7zType(struct VDirEntry* vde) {
351	struct VDirEntry7z* vde7z = (struct VDirEntry7z*) vde;
352	if (SzArEx_IsDir(&vde7z->vd->db, vde7z->index)) {
353		return VFS_DIRECTORY;
354	}
355	return VFS_FILE;
356}
357
358#endif