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
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 SzArEx_Free(&vd->db, &vd->allocImp);
102 File_Close(&vd->archiveStream.file);
103 free(vd);
104 return 0;
105 }
106
107 vd->dirent.index = -1;
108 vd->dirent.utf8 = 0;
109 vd->dirent.vd = vd;
110 vd->dirent.d.name = _vde7zName;
111 vd->dirent.d.type = _vde7zType;
112
113 vd->d.close = _vd7zClose;
114 vd->d.rewind = _vd7zRewind;
115 vd->d.listNext = _vd7zListNext;
116 vd->d.openFile = _vd7zOpenFile;
117 vd->d.openDir = _vd7zOpenDir;
118 vd->d.deleteFile = _vd7zDeleteFile;
119
120 return &vd->d;
121}
122
123bool _vf7zClose(struct VFile* vf) {
124 struct VFile7z* vf7z = (struct VFile7z*) vf;
125 IAlloc_Free(&vf7z->vd->allocImp, vf7z->outBuffer);
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 vf->offset = 0;
305
306 return &vf->d;
307}
308
309struct VDir* _vd7zOpenDir(struct VDir* vd, const char* path) {
310 UNUSED(vd);
311 UNUSED(path);
312 return 0;
313}
314
315bool _vd7zDeleteFile(struct VDir* vd, const char* path) {
316 UNUSED(vd);
317 UNUSED(path);
318 // TODO
319 return false;
320}
321
322bool _vf7zSync(struct VFile* vf, const void* memory, size_t size) {
323 UNUSED(vf);
324 UNUSED(memory);
325 UNUSED(size);
326 return false;
327}
328
329const char* _vde7zName(struct VDirEntry* vde) {
330 struct VDirEntry7z* vde7z = (struct VDirEntry7z*) vde;
331 if (!vde7z->utf8) {
332 size_t nameLength = SzArEx_GetFileNameUtf16(&vde7z->vd->db, vde7z->index, 0) * sizeof(UInt16);
333 UInt16* name = malloc(nameLength);
334 SzArEx_GetFileNameUtf16(&vde7z->vd->db, vde7z->index, name);
335 vde7z->utf8 = utf16to8(name, nameLength - sizeof(UInt16));
336 free(name);
337 }
338
339 return vde7z->utf8;
340}
341
342static enum VFSType _vde7zType(struct VDirEntry* vde) {
343 struct VDirEntry7z* vde7z = (struct VDirEntry7z*) vde;
344 if (SzArEx_IsDir(&vde7z->vd->db, vde7z->index)) {
345 return VFS_DIRECTORY;
346 }
347 return VFS_FILE;
348}
349
350#endif