2 LuaZip - Reading files inside zip files.
3 http://www.keplerproject.org/luazip/
6 Copyright (c) 2003-2006 Kepler Project
8 $Id: luazip.c,v 1.9 2006/03/23 20:44:53 carregal Exp $
13 #include "zzip/zzip.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
) {
23 lua_pushboolean(L
, 1);
29 lua_pushfstring(L
, "%s: %s", filename
, zzip_strerror(zzip_errno(errno
)));
31 lua_pushfstring(L
, "%s", zzip_strerror(zzip_errno(errno
)));
32 lua_pushnumber(L
, zzip_errno(errno
));
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");
43 static ZZIP_DIR
* tofile (lua_State
*L
, int findex
) {
44 ZZIP_DIR
** f
= topfile(L
, findex
);
46 luaL_error(L
, "attempt to use a closed zip file");
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");
56 static ZZIP_FILE
* tointernalfile (lua_State
*L
, int findex
) {
57 ZZIP_FILE
** f
= topinternalfile(L
, findex
);
59 luaL_error(L
, "attempt to use a closed zip file");
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);
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);
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);
94 lua_pushfstring(L
, "could not open file `%s'", zipfilename
);
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);
109 lua_pushboolean(L
, 0);
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);
125 lua_pushfstring(L
, "could not open file `%s'", filename
);
132 static int zip_openfile (lua_State
*L
) {
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 */
148 lua_rawseti(L
, -2, 1);
150 /* replaces the string by the table with the string inside */
154 if (lua_istable(L
, 2))
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
, ".");
176 ext2
[m
] = lua_tostring(L
, -1);
183 *inf
= zzip_open_ext_io(filename
, 0, 0664, ext
, 0);
187 *inf
= zzip_open(filename
, 0);
194 lua_pushfstring(L
, "could not open file `%s'", filename
);
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
);
202 lua_pushliteral(L
, "closed zip file");
204 lua_pushliteral(L
, "zip file");
208 static int zip_tostring (lua_State
*L
) {
210 ZZIP_DIR
** f
= topfile(L
, 1);
212 strcpy(buff
, "closed");
214 sprintf(buff
, "%p", lua_touserdata(L
, 1));
215 lua_pushfstring(L
, "zip file (%s)", buff
);
219 static int ff_tostring (lua_State
*L
) {
221 ZZIP_FILE
** f
= topinternalfile(L
, 1);
223 strcpy(buff
, "closed");
225 sprintf(buff
, "%p", lua_touserdata(L
, 1));
226 lua_pushfstring(L
, "file in zip file (%s)", buff
);
230 static int zip_gc (lua_State
*L
) {
231 ZZIP_DIR
**f
= topfile(L
, 1);
232 if (*f
!= NULL
) /* ignore closed files */
237 static int zip_readfile (lua_State
*L
) {
238 ZZIP_DIRENT
* ent
= 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
);
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);
259 static int f_files (lua_State
*L
) {
260 ZZIP_DIR
*f
= tofile(L
, 1);
262 lua_pushliteral(L
, ZIPFILEHANDLE
);
263 lua_rawget(L
, LUA_REGISTRYINDEX
);
264 lua_pushcclosure(L
, zip_readfile
, 2);
268 static int aux_close (lua_State
*L
) {
269 ZZIP_FILE
*f
= tointernalfile(L
, 1);
270 int ok
= (zzip_fclose(f
) == 0);
272 *(ZZIP_FILE
**)lua_touserdata(L
, 1) = NULL
; /* mark file as closed */
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 */
287 static int zzip_getc (ZZIP_FILE
*f
)
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
)
297 for (i
= 0; i
< size
-1; i
++)
299 c
= zzip_getc(stream
);
303 if (('\n' == c
)/* || ('\r' == c)*/)
314 /* no support to read numbers
315 static int zzip_fscanf (ZZIP_FILE *f, const char *format, ...)
321 static int read_number (lua_State *L, ZZIP_FILE *f) {
323 if (zzip_fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
324 lua_pushnumber(L, d);
327 else return 0; // read fails
331 static int test_eof (lua_State
*L
, ZZIP_FILE
*f
) {
338 static int read_line (lua_State
*L
, ZZIP_FILE
*f
) {
340 luaL_buffinit(L
, &b
);
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 */
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 */
363 luaL_buffinit(L
, &b
);
364 rlen
= LUAL_BUFFERSIZE
; /* try to read that much each time */
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;
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");
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
);
393 const char *p
= lua_tostring(L
, n
);
394 luaL_argcheck(L
, p
&& p
[0] == '*', n
, "invalid option");
397 success
= read_line(L
, f
);
400 read_chars(L
, f
, ~((size_t)0)); /* read MAX_SIZE_T chars */
401 success
= 1; /* always success */
404 return luaL_argerror(L
, n
, "invalid format");
410 lua_pop(L
, 1); /* remove last result */
411 lua_pushnil(L
); /* push nil instead */
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 */
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;
442 if (lua_toboolean(L
, lua_upvalueindex(3))) { /* generator created file? */
444 lua_pushvalue(L
, lua_upvalueindex(2));
445 aux_close(L
); /* close it */
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
]);
460 return pushresult(L
, 0, NULL
); /* error */
462 lua_pushnumber(L
, zzip_tell(f
));
467 static const luaL_Reg ziplib
[] = {
469 {"close", zip_close
},
471 /* {"files", io_files},*/
472 {"openfile", zip_openfile
},
476 static const luaL_Reg flib
[] = {
478 {"close", zip_close
},
481 {"__tostring", zip_tostring
},
485 static const luaL_Reg fflib
[] = {
491 {"__tostring", ff_tostring
},
492 /* {"flush", ff_flush},
493 {"write", ff_write},*/
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 */
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
) {
531 lua_pushvalue(L
, -1);
532 luaL_openlib(L
, LUA_ZIPLIBNAME
, ziplib
, 1);