sq_miniz.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #include <ctype.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include "squirrel.h"
  6. #include "sqstdblobimpl.h"
  7. SQ_OPT_STRING_STRLEN();
  8. #define LZ_BUFFER_SIZE 8192
  9. #include "vogl_miniz_zip.h"
  10. static const SQChar sq_miniz_ziparchive_TAG[] = _SC("sq_miniz_ziparchive_tag");
  11. #define GET_miniz_ziparchive_INSTANCE_VAR_AT(idx, Var) \
  12. SQ_GET_INSTANCE_VAR(v, idx, mz_zip_archive, Var, sq_miniz_ziparchive_TAG);\
  13. if(!Var) return sq_throwerror(v, _SC("miniz_ziparchive already destroyed"));
  14. #define GET_miniz_ziparchive_INSTANCE() GET_miniz_ziparchive_INSTANCE_VAR_AT(1, self)
  15. static SQRESULT sq_miniz_ziparchive_releasehook(SQUserPointer p, SQInteger size, HSQUIRRELVM v)
  16. {
  17. mz_zip_archive *self = ((mz_zip_archive *)p);
  18. if(self) {
  19. mz_zip_reader_end(self);
  20. sq_free(self, sizeof(mz_zip_archive));
  21. }
  22. return 0;
  23. }
  24. static SQRESULT sq_miniz_ziparchive_constructor(HSQUIRRELVM v)
  25. {
  26. SQ_FUNC_VARS_NO_TOP(v);
  27. SQ_GET_STRING(v, 2, zip_fname);
  28. mz_zip_archive *zip_archive = (mz_zip_archive*)sq_malloc(sizeof(mz_zip_archive));
  29. memset(zip_archive, 0, sizeof(mz_zip_archive));
  30. if(!mz_zip_reader_init_file(zip_archive, zip_fname, 0, 0, 0))
  31. {
  32. return sq_throwerror(v, _SC("mz_zip_reader_init_file() failed!"));
  33. }
  34. sq_setinstanceup(v, 1, zip_archive);
  35. sq_setreleasehook(v,1, sq_miniz_ziparchive_releasehook);
  36. return 1;
  37. }
  38. static SQRESULT sq_miniz_ziparchive_get_num_files(HSQUIRRELVM v)
  39. {
  40. SQ_FUNC_VARS_NO_TOP(v);
  41. GET_miniz_ziparchive_INSTANCE();
  42. sq_pushinteger(v, mz_zip_get_num_files(self));
  43. return 1;
  44. }
  45. static SQRESULT sq_miniz_ziparchive_file_stat(HSQUIRRELVM v, mz_zip_archive_file_stat *file_stat)
  46. {
  47. SQ_FUNC_VARS_NO_TOP(v);
  48. GET_miniz_ziparchive_INSTANCE();
  49. SQ_GET_INTEGER(v, 2, idx);
  50. if (!mz_zip_file_stat(self, idx, file_stat))
  51. {
  52. return sq_throwerror(v, _SC("mz_zip_file_stat() failed!"));
  53. }
  54. return SQ_OK;
  55. }
  56. static SQRESULT sq_miniz_ziparchive_get_file_name(HSQUIRRELVM v)
  57. {
  58. mz_zip_archive_file_stat file_stat;
  59. SQRESULT rc = sq_miniz_ziparchive_file_stat(v, &file_stat);
  60. if(rc != SQ_OK) return rc;
  61. sq_pushstring(v, file_stat.m_filename, -1);
  62. return 1;
  63. }
  64. static SQRESULT sq_miniz_ziparchive_get_file_size(HSQUIRRELVM v)
  65. {
  66. mz_zip_archive_file_stat file_stat;
  67. SQRESULT rc = sq_miniz_ziparchive_file_stat(v, &file_stat);
  68. if(rc != SQ_OK) return rc;
  69. sq_pushinteger(v, file_stat.m_uncomp_size);
  70. return 1;
  71. }
  72. static SQRESULT sq_miniz_ziparchive_is_file_a_directory(HSQUIRRELVM v)
  73. {
  74. SQ_FUNC_VARS_NO_TOP(v);
  75. GET_miniz_ziparchive_INSTANCE();
  76. SQ_GET_INTEGER(v, 2, idx);
  77. sq_pushbool(v, mz_zip_is_file_a_directory(self, idx));
  78. return 1;
  79. }
  80. static SQRESULT sq_miniz_ziparchive_extract_file(HSQUIRRELVM v)
  81. {
  82. SQ_FUNC_VARS_NO_TOP(v);
  83. GET_miniz_ziparchive_INSTANCE();
  84. SQ_GET_INTEGER(v, 2, idx);
  85. size_t uncomp_size;
  86. void *p = mz_zip_extract_to_heap(self, idx, &uncomp_size, 0);
  87. if (!p)
  88. {
  89. return sq_throwerror(v, _SC("mz_zip_extract_to_heap() failed!"));
  90. }
  91. sq_pushstring(v, (const SQChar*)p, uncomp_size);
  92. MZ_FREE(p);
  93. return 1;
  94. }
  95. static SQRESULT sq_miniz_ziparchive_destroy(HSQUIRRELVM v)
  96. {
  97. SQ_FUNC_VARS_NO_TOP(v);
  98. GET_miniz_ziparchive_INSTANCE();
  99. int rc = sq_miniz_ziparchive_releasehook(self, 0, v);
  100. if(rc == 0) sq_setinstanceup(v, 1, 0);
  101. sq_pushinteger(v, rc);
  102. return 1;
  103. }
  104. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_miniz_ziparchive_##name,nparams,tycheck}
  105. static SQRegFunction sq_miniz_ziparchive_methods[] =
  106. {
  107. _DECL_FUNC(constructor, 2, _SC("xs")),
  108. _DECL_FUNC(get_num_files, 1, _SC("x")),
  109. _DECL_FUNC(get_file_name, 2, _SC("xi")),
  110. _DECL_FUNC(get_file_size, 2, _SC("xi")),
  111. _DECL_FUNC(is_file_a_directory, 2, _SC("xi")),
  112. _DECL_FUNC(extract_file, 2, _SC("xi")),
  113. _DECL_FUNC(destroy, 1, _SC("x")),
  114. {0,0}
  115. };
  116. #undef _DECL_FUNC
  117. static SQRESULT sq_check_result(HSQUIRRELVM v, int result, const mz_stream_s* stream) {
  118. /* Both of these are "normal" return codes: */
  119. if ( result == MZ_OK || result == MZ_STREAM_END ) return SQ_OK;
  120. switch ( result ) {
  121. case MZ_NEED_DICT:
  122. return sq_throwerror(v, _SC("RequiresDictionary: input stream requires a dictionary to be deflated (%s)"),
  123. stream->msg);
  124. break;
  125. case MZ_STREAM_ERROR:
  126. return sq_throwerror(v, _SC("InternalError: inconsistent internal zlib stream (%s)"),
  127. stream->msg);
  128. break;
  129. case MZ_DATA_ERROR:
  130. return sq_throwerror(v, _SC("InvalidInput: input string does not conform to zlib format or checksum"));
  131. break;
  132. case MZ_MEM_ERROR:
  133. return sq_throwerror(v, _SC("OutOfMemory: not enough memory (%s)"), stream->msg);
  134. break;
  135. case MZ_BUF_ERROR:
  136. return sq_throwerror(v, _SC("InternalError: no progress possible (%s)"), stream->msg);
  137. break;
  138. case MZ_VERSION_ERROR:
  139. return sq_throwerror(v, _SC("IncompatibleLibrary: built with version %s, but dynamically linked with version %s (%s)"),
  140. MZ_VERSION, mz_version(), stream->msg);
  141. break;
  142. default:
  143. return sq_throwerror(v, _SC("ZLibError: unknown code %d (%s)"), result, stream->msg);
  144. }
  145. return SQ_OK;
  146. }
  147. static SQRESULT sq_miniz_deflate(HSQUIRRELVM v)
  148. {
  149. SQ_FUNC_VARS(v);
  150. SQ_GET_STRING(v, 2, data);
  151. SQ_OPT_INTEGER(v, 3, level, MZ_DEFAULT_COMPRESSION);
  152. /* Allocate the stream: */
  153. mz_stream_s stream;
  154. stream.zalloc = NULL;
  155. stream.zfree = NULL;
  156. if(sq_check_result(v, mz_deflateInit(&stream, level), &stream) != SQ_OK) return SQ_ERROR;
  157. SQBlob b(LZ_BUFFER_SIZE);
  158. /* Do the actual deflate'ing: */
  159. stream.next_in = (unsigned char*)data;
  160. stream.avail_in = data_size;
  161. if ( ! stream.avail_in ) {
  162. /* Passed empty string, make it a noop instead of erroring out. */
  163. sq_pushliteral(v, "");
  164. return 1;
  165. }
  166. int nchunks = 0;
  167. do {
  168. stream.next_out = ((unsigned char*)b.GetBuf()) + (LZ_BUFFER_SIZE * nchunks++);
  169. stream.avail_out = LZ_BUFFER_SIZE;
  170. int result = mz_deflate(&stream, MZ_FINISH);
  171. if (result == MZ_STREAM_END )
  172. break;
  173. if (result != MZ_OK)
  174. {
  175. sq_check_result(v, result, &stream);
  176. mz_deflateEnd(&stream);
  177. return SQ_ERROR;
  178. }
  179. b.GrowBufOf(LZ_BUFFER_SIZE);
  180. } while ( stream.avail_out == 0 );
  181. SQInteger total_out = stream.total_out;
  182. /* Close the stream: */
  183. if(sq_check_result(v, mz_deflateEnd(&stream), &stream) == SQ_ERROR) return SQ_ERROR;
  184. /* Need to do this before we alter the stack: */
  185. sq_pushstring(v, (const SQChar*)b.GetBuf(), total_out);
  186. return 1;
  187. }
  188. static SQRESULT sq_miniz_inflate(HSQUIRRELVM v)
  189. {
  190. SQ_FUNC_VARS_NO_TOP(v);
  191. SQ_GET_STRING(v, 2, data);
  192. /* By default, we will do gzip header detection w/ max window size */
  193. //SQ_OPT_INTEGER(v, 3, window_size, MAX_WBITS + 32);
  194. /* Allocate the stream: */
  195. mz_stream_s stream;
  196. stream.zalloc = NULL;
  197. stream.zfree = NULL;
  198. //if(sq_check_result(v, inflateInit2(&stream, window_size), &stream) != SQ_OK) return SQ_ERROR;
  199. if(sq_check_result(v, mz_inflateInit(&stream), &stream) != SQ_OK) return SQ_ERROR;
  200. SQBlob b(LZ_BUFFER_SIZE);
  201. /* Do the actual deflate'ing: */
  202. stream.next_in = (unsigned char*)data;
  203. stream.avail_in = data_size;
  204. if ( ! stream.avail_in ) {
  205. /* Passed empty string, make it a noop instead of erroring out. */
  206. sq_pushliteral(v, "");
  207. return 1;
  208. }
  209. int nchunks = 0;
  210. do {
  211. stream.next_out = ((unsigned char*)b.GetBuf()) + (LZ_BUFFER_SIZE * nchunks++);
  212. stream.avail_out = LZ_BUFFER_SIZE;
  213. int result = mz_inflate(&stream, MZ_FINISH);
  214. if ( MZ_BUF_ERROR != result ) {
  215. /* Ignore Z_BUF_ERROR since that just indicates that we
  216. * need a larger buffer in order to proceed. Thanks to
  217. * Tobias Markmann for finding this bug!
  218. */
  219. if(sq_check_result(v, result, &stream) == SQ_OK) break;
  220. else {
  221. mz_inflateEnd(&stream);
  222. return SQ_ERROR;
  223. }
  224. }
  225. b.GrowBufOf(LZ_BUFFER_SIZE);
  226. } while ( stream.avail_out == 0 );
  227. SQInteger total_out = stream.total_out;
  228. /* Close the stream: */
  229. if(sq_check_result(v, mz_inflateEnd(&stream), &stream) == SQ_ERROR) return SQ_ERROR;
  230. /* Need to do this before we alter the stack: */
  231. sq_pushstring(v, (const SQChar*)b.GetBuf(), total_out);
  232. return 1;
  233. }
  234. static SQRESULT sq_miniz_version(HSQUIRRELVM v)
  235. {
  236. sq_pushstring(v, mz_version(), -1);
  237. return 1;
  238. }
  239. #ifdef __cplusplus
  240. extern "C" {
  241. #endif
  242. #define INT_CONST(v,num) sq_pushstring(v,_SC(#num),-1);sq_pushinteger(v,num);sq_newslot(v,-3,SQTrue);
  243. SQRESULT sqext_register_sq_miniz(HSQUIRRELVM v)
  244. {
  245. sq_pushliteral(v,_SC("miniz"));
  246. sq_newtable(v);
  247. INT_CONST(v, MZ_DEFAULT_COMPRESSION);
  248. INT_CONST(v, MZ_BEST_SPEED);
  249. INT_CONST(v, MZ_BEST_COMPRESSION);
  250. sq_insertfunc(v, _SC("version"), sq_miniz_version, 1, _SC("."), SQTrue);
  251. sq_insertfunc(v, _SC("deflate"), sq_miniz_deflate, -2, _SC(".si"), SQTrue);
  252. sq_insertfunc(v, _SC("inflate"), sq_miniz_inflate, -2, _SC(".s"), SQTrue);
  253. sq_pushliteral(v,_SC("ZipArchive"));
  254. sq_newclass(v,SQFalse);
  255. sq_settypetag(v,-1,(void*)sq_miniz_ziparchive_TAG);
  256. sq_insert_reg_funcs(v, sq_miniz_ziparchive_methods);
  257. sq_newslot(v,-3,SQTrue);
  258. sq_newslot(v,-3,SQTrue); //push miniz table
  259. return 0;
  260. }
  261. #ifdef __cplusplus
  262. }
  263. #endif