sq_zlib.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #include <ctype.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <zlib.h>
  6. #include "squirrel.h"
  7. #include "sqstdblobimpl.h"
  8. SQ_OPT_STRING_STRLEN();
  9. #define LZ_BUFFER_SIZE 8192
  10. static int sq_check_result(HSQUIRRELVM v, int result, const z_stream* stream) {
  11. /* Both of these are "normal" return codes: */
  12. if ( result == Z_OK || result == Z_STREAM_END ) return SQ_OK;
  13. switch ( result ) {
  14. case Z_NEED_DICT:
  15. return sq_throwerror(v, _SC("RequiresDictionary: input stream requires a dictionary to be deflated (%s)"),
  16. stream->msg);
  17. break;
  18. case Z_STREAM_ERROR:
  19. return sq_throwerror(v, _SC("InternalError: inconsistent internal zlib stream (%s)"),
  20. stream->msg);
  21. break;
  22. case Z_DATA_ERROR:
  23. return sq_throwerror(v, _SC("InvalidInput: input string does not conform to zlib format or checksum"));
  24. break;
  25. case Z_MEM_ERROR:
  26. return sq_throwerror(v, _SC("OutOfMemory: not enough memory (%s)"), stream->msg);
  27. break;
  28. case Z_BUF_ERROR:
  29. return sq_throwerror(v, _SC("InternalError: no progress possible (%s)"), stream->msg);
  30. break;
  31. case Z_VERSION_ERROR:
  32. return sq_throwerror(v, _SC("IncompatibleLibrary: built with version %s, but dynamically linked with version %s (%s)"),
  33. ZLIB_VERSION, zlibVersion(), stream->msg);
  34. break;
  35. default:
  36. return sq_throwerror(v, _SC("ZLibError: unknown code %d (%s)"), result, stream->msg);
  37. }
  38. return SQ_OK;
  39. }
  40. static SQRESULT sq_zlib_deflate(HSQUIRRELVM v)
  41. {
  42. SQ_FUNC_VARS(v);
  43. SQ_GET_STRING(v, 2, data);
  44. SQ_OPT_INTEGER(v, 3, level, Z_DEFAULT_COMPRESSION);
  45. /* Allocate the stream: */
  46. z_stream stream;
  47. stream.zalloc = Z_NULL;
  48. stream.zfree = Z_NULL;
  49. if(sq_check_result(v, deflateInit(&stream, level), &stream) != SQ_OK) return SQ_ERROR;
  50. SQBlob b(LZ_BUFFER_SIZE);
  51. /* Do the actual deflate'ing: */
  52. stream.next_in = (unsigned char*)data;
  53. stream.avail_in = data_size;
  54. if ( ! stream.avail_in ) {
  55. /* Passed empty string, make it a noop instead of erroring out. */
  56. sq_pushliteral(v, "");
  57. return 1;
  58. }
  59. int nchunks = 0;
  60. do {
  61. stream.next_out = ((unsigned char*)b.GetBuf()) + (LZ_BUFFER_SIZE * nchunks++);
  62. stream.avail_out = LZ_BUFFER_SIZE;
  63. int result = deflate(&stream, Z_FINISH);
  64. if (result == Z_STREAM_END )
  65. break;
  66. if (result != Z_OK)
  67. {
  68. sq_check_result(v, result, &stream);
  69. deflateEnd(&stream);
  70. return SQ_ERROR;
  71. }
  72. b.GrowBufOf(LZ_BUFFER_SIZE);
  73. } while ( stream.avail_out == 0 );
  74. SQInteger total_out = stream.total_out;
  75. /* Close the stream: */
  76. if(sq_check_result(v, deflateEnd(&stream), &stream) == SQ_ERROR) return SQ_ERROR;
  77. /* Need to do this before we alter the stack: */
  78. sq_pushstring(v, (const SQChar*)b.GetBuf(), total_out);
  79. return 1;
  80. }
  81. static SQRESULT sq_zlib_inflate(HSQUIRRELVM v)
  82. {
  83. SQ_FUNC_VARS(v);
  84. SQ_GET_STRING(v, 2, data);
  85. /* By default, we will do gzip header detection w/ max window size */
  86. SQ_OPT_INTEGER(v, 3, window_size, MAX_WBITS + 32);
  87. /* Allocate the stream: */
  88. z_stream stream;
  89. stream.zalloc = Z_NULL;
  90. stream.zfree = Z_NULL;
  91. if(sq_check_result(v, inflateInit2(&stream, window_size), &stream) != SQ_OK) return SQ_ERROR;
  92. SQBlob b(LZ_BUFFER_SIZE);
  93. /* Do the actual deflate'ing: */
  94. stream.next_in = (unsigned char*)data;
  95. stream.avail_in = data_size;
  96. if ( ! stream.avail_in ) {
  97. /* Passed empty string, make it a noop instead of erroring out. */
  98. sq_pushliteral(v, "");
  99. return 1;
  100. }
  101. int nchunks = 0;
  102. do {
  103. stream.next_out = ((unsigned char*)b.GetBuf()) + (LZ_BUFFER_SIZE * nchunks++);
  104. stream.avail_out = LZ_BUFFER_SIZE;
  105. int result = inflate(&stream, Z_FINISH);
  106. if ( Z_BUF_ERROR != result ) {
  107. /* Ignore Z_BUF_ERROR since that just indicates that we
  108. * need a larger buffer in order to proceed. Thanks to
  109. * Tobias Markmann for finding this bug!
  110. */
  111. if(sq_check_result(v, result, &stream) == SQ_OK) break;
  112. else {
  113. inflateEnd(&stream);
  114. return SQ_ERROR;
  115. }
  116. }
  117. b.GrowBufOf(LZ_BUFFER_SIZE);
  118. } while ( stream.avail_out == 0 );
  119. SQInteger total_out = stream.total_out;
  120. /* Close the stream: */
  121. if(sq_check_result(v, inflateEnd(&stream), &stream) == SQ_ERROR) return SQ_ERROR;
  122. /* Need to do this before we alter the stack: */
  123. sq_pushstring(v, (const SQChar*)b.GetBuf(), total_out);
  124. return 1;
  125. }
  126. static int sq_zlib_version(HSQUIRRELVM v)
  127. {
  128. sq_pushstring(v, zlibVersion(), -1);
  129. return 1;
  130. }
  131. #ifdef __cplusplus
  132. extern "C" {
  133. #endif
  134. #define INT_CONST(v,num) sq_pushstring(v,_SC(#num),-1);sq_pushinteger(v,num);sq_newslot(v,-3,SQTrue);
  135. SQRESULT sqext_register_sq_zlib(HSQUIRRELVM v)
  136. {
  137. sq_pushliteral(v,_SC("zlib"));
  138. sq_newtable(v);
  139. INT_CONST(v, Z_DEFAULT_COMPRESSION);
  140. INT_CONST(v, Z_BEST_SPEED);
  141. INT_CONST(v, Z_BEST_COMPRESSION);
  142. sq_insertfunc(v, _SC("version"), sq_zlib_version, 1, _SC("."), SQTrue);
  143. sq_insertfunc(v, _SC("deflate"), sq_zlib_deflate, -2, _SC(".si"), SQTrue);
  144. sq_insertfunc(v, _SC("inflate"), sq_zlib_inflate, -2, _SC(".si"), SQTrue);
  145. sq_newslot(v,-3,SQTrue); //push zlib table
  146. return 0;
  147. }
  148. #ifdef __cplusplus
  149. }
  150. #endif