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.
21 #define TABLE_SIZE 128
31 struct record
* contents
;
35 int (*read
)(void* userdata
, byte buf
[], int count
);
36 int (*seek
)(void* userdata
, int offset
, int whence
);
37 void (*close
)(void* userdata
);
40 struct record
* table
[TABLE_SIZE
];
58 char errbuf
[EBUF_SIZE
] = "";
61 /* internal routines */
63 static void set_error(char* msg
){
64 strncpy(errbuf
, msg
, EBUF_SIZE
);
65 errbuf
[EBUF_SIZE
-1] = '\0';
68 static void out_of_memory(){
69 set_error("OUT OF MEMORY");
72 /* http://www.cse.yorku.ca/~oz/hash.html */
73 static unsigned long hash(char* str
){
74 unsigned char* ptr
= (unsigned char*)str
;
75 unsigned long hash
= 5381;
78 hash
= ((hash
<< 5) + hash
) + c
; /* hash * 33 + c */
82 static struct record
* get_record(zip_archive
* arc
, char* filename
){
83 int i
= hash(filename
) % TABLE_SIZE
;
84 struct record
* ptr
= arc
->table
[i
];
86 if(strcmp(filename
, ptr
->filename
)) return ptr
;
92 static void set_record(zip_archive
* arc
, struct record
* r
){
93 /* check if r is a dir or file */
95 /* if file, find dir. insert into dir. insert file */
96 /* if dir, find dir or create, insert into parent */
97 int i
= hash(r
->filename
) % TABLE_SIZE
;
98 if(arc
->table
[i
] == NULL
)
101 struct record
* ptr
= arc
->table
[i
];
110 static int skip(zip_archive
* arc
, int count
){
111 return -1; /* FIXME */
114 static int read_bytes(zip_archive
* arc
, char* buf
, int count
){
118 static int read_long(zip_archive
* arc
, unsigned* n
){
120 int e
= arc
->read(arc
->userdata
, b
, 4);
121 if(e
< 0){return -1;}
122 *n
= b
[0] | (b
[1]<<8) | (b
[2]<<16) | (b
[3]<<24);
126 static int read_short(zip_archive
* arc
, unsigned* n
){
128 int e
= arc
->read(arc
->userdata
, b
, 2);
129 if(e
< 0){return -1;}
130 *n
= b
[0] | (b
[1]<<8);
135 static int parse_local_header(zip_archive
* arc
, struct record
** result
){
141 set_error("refused to execute code before review");
143 r
= malloc(sizeof(struct record
));
151 read_short(arc
, &r
->method
) ||
153 read_long(arc
, &n
) ||
154 read_long(arc
, &n
) ||
155 read_short(arc
, &L1
) ||
162 char* filename
= malloc(L1
+1);
164 read_bytes(arc
, filename
, L1
) ||
174 r
->filename
= filename
;
175 r
->offset
= arc
->ptr
+ 30 + L1
+ L2
;
176 arc
->ptr
+= 26 + L1
+ L2
+ r
->clen
+ ddesc
;
183 static int build_directory(zip_archive
* arc
){
186 if(parse_local_header(arc
, &r
) < 0){
190 if(r
== NULL
){ /* end of file chunks */
201 static void free_directory_r(struct record
* r
){
202 if(r
->contents
) free_directory_r(r
->contents
);
203 if(r
->next
) free_directory_r(r
->next
);
207 static void free_directory(zip_archive
* arc
){
209 for(i
=0; i
<TABLE_SIZE
; i
++){
210 if(arc
->table
[i
]) free_directory_r(arc
->table
[i
]);
215 static int fill_inbuf(zip_file
* f
){
216 int n
= f
->arc
->read(f
->arc
->userdata
, f
->inbuf
, BUF_SIZE
);
218 set_error("archive i/o error");
221 f
->strm
.next_in
= f
->inbuf
;
222 f
->strm
.avail_in
= n
;
226 static int inflate_chunk(zip_file
* f
, byte buf
[], int count
){
227 f
->strm
.next_out
= buf
;
228 f
->strm
.avail_out
= count
;
229 int e
= inflate(&f
->strm
, Z_SYNC_FLUSH
);
232 return count
- f
->strm
.avail_out
;
235 return count
= f
->strm
.avail_out
;
237 set_error("inflate needs a preset dictionary at this point");
240 set_error("inflate data error (input corrupted or in wrong format)");
243 set_error("inflate stream error (inconsistent stream structure)");
246 set_error("inflate buffer error (probably not enough input data)");
249 set_error("inflate out of memory");
252 set_error("inflate error (unknown)");
258 /* these are callbacks for the default archive reader, filesystem i/o */
259 static int file_read(void* f
, byte buf
[], int count
){
260 return fread(buf
, 1, count
, f
);
263 static int file_seek(void* f
, int offset
, int whence
){
264 return fseek(f
, offset
, whence
);
267 static void file_close(void* f
){
279 zip_archive
* zip_aropenf(char* filename
){
280 FILE* f
= fopen(filename
, "r");
282 set_error("i/o error");
285 zip_reader rd
= {file_read
, file_seek
, file_close
, f
};
286 return zip_aropen(&rd
);
289 zip_archive
* zip_aropen(zip_reader
* rd
){
290 zip_archive
* arc
= malloc(sizeof(zip_archive
));
295 arc
->read
= rd
->read
;
296 arc
->seek
= rd
->seek
;
297 arc
->close
= rd
->close
;
298 arc
->userdata
= rd
->userdata
;
300 if(build_directory(arc
) < 0){
309 void zip_arclose(zip_archive
* arc
){
310 arc
->close(arc
->userdata
);
317 zip_file
* zip_fopen(zip_archive
* arc
, char* path
){
318 zip_file
* f
= malloc(sizeof(zip_file
));
326 f
->strm
.zalloc
= NULL
;
327 f
->strm
.zfree
= NULL
;
328 f
->strm
.opaque
= NULL
;
329 f
->strm
.next_in
= f
->inbuf
;
330 f
->strm
.avail_in
= 0;
331 f
->strm
.next_out
= NULL
;
332 f
->strm
.avail_out
= 0;
334 /*TODO: get file offset and location in arc */
341 void zip_fclose(zip_file
* f
){
345 int zip_fread(zip_file
* f
, byte buf
[], int count
){
349 while(count
> 0 && !f
->eof
){
350 if(fill_inbuf(f
) < 0){
354 n
= inflate_chunk(f
, buf
, count
);
365 int zip_feof(zip_file
* f
){
372 zip_dir
* zip_opendir(zip_archive
* arc
, char* path
){
373 zip_dir
* dir
= malloc(sizeof(zip_dir
));
379 struct record
* r
= get_record(arc
, path
);
381 set_error("file not found");
385 dir
->ptr
= r
->contents
;
389 char* zip_readdir(zip_dir
* dir
){
390 if(dir
->ptr
== NULL
){
391 /* no more entries, not an error */
395 char* filename
= dir
->ptr
->filename
;
396 dir
->ptr
= dir
->ptr
->next
;
401 void zip_closedir(zip_dir
* dir
){
406 char* zip_geterror(){