/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ### File Specific: main-programmer: Christian Meyer co-programmer: ... */ #include "data_tank.h" using namespace std; ////////////////// // DataTank ////////////////// DataTank::DataTank() { loader = new DataLoader; tree = NULL; } DataTank::~DataTank() { // free DataTree tree_delete(); // free DataLoader if( loader) delete loader; } void DataTank::tree_add( void* r, char* filename, int type) { DataTree *act; if( tree == NULL) { tree = (DataTree*) malloc( sizeof( DataTree)); tree->type = type; memset( tree->filename, 0, MAX_FILENAME_LENGHT); strncpy( tree->filename, filename, MAX_FILENAME_LENGHT-1); tree->parent = NULL; tree->up = NULL; tree->down = NULL; tree->resource = r; return; } act = tree; while( act != NULL) { if( strcmp( act->filename, filename) > 0) { if( act->up != NULL) act = act->up; else { act->up = (DataTree*) malloc( sizeof( DataTree)); act->up->type = type; memset( act->up->filename, 0, MAX_FILENAME_LENGHT); strncpy( act->up->filename, filename, MAX_FILENAME_LENGHT-1); act->up->parent = act; act->up->up = NULL; act->up->down = NULL; act->up->resource = r; break; } } else { if( act->down != NULL) act = act->down; else { act->down = (DataTree*) malloc( sizeof( DataTree)); act->down->type = type; memset( act->down->filename, 0, MAX_FILENAME_LENGHT); strncpy( act->down->filename, filename, MAX_FILENAME_LENGHT-1); act->down->parent = act; act->down->up = NULL; act->down->down = NULL; act->down->resource = r; break; } } } } DataTree* DataTank::tree_find( char* file) { DataTree *act; if( tree == NULL) return NULL; act = tree; while( act != NULL) { if( strcmp( act->filename, file) == 0) break; else if( strcmp( act->filename, file) > 0) act = act->up; else act = act->down; } return act; } DataTree* DataTank::tree_highest( DataTree* t) { DataTree* act; if( t == NULL) return NULL; act = t; while( act != NULL) { if( act->up == NULL) break; act = act->up; } return act; } DataTree* DataTank::tree_lowest( DataTree* t) { DataTree* act; if( t == NULL) return NULL; act = t; while( act != NULL) { if( act->down == NULL) break; act = act->down; } return act; } void DataTank::tree_remove( DataTree* rem) { DataTree *rep; void* tempv; int tempi; char tempn[MAX_FILENAME_LENGHT]; if( rem != NULL) { if( rem->up == NULL && rem->down == NULL) { // leaf if( rem->parent == NULL) tree = NULL; else { if( rem->parent->up == rem) rem->parent->up = NULL; else rem->parent->down = NULL; } loader->free_file( rem->resource, rem->type); free( rem); } else if( rem->up != NULL && rem->down == NULL) { // branch up if( rem->parent == NULL) { tree = rem->up; rem->up->parent = NULL; } else { if( rem->parent->up == rem) rem->parent->up = rem->up; else rem->parent->down = rem->up; rem->up->parent = rem->parent; } loader->free_file( rem->resource, rem->type); free( rem); } else if( rem->up == NULL && rem->down != NULL) { // branch down if( rem->parent == NULL) { tree = rem->down; rem->down->parent = NULL; } else { if( rem->parent->up == rem) rem->parent->up = rem->down; else rem->parent->down = rem->down; rem->down->parent = rem->parent; } loader->free_file( rem->resource, rem->type); free( rem); } else { // fork // get highest from down tree rep = tree_highest( rem->down); // swap contents tempv = rep->resource; tempi = rep->type; strcpy( tempn, rep->filename); rep->resource = rem->resource; rep->type = rem->type; strcpy( rep->filename, rem->filename); rem->resource = tempv; rem->type = tempi; strcpy( rem->filename, tempn); // remove rep tree_remove( rep); } } } void DataTank::tree_delete() { DataTree *act, *kil; if( tree != NULL) { act = tree; while( act != NULL) { if( act->up != NULL) { act = act->up; continue; } if( act->down != NULL) { act = act->down; continue; } kil = act; act = act->parent; if( act != NULL) { if( kil == act->up) act->up = NULL; if( kil == act->down) act->down = NULL; } loader->free_file( kil->resource, kil->type); free( kil); } } } void* DataTank::get( char* file) { DataTree* t; void* new_res; int type; t = tree_find( file); if( t == NULL) { type = loader->get_type( file); if( type == -1) return NULL; new_res = loader->load_file( file, type); if( new_res == NULL) { // return placeholder return loader->get_placeholder( type); } else { tree_add( new_res, file, type); return new_res; } } else { return t->resource; } } void DataTank::unload( char* file) { DataTree* rem; rem = tree_find( file); tree_remove( rem); } void DataTank::precache( char* resfile, void(*pfunc)(int, float, char*)) { FILE* source; int total, done; char file[256]; char* s; source = fopen( resfile, "r"); if( source == NULL) return; total = done = 0; while( !feof( source)) { fgets( file, 256, source); if( (s = strchr( file, '\n')) != NULL) *s = 0; if( strlen( file) > 1) total++; } rewind( source); while( !feof( source)) { fgets( file, 256, source); if( (s = strchr( file, '\n')) != NULL) *s = 0; if( strlen( file) > 1) { if( pfunc) pfunc( total, ((float)done)/((float)total), file); get( file); done++; } } fclose( source); } void DataTank::save_precache( char* filename) { FILE* out; out = fopen( filename, "w"); if( out == NULL) return; if( tree != NULL) save_node( tree, out); fclose( out); } void DataTank::save_node( DataTree* act, FILE* out) { fprintf(out, "%s\n", act->filename); if( act->down) save_node( act->down, out); if( act->up) save_node( act->up, out); return; } int DataTank::add_filetype( char* postfix, void*(*lfunc)(char*), void(*ffunc)(void*), char* placeholderfile) { return loader->add_filetype( postfix, lfunc, ffunc, placeholderfile); } //////////////// // DataLoader //////////////// DataLoader::DataLoader() { ntypes = 0; load_funcs = NULL; free_funcs = NULL; postfixes = NULL; placeholders = NULL; } DataLoader::~DataLoader() { int i; for( i = 0; i < ntypes; i++) { if( placeholders[i] != NULL) free_funcs[i]( placeholders[i]); if( postfixes[i] != NULL) free( postfixes[i]); } if( postfixes) free( postfixes); if( placeholders) free( placeholders); if( free_funcs) free( free_funcs); if( load_funcs) free( load_funcs); } int DataLoader::add_filetype( char* postfix, void*(*lfunc)(char*), void(*ffunc)(void*), char* placeholderfile) { int type = 0; char testfile[MAX_FILENAME_LENGHT]; if( !postfix || !lfunc || !ffunc || !placeholderfile) return -1; sprintf( testfile, "blabla.%s", postfix); if( (type = get_type( testfile)) != -1) { load_funcs[type] = lfunc; free_funcs[type] = ffunc; placeholders[type] = lfunc( placeholderfile); return type; } // backup void*(**old_load_funcs)(char*) = load_funcs; void(**old_free_funcs)(void*) = free_funcs; char** old_postfixes = postfixes; void** old_placeholders = placeholders; // realloc load_funcs = (void*(**)(char*)) malloc( sizeof( void*(*)(char*)) * (ntypes + 1)); free_funcs = (void(**)(void*)) malloc( sizeof( void(*)(void*)) * (ntypes + 1)); postfixes = (char**) malloc( sizeof( char*) * (ntypes + 1)); placeholders = (void**) malloc( sizeof( void*) * (ntypes + 1)); // copy memcpy( load_funcs, old_load_funcs, sizeof( void*(*)(char*)) * ntypes); memcpy( free_funcs, old_free_funcs, sizeof( void(*)(void*)) * ntypes); memcpy( postfixes, old_postfixes, sizeof( char*) * ntypes); memcpy( placeholders, old_placeholders, sizeof( void*) * ntypes); // free free( old_load_funcs); free( old_free_funcs); free( old_postfixes); free( old_placeholders); // add type = ntypes; ntypes++; load_funcs[type] = lfunc; free_funcs[type] = ffunc; postfixes[type] = (char*) malloc( sizeof( char) * POSTFIX_LENGHT); memset( postfixes[type], 0, POSTFIX_LENGHT); strncpy( postfixes[type], postfix, POSTFIX_LENGHT); placeholders[type] = lfunc( placeholderfile); return type; } void* DataLoader::load_file( char* file, int type) { if( type <= ntypes && type >= 0) return load_funcs[type]( file); else return NULL; } int DataLoader::get_type( char* file) { int i, n; char* posterior; if( file == NULL) return -1; i = 0; n = -1; while( file[i] != 0) { if( file[i] == '.') n = i; i++; } if( n == -1) return -1; posterior = &(file[n]); for( i = 0; i < ntypes; i++) { if( strcmp( posterior, postfixes[i]) == 0) return i; } return -1; } void DataLoader::free_file( void* resource, int type) { if( type <= ntypes && type >= 0) free_funcs[type]( resource); } void* DataLoader::get_placeholder( int type) { if( type <= ntypes && type >= 0) return placeholders[type]; else return NULL; }