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