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