#include "deserialiser_bridge.h" #include "deserialiser_host.h" #include static int range(wasm_rt_memory_t *ram,uint64_t address,uint64_t size) { return size<=ram->size && address<=ram->size-size; } static uint64_t get(const uint8_t *memory,uint64_t at) { uint64_t value;memcpy(&value,memory+at,8);return value; } u32 w2c_deser__host_allocate(struct w2c_deser__host *env,u32 context) { wasm_rt_memory_t *ram=w2c_factorio__deser_memory(env->module); if (!range(ram,context,256) || env->heap.memory!=ram->data || env->heap.memory_size!=ram->size) return 2; uint64_t pointer;int status=factorio_guest_heap_allocate(&env->heap,get(ram->data,context),&pointer); if (status) return status==1 ? 5 : 2; memcpy(ram->data+context,&pointer,8);return 0; } u32 w2c_deser__host_read_or_throw(struct w2c_deser__host *env,u64 source,u64 destination,u64 size) { wasm_rt_memory_t *ram=w2c_factorio__deser_memory(env->module); if (!range(ram,source,16) || !range(ram,destination,size)) return 2; uint64_t stream=get(ram->data,source+8); if (!range(ram,stream,24)) return 2; uint64_t data=get(ram->data,stream),length=get(ram->data,stream+8),cursor=get(ram->data,stream+16); if (!range(ram,data,length)) return 2; if (cursor>length || size>length-cursor) return 1; memmove(ram->data+destination,ram->data+data+cursor,(size_t)size); cursor+=size;memcpy(ram->data+stream+16,&cursor,8);++env->reads;return 0; } u32 w2c_deser__host_zero_memory(struct w2c_deser__host *env,u64 destination,u64 size,u64 ignored) { (void)ignored;wasm_rt_memory_t *ram=w2c_factorio__deser_memory(env->module); if (!range(ram,destination,size)) return 2; /* The selected bzero service may initialize live arena bytes only. */ if (destinationheap.begin || destination>env->heap.cursor || size>env->heap.cursor-destination) return 2; memset(ram->data+destination,0,(size_t)size);++env->zero_calls;return 0; } u32 w2c_deser__host_unsupported(struct w2c_deser__host *env,u64 a,u64 b,u64 c) { (void)a;(void)b;(void)c;++env->unsupported_calls;return 6; } u32 w2c_deser__host_unsupported_delete(struct w2c_deser__host *env,u64 a,u64 b,u64 c) { return w2c_deser__host_unsupported(env,a,b,c); } u32 w2c_deser__host_unsupported_length(struct w2c_deser__host *env,u64 a,u64 b,u64 c) { return w2c_deser__host_unsupported(env,a,b,c); } u32 w2c_deser__host_unsupported_array_length(struct w2c_deser__host *env,u64 a,u64 b,u64 c) { return w2c_deser__host_unsupported(env,a,b,c); } u32 w2c_deser__host_version_error(struct w2c_deser__host *env,u64 a,u64 b,u64 c) { (void)a;(void)b;(void)c;++env->version_errors;return 7; } int factorio_deserialiser_probe(const uint8_t *prefix,size_t length,FactorioDeserialiserProbe *out) { if (!prefix || !out) return 2; if (!wasm_rt_is_initialized()) wasm_rt_init(); w2c_factorio__deser module; struct w2c_deser__host env={.module=&module}; wasm2c_factorio__deser_instantiate(&module,&env); wasm_rt_memory_t *ram=w2c_factorio__deser_memory(&module);uint8_t *memory=ram->data; memset(memory,0xa5,(size_t)ram->size); uint64_t registers[32]={0};registers[0]=4096;registers[1]=512;registers[31]=ram->size-256; uint64_t stream[3]={16384,length<9 ? length:9,0}; memcpy(memory,registers,sizeof(registers));memcpy(memory+512,stream,sizeof(stream)); memcpy(memory+16384,prefix,(size_t)stream[1]); int status=factorio_guest_heap_init(&env.heap,memory,ram->size,131072,196608); if (!status) status=(int)w2c_factorio__deser_run(&module,0,10000); if (!status) { FactorioDeserialiserProbe result={0};uint64_t version=get(memory,4096+24),target=get(memory,4096+40); result.version=(FactorioMapVersion){version>>48,(version>>32)&65535,(version>>16)&65535,version&65535,memory[4096+32]}; result.allocations=env.heap.allocations;result.reads=env.reads; result.heap_bytes=env.heap.cursor-env.heap.begin;result.stream_cursor=get(memory,528); result.owns_target=memory[4096+0x4c6]; if (!range(ram,target,144) || targetenv.heap.cursor-144 || result.allocations!=12 || result.reads!=5 || env.zero_calls!=1 || env.unsupported_calls || result.stream_cursor!=9 || result.owns_target!=1 || memory[4096+16]!=1 || get(memory,0)!=4096) status=8; if (!status) { result.target_capacity=(unsigned)get(memory,target+32); if (result.target_capacity!=64) status=8; else *out=result; } } wasm2c_factorio__deser_free(&module);return status; }