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