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, const 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, const 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