/****** data.c This file contains the functions for loading Data, be they Tiles or otherwise, from text data into TileData/TileSetData/Data structures. Additionally are defined functions for populating TileData into *Tile structures (as would be used from map generation or spawning operations). Finally, and more tertiary, this file also defines functions for loading files into memory. ******/ #include // for file reading #include #include #include // for ULONG_MAX #include // for isdigit #include "data.h" /**** loadDataFromMemory Loads given data from memory into a Data struct, also populating TileSetData and TileData structs. ****/ struct Data *loadDataFromMemory(char *memory, int size) { struct Data *data = malloc(sizeof(struct Data)); data->size = SET_SIZE; data->id = malloc(sizeof(int)*SET_SIZE); data->set = malloc(sizeof(struct TileSetData*)*SET_SIZE); memset(data->set, 0, sizeof(struct TileSetData*)*SET_SIZE); int offset = 0; int depth = 0; // used to manage position! data->set_count = 0; while (offset <= size-1) { // err, size-1? FIXME if (memory[offset] == '{') { depth++; offset++; // skip that bracket if (depth == 1) { // now we get our tileset's id char temp_string[31]; int temp_offset = offset-1; int temp_offset_2 = 0; while (memory[temp_offset] != '\n' && temp_offset > 0) { temp_offset--; } while (memory[temp_offset] != '{') { temp_string[temp_offset_2++] = memory[temp_offset++]; } temp_string[temp_offset_2] = '\0'; int tileset_id = atoi(temp_string); // resize Data if tileset's id is greater than our size if (tileset_id > data->size) { data->size += tileset_id-data->size; //void *ret; data->id = realloc(data->id, sizeof(int)*data->size); data->set = realloc(data->set, sizeof(struct TileSetData*)*data->size); } data->set[tileset_id] = loadTileSetData(tileset_id, memory, &offset, &depth); data->set_count++; } } else if (memory[offset] == '}') { depth--; } offset++; } return data; } int saveDataToFile(struct Data* data, const char *filename) { FILE *output = fopen(filename, "w"); if (output == NULL) { return -1; } int chars = 0; int count = 0; while (count < data->size) { int count_2 = 0; if (data->set[count]) { chars += fprintf(output, "%d {\n", count); while (count_2 < data->set[count]->size) { if (data->set[count]->tile[count_2]) { chars += fprintf(output, "%d {\n", count_2); struct Table *table = data->set[count]->tile[count_2]->table; int i = 0; while (i < table->size) { struct TablePair *table_pair = table->pair[i]; while (table_pair != NULL) { if (table_pair->type == T_STRING) { chars += fprintf(output, "%s %s\n", table_pair->key, table_pair->value); } else if (table_pair->type == T_INT) { chars += fprintf(output, "%s %d\n", table_pair->key, *(int*)table_pair->value); } else if (table_pair->type == T_FLOAT) { chars += fprintf(output, "%s %f\n", table_pair->key, *(float*)table_pair->value); } else if (table_pair->type == T_PROTO_INVENTORY) { chars += fprintf(output, "%s {\n", table_pair->key); struct InventoryData* inv = table_pair->value; while (inv != NULL) { chars += fprintf(output, "%s, %d-%d, %f\n", inv->name, inv->count.min, inv->count.max, inv->chance); inv = inv->next; } chars += fprintf(output, "}\n"); } table_pair = table_pair->next; } i++; } chars += fprintf(output, "}\n"); } count_2++; } chars += fprintf(output, "}\n"); } count++; } fclose(output); return chars; } struct TileSetData *loadTileSetData(int tileset_id, char *memory, int *offset, int *depth) { struct TileSetData *set_data = malloc(sizeof(struct TileSetData)); set_data->tid = tileset_id; set_data->tile_count = 0; set_data->size = SET_SIZE; // default of 32 set_data->keys = newTable(set_data->size); set_data->tile = malloc(sizeof(struct TileData*)*SET_SIZE); // just so we're not working with undeclared vars int i = 0; while (i < SET_SIZE) { set_data->tile[i++] = NULL; } /* populate Tiles! */ while (*depth != 0) { if (memory[*offset] == '{') { *offset = *offset + 1; //skip the bracket *depth = *depth + 1; if (*depth == 2) { // now we get our tileset's id char temp_string[31]; int temp_offset = *offset-1; int temp_offset_2 = 0; while (memory[temp_offset] != '\n' && temp_offset > 0) { temp_offset--; } while (memory[temp_offset] != '{') { temp_string[temp_offset_2++] = memory[temp_offset++]; } temp_string[temp_offset_2] = '\0'; int tile_id = atoi(temp_string); // resize Data if tileset's id is greater than our size if (tile_id > set_data->size) { set_data->size += tile_id-set_data->size; //void *ret; set_data->tile = realloc(set_data->tile, sizeof(struct TileData*)*set_data->size); } // if tile entry already exists, free old one and load in new one if (set_data->tile[tile_id] != NULL) { // FIXME: must free data for overwrite freeTileData(set_data->tile[tile_id]); } else { set_data->tile_count++; } set_data->tile[tile_id] = loadTileData(tile_id, memory, offset, depth); set_data->tile[tile_id]->tid = tileset_id; // store the tileset id in tile as well // now let's //printf("--> key->id: (%s)%d=>%d\n", getTablePairValue(set_data->tile[tile_id]->table, "name"), getTableIndex(set_data->keys, getTablePairValue(set_data->tile[tile_id]->table, "name")), tile_id); addTablePair(set_data->keys, getTablePairValue(set_data->tile[tile_id]->table, "name"), &tile_id, sizeof(int), T_INT); //printf("<-- key->id: (%s)%d=>%d\n", getTablePairValue(set_data->tile[tile_id]->table, "name"), getTableIndex(set_data->keys, getTablePairValue(set_data->tile[tile_id]->table, "name")), *(int*)getTablePairValue(set_data->keys, getTablePairValue(set_data->tile[tile_id]->table, "name"))); } } else if (memory[*offset] == '}') { *depth = *depth - 1; } *offset = *offset + 1; } return set_data; } /**** loadTileData This function is the third step in the linear processing of a data file - it takes an offset and begins processing at that memory until the depth is less than or equal to 1. What it actually does is convert all lines into key=>value pairs (using a Table and TablePairs), with the key delimited from the value by the first occurance of a space character after a non-space character has occurred. ex: " name my name" = name=>"my name" From that point forward, properties can be retrieved from the TileData's Table by using the various getTable* functions. ****/ struct TileData *loadTileData(int id, char *memory, int *offset, int *depth) { struct TileData *tile_data = newTileData(8); tile_data->id = id; char var_name[32]; // max 32 chars for var name char var_value[256]; // max 256 chars for value int i = 0; short mode = 0; short value_mode = 0; while(*depth > 1) { switch (memory[*offset]) { case '{': *depth = *depth + 1; if (*depth == 3) { *offset = *offset + 2; // skip that bracket and newline // let's get the name for the inventory char temp_string[31]; int temp_offset = *offset-2; int temp_offset_2 = 0; while (memory[temp_offset] != '\n' && temp_offset > 0) { temp_offset--; } temp_offset++; while (memory[temp_offset] != ' ') { temp_string[temp_offset_2++] = memory[temp_offset++]; } temp_string[temp_offset_2] = '\0'; struct InventoryData *inv = loadInventoryData(memory, offset, depth); addTablePairPointer(tile_data->table, temp_string, inv, T_PROTO_INVENTORY); mode = 0; } break; case '}': *depth = *depth - 1; break; case ' ': if (mode == 1) { var_name[i] = '\0'; i = 0; mode = 2; } else if (mode == 2) { var_value[i++] = memory[*offset]; } break; case '\n': var_value[i] = '\0'; if (mode == 2) { if (*depth == 2) { if (value_mode == T_CHAR) { addTablePair(tile_data->table, var_name, var_value, strlen(var_value)+1, T_STRING); printf("%s(%d)=>%s(string)\n", var_name, getTableIndex(tile_data->table, var_name), (char*)getTablePair(tile_data->table, var_name)->value); } else if (value_mode == T_FLOAT) { float val = atof(var_value); addTablePair(tile_data->table, var_name, &val, sizeof(float*), T_FLOAT); printf("%s(%d)=>%f(float)\n", var_name, getTableIndex(tile_data->table, var_name), *(float*)getTablePair(tile_data->table, var_name)->value); } else { int val = atoi(var_value); addTablePair(tile_data->table, var_name, &val, sizeof(int*), T_INT); printf("%s(%d)=>%d(int)\n", var_name, getTableIndex(tile_data->table, var_name), *(int*)getTablePair(tile_data->table, var_name)->value); } } } i = 0; mode = 0; value_mode = 0; break; default: if (mode == 1) { var_name[i++] = memory[*offset]; } else if (mode == 2) { var_value[i++] = memory[*offset]; if (isdigit(memory[*offset]) == 0) { // not exactly fail safe if (memory[*offset] == '.' && value_mode != T_CHAR) { value_mode = T_FLOAT; } else { value_mode = T_CHAR; } } } else if (mode == 0) { mode = 1; var_name[i++] = memory[*offset]; } break; } if (*depth <= 1) break; *offset = *offset + 1; } return tile_data; } struct TileData *newTileData(int size) { struct TileData *tile_data = malloc(sizeof(struct TileData)); tile_data->id = 0; tile_data->count = 0; tile_data->size = size; tile_data->table = newTable(size); return tile_data; } struct InventoryData *newInventoryData() { struct InventoryData *inventory_data = malloc(sizeof(struct InventoryData)); inventory_data->tid = 0; inventory_data->id = 0; inventory_data->count.min = 1; inventory_data->count.max = 1; inventory_data->chance = 100.0f; inventory_data->name = malloc(6); memcpy(inventory_data->name, "undef", 6); inventory_data->next = NULL; return inventory_data; } void setInventoryDataName(struct InventoryData *inventory, const char *name) { int length = strlen(name)+1; inventory->name = realloc(inventory->name, length); memcpy(inventory->name, name, length); } void freeInventoryData(struct InventoryData *inventory_data) { struct InventoryData *current_data = inventory_data; while (current_data != NULL) { struct InventoryData *next_data = current_data->next; free(current_data->name); free(current_data); current_data = next_data; } } struct InventoryData *loadInventoryData(char *memory, int *offset, int *depth) { struct InventoryData *inventory_data = newInventoryData(); struct InventoryData *first_data = inventory_data; struct InventoryData *last_data = NULL; // mode, 0 = name, 1 = count, 2 = chance char temp_string[64]; int temp_i = 0; int mode = 0; while (*depth > 2) { switch(memory[*offset]) { case '{': *depth = *depth +1; break; case '}': *depth = *depth - 1; break; case ' ': if (mode == 0) temp_string[temp_i++] = memory[*offset]; break; case '\n': temp_string[temp_i] = '\0'; if (mode == 0) { inventory_data->name = realloc(inventory_data->name, temp_i+1); memcpy(inventory_data->name, temp_string, temp_i+1); } else if (mode == 1) { char chance_buffer[64]; int ch_buffer_i = 0; int temp_offset = 0; int c_mode = 0; while (temp_offset != temp_i) { switch(temp_string[temp_offset]) { case '-': chance_buffer[ch_buffer_i] = '\0'; inventory_data->count.min = atoi(chance_buffer); c_mode = 1; ch_buffer_i = 0; break; default: chance_buffer[ch_buffer_i++] = temp_string[temp_offset]; break; } temp_offset++; } chance_buffer[ch_buffer_i] = '\0'; if (c_mode == 0) inventory_data->count.min = atoi(chance_buffer); inventory_data->count.max = atoi(chance_buffer); } else if (mode == 2) { inventory_data->chance = atof(temp_string); } temp_i = 0; mode = 0; if (last_data != NULL) last_data->next = inventory_data; last_data = inventory_data; inventory_data = newInventoryData(); break; case ',': temp_string[temp_i] = '\0'; if (mode == 0) { inventory_data->name = realloc(inventory_data->name, temp_i+1); memcpy(inventory_data->name, temp_string, temp_i+1); } else if (mode == 1) { char chance_buffer[64]; int ch_buffer_i = 0; int temp_offset = 0; int c_mode = 0; while (temp_offset != temp_i) { switch(temp_string[temp_offset]) { case '-': chance_buffer[ch_buffer_i] = '\0'; inventory_data->count.min = atoi(chance_buffer); c_mode = 1; ch_buffer_i = 0; break; default: chance_buffer[ch_buffer_i++] = temp_string[temp_offset]; break; } temp_offset++; } chance_buffer[ch_buffer_i] = '\0'; if (c_mode == 0) inventory_data->count.min = atoi(chance_buffer); inventory_data->count.max = atoi(chance_buffer); } else if (mode == 2) { inventory_data->chance = atof(temp_string); } temp_i = 0; mode++; break; default: temp_string[temp_i++] = memory[*offset]; break; } *offset = *offset + 1; } return first_data; } struct TileSetData *getTileSetData(struct Data *data, int tileset_id) { if (tileset_id > data->size) { return NULL; } if (data->set[tileset_id] != NULL) { return data->set[tileset_id]; } return NULL; } /*struct TileData *getTileDataByKey(struct TileSetData *set, char *key) { int *tid = getTablePairValue(data->set[data_set]->keys, key); if (tid != NULL) { return data->set[data_set]->tile[*tid]; } return NULL; }*/ void freeTileData(struct TileData *tile_data) { freeTable(tile_data->table); free(tile_data); } struct Table *newTable(int size) { struct Table *table = malloc(sizeof(struct Table)); table->size = size; table->pair = malloc(sizeof(struct TablePair*)*size); int i = 0; while (i != size) { table->pair[i++] = NULL; } //memset(table->pair, sizeof(struct TablePair*)*size, NULL); return table; } void freeTable(struct Table *table) { int i = 0; while (i < table->size) { if (table->pair[i] != NULL) { freeTablePair(table->pair[i]); } i++; } free(table->pair); free(table); } int getTableIndex(struct Table *table, const char *key) { if (key == NULL) return -1; int i = 0; int index = 0; int key_length = strlen(key); while (index < INT_MAX && i < key_length) { index += key[i++]; } return index % table->size; } struct TileData *getTileDataByKey(struct Data *data, char *key) { int data_set = 0; while (data_set < data->size) { if (data->set[data_set] != NULL) { int *tid = getTablePairValue(data->set[data_set]->keys, key); if (tid != NULL) { return data->set[data_set]->tile[*tid]; } } data_set++; } return NULL; } struct TileData *getTileDataById(struct Data *data, int tileset_id, int tile_id) { if (tile_id >= data->size) { return NULL; } if (data->set[tileset_id] != NULL) { if (data->set[tileset_id]->tile[tile_id] != NULL) { return data->set[tileset_id]->tile[tile_id]; } } return NULL; } struct TablePair *getTablePair(struct Table *table, const char *key) { if (table == NULL) return NULL; struct TablePair *pair = table->pair[getTableIndex(table, key)]; while (pair != NULL) { if (strcmp(key, pair->key) == 0) { return pair; } pair = pair->next; } return NULL; } /*int deleteTablePair(struct Table *table, char *key) { int index = getTableIndex(table, key); struct TablePair *pair = table->pair[index]; if (strcmp(key, pair->key) == 0) { table->pair[index] = pair->next; freeTablePair(pair); return 0; } struct TablePair *previous = NULL; pair = pair->next; // not yet found, let's go down the chain while (pair != NULL) { if (strcmp(key, pair->key) == 0) { // found it, now let's free and repair the Table previous->next = pair->next; freeTablePair(pair); return 0; } previous = pair; pair = pair->next; } return -1; // if we reach here, that means it didn't exist }*/ /**** getTablePairValue Attempts to return the TablePair value of given key. If the TablePair's type is of T_INT, T_FLOAT, or other such values, the ****/ void *getTablePairValue(struct Table *table, const char *key) { struct TablePair *pair = getTablePair(table, key); if (pair != NULL) { return pair->value; } return NULL; } int addTablePair(struct Table *table, const char *key, void *value, int value_size, int type) { if (key == NULL || value == NULL) return -10; int index = getTableIndex(table, key); if (table->pair[index] == NULL) { struct TablePair *table_pair = malloc(sizeof(struct TablePair)); if (table_pair == NULL) return -1; table_pair->next = NULL; setTablePair(table_pair, key, value, value_size, type); table->pair[index] = table_pair; table->count++; } else { struct TablePair *current_pair = table->pair[index]; while (1) { if (strcmp(key, current_pair->key) == 0) { current_pair->value = value; break; } else { if (current_pair->next == NULL) { struct TablePair *table_pair = malloc(sizeof(struct TablePair)); if (table_pair == NULL) return -2; table_pair->next = NULL; setTablePair(table_pair, key, value, value_size, type); current_pair->next = table_pair; table->count++; break; } else { current_pair = current_pair->next; } } } } return 0; } int deleteTablePair(struct Table *table, char *key) { if (key == NULL) return -10; int index = getTableIndex(table, key); if (table->pair[index] == NULL) { // does not exist return -1; } else { struct TablePair *current_pair = table->pair[index]; struct TablePair *last_pair = NULL; while (1) { if (strcmp(key, current_pair->key) == 0) { // we have a match, so let's repair the chain if needed if (current_pair->next != NULL) { last_pair->next = current_pair->next; } freeTablePair(current_pair); table->count--; break; } else { if (current_pair->next == NULL) { // does not exist return -1; } else { last_pair = current_pair; current_pair = current_pair->next; } } } } return 0; } int addTablePairPointer(struct Table *table, const char *key, void *value, int type) { if (key == NULL || value == NULL) return -10; int index = getTableIndex(table, key); if (table->pair[index] == NULL) { struct TablePair *table_pair = malloc(sizeof(struct TablePair)); if (table_pair == NULL) return -1; setTablePairPointer(table_pair, key, value, type); table->pair[index] = table_pair; table->count++; } else { struct TablePair *current_pair = table->pair[index]; while (1) { if (strcmp(key, current_pair->key) == 0) { current_pair->value = value; break; } else { if (current_pair->next == NULL) { struct TablePair *table_pair = malloc(sizeof(struct TablePair)); if (table_pair == NULL) return -2; setTablePairPointer(table_pair, key, value, type); current_pair->next = table_pair; table->count++; break; } else { current_pair = current_pair->next; } } } } return 0; } void setTablePair(struct TablePair *table_pair, const char *key, void *value, int value_size, int type) { int key_size = strlen(key)+1; table_pair->key = malloc(key_size); memcpy(table_pair->key, key, key_size); table_pair->value = malloc(value_size); memcpy(table_pair->value, value, value_size); table_pair->type = type; table_pair->next = NULL; } void setTablePairPointer(struct TablePair *table_pair, const char *key, void *value, int type) { int key_size = strlen(key)+1; table_pair->key = malloc(key_size); memcpy(table_pair->key, key, key_size); table_pair->value = value; table_pair->type = type; table_pair->next = NULL; } void freeTablePair(struct TablePair *table_pair) { struct TablePair *pair = table_pair; while (pair != NULL) { struct TablePair *sub_pair = pair->next; free(pair->key); switch (pair->type) { case T_PROTO_INVENTORY: freeInventoryData(pair->value); break; default: free(pair->value); break; } free(pair); pair = sub_pair; } } /**** fileToMemory This function takes a pointer to an uninitialized char array, along with a char array for a file name. It then attempts to read the provided file into the passed buffer, returning the size on completion. ****/ int fileToMemory(char **buffer, const char *file_name) { int i, n, pos = 0; char t_buf[16]; FILE *file = fopen(file_name, "r"); if (file == NULL) { return -1; } fseek(file, 0, SEEK_END); int size = ftell(file); fseek(file, 0, SEEK_SET); char *new_buffer = malloc(size); while ((n = fread(t_buf, 1, 16, file))) { for (i = 0; i < n; i++) { new_buffer[pos++] = t_buf[i]; } } fclose(file); *buffer = new_buffer; return size; }