00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <cstdlib>
00031 #include <cstring>
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <math.h>
00035 #include <stdarg.h>
00036 #include <sys/types.h>
00037 #include <sys/stat.h>
00038 #include <fstream>
00039 #include <boost/regex.hpp>
00040
00041 #include "global.h"
00042 #include "typen.h"
00043 #include "basegfx.h"
00044 #include "misc.h"
00045 #include "sgstream.h"
00046 #include "basestrm.h"
00047 #include "palette.h"
00048 #include "gameoptions.h"
00049
00050 #ifdef _WIN32_
00051 #include <direct.h>
00052 #include <windows.h>
00053 #include <winreg.h>
00054 #include <shlobj.h>
00055 #endif
00056
00057
00058 const char* asc_EnvironmentName = "ASC_CONFIGFILE";
00059 int dataVersion = 0;
00060
00061 const int object_version = 1;
00062 const int technology_version = 1;
00063
00064
00065
00066
00067 void loadpalette ( void )
00068 {
00069 if ( ! asc_paletteloaded ) {
00070 displayLogMessage ( 4, "loading palette ... " );
00071
00072 tnfilestream stream ("palette.pal", tnstream::reading);
00073 stream.readdata( & pal, sizeof(pal));
00074 colormixbufchar = new char [ sizeof ( tmixbuf ) ];
00075 colormixbuf = (pmixbuf) colormixbufchar;
00076 stream.readdata( colormixbuf, sizeof ( *colormixbuf ));
00077
00078 for ( int i= 0; i < 8; i++ ) {
00079 stream.readdata( &xlattables.xl[i], sizeof ( xlattables.a.dark05 ));
00080 xlattables.xl[i][255] = 255;
00081 }
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 #ifdef use_truecolor2pal
00096 stream.readdata( &truecolor2pal_table, sizeof ( truecolor2pal_table ));
00097 stream.readdata( &bi2asc_color_translation_table, sizeof ( bi2asc_color_translation_table ));
00098 #endif
00099 xlatpictgraytable = (ppixelxlattable) malloc( sizeof(*xlatpictgraytable) );
00100
00101 generategrayxlattable(xlatpictgraytable,160,16,&pal);
00102
00103 (*xlatpictgraytable)[255] = 255;
00104
00105 asc_paletteloaded = 1;
00106 displayLogMessage ( 4, "done\n" );
00107 }
00108
00109 }
00110
00111
00112
00113 ASCString resolvePath( ASCString path )
00114 {
00115 #ifdef WIN32
00116 static boost::regex exevar( "\\$\\(?EXEPATH\\)?", boost::regex::icase);
00117 path = boost::regex_replace( path, exevar, ConfigurationFileLocator::Instance().getExecutableLocation(), boost::regex_constants::format_literal );
00118
00119 static boost::regex appdata( "\\$\\(?APPDATA\\)?", boost::regex::icase);
00120 path = boost::regex_replace( path, appdata, ConfigurationFileLocator::Instance().getSpecialPath( CSIDL_APPDATA ), boost::regex_constants::format_literal );
00121
00122 static boost::regex commonappdata( "\\$\\(?COMMON_APPDATA\\)?", boost::regex::icase);
00123 path = boost::regex_replace( path, commonappdata, ConfigurationFileLocator::Instance().getSpecialPath( CSIDL_COMMON_APPDATA ), boost::regex_constants::format_literal );
00124
00125 static boost::regex myDocs( "\\$\\(?MY_DOCUMENTS\\)?", boost::regex::icase);
00126 path = boost::regex_replace( path, myDocs, ConfigurationFileLocator::Instance().getSpecialPath( CSIDL_PERSONAL ), boost::regex_constants::format_literal );
00127 #endif
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 return path;
00143 }
00144
00145
00146 bool makeDirectory ( const ASCString& path )
00147 {
00148 if ( path.empty() )
00149 return false;
00150
00151 ASCString path2 = resolvePath( path );
00152
00153 char tmp[10000];
00154 constructFileName( tmp, 0, path2.c_str(), NULL );
00155
00156 int existence = directoryExist ( tmp );
00157
00158 if ( !existence ) {
00159 int res = createDirectory( tmp );
00160 if ( res ) {
00161 fprintf(stderr, "could neither access nor create directory %s\n", tmp );
00162 return false;
00163 }
00164 }
00165
00166 return true;
00167 }
00168
00169
00170 ASCString getDirectory( ASCString filename )
00171 {
00172 if ( directoryExist( filename ))
00173 return filename;
00174
00175 ASCString directory;
00176
00177 static boost::regex dir( "(.*)[\\\\/:][^\\\\/:]+");
00178 boost::smatch what;
00179 if( boost::regex_match( filename, what, dir)) {
00180 directory.assign( what[1].first, what[1].second );
00181 return directory;
00182 } else {
00183 return ".";
00184 }
00185 }
00186
00187
00188 void ConfigurationFileLocatorCore::setCommandLineParam( const ASCString& path )
00189 {
00190 cmdline = path;
00191 }
00192
00193 void ConfigurationFileLocatorCore::setExecutableLocation( const ASCString& path )
00194 {
00195 exePath = getDirectory( path );
00196
00197 #ifdef WIN32
00198 char buffer[_MAX_PATH];
00199 if( _getcwd( buffer, _MAX_PATH ) )
00200 if ( exePath == "." || exePath == ".\\" )
00201 exePath = buffer;
00202
00203
00204 #endif
00205
00206 }
00207
00208
00209 ASCString ConfigurationFileLocatorCore::getExecutableLocation()
00210 {
00211 return exePath;
00212 }
00213
00214
00215 ASCString ConfigurationFileLocatorCore::getSpecialPath( int type)
00216 {
00217 #ifdef WIN32
00218 TCHAR szPath[MAX_PATH];
00219
00220 if ( SUCCEEDED(SHGetFolderPath( NULL, type, NULL, SHGFP_TYPE_CURRENT, szPath ))) {
00221 ASCString dir = szPath;
00222 appendbackslash ( dir );
00223 dir += "ASC";
00224 appendbackslash ( dir );
00225 return dir;
00226 }
00227
00228 #endif
00229 return "";
00230 }
00231
00232 vector<ASCString> ConfigurationFileLocatorCore::getDefaultDirectory()
00233 {
00234 vector<ASCString> dirs;
00235
00236 #ifdef _WIN32_
00237 HKEY key;
00238 if ( RegOpenKeyEx ( HKEY_LOCAL_MACHINE,
00239 "SOFTWARE\\Advanced Strategic Command\\",
00240 0,
00241 KEY_READ,
00242 &key ) == ERROR_SUCCESS) {
00243
00244 DWORD type;
00245 const int size = 2000;
00246 char buf[size];
00247 DWORD size2 = size;
00248 if ( RegQueryValueEx ( key, "InstallDir2", NULL, &type, (BYTE*)buf, &size2 ) == ERROR_SUCCESS ) {
00249 if ( type == REG_SZ ) {
00250 ASCString dir = buf;
00251 appendbackslash ( dir );
00252 dirs.push_back( dir );
00253 }
00254 }
00255
00256 RegCloseKey ( key );
00257 }
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270 dirs.push_back( "$(MY_DOCUMENTS)\\" );
00271 dirs.push_back( "$(APPDATA)\\" );
00272 dirs.push_back( "$(COMMON_APPDATA)\\" );
00273 dirs.push_back( "$(EXEPATH)\\" );
00274
00275
00276
00277
00278
00279
00280 #else
00281 ASCString dir = getenv("HOME");
00282 appendbackslash ( dir );
00283 dir += ".asc/";
00284 dirs.push_back( dir );
00285 #endif
00286
00287 return dirs;
00288
00289 }
00290
00291
00292
00293
00294 ASCString ConfigurationFileLocatorCore::getConfigFileName()
00295 {
00296 if ( cmdline.length() ) {
00297 configFileType = 1;
00298 displayLogMessage( 7, "ConfigurationFileLocatorCore::getConfigFileName() returns cmdline: " + cmdline + "\n" );
00299 return cmdline;
00300 }
00301
00302 if ( getenv ( asc_EnvironmentName )) {
00303 ASCString res = getenv ( asc_EnvironmentName );
00304 configFileType = 2;
00305 displayLogMessage( 7, "ConfigurationFileLocatorCore::getConfigFileName() returns env dir: " + res + "\n" );
00306 return res;
00307 }
00308
00309 if ( !exePath.empty() && !isPathRelative(exePath) ) {
00310 displayLogMessage( 5, "Exe path is " + exePath + "\n" );
00311 ASCString completeName = exePath + "/" + asc_configurationfile;
00312 if ( exist( completeName )) {
00313 configFileType = 3;
00314 displayLogMessage( 7, "ConfigurationFileLocatorCore::getConfigFileName() returns exepath: " + completeName + "\n" );
00315 return completeName;
00316 }
00317 }
00318
00319 vector<ASCString> list = getDefaultDirectory();
00320 if ( list.size() >= 1 ) {
00321 configFileType = 4;
00322 for ( vector<ASCString>::iterator i = list.begin(); i != list.end(); ++i ) {
00323 ASCString p = resolvePath( *i ) + asc_configurationfile;
00324 if( exist( p )) {
00325 displayLogMessage( 7, "ConfigurationFileLocatorCore::getConfigFileName() returns default dir: " + p + "\n" );
00326 return p;
00327 }
00328 }
00329 ASCString res = resolvePath( list[0] ) + asc_configurationfile;
00330 displayLogMessage( 7, "ConfigurationFileLocatorCore::getConfigFileName() returns list0: " + res + "\n" );
00331 return res;
00332 }
00333
00334 configFileType = 5;
00335 displayLogMessage( 7, "ConfigurationFileLocatorCore::getConfigFileName() returns asc_configurationfile: " + ASCString(asc_configurationfile) + "\n" );
00336 return asc_configurationfile;
00337
00338 }
00339
00340 ASCString ConfigurationFileLocatorCore::getConfigForPrinting()
00341 {
00342 return "";
00343 }
00344
00345 ConfigurationFileLocatorCore::ConfigurationFileLocatorCore() : configFileType(-1)
00346 {
00347 }
00348
00349 void ConfigurationFileLocatorCore::writeDefaultPathsToOptions()
00350 {
00351 #ifdef WIN32
00352 vector<ASCString> dirs = getDefaultDirectory();
00353 CGameOptions::Instance()->searchPathNum = 0;
00354 for ( vector<ASCString>::iterator i = dirs.begin(); i != dirs.end(); ++i )
00355 CGameOptions::Instance()->addSearchPath ( *i );
00356 #else
00357 CGameOptions::Instance()->setDefaultDirectories();
00358 #endif
00359 }
00360
00361 ASCString getConfigFileName ()
00362 {
00363 ASCString configFileName = ConfigurationFileLocator::Instance().getConfigFileName();
00364 if ( !configFileName.empty() )
00365 return configFileName ;
00366 else
00367 return "-none- ; default values used";
00368 }
00369
00370
00371
00372 int readgameoptions ( const ASCString& filename )
00373 {
00374 displayLogMessage ( 4, "loading game options ... " );
00375
00376
00377 displayLogMessage ( 6, ASCString("Path is ") + filename + "; " );
00378
00379
00380 if ( exist ( filename )) {
00381 displayLogMessage ( 6, "found, " );
00382 try {
00383 CGameOptions::Instance()->load( filename );
00384 }
00385 catch ( ParsingError err ) {
00386 fatalError ( "Error parsing text file " + err.getMessage() );
00387 }
00388 catch ( tfileerror err ) {
00389 fatalError ( "Error loading file " + err.getFileName() );
00390 }
00391 catch ( ... ) {
00392 fatalError ( "caught undefined exception" );
00393 }
00394
00395 } else {
00396 displayLogMessage ( 6, "not found, using defaults, " );
00397
00398 ConfigurationFileLocator::Instance().writeDefaultPathsToOptions();
00399
00400 if ( !filename.empty() ) {
00401 CGameOptions::Instance()->setChanged();
00402 if ( writegameoptions( filename ))
00403 displayLogMessage ( 6, "A config file has been sucessfully written to " + filename + " ");
00404 else {
00405 warningMessage("Unable to write file " + filename );
00406 displayLogMessage ( 6, "Failed to write config file to " + filename + " ");
00407 }
00408 }
00409 }
00410
00411 displayLogMessage ( 4, "done\n" );
00412
00413 makeDirectory ( CGameOptions::Instance()->getSearchPath(0) );
00414
00415 return 0;
00416 }
00417
00418 bool writegameoptions ( ASCString configFileName )
00419 {
00420 try {
00421 if ( configFileName.empty() )
00422 configFileName = ConfigurationFileLocator::Instance().getConfigFileName();
00423
00424 configFileName = resolvePath( configFileName );
00425
00426 if ( CGameOptions::Instance()->isChanged() && !configFileName.empty() ) {
00427 char buf[10000];
00428 if ( makeDirectory ( extractPath ( buf, configFileName.c_str() ))) {
00429 CGameOptions::Instance()->save( configFileName );
00430 return true;
00431 }
00432 }
00433 }
00434 catch ( ... ) {
00435
00436 }
00437 return false;
00438 }
00439
00440 void checkFileLoadability ( const ASCString& filename )
00441 {
00442 try {
00443 tnfilestream strm ( filename, tnstream::reading );
00444 strm.readChar();
00445 }
00446 catch ( ASCexception ) {
00447 ASCString msg = "Unable to access " + filename + "\n";
00448 msg += "Make sure the file main.ascdat is in one of the search paths specified in your config file !\n";
00449
00450 ASCString configFileName = ConfigurationFileLocator::Instance().getConfigFileName();
00451 if ( exist( configFileName ))
00452 msg += "The configuration file that is used is: " + configFileName + "\n";
00453 else
00454 if ( !configFileName.empty() ) {
00455 CGameOptions::Instance()->setChanged();
00456 if ( writegameoptions( configFileName ))
00457 msg += "A configuration file has been written to " + configFileName + "\n";
00458 }
00459
00460 msg += "These paths are being searched for data files:\n ";
00461
00462 for ( int i = 0; i < getSearchPathNum(); ++i )
00463 if ( !getSearchPath(i).empty() )
00464 msg += getSearchPath(i) + "\n ";
00465
00466 fatalError ( msg );
00467 }
00468 catch ( ... ) {
00469 fatalError ( "checkFileLoadability threw an unspecified exception\n" );
00470 }
00471 }
00472
00473
00474
00475 void initFileIO ( const ASCString& configFileName, int skipChecks )
00476 {
00477
00478 ConfigurationFileLocator::Instance().setCommandLineParam( configFileName );
00479
00480 readgameoptions( ConfigurationFileLocator::Instance().getConfigFileName() );
00481
00482 for ( int i = 0; i < CGameOptions::Instance()->getSearchPathNum(); i++ )
00483 if ( !CGameOptions::Instance()->getSearchPath(i).empty() ) {
00484 displayLogMessage ( 3, "adding search patch " + CGameOptions::Instance()->getSearchPath(i) + "\n" );
00485 ASCString path = resolvePath( CGameOptions::Instance()->getSearchPath(i) );
00486
00487 if ( isPathRelative( path ) && !isPathRelative( ConfigurationFileLocator::Instance().getConfigFileName() )) {
00488 ASCString path2 = getDirectory( ConfigurationFileLocator::Instance().getConfigFileName() );
00489 appendbackslash ( path2 );
00490 addSearchPath( path2 + path );
00491 } else
00492 addSearchPath ( path );
00493 }
00494 try {
00495 opencontainer ( "*.ascdat" );
00496 }
00497 catch ( tfileerror err ) {
00498 fatalError ( "a fatal IO error occured while mounting the container file %s\n"
00499 "It is probably damaged, try getting a new one.\n", err.getFileName().c_str() );
00500 }
00501 catch ( StreamCompressionError err ) {
00502 fatalError ( "a fatal error occured while decompressing a container file.\n"
00503 "If you have several *.ascdat files in your ASC directory, try removing all but main.ascdat.\n"
00504 "If the error still occurs then, get a new data package from www.asc-hq.org\n" );
00505 }
00506 catch ( ASCexception ) {
00507 fatalError ( "a fatal error occured while mounting the container files \n");
00508 }
00509 catch ( ... ) {
00510 fatalError ( "loading of game failed during pre graphic initializing" );
00511 }
00512
00513 if ( ! (skipChecks & 1 ))
00514 checkFileLoadability ( "palette.pal" );
00515 }
00516
00517 void versionError( const ASCString& filename, const ASCString& location )
00518 {
00519 ASCString msg = "A newer version of the data file '";
00520 msg += filename + "' is required. \nYou can get a new data package at http://www.asc-hq.org\n";
00521 msg += "The old file is " + location;
00522 fatalError( msg );
00523 }