1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "titanic/true_talk/tt_quotes.h"
24 #include "titanic/support/files_manager.h"
25 #include "titanic/titanic.h"
26 #include "common/algorithm.h"
27 
28 namespace Titanic {
29 
TTquotes()30 TTquotes::TTquotes() : _loaded(false), _dataP(nullptr), _dataSize(0),
31 		_field544(0) {
32 	Common::fill(&_tags[0], &_tags[256], 0);
33 }
34 
~TTquotes()35 TTquotes::~TTquotes() {
36 	delete[] _dataP;
37 }
38 
load()39 void TTquotes::load() {
40 	Common::SeekableReadStream *r = g_vm->_filesManager->getResource("TEXT/JRQUOTES");
41 	size_t size = r->readUint32LE();
42 	_loaded = true;
43 
44 	_dataSize = _field544 = size;
45 	_dataP = new char[size + 0x10];
46 
47 	for (int idx = 0; idx < 256; ++idx)
48 		_tags[idx] = r->readUint32LE();
49 
50 	for (int charIdx = 0; charIdx < 26; ++charIdx) {
51 		TTquotesLetter &letter = _alphabet[charIdx];
52 		int count = r->readUint32LE();
53 
54 		// Load the list of entries for the given letter
55 		letter._entries.resize(count);
56 		for (int idx = 0; idx < count; ++idx) {
57 			letter._entries[idx]._tagIndex = r->readByte();
58 			letter._entries[idx]._maxSize = r->readByte();
59 			letter._entries[idx]._strP = _dataP + r->readUint32LE();
60 		}
61 	}
62 
63 	// Read in buffer and then decode it
64 	r->read((byte *)_dataP, _dataSize);
65 	for (size_t idx = 0; idx < _dataSize; idx += 4)
66 		WRITE_LE_UINT32((byte *)_dataP + idx, READ_LE_UINT32((const byte *)_dataP + idx) ^ 0xA55A5AA5);
67 
68 	delete r;
69 }
70 
find(const char * str) const71 int TTquotes::find(const char *str)  const {
72 	if (!str || !*str)
73 		return 0;
74 
75 	// Find start and end of string
76 	const char *startP = str, *endP = str;
77 	while (*endP)
78 		++endP;
79 
80 	do {
81 		int tagId = find(startP, endP);
82 		if (tagId)
83 			return tagId;
84 
85 		// Move to next following space or end of string
86 		while (*startP && *startP != ' ')
87 			++startP;
88 		// If it's a space, then move past it to start of next word
89 		while (*startP && *startP == ' ')
90 			++startP;
91 
92 	} while (*startP);
93 
94 	// No match
95 	return 0;
96 }
97 
find(const char * startP,const char * endP) const98 int TTquotes::find(const char *startP, const char *endP) const {
99 	int size = endP - startP;
100 	if (size < 3)
101 		return 0;
102 
103 	uint index = MIN((uint)(*startP - 'a'), (uint)25);
104 	const TTquotesLetter &letter = _alphabet[index];
105 	if (letter._entries.empty())
106 		// No entries for the letter, so exit immediately
107 		return 0;
108 
109 	int maxSize = size + 4;
110 
111 	for (uint idx = 0; idx < letter._entries.size(); ++idx) {
112 		const TTquotesEntry &entry = letter._entries[idx];
113 		if (entry._maxSize > maxSize)
114 			continue;
115 
116 		const char *srcP = startP;
117 		const char *destP = entry._strP;
118 		int srcIndex = index != 25 ? 1 : 0, destIndex = 0;
119 		if (*destP) {
120 			do {
121 				if (!srcP[srcIndex]) {
122 					break;
123 				} else if (srcP[srcIndex] == '*') {
124 					++srcIndex;
125 				} else if (destP[destIndex] == '-') {
126 					++destIndex;
127 					if (srcP[srcIndex] == ' ')
128 						++srcIndex;
129 				} else if (srcP[srcIndex] != destP[destIndex]) {
130 					break;
131 				} else {
132 					++destIndex;
133 					++srcIndex;
134 				}
135 			} while (destP[destIndex]);
136 
137 			if (!destP[destIndex] && (srcP[srcIndex] <= '*' ||
138 					(srcP[srcIndex] == 's' && srcP[srcIndex + 1] <= '*')))
139 				return _tags[entry._tagIndex];
140 		}
141 	}
142 
143 	return 0;
144 }
145 
146 } // End of namespace Titanic
147