beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luazip / src / luazip.c
blobcebd343ceceb5c31161613db98683e7c8790b360
1 /*
2 LuaZip - Reading files inside zip files.
3 http://www.keplerproject.org/luazip/
5 Author: Danilo Tuler
6 Copyright (c) 2003-2006 Kepler Project
8 $Id: luazip.c,v 1.9 2006/03/23 20:44:53 carregal Exp $
9 */
11 #include <string.h>
12 #include <stdlib.h>
13 #include "zzip/zzip.h"
14 #include "luazip.h"
15 #include "lauxlib.h"
17 #define ZIPFILEHANDLE "lzip.File"
18 #define ZIPINTERNALFILEHANDLE "lzip.InternalFile"
19 #define LUAZIP_MAX_EXTENSIONS 32
21 static int pushresult (lua_State *L, int i, const char *filename) {
22 if (i) {
23 lua_pushboolean(L, 1);
24 return 1;
26 else {
27 lua_pushnil(L);
28 if (filename)
29 lua_pushfstring(L, "%s: %s", filename, zzip_strerror(zzip_errno(errno)));
30 else
31 lua_pushfstring(L, "%s", zzip_strerror(zzip_errno(errno)));
32 lua_pushnumber(L, zzip_errno(errno));
33 return 3;
37 static ZZIP_DIR** topfile (lua_State *L, int findex) {
38 ZZIP_DIR** f = (ZZIP_DIR**)luaL_checkudata(L, findex, ZIPFILEHANDLE);
39 if (f == NULL) luaL_argerror(L, findex, "bad zip file");
40 return f;
43 static ZZIP_DIR* tofile (lua_State *L, int findex) {
44 ZZIP_DIR** f = topfile(L, findex);
45 if (*f == NULL)
46 luaL_error(L, "attempt to use a closed zip file");
47 return *f;
50 static ZZIP_FILE** topinternalfile (lua_State *L, int findex) {
51 ZZIP_FILE** f = (ZZIP_FILE**)luaL_checkudata(L, findex, ZIPINTERNALFILEHANDLE);
52 if (f == NULL) luaL_argerror(L, findex, "bad zip file");
53 return f;
56 static ZZIP_FILE* tointernalfile (lua_State *L, int findex) {
57 ZZIP_FILE** f = topinternalfile(L, findex);
58 if (*f == NULL)
59 luaL_error(L, "attempt to use a closed zip file");
60 return *f;
64 ** When creating file handles, always creates a `closed' file handle
65 ** before opening the actual file; so, if there is a memory error, the
66 ** file is not left opened.
68 static ZZIP_DIR** newfile (lua_State *L) {
69 ZZIP_DIR** pf = (ZZIP_DIR**)lua_newuserdata(L, sizeof(ZZIP_DIR*));
70 *pf = NULL; /* file handle is currently `closed' */
71 luaL_getmetatable(L, ZIPFILEHANDLE);
72 lua_setmetatable(L, -2);
73 return pf;
76 static ZZIP_FILE** newinternalfile (lua_State *L) {
77 ZZIP_FILE** pf = (ZZIP_FILE**)lua_newuserdata(L, sizeof(ZZIP_FILE*));
78 *pf = NULL; /* file handle is currently `closed' */
79 luaL_getmetatable(L, ZIPINTERNALFILEHANDLE);
80 lua_setmetatable(L, -2);
81 return pf;
85 static int zip_open (lua_State *L) {
86 const char *zipfilename = luaL_checkstring(L, 1);
87 /*const char *mode = luaL_optstring(L, 2, "r");*/
89 ZZIP_DIR** pf = newfile(L);
90 *pf = zzip_dir_open(zipfilename, 0);
91 if (*pf == NULL)
93 lua_pushnil(L);
94 lua_pushfstring(L, "could not open file `%s'", zipfilename);
95 return 2;
97 return 1;
101 static int zip_close (lua_State *L) {
102 ZZIP_DIR* f = tofile(L, 1);
103 if ( zzip_closedir(f) == 0 )
105 *(ZZIP_DIR**)lua_touserdata(L, 1) = NULL; /* mark file as close */
106 lua_pushboolean(L, 1);
108 else {
109 lua_pushboolean(L, 0);
111 return 1;
114 static int f_open (lua_State *L) {
115 ZZIP_DIR* uf = tofile(L, 1);
116 const char *filename = luaL_checkstring(L, 2);
117 /*const char *mode = luaL_optstring(L, 3, "r");*/
118 ZZIP_FILE** inf = newinternalfile(L);
120 *inf = zzip_file_open(uf, filename, 0);
121 if (*inf)
122 return 1;
124 lua_pushnil(L);
125 lua_pushfstring(L, "could not open file `%s'", filename);
126 return 2;
132 static int zip_openfile (lua_State *L) {
133 ZZIP_FILE** inf;
135 const char * ext2[LUAZIP_MAX_EXTENSIONS+1];
136 zzip_strings_t *ext = ext2;
138 const char *filename = luaL_checkstring(L, 1);
139 /*const char *mode = luaL_optstring(L, 2, "r");*/
141 inf = newinternalfile(L);
143 if (lua_isstring(L, 2))
145 /* creates a table with the string as the first and only (numerical) element */
146 lua_newtable(L);
147 lua_pushvalue(L, 2);
148 lua_rawseti(L, -2, 1);
150 /* replaces the string by the table with the string inside */
151 lua_replace(L, 2);
154 if (lua_istable(L, 2))
156 int i, m, n;
158 /* how many extension were specified? */
159 n = lua_rawlen(L, 2);
161 if (n > LUAZIP_MAX_EXTENSIONS)
163 luaL_error(L, "too many extensions specified");
166 for (i = 0, m = 0; i < n; i++)
168 lua_rawgeti(L, 2, i+1);
169 if (lua_isstring(L, -1))
171 /* luazip specifies "zip" as the extension, but zziplib expects ".zip" */
172 lua_pushstring(L, ".");
173 lua_insert(L, -2);
174 lua_concat(L, 2);
176 ext2[m] = lua_tostring(L, -1);
177 m++;
179 lua_pop(L, 1);
181 ext2[m] = 0;
183 *inf = zzip_open_ext_io(filename, 0, 0664, ext, 0);
185 else
187 *inf = zzip_open(filename, 0);
190 if (*inf)
191 return 1;
193 lua_pushnil(L);
194 lua_pushfstring(L, "could not open file `%s'", filename);
195 return 2;
198 static int zip_type (lua_State *L) {
199 ZZIP_DIR** f = (ZZIP_DIR**)luaL_checkudata(L, 1, ZIPFILEHANDLE);
200 if (f == NULL) lua_pushnil(L);
201 else if (*f == NULL)
202 lua_pushliteral(L, "closed zip file");
203 else
204 lua_pushliteral(L, "zip file");
205 return 1;
208 static int zip_tostring (lua_State *L) {
209 char buff[32];
210 ZZIP_DIR** f = topfile(L, 1);
211 if (*f == NULL)
212 strcpy(buff, "closed");
213 else
214 sprintf(buff, "%p", lua_touserdata(L, 1));
215 lua_pushfstring(L, "zip file (%s)", buff);
216 return 1;
219 static int ff_tostring (lua_State *L) {
220 char buff[32];
221 ZZIP_FILE** f = topinternalfile(L, 1);
222 if (*f == NULL)
223 strcpy(buff, "closed");
224 else
225 sprintf(buff, "%p", lua_touserdata(L, 1));
226 lua_pushfstring(L, "file in zip file (%s)", buff);
227 return 1;
230 static int zip_gc (lua_State *L) {
231 ZZIP_DIR**f = topfile(L, 1);
232 if (*f != NULL) /* ignore closed files */
233 zip_close(L);
234 return 0;
237 static int zip_readfile (lua_State *L) {
238 ZZIP_DIRENT* ent = NULL;
239 ZZIP_DIR* uf = NULL;
241 uf = *(ZZIP_DIR**)lua_touserdata(L, lua_upvalueindex(1));
242 if (uf == NULL) /* file is already closed? */
243 luaL_error(L, "file is already closed");
245 ent = zzip_readdir(uf);
247 if (ent == NULL)
248 return 0;
250 lua_newtable(L);
251 lua_pushstring(L, "compressed_size"); lua_pushnumber(L, ent->d_csize); lua_settable(L, -3);
252 lua_pushstring(L, "compression_method"); lua_pushnumber(L, ent->d_compr); lua_settable(L, -3);
253 lua_pushstring(L, "uncompressed_size"); lua_pushnumber(L, ent->st_size); lua_settable(L, -3);
254 lua_pushstring(L, "filename"); lua_pushstring(L, ent->d_name); lua_settable(L, -3);
256 return 1;
259 static int f_files (lua_State *L) {
260 ZZIP_DIR *f = tofile(L, 1);
261 zzip_rewinddir(f);
262 lua_pushliteral(L, ZIPFILEHANDLE);
263 lua_rawget(L, LUA_REGISTRYINDEX);
264 lua_pushcclosure(L, zip_readfile, 2);
265 return 1;
268 static int aux_close (lua_State *L) {
269 ZZIP_FILE *f = tointernalfile(L, 1);
270 int ok = (zzip_fclose(f) == 0);
271 if (ok)
272 *(ZZIP_FILE **)lua_touserdata(L, 1) = NULL; /* mark file as closed */
273 return ok;
276 static int ff_close (lua_State *L) {
277 return pushresult(L, aux_close(L), NULL);
280 static int ff_gc (lua_State *L) {
281 ZZIP_FILE**f = topinternalfile(L, 1);
282 if (*f != NULL) /* ignore closed files */
283 aux_close(L);
284 return 0;
287 static int zzip_getc (ZZIP_FILE *f)
289 char c;
290 return (zzip_fread(&c, sizeof(char), 1, f) == 0) ? EOF : (int)c;
293 static char* zzip_fgets(char *str, int size, ZZIP_FILE *stream)
295 int c, i;
297 for (i = 0; i < size-1; i++)
299 c = zzip_getc(stream);
300 if (EOF == c)
301 return NULL;
302 str[i]=c;
303 if (('\n' == c)/* || ('\r' == c)*/)
305 str[i++]='\n';
306 break;
309 str[i] = '\0';
311 return str;
314 /* no support to read numbers
315 static int zzip_fscanf (ZZIP_FILE *f, const char *format, ...)
317 // TODO
318 return 0;
321 static int read_number (lua_State *L, ZZIP_FILE *f) {
322 lua_Number d;
323 if (zzip_fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
324 lua_pushnumber(L, d);
325 return 1;
327 else return 0; // read fails
331 static int test_eof (lua_State *L, ZZIP_FILE *f) {
332 /* TODO */
333 (void) L;
334 (void) f;
335 return 1;
338 static int read_line (lua_State *L, ZZIP_FILE *f) {
339 luaL_Buffer b;
340 luaL_buffinit(L, &b);
341 for (;;) {
342 size_t l;
343 char *p = luaL_prepbuffer(&b);
344 if (zzip_fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */
345 luaL_pushresult(&b); /* close buffer */
346 return (lua_rawlen(L, -1) > 0); /* check whether read something */
348 l = strlen(p);
349 if (p[l-1] != '\n')
350 luaL_addsize(&b, l);
351 else {
352 luaL_addsize(&b, l - 1); /* do not include `eol' */
353 luaL_pushresult(&b); /* close buffer */
354 return 1; /* read at least an `eol' */
359 static int read_chars (lua_State *L, ZZIP_FILE *f, size_t n) {
360 size_t rlen; /* how much to read */
361 size_t nr; /* number of chars actually read */
362 luaL_Buffer b;
363 luaL_buffinit(L, &b);
364 rlen = LUAL_BUFFERSIZE; /* try to read that much each time */
365 do {
366 char *p = luaL_prepbuffer(&b);
367 if (rlen > n) rlen = n; /* cannot read more than asked */
368 nr = zzip_fread(p, sizeof(char), rlen, f);
369 luaL_addsize(&b, nr);
370 n -= nr; /* still have to read `n' chars */
371 } while (n > 0 && nr == rlen); /* until end of count or eof */
372 luaL_pushresult(&b); /* close buffer */
373 return (n == 0 || lua_rawlen(L, -1) > 0);
376 static int g_read (lua_State *L, ZZIP_FILE *f, int first) {
377 int nargs = lua_gettop(L) - 1;
378 int success;
379 int n;
380 if (nargs == 0) { /* no arguments? */
381 success = read_line(L, f);
382 n = first+1; /* to return 1 result */
384 else { /* ensure stack space for all results and for auxlib's buffer */
385 luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
386 success = 1;
387 for (n = first; nargs-- && success; n++) {
388 if (lua_type(L, n) == LUA_TNUMBER) {
389 size_t l = (size_t)lua_tonumber(L, n);
390 success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
392 else {
393 const char *p = lua_tostring(L, n);
394 luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
395 switch (p[1]) {
396 case 'l': /* line */
397 success = read_line(L, f);
398 break;
399 case 'a': /* file */
400 read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */
401 success = 1; /* always success */
402 break;
403 default:
404 return luaL_argerror(L, n, "invalid format");
409 if (!success) {
410 lua_pop(L, 1); /* remove last result */
411 lua_pushnil(L); /* push nil instead */
413 return n - first;
416 static int ff_read (lua_State *L) {
417 return g_read(L, tointernalfile(L, 1), 2);
420 static int zip_readline (lua_State *L);
422 static void aux_lines (lua_State *L, int idx, int close) {
423 lua_pushliteral(L, ZIPINTERNALFILEHANDLE);
424 lua_rawget(L, LUA_REGISTRYINDEX);
425 lua_pushvalue(L, idx);
426 lua_pushboolean(L, close); /* close/not close file when finished */
427 lua_pushcclosure(L, zip_readline, 3);
430 static int ff_lines (lua_State *L) {
431 tointernalfile(L, 1); /* check that it's a valid file handle */
432 aux_lines(L, 1, 0);
433 return 1;
436 static int zip_readline (lua_State *L) {
437 ZZIP_FILE *f = *(ZZIP_FILE **)lua_touserdata(L, lua_upvalueindex(2));
438 if (f == NULL) /* file is already closed? */
439 luaL_error(L, "file is already closed");
440 if (read_line(L, f)) return 1;
441 else { /* EOF */
442 if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */
443 lua_settop(L, 0);
444 lua_pushvalue(L, lua_upvalueindex(2));
445 aux_close(L); /* close it */
447 return 0;
451 static int ff_seek (lua_State *L) {
452 static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
453 static const char *const modenames[] = {"set", "cur", "end", NULL};
454 ZZIP_FILE *f = tointernalfile(L, 1);
455 int op = luaL_checkoption(L, 2, "cur", modenames);
456 long offset = luaL_optlong(L, 3, 0);
457 luaL_argcheck(L, op != -1, 2, "invalid mode");
458 op = zzip_seek(f, offset, mode[op]);
459 if (op < 0)
460 return pushresult(L, 0, NULL); /* error */
461 else {
462 lua_pushnumber(L, zzip_tell(f));
463 return 1;
467 static const luaL_Reg ziplib[] = {
468 {"open", zip_open},
469 {"close", zip_close},
470 {"type", zip_type},
471 /* {"files", io_files},*/
472 {"openfile", zip_openfile},
473 {NULL, NULL}
476 static const luaL_Reg flib[] = {
477 {"open", f_open},
478 {"close", zip_close},
479 {"files", f_files},
480 {"__gc", zip_gc},
481 {"__tostring", zip_tostring},
482 {NULL, NULL}
485 static const luaL_Reg fflib[] = {
486 {"read", ff_read},
487 {"close", ff_close},
488 {"seek", ff_seek},
489 {"lines", ff_lines},
490 {"__gc", ff_gc},
491 {"__tostring", ff_tostring},
492 /* {"flush", ff_flush},
493 {"write", ff_write},*/
494 {NULL, NULL}
499 ** Assumes the table is on top of the stack.
501 static void set_info (lua_State *L) {
502 lua_pushliteral (L, "_COPYRIGHT");
503 lua_pushliteral (L, "Copyright (C) 2003-2006 Kepler Project");
504 lua_settable (L, -3);
505 lua_pushliteral (L, "_DESCRIPTION");
506 lua_pushliteral (L, "Reading files inside zip files");
507 lua_settable (L, -3);
508 lua_pushliteral (L, "_VERSION");
509 lua_pushliteral (L, "LuaZip 1.2.2");
510 lua_settable (L, -3);
513 static void createmeta (lua_State *L) {
514 luaL_newmetatable(L, ZIPFILEHANDLE); /* create new metatable for file handles */
515 /* file methods */
516 lua_pushliteral(L, "__index");
517 lua_pushvalue(L, -2); /* push metatable */
518 lua_rawset(L, -3); /* metatable.__index = metatable */
519 luaL_openlib(L, NULL, flib, 0);
521 luaL_newmetatable(L, ZIPINTERNALFILEHANDLE); /* create new metatable for internal file handles */
522 /* internal file methods */
523 lua_pushliteral(L, "__index");
524 lua_pushvalue(L, -2); /* push metatable */
525 lua_rawset(L, -3); /* metatable.__index = metatable */
526 luaL_openlib(L, NULL, fflib, 0);
529 LUAZIP_API int luaopen_zip (lua_State *L) {
530 createmeta(L);
531 lua_pushvalue(L, -1);
532 luaL_openlib(L, LUA_ZIPLIBNAME, ziplib, 1);
533 set_info(L);
534 return 1;