qc_program_t* prog_load(const char *filename, bool skipversion) { prog_header_t header; qc_program_t *prog; FILE *file = fopen(filename, "rb"); /* we need all those in order to support INSTR_STATE: */ bool has_self = false, has_time = false, has_think = false, has_nextthink = false, has_frame = false; if (!file) return nullptr; if (fread(&header, sizeof(header), 1, file) != 1) { loaderror("failed to read header from '%s'", filename); fclose(file); return nullptr; } util_swap_header(header); if (!skipversion && header.version != 6) { loaderror("header says this is a version %i progs, we need version 6\n", header.version); fclose(file); return nullptr; } prog = (qc_program_t*)mem_a(sizeof(qc_program_t)); if (!prog) { fclose(file); fprintf(stderr, "failed to allocate program data\n"); return nullptr; } memset(prog, 0, sizeof(*prog)); prog->entityfields = header.entfield; prog->crc16 = header.crc16; prog->filename = util_strdup(filename); if (!prog->filename) { loaderror("failed to store program name"); goto error; } #define read_data(hdrvar, progvar, reserved) \ if (fseek(file, header.hdrvar.offset, SEEK_SET) != 0) { \ loaderror("seek failed"); \ goto error; \ } \ prog->progvar.resize(header.hdrvar.length + reserved); \ if (fread( \ &prog->progvar[0], \ sizeof(prog->progvar[0]), \ header.hdrvar.length, \ file \ )!= header.hdrvar.length \ ) { \ loaderror("read failed"); \ goto error; \ } #define read_data1(x) read_data(x, x, 0) #define read_data2(x, y) read_data(x, x, y) read_data (statements, code, 0); read_data1(defs); read_data1(fields); read_data1(functions); read_data1(strings); read_data2(globals, 2); /* reserve more in case a RETURN using with the global at "the end" exists */ util_swap_statements(prog->code); util_swap_defs_fields(prog->defs); util_swap_defs_fields(prog->fields); util_swap_functions(prog->functions); util_swap_globals(prog->globals); fclose(file); /* profile counters */ memset(vec_add(prog->profile, prog->code.size()), 0, sizeof(prog->profile[0]) * prog->code.size()); /* Add tempstring area */ prog->tempstring_start = prog->strings.size(); prog->tempstring_at = prog->strings.size(); prog->strings.resize(prog->strings.size() + 16*1024, '\0'); /* spawn the world entity */ vec_push(prog->entitypool, true); memset(vec_add(prog->entitydata, prog->entityfields), 0, prog->entityfields * sizeof(prog->entitydata[0])); prog->entities = 1; /* cache some globals and fields from names */ for (auto &it : prog->defs) { const char *name = prog_getstring(prog, it.name); if (!strcmp(name, "self")) { prog->cached_globals.self = it.offset; has_self = true; } else if (!strcmp(name, "time")) { prog->cached_globals.time = it.offset; has_time = true; } } for (auto &it : prog->fields) { const char *name = prog_getstring(prog, it.name); if (!strcmp(name, "think")) { prog->cached_fields.think = it.offset; has_think = true; } else if (!strcmp(name, "nextthink")) { prog->cached_fields.nextthink = it.offset; has_nextthink = true; } else if (!strcmp(name, "frame")) { prog->cached_fields.frame = it.offset; has_frame = true; } } if (has_self && has_time && has_think && has_nextthink && has_frame) prog->supports_state = true; return prog; error: if (prog->filename) mem_d(prog->filename); vec_free(prog->entitydata); vec_free(prog->entitypool); mem_d(prog); fclose(file); return nullptr; }
qc_program* prog_load(const char *filename) { qc_program *prog; prog_header header; FILE *file; file = util_fopen(filename, "rb"); if (!file) return NULL; if (fread(&header, sizeof(header), 1, file) != 1) { loaderror("failed to read header from '%s'", filename); fclose(file); return NULL; } if (header.version != 6) { loaderror("header says this is a version %i progs, we need version 6\n", header.version); fclose(file); return NULL; } prog = (qc_program*)mem_a(sizeof(qc_program)); if (!prog) { fclose(file); printf("failed to allocate program data\n"); return NULL; } memset(prog, 0, sizeof(*prog)); prog->entityfields = header.entfield; prog->crc16 = header.crc16; prog->filename = util_strdup(filename); if (!prog->filename) { loaderror("failed to store program name"); goto error; } #define read_data(hdrvar, progvar, reserved) \ if (fseek(file, header.hdrvar.offset, SEEK_SET) != 0) { \ loaderror("seek failed"); \ goto error; \ } \ if (fread(vec_add(prog->progvar, header.hdrvar.length + reserved), \ sizeof(*prog->progvar), \ header.hdrvar.length, file) \ != header.hdrvar.length) \ { \ loaderror("read failed"); \ goto error; \ } #define read_data1(x) read_data(x, x, 0) #define read_data2(x, y) read_data(x, x, y) read_data (statements, code, 0); read_data1(defs); read_data1(fields); read_data1(functions); read_data1(strings); read_data2(globals, 2); /* reserve more in case a RETURN using with the global at "the end" exists */ fclose(file); /* profile counters */ memset(vec_add(prog->profile, vec_size(prog->code)), 0, sizeof(prog->profile[0]) * vec_size(prog->code)); /* Add tempstring area */ prog->tempstring_start = vec_size(prog->strings); prog->tempstring_at = vec_size(prog->strings); memset(vec_add(prog->strings, 16*1024), 0, 16*1024); /* spawn the world entity */ vec_push(prog->entitypool, true); memset(vec_add(prog->entitydata, prog->entityfields), 0, prog->entityfields * sizeof(prog->entitydata[0])); prog->entities = 1; return prog; error: if (prog->filename) mem_d(prog->filename); vec_free(prog->code); vec_free(prog->defs); vec_free(prog->fields); vec_free(prog->functions); vec_free(prog->strings); vec_free(prog->globals); vec_free(prog->entitydata); vec_free(prog->entitypool); mem_d(prog); return NULL; }