#include "save_layout.h" #include enum { LIMIT = 1024 * 1024, NODES = 4096, DEPTH = 64 }; typedef struct { const uint8_t *bytes; size_t length, cursor, needed; unsigned nodes; int status; } Reader; static void fail(Reader *r, int status) { if (!r->status) r->status = status; } static const uint8_t *take(Reader *r, size_t size) { if (r->status) return NULL; if (size > LIMIT || r->cursor > LIMIT - size) { fail(r, FACTORIO_SAVE_PREFIX_LIMIT); return NULL; } size_t end = r->cursor + size; if (end > r->length) { r->needed = end; fail(r, FACTORIO_SAVE_SHORT_HEADER); return NULL; } const uint8_t *result = r->bytes + r->cursor; r->cursor = end; return result; } static uint32_t number(Reader *r, unsigned size) { const uint8_t *p = take(r,size); uint32_t result = 0; if (p) for (unsigned i=0;i1) fail(r,FACTORIO_SAVE_UNSUPPORTED); } static void version(Reader *r) { for(unsigned i=0;i<3;++i) compact(r,2); } static void localised(Reader *r, unsigned depth) { if (r->status) return; if (depth>=DEPTH || ++r->nodes>NODES) { fail(r,FACTORIO_SAVE_PREFIX_LIMIT); return; } if (number(r,1)) { string(r); unsigned children = number(r,1); for(unsigned i=0;istatus;++i) localised(r,depth+1); } } static void ending(Reader *r) { localised(r,0); localised(r,0); uint32_t count = compact(r,4); if (count>NODES) { fail(r,FACTORIO_SAVE_PREFIX_LIMIT); return; } for(uint32_t i=0;istatus;++i) localised(r,0); localised(r,0); string(r); } int factorio_save_layout_bytes(const uint8_t *prefix, size_t length, FactorioSaveLayout *out, size_t *needed) { if (!prefix || !out || !needed) return FACTORIO_SAVE_IO; *needed=0; if (length<9) { *needed=9; return FACTORIO_SAVE_SHORT_HEADER; } FactorioMapVersion v; if (factorio_version_parse(prefix,9,&v)) return FACTORIO_SAVE_SHORT_HEADER; if (v.major!=2 || v.minor!=0 || v.patch!=77 || v.build || v.flag) return FACTORIO_SAVE_UNSUPPORTED; Reader r = {.bytes=prefix,.length=length,.cursor=9}; // ScenarioLocation: three compact-length strings. string(&r); string(&r); string(&r); if(number(&r,1)>2) fail(&r,FACTORIO_SAVE_UNSUPPORTED); // Difficulty boolean(&r); boolean(&r); string(&r); for(unsigned i=0;i<4;++i) boolean(&r); version(&r); number(&r,4); boolean(&r); number(&r,4); uint32_t mods=compact(&r,4); if(mods>NODES) fail(&r,FACTORIO_SAVE_PREFIX_LIMIT); for(uint32_t i=0;i