|
#include <stdio.h> |
|
#include <stdint.h> |
|
#include <string.h> |
|
#include <stdlib.h> |
|
#include <assert.h> |
|
|
|
typedef uint32_t u32; |
|
|
|
// Exports from sandboxed code (we could also include libz.wasm.h and |
|
// wasm-rt.h). |
|
|
|
/** A Memory object. */ |
|
typedef struct { |
|
/** The linear memory data, with a byte length of `size`. */ |
|
uint8_t* data; |
|
/** The current and maximum page count for this Memory object. If there is no |
|
* maximum, `max_pages` is 0xffffffffu (i.e. UINT32_MAX). */ |
|
uint32_t pages, max_pages; |
|
/** The current size of the linear memory, in bytes. */ |
|
uint32_t size; |
|
} wasm_rt_memory_t; |
|
|
|
extern wasm_rt_memory_t *Z_memory; |
|
|
|
// The zlib methods we need |
|
extern u32 (*Z_compressZ_iiiii)(u32, u32, u32, u32); |
|
extern u32 (*Z_compressBoundZ_ii)(u32); |
|
extern u32 (*Z_uncompressZ_iiiii)(u32, u32, u32, u32); |
|
|
|
// malloc() in the sandboxed wasm. |
|
extern u32 (*Z_mallocZ_ii)(u32); |
|
|
|
// Initialize the compiled wasm. This must be called before doing anything. |
|
extern void wasmbox_init(void); |
|
|
|
// Utilities |
|
|
|
void* wasm_addr_to_absolute(u32 wasm_addr) { |
|
return &Z_memory->data[wasm_addr]; |
|
} |
|
|
|
void write_u32(u32 wasm_addr, u32 value) { |
|
*(u32*)wasm_addr_to_absolute(wasm_addr) = value; |
|
} |
|
|
|
u32 read_u32(u32 wasm_addr) { |
|
return *(u32*)wasm_addr_to_absolute(wasm_addr); |
|
} |
|
|
|
// Main code |
|
|
|
int main() { |
|
wasmbox_init(); |
|
|
|
int size = 100 * 1000; |
|
|
|
// Create a buffer with some data that will compress fairly well. |
|
unsigned char *externalBuffer = (unsigned char*)malloc(size); |
|
|
|
int i = 0; |
|
int run = 0; |
|
char runChar = 17; |
|
while (i < size) { |
|
if (run > 0) { |
|
run--; |
|
} else { |
|
if ((i & 7) == 0) { |
|
runChar = i & 7; |
|
run = i & 31; |
|
} else { |
|
runChar = (i*i) % 6714; |
|
} |
|
} |
|
externalBuffer[i] = runChar; |
|
i++; |
|
} |
|
|
|
u32 zlib_result; |
|
|
|
// Allocate a buffer in the wasm, and copy the data to it. |
|
printf("buffer size: %u\n", size); |
|
u32 buffer = Z_mallocZ_ii(size); |
|
memcpy(wasm_addr_to_absolute(buffer), externalBuffer, size); |
|
|
|
// Get the maximum compressed size and allocate a buffer of that size. |
|
u32 maxCompressedSize = Z_compressBoundZ_ii(size); |
|
u32 buffer2 = Z_mallocZ_ii(maxCompressedSize); |
|
|
|
// compress() has an in-out param which receives the size of the buffer for |
|
// the compressed data, and will contain the used space in that buffer that |
|
// the compressed data actually takes. For this we allocate a u32 whose |
|
// address we can pass to zlib. |
|
u32 compressedSizeBuffer = Z_mallocZ_ii(4); |
|
write_u32(compressedSizeBuffer, maxCompressedSize); |
|
|
|
// Compress the data! |
|
zlib_result = Z_compressZ_iiiii(buffer2, compressedSizeBuffer, buffer, size); |
|
assert(zlib_result == 0); // no error |
|
u32 compressedSize = read_u32(compressedSizeBuffer); |
|
printf("compressed size: %u\n", compressedSize); |
|
|
|
// decompress() also has an in-out param. |
|
u32 decompressedSizeBuffer = Z_mallocZ_ii(4); |
|
write_u32(decompressedSizeBuffer, size); |
|
|
|
// Allocate a buffer for the decompressed data and decompress it! |
|
u32 buffer3 = Z_mallocZ_ii(size); |
|
zlib_result = Z_uncompressZ_iiiii(buffer3, decompressedSizeBuffer, buffer2, compressedSize); |
|
assert(zlib_result == 0); // no error |
|
u32 decompressedSize = read_u32(decompressedSizeBuffer); |
|
printf("decompressed size: %u\n", decompressedSize); |
|
|
|
// Verify the expected size and that the decompressed data is identical to |
|
// what we compressed (which in turn is the same as the original data outside |
|
// the sandbox). |
|
assert(decompressedSize == size); |
|
if (memcmp(wasm_addr_to_absolute(buffer), wasm_addr_to_absolute(buffer3), size) != 0) { |
|
puts("incorrect output!"); |
|
abort(); |
|
} |
|
if (memcmp(externalBuffer, wasm_addr_to_absolute(buffer3), size) != 0) { |
|
puts("incorrect output!"); |
|
abort(); |
|
} |
|
puts("output looks good!"); |
|
} |