aboutsummaryrefslogtreecommitdiff
path: root/engines/sky/disk.cpp
diff options
context:
space:
mode:
authorMax Horn2006-02-11 22:45:04 +0000
committerMax Horn2006-02-11 22:45:04 +0000
commit26ee630756ebdd7c96bccede0881a8c8b98e8f2b (patch)
tree26e378d5cf990a2b81c2c96e9e683a7f333b62e8 /engines/sky/disk.cpp
parent2a9a0d4211b1ea5723f1409d91cb95de8984429e (diff)
downloadscummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.gz
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.bz2
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.zip
Moved engines to the new engines/ directory
svn-id: r20582
Diffstat (limited to 'engines/sky/disk.cpp')
-rw-r--r--engines/sky/disk.cpp375
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