all repos — mgba @ b4c3440bc4b8bf85cd91f3571c91f4a6a958c7aa

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