1 // configfile.cpp
2 //
3 // Copyright (C) 2001-2009, the Celestia Development Team
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 
10 #include <iostream>
11 #include <fstream>
12 #include <cassert>
13 #include <celutil/debug.h>
14 #include <celutil/directory.h>
15 #include <celutil/util.h>
16 #include <celengine/celestia.h>
17 #include <celengine/texmanager.h>
18 #include "configfile.h"
19 
20 using namespace std;
21 
22 
getUint(Hash * params,const string & paramName,unsigned int defaultValue)23 static unsigned int getUint(Hash* params,
24                             const string& paramName,
25                             unsigned int defaultValue)
26 {
27     double value = 0.0;
28     if (params->getNumber(paramName, value))
29         return (unsigned int) value;
30     else
31         return defaultValue;
32 }
33 
34 
ReadCelestiaConfig(string filename,CelestiaConfig * config)35 CelestiaConfig* ReadCelestiaConfig(string filename, CelestiaConfig *config)
36 {
37     ifstream configFile(filename.c_str());
38     if (!configFile.good())
39     {
40         DPRINTF(0, "Error opening config file '%s'.\n", filename.c_str());
41         return config;
42     }
43 
44     Tokenizer tokenizer(&configFile);
45     Parser parser(&tokenizer);
46 
47     if (tokenizer.nextToken() != Tokenizer::TokenName)
48     {
49         DPRINTF(0, "%s:%d 'Configuration' expected.\n", filename.c_str(),
50                 tokenizer.getLineNumber());
51         return config;
52     }
53 
54     if (tokenizer.getStringValue() != "Configuration")
55     {
56         DPRINTF(0, "%s:%d 'Configuration' expected.\n", filename.c_str(),
57                 tokenizer.getLineNumber());
58         return config;
59     }
60 
61     Value* configParamsValue = parser.readValue();
62     if (configParamsValue == NULL || configParamsValue->getType() != Value::HashType)
63     {
64         DPRINTF(0, "%s: Bad configuration file.\n", filename.c_str());
65         return config;
66     }
67 
68     Hash* configParams = configParamsValue->getHash();
69 
70     if (config == NULL)
71         config = new CelestiaConfig();
72 
73 #ifdef CELX
74     config->configParams = configParams;
75     configParams->getString("LuaHook", config->luaHook);
76     config->luaHook = WordExp(config->luaHook);
77 #endif
78 
79     config->faintestVisible = 6.0f;
80     configParams->getNumber("FaintestVisibleMagnitude", config->faintestVisible);
81     configParams->getString("FavoritesFile", config->favoritesFile);
82     config->favoritesFile = WordExp(config->favoritesFile);
83     configParams->getString("DestinationFile", config->destinationsFile);
84     config->destinationsFile = WordExp(config->destinationsFile);
85     configParams->getString("InitScript", config->initScriptFile);
86     config->initScriptFile = WordExp(config->initScriptFile);
87     configParams->getString("DemoScript", config->demoScriptFile);
88     config->demoScriptFile = WordExp(config->demoScriptFile);
89     configParams->getString("AsterismsFile", config->asterismsFile);
90     config->asterismsFile = WordExp(config->asterismsFile);
91     configParams->getString("BoundariesFile", config->boundariesFile);
92     config->boundariesFile = WordExp(config->boundariesFile);
93     configParams->getString("StarDatabase", config->starDatabaseFile);
94     config->starDatabaseFile = WordExp(config->starDatabaseFile);
95     configParams->getString("StarNameDatabase", config->starNamesFile);
96     config->starNamesFile = WordExp(config->starNamesFile);
97     configParams->getString("HDCrossIndex", config->HDCrossIndexFile);
98     config->HDCrossIndexFile = WordExp(config->HDCrossIndexFile);
99     configParams->getString("SAOCrossIndex", config->SAOCrossIndexFile);
100     config->SAOCrossIndexFile = WordExp(config->SAOCrossIndexFile);
101     configParams->getString("GlieseCrossIndex", config->GlieseCrossIndexFile);
102     config->GlieseCrossIndexFile = WordExp(config->GlieseCrossIndexFile);
103     configParams->getString("Font", config->mainFont);
104     configParams->getString("LabelFont", config->labelFont);
105     configParams->getString("TitleFont", config->titleFont);
106     configParams->getString("LogoTexture", config->logoTextureFile);
107     configParams->getString("Cursor", config->cursor);
108 
109     double aaSamples = 1;
110     configParams->getNumber("AntialiasingSamples", aaSamples);
111     config->aaSamples = (unsigned int) aaSamples;
112 
113     config->hdr = false;
114     configParams->getBoolean("HighDynamicRange", config->hdr);
115 
116     config->rotateAcceleration = 120.0f;
117     configParams->getNumber("RotateAcceleration", config->rotateAcceleration);
118     config->mouseRotationSensitivity = 1.0f;
119     configParams->getNumber("MouseRotationSensitivity", config->mouseRotationSensitivity);
120     config->reverseMouseWheel = false;
121     configParams->getBoolean("ReverseMouseWheel", config->reverseMouseWheel);
122     configParams->getString("ScriptScreenshotDirectory", config->scriptScreenshotDirectory);
123     config->scriptScreenshotDirectory = WordExp(config->scriptScreenshotDirectory);
124     config->scriptSystemAccessPolicy = "ask";
125     configParams->getString("ScriptSystemAccessPolicy", config->scriptSystemAccessPolicy);
126 
127     config->ringSystemSections = getUint(configParams, "RingSystemSections", 100);
128     config->orbitPathSamplePoints = getUint(configParams, "OrbitPathSamplePoints", 100);
129     config->shadowTextureSize = getUint(configParams, "ShadowTextureSize", 256);
130     config->eclipseTextureSize = getUint(configParams, "EclipseTextureSize", 128);
131 
132     config->consoleLogRows = getUint(configParams, "LogSize", 200);
133 
134     Value* solarSystemsVal = configParams->getValue("SolarSystemCatalogs");
135     if (solarSystemsVal != NULL)
136     {
137         if (solarSystemsVal->getType() != Value::ArrayType)
138         {
139             DPRINTF(0, "%s: SolarSystemCatalogs must be an array.\n", filename.c_str());
140         }
141         else
142         {
143             Array* solarSystems = solarSystemsVal->getArray();
144             // assert(solarSystems != NULL);
145 
146             for (Array::iterator iter = solarSystems->begin(); iter != solarSystems->end(); iter++)
147             {
148                 Value* catalogNameVal = *iter;
149                 // assert(catalogNameVal != NULL);
150                 if (catalogNameVal->getType() == Value::StringType)
151                 {
152                     config->solarSystemFiles.insert(config->solarSystemFiles.end(),
153                                                     WordExp(catalogNameVal->getString()));
154                 }
155                 else
156                 {
157                     DPRINTF(0, "%s: Solar system catalog name must be a string.\n",
158                             filename.c_str());
159                 }
160             }
161         }
162     }
163 
164     Value* starCatalogsVal = configParams->getValue("StarCatalogs");
165     if (starCatalogsVal != NULL)
166     {
167         if (starCatalogsVal->getType() != Value::ArrayType)
168         {
169             DPRINTF(0, "%s: StarCatalogs must be an array.\n",
170                     filename.c_str());
171         }
172         else
173         {
174             Array* starCatalogs = starCatalogsVal->getArray();
175             assert(starCatalogs != NULL);
176 
177             for (Array::iterator iter = starCatalogs->begin();
178                  iter != starCatalogs->end(); iter++)
179             {
180                 Value* catalogNameVal = *iter;
181                 assert(catalogNameVal != NULL);
182 
183                 if (catalogNameVal->getType() == Value::StringType)
184                 {
185                     config->starCatalogFiles.push_back(WordExp(catalogNameVal->getString()));
186                 }
187                 else
188                 {
189                     DPRINTF(0, "%s: Star catalog name must be a string.\n",
190                             filename.c_str());
191                 }
192             }
193         }
194     }
195 
196 	Value* dsoCatalogsVal = configParams->getValue("DeepSkyCatalogs");
197     if (dsoCatalogsVal != NULL)
198     {
199         if (dsoCatalogsVal->getType() != Value::ArrayType)
200         {
201             DPRINTF(0, "%s: DeepSkyCatalogs must be an array.\n",
202                     filename.c_str());
203         }
204         else
205         {
206             Array* dsoCatalogs = dsoCatalogsVal->getArray();
207             assert(dsoCatalogs != NULL);
208 
209             for (Array::iterator iter = dsoCatalogs->begin();
210                  iter != dsoCatalogs->end(); iter++)
211             {
212                 Value* catalogNameVal = *iter;
213                 assert(catalogNameVal != NULL);
214 
215                 if (catalogNameVal->getType() == Value::StringType)
216                 {
217                     config->dsoCatalogFiles.push_back(WordExp(catalogNameVal->getString()));
218                 }
219                 else
220                 {
221                     DPRINTF(0, "%s: DeepSky catalog name must be a string.\n",
222                             filename.c_str());
223                 }
224             }
225         }
226     }
227 
228     Value* extrasDirsVal = configParams->getValue("ExtrasDirectories");
229     if (extrasDirsVal != NULL)
230     {
231         if (extrasDirsVal->getType() == Value::ArrayType)
232         {
233             Array* extrasDirs = extrasDirsVal->getArray();
234             assert(extrasDirs != NULL);
235 
236             for (Array::iterator iter = extrasDirs->begin();
237                  iter != extrasDirs->end(); iter++)
238             {
239                 Value* dirNameVal = *iter;
240                 if (dirNameVal->getType() == Value::StringType)
241                 {
242                     config->extrasDirs.insert(config->extrasDirs.end(),
243                                               WordExp(dirNameVal->getString()));
244                 }
245                 else
246                 {
247                     DPRINTF(0, "%s: Extras directory name must be a string.\n",
248                             filename.c_str());
249                 }
250             }
251         }
252         else if (extrasDirsVal->getType() == Value::StringType)
253         {
254             config->extrasDirs.insert(config->extrasDirs.end(),
255                                       WordExp(extrasDirsVal->getString()));
256         }
257         else
258         {
259             DPRINTF(0, "%s: ExtrasDirectories must be an array or string.\n", filename.c_str());
260         }
261     }
262 
263     Value* ignoreExtVal = configParams->getValue("IgnoreGLExtensions");
264     if (ignoreExtVal != NULL)
265     {
266         if (ignoreExtVal->getType() != Value::ArrayType)
267         {
268             DPRINTF(0, "%s: IgnoreGLExtensions must be an array.\n",
269                     filename.c_str());
270         }
271         else
272         {
273             Array* ignoreExt = ignoreExtVal->getArray();
274 
275             for (Array::iterator iter = ignoreExt->begin();
276                  iter != ignoreExt->end(); iter++)
277             {
278                 Value* extVal = *iter;
279                 if (extVal->getType() == Value::StringType)
280                 {
281                     config->ignoreGLExtensions.push_back(extVal->getString());
282                 }
283                 else
284                 {
285                     DPRINTF(0, "%s: extension name must be a string.\n", filename.c_str());
286                 }
287             }
288         }
289     }
290 
291     Value* starTexValue = configParams->getValue("StarTextures");
292     if (starTexValue != NULL)
293     {
294         if (starTexValue->getType() != Value::HashType)
295         {
296             DPRINTF(0, "%s: StarTextures must be a property list.\n", filename.c_str());
297         }
298         else
299         {
300             Hash* starTexTable = starTexValue->getHash();
301             string starTexNames[StellarClass::Spectral_Count];
302             starTexTable->getString("O", starTexNames[StellarClass::Spectral_O]);
303             starTexTable->getString("B", starTexNames[StellarClass::Spectral_B]);
304             starTexTable->getString("A", starTexNames[StellarClass::Spectral_A]);
305             starTexTable->getString("F", starTexNames[StellarClass::Spectral_F]);
306             starTexTable->getString("G", starTexNames[StellarClass::Spectral_G]);
307             starTexTable->getString("K", starTexNames[StellarClass::Spectral_K]);
308             starTexTable->getString("M", starTexNames[StellarClass::Spectral_M]);
309             starTexTable->getString("R", starTexNames[StellarClass::Spectral_R]);
310             starTexTable->getString("S", starTexNames[StellarClass::Spectral_S]);
311             starTexTable->getString("N", starTexNames[StellarClass::Spectral_N]);
312             starTexTable->getString("WC", starTexNames[StellarClass::Spectral_WC]);
313             starTexTable->getString("WN", starTexNames[StellarClass::Spectral_WN]);
314             starTexTable->getString("Unknown", starTexNames[StellarClass::Spectral_Unknown]);
315             starTexTable->getString("L", starTexNames[StellarClass::Spectral_L]);
316             starTexTable->getString("T", starTexNames[StellarClass::Spectral_T]);
317             starTexTable->getString("C", starTexNames[StellarClass::Spectral_C]);
318 
319             // One texture for all white dwarf types; not sure if this needs to be
320             // changed. White dwarfs vary widely in temperature, so texture choice
321             // should probably be based on that instead of spectral type.
322             starTexTable->getString("WD", starTexNames[StellarClass::Spectral_D]);
323 
324             string neutronStarTexName;
325             if (starTexTable->getString("NeutronStar", neutronStarTexName))
326             {
327                 config->starTextures.neutronStarTex.setTexture(neutronStarTexName, "textures");
328             }
329 
330             string defaultTexName;
331             if (starTexTable->getString("Default", defaultTexName))
332             {
333                 config->starTextures.defaultTex.setTexture(defaultTexName, "textures");
334             }
335 
336             for (unsigned int i = 0; i < (unsigned int) StellarClass::Spectral_Count; i++)
337             {
338                 if (starTexNames[i] != "")
339                 {
340                     config->starTextures.starTex[i].setTexture(starTexNames[i], "textures");
341                 }
342             }
343         }
344     }
345 
346     // TODO: not cleaning up properly here--we're just saving the hash, not the instance of Value
347     config->params = configParams;
348 
349 #ifndef CELX
350      delete configParamsValue;
351 #endif
352 
353     return config;
354 }
355 
356 
357 float
getFloatValue(const string & name)358 CelestiaConfig::getFloatValue(const string& name)
359 {
360     assert(params != NULL);
361 
362     double x = 0.0;
363     params->getNumber(name, x);
364 
365     return (float) x;
366 }
367 
368 
369 const string
getStringValue(const string & name)370 CelestiaConfig::getStringValue(const string& name)
371 {
372     assert(params != NULL);
373 
374     Value* v = params->getValue(name);
375     if (v == NULL || v->getType() != Value::StringType)
376         return string("");
377 
378     return v->getString();
379 }
380