294 lines
7.0 KiB
C++
294 lines
7.0 KiB
C++
#include "MonoPosixHelper.h"
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "../external/zlib/zlib.h"
|
|
|
|
#include "vm/Exception.h"
|
|
|
|
#define BUFFER_SIZE 4096
|
|
#define ARGUMENT_ERROR -10
|
|
#define IO_ERROR -11
|
|
|
|
typedef int32_t (*read_write_func)(intptr_t buffer, int32_t length, intptr_t gchandle);
|
|
|
|
struct ZStream
|
|
{
|
|
z_stream *stream;
|
|
uint8_t *buffer;
|
|
read_write_func func;
|
|
void *gchandle;
|
|
uint8_t compress;
|
|
uint8_t eof;
|
|
uint32_t total_in;
|
|
};
|
|
|
|
static int32_t write_to_managed(ZStream *stream)
|
|
{
|
|
int32_t n;
|
|
z_stream *zs;
|
|
|
|
zs = stream->stream;
|
|
if (zs->avail_out != BUFFER_SIZE)
|
|
{
|
|
intptr_t buffer_ptr = reinterpret_cast<intptr_t>(stream->buffer);
|
|
intptr_t gchandle_ptr = reinterpret_cast<intptr_t>(stream->gchandle);
|
|
|
|
n = stream->func(buffer_ptr, BUFFER_SIZE - zs->avail_out, gchandle_ptr);
|
|
zs->next_out = stream->buffer;
|
|
zs->avail_out = BUFFER_SIZE;
|
|
if (n < 0)
|
|
return IO_ERROR;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int32_t flush_internal(ZStream *stream, bool is_final)
|
|
{
|
|
int32_t status;
|
|
|
|
if (!stream->compress)
|
|
return 0;
|
|
|
|
if (!is_final && stream->stream->avail_in != 0)
|
|
{
|
|
status = deflate(stream->stream, Z_PARTIAL_FLUSH);
|
|
if (status != Z_OK && status != Z_STREAM_END)
|
|
return status;
|
|
}
|
|
|
|
return write_to_managed(stream);
|
|
}
|
|
|
|
static void *z_alloc(void *opaque, uint32_t nitems, uint32_t item_size)
|
|
{
|
|
return calloc(nitems, item_size);
|
|
}
|
|
|
|
static void z_free(void *opaque, void *ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
|
|
intptr_t CreateZStream(int32_t compress, uint8_t gzip, Il2CppMethodPointer func_ptr, intptr_t gchandle)
|
|
{
|
|
z_stream *z;
|
|
int32_t retval;
|
|
ZStream *result;
|
|
|
|
intptr_t result_ptr = 0;
|
|
read_write_func func = (read_write_func)func_ptr;
|
|
|
|
if (func == NULL)
|
|
return result_ptr;
|
|
|
|
#if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1204)
|
|
// Older versions of zlib do not support raw deflate or gzip
|
|
return NULL;
|
|
#endif
|
|
|
|
z = (z_stream*)calloc(1, sizeof(z_stream));
|
|
if (compress)
|
|
{
|
|
retval = deflateInit2(z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, gzip ? 31 : -15, 8, Z_DEFAULT_STRATEGY);
|
|
}
|
|
else
|
|
{
|
|
retval = inflateInit2(z, gzip ? 31 : -15);
|
|
}
|
|
|
|
if (retval != Z_OK)
|
|
{
|
|
free(z);
|
|
return result_ptr;
|
|
}
|
|
|
|
z->zalloc = z_alloc;
|
|
z->zfree = z_free;
|
|
result = (ZStream*)calloc(1, sizeof(ZStream));
|
|
result->stream = z;
|
|
result->func = func;
|
|
result->gchandle = reinterpret_cast<void*>(gchandle);
|
|
result->compress = compress;
|
|
result->buffer = (uint8_t*)malloc(BUFFER_SIZE * sizeof(uint8_t));
|
|
|
|
result->stream->next_out = result->buffer;
|
|
result->stream->avail_out = BUFFER_SIZE;
|
|
result->stream->total_in = 0;
|
|
|
|
result_ptr = reinterpret_cast<intptr_t>(result);
|
|
return result_ptr;
|
|
}
|
|
|
|
int32_t CloseZStream(intptr_t zstream)
|
|
{
|
|
int32_t status;
|
|
int32_t flush_status;
|
|
|
|
ZStream *stream = reinterpret_cast<ZStream*>(zstream);
|
|
|
|
if (stream == NULL)
|
|
return ARGUMENT_ERROR;
|
|
|
|
status = 0;
|
|
if (stream->compress)
|
|
{
|
|
if (stream->stream->total_in > 0)
|
|
{
|
|
do
|
|
{
|
|
status = deflate(stream->stream, Z_FINISH);
|
|
flush_status = flush_internal(stream, true);
|
|
}
|
|
while (status == Z_OK); /* We want Z_STREAM_END or error here here */
|
|
|
|
if (status == Z_STREAM_END)
|
|
status = flush_status;
|
|
}
|
|
deflateEnd(stream->stream);
|
|
}
|
|
else
|
|
{
|
|
inflateEnd(stream->stream);
|
|
}
|
|
|
|
free(stream->buffer);
|
|
free(stream->stream);
|
|
memset(stream, 0, sizeof(ZStream));
|
|
free(stream);
|
|
|
|
return status;
|
|
}
|
|
|
|
int32_t Flush(intptr_t zstream)
|
|
{
|
|
ZStream *stream = (ZStream*)zstream;
|
|
return flush_internal(stream, false);
|
|
}
|
|
|
|
int32_t ReadZStream(intptr_t zstream, intptr_t zbuffer, int32_t length)
|
|
{
|
|
int32_t n;
|
|
int32_t status;
|
|
z_stream *zs;
|
|
|
|
ZStream *stream = (ZStream*)zstream;
|
|
uint8_t *buffer = (uint8_t*)zbuffer;
|
|
|
|
if (stream == NULL || buffer == NULL || length < 0)
|
|
return ARGUMENT_ERROR;
|
|
|
|
if (stream->eof)
|
|
return 0;
|
|
|
|
zs = stream->stream;
|
|
zs->next_out = buffer;
|
|
zs->avail_out = length;
|
|
while (zs->avail_out > 0)
|
|
{
|
|
if (zs->avail_in == 0)
|
|
{
|
|
intptr_t buffer_ptr = reinterpret_cast<intptr_t>(stream->buffer);
|
|
intptr_t gchandle_ptr = reinterpret_cast<intptr_t>(stream->gchandle);
|
|
|
|
n = stream->func(buffer_ptr, BUFFER_SIZE, gchandle_ptr);
|
|
if (n < 0)
|
|
n = 0;
|
|
|
|
// Even if avail_in reports zero, and we have no more data from the stream,
|
|
// inflate may have more data to return. So we cannot break here and need to
|
|
// keep calling inflate until it returns Z_STREAM_END.
|
|
|
|
stream->total_in += n;
|
|
zs->next_in = stream->buffer;
|
|
zs->avail_in = n;
|
|
}
|
|
|
|
status = inflate(stream->stream, Z_SYNC_FLUSH);
|
|
if (status == Z_STREAM_END)
|
|
{
|
|
stream->eof = 1;
|
|
break;
|
|
}
|
|
else if (status == Z_BUF_ERROR && stream->total_in == zs->total_in)
|
|
{
|
|
if (zs->avail_in != 0)
|
|
{
|
|
stream->eof = 1;
|
|
}
|
|
break;
|
|
}
|
|
else if (status != Z_OK)
|
|
{
|
|
return status;
|
|
}
|
|
}
|
|
return length - zs->avail_out;
|
|
}
|
|
|
|
int32_t WriteZStream(intptr_t zstream, intptr_t zbuffer, int32_t length)
|
|
{
|
|
int32_t n;
|
|
int32_t status;
|
|
z_stream *zs;
|
|
|
|
ZStream *stream = (ZStream*)zstream;
|
|
uint8_t *buffer = (uint8_t*)zbuffer;
|
|
|
|
if (stream == NULL || buffer == NULL || length < 0)
|
|
return ARGUMENT_ERROR;
|
|
|
|
if (stream->eof)
|
|
return IO_ERROR;
|
|
|
|
zs = stream->stream;
|
|
zs->next_in = buffer;
|
|
zs->avail_in = length;
|
|
while (zs->avail_in > 0)
|
|
{
|
|
if (zs->avail_out == 0)
|
|
{
|
|
zs->next_out = stream->buffer;
|
|
zs->avail_out = BUFFER_SIZE;
|
|
}
|
|
status = deflate(stream->stream, Z_NO_FLUSH);
|
|
if (status != Z_OK && status != Z_STREAM_END)
|
|
return status;
|
|
|
|
if (zs->avail_out == 0)
|
|
{
|
|
n = write_to_managed(stream);
|
|
if (n < 0)
|
|
return n;
|
|
}
|
|
}
|
|
return length;
|
|
}
|
|
|
|
// The following methods are used by LinuxNetworkChange
|
|
// Which the implementation for System.Net.NetworkInformation.NetworkChange on linux
|
|
// These are here we throw a NotImplemented exception rather than getting an entry point not found
|
|
// We could probably port this if we hard the time
|
|
|
|
intptr_t CreateNLSocket()
|
|
{
|
|
IL2CPP_NOT_IMPLEMENTED(CreateNLSocket);
|
|
NOT_SUPPORTED_IL2CPP(CreateNLSocket, Not implemented);
|
|
return 0;
|
|
}
|
|
|
|
int32_t ReadEvents(intptr_t sock, intptr_t buffer, int32_t count, int32_t size)
|
|
{
|
|
IL2CPP_NOT_IMPLEMENTED(ReadEvents);
|
|
NOT_SUPPORTED_IL2CPP(ReadEvents, Not implemented);
|
|
return 0;
|
|
}
|
|
|
|
intptr_t CloseNLSocket(intptr_t sock)
|
|
{
|
|
IL2CPP_NOT_IMPLEMENTED(CloseNLSocket);
|
|
NOT_SUPPORTED_IL2CPP(CloseNLSocket, Not implemented);
|
|
return 0;
|
|
}
|