diff options
Diffstat (limited to 'engines/macventure/text.cpp')
-rw-r--r-- | engines/macventure/text.cpp | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/engines/macventure/text.cpp b/engines/macventure/text.cpp new file mode 100644 index 0000000000..d8e18fffdf --- /dev/null +++ b/engines/macventure/text.cpp @@ -0,0 +1,209 @@ +/* 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. + * + */ + +/* + * Based on + * WebVenture (c) 2010, Sean Kasun + * https://github.com/mrkite/webventure, http://seancode.com/webventure/ + * + * Used with explicit permission from the author + */ + +#include "macventure/text.h" + +namespace MacVenture { +TextAsset::TextAsset(MacVentureEngine *engine, ObjID objid, ObjID source, ObjID target, Container *container, bool isOld, const HuffmanLists *huffman) { + _id = objid; + _sourceObj = source; + _targetObj = target; + _container = container; + _huffman = huffman; + _isOld = isOld; + _engine = engine; + + if (_isOld) { + decodeOld(); + } else { + decodeHuffman(); + } +} + +void TextAsset::decodeOld() { + Common::SeekableReadStream *res = _container->getItem(_id); + uint16 strLen = res->readUint16BE(); + Common::BitStream32BELSB stream(res, DisposeAfterUse::YES); + char *str = new char[strLen + 1]; + bool lowercase = false; + char c; + for (uint16 i = 0; i < strLen; i++) { + char val = stream.getBits(5); + if (val == 0x0) { // Space + c = ' '; + } else if (val >= 0x1 && val <= 0x1A) { + if (lowercase) { // Ascii a-z + c = val + 0x60; + } else { // Ascii A-Z + c = val + 0x40; + } + lowercase = true; + } else if (val == 0x1B) { + if (lowercase) { + c = '.'; + } else { + c = ','; + } + lowercase = true; + } else if (val == 0x1C) { + if (lowercase) { + c = '\''; + } else { + c = '"'; + } + lowercase = true; + } else if (val == 0x1D) { // Composite + ObjID subval = stream.getBits(16); + Common::String child; + if (subval & 0x8000) { + // Composite object id + subval ^= 0xFFFF; + child = getNoun(subval); + } else { + // Just another id + // HACK, see below in getNoun() + child = *TextAsset(_engine, subval, _sourceObj, _targetObj, _container, _isOld, _huffman).decode(); + } + if (child.size() > 0) { + c = '?'; // HACK Will fix later, should append + } + lowercase = true; + } else if (val == 0x1E) { + c = stream.getBits(8); + lowercase = true; + } else if (val == 0x1F) { + lowercase = !lowercase; + } else { + warning("Unrecognized char in old text %d, pos %d", _id, i); + } + str[i] = c; + } + + str[strLen] = '\0'; + debugC(3, kMVDebugText, "Decoded string [%d] (old encoding): %s", _id, str); + _decoded = Common::String(str); +} + +void TextAsset::decodeHuffman() { + _decoded = Common::String(""); + Common::SeekableReadStream *res = _container->getItem(_id); + Common::BitStream8MSB stream(res, DisposeAfterUse::YES); + uint16 strLen = 0; + if (stream.getBit()) { + strLen = stream.getBits(15); + } else { + strLen = stream.getBits(7); + } + uint32 mask = 0; + uint32 symbol = 0; + char c; + for (uint16 i = 0; i < strLen; i++) { + mask = stream.peekBits(16); + + uint32 entry; + // Find the length index + for (entry = 0; entry < _huffman->getNumEntries(); entry++) { + if (mask < _huffman->getMask(entry)) { + break; + } + } + + stream.skip(_huffman->getLength(entry)); + + symbol = _huffman->getSymbol(entry); + + if (symbol == 1) { // 7-bit ascii + c = stream.getBits(7); + _decoded += c; + } else if (symbol == 2) { // Composite + if (stream.getBit()) { // TextID + ObjID embedId = stream.getBits(15); + uint pos = stream.pos(); // HACK, part 1 + TextAsset embedded(_engine, embedId, _sourceObj, _targetObj, _container, _isOld, _huffman); + stream.rewind();// HACK, part 2 + stream.skip(pos); + + _decoded.replace(_decoded.end(), _decoded.end(), *embedded.decode()); + + // Another HACK, to get around that EOS char I insert at the end + _decoded.replace(_decoded.end() - 1, _decoded.end(), ""); + } else { //Composite obj string + ObjID embedId = stream.getBits(8); + uint pos = stream.pos(); // HACK, part 1 + + _decoded.replace(_decoded.end(), _decoded.end(), getNoun(embedId)); + stream.rewind();// HACK, part 2 + stream.skip(pos); + + // Another HACK, to get around that EOS char I insert at the end + _decoded.replace(_decoded.end() - 1, _decoded.end(), ""); + } + } else { // Plain ascii + c = symbol & 0xFF; + _decoded.replace(_decoded.end(), _decoded.end(), Common::String(c)); + } + } + _decoded += '\0'; + debugC(3, kMVDebugText, "Decoded string [%d] (new encoding): %s", _id, _decoded.c_str()); +} +Common::String TextAsset::getNoun(ObjID subval) { + ObjID obj; + Common::String name; + if (subval & 8) { + obj = _targetObj; + } else { + obj = _sourceObj; + } + if ((subval & 3) == 1) { + uint idx = _engine->getPrefixNdx(obj); + idx = ((idx >> 4) & 3) + 1; + name = _engine->getNoun(idx); + } else { + // HACK, there should be a pool of assets or something like in the GUI + name = *TextAsset(_engine, obj, _sourceObj, _targetObj, _container, _isOld, _huffman).decode(); + switch (subval & 3) { + case 2: + name = _engine->getPrefixString(0, obj) + name; + break; + case 3: + name = _engine->getPrefixString(2, obj) + name; + break; + } + } + if (name.size() && (subval & 4)) { + Common::String tmp = name; + name.toUppercase(); + name.replace(1, name.size() - 1, tmp, 1, tmp.size() - 1); + } + + return name; +} + +} // End of namespace MacVenture |