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

Last change on this file since 506 was 506, checked in by Sam Hocevar, 11 years ago

cache: get rid of more Lisp cache code.

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