diff options
Diffstat (limited to 'engines/fullpipe/utils.cpp')
-rw-r--r-- | engines/fullpipe/utils.cpp | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/engines/fullpipe/utils.cpp b/engines/fullpipe/utils.cpp new file mode 100644 index 0000000000..3304a93667 --- /dev/null +++ b/engines/fullpipe/utils.cpp @@ -0,0 +1,486 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "common/file.h" +#include "common/memstream.h" + +#include "fullpipe/objects.h" +#include "fullpipe/motion.h" +#include "fullpipe/ngiarchive.h" +#include "fullpipe/messages.h" +#include "fullpipe/interaction.h" + +namespace Fullpipe { + +bool CObject::loadFile(const char *fname) { + Common::File file; + + if (!file.open(fname)) + return false; + + MfcArchive archive(&file); + + return load(archive); +} + +bool ObList::load(MfcArchive &file) { + debug(5, "ObList::load()"); + int count = file.readCount(); + + debug(9, "ObList::count: %d:", count); + + for (int i = 0; i < count; i++) { + debug(9, "ObList::[%d]", i); + CObject *t = file.readClass(); + + push_back(t); + } + + return true; +} + +bool ObArray::load(MfcArchive &file) { + debug(5, "ObArray::load()"); + int count = file.readCount(); + + resize(count); + + for (int i = 0; i < count; i++) { + CObject *t = file.readClass(); + + push_back(*t); + } + + return true; +} + +bool DWordArray::load(MfcArchive &file) { + debug(5, "DWordArray::load()"); + int count = file.readCount(); + + debug(9, "DWordArray::count: %d", count); + + resize(count); + + for (int i = 0; i < count; i++) { + int32 t = file.readUint32LE(); + + push_back(t); + } + + return true; +} + +char *MfcArchive::readPascalString(bool twoByte) { + char *tmp; + int len; + + if (twoByte) + len = readUint16LE(); + else + len = readByte(); + + tmp = (char *)calloc(len + 1, 1); + read(tmp, len); + + debug(9, "readPascalString: %d <%s>", len, transCyrillic((byte *)tmp)); + + return tmp; +} + +MemoryObject::MemoryObject() { + _memfilename = 0; + _mfield_8 = 0; + _mfield_C = 0; + _mfield_10 = -1; + _mfield_14 = 1; + _dataSize = 0; + _mflags = 0; + _libHandle = 0; + _data = 0; +} + +MemoryObject::~MemoryObject() { + freeData(); + if (_memfilename) + free(_memfilename); +} + +bool MemoryObject::load(MfcArchive &file) { + debug(5, "MemoryObject::load()"); + _memfilename = file.readPascalString(); + + if (char *p = strchr(_memfilename, '\\')) { + for (char *d = _memfilename; *p;) { + p++; + *d++ = *p; + } + } + + if (g_fullpipe->_currArchive) { + _mfield_14 = 0; + _libHandle = g_fullpipe->_currArchive; + } + + return true; +} + +void MemoryObject::loadFile(char *filename) { + debug(5, "MemoryObject::loadFile(<%s>)", filename); + if (!_data) { + Common::SeekableReadStream *s = g_fullpipe->_currArchive->createReadStreamForMember(filename); + + if (s) { + assert(s->size() > 0); + + _dataSize = s->size(); + + debug(5, "Loading %s (%d bytes)", filename, _dataSize); + _data = (byte *)calloc(_dataSize, 1); + s->read(_data, _dataSize); + + delete s; + } + } +} + +byte *MemoryObject::getData() { + load(); + + if (_mfield_14 || _mflags & 1) { + return _data; + } else { + error("Unhandled packed data"); + } +} + +byte *MemoryObject::loadData() { + load(); + return _data; +} + +void MemoryObject::freeData() { + if (_data) + free(_data); + + _data = 0; +} + +bool MemoryObject::testFlags() { + if (_mfield_8) + return false; + + if (_mflags & 1) + return true; + + return false; +} + +MemoryObject2::MemoryObject2() { + _rows = 0; +} + +MemoryObject2::~MemoryObject2() { + if (_rows) + free(_rows); +} + +bool MemoryObject2::load(MfcArchive &file) { + debug(5, "MemoryObject2::load()"); + MemoryObject::load(file); + + _mflags |= 1; + + debug(5, "MemoryObject2::load: <%s>", _memfilename); + + if (_memfilename && *_memfilename) { + MemoryObject::loadFile(_memfilename); + } + + return true; +} + +void MemoryObject2::copyData(byte *src, int dataSize) { + if (_data) + freeData(); + + _dataSize = dataSize; + _data = (byte *)malloc(dataSize); + + memcpy(_data, src, _dataSize); +} + +int MfcArchive::readCount() { + int count = readUint16LE(); + + if (count == 0xffff) + count = readUint32LE(); + + return count; +} + +double MfcArchive::readDouble() { + // FIXME: This is utterly cruel and unportable + // Some articles on the matter: + // http://randomascii.wordpress.com/2013/02/07/float-precision-revisited-nine-digit-float-portability/ + // http://randomascii.wordpress.com/2012/01/11/tricks-with-the-floating-point-format/ + + union { + struct { + int32 a; + int32 b; + } i; + double d; + } tmp; + + tmp.i.a = readUint32LE(); + tmp.i.b = readUint32LE(); + + return tmp.d; +} + +enum { + kNullObject, + kInteraction, + kMessageQueue, + kExCommand, + kObjstateCommand, + kGameVar, + kMctlCompound, + kMovGraph, + kMovGraphLink, + kMovGraphNode, + kReactParallel, + kReactPolygonal +}; + +const struct { + const char *name; + int id; +} classMap[] = { + { "CInteraction", kInteraction }, + { "MessageQueue", kMessageQueue }, + { "ExCommand", kExCommand }, + { "CObjstateCommand", kObjstateCommand }, + { "CGameVar", kGameVar }, + { "CMctlCompound", kMctlCompound }, + { "CMovGraph", kMovGraph }, + { "CMovGraphLink", kMovGraphLink }, + { "CMovGraphNode", kMovGraphNode }, + { "CReactParallel", kReactParallel }, + { "CReactPolygonal", kReactPolygonal }, + { 0, 0 } +}; + +static const char *lookupObjectId(int id) { + for (int i = 0; classMap[i].name; i++) { + if (classMap[i].id == id) + return classMap[i].name; + } + + return ""; +} + +static CObject *createObject(int objectId) { + switch (objectId) { + case kNullObject: + return 0; + case kInteraction: + return new Interaction(); + case kMessageQueue: + return new MessageQueue(); + case kExCommand: + return new ExCommand(); + case kObjstateCommand: + return new ObjstateCommand(); + case kGameVar: + return new GameVar(); + case kMctlCompound: + return new MctlCompound(); + case kMovGraph: + return new MovGraph(); + case kMovGraphLink: + return new MovGraphLink(); + case kMovGraphNode: + return new MovGraphNode(); + case kReactParallel: + return new ReactParallel(); + case kReactPolygonal: + return new ReactPolygonal(); + default: + error("Unknown objectId: %d", objectId); + } + + return 0; +} + +MfcArchive::MfcArchive(Common::SeekableReadStream *stream) { + for (int i = 0; classMap[i].name; i++) { + _classMap[classMap[i].name] = classMap[i].id; + } + + _lastIndex = 1; + _level = 0; + + _stream = stream; + + _objectMap.push_back(0); + _objectIdMap.push_back(kNullObject); +} + +CObject *MfcArchive::readClass() { + bool isCopyReturned; + CObject *res = parseClass(&isCopyReturned); + + if (res && !isCopyReturned) + res->load(*this); + + return res; +} + +CObject *MfcArchive::parseClass(bool *isCopyReturned) { + char *name; + int objectId = 0; + CObject *res = 0; + + uint obTag = readUint16LE(); + + debug(7, "parseClass::obTag = %d (%04x) at 0x%08x", obTag, obTag, pos() - 2); + + if (obTag == 0xffff) { + int schema = readUint16LE(); + + debug(7, "parseClass::schema = %d", schema); + + name = readPascalString(true); + debug(7, "parseClass::class <%s>", name); + + if (!_classMap.contains(name)) { + error("Unknown class in MfcArchive: <%s>", name); + } + + objectId = _classMap[name]; + + debug(7, "tag: %d 0x%x (%x)", _objectMap.size() - 1, _objectMap.size() - 1, objectId); + + res = createObject(objectId); + _objectMap.push_back(res); + _objectIdMap.push_back(objectId); + + _objectMap.push_back(res); // Basically a hack, but behavior is all correct + _objectIdMap.push_back(objectId); + + *isCopyReturned = false; + } else if ((obTag & 0x8000) == 0) { + if (_objectMap.size() < obTag) { + error("Object index too big: %d at 0x%08x", obTag, pos() - 2); + } + debug(7, "parseClass::obTag <%s>", lookupObjectId(_objectIdMap[obTag])); + + res = _objectMap[obTag]; + + *isCopyReturned = true; + } else { + + obTag &= ~0x8000; + + if (_objectMap.size() < obTag) { + error("Object index too big: %d at 0x%08x", obTag, pos() - 2); + } + + debug(7, "parseClass::obTag <%s>", lookupObjectId(_objectIdMap[obTag])); + + objectId = _objectIdMap[obTag]; + + res = createObject(objectId); + _objectMap.push_back(res); + _objectIdMap.push_back(objectId); + + *isCopyReturned = false; + } + + return res; +} + +char *genFileName(int superId, int sceneId, const char *ext) { + char *s = (char *)calloc(256, 1); + + if (superId) { + snprintf(s, 255, "%04d%04d.%s", superId, sceneId, ext); + } else { + snprintf(s, 255, "%04d.%s", sceneId, ext); + } + + debug(7, "genFileName: %s", s); + + return s; +} + +// Translates cp-1251..utf-8 +byte *transCyrillic(byte *s) { + static byte tmp[1024]; + + static int trans[] = { 0xa8, 0xd081, 0xb8, 0xd191, 0xc0, 0xd090, + 0xc1, 0xd091, 0xc2, 0xd092, 0xc3, 0xd093, 0xc4, 0xd094, + 0xc5, 0xd095, 0xc6, 0xd096, 0xc7, 0xd097, 0xc8, 0xd098, + 0xc9, 0xd099, 0xca, 0xd09a, 0xcb, 0xd09b, 0xcc, 0xd09c, + 0xcd, 0xd09d, 0xce, 0xd09e, 0xcf, 0xd09f, 0xd0, 0xd0a0, + 0xd1, 0xd0a1, 0xd2, 0xd0a2, 0xd3, 0xd0a3, 0xd4, 0xd0a4, + 0xd5, 0xd0a5, 0xd6, 0xd0a6, 0xd7, 0xd0a7, 0xd8, 0xd0a8, + 0xd9, 0xd0a9, 0xda, 0xd0aa, 0xdb, 0xd0ab, 0xdc, 0xd0ac, + 0xdd, 0xd0ad, 0xde, 0xd0ae, 0xdf, 0xd0af, 0xe0, 0xd0b0, + 0xe1, 0xd0b1, 0xe2, 0xd0b2, 0xe3, 0xd0b3, 0xe4, 0xd0b4, + 0xe5, 0xd0b5, 0xe6, 0xd0b6, 0xe7, 0xd0b7, 0xe8, 0xd0b8, + 0xe9, 0xd0b9, 0xea, 0xd0ba, 0xeb, 0xd0bb, 0xec, 0xd0bc, + 0xed, 0xd0bd, 0xee, 0xd0be, 0xef, 0xd0bf, 0xf0, 0xd180, + 0xf1, 0xd181, 0xf2, 0xd182, 0xf3, 0xd183, 0xf4, 0xd184, + 0xf5, 0xd185, 0xf6, 0xd186, 0xf7, 0xd187, 0xf8, 0xd188, + 0xf9, 0xd189, 0xfa, 0xd18a, 0xfb, 0xd18b, 0xfc, 0xd18c, + 0xfd, 0xd18d, 0xfe, 0xd18e, 0xff, 0xd18f }; + + int i = 0; + + for (byte *p = s; *p; p++) { + if (*p < 128) { + tmp[i++] = *p; + } else { + int j; + for (j = 0; trans[j]; j += 2) { + if (trans[j] == *p) { + tmp[i++] = (trans[j + 1] >> 8) & 0xff; + tmp[i++] = trans[j + 1] & 0xff; + break; + } + } + + assert(trans[j]); + } + } + + tmp[i] = 0; + + return tmp; +} + +} // End of namespace Fullpipe |