Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}