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 _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 struct VDir7z* vd = malloc(sizeof(struct VDir7z));
69
70 if (flags & O_WRONLY || flags & O_CREAT) {
71 return 0;
72 }
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