diff options
author | Ludvig Strigeus | 2001-10-09 14:30:12 +0000 |
---|---|---|
committer | Ludvig Strigeus | 2001-10-09 14:30:12 +0000 |
commit | c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e (patch) | |
tree | 192b56f3908880c5a513a366f616341bcb47056e /resource.cpp | |
download | scummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.tar.gz scummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.tar.bz2 scummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.zip |
Initial revision
svn-id: r3408
Diffstat (limited to 'resource.cpp')
-rw-r--r-- | resource.cpp | 647 |
1 files changed, 647 insertions, 0 deletions
diff --git a/resource.cpp b/resource.cpp new file mode 100644 index 0000000000..603311b951 --- /dev/null +++ b/resource.cpp @@ -0,0 +1,647 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Change Log: + * $Log$ + * Revision 1.1 2001/10/09 14:30:14 strigeus + * Initial revision + * + * + */ + +#include "stdafx.h" +#include "scumm.h" + +/* Open a room */ +void Scumm::openRoom(int room) { + uint room_offs; + char buf[256]; + + debug(9, "openRoom(%d)",room); + + /* Don't load the same room again */ + if (_lastLoadedRoom == room) + return; + _lastLoadedRoom = room; + + /* Room -1 means close file */ + if (room==-1) { + _encbyte = 0; + deleteRoomOffsets(); + fileClose(_fileHandle); + _fileHandle = NULL; + return; + } + + /* Either xxx.lfl or monkey.xxx file name */ + while (!_resFilePrefix) { +#if REAL_CODE + room_offs = _roomFileOffsets[room]; +#else + room_offs = room ? _roomFileOffsets[room] : 0; +#endif + + if (room_offs == 0xFFFFFFFF) + break; + + if (room_offs != 0 && room != 0) { + _fileOffset = _roomFileOffsets[room]; + return; + } + if (room==0) { + sprintf(buf, "%s.000", _exe_name); + } else { + sprintf(buf, "%s.%.3d", _exe_name, res.roomno[1][room]); + } + _encbyte = 0x69; + if (openResourceFile(buf)) { + if (room==0) + return; + readRoomsOffsets(); + _fileOffset = _roomFileOffsets[room]; + + if (_fileOffset != 8) + return; + + error("Room %d not in %s", room, buf); + return; + } + askForDisk(); + } + + do { + sprintf(buf, "%.3d.lfl", room); + _encbyte = 0; + if (openResourceFile(buf)) + break; + askForDisk(); + } while(1); + + deleteRoomOffsets(); + _fileOffset = 0; /* start of file */ +} + +/* Delete the currently loaded room offsets */ +void Scumm::deleteRoomOffsets() { + if (!_dynamicRoomOffsets) + return; + + for (int i=0; i<_maxRooms; i++) { + if (_roomFileOffsets[i]!=0xFFFFFFFF) + _roomFileOffsets[i] = 0; + } +} + +/* Read room offsets */ +void Scumm::readRoomsOffsets() { + int num,room; + + debug(9, "readRoomOffsets()"); + + deleteRoomOffsets(); + if (!_dynamicRoomOffsets) + return; + + fileSeek(_fileHandle, 16, SEEK_SET); + + num = fileReadByte(); + while (num) { + num--; + + room = fileReadByte(); + if (_roomFileOffsets[room]!=0xFFFFFFFF) { + _roomFileOffsets[room] = fileReadDwordLE(); + } else { + fileReadDwordLE(); + } + } +} + +bool Scumm::openResourceFile(const char *filename) { + char buf[256]; + + debug(9, "openResourceFile(%s)",filename); + + if (_resFilePath) { + sprintf(buf, "%s.%d\\%s", _resFilePath, _resFilePathId, filename); + } else if (_resFilePrefix) { + sprintf(buf, "%s%s", _resFilePrefix, filename); + } else { + strcpy(buf, filename); + } + + if (_fileHandle != NULL) { + fileClose(_fileHandle); + _fileHandle = NULL; + } + + _fileHandle = fileOpen(buf, 1); + + return _fileHandle != NULL; +} + +void Scumm::askForDisk() { + /* TODO: Not yet implemented */ + error("askForDisk: not yet implemented"); +} + + +void Scumm::readIndexFile(int mode) { + uint32 blocktype,itemsize; + int numblock = 0; +#if defined(SCUMM_BIG_ENDIAN) + int i; +#endif + + debug(9, "readIndexFile(%d)",mode); + + openRoom(-1); + openRoom(0); + + while (1) { + blocktype = fileReadDword(); + + if (fileReadFailed(_fileHandle)) + break; + itemsize = fileReadDwordBE(); + + numblock++; + + switch(blocktype) { + case MKID('DCHR'): + readResTypeList(6,MKID('CHAR'),"charset"); + break; + + case MKID('DOBJ'): + _maxNrObjects = fileReadWordLE(); + _objectFlagTable = (byte*)alloc(_maxNrObjects); + if (mode==1) { + fileSeek(_fileHandle, itemsize - 10, 1); + break; + } + + _classData = (uint32*)alloc(_maxNrObjects * sizeof(uint32)); + fileRead(_fileHandle, _objectFlagTable, _maxNrObjects); + fileRead(_fileHandle, _classData, _maxNrObjects * sizeof(uint32)); +#if defined(SCUMM_BIG_ENDIAN) + for (i=0; i<_maxNrObjects; i++) + _classData[i] = FROM_LE_32(_classData[i]); +#endif + break; + + case MKID('RNAM'): + fileSeek(_fileHandle, itemsize-8,1); + break; + + case MKID('DROO'): + readResTypeList(1,MKID('ROOM'),"room"); + break; + + case MKID('DSCR'): + readResTypeList(2,MKID('SCRP'),"script"); + break; + + case MKID('DCOS'): + readResTypeList(3,MKID('COST'),"costume"); + break; + + case MKID('MAXS'): + fileReadWordLE(); + fileReadWordLE(); + fileReadWordLE(); + fileReadWordLE(); + fileReadWordLE(); + fileReadWordLE(); + fileReadWordLE(); + fileReadWordLE(); + fileReadWordLE(); + break; + + case MKID('DSOU'): + readResTypeList(4,MKID('SOUN'),"sound"); + break; + + default: + error("Bad ID %c%c%c%c found in directory!", blocktype&0xFF, blocktype>>8, blocktype>>16, blocktype>>24); + return; + } + } + + clearFileReadFailed(_fileHandle); + + if (numblock!=8) + error("Not enough blocks read from directory"); + + openRoom(-1); + + _numGlobalScriptsUsed = _maxScripts; + _dynamicRoomOffsets = true; +} + +void Scumm::readResTypeList(int id, uint32 tag, const char *name) { + int num; +#if defined(SCUMM_BIG_ENDIAN) + int i; +#endif + + debug(9, "readResTypeList(%d,%x,%s)",id,FROM_LE_32(tag),name); + + num = fileReadWordLE(); + + if (num>0xFF) { + error("Too many %ss (%d) in directory", name, num); + } + + allocResTypeData(id, tag, num, name, 1); + + fileRead(_fileHandle, res.roomno[id], num); + fileRead(_fileHandle, res.roomoffs[id], num*sizeof(uint32)); + +#if defined(SCUMM_BIG_ENDIAN) + for (i=0; i<num; i++) + res.roomoffs[id][i] = FROM_LE_32(res.roomoffs[id][i]); +#endif +} + +void Scumm::allocResTypeData(int id, uint32 tag, int num, const char *name, int mode) { + debug(9, "allocResTypeData(%d,%x,%d,%s,%d)",id,FROM_LE_32(tag),num,name,mode); + res.mode[id] = mode; + res.num[id] = num; + res.tags[id] = tag; + res.name[id] = name; + res.address[id] = (byte**)alloc(num*sizeof(void*)); + res.flags[id] = (byte*)alloc(num*sizeof(byte)); + + if (mode) { + res.roomno[id] = (byte*)alloc(num*sizeof(byte)); + res.roomoffs[id] = (uint32*)alloc(num*sizeof(uint32)); + } +} + +void Scumm::loadCharset(int no) { + int i; + byte *ptr; + + debug(9, "loadCharset(%d)",no); + + checkRange(_maxCharsets-1, 1, no, "Loading illegal charset %d"); + ensureResourceLoaded(6, no); + ptr = getResourceAddress(6, no); + + for (i=0; i<15; i++) { + _charsetData[no][i+1] = ptr[i+14]; + } +} + +void Scumm::nukeCharset(int i) { + checkRange(_maxCharsets-1, 1, i, "Nuking illegal charset %d"); + nukeResource(6, i); +} + +void Scumm::ensureResourceLoaded(int type, int i) { + void *addr; + + debug(9, "ensureResourceLoaded(%d,%d)", type, i); + + if (type==1 && i>127) { + i = _resourceMapper[i&127]; + } + + if (i==0) + return; + + addr = res.address[type][i]; + if (addr) + return; + + loadResource(type, i); + + if (type==1 && i==_roomResource) + vm.vars[VAR_ROOM_FLAG] = 1; +} + +int Scumm::loadResource(int type, int index) { + int roomNr, i; + uint32 fileOffs; + uint32 size, tag; + + debug(9, "loadResource(%d,%d)", type,index); + + roomNr = getResourceRoomNr(type, index); + if (roomNr == 0 || index >= res.num[type]) { + error("%s %d undefined", + res.name[type],index); + } + + if (type==1) { + fileOffs = 0; + } else { + fileOffs = res.roomoffs[type][index]; + if (fileOffs==0xFFFFFFFF) + return 0; + } + + do { + for (i=0; i<5; i++) { + _resIndexToLoad = index; + _resTypeToLoad = type; + openRoom(roomNr); + + fileSeek(_fileHandle, fileOffs + _fileOffset, SEEK_SET); + if (type==4) { + fileReadDwordLE(); + fileReadDwordLE(); + return readSoundResource(type, index); + } + + tag = fileReadDword(); + + if (tag != res.tags[type]) { + error("%s %d not in room %d at %d+%d", + res.name[type], type, roomNr, _fileOffset, fileOffs); + } + + size = fileReadDwordBE(); + fileSeek(_fileHandle, -8, SEEK_CUR); + + fileRead(_fileHandle, createResource(type, index, size), size); + + /* dump the resource */ +#ifdef DUMP_SCRIPTS + if(type==2) { + dumpResource("script-", index, getResourceAddress(2, index)); + } +#endif + + if (!fileReadFailed(_fileHandle)) { + _scummTimer = 0; + return 1; + } + + nukeResource(type, index); + } + + error("Cannot read resource"); + } while(1); +} + +int Scumm::readSoundResource(int type, int index) { + uint32 resStart, size, tag, size2; + byte *ptr; + int i; + + debug(9, "readSoundResource(%d,%d)", type, index); + + resStart = 0; + + fileReadDwordLE(); + size = fileReadDwordBE(); + + while (size>resStart) { + tag = fileReadDword(); + size2 = fileReadDwordBE(); + + resStart += size2 + 8; + + for (i=0,ptr=_soundTagTable; i<_numSoundTags; i++,ptr+=5) { +/* endian OK, tags are in native format */ + if (READ_UINT32_UNALIGNED(ptr) == tag) { + fileSeek(_fileHandle, -8, SEEK_CUR); + fileRead(_fileHandle,createResource(type, index, size2+8), size+8); + return 1; + } + } + + fileSeek(_fileHandle, size2, SEEK_CUR); + } + + res.roomoffs[type][index] = 0xFFFFFFFF; + return 0; +} + + +int Scumm::getResourceRoomNr(int type, int index) { + if (type==1) + return index; + return res.roomno[type][index]; +} + +byte *Scumm::getResourceAddress(int type, int index) { + byte *ptr; + + debug(9, "getResourceAddress(%d,%d)", type, index); + + checkHeap(); + + validateResource("getResourceAddress", type, index); + + if (res.mode[type] && !res.address[type][index]) { + ensureResourceLoaded(type, index); + } + + setResourceFlags(type, index, 1); + + ptr=(byte*)res.address[type][index]; + if (!ptr) + return NULL; + + return ptr + 8; +} + +void Scumm::setResourceFlags(int type, int index, byte flag) { + res.flags[type][index] &= 0x80; + res.flags[type][index] |= flag; +} + +byte *Scumm::createResource(int type, int index, uint32 size) { + byte *ptr; + + checkHeap(); + + debug(9, "createResource(%d,%d,%d)", type, index,size); + + if (size > 65536*4+37856) + error("Invalid size allocating"); + + validateResource("allocating", type, index); + nukeResource(type, index); + + ptr = (byte*)alloc(size + 8); + if (ptr==NULL) { + error("Out of memory while allocating %d", size); + } + + res.address[type][index] = ptr; + + setResourceFlags(type, index, 1); + + return ptr + 8; /* skip header */ +} + +void Scumm::validateResource(const char *str, int type, int index) { + if (type<1 || type>15 || index<0 || index >= res.num[type]) { + error("%d Illegal Glob type %d num %d", str, type, index); + } +} + +void Scumm::nukeResource(int type, int index) { + + debug(9, "nukeResource(%d,%d)", type, index); + + checkHeap(); + assert( res.address[type] ); + assert( index>=0 && index < res.num[type]); + + if (res.address[type][index]) { + free(res.address[type][index]); + res.address[type][index] = 0; + } +} + +void Scumm::unkResourceProc() { + int i; + for (i=1; i<16; i++) { + } + /* TODO: not implemented */ + warning("unkResourceProc: not implemented"); +} + + +byte *Scumm::findResource(uint32 tag, byte *searchin) { + uint32 size; + + if (searchin) { + searchin+=4; + _findResSize = READ_BE_UINT32_UNALIGNED(searchin); + _findResHeaderSize = 8; + _findResPos = searchin+4; + goto startScan; + } + + do { + size = READ_BE_UINT32_UNALIGNED(_findResPos+4); + if ((int32)size <= 0) { + error("(%c%c%c%c) Not found in %d... illegal block len %d", + tag&0xFF,(tag>>8)&0xFF,(tag>>16)&0xFF,(tag>>24)&0xFF, + 0, + size); + return NULL; + } + _findResHeaderSize += size; + _findResPos += size; + +startScan:; + if (_findResHeaderSize >= _findResSize) + return NULL; +/* endian OK, tags are in native format */ + } while (READ_UINT32_UNALIGNED(_findResPos) != tag); + + return _findResPos; +} + +byte *Scumm::findResource2(uint32 tag, byte *searchin) { + uint32 size; + + if (searchin) { + searchin+=4; + _findResSize2 = READ_BE_UINT32_UNALIGNED(searchin); + _findResHeaderSize2 = 8; + _findResPos2 = searchin+4; + goto startScan; + } + + do { + size = READ_BE_UINT32_UNALIGNED(_findResPos2+4); + if ((int32)size <= 0) { + error("(%c%c%c%c) Not found in %d... illegal block len %d", + tag&0xFF,(tag>>8)&0xFF,(tag>>16)&0xFF,(tag>>24)&0xFF, + 0, + size); + return NULL; + } + _findResHeaderSize2 += size; + _findResPos2 += size; + +startScan:; + if (_findResHeaderSize2 >= _findResSize2) + return NULL; +/* endian OK, tags are in native format */ + } while (READ_UINT32_UNALIGNED(_findResPos2) != tag); + return _findResPos2; +} + +void Scumm::lock(int type, int i) { + validateResource("Locking", type, i); + res.flags[type][i] |= 0x80; + +} + +void Scumm::unlock(int type, int i) { + validateResource("Unlocking", type, i); + res.flags[type][i] &= ~0x7F; +} + +void Scumm::loadPtrToResource(int type, int resindex, byte *source) { + byte *ptr, *alloced; + int i,len; + + nukeResource(type, resindex); + if (!source) { + ptr = _scriptPointer; + } else { + ptr = source; + } + + len = 0; + do { + i = *ptr++; + if (!i) break; + len++; + if (i==0xFF) + ptr += 3, len += 3; + } while (1); + + if (++len <= 1) + return; + + alloced = createResource(type, resindex, len); + + if (!source) { + alloced[0] = fetchScriptByte(); + for (i=1; i<len; i++) + alloced[i] = *_scriptPointer++; + } else { + for(i=0; i<len; i++) + alloced[i] = source[i]; + } +} + +void Scumm::heapClear(int mode) { + /* TODO: implement this */ + warning("heapClear: not implemented"); +} + + +void Scumm::unkHeapProc2(int a, int b) { + warning("unkHeapProc2: not implemented"); +} + +void Scumm::unkResProc(int a, int b) { + error("unkResProc:not implemented"); +} + + |