void CacheList::locate(CacheItem *i, int local_only) { // dprintf("cache in %s, type %d, offset %d\n",crc_manager.get_filename(i->file_number),i->type,i->offset); if (i->file_number!=last_file) { if (fp) delete fp; if (last_dir) delete last_dir; if (local_only) fp=new jFILE(crc_manager.get_filename(i->file_number),"rb"); else fp=open_file(crc_manager.get_filename(i->file_number),"rb"); if (fp->open_failure()) { printf("Ooch. Could not open file %s\n",crc_manager.get_filename(i->file_number)); delete fp; exit(0); } last_offset=-1; last_dir=new spec_directory(fp); last_file=i->file_number; } if (i->offset!=last_offset) { fp->seek(i->offset,SEEK_SET); last_offset=i->offset; } used=1; }
int CacheList::prof_size() { int size = 0; // count up the size for a spec enrty size += 2; // total filenames int i; for (i = 0; i < crc_manager.total_filenames(); i++) size += strlen(crc_manager.get_filename(i)) + 2; // filename + 0 + size of string size += 4; // number of entries saved for (i = 0; i < total; i++) if (list[i].last_access > 0) // don't save unaccessed counts size += 2 + 4 + 1; // filenumber & offset & type return size; }
void CacheList::show_accessed() { int old=last_access,new_old_accessed; CacheItem *ci,*new_old; do { new_old_accessed=-1; new_old=NULL; ci=list; for (int i=0; i<total; i++,ci++) { if (ci->last_access<old && ci->last_access>0 && ci->last_access>new_old_accessed) { new_old_accessed=ci->last_access; new_old=ci; } } if (new_old) { ci=new_old; old=ci->last_access; printf("type=(%20s) file=(%20s) access=(%6ld)\n",spec_types[ci->type], crc_manager.get_filename(ci->file_number), (long int)ci->last_access); } } while (new_old); }
void CacheList::prof_write(bFILE *fp) { if (prof_data) { int *ordered_ids=(int *)malloc(sizeof(int)*total); int i; for (i=0; i<total; i++) ordered_ids[i]=i; qsort(ordered_ids,total,sizeof(int),c_sorter); if (fp) { fp->write_uint16(crc_manager.total_filenames()); for (i=0; i<crc_manager.total_filenames(); i++) { int l=strlen(crc_manager.get_filename(i))+1; fp->write_uint8(l); fp->write(crc_manager.get_filename(i),l); } int tsaved=0; for (i=0; i<total; i++) if (list[i].last_access>0) tsaved++; fp->write_uint32(tsaved); for (i=0; i<total; i++) { int id=ordered_ids[i]; if (list[id].last_access>0) // don't save unaccessed counts { fp->write_uint8(list[id].type); // save type, if type changed on reload // don't cache in-> its a different refrence fp->write_uint16(list[id].file_number); fp->write_uint32(list[id].offset); } } } free(ordered_ids); } else dprintf("Cache profiling was not initialized\n"); }
sound_effect *CacheList::sfx(int id) { CacheItem *me = list + id; CONDITION(id<total && id>=0 && me->file_number>=0, "Bad id"); if (me->last_access >= 0) { touch(me); // hold me, feel me, be me! return (sound_effect *) me->data; } else { touch(me); // hold me, feel me, be me! char *fn = crc_manager.get_filename(me->file_number); me->data = (void *) new sound_effect(fn); return (sound_effect *) me->data; } }
int CacheList::reg(char const *filename, char const *name, int type, int rm_dups) { int fn = crc_manager.get_filenumber(filename); int offset = 0; if (type == SPEC_EXTERN_SFX) { // Missing sound effect is not a critical error, so we don't // quit when error happens. bFILE *check = open_file(filename, "rb"); if (!check->open_failure()) { printf("Unable to open sfx file '%s' for reading, ignoring.\n", filename); } delete check; } else { // If a classic spec item, look for it in the archive. spec_directory *sd = sd_cache.get_spec_directory(filename); if (!sd) { printf("Unable to open file %s for item %s\n", filename, name); assert(false); exit(0); } spec_entry *se = NULL; if (type != -1) se = sd->find(name, type); if (!se) se = sd->find(name); if (!se) { printf("No such item %s in file %s\n", name, filename); assert(false); exit(0); } if (type >= 0 && type != se->type && ((type != SPEC_CHARACTER2 && type != SPEC_CHARACTER) || (se->type != SPEC_CHARACTER && se->type != SPEC_CHARACTER2))) { printf("Item %s of file %s should be type %s\n", name, filename, spec_types[type]); assert(false); exit(0); } type = se->type; offset = se->offset; } // Check whether there is another entry pointing to the same // file and offset, and return it as a shortcut. if (rm_dups) { for (int i = 0; i < total; i++) if (list[i].file_number == fn && list[i].offset == offset) return i; } int id = AllocId(); CHECK(id < total && list[id].file_number < 0); list[id].file_number = fn; list[id].last_access = -1; list[id].data = NULL; list[id].offset = offset; list[id].type = type; return id; }
void CacheList::load_cache_prof_info(char *filename, level *lev) { int j; for (j=0; j<this->total; j++) if (list[j].last_access>=0) // reset all loaded cache items to 0, all non-load to -1 list[j].last_access=0; preload_cache(lev); // preliminary guesses at stuff to load int load_fail=1; bFILE *fp=open_file(filename,"rb"); if (!fp->open_failure()) { spec_directory sd(fp); spec_entry *se=sd.find("cache profile info"); // see if the cache profile info is in the file if (se) { fp->seek(se->offset,0); char name[255]; int tnames=0; int *fnum_remap; // remaps old filenumbers into current ones tnames=fp->read_uint16(); if (tnames) /// make sure there isn't bad info in the file { fnum_remap=(int *)malloc(sizeof(int)*tnames); int i; for (i=0; i<tnames; i++) { fp->read(name,fp->read_uint8()); fnum_remap[i]=-1; // initialize the map to no-map int j; for (j=0; j<crc_manager.total_filenames(); j++) if (!strcmp(crc_manager.get_filename(j),name)) fnum_remap[i]=j; } int tsaved = fp->read_uint32(); int *priority=(int *)malloc(tsaved*sizeof(int)); memset(priority,0xff,tsaved*sizeof(int)); // initialize to -1 int tmatches=0; sorted_id_list=(int *)malloc(sizeof(int)*total); for (j=0; j<total; j++) sorted_id_list[j]=j; qsort(sorted_id_list,total,sizeof(int),s_offset_compare); for (i=0; i<tsaved; i++) { fp->read_uint8(); // read type short file_num=fp->read_uint16(); if (file_num>=tnames) // bad data? file_num=-1; else file_num=fnum_remap[file_num]; uint32_t offset=fp->read_uint32(); // search for a match j=search(sorted_id_list,file_num,offset); if (j!=-1) { if (list[j].last_access<0) // if not loaded list[j].last_access=-2; // mark as needing loading else list[j].last_access=2; // mark as loaded and needing to stay that way priority[i]=j; tmatches++; } } free(sorted_id_list); // was used for searching, no longer needed for (j=0; j<total; j++) if (list[j].last_access==0) unmalloc(list+j); // free any cache entries that are not accessed at all in the level ful=0; int tcached=0; for (j=0; j<total; j++) // now load all of the objects until full { // stat_man->update(j*70/total+25); if (list[j].file_number>=0 && list[j].last_access==-2) { list[j].last_access=-1; if (!ful) { switch (list[j].type) { case SPEC_BACKTILE : backt(j); break; case SPEC_FORETILE : foret(j); break; case SPEC_CHARACTER : case SPEC_CHARACTER2 : fig(j); break; case SPEC_IMAGE : img(j); break; case SPEC_PARTICLE : part(j); break; case SPEC_EXTERN_SFX : sfx(j); break; case SPEC_EXTERNAL_LCACHE : lblock(j); break; case SPEC_PALETTE : ctint(j); break; } tcached++; } } } load_fail=0; // if (full()) // dprintf("Cache filled while loading\n"); if (tsaved>tmatches) tmatches=tsaved+1; last_access=tmatches+1; for (i=0; i<tsaved; i++) // reorder the last access of each cache to reflect prioirties { if (priority[i]!=-1) { if (list[priority[i]].last_access!=-1) // make sure this wasn't the last item list[priority[i]].last_access=tmatches--; } } free(priority); free(fnum_remap); } } } if (load_fail) // no cache file, go solely on above gueses { int j; for (j=0; j<total; j++) // now load all of the objects until full, don't free old stuff { // stat_man->update(j*70/total+25); if (list[j].file_number>=0 && list[j].last_access==-2) { list[j].last_access=-1; if (!ful) { switch (list[j].type) { case SPEC_BACKTILE : backt(j); break; case SPEC_FORETILE : foret(j); break; case SPEC_CHARACTER : case SPEC_CHARACTER2 : fig(j); break; case SPEC_IMAGE : img(j); break; case SPEC_PARTICLE : part(j); break; case SPEC_EXTERN_SFX : sfx(j); break; case SPEC_EXTERNAL_LCACHE : lblock(j); break; case SPEC_PALETTE : ctint(j); break; } } } } if (full()) dprintf("Cache filled while loading\n"); } delete fp; }
int crc_man_write_crc_file(char const *filename) { return crc_manager.write_crc_file(filename); }
int CacheList::reg(char const *filename, char const *name, int type, int rm_dups) { int fn = crc_manager.get_filenumber(filename); int offset = 0; if (type == SPEC_EXTERN_SFX) { // If an extern sound effect then just make sure it's there. If sound // is disabled, ignore the load error, just pretend it's all OK. bFILE *check = open_file(filename, "rb"); if (!check->open_failure()) { char buf[4]; check->read(buf, 4); if (memcmp(buf, "RIFF", 4)) { printf("File %s is not a WAV file\n", filename); exit(0); } } else if (sound_avail) { printf("Unable to open file '%s' for reading\n", filename); exit(0); } delete check; } else { // If a classic spec item, look for it in the archive. spec_directory *sd = sd_cache.get_spec_directory(filename); if (!sd) { printf("Unable to open file %s for item %s\n", filename, name); exit(0); } spec_entry *se = NULL; if (type != -1) se = sd->find(name, type); if (!se) se = sd->find(name); if (!se) { printf("No such item %s in file %s\n", name, filename); exit(0); } if (type >= 0 && type != se->type && ((type != SPEC_CHARACTER2 && type != SPEC_CHARACTER) || (se->type != SPEC_CHARACTER && se->type != SPEC_CHARACTER2))) { printf("Item %s of file %s should be type %s\n", name, filename, spec_types[type]); exit(0); } type = se->type; offset = se->offset; } // Check whether there is another entry pointing to the same // file and offset, and return it as a shortcut. if (rm_dups) { for (int i = 0; i < total; i++) if (list[i].file_number == fn && list[i].offset == offset) return i; } int id = AllocId(); CHECK(id < total && list[id].file_number < 0); list[id].file_number = fn; list[id].last_access = -1; list[id].data = NULL; list[id].offset = offset; list[id].type = type; return id; }