5 Copyright (C) 2009 Evan Rinehart
7 This software comes with no warranty.
8 1. This software can be used for any purpose, good or evil.
9 2. Modifications must retain this license, at least in spirit.
13 read files from a zip file.
16 *zip archive may be in a file, or accessed using a reader struct
17 *reader struct must support seeking
18 *directory listing is supported
19 *various errors with the archive and i/o are reported via zip_geterror()
21 *files in the archive are accessed sequentially, no seek supported
22 *writing is not supported
24 *only inflate compression method supported
38 #define TABLE_SIZE 128
48 struct record
* contents
;
52 int (*read
)(void* userdata
, byte buf
[], int count
);
53 int (*seek
)(void* userdata
, int offset
, int whence
);
54 void (*close
)(void* userdata
);
57 struct record
* table
[TABLE_SIZE
];
76 static char errbuf
[EBUF_SIZE
] = "";
79 /* internal routines */
81 static void set_error(char* msg
){
82 strncpy(errbuf
, msg
, EBUF_SIZE
);
83 errbuf
[EBUF_SIZE
-1] = '\0';
86 static void out_of_memory(){
87 set_error("OUT OF MEMORY");
90 /* http://www.cse.yorku.ca/~oz/hash.html */
91 static unsigned long hash(char* str
){
92 unsigned char* ptr
= (unsigned char*)str
;
93 unsigned long hash
= 5381;
96 hash
= ((hash
<< 5) + hash
) + c
; /* hash * 33 + c */
101 static struct record
* make_record(char* filename
, int ulen
, int clen
, int offset
, int method
){
102 struct record
* r
= malloc(sizeof(struct record
));
106 r
->filename
= strdup(filename
);
116 static struct record
* copy_record(struct record
* rec
){
117 return make_record(rec
->filename
, rec
->ulen
, rec
->clen
, rec
->offset
, rec
->method
);
120 static struct record
* get_record(zip_archive
* arc
, char* filename
){
121 int i
= hash(filename
) % TABLE_SIZE
;
122 struct record
* ptr
= arc
->table
[i
];
124 if(strcmp(filename
, ptr
->filename
) == 0){
132 static void hash_insert(zip_archive
* arc
, struct record
* rec
){
133 int i
= hash(rec
->filename
) % TABLE_SIZE
;
134 struct record
* ptr
= arc
->table
[i
];
136 if(get_record(arc
, rec
->filename
)){
137 fprintf(stderr
, "zip: can't insert %s twice\n", rec
->filename
);
150 static char* baseof(char* path
){
151 if(strlen(path
) < 2) return NULL
;
152 int ptr
= strlen(path
) - 2;
153 while(ptr
> 0 && path
[ptr
] != '/') ptr
--;
154 if(ptr
== 0) return NULL
;
155 char* result
= malloc(ptr
+5);
156 memcpy(result
, path
, ptr
+1);
157 result
[ptr
+1] = '\0';
161 static void contents_insert(struct record
* item
, struct record
* dir
){
162 item
->next
= dir
->contents
;
163 dir
->contents
= item
;
166 static void print_hash(zip_archive* arc){
169 for(i=0; i<TABLE_SIZE; i++){
170 printf("table[%d]: ",i);
180 static void print_zipfile(zip_file* f){
181 printf("(+0x%x, %u/%uB, cptr +0x%x, uptr %u)\n",
182 f->offset, f->clen, f->ulen, f->cptr, f->uptr);
185 static void print_record(struct record* rec){
186 printf("(%s, %uB, %uB, +0x%x, method %u)\n", rec->filename, rec->clen, rec->ulen, rec->offset, rec->method);
189 static char* method_str(unsigned method
){
191 case 0: return "uncompressed";
192 case 1: return "shrink";
196 case 5: return "reduce";
197 case 6: return "implode";
198 case 8: return "deflate";
199 case 9: return "deflate64";
200 case 10: return "IBM TERSE (old)";
201 case 12: return "bzip2";
202 case 14: return "lzma";
203 case 18: return "IBM TERSE (new)";
204 case 19: return "IBM LZ77 z";
205 case 97: return "WavPack";
206 case 98: return "PPMd";
207 default: return "unknown";
211 static void unrecognized_method(unsigned method
){
213 snprintf(buf
, 64, "unrecognized compression method '%s'", method_str(method
));
218 static void set_record(zip_archive
* arc
, char* filename
, int ulen
, int clen
, int offset
, int method
){
222 if(get_record(arc
, filename
)) return;
223 rec
= make_record(filename
, ulen
, clen
, offset
, method
);
224 hash_insert(arc
, rec
);
225 dirname
= baseof(filename
);
226 if(dirname
== NULL
) return;
227 if(get_record(arc
, dirname
) == NULL
)
228 set_record(arc
, dirname
, 0, 0, 0, 0);
229 dir
= get_record(arc
, dirname
);
230 contents_insert(copy_record(rec
), dir
);
236 static int read_bytes(zip_archive
* arc
, void* buf
, int count
){
237 return arc
->read(arc
->userdata
, buf
, count
);
240 static int read_chunk(zip_archive
* arc
, void* buf
, int count
){
241 int n
= read_bytes(arc
, buf
, count
);
243 set_error("read error");
247 set_error("not enough data");
253 static int skip(zip_archive
* arc
, int count
){
258 while(total
!= count
){
259 int diff
= count
- total
;
260 int chunk
= diff
< 256 ? diff
: 256;
261 n
= read_bytes(arc
, buf
, chunk
);
263 set_error("read error");
267 set_error("not enough data");
276 static int read_long(zip_archive
* arc
, unsigned* n
){
278 int e
= read_bytes(arc
, b
, 4);
280 set_error("read error");
284 set_error("not enough data");
287 *n
= b
[0] | (b
[1]<<8) | (b
[2]<<16) | (b
[3]<<24);
291 static int read_short(zip_archive
* arc
, unsigned* n
){
293 int e
= read_bytes(arc
, b
, 2);
295 set_error("read error");
299 set_error("not enough data");
302 *n
= b
[0] | (b
[1]<<8);
307 static int parse_local_header(zip_archive
* arc
){
317 read_short(arc
, &flags
) ||
318 read_short(arc
, &method
) ||
320 read_long(arc
, &clen
) ||
321 read_long(arc
, &ulen
) ||
322 read_short(arc
, &L1
) ||
328 filename
= malloc(L1
+1);
330 read_chunk(arc
, filename
, L1
) ||
339 offset
= arc
->ptr
+ 30 + L1
+ L2
;
340 arc
->ptr
= offset
+ clen
+ (flags
&(1<<3) ? 12 : 0);
342 set_record(arc
, filename
, ulen
, clen
, offset
, method
);
349 static int build_directory(zip_archive
* arc
){
352 if(read_long(arc
, &sig
) < 0) return -1;
353 else if(sig
== 0x04034b50) parse_local_header(arc
);
361 static void free_directory_r(struct record
* r
){
362 if(r
->contents
) free_directory_r(r
->contents
);
363 if(r
->next
) free_directory_r(r
->next
);
368 static void free_directory(zip_archive
* arc
){
370 for(i
=0; i
<TABLE_SIZE
; i
++){
371 if(arc
->table
[i
]) free_directory_r(arc
->table
[i
]);
376 static int fill_inbuf(zip_file
* f
){
378 int nleftstream
, nleftbuffer
;
380 /* shift everything left */
381 memmove(f
->inbuf
, f
->strm
.next_in
, f
->strm
.avail_in
);
382 f
->strm
.next_in
= f
->inbuf
;
384 /* fill the buffer */
385 if(f
->arc
->seek(f
->arc
->userdata
, f
->offset
+f
->cptr
, SEEK_SET
) < 0){
386 set_error("archive seek error");
390 /* you want the minimum of
391 a) bytes needed to fill the buffer and
392 b) bytes left in the compressed stream */
393 nleftstream
= f
->clen
- f
->cptr
;
394 nleftbuffer
= BUF_SIZE
- f
->strm
.avail_in
;
395 nwant
= nleftstream
< nleftbuffer
? nleftstream
: nleftbuffer
;
396 nread
= f
->arc
->read(f
->arc
->userdata
, f
->inbuf
+f
->strm
.avail_in
, nwant
);
398 set_error("archive read error");
403 f
->strm
.avail_in
+= nread
;
407 static int inflate_chunk(zip_file
* f
, byte buf
[], int count
){
408 f
->strm
.next_out
= buf
;
409 f
->strm
.avail_out
= count
;
410 int e
= inflate(&f
->strm
, Z_SYNC_FLUSH
);
413 return count
- f
->strm
.avail_out
;
416 return count
- f
->strm
.avail_out
;
420 set_error("inflate needs a preset dictionary at this point");
423 set_error("inflate data error (input corrupted or in wrong format)");
426 set_error("inflate stream error (inconsistent stream structure)");
429 set_error("inflate out of memory");
432 set_error("inflate error (unknown)");
438 /* these are callbacks for the default archive reader, filesystem i/o */
439 static int file_read(void* f
, byte buf
[], int count
){
440 return fread(buf
, 1, count
, f
);
443 static int file_seek(void* f
, int offset
, int whence
){
444 return fseek(f
, offset
, whence
);
447 static void file_close(void* f
){
459 zip_archive
* zip_aropenf(char* filename
){
460 FILE* f
= fopen(filename
, "r");
462 set_error("i/o error");
465 zip_reader rd
= {file_read
, file_seek
, file_close
, f
};
466 return zip_aropen(&rd
);
469 zip_archive
* zip_aropen(zip_reader
* rd
){
471 zip_archive
* arc
= malloc(sizeof(zip_archive
));
476 arc
->read
= rd
->read
;
477 arc
->seek
= rd
->seek
;
478 arc
->close
= rd
->close
;
479 arc
->userdata
= rd
->userdata
;
482 for(i
=0; i
<TABLE_SIZE
; i
++){
483 arc
->table
[i
] = NULL
;
486 if(build_directory(arc
) < 0){
495 void zip_arclose(zip_archive
* arc
){
496 arc
->close(arc
->userdata
);
501 zip_file
* zip_fopen(zip_archive
* arc
, char* path
){
502 struct record
* r
= get_record(arc
, path
);
504 set_error("file not found");
508 if(r
->filename
[strlen(r
->filename
)-1] == '/'){
509 set_error("cannot open directory");
514 unrecognized_method(r
->method
);
518 zip_file
* f
= malloc(sizeof(zip_file
));
526 f
->strm
.zalloc
= NULL
;
527 f
->strm
.zfree
= NULL
;
528 f
->strm
.opaque
= NULL
;
529 f
->strm
.next_in
= f
->inbuf
;
530 f
->strm
.avail_in
= 0;
531 f
->strm
.next_out
= NULL
;
532 f
->strm
.avail_out
= 0;
537 f
->offset
= r
->offset
;
539 int e
= inflateInit2(&f
->strm
, -15);
542 case Z_MEM_ERROR
: set_error("memory"); break;
543 case Z_STREAM_ERROR
: set_error("stream"); break;
552 void zip_fclose(zip_file
* f
){
553 inflateEnd(&f
->strm
);
557 int zip_fread(zip_file
* f
, byte buf
[], int count
){
560 int sentry
= 0; /* annoying */
562 while(count
> 0 && !f
->eof
){
563 n
= inflate_chunk(f
, buf
+total
, count
);
567 /* need more input */
568 if(fill_inbuf(f
) < 0) return -1;
570 set_error("unable to satisfy buffer requirements");
582 if(f
->uptr
== f
->ulen
){
590 int zip_feof(zip_file
* f
){
597 zip_dir
* zip_opendir(zip_archive
* arc
, char* path
){
598 if(path
[strlen(path
)-1] != '/'){
599 set_error("path does not specify directory");
603 zip_dir
* dir
= malloc(sizeof(zip_dir
));
609 struct record
* r
= get_record(arc
, path
);
611 set_error("file not found");
616 dir
->ptr
= r
->contents
;
620 char* zip_readdir(zip_dir
* dir
){
621 if(dir
->ptr
== NULL
){
622 /* no more entries, not an error */
626 char* filename
= dir
->ptr
->filename
;
627 dir
->ptr
= dir
->ptr
->next
;
632 void zip_closedir(zip_dir
* dir
){
637 char* zip_geterror(){