Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

strings.cpp

/* 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: https://svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-9-1/engines/lure/strings.cpp $
 * $Id: strings.cpp 22820 2006-06-01 22:43:19Z anotherguest $
 *
 */

#include "lure/strings.h"
#include "lure/disk.h"
#include "lure/room.h"
#include "common/endian.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");

      return 0;
}

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

Generated by  Doxygen 1.6.0   Back to index