source: abuse/trunk/src/cache.cpp @ 682

Last change on this file since 682 was 635, checked in by Sam Hocevar, 9 years ago

lisp: refactor Lisp spaces so that they are real objects, and get rid
of the unused USER_SPACE.

File size: 25.6 KB
RevLine 
[56]1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
[494]4 *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
[56]5 *
6 *  This software was released into the Public Domain. As with most public
[555]7 *  domain software, no warranty is made or implied by Crack dot Com, by
8 *  Jonathan Clark, or by Sam Hocevar.
[56]9 */
10
[555]11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
[41]14
15#if (defined(__MACH__) || !defined(__APPLE__))
[56]16#   include <sys/stat.h>
[41]17#endif
18
19#include <fcntl.h>
[131]20#include <string.h>
[41]21
[512]22#include "common.h"
23
[481]24#include "cache.h"
25#include "lisp.h"
26#include "video.h"
27#include "dprint.h"
28#include "lcache.h"
29#include "status.h"
30#include "game.h"
31#include "lisp_gc.h"
32#include "level.h"
33#include "status.h"
34#include "crc.h"
35#include "dev.h"
36#include "specache.h"
37#include "netface.h"
[2]38
39#define touch(x) { (x)->last_access=last_access++; \
[124]40           if ((x)->last_access<0) { normalize(); (x)->last_access=1; } }
[2]41
[123]42CrcManager crc_manager;
[2]43
44int past_startup=0;
45
[39]46int crc_man_write_crc_file(char const *filename)
[2]47{
[123]48  return crc_manager.write_crc_file(filename);
[2]49}
50
[123]51int CrcManager::write_crc_file(char const *filename)  // return 0 on failure
[2]52{
53  char msg[100];
[58]54  sprintf(msg, "%s", symbol_str("calc_crc"));  // this may take some time, show the user a status indicator
[2]55  if (stat_man) stat_man->push(msg,NULL);
56
57  int i,total=0;
[494]58  for (i=0; i<total_files; i++)
[2]59  {
60    int failed=0;
61    get_crc(i,failed);
62
63    if (failed)
64    {
65      jFILE *fp=new jFILE(get_filename(i),"rb");
66      if (!fp->open_failure())
67      {
[124]68    set_crc(i,crc_file(fp));
69    total++;
[2]70      }
71      delete fp;
72    } else total++;
73    if (stat_man)
74      stat_man->update(i*100/total_files);
75  }
76  if (stat_man) stat_man->pop();
[147]77  jFILE *fp=new jFILE(NET_CRC_FILENAME,"wb");
[2]78  if (fp->open_failure())
79  {
80    delete fp;
[124]81    return 0;
[2]82  }
83
[17]84  fp->write_uint16(total);
[2]85  total=0;
[494]86  for (i=0; i<total_files; i++)
[2]87  {
[17]88    uint32_t crc;
[2]89    int failed=0;
90    crc=get_crc(i,failed);
91    if (!failed)
92    {
[17]93      fp->write_uint32(crc);
94      uint8_t len=strlen(get_filename(i))+1;
95      fp->write_uint8(len);
[2]96      fp->write(get_filename(i),len);
97      total++;
98    }
99  }
100  delete fp;
[124]101  return 1;
[2]102}
103
[123]104int CrcManager::load_crc_file(char const *filename)
[2]105{
106  bFILE *fp=open_file(filename,"rb");
107  if (fp->open_failure())
108  {
109    delete fp;
110    return 0;
111  } else
112  {
[17]113    short total=fp->read_uint16();
[2]114    int i;
[494]115    for (i=0; i<total; i++)
[2]116    {
117      char name[256];
[17]118      uint32_t crc=fp->read_uint32();
119      uint8_t len=fp->read_uint8();
[2]120      fp->read(name,len);
121      set_crc(get_filenumber(name),crc);
122    }
123    delete fp;
124  }
[124]125  return 1;
[2]126}
127
[123]128void CrcManager::clean_up()
[2]129{
[494]130  for (int i=0; i<total_files; i++)
[2]131    delete files[i];
132  if (total_files)
[129]133    free(files);
[2]134  total_files=0;
135  files=NULL;
136}
137
[123]138CrcedFile::~CrcedFile()
[2]139{
[129]140  free(filename);
[2]141}
142
[124]143CrcedFile::CrcedFile(char const *name)
144{
[131]145  filename = strdup(name);
[2]146  crc_calculated=0;
147}
148
[123]149CrcManager::CrcManager()
[2]150{
151  total_files=0;
152  files=NULL;
153}
154
[123]155int CrcManager::get_filenumber(char const *filename)
[2]156{
[494]157  for (int i=0; i<total_files; i++)
[2]158    if (!strcmp(filename,files[i]->filename)) return i;
159  total_files++;
[129]160  files=(CrcedFile **)realloc(files,total_files*sizeof(CrcedFile *));
[123]161  files[total_files-1]=new CrcedFile(filename);
[2]162  return total_files-1;
163}
164
[503]165char *CrcManager::get_filename(int filenumber)
[2]166{
167  CHECK(filenumber>=0 && filenumber<total_files);
168  return files[filenumber]->filename;
169}
170
[503]171uint32_t CrcManager::get_crc(int filenumber, int &failed)
[124]172{
[2]173  CHECK(filenumber>=0 && filenumber<total_files);
[124]174  if (files[filenumber]->crc_calculated)
[2]175  {
176    failed=0;
177    return files[filenumber]->crc;
178  }
179  failed=1;
180  return 0;
181}
182
[503]183void CrcManager::set_crc(int filenumber, uint32_t crc)
[2]184{
185  CHECK(filenumber>=0 && filenumber<total_files);
186  files[filenumber]->crc_calculated=1;
187  files[filenumber]->crc=crc;
188}
189
[123]190void CacheList::unmalloc(CacheItem *i)
[2]191{
192  switch (i->type)
193  {
194    case SPEC_CHARACTER2 :
195    case SPEC_CHARACTER : delete ((figure *)i->data);   break;
196    case SPEC_FORETILE : delete ((foretile *)i->data);  break;
197    case SPEC_BACKTILE : delete ((backtile *)i->data);  break;
198    case SPEC_IMAGE    : delete ((image *)i->data);     break;
199    case SPEC_EXTERN_SFX : delete ((sound_effect *)i->data); break;
200    case SPEC_PARTICLE : delete ((part_frame *)i->data); break;
[129]201    case SPEC_EXTERNAL_LCACHE : if (i->data) free(i->data); break;
[2]202    case SPEC_PALETTE : delete ((char_tint *)i->data); break;
203    default :
204      printf("Trying to unmalloc unknown type\n");
205  }
206  i->data=NULL;
207  i->last_access=-1;
208}
209
210
211
[123]212void CacheList::prof_init()
[2]213{
214  if (prof_data)
[129]215    free(prof_data);
[124]216
[129]217  prof_data=(int *)malloc(sizeof(int)*total);
[2]218  memset(prof_data,0,sizeof(int)*total);
219}
220
221static int c_sorter(const void *a, const void *b)
222{
[123]223  return cache.compare(*(int *)a,*(int *)b);
[2]224}
225
[123]226int CacheList::compare(int a, int b)
[2]227{
228  if (prof_data[a]<prof_data[b])
229    return 1;
230  else if (prof_data[a]>prof_data[b])
231    return -1;
232  else return 0;
233}
234
235
[123]236int CacheList::prof_size()
[2]237{
238  int size=0;     // count up the size for a spec enrty
239  size+=2;        // total filenames
240  int i;
[494]241  for (i=0; i<crc_manager.total_filenames(); i++)
[123]242      size+=strlen(crc_manager.get_filename(i))+2;    // filename + 0 + size of string
[2]243
244  size+=4;       // number of entries saved
245
[494]246  for (i=0; i<total; i++)
[2]247    if (list[i].last_access>0)       // don't save unaccessed counts
248      size+=2+4+1;                   // filenumber & offset & type
249
250  return size;
251}
252
253
[123]254void CacheList::prof_write(bFILE *fp)
[2]255{
256  if (prof_data)
257  {
[129]258    int *ordered_ids=(int *)malloc(sizeof(int)*total);
[2]259    int i;
[494]260    for (i=0; i<total; i++) ordered_ids[i]=i;
[2]261    qsort(ordered_ids,total,sizeof(int),c_sorter);
262
263    if (fp)
264    {
[123]265      fp->write_uint16(crc_manager.total_filenames());
[494]266      for (i=0; i<crc_manager.total_filenames(); i++)
[2]267      {
[124]268    int l=strlen(crc_manager.get_filename(i))+1;
[17]269        fp->write_uint8(l);
[124]270    fp->write(crc_manager.get_filename(i),l);
[2]271      }
272
273      int tsaved=0;
[494]274      for (i=0; i<total; i++)
[2]275        if (list[i].last_access>0) tsaved++;
[17]276      fp->write_uint32(tsaved);
[2]277
[494]278      for (i=0; i<total; i++)
[2]279      {
[124]280    int id=ordered_ids[i];
281        if (list[id].last_access>0)       // don't save unaccessed counts
282    {
283      fp->write_uint8(list[id].type);    // save type, if type changed on reload
284                                        // don't cache in-> its a different refrence
285      fp->write_uint16(list[id].file_number);
286      fp->write_uint32(list[id].offset);
[2]287    }
[124]288      }
289    }
[2]290
[129]291    free(ordered_ids);
[2]292
293  } else dprintf("Cache profiling was not initialized\n");
294}
295
[123]296void CacheList::prof_uninit()
[2]297{
298  if (prof_data)
299  {
[129]300    free(prof_data);
[2]301    prof_data=NULL;
302  }
303}
304
305int *sorted_id_list;
306
307
308static int s_offset_compare(const void *a, const void *b)
309{
[123]310  return cache.offset_compare(*(int *)a,*(int *)b);
[2]311}
312
[123]313int CacheList::offset_compare(int a, int b)
[2]314{
315  if (list[a].offset<list[b].offset)
316    return -1;
317  else if (list[a].offset>list[b].offset)
318    return 1;
319  else if (list[a].file_number<list[b].file_number)
320    return -1;
321  else if (list[a].file_number>list[b].file_number)
322    return 1;
323  else return 0;
324}
325
326
[123]327int CacheList::search(int *sarray, uint16_t filenum, int32_t offset)
[2]328{
329  int x1=0,x2=total-1;
330  int split;
331  do
332  {
333    split=(x1+x2)/2;
[123]334    CacheItem *e=list+sarray[split];
[2]335
[124]336    if (e->offset<offset)      // search to the right
[2]337      x1=split+1;
338    else if (e->offset>offset)
339      x2=split-1;
340    else if (e->file_number<filenum)
341      x1=split+1;
342    else if (e->file_number>filenum)
343      x2=split-1;
344    else return sarray[split];
345  } while (x1<=x2);
346  return -1;
347}
348
349static int load_chars()  // returns 0 if cache filled
350{
351  int i;
[494]352  for (i=0; i<total_objects; i++)
[2]353  {
354    if (figures[i]->get_cflag(CFLAG_NEED_CACHE_IN))
355    {
356      figures[i]->set_cflag(CFLAG_CACHED_IN,0);
357      figures[i]->cache_in();
358      figures[i]->set_cflag(CFLAG_NEED_CACHE_IN,0);
359    }
360  }
361  return 1;
[124]362
[2]363}
364
[123]365void CacheList::note_need(int id)
[2]366{
367  if (list[id].last_access<0)
368    list[id].last_access=-2;
369  else
370    list[id].last_access=2;
371}
372
[123]373void CacheList::preload_cache_object(int type)
[2]374{
375  if (type<0xffff)
376  {
377    if (!figures[type]->get_cflag(CFLAG_NEED_CACHE_IN))  // see if it's already marked
[124]378    {
[2]379      figures[type]->set_cflag(CFLAG_NEED_CACHE_IN,1);
380      void *cache_fun=figures[type]->get_fun(OFUN_GET_CACHE_LIST);
381
382      if (cache_fun)
383      {
[635]384    LSpace *sp = LSpace::Current;
385    LSpace::Current = &LSpace::Perm;
[2]386
[124]387    void *call_with=NULL;
[492]388    push_onto_list(LNumber::Create(type),call_with);
[2]389
[497]390    void *CacheList = ((LSymbol *)cache_fun)->EvalFunction(call_with);
[491]391    PtrRef r1(CacheList);
[2]392
[124]393    if (CacheList && lcar(CacheList))
394    {
395      void *obj_list=lcar(CacheList);
396      while (obj_list)
397      {
398        int t=lnumber_value(CAR(obj_list));
399        if (t<0 || t>=total_objects)
400          lbreak("Get cache list returned a bad object number %d\n",t);
401        else
402          preload_cache_object(t);
403        obj_list=CDR(obj_list);
404      }
405    }
406    if (CacheList && lcdr(CacheList))
407    {
408      void *id_list=lcar(lcdr(CacheList));
409      while (id_list)
410      {
411        int id=lnumber_value(CAR(id_list));
412        if (id<0 || id>=total)
413          lbreak("Get cache list returned a bad id number %d\n",id);
414        else if (list[id].last_access<0)
415          list[id].last_access=-2;
416        else list[id].last_access=2;
[2]417
[124]418        id_list=CDR(id_list);
419      }
420    }
[635]421    LSpace::Current=sp;
[2]422
423      }
424    }
425  }
426}
427
[123]428void CacheList::preload_cache(level *lev)
[2]429{
430  game_object *f;
431  int i;
[494]432  for (i=0; i<total_objects; i++)                       // mark all types as not needing loading
[2]433    figures[i]->set_cflag(CFLAG_NEED_CACHE_IN,0);
434
[494]435  for (f=lev->first_object(); f; f=f->next)               // go through each object and get requested items to cache in
[2]436    preload_cache_object(f->otype);
437
438
439  int j;
[17]440  uint16_t *fg_line;
[494]441  for (j=0; j<lev->foreground_height(); j++)
[2]442  {
443    fg_line=lev->get_fgline(j);
[494]444    for (i=0; i<lev->foreground_width(); i++,fg_line++)
[2]445    {
446      int id=foretiles[fgvalue(*fg_line)];
447      if (id>=0 && id<nforetiles)
448      {
[124]449    if (list[id].last_access<0)
[2]450          list[id].last_access=-2;
[124]451    else list[id].last_access=2;
[2]452      }
[124]453    }
[2]454  }
455
[17]456  uint16_t *bg_line;
[494]457  for (j=0; j<lev->background_height(); j++)
[2]458  {
459    bg_line=lev->get_bgline(j);
[494]460    for (i=0; i<lev->background_width(); i++,bg_line++)
[124]461    {
[2]462      int id=backtiles[bgvalue(*bg_line)];
463      if (id>=0 && id<nbacktiles)
464      {
[124]465    if (list[id].last_access<0)
[2]466          list[id].last_access=-2;
[124]467    else list[id].last_access=2;
[2]468      }
[124]469    }
[2]470  }
471
472  load_chars();
473}
474
[123]475void CacheList::load_cache_prof_info(char *filename, level *lev)
[2]476{
477  int j;
[494]478  for (j=0; j<this->total; j++)
[2]479    if (list[j].last_access>=0)      // reset all loaded cache items to 0, all non-load to -1
480      list[j].last_access=0;
481
482  preload_cache(lev);                // preliminary guesses at stuff to load
483
484  int load_fail=1;
485  bFILE *fp=open_file(filename,"rb");
486  if (!fp->open_failure())
487  {
488    spec_directory sd(fp);
489    spec_entry *se=sd.find("cache profile info");   // see if the cache profile info is in the file
490    if (se)
491    {
492      fp->seek(se->offset,0);
493
494      char name[255];
495      int tnames=0;
496      int *fnum_remap;    // remaps old filenumbers into current ones
[124]497
[17]498      tnames=fp->read_uint16();
[2]499      if (tnames)                     /// make sure there isn't bad info in the file
500      {
[129]501    fnum_remap=(int *)malloc(sizeof(int)*tnames);
[2]502
[124]503    int i;
[494]504    for (i=0; i<tnames; i++)
[124]505    {
506      fp->read(name,fp->read_uint8());
507      fnum_remap[i]=-1;                    // initialize the map to no-map
[2]508
[124]509      int j;
[494]510      for (j=0; j<crc_manager.total_filenames(); j++)
[124]511        if (!strcmp(crc_manager.get_filename(j),name))
512          fnum_remap[i]=j;
513    }
[494]514
[162]515    int tsaved = fp->read_uint32();
[2]516
517
[129]518    int *priority=(int *)malloc(tsaved*sizeof(int));
[124]519    memset(priority,0xff,tsaved*sizeof(int));   // initialize to -1
520    int tmatches=0;
[2]521
[129]522    sorted_id_list=(int *)malloc(sizeof(int)*total);
[494]523    for (j=0; j<total; j++) sorted_id_list[j]=j;
[124]524    qsort(sorted_id_list,total,sizeof(int),s_offset_compare);
[2]525
[494]526    for (i=0; i<tsaved; i++)
[124]527    {
[476]528      fp->read_uint8(); // read type
[124]529      short file_num=fp->read_uint16();
530      if (file_num>=tnames)  // bad data?
531        file_num=-1;
532      else file_num=fnum_remap[file_num];
[2]533
[124]534      uint32_t offset=fp->read_uint32();
[2]535
[124]536      // search for a match
[494]537      j=search(sorted_id_list,file_num,offset);
[124]538      if (j!=-1)
[494]539      {
[124]540        if (list[j].last_access<0)  // if not loaded
541          list[j].last_access=-2;      // mark as needing loading
542        else list[j].last_access=2;   // mark as loaded and needing to stay that way
543        priority[i]=j;
544        tmatches++;
545      }
546    }
[2]547
[129]548    free(sorted_id_list);            // was used for searching, no longer needed
[2]549
[494]550    for (j=0; j<total; j++)
[124]551      if (list[j].last_access==0)
552        unmalloc(list+j);             // free any cache entries that are not accessed at all in the level
[2]553
554
[124]555    ful=0;
556    int tcached=0;
[494]557    for (j=0; j<total; j++)    // now load all of the objects until full
[124]558    {
559//      stat_man->update(j*70/total+25);
560      if (list[j].file_number>=0 && list[j].last_access==-2)
561      {
562        list[j].last_access=-1;
563        if (!ful)
564        {
565          switch (list[j].type)
566          {
567        case SPEC_BACKTILE : backt(j); break;
568        case SPEC_FORETILE : foret(j); break;
569        case SPEC_CHARACTER :
570        case SPEC_CHARACTER2 : fig(j); break;
571        case SPEC_IMAGE : img(j); break;
572        case SPEC_PARTICLE : part(j); break;
573        case SPEC_EXTERN_SFX : sfx(j); break;
574        case SPEC_EXTERNAL_LCACHE : lblock(j); break;
575        case SPEC_PALETTE : ctint(j); break;
576          }
577          tcached++;
578        }
579      }
580    }
581    load_fail=0;
582//    if (full())
583//      dprintf("Cache filled while loading\n");
[2]584
[124]585    if (tsaved>tmatches)
586      tmatches=tsaved+1;
[2]587
[124]588    last_access=tmatches+1;
[494]589    for (i=0; i<tsaved; i++)      // reorder the last access of each cache to reflect prioirties
[124]590    {
591      if (priority[i]!=-1)
592      {
593        if (list[priority[i]].last_access!=-1)            // make sure this wasn't the last item
594          list[priority[i]].last_access=tmatches--;
595      }
596    }
[2]597
[129]598    free(priority);
599    free(fnum_remap);
[2]600
601
602      }
[124]603    }
[2]604  }
605
606  if (load_fail) // no cache file, go solely on above gueses
607  {
608    int j;
[494]609    for (j=0; j<total; j++)    // now load all of the objects until full, don't free old stuff
[2]610    {
611//      stat_man->update(j*70/total+25);
612
613      if (list[j].file_number>=0 && list[j].last_access==-2)
614      {
[124]615    list[j].last_access=-1;
616    if (!ful)
617    {
618      switch (list[j].type)
619      {
620        case SPEC_BACKTILE : backt(j); break;
621        case SPEC_FORETILE : foret(j); break;
622        case SPEC_CHARACTER :
623        case SPEC_CHARACTER2 : fig(j); break;
624        case SPEC_IMAGE : img(j); break;
625        case SPEC_PARTICLE : part(j); break;
626        case SPEC_EXTERN_SFX : sfx(j); break;
627        case SPEC_EXTERNAL_LCACHE : lblock(j); break;
628        case SPEC_PALETTE : ctint(j); break;
[2]629      }
630    }
[124]631      }
632    }
[2]633    if (full())
634      dprintf("Cache filled while loading\n");
635  }
636  delete fp;
637}
638
639
[123]640void CacheList::prof_poll_start()
[2]641{
[124]642  poll_start_access=last_access;
[2]643}
644
[123]645void CacheList::prof_poll_end()
[2]646{
647  if (prof_data)
648  {
649    int i=0;
[494]650    for (; i<total; i++)
[2]651    {
652      if (list[i].last_access>=poll_start_access)
653        prof_data[i]++;
654    }
655  }
656}
657
[123]658void CacheList::unreg(int id)
[2]659{
[505]660    if (list[id].file_number >= 0)
661    {
662        unmalloc(&list[id]);
663        list[id].file_number = -1;
664    }
665    else
666        printf("Error : trying to unregister free object\n");
[2]667}
668
[123]669CacheList::CacheList()
[2]670{
[506]671    // Start out with a decent sized cache buffer because it's going to
672    // get allocated anyway.
673    total = 0;
674    list = NULL;
675    last_registered = -1;
676    fp = NULL;
677    last_access = 1;
678    used = ful = 0;
679    last_dir = NULL;
680    last_file = -1;
681    prof_data = NULL;
[2]682}
683
[123]684CacheList::~CacheList()
[124]685{
[2]686}
687
[123]688void CacheList::empty()
[2]689{
[494]690  for (int i=0; i<total; i++)
[2]691  {
692    if (list[i].file_number>=0 && list[i].last_access!=-1)
693      unmalloc(&list[i]);
694  }
[129]695  free(list);
[2]696  if (fp) delete fp;
697  if (last_dir) delete last_dir;
698
699  if (prof_data)
700  {
701    delete prof_data;
702    prof_data=NULL;
703  }
704
705  total=0;                    // reinitalize
706  list=NULL;
[124]707  last_registered=-1;
[506]708  fp=NULL;
[2]709
710  last_access=1;
711  used=ful=0;
712  last_dir=NULL;
713  last_file=-1;
714  prof_data=NULL;
715}
716
[123]717void CacheList::locate(CacheItem *i, int local_only)
[2]718{
[123]719//  dprintf("cache in %s, type %d, offset %d\n",crc_manager.get_filename(i->file_number),i->type,i->offset);
[2]720  if (i->file_number!=last_file)
721  {
722    if (fp) delete fp;
[124]723    if (last_dir) delete last_dir;
[2]724    if (local_only)
[123]725      fp=new jFILE(crc_manager.get_filename(i->file_number),"rb");
[2]726    else
[123]727      fp=open_file(crc_manager.get_filename(i->file_number),"rb");
[2]728
729
730    if (fp->open_failure())
731    {
[123]732      printf("Ooch. Could not open file %s\n",crc_manager.get_filename(i->file_number));
[2]733      delete fp;
734      exit(0);
735    }
736
737    last_offset=-1;
738    last_dir=new spec_directory(fp);
739    last_file=i->file_number;
740  }
741  if (i->offset!=last_offset)
742  {
743    fp->seek(i->offset,SEEK_SET);
744    last_offset=i->offset;
745  }
746  used=1;
747}
748
[503]749int CacheList::AllocId()
[2]750{
[503]751    if (prof_data)
[2]752    {
[503]753        the_game->show_help("new id allocated, cache profiling turned off\n");
754        prof_uninit();
[2]755    }
756
[503]757    // See if we previously allocated an id, if so check the next spot in
758    // the array otherwise we will have to scan the whole list for a free
759    // id and possibly grow the list.
760    int ret = last_registered + 1;
761    if (ret >= total || list[ret].file_number < 0)
[2]762    {
[503]763        // Scan list for a free id
764        CacheItem *ci = list;
765        ret = -1;
766        for (int i = 0; i < total && ret < 0; i++, ci++)
767            if (ci->file_number < 0)
768                ret = i;
769
770        if (ret < 0) // if no free id then make list bigger
771        {
772            int add_size = 20;
773            list = (CacheItem *)realloc(list,
774                                  (sizeof(CacheItem) * (total + add_size)));
775            for (int i = 0; i < add_size; i++)
776            {
777                list[total + i].file_number = -1; // mark new entries as new
778                list[total + i].last_access = -1;
779                list[total + i].data = NULL;
780            }
781            ret = total;
782            // If new id's have been added, old prof_data size won't work
783            if (prof_data)
784            {
785                free(prof_data);
786                prof_data = NULL;
787            }
788            total += add_size;
789        }
[2]790    }
[503]791    last_registered = ret;
792    return ret;
[2]793}
794
[503]795int CacheList::reg_object(char const *filename, LObject *object,
796                          int type, int rm_dups)
[124]797{
[503]798    // See if we got a object with a filename included. Otherwise,
799    // it's a string.
800    if (item_type(object) == L_CONS_CELL)
801    {
802        filename = lstring_value(lcar(object));
803        object = lcdr(object);
804    }
[2]805
[503]806    return reg(filename, lstring_value(object), type, rm_dups);
[2]807}
808
809extern int total_files_open;
810
[503]811int CacheList::reg(char const *filename, char const *name, int type, int rm_dups)
[2]812{
[503]813    int fn = crc_manager.get_filenumber(filename);
814    int offset = 0;
[2]815
[503]816    if (type == SPEC_EXTERN_SFX)
[124]817    {
[503]818        // If an extern sound effect then just make sure it's there. If sound
819        // is disabled, ignore the load error, just pretend it's all OK.
820        bFILE *check = open_file(filename, "rb");
821        if (!check->open_failure())
[124]822        {
[503]823            char buf[4];
824            check->read(buf, 4);
825            if (memcmp(buf, "RIFF", 4))
[124]826            {
[503]827                printf("File %s is not a WAV file\n", filename);
[124]828                exit(0);
829            }
830        }
[503]831        else if (sound_avail)
[124]832        {
[503]833            printf("Unable to open file '%s' for reading\n", filename);
[124]834            exit(0);
835        }
[503]836        delete check;
[124]837    }
[503]838    else
839    {
840        // If a classic spec item, look for it in the archive.
841        spec_directory *sd = sd_cache.get_spec_directory(filename);
[2]842
[503]843        if (!sd)
844        {
845            printf("Unable to open file %s for item %s\n", filename, name);
846            exit(0);
847        }
[2]848
[503]849        spec_entry *se = NULL;
850        if (type != -1)
851            se = sd->find(name, type);
852        if (!se)
853            se = sd->find(name);
854        if (!se)
855        {
856            printf("No such item %s in file %s\n", name, filename);
857            exit(0);
858        }
[2]859
[503]860        if (type >= 0 && type != se->type &&
861             ((type != SPEC_CHARACTER2 && type != SPEC_CHARACTER)
862               || (se->type != SPEC_CHARACTER && se->type != SPEC_CHARACTER2)))
863        {
864            printf("Item %s of file %s should be type %s\n",
865                   name, filename, spec_types[type]);
866            exit(0);
867        }
[2]868
[503]869        type = se->type;
870        offset = se->offset;
[124]871    }
[2]872
[503]873    // Check whether there is another entry pointing to the same
874    // file and offset, and return it as a shortcut.
[124]875    if (rm_dups)
876    {
[503]877        for (int i = 0; i < total; i++)
878            if (list[i].file_number == fn && list[i].offset == offset)
[124]879                return i;
880    }
[2]881
[503]882    int id = AllocId();
883
884    CHECK(id < total && list[id].file_number < 0);
885
886    list[id].file_number = fn;
887    list[id].last_access = -1;
888    list[id].data = NULL;
889    list[id].offset = offset;
890    list[id].type = type;
891
[124]892    return id;
[2]893}
894
895
[123]896void CacheList::normalize()
[2]897{
898  int j;
[123]899  CacheItem *ci=list;
[2]900  last_access=-1;
[494]901  for (j=0; j<total; j++,ci++)
[2]902  {
903    if (ci->last_access>=0)
904      ci->last_access=ci->last_access>>16;        // shift everything over by 16
905    if (ci->last_access>last_access)            //  and find new largest timestamp
906      last_access=ci->last_access;
907  }
908  last_access++;
909}
910
[123]911backtile *CacheList::backt(int id)
[2]912{
[123]913  CacheItem *me=list+id;
[2]914  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
915
[124]916  if (me->last_access>=0)
[2]917  {
918    touch(me);
919    return (backtile *)me->data;
920  }
921  else
922  {
923    touch(me);
924    locate(me);
925    me->data=(void *)new backtile(fp);
926    last_offset=fp->tell();
927    return (backtile *)me->data;
[124]928  }
[2]929}
930
931
[123]932foretile *CacheList::foret(int id)
[2]933{
[123]934  CacheItem *me=list+id;
[2]935  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
936
[124]937  if (me->last_access>=0)
[2]938  {
939    touch(me);
940    return (foretile *)me->data;
941  }
942  else
943  {
944    touch(me);
945    locate(me);
946    me->data=(void *)new foretile(fp);
947    last_offset=fp->tell();
948    return (foretile *)me->data;
[124]949  }
[2]950}
951
[123]952figure *CacheList::fig(int id)
[2]953{
[123]954  CacheItem *me=list+id;
[2]955//  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
[124]956  if (me->last_access>=0)
[2]957  {
958    touch(me);
959    return (figure *)me->data;
960  }
961  else
962  {
963    touch(me);
964    locate(me);
965    me->data=(void *)new figure(fp,me->type);
[503]966     last_offset=fp->tell();
[2]967    return (figure *)me->data;
[124]968  }
[2]969}
970
[123]971image *CacheList::img(int id)
[2]972{
[123]973  CacheItem *me=list+id;
[2]974  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
[124]975  if (me->last_access>=0)
[2]976  {
977    touch(me);
978    return (image *)me->data;
979  }
980  else
981  {
982    touch(me);                                           // hold me, feel me, be me!
983    locate(me);
984    image *im=new image(fp);
985    me->data=(void *)im;
986    last_offset=fp->tell();
987
988    return (image *)me->data;
[124]989  }
[2]990}
991
[123]992sound_effect *CacheList::sfx(int id)
[2]993{
[123]994  CacheItem *me=list+id;
[2]995  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
[124]996  if (me->last_access>=0)
[2]997  {
998    touch(me);                                           // hold me, feel me, be me!
999    return (sound_effect *)me->data;
1000  }
1001  else
1002  {
1003    touch(me);                                           // hold me, feel me, be me!
[123]1004    char *fn=crc_manager.get_filename(me->file_number);
[2]1005    me->data=(void *)new sound_effect(fn);
1006    return (sound_effect *)me->data;
[124]1007  }
[2]1008}
1009
1010
[123]1011part_frame *CacheList::part(int id)
[2]1012{
[123]1013  CacheItem *me=list+id;
[2]1014  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
[124]1015  if (me->last_access>=0)
[2]1016  {
1017    touch(me);                                           // hold me, feel me, be me!
1018    return (part_frame *)me->data;
1019  }
1020  else
1021  {
1022    touch(me);
1023    locate(me);
1024    me->data=(void *)new part_frame(fp);
1025    last_offset=fp->tell();
1026    return (part_frame *)me->data;
[124]1027  }
[2]1028}
1029
1030
[503]1031LObject *CacheList::lblock(int id)
[2]1032{
[123]1033  CacheItem *me=list+id;
[2]1034  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
[503]1035  return (LObject *)me->data;
[2]1036}
1037
[123]1038CacheList cache;
[2]1039
[123]1040void CacheList::free_oldest()
[2]1041{
[162]1042  int32_t old_time = last_access;
[123]1043  CacheItem *ci=list,*oldest=NULL;
[2]1044  ful=1;
1045
[162]1046  for (int i = 0; i < total; i++, ci++)
[2]1047  {
[162]1048    if (ci->data && ci->last_access < old_time)
[2]1049    {
[162]1050      oldest = ci;
1051      old_time = ci->last_access;
[2]1052    }
1053  }
1054  if (oldest)
1055  {
1056    dprintf("mem_maker : freeing %s\n",spec_types[oldest->type]);
[124]1057    unmalloc(oldest);
[2]1058  }
1059  else
1060  {
1061    close_graphics();
1062    printf("Out of memory, please remove any TSR's device drivers you can\n");
1063    exit(0);
[124]1064  }
[2]1065}
1066
1067
[123]1068void CacheList::show_accessed()
[2]1069{
1070  int old=last_access,new_old_accessed;
[123]1071  CacheItem *ci,*new_old;
[124]1072
[2]1073  do
1074  {
1075    new_old_accessed=-1;
1076    new_old=NULL;
1077    ci=list;
[494]1078    for (int i=0; i<total; i++,ci++)
[2]1079    {
[124]1080      if (ci->last_access<old && ci->last_access>0 && ci->last_access>new_old_accessed)
[2]1081      {
[124]1082    new_old_accessed=ci->last_access;
1083        new_old=ci;
[2]1084      }
1085    }
1086    if (new_old)
1087    {
1088      ci=new_old;
1089      old=ci->last_access;
1090      printf("type=(%20s) file=(%20s) access=(%6ld)\n",spec_types[ci->type],
[124]1091         crc_manager.get_filename(ci->file_number),
1092         (long int)ci->last_access);
[2]1093    }
1094  } while (new_old);
1095}
1096
[123]1097int CacheList::loaded(int id)
[2]1098{
[123]1099  CacheItem *me=list+id;
[2]1100  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
[124]1101  if (me->last_access>=0)
[2]1102    return 1;
1103  else return 0;
1104}
1105
[123]1106char_tint *CacheList::ctint(int id)
[2]1107{
[123]1108  CacheItem *me=list+id;
[2]1109  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id" && me->type==SPEC_PALETTE);
[124]1110  if (me->last_access>=0)
[2]1111  {
1112    touch(me);
1113    return (char_tint *)me->data;
1114  }
1115  else
1116  {
1117    touch(me);
1118    locate(me);
1119    me->data=(void *)new char_tint(fp);
1120    last_offset=fp->tell();
1121    return (char_tint *)me->data;
[124]1122  }
[2]1123}
1124
Note: See TracBrowser for help on using the repository browser.