source: abuse/branches/lol/src/cache.cpp @ 732

Last change on this file since 732 was 732, checked in by Sam Hocevar, 8 years ago

build: SDL2 compilation fixes.

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