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

Last change on this file since 494 was 494, checked in by Sam Hocevar, 10 years ago

style: remove trailing spaces, fix copyright statements.

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