home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 February / chip_20022115.iso / amiga / chipgame / scummvm_aga.lha / ScummVM_AGA / src / resource.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-01-05  |  21.3 KB  |  902 lines

  1. /* ScummVM - Scumm Interpreter
  2.  * Copyright (C) 2001  Ludvig Strigeus
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  *
  18.  * $Header: /cvsroot/scummvm/scummvm/resource.cpp,v 1.15 2001/11/09 18:54:14 strigeus Exp $
  19.  *
  20.  */
  21.  
  22. #include "stdafx.h"
  23. #include "scumm.h"
  24.  
  25. /* Open a room */
  26. void Scumm::openRoom(int room) {
  27.     uint room_offs;
  28.     char buf[256];
  29.  
  30.     //printf("openRoom()->debug(9...\n");
  31.     debug(9, "openRoom(%d)",room);
  32.     //printf("retour openRoom...\n");
  33.  
  34.     /* Don't load the same room again */
  35.     if (_lastLoadedRoom == room)
  36.         return;
  37.     _lastLoadedRoom = room;
  38.  
  39.     /* Room -1 means close file */
  40.     if (room==-1) {
  41.         _encbyte = 0;
  42.         deleteRoomOffsets();
  43.         fileClose(_fileHandle);
  44.         _fileHandle = NULL;
  45.         return;
  46.     }
  47.  
  48.     /* Either xxx.lfl or monkey.xxx file name */
  49.     while (!_resFilePrefix) {
  50. #if REAL_CODE
  51.         //printf("REALCODE\n");
  52.         room_offs = _roomFileOffsets[room];
  53. #else
  54.         //printf("not REALCODE\n");
  55.         room_offs = room ? _roomFileOffsets[room] : 0;
  56. #endif
  57.         
  58.         if (room_offs == 0xFFFFFFFF){
  59.             //printf("0xFFFFF->break\n");
  60.             break;
  61.           }
  62.         if (room_offs != 0 && room != 0) {
  63.             //printf("room_off !=0 &&...->return\n");
  64.             _fileOffset = _roomFileOffsets[room];
  65.             return;
  66.         }
  67.         //printf("sprintf exe_name,...\n");
  68.         // Original... sprintf(buf, "%s.%.3d", _exe_name,
  69.         sprintf(buf, "%s.%.3d", _exe_name,room==0 ? 0 : res.roomno[rtRoom][room]);
  70.  
  71.         _encbyte = 0x69;
  72.         //printf("openResourceFile(buf)\n");
  73.         if (openResourceFile(buf)) {
  74.             //printf("openED !!\n");
  75.             if (room==0)
  76.                 return;
  77.             readRoomsOffsets();
  78.             _fileOffset = _roomFileOffsets[room];
  79.  
  80.             if (_fileOffset != 8)
  81.                 return;
  82.  
  83.             error("Room %d not in %s", room, buf);
  84.             return;
  85.         }
  86.         //printf("Apres Boucle openRessource...\n");
  87.         askForDisk(buf);
  88.  
  89.     }
  90.     //printf("do{... 90\n");
  91.     do {
  92.         sprintf(buf, "%.3d.lfl", room);
  93.         _encbyte = 0;
  94.         //printf("openResourceFile(buf)... 94\n");
  95.         if (openResourceFile(buf))  {
  96.             //printf("break... 96\n");
  97.             break;
  98.         }
  99.         //printf("askfordisk... 99\n");
  100.         askForDisk(buf);
  101.     } while(1);
  102.     //printf("deleteroomoffsets... 102\n");
  103.     deleteRoomOffsets();
  104.     //printf("retour deleteRoom...104\n");
  105.     _fileOffset = 0; /* start of file */
  106.     //printf("Fin Loadroom()\n 106");
  107. }
  108.  
  109. /* Delete the currently loaded room offsets */
  110. void Scumm::deleteRoomOffsets() {
  111.     //printf("deleteroom 109\n");
  112.     if (!_dynamicRoomOffsets)
  113.         return;
  114.     //printf("For...113\n ");
  115.      for (int i=0; i<_maxRooms; i++) {
  116.         if (_roomFileOffsets[i]!=0xFFFFFFFF)
  117.             _roomFileOffsets[i] = 0;
  118.     }
  119.     //printf("Fin deleteRoomOffsets() 119\n");
  120. }
  121.  
  122. /* Read room offsets */
  123. void Scumm::readRoomsOffsets() {
  124.     int num,room;
  125.  
  126.     debug(9, "readRoomOffsets()");
  127.  
  128.     deleteRoomOffsets();
  129.     if (!_dynamicRoomOffsets)
  130.         return;
  131.     //printf("FileSeek...\n");
  132.     fileSeek(_fileHandle, 16, SEEK_SET);
  133.     //printf("FileReadByte()\n");
  134.     num = fileReadByte();
  135.     while (num) {
  136.         num--;
  137.         //printf("FileReadByte()\n");
  138.         room = fileReadByte();
  139.         if (_roomFileOffsets[room]!=0xFFFFFFFF) {
  140.             //printf("fileReadDwordLE()140...\n");
  141.             _roomFileOffsets[room] = fileReadDwordLE();
  142.         } else {
  143.             //printf("File... 143\n");
  144.             fileReadDwordLE();
  145.         }
  146.     }
  147. }
  148.  
  149. bool Scumm::openResourceFile(const char *filename) {
  150.     char buf[256];
  151.     
  152.     debug(9, "openResourceFile(%s)",filename);
  153.  
  154.     if (_resFilePath) {
  155.         sprintf(buf, "%s.%d\\%s", _resFilePath, _resFilePathId, filename);
  156.     } else if (_resFilePrefix) {
  157.         sprintf(buf, "%s%s", _resFilePrefix, filename);
  158.     } else {
  159.         strcpy(buf, filename);
  160.     }
  161.  
  162.     if (_fileHandle != NULL) {
  163.         fileClose(_fileHandle);
  164.         _fileHandle = NULL;
  165.     }
  166.  
  167.     _fileHandle = fileOpen(buf, 1);
  168.     
  169.     return _fileHandle != NULL;
  170. }
  171.  
  172. void Scumm::askForDisk(const char *filename) {
  173.     printf("(askfordisk)\n");
  174.     printf("Cannot find '%s'\n",filename);
  175.     error("Cannot find '%s'", filename);
  176. }
  177.  
  178. void Scumm::readIndexFileV5(int mode) {
  179.     uint32 blocktype,itemsize;
  180.     int numblock = 0;
  181. #if defined(SCUMM_BIG_ENDIAN)
  182.     int i;
  183. #endif
  184.  
  185.     //printf("Debug(9,...\n");
  186.     debug(9, "readIndexFile(%d)",mode);
  187.     //printf("retour Debug(9...\n");
  188.  
  189.     //printf("openRoom(-1)\n");
  190.     openRoom(-1);
  191.     //printf("Retour openRoom(-1)\n");
  192.  
  193.     //printf("openRoom(0)\n");
  194.     openRoom(0);
  195.     //printf("retour openRoom(1)\n");
  196.     
  197.     while (1) {
  198.         //printf("fileReadDword()\n");
  199.         blocktype = fileReadDword();
  200.         //printf("retour fileReadDword()\n");
  201.  
  202.         if (fileReadFailed(_fileHandle))
  203.             break;
  204.         itemsize = fileReadDwordBE();
  205.  
  206.         numblock++;
  207.  
  208.         switch(blocktype) {
  209.         case MKID('DCHR'):
  210.             readResTypeList(6,MKID('CHAR'),"charset");
  211.             break;
  212.  
  213.         case MKID('DOBJ'):
  214.             _numGlobalObjects = fileReadWordLE();
  215.             _objectFlagTable = (byte*)alloc(_numGlobalObjects);
  216.             if (mode==1) {
  217.                 fileSeek(_fileHandle, itemsize - 10, 1);
  218.                 break;
  219.             }
  220.  
  221.             _classData = (uint32*)alloc(_numGlobalObjects * sizeof(uint32));
  222.             fileRead(_fileHandle, _objectFlagTable, _numGlobalObjects);
  223.             fileRead(_fileHandle, _classData, _numGlobalObjects * sizeof(uint32));
  224. #if defined(SCUMM_BIG_ENDIAN)
  225.             for (i=0; i<_numGlobalObjects; i++)
  226.                 _classData[i] = FROM_LE_32(_classData[i]);
  227. #endif
  228.             break;
  229.  
  230.         case MKID('RNAM'):
  231.             fileSeek(_fileHandle, itemsize-8,1);
  232.             break;
  233.  
  234.         case MKID('DROO'):
  235.             readResTypeList(1,MKID('ROOM'),"room");
  236.             break;
  237.  
  238.         case MKID('DSCR'):
  239.             readResTypeList(2,MKID('SCRP'),"script");
  240.             break;
  241.  
  242.         case MKID('DCOS'):
  243.             readResTypeList(3,MKID('COST'),"costume");
  244.             break;
  245.  
  246.         case MKID('MAXS'):
  247.             fileReadWordLE();
  248.             fileReadWordLE();
  249.             fileReadWordLE();
  250.             fileReadWordLE();
  251.             fileReadWordLE();
  252.             fileReadWordLE();
  253.             fileReadWordLE();
  254.             fileReadWordLE();
  255.             fileReadWordLE();
  256.             break;
  257.  
  258.         case MKID('DSOU'):
  259.             readResTypeList(4,MKID('SOUN'),"sound");
  260.             break;
  261.  
  262.         default:
  263.             error("Bad ID %c%c%c%c found in directory!", blocktype&0xFF, blocktype>>8, blocktype>>16, blocktype>>24);
  264.             return;
  265.         }
  266.     }
  267.  
  268.     clearFileReadFailed(_fileHandle);
  269.  
  270.     if (numblock!=8)
  271.         error("Not enough blocks read from directory");
  272.  
  273.     openRoom(-1);
  274.     
  275.     _numGlobalScripts = _maxScripts;
  276.     _dynamicRoomOffsets = true;
  277. }
  278.  
  279. void Scumm::readIndexFileV6() {
  280.     uint32 blocktype,itemsize;
  281.     int numblock = 0;
  282.     int num, i;
  283.  
  284.     debug(9, "readIndexFile()");
  285.  
  286.     openRoom(-1);
  287.     openRoom(0);
  288.     
  289.     while (1) {
  290.         blocktype = fileReadDword();
  291.  
  292.         if (fileReadFailed(_fileHandle))
  293.             break;
  294.         itemsize = fileReadDwordBE();
  295.  
  296.         numblock++;
  297.  
  298.             switch(blocktype) {
  299.         case MKID('DCHR'):
  300.             readResTypeList(6,MKID('CHAR'),"charset");
  301.             break;
  302.  
  303.         case MKID('DOBJ'):
  304.              num = fileReadWordLE();
  305.              assert(num == _numGlobalObjects);
  306.             fileRead(_fileHandle, _objectFlagTable, num);
  307.             fileRead(_fileHandle, _classData, num * sizeof(uint32));
  308. #if defined(SCUMM_BIG_ENDIAN)
  309.             for (i=0; i<_numGlobalObjects; i++)
  310.                 _classData[i] = FROM_LE_32(_classData[i]);
  311. #endif
  312.             break;
  313.  
  314.         case MKID('RNAM'):
  315.             fileSeek(_fileHandle, itemsize-8,1);
  316.             break;
  317.  
  318.         case MKID('DROO'):
  319.             readResTypeList(1,MKID('ROOM'),"room");
  320.             break;
  321.  
  322.         case MKID('DSCR'):
  323.             readResTypeList(2,MKID('SCRP'),"script");
  324.             break;
  325.  
  326.         case MKID('DCOS'):
  327.             readResTypeList(3,MKID('COST'),"costume");
  328.             break;
  329.  
  330.         case MKID('MAXS'):
  331.             readMAXS();
  332.             break;
  333.  
  334.         case MKID('DSOU'):
  335.             readResTypeList(4,MKID('SOUN'),"sound");
  336.             break;
  337.  
  338.         case MKID('AARY'):
  339.             readArrayFromIndexFile();
  340.             break;
  341.  
  342.         default:
  343.             error("Bad ID %c%c%c%c found in directory!", blocktype&0xFF, blocktype>>8, blocktype>>16, blocktype>>24);
  344.             return;
  345.         }
  346.     }
  347.  
  348.     clearFileReadFailed(_fileHandle);
  349.  
  350.     if (numblock!=9)
  351.         error("Not enough blocks read from directory");
  352.  
  353.     openRoom(-1);
  354. }
  355.  
  356.  
  357. void Scumm::readArrayFromIndexFile() {
  358.     int num;
  359.     int a,b,c;
  360.  
  361.     while ((num = fileReadWordLE()) != 0) {
  362.         a = fileReadWordLE();
  363.         b = fileReadWordLE();
  364.         c = fileReadWordLE();
  365.         if (c==1)
  366.             defineArray(num, 1, a, b);
  367.         else
  368.             defineArray(num, 5, a, b);
  369.     }
  370. }
  371.  
  372. void Scumm::readResTypeList(int id, uint32 tag, const char *name) {
  373.     int num;
  374.     int i;
  375.     
  376.     debug(9, "readResTypeList(%d,%x,%s)",id,FROM_LE_32(tag),name);
  377.     
  378.     num = fileReadWordLE();
  379.  
  380.     if (_majorScummVersion == 6) {
  381.         if (num != res.num[id]) {
  382.             error("Invalid number of %ss (%d) in directory", name, num);    
  383.         }
  384.     } else {
  385.         if (num>=0xFF) {
  386.             error("Too many %ss (%d) in directory", name, num);
  387.         }
  388.         allocResTypeData(id, tag, num, name, 1);
  389.     }
  390.     
  391.     fileRead(_fileHandle, res.roomno[id], num*sizeof(uint8));
  392.     fileRead(_fileHandle, res.roomoffs[id], num*sizeof(uint32));
  393.  
  394. #if defined(SCUMM_BIG_ENDIAN)
  395.     for (i=0; i<num; i++)
  396.         res.roomoffs[id][i] = FROM_LE_32(res.roomoffs[id][i]);
  397. #endif
  398. }
  399.  
  400.  
  401. void Scumm::allocResTypeData(int id, uint32 tag, int num, const char *name, int mode) {
  402.     debug(9, "allocResTypeData(%d,%x,%d,%s,%d)",id,FROM_LE_32(tag),num,name,mode);
  403.     assert(id>=0 && id<sizeof(res.mode)/sizeof(res.mode[0]));
  404.  
  405.     if (num>=512) {
  406.         error("Too many %ss (%d) in directory", name, num);
  407.     }
  408.  
  409.     res.mode[id] = mode;
  410.     res.num[id] = num;
  411.     res.tags[id] = tag;
  412.     res.name[id] = name;
  413.     res.address[id] = (byte**)alloc(num*sizeof(void*));
  414.     res.flags[id] = (byte*)alloc(num*sizeof(byte));
  415.  
  416.     if (mode) {
  417.         res.roomno[id] = (byte*)alloc(num*sizeof(byte));
  418.         res.roomoffs[id] = (uint32*)alloc(num*sizeof(uint32));
  419.     }
  420. }
  421.  
  422. void Scumm::loadCharset(int no) {
  423.     int i;
  424.     byte *ptr;
  425.  
  426.     debug(9, "loadCharset(%d)",no);
  427.  
  428.     checkRange(_maxCharsets-1, 1, no, "Loading illegal charset %d");
  429. //    ensureResourceLoaded(6, no);
  430.     ptr = getResourceAddress(6, no);
  431.  
  432.     for (i=0; i<15; i++) {
  433.         _charsetData[no][i+1] = ptr[i+14];
  434.     }
  435. }
  436.  
  437. void Scumm::nukeCharset(int i) {
  438.     checkRange(_maxCharsets-1, 1, i, "Nuking illegal charset %d");
  439.     nukeResource(rtCharset, i);
  440. }
  441.  
  442. void Scumm::ensureResourceLoaded(int type, int i) {
  443.     void *addr;
  444.  
  445.     debug(9, "ensureResourceLoaded(%d,%d)", type, i);
  446.  
  447.     if (type==1 && i>127) {
  448.         i = _resourceMapper[i&127];
  449.     }
  450.  
  451.     if (i==0)
  452.         return;
  453.  
  454.     addr = res.address[type][i];
  455.     if (addr)
  456.         return;
  457.  
  458.     loadResource(type, i);
  459.  
  460.     if (type==1 && i==_roomResource)
  461.         _vars[VAR_ROOM_FLAG] = 1;
  462. }
  463.  
  464. int Scumm::loadResource(int type, int index) {
  465.     int roomNr, i;
  466.     uint32 fileOffs;
  467.     uint32 size, tag;
  468.     
  469.     debug(9, "loadResource(%d,%d)", type,index);
  470.  
  471.     roomNr = getResourceRoomNr(type, index);
  472.     if (roomNr == 0 || index >= res.num[type]) {
  473.         error("%s %d undefined", 
  474.             res.name[type],index);
  475.     }
  476.  
  477.     if (type==1) {
  478.         fileOffs = 0;
  479.     } else {
  480.         fileOffs = res.roomoffs[type][index];
  481.         if (fileOffs==0xFFFFFFFF)
  482.             return 0;
  483.     }
  484.         
  485.     do {
  486.         for (i=0; i<5; i++) {
  487.             openRoom(roomNr);
  488.  
  489.             fileSeek(_fileHandle, fileOffs + _fileOffset, SEEK_SET);
  490.             if (type==4) {
  491.                 fileReadDwordLE();
  492.                 fileReadDwordLE();
  493.                 return readSoundResource(type, index);
  494.             }
  495.             
  496.             tag = fileReadDword();
  497.  
  498.             if (tag != res.tags[type]) {
  499.                 error("%s %d not in room %d at %d+%d", 
  500.                     res.name[type], type, roomNr, _fileOffset, fileOffs);
  501.             }
  502.  
  503.             size = fileReadDwordBE();
  504.             fileSeek(_fileHandle, -8, SEEK_CUR);
  505.  
  506.             fileRead(_fileHandle, createResource(type, index, size), size);
  507.  
  508.             /* dump the resource */
  509. #ifdef DUMP_SCRIPTS
  510.             if(type==2) {
  511.                 dumpResource("script-", index, getResourceAddress(rtScript, index));
  512.             }
  513. #endif
  514.  
  515.             if (!fileReadFailed(_fileHandle)) {
  516.                 return 1;
  517.             }
  518.  
  519.             nukeResource(type, index);
  520.         }
  521.  
  522.         error("Cannot read resource");
  523.     } while(1);
  524. }
  525.  
  526. int Scumm::readSoundResource(int type, int index) {
  527.     uint32 resStart, size, tag, size2;
  528.     byte *ptr;
  529.     int i;
  530.  
  531.     debug(9, "readSoundResource(%d,%d)", type, index);
  532.  
  533.     resStart = 0;
  534.  
  535.     fileReadDwordLE();
  536.     size = fileReadDwordBE();
  537.  
  538.     while (size>resStart) {
  539.         tag = fileReadDword();
  540.         size2 = fileReadDwordBE();
  541.         
  542.         resStart += size2 + 8;
  543.         
  544.         for (i=0,ptr=_soundTagTable; i<_numSoundTags; i++,ptr+=4) {
  545. /* endian OK, tags are in native format */
  546.             if (READ_UINT32_UNALIGNED(ptr) == tag) {
  547.                 fileSeek(_fileHandle, -8, SEEK_CUR);
  548.                 fileRead(_fileHandle,createResource(type, index, size2+8), size2+8);
  549.                 return 1;
  550.             }
  551.         }
  552.  
  553.         fileSeek(_fileHandle, size2, SEEK_CUR);
  554.     }
  555.  
  556.     res.roomoffs[type][index] = 0xFFFFFFFF;
  557.     return 0;
  558. }
  559.  
  560. int Scumm::getResourceRoomNr(int type, int index) {
  561.     if (type==1)
  562.         return index;
  563.     return res.roomno[type][index];
  564. }
  565.  
  566. byte *Scumm::getResourceAddress(int type, int index) {
  567.     byte *ptr;
  568.     //printf("debug...\n");
  569.     debug(9, "getResourceAddress(%d,%d)", type, index);
  570.     //printf("CHECK_HEAP ??\n");
  571.     CHECK_HEAP
  572.     //printf("validateress..\n");
  573.     validateResource("getResourceAddress", type, index);
  574.     
  575.     if (res.mode[type] && !res.address[type][index]) {
  576.         //printf("Ensure...\n");
  577.         ensureResourceLoaded(type, index);
  578.     }    
  579.     //printf("setresscounter\n");
  580.     setResourceCounter(type, index, 1);
  581.  
  582.     ptr=(byte*)res.address[type][index];
  583.     if (!ptr)
  584.         return NULL;
  585.  
  586.     return ptr + sizeof(ResHeader);
  587. }
  588.  
  589. byte *Scumm::getStringAddress(int i) {
  590.     //printf("ress: getresor addr()\n");
  591.     byte *b = getResourceAddress(rtString, i);
  592.     //printf("retour getress\n");
  593.     if (!b)
  594.         return b;
  595.     
  596.     if (_majorScummVersion==6)
  597.         return ((ArrayHeader*)b)->data;
  598.     return b;
  599. }
  600.  
  601. void Scumm::setResourceCounter(int type, int index, byte flag) {
  602.     res.flags[type][index] &= 0x80;
  603.     res.flags[type][index] |= flag;
  604. }
  605.  
  606. /* 2 bytes safety area to make "precaching" of bytes in the gdi drawer easier */
  607. #define SAFETY_AREA 2
  608.  
  609. byte *Scumm::createResource(int type, int index, uint32 size) {
  610.     byte *ptr;
  611.  
  612.     CHECK_HEAP
  613.  
  614.     debug(9, "createResource(%d,%d,%d)", type, index,size);
  615.  
  616.     if (size > 65536*4+37856)
  617.         error("Invalid size allocating");
  618.  
  619.     validateResource("allocating", type, index);
  620.     nukeResource(type, index);
  621.  
  622.     expireResources(size);
  623.  
  624.     CHECK_HEAP
  625.     
  626.     ptr = (byte*)alloc(size + sizeof(ResHeader) + SAFETY_AREA);
  627.     if (ptr==NULL) {
  628.         error("Out of memory while allocating %d", size);
  629.     }
  630.  
  631.     _allocatedSize += size;
  632.  
  633.     res.address[type][index] = ptr;
  634.     ((ResHeader*)ptr)->size = size;
  635.     setResourceCounter(type, index, 1);
  636.     return ptr + sizeof(ResHeader); /* skip header */
  637. }
  638.  
  639. void Scumm::validateResource(const char *str, int type, int index) {
  640.     if (type<1 || type>16 || index<0 || index >= res.num[type]) {
  641.         printf("%d Illegal Glob type %d num %d", str, type, index);
  642.         error("%d Illegal Glob type %d num %d", str, type, index);
  643.     }
  644. }
  645.  
  646. void Scumm::nukeResource(int type, int index) {
  647.     byte *ptr;
  648.  
  649.     debug(9, "nukeResource(%d,%d)", type, index);
  650.  
  651.     CHECK_HEAP
  652.     assert( res.address[type] );
  653.     assert( index>=0 && index < res.num[type]);
  654.  
  655.     if ((ptr = res.address[type][index]) != NULL) {
  656.         res.address[type][index] = 0;
  657.         res.flags[type][index] = 0;
  658.         _allocatedSize -= ((ResHeader*)ptr)->size;
  659.         free(ptr);
  660.     }
  661. }
  662.  
  663. byte *findResource(uint32 tag, byte *searchin, int index) {
  664.     uint32 maxsize,curpos,totalsize,size;
  665.  
  666.     searchin += 4;
  667.     totalsize = READ_BE_UINT32_UNALIGNED(searchin);
  668.     curpos = 8;
  669.     searchin += 4;
  670.  
  671.     while (curpos<totalsize) {
  672.         if (READ_UINT32_UNALIGNED(searchin)==tag && !index--)
  673.             return searchin;
  674.  
  675.         size = READ_BE_UINT32_UNALIGNED(searchin+4);
  676.         if ((int32)size <= 0) {
  677.             error("(%c%c%c%c) Not found in %d... illegal block len %d", 
  678.                 tag&0xFF,(tag>>8)&0xFF,(tag>>16)&0xFF,(tag>>24)&0xFF,
  679.                 0,
  680.                 size);
  681.             return NULL;
  682.         }
  683.  
  684.         curpos += size;
  685.         searchin += size;
  686.     } 
  687.  
  688.     return NULL;
  689. }
  690.  
  691. void Scumm::lock(int type, int i) {
  692.     validateResource("Locking", type, i);
  693.     res.flags[type][i] |= 0x80;
  694.  
  695. //    debug(1, "locking %d,%d", type, i);
  696. }
  697.  
  698. void Scumm::unlock(int type, int i) {
  699.     validateResource("Unlocking", type, i);
  700.     res.flags[type][i] &= ~0x80;
  701.  
  702. //    debug(1, "unlocking %d,%d", type, i);
  703. }
  704.  
  705. bool Scumm::isResourceInUse(int type, int i) {
  706.     validateResource("isResourceInUse", type, i);
  707.     switch(type) {
  708.     case rtRoom:
  709.         return _roomResource == (byte)i;
  710.     case rtScript:
  711.         return isScriptInUse(i);
  712.     case rtCostume:
  713.         return isCostumeInUse(i);
  714.     case rtSound:
  715.         return isSoundRunning(i)!=0;
  716.     default:
  717.         return false;
  718.     }
  719. }
  720.  
  721. void Scumm::increaseResourceCounter() {
  722.     int i,j;
  723.     byte counter;
  724.  
  725.     for (i=1; i<=16; i++) {
  726.         for(j=res.num[i]; --j>=0;) {
  727.             counter = res.flags[i][j] & 0x7F;
  728.             if (counter && counter < 0x7F) {
  729.                 setResourceCounter(i, j, counter+1);
  730.             }
  731.         }
  732.     }
  733. }
  734.  
  735. void Scumm::expireResources(uint32 size) {
  736.     int i,j;
  737.     byte flag;
  738.     byte best_counter;
  739.     int best_type, best_res;
  740.     uint32 oldAllocatedSize;
  741.  
  742.     if (_expire_counter != 0xFF) {
  743.         _expire_counter = 0xFF;
  744.         increaseResourceCounter();
  745.     }
  746.  
  747.     if (size + _allocatedSize < _maxHeapThreshold)
  748.         return;
  749.  
  750.     oldAllocatedSize = _allocatedSize;
  751.  
  752.     do {
  753.         best_type = 0;
  754.         best_counter = 2;
  755.  
  756.         for (i=1; i<=16; i++)
  757.             if (res.mode[i]) {
  758.                 for(j=res.num[i]; --j>=0;) {
  759.                     flag = res.flags[i][j];
  760.                     if (!(flag&0x80) && flag >= best_counter && !isResourceInUse(i,j)) {
  761.                         best_counter = flag;
  762.                         best_type = i;
  763.                         best_res = j;
  764.                     }
  765.                 }
  766.             }
  767.  
  768.         if (!best_type)
  769.             break;
  770.         nukeResource(best_type, best_res);
  771.     } while (size + _allocatedSize > _minHeapThreshold);
  772.  
  773.     increaseResourceCounter();
  774.  
  775.     debug(1, "Expired resources, mem %d -> %d", oldAllocatedSize, _allocatedSize);
  776. }
  777.  
  778. void Scumm::freeResources() {
  779.     int i,j;
  780.     for (i=1; i<=16; i++) {
  781.         for(j=res.num[i]; --j>=0;) {
  782.             if (isResourceLoaded(i,j))
  783.                 nukeResource(i,j);
  784.         }
  785.         free(res.address[i]);
  786.         free(res.flags[i]);
  787.         free(res.roomno[i]);
  788.         free(res.roomoffs[i]);
  789.     }
  790. }
  791.  
  792. void Scumm::loadPtrToResource(int type, int resindex, byte *source) {
  793.     byte *ptr, *alloced;
  794.     int i,len;
  795.  
  796.     nukeResource(type, resindex);
  797.  
  798.     len = getStringLen(source);
  799.  
  800.     if (len <= 1)
  801.         return;
  802.  
  803.     alloced = createResource(type, resindex, len);
  804.  
  805.     if (!source) {
  806.         alloced[0] = fetchScriptByte();
  807.         for (i=1; i<len; i++)
  808.             alloced[i] = *_scriptPointer++;
  809.     } else {
  810.         for(i=0; i<len; i++)
  811.             alloced[i] = source[i];
  812.     }
  813. }
  814.  
  815. bool Scumm::isResourceLoaded(int type, int index) {
  816.     validateResource("isLoaded", type, index);
  817.     return res.address[type][index] != NULL;
  818. }
  819.  
  820. void Scumm::resourceStats() {
  821.     int i,j;
  822.     uint32 lockedSize = 0, lockedNum = 0;
  823.     byte flag;
  824.     
  825.     for (i=1; i<=16; i++)
  826.         for(j=res.num[i]; --j>=0;) {
  827.             flag = res.flags[i][j];
  828.             if (flag&0x80 && res.address[i][j]) {
  829.                 lockedSize += ((ResHeader*)res.address[i][j])->size;
  830.                 lockedNum++;
  831.             }
  832.         }
  833.     
  834.     printf("Total allocated size=%d, locked=%d(%d)\n", _allocatedSize, lockedSize, lockedNum);
  835. }
  836.  
  837. void Scumm::heapClear(int mode) {
  838.     /* TODO: implement this */
  839.     warning("heapClear: not implemented");
  840. }
  841.  
  842. void Scumm::unkHeapProc2(int a, int b) {
  843.     warning("unkHeapProc2: not implemented");
  844.  
  845. void Scumm::loadFlObject(int a, int b) {
  846.     warning("loadFlObject(%d,%d):not implemented", a, b);
  847. }
  848.  
  849. void Scumm::readMAXS() {
  850.     _numVariables = fileReadWordLE();
  851.     fileReadWordLE();
  852.     _numBitVariables = fileReadWordLE();
  853.     _numLocalObjects = fileReadWordLE();
  854.     _numArray = fileReadWordLE();
  855.     fileReadWordLE();
  856.     _numVerbs = fileReadWordLE();
  857.     _numFlObject = fileReadWordLE();
  858.     _numInventory = fileReadWordLE();
  859.     _numRooms = fileReadWordLE();
  860.     _numScripts = fileReadWordLE();
  861.     _numSounds = fileReadWordLE();
  862.     _numCharsets = fileReadWordLE();
  863.     _numCostumes = fileReadWordLE();
  864.     _numGlobalObjects = fileReadWordLE();
  865.  
  866.     allocResTypeData(rtCostume, MKID('COST'), _numCostumes, "costume", 1);
  867.     allocResTypeData(rtRoom, MKID('ROOM'), _numRooms, "room", 1);
  868.     allocResTypeData(rtSound, MKID('SOUN'), _numSounds, "sound", 1);
  869.     allocResTypeData(rtScript, MKID('SCRP'), _numScripts, "script", 1);
  870.     allocResTypeData(rtCharset, MKID('CHAR'), _numCharsets, "charset", 1);
  871.     allocResTypeData(rtObjectName, MKID('NONE'),50,"new name", 0);
  872.     
  873.     allocateArrays();
  874.  
  875.     _objectFlagTable = (byte*)alloc(_numGlobalObjects);
  876.     _arrays = (byte*)alloc(_numArray);
  877.     _newNames = (uint16*)alloc(50 * sizeof(uint16));
  878.     _classData = (uint32*)alloc(_numGlobalObjects * sizeof(uint32));
  879.  
  880.     _numGlobalScripts = 200;
  881.     _dynamicRoomOffsets = 1;
  882. }
  883.  
  884. void Scumm::allocateArrays() {
  885.     _inventory = (uint16*)alloc(_numInventory * sizeof(uint16));
  886.     _verbs = (VerbSlot*)alloc(_numVerbs * sizeof(VerbSlot));
  887.     _objs = (ObjectData*)alloc(_numLocalObjects * sizeof(ObjectData));
  888.     _vars = (int16*)alloc(_numVariables * sizeof(int16));
  889.     _bitVars = (byte*)alloc(_numBitVariables >> 3);
  890.  
  891.     allocResTypeData(rtInventory, MKID('NONE'),    _numInventory, "inventory", 0);
  892.     allocResTypeData(rtTemp,MKID('NONE'),10, "temp", 0);
  893.     allocResTypeData(rtScaleTable,MKID('NONE'),5, "scale table", 0);
  894.     allocResTypeData(rtActorName, MKID('NONE'),13,"actor name", 0);
  895.     allocResTypeData(rtBuffer, MKID('NONE'),10,"buffer", 0);
  896.      allocResTypeData(rtVerb, MKID('NONE'),_numVerbs,"verb", 0);
  897.     allocResTypeData(rtString, MKID('NONE'),_numArray,"array", 0);
  898.     allocResTypeData(rtFlObject, MKID('NONE'),_numFlObject,"flobject", 0);
  899.     allocResTypeData(rtMatrix, MKID('NONE'),10,"boxes", 0);
  900. }
  901.