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 "scummvm_file.h"
24 #include "common/config-manager.h"
25 #include "common/language.h"
26 
27 namespace Lua {
28 
create(const Common::String & filename,const Common::String & mode)29 LuaFileProxy *LuaFileProxy::create(const Common::String &filename, const Common::String &mode) {
30 	if (filename.contains("config.lua"))
31 		return new LuaFileConfig(filename, mode);
32 
33 	return new LuaFileRead(filename, mode);
34 }
35 
LuaFileConfig(const Common::String & filename,const Common::String & mode)36 LuaFileConfig::LuaFileConfig(const Common::String &filename, const Common::String &mode) : _readPos(0) {
37 	assert(filename.contains("config.lua"));
38 	if (mode == "r")
39 		setupConfigFile();
40 }
41 
formatDouble(double value)42 Common::String LuaFileConfig::formatDouble(double value) {
43 	// This is a bit hackish. The point of it is that it's important that
44 	// we ignore the locale decimal mark and force it to be a point. If it
45 	// would happen to be a comma instead, it seems that it's seen as two
46 	// comma-separated integers rather than one floating-point value. Or
47 	// something like that.
48 
49 	bool negative = value < 0.0;
50 	value = fabs(value);
51 	double integerPart = floor(value);
52 	double fractionalPart = (value - integerPart) * 1000000.0;
53 
54 	return Common::String::format("%s%.0f.%.0f", negative ? "-" : "", integerPart, fractionalPart);
55 }
56 
setupConfigFile()57 void LuaFileConfig::setupConfigFile() {
58 	double sfxVolume = !ConfMan.hasKey("sfx_volume") ? 1.0 : 1.0 * ConfMan.getInt("sfx_volume") / 255.0;
59 	double musicVolume = !ConfMan.hasKey("music_volume") ? 0.5 : 1.0 * ConfMan.getInt("music_volume") / 255.0;
60 	double speechVolume = !ConfMan.hasKey("speech_volume") ? 1.0 : 1.0 * ConfMan.getInt("speech_volume") / 255.0;
61 	bool subtitles = !ConfMan.hasKey("subtitles") ? true : ConfMan.getBool("subtitles");
62 
63 	_readData = Common::String::format(
64 "GAME_LANGUAGE = \"%s\"\r\n\
65 GAME_SUBTITLES = %s\r\n\
66 MAX_MEMORY_USAGE = 256000000\r\n\
67 GFX_VSYNC_ACTIVE = true\r\n\
68 SFX_SAMPLING_RATE = 44100\r\n\
69 SFX_CHANNEL_COUNT = 32\r\n\
70 SFX_SOUND_VOLUME = %s\r\n\
71 SFX_MUSIC_VOLUME = %s\r\n\
72 SFX_SPEECH_VOLUME = %s\r\n",
73 		getLanguage().c_str(), subtitles ? "true" : "false",
74 		formatDouble(sfxVolume).c_str(),
75 		formatDouble(musicVolume).c_str(),
76 		formatDouble(speechVolume).c_str());
77 
78 	_readPos = 0;
79 }
80 
~LuaFileConfig()81 LuaFileConfig::~LuaFileConfig() {
82 	if (!_settings.empty())
83 		writeSettings();
84 }
85 
read(void * ptr,size_t size,size_t count)86 size_t LuaFileConfig::read(void *ptr, size_t size, size_t count) {
87 	size_t bytesRead = MIN<size_t>(_readData.size() - _readPos, size * count);
88 	memmove(ptr, &_readData.c_str()[_readPos], bytesRead);
89 	_readPos += bytesRead;
90 	return bytesRead / size;
91 }
92 
write(const char * ptr,size_t count)93 size_t LuaFileConfig::write(const char *ptr, size_t count) {
94 	// Loop through the provided line(s)
95 	while (*ptr) {
96 		if ((*ptr == '-') && (*(ptr + 1) == '-')) {
97 			// Comment line to skip over
98 			while ((*ptr != '\r') && (*ptr != '\n'))
99 				++ptr;
100 		} else {
101 			// Legitimate data
102 			const char *p = strchr(ptr, '\n');
103 			if (!p) p = ptr + strlen(ptr);
104 			while ((*p == '\r') || (*p == '\n'))
105 				++p;
106 
107 			_settings += Common::String(ptr, p - ptr);
108 			ptr = p;
109 		}
110 
111 		while ((*ptr == '\r') || (*ptr == '\n'))
112 			++ptr;
113 	}
114 
115 	return count;
116 }
117 
writeSettings()118 void LuaFileConfig::writeSettings() {
119 	// Loop through the setting lines
120 	const char *pSrc = _settings.c_str();
121 	while (*pSrc) {
122 		if ((*pSrc != '\r') && (*pSrc != '\n')) {
123 			const char *p = strchr(pSrc, '=');
124 			assert(p);
125 
126 			// Get the setting name
127 			const char *pEnd = p - 1;
128 			while (*pEnd == ' ')
129 				--pEnd;
130 			Common::String settingName(pSrc, pEnd - pSrc + 1);
131 
132 			// Get the setting value
133 			const char *pStart = p + 1;
134 			while (*pStart == ' ')
135 				++pStart;
136 
137 			pEnd = pStart + 1;
138 			while ((*pEnd != '\r') && (*pEnd != '\n') && (*pEnd != '\0'))
139 				++pEnd;
140 			Common::String value(pStart + (*pStart == '"' ? 1 : 0), pEnd - pStart - (*pStart == '"' ? 2 : 0));
141 
142 			// Update the setting
143 			updateSetting(settingName, value);
144 			pSrc = pEnd;
145 		}
146 
147 		// Move to next line
148 		while ((*pSrc == '\r') || (*pSrc == '\n'))
149 			++pSrc;
150 	}
151 
152 	ConfMan.flushToDisk();
153 }
154 
updateSetting(const Common::String & setting,const Common::String & value)155 void LuaFileConfig::updateSetting(const Common::String &setting, const Common::String &value) {
156 	if (setting == "GAME_LANGUAGE")
157 		setLanguage(value);
158 	else if (setting == "GAME_SUBTITLES")
159 		ConfMan.setBool("subtitles", value == "true");
160 	else if (setting == "SFX_SOUND_VOLUME") {
161 		double v = strtod(value.c_str(), NULL);
162 		ConfMan.setInt("sfx_volume", (int)(v * 255));
163 	} else if (setting == "SFX_MUSIC_VOLUME") {
164 		double v = strtod(value.c_str(), NULL);
165 		ConfMan.setInt("music_volume", (int)(v * 255));
166 	} else if (setting == "SFX_SPEECH_VOLUME") {
167 		double v = strtod(value.c_str(), NULL);
168 		ConfMan.setInt("speech_volume", (int)(v * 255));
169 	} else {
170 		// All other settings are ignored
171 	}
172 }
173 
174 /**
175  * Get the language code used by the game for each language it supports
176  */
getLanguage()177 Common::String LuaFileConfig::getLanguage() {
178 	Common::Language lang = Common::parseLanguage(ConfMan.get("language"));
179 	switch (lang) {
180 	case Common::EN_ANY:
181 		return "en";
182 	case Common::DE_DEU:
183 		return "de";
184 	case Common::ES_ESP:
185 		return "es";
186 	case Common::FR_FRA:
187 		return "fr";
188 	case Common::HR_HRV:
189 		return "hr";
190 	case Common::HU_HUN:
191 		return "hu";
192 	case Common::IT_ITA:
193 		return "it";
194 	case Common::PL_POL:
195 		return "pl";
196 	case Common::PT_BRA:
197 		return "pt";
198 	case Common::RU_RUS:
199 		return "ru";
200 	default:
201 		error("Unknown language '%s' encountered", ConfMan.get("language").c_str());
202 		break;
203 	}
204 }
205 
206 /**
207  * Set the language code fro the game
208  */
setLanguage(const Common::String & lang)209 void LuaFileConfig::setLanguage(const Common::String &lang) {
210 	if (lang == "en")
211 		ConfMan.set("language", Common::getLanguageCode(Common::EN_ANY));
212 	else if (lang == "de")
213 		ConfMan.set("language", Common::getLanguageCode(Common::DE_DEU));
214 	else if (lang == "es")
215 		ConfMan.set("language", Common::getLanguageCode(Common::ES_ESP));
216 	else if (lang == "fr")
217 		ConfMan.set("language", Common::getLanguageCode(Common::FR_FRA));
218 	else if (lang == "hr")
219 		ConfMan.set("language", Common::getLanguageCode(Common::HR_HRV));
220 	else if (lang == "hu")
221 		ConfMan.set("language", Common::getLanguageCode(Common::HU_HUN));
222 	else if (lang == "it")
223 		ConfMan.set("language", Common::getLanguageCode(Common::IT_ITA));
224 	else if (lang == "pl")
225 		ConfMan.set("language", Common::getLanguageCode(Common::PL_POL));
226 	else if (lang == "pt")
227 		ConfMan.set("language", Common::getLanguageCode(Common::PT_BRA));
228 	else if (lang == "ru")
229 		ConfMan.set("language", Common::getLanguageCode(Common::RU_RUS));
230 	else
231 		error("Unknown language encountered: %s", lang.c_str());
232 }
233 
234 
LuaFileRead(const Common::String & filename,const Common::String & mode)235 LuaFileRead::LuaFileRead(const Common::String &filename, const Common::String &mode) {
236 	assert(mode == "r");
237 	if (!_file.open(filename))
238 		error("Could not open file %s", filename.c_str());
239 
240 	_size = _file.size();
241 }
242 
eof() const243 bool LuaFileRead::eof() const {
244 	return _file.eos();
245 }
246 
read(void * ptr,size_t size,size_t count)247 size_t LuaFileRead::read(void *ptr, size_t size, size_t count) {
248 	assert(size == 1);
249 	byte *dataPtr = (byte *)ptr;
250 
251 	while (count > 0) {
252 		byte c = _file.readByte();
253 		if (_file.eos())
254 			break;
255 		if (c == '\r')
256 			continue;
257 
258 		*dataPtr++ = c;
259 		--count;
260 	}
261 
262 	return dataPtr - (byte *)ptr;
263 }
264 
write(const char * ptr,size_t count)265 size_t LuaFileRead::write(const char *ptr, size_t count) {
266 	// Unsupported
267 	return 0;
268 }
269 
270 } // End of namespace Lua
271