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

Last change on this file since 492 was 492, checked in by Sam Hocevar, 12 years ago

lisp: rename core classes to slightly shorter names (LispObject? -> LObject).

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