all repos — mgba @ 6d0f370630355b203612368a4cb0cbc8754768b8

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