#include #include #include "datafile.h" static const int DEBUG=0; struct item_type { int type; int start; int num; }; struct item { int type_and_id; int size; }; struct datafile_header { int id; int version; int size; int swaplen; int num_item_types; int num_items; int num_raw_data; int item_size; int data_size; }; struct datafile_data { int num_item_types; int num_items; int num_raw_data; int item_size; int data_size; char start[4]; }; struct datafile_info { item_type *item_types; int *item_offsets; int *data_offsets; char *item_start; char *data_start; }; struct datafile { datafile_info info; datafile_data data; }; datafile *datafile_load(const char *filename) { dbg_msg("datafile", "datafile loading. filename='%s'", filename); baselib::file_stream file; if(!file.open_r(filename)) return 0; // TODO: change this header unsigned char header[16]; file.read(header, sizeof(header)); if(header[3] != 'D' || header[2] != 'A' || header[1] != 'T' || header[0] != 'A') { dbg_msg("datafile", "wrong signature. %x %x %x %x", header[0], header[1], header[2], header[3]); return 0; } int version = (unsigned)header[4] | (unsigned)header[5]<<8 | (unsigned)header[6]<<16 | (unsigned)header[7]<<24; if(version != 3) { dbg_msg("datafile", "wrong version. version=%x", version); return 0; } unsigned size = (unsigned)header[8] | (unsigned)header[9]<<8 | (unsigned)header[10]<<16 | (unsigned)header[11]<<24; unsigned swapsize = (unsigned)header[12] | (unsigned)header[13]<<8 | (unsigned)header[14]<<16 | (unsigned)header[15]<<24; if(DEBUG) dbg_msg("datafile", "loading. size=%d", size); datafile *df = (datafile*)mem_alloc(size+sizeof(datafile_info), 1); unsigned readsize = file.read(&df->data, size); if(readsize != size) { dbg_msg("datafile", "couldn't load the whole thing, wanted=%d got=%d", size, readsize); return 0; } #if defined(CONF_ARCH_ENDIAN_BIG) unsigned *dst = (unsigned*)df; unsigned char *src = (unsigned char*)df; for(unsigned i = 0; i < swapsize; i++) { unsigned j = i << 2; dst[i] = src[j] | src[j+1]<<8 | src[j+2]<<16 | src[j+3]<<24; } #endif if(DEBUG) dbg_msg("datafile", "item_size=%d", df->data.item_size); df->info.item_types = (item_type *)df->data.start; df->info.item_offsets = (int *)&df->info.item_types[df->data.num_item_types]; df->info.data_offsets = (int *)&df->info.item_offsets[df->data.num_items]; df->info.item_start = (char *)&df->info.data_offsets[df->data.num_raw_data]; df->info.data_start = df->info.item_start + df->data.item_size; if(DEBUG) dbg_msg("datafile", "datafile loading done. datafile='%s'", filename); if(DEBUG) { for(int i = 0; i < df->data.num_raw_data; i++) { void *p = datafile_get_data(df, i); dbg_msg("datafile", "%d %d", (int)((char*)p - (char*)(&df->data)), size); } for(int i = 0; i < datafile_num_items(df); i++) { int type, id; void *data = datafile_get_item(df, i, &type, &id); dbg_msg("map", "\t%d: type=%x id=%x p=%p offset=%d", i, type, id, data, df->info.item_offsets[i]); int *idata = (int*)data; for(int k = 0; k < 3; k++) dbg_msg("datafile", "\t\t%d=%d (%x)", k, idata[k], idata[k]); } for(int i = 0; i < df->data.num_item_types; i++) { dbg_msg("map", "\t%d: type=%x start=%d num=%d", i, df->info.item_types[i].type, df->info.item_types[i].start, df->info.item_types[i].num); for(int k = 0; k < df->info.item_types[i].num; k++) { int type, id; datafile_get_item(df, df->info.item_types[i].start+k, &type, &id); if(type != df->info.item_types[i].type) dbg_msg("map", "\tERROR"); } } } return df; } void *datafile_get_data(datafile *df, int index) { return df->info.data_start+df->info.data_offsets[index]; } void *datafile_get_item(datafile *df, int index, int *type, int *id) { item *i = (item *)(df->info.item_start+df->info.item_offsets[index]); if(type) *type = (i->type_and_id>>16)&0xffff; // remove sign extention if(id) *id = i->type_and_id&0xffff; return (void *)(i+1); } void datafile_get_type(datafile *df, int type, int *start, int *num) { for(int i = 0; i < df->data.num_item_types; i++) { if(df->info.item_types[i].type == type) { *start = df->info.item_types[i].start; *num = df->info.item_types[i].num; return; } } *start = 0; *num = 0; } void *datafile_find_item(datafile *df, int type, int id) { int start, num; datafile_get_type(df, type, &start, &num); for(int i = 0; i < num; i++) { int item_id; void *item = datafile_get_item(df, start+i,0, &item_id); if(id == item_id) return item; } return 0; } int datafile_num_items(datafile *df) { return df->data.num_items; } void datafile_unload(datafile *df) { if(df) mem_free(df); } // DATAFILE output struct data_info { int size; void *data; }; struct item_info { int type; int id; int size; int next; int prev; void *data; }; struct itemtype_info { int num; int first; int last; }; // struct datafile_out { baselib::file_stream file; int num_items; int num_datas; int num_item_types; itemtype_info item_types[0xffff]; item_info items[1024]; data_info datas[1024]; }; datafile_out *datafile_create(const char *filename) { datafile_out *df = new datafile_out; if(!df->file.open_w(filename)) { delete df; return 0; } df->num_items = 0; df->num_datas = 0; df->num_item_types = 0; mem_zero(&df->item_types, sizeof(df->item_types)); for(int i = 0; i < 0xffff; i++) { df->item_types[i].first = -1; df->item_types[i].last = -1; } return df; } int datafile_add_item(datafile_out *df, int type, int id, int size, void *data) { df->items[df->num_items].type = type; df->items[df->num_items].id = id; df->items[df->num_items].size = size; // copy data df->items[df->num_items].data = mem_alloc(size, 1); mem_copy(df->items[df->num_items].data, data, size); if(!df->item_types[type].num) // count item types df->num_item_types++; // link df->items[df->num_items].prev = df->item_types[type].last; df->items[df->num_items].next = -1; if(df->item_types[type].last != -1) df->items[df->item_types[type].last].next = df->num_items; df->item_types[type].last = df->num_items; if(df->item_types[type].first == -1) df->item_types[type].first = df->num_items; df->item_types[type].num++; df->num_items++; return df->num_items-1; } int datafile_add_data(datafile_out *df, int size, void *data) { df->datas[df->num_items].size = size; df->datas[df->num_datas].data = data; df->num_datas++; return df->num_datas-1; } int datafile_finish(datafile_out *df) { // we should now write this file! if(DEBUG) dbg_msg("datafile", "writing"); // calculate sizes int itemsize = 0; for(int i = 0; i < df->num_items; i++) { if(DEBUG) dbg_msg("datafile", "item=%d size=%d (%d)", i, df->items[i].size, df->items[i].size+sizeof(item)); itemsize += df->items[i].size + sizeof(item); } int datasize = 0; for(int i = 0; i < df->num_datas; i++) datasize += df->datas[i].size; // calculate the complete size int typessize = df->num_item_types*sizeof(item_type); int headersize = sizeof(datafile_header); int offsetsize = df->num_items*sizeof(int) + df->num_datas*sizeof(int); int filesize = headersize + typessize + offsetsize + itemsize + datasize; int swapsize = filesize - datasize; if(DEBUG) dbg_msg("datafile", "num_item_types=%d typessize=%d itemsize=%d datasize=%d", df->num_item_types, typessize, itemsize, datasize); // construct header datafile_header header; header.id = ('D'<<24) | ('A'<<16) | ('T'<<8) | ('A'); header.version = 3; header.size = filesize - 16; header.swaplen = swapsize - 16; header.num_item_types = df->num_item_types; header.num_items = df->num_items; header.num_raw_data = df->num_datas; header.item_size = itemsize; header.data_size = datasize; // TODO: apply swapping // write header if(DEBUG) dbg_msg("datafile", "headersize=%d", sizeof(header)); df->file.write(&header, sizeof(header)); // write types for(int i = 0, count = 0; i < 0xffff; i++) { if(df->item_types[i].num) { // write info item_type info; info.type = i; info.start = count; info.num = df->item_types[i].num; if(DEBUG) dbg_msg("datafile", "writing type=%x start=%d num=%d", info.type, info.start, info.num); df->file.write(&info, sizeof(info)); count += df->item_types[i].num; } } // write item offsets for(int i = 0, offset = 0; i < 0xffff; i++) { if(df->item_types[i].num) { // write all items in of this type int k = df->item_types[i].first; while(k != -1) { if(DEBUG) dbg_msg("datafile", "writing item offset num=%d offset=%d", k, offset); df->file.write(&offset, sizeof(offset)); offset += df->items[k].size + sizeof(item); // next k = df->items[k].next; } } } // write data offsets for(int i = 0, offset = 0; i < df->num_datas; i++) { if(DEBUG) dbg_msg("datafile", "writing data offset num=%d offset=%d", i, offset); df->file.write(&offset, sizeof(offset)); offset += df->datas[i].size; } // write items for(int i = 0; i < 0xffff; i++) { if(df->item_types[i].num) { // write all items in of this type int k = df->item_types[i].first; while(k != -1) { item itm; itm.type_and_id = (i<<16)|df->items[k].id; itm.size = df->items[k].size; if(DEBUG) dbg_msg("datafile", "writing item type=%x idx=%d id=%d size=%d", i, k, df->items[k].id, df->items[k].size); df->file.write(&itm, sizeof(itm)); df->file.write(df->items[k].data, df->items[k].size); // next k = df->items[k].next; } } } // write data for(int i = 0; i < df->num_datas; i++) { if(DEBUG) dbg_msg("datafile", "writing data id=%d size=%d", i, df->datas[i].size); df->file.write(df->datas[i].data, df->datas[i].size); } // free data for(int i = 0; i < df->num_items; i++) mem_free(df->items[i].data); delete df; if(DEBUG) dbg_msg("datafile", "done"); return 0; }