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

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