MonoPosixHelper.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #include "MonoPosixHelper.h"
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include "../external/zlib/zlib.h"
  5. #include "vm/Exception.h"
  6. #define BUFFER_SIZE 4096
  7. #define ARGUMENT_ERROR -10
  8. #define IO_ERROR -11
  9. typedef int32_t (*read_write_func)(intptr_t buffer, int32_t length, intptr_t gchandle);
  10. struct ZStream
  11. {
  12. z_stream *stream;
  13. uint8_t *buffer;
  14. read_write_func func;
  15. void *gchandle;
  16. uint8_t compress;
  17. uint8_t eof;
  18. uint32_t total_in;
  19. };
  20. static int32_t write_to_managed(ZStream *stream)
  21. {
  22. int32_t n;
  23. z_stream *zs;
  24. zs = stream->stream;
  25. if (zs->avail_out != BUFFER_SIZE)
  26. {
  27. intptr_t buffer_ptr = reinterpret_cast<intptr_t>(stream->buffer);
  28. intptr_t gchandle_ptr = reinterpret_cast<intptr_t>(stream->gchandle);
  29. n = stream->func(buffer_ptr, BUFFER_SIZE - zs->avail_out, gchandle_ptr);
  30. zs->next_out = stream->buffer;
  31. zs->avail_out = BUFFER_SIZE;
  32. if (n < 0)
  33. return IO_ERROR;
  34. }
  35. return 0;
  36. }
  37. static int32_t flush_internal(ZStream *stream, bool is_final)
  38. {
  39. int32_t status;
  40. if (!stream->compress)
  41. return 0;
  42. if (!is_final && stream->stream->avail_in != 0)
  43. {
  44. status = deflate(stream->stream, Z_PARTIAL_FLUSH);
  45. if (status != Z_OK && status != Z_STREAM_END)
  46. return status;
  47. }
  48. return write_to_managed(stream);
  49. }
  50. static void *z_alloc(void *opaque, uint32_t nitems, uint32_t item_size)
  51. {
  52. return calloc(nitems, item_size);
  53. }
  54. static void z_free(void *opaque, void *ptr)
  55. {
  56. free(ptr);
  57. }
  58. intptr_t CreateZStream(int32_t compress, uint8_t gzip, Il2CppMethodPointer func_ptr, intptr_t gchandle)
  59. {
  60. z_stream *z;
  61. int32_t retval;
  62. ZStream *result;
  63. intptr_t result_ptr = 0;
  64. read_write_func func = (read_write_func)func_ptr;
  65. if (func == NULL)
  66. return result_ptr;
  67. #if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1204)
  68. // Older versions of zlib do not support raw deflate or gzip
  69. return NULL;
  70. #endif
  71. z = (z_stream*)calloc(1, sizeof(z_stream));
  72. if (compress)
  73. {
  74. retval = deflateInit2(z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, gzip ? 31 : -15, 8, Z_DEFAULT_STRATEGY);
  75. }
  76. else
  77. {
  78. retval = inflateInit2(z, gzip ? 31 : -15);
  79. }
  80. if (retval != Z_OK)
  81. {
  82. free(z);
  83. return result_ptr;
  84. }
  85. z->zalloc = z_alloc;
  86. z->zfree = z_free;
  87. result = (ZStream*)calloc(1, sizeof(ZStream));
  88. result->stream = z;
  89. result->func = func;
  90. result->gchandle = reinterpret_cast<void*>(gchandle);
  91. result->compress = compress;
  92. result->buffer = (uint8_t*)malloc(BUFFER_SIZE * sizeof(uint8_t));
  93. result->stream->next_out = result->buffer;
  94. result->stream->avail_out = BUFFER_SIZE;
  95. result->stream->total_in = 0;
  96. result_ptr = reinterpret_cast<intptr_t>(result);
  97. return result_ptr;
  98. }
  99. int32_t CloseZStream(intptr_t zstream)
  100. {
  101. int32_t status;
  102. int32_t flush_status;
  103. ZStream *stream = reinterpret_cast<ZStream*>(zstream);
  104. if (stream == NULL)
  105. return ARGUMENT_ERROR;
  106. status = 0;
  107. if (stream->compress)
  108. {
  109. if (stream->stream->total_in > 0)
  110. {
  111. do
  112. {
  113. status = deflate(stream->stream, Z_FINISH);
  114. flush_status = flush_internal(stream, true);
  115. }
  116. while (status == Z_OK); /* We want Z_STREAM_END or error here here */
  117. if (status == Z_STREAM_END)
  118. status = flush_status;
  119. }
  120. deflateEnd(stream->stream);
  121. }
  122. else
  123. {
  124. inflateEnd(stream->stream);
  125. }
  126. free(stream->buffer);
  127. free(stream->stream);
  128. memset(stream, 0, sizeof(ZStream));
  129. free(stream);
  130. return status;
  131. }
  132. int32_t Flush(intptr_t zstream)
  133. {
  134. ZStream *stream = (ZStream*)zstream;
  135. return flush_internal(stream, false);
  136. }
  137. int32_t ReadZStream(intptr_t zstream, intptr_t zbuffer, int32_t length)
  138. {
  139. int32_t n;
  140. int32_t status;
  141. z_stream *zs;
  142. ZStream *stream = (ZStream*)zstream;
  143. uint8_t *buffer = (uint8_t*)zbuffer;
  144. if (stream == NULL || buffer == NULL || length < 0)
  145. return ARGUMENT_ERROR;
  146. if (stream->eof)
  147. return 0;
  148. zs = stream->stream;
  149. zs->next_out = buffer;
  150. zs->avail_out = length;
  151. while (zs->avail_out > 0)
  152. {
  153. if (zs->avail_in == 0)
  154. {
  155. intptr_t buffer_ptr = reinterpret_cast<intptr_t>(stream->buffer);
  156. intptr_t gchandle_ptr = reinterpret_cast<intptr_t>(stream->gchandle);
  157. n = stream->func(buffer_ptr, BUFFER_SIZE, gchandle_ptr);
  158. if (n < 0)
  159. n = 0;
  160. // Even if avail_in reports zero, and we have no more data from the stream,
  161. // inflate may have more data to return. So we cannot break here and need to
  162. // keep calling inflate until it returns Z_STREAM_END.
  163. stream->total_in += n;
  164. zs->next_in = stream->buffer;
  165. zs->avail_in = n;
  166. }
  167. status = inflate(stream->stream, Z_SYNC_FLUSH);
  168. if (status == Z_STREAM_END)
  169. {
  170. stream->eof = 1;
  171. break;
  172. }
  173. else if (status == Z_BUF_ERROR && stream->total_in == zs->total_in)
  174. {
  175. if (zs->avail_in != 0)
  176. {
  177. stream->eof = 1;
  178. }
  179. break;
  180. }
  181. else if (status != Z_OK)
  182. {
  183. return status;
  184. }
  185. }
  186. return length - zs->avail_out;
  187. }
  188. int32_t WriteZStream(intptr_t zstream, intptr_t zbuffer, int32_t length)
  189. {
  190. int32_t n;
  191. int32_t status;
  192. z_stream *zs;
  193. ZStream *stream = (ZStream*)zstream;
  194. uint8_t *buffer = (uint8_t*)zbuffer;
  195. if (stream == NULL || buffer == NULL || length < 0)
  196. return ARGUMENT_ERROR;
  197. if (stream->eof)
  198. return IO_ERROR;
  199. zs = stream->stream;
  200. zs->next_in = buffer;
  201. zs->avail_in = length;
  202. while (zs->avail_in > 0)
  203. {
  204. if (zs->avail_out == 0)
  205. {
  206. zs->next_out = stream->buffer;
  207. zs->avail_out = BUFFER_SIZE;
  208. }
  209. status = deflate(stream->stream, Z_NO_FLUSH);
  210. if (status != Z_OK && status != Z_STREAM_END)
  211. return status;
  212. if (zs->avail_out == 0)
  213. {
  214. n = write_to_managed(stream);
  215. if (n < 0)
  216. return n;
  217. }
  218. }
  219. return length;
  220. }
  221. // The following methods are used by LinuxNetworkChange
  222. // Which the implementation for System.Net.NetworkInformation.NetworkChange on linux
  223. // These are here we throw a NotImplemented exception rather than getting an entry point not found
  224. // We could probably port this if we hard the time
  225. intptr_t CreateNLSocket()
  226. {
  227. IL2CPP_NOT_IMPLEMENTED(CreateNLSocket);
  228. NOT_SUPPORTED_IL2CPP(CreateNLSocket, Not implemented);
  229. return 0;
  230. }
  231. int32_t ReadEvents(intptr_t sock, intptr_t buffer, int32_t count, int32_t size)
  232. {
  233. IL2CPP_NOT_IMPLEMENTED(ReadEvents);
  234. NOT_SUPPORTED_IL2CPP(ReadEvents, Not implemented);
  235. return 0;
  236. }
  237. intptr_t CloseNLSocket(intptr_t sock)
  238. {
  239. IL2CPP_NOT_IMPLEMENTED(CloseNLSocket);
  240. NOT_SUPPORTED_IL2CPP(CloseNLSocket, Not implemented);
  241. return 0;
  242. }