all repos — mgba @ 7d385aabaf13a01b5b61991f18fe375fa0196e26

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