diff options
Diffstat (limited to 'engines/sky/disk.cpp')
| -rw-r--r-- | engines/sky/disk.cpp | 375 | 
1 files changed, 375 insertions, 0 deletions
| diff --git a/engines/sky/disk.cpp b/engines/sky/disk.cpp new file mode 100644 index 0000000000..3c39a287d0 --- /dev/null +++ b/engines/sky/disk.cpp @@ -0,0 +1,375 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2003-2006 The ScummVM project + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "common/file.h" +#include "common/util.h" +#include "common/scummsys.h" +#include "sky/disk.h" +#include "sky/rnc_deco.h" +#include "sky/sky.h" +#include "sky/struc.h" + +namespace Sky { + +static const char *dataFilename = "sky.dsk"; +static const char *dinnerFilename = "sky.dnr"; + +Disk::Disk(const Common::String &gameDataPath) { +	_dataDiskHandle = new Common::File(); +	_dnrHandle = new Common::File(); + +	_dnrHandle->open(dinnerFilename); +	if (!_dnrHandle->isOpen()) +		error("Could not open %s%s", gameDataPath.c_str(), dinnerFilename); + +	if (!(_dinnerTableEntries = _dnrHandle->readUint32LE())) +		error("Error reading from sky.dnr"); //even though it was opened correctly?! + +	_dinnerTableArea = (uint8 *)malloc(_dinnerTableEntries * 8); +	uint32 entriesRead = _dnrHandle->read(_dinnerTableArea, 8 * _dinnerTableEntries) / 8; + +	if (entriesRead != _dinnerTableEntries) +		error("entriesRead != dinnerTableEntries. [%d/%d]", entriesRead, _dinnerTableEntries); + +	_dataDiskHandle->open(dataFilename); +	if (!_dataDiskHandle->isOpen()) +		error("Error opening %s%s", gameDataPath.c_str(), dataFilename); + +	printf("Found BASS version v0.0%d (%d dnr entries)\n", determineGameVersion(), _dinnerTableEntries); + +	memset(_buildList, 0, 60 * 2); +	memset(_loadedFilesList, 0, 60 * 4); +} + +Disk::~Disk(void) { +	if (_dnrHandle->isOpen()) +		_dnrHandle->close(); +	if (_dataDiskHandle->isOpen()) +		_dataDiskHandle->close(); +	fnFlushBuffers(); +	free(_dinnerTableArea); +	delete _dnrHandle; +	delete _dataDiskHandle; +} + +bool Disk::fileExists(uint16 fileNr) { +	return (getFileInfo(fileNr) != NULL); +} + +// allocate memory, load the file and return a pointer +uint8 *Disk::loadFile(uint16 fileNr) { + +	uint8 cflag; + +	debug(2, "load file %d,%d (%d)", (fileNr >> 11), (fileNr & 2047), fileNr); + +	uint8 *fileInfoPtr = getFileInfo(fileNr); +	if (fileInfoPtr == NULL) { +		debug(1, "File %d not found", fileNr); +		return NULL; +	} + +	uint32 fileFlags = READ_LE_UINT24(fileInfoPtr + 5); +	uint32 fileSize = fileFlags & 0x03fffff; +	uint32 fileOffset = READ_LE_UINT32(fileInfoPtr + 2) & 0x0ffffff; + +	_lastLoadedFileSize = fileSize; +	cflag = (uint8)((fileOffset >> 23) & 0x1); +	fileOffset &= 0x7FFFFF; + +	if (cflag) { +		if (SkyEngine::_systemVars.gameVersion == 331) +			fileOffset <<= 3; +		else +			fileOffset <<= 4; +	} + +	uint8 *fileDest = (uint8 *)malloc(fileSize + 4); // allocate memory for file + +	_dataDiskHandle->seek(fileOffset, SEEK_SET); + +	//now read in the data +	int32 bytesRead = _dataDiskHandle->read(fileDest, fileSize); + +	if (bytesRead != (int32)fileSize) +		warning("Unable to read %d bytes from datadisk (%d bytes read)", fileSize, bytesRead); + +	cflag = (uint8)((fileFlags >> 23) & 0x1); +	//if cflag == 0 then file is compressed, 1 == uncompressed + +	dataFileHeader *fileHeader = (dataFileHeader*)fileDest; + +	if ((!cflag) && ((FROM_LE_16(fileHeader->flag) >> 7) & 1)) { +		debug(2, "File is RNC compressed."); + +		uint32 decompSize = (FROM_LE_16(fileHeader->flag) & ~0xFF) << 8; +		decompSize |= FROM_LE_16(fileHeader->s_tot_size); + +		uint8 *uncompDest = (uint8 *)malloc(decompSize); + +		int32 unpackLen; +		void *output, *input = fileDest + sizeof(dataFileHeader); + +		if ((fileFlags >> 22) & 0x1) { //do we include the header? +			// don't return the file's header +			output = uncompDest; +			unpackLen = _rncDecoder.unpackM1(input, output, 0); +		} else { +#ifdef SCUMM_BIG_ENDIAN +			// Convert dataFileHeader to BE (it only consists of 16 bit words) +			uint16 *headPtr = (uint16 *)fileDest; +			for (uint i = 0; i < sizeof(struct dataFileHeader) / 2; i++) +				*(headPtr + i) = READ_LE_UINT16(headPtr + i); +#endif + +			memcpy(uncompDest, fileDest, sizeof(dataFileHeader)); +			output = uncompDest + sizeof(dataFileHeader); +			unpackLen = _rncDecoder.unpackM1(input, output, 0); +			if (unpackLen) +				unpackLen += sizeof(dataFileHeader); +		} + +		debug(3, "UnpackM1 returned: %d", unpackLen); + +		if (unpackLen == 0) { //Unpack returned 0: file was probably not packed. +			free(uncompDest); +			return fileDest; +		} else { +			if (unpackLen != (int32)decompSize) +				debug(1, "ERROR: File %d: invalid decomp size! (was: %d, should be: %d)", fileNr, unpackLen, decompSize); +			_lastLoadedFileSize = decompSize; + +			free(fileDest); +			return uncompDest; +		} +	} else { +#ifdef SCUMM_BIG_ENDIAN +		if (!cflag) { +			uint16 *headPtr = (uint16 *)fileDest; +			for (uint i = 0; i < sizeof(struct dataFileHeader) / 2; i++) +				*(headPtr + i) = READ_LE_UINT16(headPtr + i); +		} +#endif +		return fileDest; +	} +} + +uint16 *Disk::loadScriptFile(uint16 fileNr) { +	uint16 *buf = (uint16*)loadFile(fileNr); +#ifdef SCUMM_BIG_ENDIAN +	for (uint i = 0; i < _lastLoadedFileSize / 2; i++) +		buf[i] = FROM_LE_16(buf[i]); +#endif +	return buf; +} + +uint8 *Disk::getFileInfo(uint16 fileNr) { + +	uint16 i; +	uint16 *dnrTbl16Ptr = (uint16 *)_dinnerTableArea; + +	for (i = 0; i < _dinnerTableEntries; i++) { +		if (READ_LE_UINT16(dnrTbl16Ptr) == fileNr) { +			debug(2, "file %d found!", fileNr); +			return (uint8 *)dnrTbl16Ptr; +		} +		dnrTbl16Ptr += 4; +	} + +	return 0; //not found +} + +void Disk::fnCacheChip(uint16 *fList) { + +	// fnCacheChip is called after fnCacheFast +	uint16 cnt = 0; +	while (_buildList[cnt]) +		cnt++; +	uint16 fCnt = 0; +	do { +		_buildList[cnt + fCnt] = fList[fCnt] & 0x7FFFU; +		fCnt++; +	} while (fList[fCnt-1]); +	fnCacheFiles(); +} + +void Disk::fnCacheFast(uint16 *fList) { +	if (fList != NULL) { +		uint8 cnt = 0; +		do { +			_buildList[cnt] = fList[cnt] & 0x7FFFU; +			cnt++; +		} while (fList[cnt-1]); +	} +} + +void Disk::fnCacheFiles(void) { + +	uint16 lCnt, bCnt, targCnt; +	targCnt = lCnt = 0; +	bool found; +	while (_loadedFilesList[lCnt]) { +		bCnt = 0; +		found = false; +		while (_buildList[bCnt] && (!found)) { +			if ((_buildList[bCnt] & 0x7FFFU) == _loadedFilesList[lCnt]) +				found = true; +			else +				bCnt++; +		} +		if (found) { +			_loadedFilesList[targCnt] = _loadedFilesList[lCnt]; +			targCnt++; +		} else { +			free(SkyEngine::_itemList[_loadedFilesList[lCnt] & 2047]); +			SkyEngine::_itemList[_loadedFilesList[lCnt] & 2047] = NULL; +		} +		lCnt++; +	} +	_loadedFilesList[targCnt] = 0; // mark end of list +	bCnt = 0; +	while (_buildList[bCnt]) { +		if ((_buildList[bCnt] & 0x7FF) == 0x7FF) { +			// amiga dummy files +			bCnt++; +			continue; +		} +		lCnt = 0; +		found = false; +		while (_loadedFilesList[lCnt] && (!found)) { +			if (_loadedFilesList[lCnt] == (_buildList[bCnt] & 0x7FFFU)) +				found = true; +			lCnt++; +		} +		if (found) { +			bCnt++; +			continue; +		} +		// ok, we really have to load the file. +		_loadedFilesList[targCnt] = _buildList[bCnt] & 0x7FFFU; +		targCnt++; +		_loadedFilesList[targCnt] = 0; +		SkyEngine::_itemList[_buildList[bCnt] & 2047] = (void**)loadFile(_buildList[bCnt] & 0x7FFF); +		if (!SkyEngine::_itemList[_buildList[bCnt] & 2047]) +			warning("fnCacheFiles: Disk::loadFile() returned NULL for file %d",_buildList[bCnt] & 0x7FFF); +		bCnt++; +	} +	_buildList[0] = 0; +} + +void Disk::refreshFilesList(uint32 *list) { + +	uint8 cnt = 0; +	while (_loadedFilesList[cnt]) { +		if (SkyEngine::_itemList[_loadedFilesList[cnt] & 2047]) +			free(SkyEngine::_itemList[_loadedFilesList[cnt] & 2047]); +		SkyEngine::_itemList[_loadedFilesList[cnt] & 2047] = NULL; +		cnt++; +	} +	cnt = 0; +	while (list[cnt]) { +		_loadedFilesList[cnt] = list[cnt]; +		SkyEngine::_itemList[_loadedFilesList[cnt] & 2047] = (void**)loadFile((uint16)(_loadedFilesList[cnt] & 0x7FFF)); +		cnt++; +	} +	_loadedFilesList[cnt] = 0; +} + +void Disk::fnMiniLoad(uint16 fileNum) { + +	uint16 cnt = 0; +	while (_loadedFilesList[cnt]) { +		if (_loadedFilesList[cnt] == fileNum) +			return; +		cnt++; +	} +	_loadedFilesList[cnt] = fileNum & 0x7FFFU; +	_loadedFilesList[cnt + 1] = 0; +	SkyEngine::_itemList[fileNum & 2047] = (void**)loadFile(fileNum); +} + +void Disk::fnFlushBuffers(void) { + +	// dump all loaded sprites +	uint8 lCnt = 0; +	while (_loadedFilesList[lCnt]) { +		free(SkyEngine::_itemList[_loadedFilesList[lCnt] & 2047]); +		SkyEngine::_itemList[_loadedFilesList[lCnt] & 2047] = NULL; +		lCnt++; +	} +	_loadedFilesList[0] = 0; +} + +void Disk::dumpFile(uint16 fileNr) { +	char buf[128]; +	Common::File out; +	byte* filePtr; + +	filePtr = loadFile(fileNr); +	sprintf(buf, "dumps/file-%d.dmp", fileNr); + +	if (!out.exists(buf, "")) { +		if (out.open(buf, Common::File::kFileWriteMode, "")) +			out.write(filePtr, _lastLoadedFileSize); +	} +	free(filePtr); +} + +uint32 Disk::determineGameVersion() { +	//determine game version based on number of entries in dinner table +	switch (_dinnerTableEntries) { +	case 243: +		// pc gamer demo (v0.0109) +		return 109; +	case 247: +		//floppy demo (v0.0267) +		return 267; +	case 1404: +		//floppy (v0.0288) +		return 288; +	case 1413: +		//floppy (v0.0303) +		return 303; +	case 1445: +		//floppy (v0.0331 or v0.0348) +		if (_dataDiskHandle->size() == 8830435) +			return 348; +		else +			return 331; +	case 1711: +		//cd demo (v0.0365) +		return 365; +	case 5099: +		//cd (v0.0368) +		return 368; +	case 5097: +		//cd (v0.0372) +		return 372; +	default: +		//unknown version +		error("Unknown game version! %d dinner table entries", _dinnerTableEntries); +		break; +	} +} + +} // End of namespace Sky | 
