Esempio n. 1
0
/*
 * EXPOSED INTERFACE for the hashtable implementation
 * util_htnew(size)                             -- to make a new hashtable
 * util_htset(table, key, value, sizeof(value)) -- to set something in the table
 * util_htget(table, key)                       -- to get something from the table
 * util_htdel(table)                            -- to delete the table
 */
hash_table_t *util_htnew(size_t size) {
    hash_table_t      *hashtable = NULL;
    stat_size_entry_t *find      = NULL;

    if (size < 1)
        return NULL;

    if (!stat_size_hashtables)
        stat_size_hashtables = stat_size_new();

    if (!(hashtable = (hash_table_t*)mem_a(sizeof(hash_table_t))))
        return NULL;

    if (!(hashtable->table = (hash_node_t**)mem_a(sizeof(hash_node_t*) * size))) {
        mem_d(hashtable);
        return NULL;
    }

    if ((find = stat_size_get(stat_size_hashtables, size)))
        find->value++;
    else {
        stat_type_hashtables++;
        stat_size_put(stat_size_hashtables, size, 1);
    }

    hashtable->size = size;
    memset(hashtable->table, 0, sizeof(hash_node_t*) * size);

    stat_used_hashtables++;
    return hashtable;
}
Esempio n. 2
0
/*
 * The following functions below implement printing / dumping of statistical
 * information.
 */
static void stat_dump_mem_contents(stat_mem_block_t *block, uint16_t cols) {
    unsigned char *buffer = (unsigned char *)mem_a(cols);
    unsigned char *memory = (unsigned char *)(block + 1);
    size_t         i;

    for (i = 0; i < block->size; i++) {
        if (!(i % 16)) {
            if (i != 0)
                con_out(" %s\n", buffer);
            con_out(" 0x%08X: ", i);
        }

        con_out(" %02X", memory[i]);

        buffer[i % cols] = ((memory[i] < 0x20) || (memory[i] > 0x7E))
                            ? '.'
                            : memory[i];

        buffer[(i % cols) + 1] = '\0';
    }

    while ((i % cols) != 0) {
        con_out("   ");
        i++;
    }

    con_out(" %s\n", buffer);
    mem_d(buffer);
}
Esempio n. 3
0
/*
 * The reallocate function for resizing vectors.
 */
void _util_vec_grow(void **a, size_t i, size_t s) {
    vector_t          *d = vec_meta(*a);
    size_t             m = 0;
    stat_size_entry_t *e = NULL;
    void              *p = NULL;

    if (*a) {
        m = 2 * d->allocated + i;
        p = mem_r(d, s * m + sizeof(vector_t));
    } else {
        m = i + 1;
        p = mem_a(s * m + sizeof(vector_t));
        ((vector_t*)p)->used = 0;
        stat_used_vectors++;
    }

    if (!stat_size_vectors)
        stat_size_vectors = stat_size_new();

    if ((e = stat_size_get(stat_size_vectors, s))) {
        e->value ++;
    } else {
        stat_size_put(stat_size_vectors, s, 1); /* start off with 1 */
        stat_type_vectors++;
    }

    *a = (vector_t*)p + 1;
    vec_meta(*a)->allocated = m;
}
Esempio n. 4
0
/*
 * The reallocate function for resizing vectors.
 */
void _util_vec_grow(void **a, size_t i, size_t s) {
    vector_t          *d = (vector_t*)((char *)*a - IDENT_VEC_TOP);
    size_t             m = 0;
    stat_size_entry_t *e = NULL;
    void              *p = NULL;

    if (*a) {
        m = 2 * d->allocated + i;
        p = mem_r(d, s * m + IDENT_VEC_TOP);
    } else {
        m = i + 1;
        p = mem_a(s * m + IDENT_VEC_TOP);
        ((vector_t*)p)->used = 0;
        stat_used_vectors++;
    }

    if (!stat_size_vectors)
        stat_size_vectors = stat_size_new();

    if ((e = stat_size_get(stat_size_vectors, s))) {
        e->value ++;
    } else {
        stat_size_put(stat_size_vectors, s, 1); /* start off with 1 */
        stat_type_vectors++;
    }

    d = (vector_t*)p;
    d->allocated = m;
    memcpy(d + 1, IDENT_VEC, IDENT_SIZE);
    *a = (void *)((char *)d + IDENT_VEC_TOP);
}
Esempio n. 5
0
int platform_vasprintf(char **dat, const char *fmt, va_list args) {
    int     ret;
    int     len;
    char   *tmp = NULL;
    char    buf[128];
    va_list cpy;

    va_copy(cpy, args);
    len = vsnprintf(buf, sizeof(buf), fmt, cpy);
    va_end (cpy);

    if (len < (int)sizeof(buf)) {
        *dat = util_strdup(buf);
        return len;
    }

    tmp = (char*)mem_a(len + 1);
    if ((ret = vsnprintf(tmp, len + 1, fmt, args)) != len) {
        mem_d(tmp);
        *dat = NULL;
        return -1;
    }

    *dat = tmp;
    return len;
}
Esempio n. 6
0
code_t *code_init() {
    static lex_ctx_t                empty_ctx       = {0, 0, 0};
    static prog_section_function_t  empty_function  = {0,0,0,0,0,0,0,{0,0,0,0,0,0,0,0}};
    static prog_section_statement_t empty_statement = {0,{0},{0},{0}};
    static prog_section_def_t       empty_def       = {0, 0, 0};

    code_t *code       = (code_t*)mem_a(sizeof(code_t));
    int     i          = 0;

    memset(code, 0, sizeof(code_t));
    code->entfields    = 0;
    code->string_cache = util_htnew(OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS) ? 0x100 : 1024);

    /*
     * The way progs.dat is suppose to work is odd, there needs to be
     * some null (empty) statements, functions, and 28 globals
     */
    for(; i < 28; i++)
        vec_push(code->globals, 0);

    vec_push(code->chars, '\0');
    vec_push(code->functions,  empty_function);

    code_push_statement(code, &empty_statement, empty_ctx);

    vec_push(code->defs,    empty_def);
    vec_push(code->fields,  empty_def);

    return code;
}
Esempio n. 7
0
static void stat_size_put(stat_size_table_t table, size_t key, size_t value) {
    size_t hash = (key % ST_SIZE);
    while (table[hash] && table[hash]->key != key)
        hash = (hash + 1) % ST_SIZE;
    table[hash]        = (stat_size_entry_t*)mem_a(sizeof(stat_size_entry_t));
    table[hash]->key   = key;
    table[hash]->value = value;
}
Esempio n. 8
0
static pak_file_t *pak_open_read(const char *file) {
    pak_file_t *pak;
    size_t      itr;

    if (!(pak = (pak_file_t*)mem_a(sizeof(pak_file_t))))
        return NULL;

    if (!(pak->handle = fs_file_open(file, "rb"))) {
        mem_d(pak);
        return NULL;
    }

    pak->directories = NULL;
    pak->insert      = false; /* read doesn't allow insert */

    memset         (&pak->header, 0, sizeof(pak_header_t));
    fs_file_read   (&pak->header,    sizeof(pak_header_t), 1, pak->handle);

    util_endianswap(&pak->header.magic,  1, sizeof(pak->header.magic));
    util_endianswap(&pak->header.diroff, 1, sizeof(pak->header.diroff));
    util_endianswap(&pak->header.dirlen, 1, sizeof(pak->header.dirlen));

    /*
     * Every PAK file has "PACK" stored as FOURCC data in the
     * header.  If this data cannot compare (as checked here), it's
     * probably not a PAK file.
     */
    if (pak->header.magic != PAK_FOURCC) {
        fs_file_close(pak->handle);
        mem_d        (pak);
        return NULL;
    }

    /*
     * Time to read in the directory handles and prepare the directories
     * vector.  We're going to be reading some the file inwards soon.
     */
    fs_file_seek(pak->handle, pak->header.diroff, FS_FILE_SEEK_SET);

    /*
     * Read in all directories from the PAK file. These are considered
     * to be the "file entries".
     */
    for (itr = 0; itr < pak->header.dirlen / 64; itr++) {
        pak_directory_t dir;
        fs_file_read   (&dir,    sizeof(pak_directory_t), 1, pak->handle);

        /* Don't translate name - it's just an array of bytes. */
        util_endianswap(&dir.pos, 1, sizeof(dir.pos));
        util_endianswap(&dir.len, 1, sizeof(dir.len));

        vec_push(pak->directories, dir);
    }
    return pak;
}
Esempio n. 9
0
void correct_add(correct_trie_t* table, size_t ***size, const char *ident) {
    size_t     *data = NULL;
    const char *add  = ident;

    if (!correct_update(&table, add)) {
        data  = (size_t*)mem_a(sizeof(size_t));
        *data = 1;

        vec_push((*size), data);
        correct_trie_set(table, add, data);
    }
}
Esempio n. 10
0
static GMQCC_INLINE void correct_trie_set(correct_trie_t *t, const char *key, void * const value) {
    const unsigned char *data = (const unsigned char*)key;
    while (*data) {
        if (!t->entries) {
            t->entries = (correct_trie_t*)mem_a(sizeof(correct_trie_t)*(sizeof(correct_alpha)-1));
            memset(t->entries, 0, sizeof(correct_trie_t)*(sizeof(correct_alpha)-1));
        }
        t = t->entries + correct_alpha_index[*data];
        ++data;
    }
    t->value = value;
}
Esempio n. 11
0
/*
 * Some string utility functions, because strdup uses malloc, and we want
 * to track all memory (without replacing malloc).
 */
char *util_strdup(const char *s) {
    size_t  len = 0;
    char   *ptr = NULL;

    if (!s)
        return NULL;

    if ((len = strlen(s)) && (ptr = mem_a(len+1))) {
        memcpy(ptr, s, len);
        ptr[len] = '\0';
    }
    return ptr;
}
Esempio n. 12
0
/*
 * When given a string like "a/b/c/d/e/file"
 * this function will handle the creation of
 * the directory structure, included nested
 * directories.
 */
static void pak_tree_build(const char *entry) {
    char *directory;
    char *elements[28];
    char *pathsplit;
    char *token;

    size_t itr;
    size_t jtr;

    pathsplit = (char *)mem_a(56);
    directory = (char *)mem_a(56);

    memset(pathsplit, 0, 56);

    util_strncpy(directory, entry, 56);
    for (itr = 0; (token = pak_tree_sep(&directory, "/")) != NULL; itr++) {
        elements[itr] = token;
    }

    for (jtr = 0; jtr < itr - 1; jtr++) {
        util_strcat(pathsplit, elements[jtr]);
        util_strcat(pathsplit, "/");

        if (fs_dir_make(pathsplit)) {
            mem_d(pathsplit);
            mem_d(directory);

            /* TODO: undo on fail */

            return;
        }
    }

    mem_d(pathsplit);
    mem_d(directory);
}
Esempio n. 13
0
static hash_node_t *_util_htnewpair(const char *key, void *value) {
    hash_node_t *node;
    if (!(node = (hash_node_t*)mem_a(sizeof(hash_node_t))))
        return NULL;

    if (!(node->key = util_strdupe(key))) {
        mem_d(node);
        return NULL;
    }

    node->value = value;
    node->next  = NULL;

    return node;
}
Esempio n. 14
0
/*
 * Extraction abilities.  These work as you expect them to.
 */
static bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdir) {
    pak_directory_t *dir   = NULL;
    unsigned char   *dat   = NULL;
    char            *local = NULL;
    FILE            *out   = NULL;

    if (!pak_exists(pak, file, &dir)) {
        return false;
    }

    if (!(dat = (unsigned char *)mem_a(dir->len)))
        goto err;

    /*
     * Generate the directory structure / tree that will be required
     * to store the extracted file.
     */
    pak_tree_build(file);

    /* TODO portable path seperators */
    util_asprintf(&local, "%s/%s", outdir, file);

    /*
     * Now create the file, if this operation fails.  Then abort
     * It shouldn't fail though.
     */
    if (!(out = fs_file_open(local, "wb")))
        goto err;

    /* free memory for directory string */
    mem_d(local);

    /* read */
    if (fs_file_seek (pak->handle, dir->pos, SEEK_SET) != 0)
        goto err;

    fs_file_read (dat, 1, dir->len, pak->handle);
    fs_file_write(dat, 1, dir->len, out);
    fs_file_close(out);

    mem_d(dat);
    return true;

err:
    if (dat) mem_d(dat);
    if (out) fs_file_close(out);
    return false;
}
Esempio n. 15
0
static pak_file_t *pak_open_write(const char *file) {
    pak_file_t *pak;

    if (!(pak = (pak_file_t*)mem_a(sizeof(pak_file_t))))
        return NULL;

    /*
     * Generate the required directory structure / tree for
     * writing this PAK file too.
     */
    pak_tree_build(file);

    if (!(pak->handle = fs_file_open(file, "wb"))) {
        /*
         * The directory tree that was created, needs to be
         * removed entierly if we failed to open a file.
         */
        /* TODO backup directory clean */

        mem_d(pak);
        return NULL;
    }

    memset(&(pak->header), 0, sizeof(pak_header_t));

    /*
     * We're in "insert" mode, we need to do things like header
     * "patching" and writing the directories at the end of the
     * file.
     */
    pak->insert       = true;
    pak->header.magic = PAK_FOURCC;

    /* on BE systems we need to swap the byte order of the FOURCC */
    util_endianswap(&pak->header.magic, 1, sizeof(uint32_t));

    /*
     * We need to write out the header since files will be wrote out to
     * this even with directory entries, and that not wrote.  The header
     * will need to be patched in later with a file_seek, and overwrite,
     * we could use offsets and other trickery.  This is just easier.
     */
    fs_file_write(&(pak->header), sizeof(pak_header_t), 1, pak->handle);

    return pak;
}
Esempio n. 16
0
/*
 * Implements libc getline for systems that don't have it, which is
 * assmed all.  This works the same as getline().
 */
int util_getline(char **lineptr, size_t *n, FILE *stream) {
    int   chr;
    int   ret;
    char *pos;

    if (!lineptr || !n || !stream)
        return -1;
    if (!*lineptr) {
        if (!(*lineptr = (char*)mem_a((*n=64))))
            return -1;
    }

    chr = *n;
    pos = *lineptr;

    for (;;) {
        int c = getc(stream);

        if (chr < 2) {
            *n += (*n > 16) ? *n : 64;
            chr = *n + *lineptr - pos;
            if (!(*lineptr = (char*)mem_r(*lineptr,*n)))
                return -1;
            pos = *n - chr + *lineptr;
        }

        if (ferror(stream))
            return -1;
        if (c == EOF) {
            if (pos == *lineptr)
                return -1;
            else
                break;
        }

        *pos++ = c;
        chr--;
        if (c == '\n')
            break;
    }
    *pos = '\0';
    return (ret = pos - *lineptr);
}
Esempio n. 17
0
fold_t *fold_init(parser_t *parser) {
    fold_t *fold                 = (fold_t*)mem_a(sizeof(fold_t));
    fold->parser                 = parser;
    fold->imm_float              = NULL;
    fold->imm_vector             = NULL;
    fold->imm_string             = NULL;
    fold->imm_string_untranslate = util_htnew(FOLD_STRING_UNTRANSLATE_HTSIZE);
    fold->imm_string_dotranslate = util_htnew(FOLD_STRING_DOTRANSLATE_HTSIZE);

    /*
     * prime the tables with common constant values at constant
     * locations.
     */
    (void)fold_constgen_float (fold,  0.0f);
    (void)fold_constgen_float (fold,  1.0f);
    (void)fold_constgen_float (fold, -1.0f);
    (void)fold_constgen_float (fold,  2.0f);

    (void)fold_constgen_vector(fold, vec3_create(0.0f, 0.0f, 0.0f));
    (void)fold_constgen_vector(fold, vec3_create(-1.0f, -1.0f, -1.0f));

    return fold;
}
Esempio n. 18
0
static int qc_strcat(qc_program_t *prog) {
    char  *buffer;
    size_t len1,   len2;
    qcany_t *str1,  *str2;
    qcany_t  out;

    const char *cstr1;
    const char *cstr2;

    CheckArgs(2);
    str1 = GetArg(0);
    str2 = GetArg(1);
    cstr1 = prog_getstring(prog, str1->string);
    cstr2 = prog_getstring(prog, str2->string);
    len1 = strlen(cstr1);
    len2 = strlen(cstr2);
    buffer = (char*)mem_a(len1 + len2 + 1);
    memcpy(buffer, cstr1, len1);
    memcpy(buffer+len1, cstr2, len2+1);
    out.string = prog_tempstring(prog, buffer);
    mem_d(buffer);
    Return(out);
    return 0;
}
Esempio n. 19
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;
}
Esempio n. 20
0
/*
 * A tiny size_t key-value hashtbale for tracking vector and hashtable
 * sizes. We can use it for other things too, if we need to. This is
 * very TIGHT, and efficent in terms of space though.
 */
static stat_size_table_t stat_size_new(void) {
    return (stat_size_table_t)memset(
        mem_a(sizeof(stat_size_entry_t*) * ST_SIZE),
        0, ST_SIZE * sizeof(stat_size_entry_t*)
    );
}
Esempio n. 21
0
static GMQCC_INLINE void correct_pool_new(void) {
    correct_pool_addr = 0;
    correct_pool_this = (unsigned char *)mem_a(CORRECT_POOL_SIZE);

    vec_push(correct_pool_data, correct_pool_this);
}
Esempio n. 22
0
static task_template_t *task_template_compile(const char *file, const char *dir, size_t *pad) {
    /* a page should be enough */
    char             fullfile[4096];
    size_t           filepadd = 0;
    fs_file_t       *tempfile = NULL;
    task_template_t *tmpl     = NULL;

    util_snprintf(fullfile,    sizeof(fullfile), "%s/%s", dir, file);

    tempfile = fs_file_open(fullfile, "r");
    tmpl     = (task_template_t*)mem_a(sizeof(task_template_t));
    task_template_nullify(tmpl);

    /*
     * Create some padding for the printing to align the
     * printing of the rules file to the console.
     */
    if ((filepadd = strlen(fullfile)) > pad[1])
        pad[1] = filepadd;

    tmpl->rulesfile = util_strdup(fullfile);

    /*
     * Esnure the file even exists for the task, this is pretty useless
     * to even do.
     */
    if (!tempfile) {
        con_err("template file: %s does not exist or invalid permissions\n",
            file
        );
        goto failure;
    }

    if (!task_template_parse(file, tmpl, tempfile, pad)) {
        con_err("template parse error: error during parsing\n");
        goto failure;
    }

    /*
     * Regardless procedure type, the following tags must exist:
     *  D
     *  T
     *  C
     *  I
     */
    if (!tmpl->description) {
        con_err("template compile error: %s missing `D:` tag\n", file);
        goto failure;
    }
    if (!tmpl->proceduretype) {
        con_err("template compile error: %s missing `T:` tag\n", file);
        goto failure;
    }
    if (!tmpl->compileflags) {
        con_err("template compile error: %s missing `C:` tag\n", file);
        goto failure;
    }
    if (!tmpl->sourcefile) {
        con_err("template compile error: %s missing `I:` tag\n", file);
        goto failure;
    }

    /*
     * Now lets compile the template, compilation is really just
     * the process of validating the input.
     */
    if (!strcmp(tmpl->proceduretype, "-compile")) {
        if (tmpl->executeflags)
            con_err("template compile warning: %s erroneous tag `E:` when only compiling\n", file);
        if (tmpl->comparematch)
            con_err("template compile warning: %s erroneous tag `M:` when only compiling\n", file);
        goto success;
    } else if (!strcmp(tmpl->proceduretype, "-execute")) {
        if (!tmpl->executeflags) {
            /* default to $null */
            tmpl->executeflags = util_strdup("$null");
        }
        if (!tmpl->comparematch) {
            con_err("template compile error: %s missing `M:` tag (use `$null` for exclude)\n", file);
            goto failure;
        }
    } else if (!strcmp(tmpl->proceduretype, "-fail")) {
        if (tmpl->executeflags)
            con_err("template compile warning: %s erroneous tag `E:` when only failing\n", file);
        if (tmpl->comparematch)
            con_err("template compile warning: %s erroneous tag `M:` when only failing\n", file);
    } else if (!strcmp(tmpl->proceduretype, "-diagnostic")) {
        if (tmpl->executeflags)
            con_err("template compile warning: %s erroneous tag `E:` when only diagnostic\n", file);
        if (!tmpl->comparematch) {
            con_err("template compile error: %s missing `M:` tag (use `$null` for exclude)\n", file);
            goto failure;
        }
    } else if (!strcmp(tmpl->proceduretype, "-pp")) {
        if (tmpl->executeflags)
            con_err("template compile warning: %s erroneous tag `E:` when only preprocessing\n", file);
        if (!tmpl->comparematch) {
            con_err("template compile error: %s missing `M:` tag (use `$null` for exclude)\n", file);
            goto failure;
        }
    } else {
        con_err("template compile error: %s invalid procedure type: %s\n", file, tmpl->proceduretype);
        goto failure;
    }

success:
    fs_file_close(tempfile);
    return tmpl;

failure:
    /*
     * The file might not exist and we jump here when that doesn't happen
     * so the check to see if it's not null here is required.
     */
    if (tempfile)
        fs_file_close(tempfile);
    mem_d (tmpl);

    return NULL;
}
Esempio n. 23
0
/*
 * A fast space efficent trie for a dictionary of identifiers.  This is
 * faster than a hashtable for one reason.  A hashtable itself may have
 * fast constant lookup time, but the hash itself must be very fast. We
 * have one of the fastest hash functions for strings, but if you do a
 * lost of hashing (which we do, almost 3 million hashes per identifier)
 * a hashtable becomes slow.
 */
correct_trie_t* correct_trie_new() {
    correct_trie_t *t = (correct_trie_t*)mem_a(sizeof(correct_trie_t));
    t->value   = NULL;
    t->entries = NULL;
    return t;
}
Esempio n. 24
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;
}
Esempio n. 25
0
void *code_t::operator new(std::size_t bytes) {
  return mem_a(bytes);
}
Esempio n. 26
0
/*
 * Insertion functions (the opposite of extraction).  Yes for generating
 * PAKs.
 */
static bool pak_insert_one(pak_file_t *pak, const char *file) {
    pak_directory_t dir;
    unsigned char  *dat;
    long            len;
    FILE           *fp;

    /*
     * We don't allow insertion on files that already exist within the
     * pak file.  Weird shit can happen if we allow that ;). We also
     * don't allow insertion if the pak isn't opened in write mode.
     */
    if (!pak || !file || !pak->insert || pak_exists(pak, file, NULL))
        return false;

    if (!(fp = fs_file_open(file, "rb")))
        return false;

    /*
     * Calculate the total file length, since it will be wrote to
     * the directory entry, and the actual contents of the file
     * to the PAK file itself.
     */
    if (fs_file_seek(fp, 0, SEEK_END) != 0 || ((len = fs_file_tell(fp)) < 0))
        goto err;
    if (fs_file_seek(fp, 0, SEEK_SET) != 0)
        goto err;

    dir.len = len;
    dir.pos = fs_file_tell(pak->handle);

    /*
     * We're limited to 56 bytes for a file name string, that INCLUDES
     * the directory and '/' seperators.
     */
    if (strlen(file) >= 56)
        goto err;

    util_strncpy(dir.name, file, strlen(file));

    /*
     * Allocate some memory for loading in the data that will be
     * redirected into the PAK file.
     */
    if (!(dat = (unsigned char *)mem_a(dir.len)))
        goto err;

    fs_file_read (dat, dir.len, 1, fp);
    fs_file_close(fp);
    fs_file_write(dat, dir.len, 1, pak->handle);

    /*
     * Now add the directory to the directories vector, so pak_close
     * can actually write it.
     */
    vec_push(pak->directories, dir);

    return true;

err:
    fs_file_close(fp);
    return false;
}