/****** 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). ******/ #include #include #include // for ULONG_MAX #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) { 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; ret = realloc(data->id, sizeof(int)*data->size); ret = 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; } 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 (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 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); /* 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; ret = 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 = malloc(sizeof(struct TileData)); tile_data->id = id; tile_data->count = 0; tile_data->size = 8; tile_data->table = newTable(8); 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; while(*depth > 1) { switch (memory[*offset]) { case '{': *depth = *depth + 1; 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) { addTablePair(tile_data->table, var_name, var_value, strlen(var_value)+1, T_STRING); printf("%s(%d)=>%s\n", var_name, getTableIndex(tile_data->table, var_name), (char*)getTablePair(tile_data->table, var_name)->value); } } i = 0; mode = 0; break; default: if (mode == 1) { var_name[i++] = memory[*offset]; } else if (mode == 2) { var_value[i++] = memory[*offset]; } else if (mode == 0) { mode = 1; var_name[i++] = memory[*offset]; } break; } if (*depth <= 1) break; *offset = *offset + 1; } return tile_data; } 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); return table; } void freeTable(struct Table *table) { int i = 0; while (i < table->size) { freeTablePair(table->pair[i++]); } free(table->pair); free(table); } int getTableIndex(struct Table *table, char *key) { if (key == NULL) return NULL; 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 TablePair *getTablePair(struct Table *table, char *key) { struct TablePair *pair = table->pair[getTableIndex(table, key)]; while (pair != NULL) { if (strcmp(key, pair->key) == 0) { return pair; } pair = pair->next; } return NULL; } /**** 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, char *key) { struct TablePair *pair = getTablePair(table, key); if (pair != NULL) { return pair->value; } return NULL; } int addTablePair(struct Table *table, 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; setTablePair(table_pair, key, value, value_size, type); table->pair[index] = table_pair; } 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; setTablePair(table_pair, key, value, value_size, type); current_pair->next = table_pair; break; } else { current_pair = current_pair->next; } } } } return 0; } void setTablePair(struct TablePair *table_pair, 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 freeTablePair(struct TablePair *table_pair) { struct TablePair *pair = table_pair; while (pair != NULL) { struct TablePair *sub_pair = pair->next; free(pair->key); free(pair->value); free(pair); pair = sub_pair; } }