diff options
Diffstat (limited to 'engines/lure/strings.cpp')
-rw-r--r-- | engines/lure/strings.cpp | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/engines/lure/strings.cpp b/engines/lure/strings.cpp new file mode 100644 index 0000000000..d509e3842d --- /dev/null +++ b/engines/lure/strings.cpp @@ -0,0 +1,300 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-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 "lure/strings.h" +#include "lure/disk.h" +#include "lure/room.h" + +namespace Lure { + +StringData *int_strings = NULL; + +StringData::StringData() { + int_strings = this; + + for (uint8 ctr = 0; ctr < MAX_NUM_CHARS; ++ctr) _chars[ctr] = NULL; + _numChars = 0; + _names = Disk::getReference().getEntry(NAMES_RESOURCE_ID); + _strings[0] = Disk::getReference().getEntry(STRINGS_RESOURCE_ID); + _strings[1] = Disk::getReference().getEntry(STRINGS_2_RESOURCE_ID); + _strings[2] = Disk::getReference().getEntry(STRINGS_3_RESOURCE_ID); + + // Add in the list of bit sequences, and what characters they represent + add("00", ' '); + add("0100", 'e'); + add("0101", 'o'); + add("0110", 't'); + add("01110", 'a'); + add("01111", 'n'); + add("1000", 's'); + add("1001", 'i'); + add("1010", 'r'); + add("10110", 'h'); + add("101110", 'u'); + add("1011110", 'l'); + add("1011111", 'd'); + add("11000", 'y'); + add("110010", 'g'); + add("110011", '\0'); + add("110100", 'w'); + add("110101", 'c'); + add("110110", 'f'); + add("1101110", '.'); + add("1101111", 'm'); + add("111000", 'p'); + add("111001", 'b'); + add("1110100", ','); + add("1110101", 'k'); + add("1110110", '\''); + add("11101110", 'I'); + add("11101111", 'v'); + add("1111000", '!'); + add("1111001", '\xb4'); + add("11110100", 'T'); + add("11110101", '\xb5'); + add("11110110", '?'); + add("111101110", '\xb2'); + add("111101111", '\xb3'); + add("11111000", 'W'); + add("111110010", 'H'); + add("111110011", 'A'); + add("111110100", '\xb1'); + add("111110101", 'S'); + add("111110110", 'Y'); + add("1111101110", 'G'); + add("11111011110", 'M'); + add("11111011111", 'N'); + add("111111000", 'O'); + add("1111110010", 'E'); + add("1111110011", 'L'); + add("1111110100", '-'); + add("1111110101", 'R'); + add("1111110110", 'B'); + add("11111101110", 'D'); + add("11111101111", '\xa6'); + add("1111111000", 'C'); + add("11111110010", 'x'); + add("11111110011", 'j'); + add("1111111010", '\xac'); + add("11111110110", '\xa3'); + add("111111101110", 'P'); + add("111111101111", 'U'); + add("11111111000", 'q'); + add("11111111001", '\xad'); + add("111111110100", 'F'); + add("111111110101", '1'); + add("111111110110", '\xaf'); + add("1111111101110", ';'); + add("1111111101111", 'z'); + add("111111111000", '\xa5'); + add("1111111110010", '2'); + add("1111111110011", '\xb0'); + add("111111111010", 'K'); + add("1111111110110", '%'); + add("11111111101110", '\xa2'); + add("11111111101111", '5'); + add("1111111111000", ':'); + add("1111111111001", 'J'); + add("1111111111010", 'V'); + add("11111111110110", '6'); + add("11111111110111", '3'); + add("1111111111100", '\xab'); + add("11111111111010", '\xae'); + add("111111111110110", '0'); + add("111111111110111", '4'); + add("11111111111100", '7'); + add("111111111111010", '9'); + add("111111111111011", '"'); + add("111111111111100", '8'); + add("111111111111101", '\xa7'); + add("1111111111111100", '/'); + add("1111111111111101", 'Q'); + add("11111111111111100", '\xa8'); + add("11111111111111101", '('); + add("111111111111111100", ')'); + add("111111111111111101", '\x99'); + add("11111111111111111", '\xa9'); +} + +StringData::~StringData() { + int_strings = NULL; + + for (uint8 ctr = 0; ctr < MAX_NUM_CHARS; ++ctr) + if (_chars[ctr]) delete _chars[ctr]; + else break; + + delete _names; + delete _strings[0]; + delete _strings[1]; + delete _strings[2]; +} + +StringData &StringData::getReference() { + return *int_strings; +} + +void StringData::add(const char *sequence, char ascii) { + uint32 value = 0; + + for (uint8 index = 0; index < strlen(sequence); ++index) { + if (sequence[index] == '1') + value |= (1 << index); + else if (sequence[index] != '0') + error("Invalid character in string bit-stream sequence"); + } + + if (_numChars == MAX_NUM_CHARS) + error("Max characters too lower in string decoder"); + _chars[_numChars++] = new CharacterEntry(strlen(sequence), value, ascii); +} + +byte StringData::readBit() { + byte result = ((*_srcPos & _bitMask) != 0) ? 1 : 0; + _bitMask >>= 1; + if (_bitMask == 0) { + _bitMask = 0x80; + ++_srcPos; + } + + return result; +} + +void StringData::initPosition(uint16 stringId) { + uint16 roomNumber = Room::getReference().roomNumber(); + byte *stringTable; + + if ((roomNumber >= 0x2A) && (stringId >= STRING_ID_RANGE) && (stringId < STRING_ID_UPPER)) + stringId = 0x76; + if ((roomNumber < 0x2A) && (stringId >= STRING_ID_UPPER)) + stringId = 0x76; + + if (stringId < STRING_ID_RANGE) + stringTable = _strings[0]->data(); + else if (stringId < STRING_ID_RANGE*2) { + stringId -= STRING_ID_RANGE; + stringTable = _strings[1]->data(); + } else { + stringId -= STRING_ID_RANGE * 2; + stringTable = _strings[2]->data(); + } + + _srcPos = stringTable + 4; + + uint32 total = 0; + int numLoops = stringId >> 5; + for (int ctr = 0; ctr < numLoops; ++ctr) { + total += READ_LE_UINT16(_srcPos); + _srcPos += sizeof(uint16); + } + + numLoops = stringId & 0x1f; + if (numLoops!= 0) { + byte *tempPtr = stringTable + (stringId & 0xffe0) + READ_LE_UINT16(stringTable); + + for (int ctr = 0; ctr < numLoops; ++ctr) { + byte v = *tempPtr++; + if ((v & 0x80) == 0) { + total += v; + } else { + total += (v & 0x7f) << 3; + } + } + } + + _bitMask = 0x80; + + if ((total & 3) != 0) + _bitMask >>= (total & 3) * 2; + + _srcPos = stringTable + (total >> 2) + READ_LE_UINT16(stringTable + 2); + + // Final positioning to start of string + for (;;) { + if (readBit() == 0) break; + _srcPos += 2; + } + readBit(); +} + +// readCharatcer +// Reads the next character from the input bit stream + +char StringData::readCharacter() { + uint32 searchValue = 0; + + // Loop through an increasing number of bits + + for (uint8 numBits = 1; numBits <= 18; ++numBits) { + searchValue |= readBit() << (numBits - 1); + + // Scan through list for a match + for (int index = 0; _chars[index] != NULL; ++index) { + if ((_chars[index]->_numBits == numBits) && + (_chars[index]->_sequence == searchValue)) + return _chars[index]->_ascii; + } + } + + error("Unknown bit sequence encountered when decoding string"); +} + +void StringData::getString(uint16 stringId, char *dest, const char *hotspotName, + const char *actionName) { + char ch; + char *destPos = dest; + initPosition(stringId); + + ch = readCharacter(); + while (ch != '\0') { + if (ch == '%') { + // Copy over hotspot or action + ch = readCharacter(); + const char *p = (ch == '1') ? hotspotName : actionName; + strcpy(destPos, p); + destPos += strlen(p); + } else if ((uint8) ch >= 0xa0) { + const char *p = getName((uint8) ch - 0xa0); + strcpy(destPos, p); + destPos += strlen(p); + } else { + *destPos++ = ch; + } + + ch = readCharacter(); + } + + *destPos = '\0'; +} + +// getName +// Returns the name or fragment of word at the specified index in the names resource + +char *StringData::getName(uint8 nameIndex) { + uint16 numNames = *((uint16 *) _names->data()) / 2; + if (nameIndex >= numNames) + error("Invalid name index was passed to getCharacterName"); + + uint16 nameStart = *((uint16 *) (_names->data() + (nameIndex * 2))); + return (char *) (_names->data() + nameStart); +} + +} // namespace Lure |