beta-0.89.2
[luatex.git] / source / libs / zziplib / zziplib-0.13.62 / zzip / memdisk.c
blobdc00ea865087435dbab6ce2522ef294d7b0bce63
2 /*
3 * NOTE: this is part of libzzipmmapped (i.e. it is not libzzip).
4 * ==================
6 * The mem_disk cache will parse the central information of a zip archive
7 * and store it internally. One the one hand it allows to find files
8 * faster - no disk access is required and endian conversion is not
9 * needed. If zzip is compiled with zip extensions then it is about
10 * the only way to build maintainable code around the zip format.
12 * Note that 64bit support is almost entirely living in extension
13 * blocks as well as different character encodings and file access
14 * control bits that are mostly platform specific.
16 * Author:
17 * Guido Draheim <guidod@gmx.de>
19 * Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim
20 * All rights reserved,
21 * use under the restrictions of the
22 * Lesser GNU General Public License
23 * or alternatively the restrictions
24 * of the Mozilla Public License 1.1
26 #define _ZZIP_DISK_FILE_STRUCT 1
28 #include <zzip/types.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <time.h>
35 #include <zlib.h>
36 #include <zzip/format.h>
37 #include <zzip/fetch.h>
38 #include <zzip/mmapped.h>
39 #include <zzip/memdisk.h>
40 #include <zzip/__fnmatch.h>
42 #define ___ {
43 #define ____ }
45 static const char *error[] = {
46 "Ok",
47 # define _zzip_mem_disk_open_fail 1
48 "zzip_mem_disk_open: zzip_disk_open did fail",
49 # define _zzip_mem_disk_fdopen_fail 2
50 "zzip_mem_disk_fdopen: zzip_disk_mmap did fail"
51 # define _zzip_mem_disk_buffer_fail 3
52 "zzip_mem_disk_buffer: zzip_disk_buffer did fail",
56 #define ZZIP_EXTRA_zip64 0x0001
57 typedef struct _zzip_extra_zip64
58 { /* ZIP64 extended information extra field */
59 zzip_byte_t z_datatype[2]; /* Tag for this "extra" block type */
60 zzip_byte_t z_datasize[2]; /* Size of this "extra" block */
61 zzip_byte_t z_usize[8]; /* Original uncompressed file size */
62 zzip_byte_t z_csize[8]; /* Size of compressed data */
63 zzip_byte_t z_offset[8]; /* Offset of local header record */
64 zzip_byte_t z_diskstart[4]; /* Number of the disk for file start */
65 } zzip_extra_zip64;
67 /*forward*/
69 static zzip__new__ ZZIP_MEM_ENTRY *
70 zzip_mem_entry_new(ZZIP_DISK * disk, ZZIP_DISK_ENTRY * entry);
71 static void
72 zzip_mem_entry_free(ZZIP_MEM_ENTRY * _zzip_restrict item);
74 zzip__new__ ZZIP_MEM_DISK *
75 zzip_mem_disk_new(void)
77 return calloc(1, sizeof(ZZIP_MEM_DISK));
80 /** create new diskdir handle.
81 * wraps underlying zzip_disk_open. */
82 zzip__new__ ZZIP_MEM_DISK *
83 zzip_mem_disk_open(char *filename)
85 ZZIP_DISK *disk = zzip_disk_open(filename);
86 if (! disk)
87 { perror(error[_zzip_mem_disk_open_fail]); return 0; }
88 ___ ZZIP_MEM_DISK *dir = zzip_mem_disk_new();
89 zzip_mem_disk_load(dir, disk);
90 return dir;
91 ____;
94 /** create new diskdir handle.
95 * wraps underlying zzip_disk_open. */
96 zzip__new__ ZZIP_MEM_DISK *
97 zzip_mem_disk_fdopen(int fd)
99 ZZIP_DISK *disk = zzip_disk_mmap(fd);
100 if (! disk)
101 { perror(error[_zzip_mem_disk_fdopen_fail]); return 0; }
102 ___ ZZIP_MEM_DISK *dir = zzip_mem_disk_new();
103 zzip_mem_disk_load(dir, disk);
104 return dir;
105 ____;
108 /** create new diskdir handle.
109 * wraps underlying zzip_disk_buffer. */
110 zzip__new__ ZZIP_MEM_DISK *
111 zzip_mem_disk_buffer(char *buffer, size_t buflen)
113 ZZIP_DISK *disk = zzip_disk_buffer(buffer, buflen);
114 if (! disk)
115 { perror(error[_zzip_mem_disk_buffer_fail]); return 0; }
116 ___ ZZIP_MEM_DISK *dir = zzip_mem_disk_new();
117 zzip_mem_disk_load(dir, disk);
118 return dir;
119 ____;
122 /** parse central dir.
123 * creates an internal copy of each entry converted to the local platform.
124 * returns: number of entries, or -1 on error (setting errno)
126 long
127 zzip_mem_disk_load(ZZIP_MEM_DISK * dir, ZZIP_DISK * disk)
129 if (! dir || ! disk)
130 { errno=EINVAL; return -1; }
131 if (dir->list)
132 zzip_mem_disk_unload(dir);
133 ___ long count = 0;
134 ___ struct zzip_disk_entry *entry = zzip_disk_findfirst(disk);
135 for (; entry; entry = zzip_disk_findnext(disk, entry))
137 ZZIP_MEM_ENTRY *item = zzip_mem_entry_new(disk, entry);
138 if (! item)
139 goto error;
140 if (dir->last)
142 dir->last->zz_next = item; /* chain last */
143 } else
145 dir->list = item;
147 dir->last = item; /* to earlier */
148 count++;
150 ____;
151 dir->disk = disk;
152 return count;
153 ____;
154 error:
155 zzip_mem_disk_unload(dir);
156 return -1;
159 /** convert a zip disk entry to internal format.
160 * creates a new item parsing the information out of the various places
161 * in the zip archive. This is a good place to extend functionality if
162 * you have a project with extra requirements as you can push more bits
163 * right into the diskdir_entry for later usage in higher layers.
164 * returns: new item, or null on error (setting errno)
166 zzip__new__ ZZIP_MEM_ENTRY *
167 zzip_mem_entry_new(ZZIP_DISK * disk, ZZIP_DISK_ENTRY * entry)
169 if (! disk || ! entry)
170 { errno=EINVAL; return 0; }
171 ___ ZZIP_MEM_ENTRY *item = calloc(1, sizeof(*item));
172 if (! item)
173 return 0; /* errno=ENOMEM; */
174 ___ struct zzip_file_header *header =
175 zzip_disk_entry_to_file_header(disk, entry);
176 /* there is a number of duplicated information in the file header
177 * or the disk entry block. Theoretically some part may be missing
178 * that exists in the other, ... but we will prefer the disk entry.
180 item->zz_comment = zzip_disk_entry_strdup_comment(disk, entry);
181 item->zz_name = zzip_disk_entry_strdup_name(disk, entry);
182 item->zz_data = zzip_file_header_to_data(header);
183 item->zz_flags = zzip_disk_entry_get_flags(entry);
184 item->zz_compr = zzip_disk_entry_get_compr(entry);
185 item->zz_mktime = zzip_disk_entry_get_mktime(entry);
186 item->zz_crc32 = zzip_disk_entry_get_crc32(entry);
187 item->zz_csize = zzip_disk_entry_get_csize(entry);
188 item->zz_usize = zzip_disk_entry_get_usize(entry);
189 item->zz_diskstart = zzip_disk_entry_get_diskstart(entry);
190 item->zz_filetype = zzip_disk_entry_get_filetype(entry);
192 { /* copy the extra blocks to memory as well */
193 int /* */ ext1 = zzip_disk_entry_get_extras(entry);
194 char *_zzip_restrict ptr1 = zzip_disk_entry_to_extras(entry);
195 int /* */ ext2 = zzip_file_header_get_extras(header);
196 char *_zzip_restrict ptr2 = zzip_file_header_to_extras(header);
198 if (ext1)
200 void *mem = malloc(ext1 + 2);
201 item->zz_ext[1] = mem;
202 memcpy(mem, ptr1, ext1);
203 ((char *) (mem))[ext1 + 0] = 0;
204 ((char *) (mem))[ext1 + 1] = 0;
206 if (ext2)
208 void *mem = malloc(ext2 + 2);
209 item->zz_ext[2] = mem;
210 memcpy(mem, ptr2, ext2);
211 ((char *) (mem))[ext2 + 0] = 0;
212 ((char *) (mem))[ext2 + 1] = 0;
216 /* override sizes/offsets with zip64 values for largefile support */
217 zzip_extra_zip64 *block = (zzip_extra_zip64 *)
218 zzip_mem_entry_extra_block(item, ZZIP_EXTRA_zip64);
219 if (block)
221 item->zz_usize = __zzip_get64(block->z_usize);
222 item->zz_csize = __zzip_get64(block->z_csize);
223 item->zz_offset = __zzip_get64(block->z_offset);
224 item->zz_diskstart = __zzip_get32(block->z_diskstart);
227 /* NOTE:
228 * All information from the central directory entry is now in memory.
229 * Effectivly that allows us to modify it and write it back to disk.
231 return item;
232 ____;
233 ____;
236 /* find an extra block for the given datatype code.
237 * We assume that the central directory has been preparsed to memory.
239 ZZIP_EXTRA_BLOCK *
240 zzip_mem_entry_extra_block(ZZIP_MEM_ENTRY * entry, short datatype)
242 int i = 2;
243 while (1)
245 ZZIP_EXTRA_BLOCK *ext = entry->zz_ext[i];
246 if (ext)
248 while (*(short *) (ext->z_datatype))
250 if (datatype == zzip_extra_block_get_datatype(ext))
252 return ext;
254 ___ char *e = (char *) ext;
255 e += zzip_extra_block_headerlength;
256 e += zzip_extra_block_get_datasize(ext);
257 ext = (void *) e;
258 ____;
261 if (! i)
262 return 0;
263 i--;
267 void
268 zzip_mem_entry_free(ZZIP_MEM_ENTRY * _zzip_restrict item)
270 if (item)
272 /* *INDENT-OFF* */
273 if (item->zz_ext[0]) free (item->zz_ext[0]);
274 if (item->zz_ext[1]) free (item->zz_ext[1]);
275 if (item->zz_ext[2]) free (item->zz_ext[2]);
276 if (item->zz_comment) free (item->zz_comment);
277 if (item->zz_name) free (item->zz_name);
278 free (item);
279 /* *INDENT-ON* */
283 void
284 zzip_mem_disk_unload(ZZIP_MEM_DISK * dir)
286 ZZIP_MEM_ENTRY *item = dir->list;
287 while (item)
289 ZZIP_MEM_ENTRY *next = item->zz_next;
290 zzip_mem_entry_free(item);
291 item = next;
293 dir->list = dir->last = 0;
294 zzip_disk_close(dir->disk);
295 dir->disk = 0;
298 void
299 zzip_mem_disk_close(ZZIP_MEM_DISK * _zzip_restrict dir)
301 if (dir)
303 zzip_mem_disk_unload(dir);
304 zzip_disk_close(dir->disk);
305 free(dir);
309 #if 0
310 static void
311 foo(short zz_datatype)
313 switch (zz_datatype)
315 /* *INDENT-OFF* */
316 case 0x0001: /* ZIP64 extended information extra field */
317 case 0x0007: /* AV Info */
318 case 0x0008: /* Reserved for future Unicode file name data (PFS) */
319 case 0x0009: /* OS/2 */
320 case 0x000a: /* NTFS */
321 case 0x000c: /* OpenVMS */
322 case 0x000d: /* Unix */
323 case 0x000e: /* Reserved for file stream and fork descriptors */
324 case 0x000f: /* Patch Descriptor */
325 case 0x0014: /* PKCS#7 Store for X.509 Certificates */
326 case 0x0015: /* X.509 Certificate ID and Signature for file */
327 case 0x0016: /* X.509 Certificate ID for Central Directory */
328 case 0x0017: /* Strong Encryption Header */
329 case 0x0018: /* Record Management Controls */
330 case 0x0019: /* PKCS#7 Encryption Recipient Certificate List */
331 case 0x0065: /* IBM S/390, AS/400 attributes - uncompressed */
332 case 0x0066: /* Reserved for IBM S/390, AS/400 attr - compressed */
333 case 0x07c8: /* Macintosh */
334 case 0x2605: /* ZipIt Macintosh */
335 case 0x2705: /* ZipIt Macintosh 1.3.5+ */
336 case 0x2805: /* ZipIt Macintosh 1.3.5+ */
337 case 0x334d: /* Info-ZIP Macintosh */
338 case 0x4341: /* Acorn/SparkFS */
339 case 0x4453: /* Windows NT security descriptor (binary ACL) */
340 case 0x4704: /* VM/CMS */
341 case 0x470f: /* MVS */
342 case 0x4b46: /* FWKCS MD5 (see below) */
343 case 0x4c41: /* OS/2 access control list (text ACL) */
344 case 0x4d49: /* Info-ZIP OpenVMS */
345 case 0x4f4c: /* Xceed original location extra field */
346 case 0x5356: /* AOS/VS (ACL) */
347 case 0x5455: /* extended timestamp */
348 case 0x554e: /* Xceed unicode extra field */
349 case 0x5855: /* Info-ZIP Unix (original, also OS/2, NT, etc) */
350 case 0x6542: /* BeOS/BeBox */
351 case 0x756e: /* ASi Unix */
352 case 0x7855: /* Info-ZIP Unix (new) */
353 case 0xfd4a: /* SMS/QDOS */
354 /* *INDENT-ON* */
357 #endif
359 ZZIP_MEM_ENTRY *
360 zzip_mem_disk_findfile(ZZIP_MEM_DISK * dir,
361 char *filename, ZZIP_MEM_ENTRY * after,
362 zzip_strcmp_fn_t compare)
364 ZZIP_MEM_ENTRY *entry = (! after ? dir->list : after->zz_next);
365 if (! compare)
366 compare = (zzip_strcmp_fn_t) (strcmp);
367 for (; entry; entry = entry->zz_next)
369 if (! compare(filename, entry->zz_name))
371 return entry;
374 return 0;
377 ZZIP_MEM_ENTRY *
378 zzip_mem_disk_findmatch(ZZIP_MEM_DISK * dir,
379 char *filespec, ZZIP_MEM_ENTRY * after,
380 zzip_fnmatch_fn_t compare, int flags)
382 ZZIP_MEM_ENTRY *entry = (! after ? dir->list : after->zz_next);
383 if (! compare)
384 compare = (zzip_fnmatch_fn_t) _zzip_fnmatch;
385 for (; entry; entry = entry->zz_next)
387 if (! compare(filespec, entry->zz_name, flags))
389 return entry;
392 return 0;
395 zzip__new__ ZZIP_MEM_DISK_FILE *
396 zzip_mem_entry_fopen(ZZIP_MEM_DISK * dir, ZZIP_MEM_ENTRY * entry)
398 /* keep this in sync with zzip_disk_entry_fopen */
399 ZZIP_DISK_FILE *file = malloc(sizeof(ZZIP_MEM_DISK_FILE));
400 if (! file)
401 return file;
402 file->buffer = dir->disk->buffer;
403 file->endbuf = dir->disk->endbuf;
404 file->avail = zzip_mem_entry_usize(entry);
406 if (! file->avail || zzip_mem_entry_data_stored(entry))
407 { file->stored = zzip_mem_entry_to_data (entry); return file; }
409 file->stored = 0;
410 file->zlib.opaque = 0;
411 file->zlib.zalloc = Z_NULL;
412 file->zlib.zfree = Z_NULL;
413 file->zlib.avail_in = zzip_mem_entry_csize(entry);
414 file->zlib.next_in = zzip_mem_entry_to_data(entry);
416 if (! zzip_mem_entry_data_deflated(entry) ||
417 inflateInit2(&file->zlib, -MAX_WBITS) != Z_OK)
418 { free (file); return 0; }
420 return file;
423 zzip__new__ ZZIP_MEM_DISK_FILE *
424 zzip_mem_disk_fopen(ZZIP_MEM_DISK * dir, char *filename)
426 ZZIP_MEM_ENTRY *entry = zzip_mem_disk_findfile(dir, filename, 0, 0);
427 if (! entry)
428 return 0;
429 else
430 return zzip_mem_entry_fopen(dir, entry);
433 _zzip_size_t
434 zzip_mem_disk_fread(void *ptr, _zzip_size_t size, _zzip_size_t nmemb,
435 ZZIP_MEM_DISK_FILE * file)
437 return zzip_disk_fread(ptr, size, nmemb, file);
441 zzip_mem_disk_fclose(ZZIP_MEM_DISK_FILE * file)
443 return zzip_disk_fclose(file);
447 zzip_mem_disk_feof(ZZIP_MEM_DISK_FILE * file)
449 return zzip_disk_feof(file);
452 /* convert dostime of entry to unix time_t */
453 long
454 zzip_disk_entry_get_mktime(ZZIP_DISK_ENTRY * entry)
456 uint16_t dostime = ZZIP_GET16(entry->z_dostime.time);
457 uint16_t dosdate = ZZIP_GET16(entry->z_dostime.date);
458 struct tm date;
459 date.tm_sec = (dostime) & 0x1F; /* bits 0..4 */
460 date.tm_min = (dostime >> 5) & 0x3F; /* bits 5..10 */
461 date.tm_hour = (dostime >> 11); /* bits 11..15 */
462 date.tm_mday = (dosdate) & 0x1F; /* bits 16..20 */
463 date.tm_mon = (dosdate >> 5) & 0xF; /* bits 21..24 */
464 date.tm_year = (dosdate >> 9) + 80; /* bits 25..31 */
465 return mktime(&date); /* well, unix has that function... */