My Documents/Projects/Popcap_1_22_beta/source/sexyappframework/SexyApp.cpp

Go to the documentation of this file.
00001 #include "SexyApp.h"
00002 
00003 #include "..\Crypt\RegKey.h"
00004 #include "SEHCatcher.h"
00005 #include "InternetManager.h"
00006 #include <time.h>
00007 #include <fstream>
00008 #include <direct.h>
00009 #include "BetaSupport.h"
00010 
00011 #ifdef ZYLOM
00012 #include "zylomso.h"
00013 using namespace zylom::zylomso;
00014 #endif
00015 
00016 using namespace Sexy;
00017 
00018 SexyApp* Sexy::gSexyApp = NULL;
00019 
00020 // Groups of 80-byte data
00021 const char DYNAMIC_DATA_BLOCK[400] = 
00022         "DYN00000PACPOPPOPCAPPACPOPPOPCAPBUILDINFOMARKERPACPOPPOPCAPPACPOPPOPCAPXXXXXXXXX"
00023         "00000000PACPOPPOPCAPPACPOPPOPCAPBUILDINFOMARKERPACPOPPOPCAPPACPOPPOPCAPXXXXXXXXX";
00024                                                                         
00025 const char* BUILD_INFO_MARKER           = DYNAMIC_DATA_BLOCK + 80;
00026 const char* SIGNATURE_CODE_MARKER       = DYNAMIC_DATA_BLOCK + 80*2;
00027 const char* BETA_ID_MARKER                      = DYNAMIC_DATA_BLOCK + 80*3;
00028 
00029 SexyApp::SexyApp()
00030 {
00031         gSexyApp = this;
00032 
00033         mTimesPlayed = 0;
00034         mTimesExecuted = 0;
00035         mTimedOut = false;
00036 
00037         mIsRegistered = false;
00038         mBuildUnlocked = false;
00039         mDownloadId = 0;
00040         mRegSource = "ingame";
00041         mSkipAd = false;
00042         mDontUpdate = false;
00043         mLastVerCheckQueryTime = 0;
00044 
00045         mDemoPrefix = "popcap";
00046         mDemoFileName = mDemoPrefix + ".dmo";   
00047         mCompanyName = "PopCap";
00048 
00049         mInternetManager = new InternetManager();
00050         mBetaSupport = NULL;
00051         mBetaValidate = false;  
00052 
00053         SetString("UPDATE_CHECK_BODY", "Contacting PopCap.com to determine if there are any updates available for this product ...");
00054 
00055         char aStr[9] = {0};
00056         strncpy(aStr, BUILD_INFO_MARKER, 8);
00057         mBuildNum = atoi(aStr);
00058 
00059         if (mBuildNum != 0)
00060                 mBuildDate = BUILD_INFO_MARKER + 8;
00061 }
00062 
00063 SexyApp::~SexyApp()
00064 {
00065         delete mBetaSupport;
00066         delete mInternetManager;
00067 }
00068 
00069 bool SexyApp::Validate(const std::string& theUserName, const std::string& theRegCode)
00070 {
00071         BigInt n("42BF94023BBA6D040C8B81D9");
00072         BigInt e("11");
00073 
00074         ulong i;
00075         std::string aDataString;
00076         bool space = false;     
00077         for (i = 0; i < theUserName.size(); i++)
00078         {
00079                 if (theUserName[i] == ' ')
00080                 {
00081                         if (aDataString.length() > 0)
00082                                 space = true;
00083                 }
00084                 else
00085                 {
00086                         if (space)
00087                         {
00088                                 aDataString += " ";
00089                                 space = false;
00090                         }
00091 
00092                         char aChar = theUserName[i];
00093                         for (int j = 0; gRegKeyTranslationTable[j][0] != 0; j++)
00094                                 if (gRegKeyTranslationTable[j][0] == aChar)
00095                                         aChar = gRegKeyTranslationTable[j][1];
00096 
00097                         aDataString += toupper(aChar);
00098                 }
00099         }
00100 
00101         std::string aProduct;
00102         aProduct = mProdName;
00103         for (i = 0; i < aProduct.length(); i++)
00104                 aProduct[i] = toupper(aProduct[i]);
00105 
00106         aDataString += "\n";
00107         aDataString += aProduct;
00108         BigInt aHash = HashString(aDataString, 94);     
00109         
00110         BigInt aSignature = KeyToInt(theRegCode);
00111         BigInt aHashTest = aSignature.ModPow(e, n);
00112 
00113         return aHashTest == aHash;
00114 }
00115 
00116 void SexyApp::ReadFromRegistry()
00117 {
00118         SexyAppBase::ReadFromRegistry();
00119 
00120         if (!mPlayingDemoBuffer)
00121         {
00122                 mTimesPlayed = 0;
00123                 mTimesExecuted = 0;
00124 
00125                 char aFileName[256];
00126                 GetWindowsDirectory(aFileName, 256);
00127                 if (aFileName[strlen(aFileName)-1] != '\\')
00128                         strcat(aFileName, "\\");
00129                 strcat(aFileName, "popcinfo.dat");
00130 
00131                 FILE* fp = fopen(aFileName, "rb");
00132                 if (fp != NULL)
00133                 {
00134                         for (;;)
00135                         {
00136                                 ushort aLen;
00137                                 if (fread(&aLen, 1, sizeof(short), fp) == 0)
00138                                         break;
00139 
00140                                 if (aLen < 256)
00141                                 {
00142                                         char aProdName[256];
00143                                         aProdName[aLen] = '\0';
00144                                         fread(aProdName, aLen, sizeof(char), fp);
00145 
00146                                         if (strcmp(aProdName, mProdName.c_str()) == 0)
00147                                         {
00148                                                 short aShort;
00149                                                 fread(&aShort, 1, sizeof(short), fp);
00150                                                 mTimesPlayed = aShort;
00151 
00152                                                 fread(&aShort, 1, sizeof(short), fp);
00153                                                 mTimesExecuted = aShort;
00154 
00155                                                 break;
00156                                         }
00157                                 }
00158 
00159                                 fseek(fp, sizeof(int), SEEK_CUR);
00160                         }
00161                         fclose(fp);
00162                 }
00163         }
00164 
00165         RegistryReadString("ReferId", &mReferId);
00166         mReferId = GetString("ReferId", mReferId);
00167         mRegisterLink = "http://www.popcap.com/register.php?theGame=" + mProdName + "&referid=" + mReferId;     
00168         RegistryReadString("RegisterLink", &mRegisterLink);
00169 
00170         int anInt;
00171 
00172         if (RegistryReadInteger("DontUpdate", &anInt))
00173                 mDontUpdate = anInt != 0;
00174 
00175         if (RegistryReadInteger("DownloadId", &anInt))
00176                 mDownloadId = anInt;
00177 
00178         RegistryReadString("Variation", &mVariation);
00179 
00180         if (RegistryReadInteger("TimesPlayed", &anInt))
00181         {
00182                 if (!mPlayingDemoBuffer)
00183                 {
00184                         if (mTimesPlayed != anInt)
00185                                 mTimesPlayed = 100;
00186                 }
00187                 else
00188                 {
00189                         mTimesPlayed = anInt;
00190                 }
00191         }
00192 
00193         if (RegistryReadInteger("TimesExecuted", &anInt))
00194         {
00195                 if (!mPlayingDemoBuffer)
00196                 {
00197                         if (mTimesExecuted != anInt)
00198                                 mTimesExecuted = 100;
00199                 }
00200                 else
00201                 {
00202                         mTimesExecuted = anInt;
00203                 }
00204         }
00205         
00206         if (RegistryReadInteger("LastVerCheckQueryTime", &anInt))
00207         {
00208                 mLastVerCheckQueryTime = anInt;
00209         }
00210         else
00211         {
00212                 time_t aTimeNow;
00213                 time(&aTimeNow);
00214 
00215                 mLastVerCheckQueryTime = aTimeNow;
00216         }
00217 
00218         if (RegistryReadString("RegName", &mRegUserName))
00219                 mUserName = mRegUserName;
00220         
00221         RegistryReadString("RegCode", &mRegCode);               
00222 
00223         mIsRegistered |= Validate(mRegUserName, mRegCode);      
00224 
00225         // Override registry values with partner.xml values
00226         mRegisterLink = GetString("RegisterLink", mRegisterLink);
00227         mDontUpdate = GetBoolean("DontUpdate", mDontUpdate);
00228 }
00229 
00230 void SexyApp::WriteToRegistry()
00231 {
00232         SexyAppBase::WriteToRegistry();
00233 
00234         if (!mPlayingDemoBuffer)
00235         {
00236                 char aFileName[256];
00237                 GetWindowsDirectory(aFileName, 256);
00238                 if (aFileName[strlen(aFileName)-1] != '\\')
00239                         strcat(aFileName, "\\");
00240                 strcat(aFileName, "popcinfo.dat");
00241 
00242                 FILE* fp = fopen(aFileName, "r+b");
00243                 if (fp != NULL)
00244                 {
00245                         for (;;)
00246                         {
00247                                 ushort aLen;
00248                                 if (fread(&aLen, 1, sizeof(short), fp) == 0)
00249                                         break;
00250 
00251                                 if (aLen < 256)
00252                                 {
00253                                         char aProdName[256];
00254                                         aProdName[aLen] = '\0';
00255                                         fread(aProdName, aLen, sizeof(char), fp);
00256 
00257                                         if (strcmp(aProdName, mProdName.c_str()) == 0)
00258                                         {
00259                                                 fseek(fp, -(2 + aLen), SEEK_CUR);
00260                                                 break;
00261                                         }
00262                                 }
00263 
00264                                 fseek(fp, sizeof(int), SEEK_CUR);
00265                         }
00266                 }
00267                 else
00268                         fp = fopen(aFileName, "wb");
00269                         
00270                 if (fp != NULL)
00271                 {
00272                         ushort aLen = mProdName.length();
00273                         fwrite(&aLen, 1, sizeof(short), fp);
00274                         fwrite(mProdName.c_str(), aLen, sizeof(char), fp);
00275 
00276                         short aShort = mTimesPlayed;
00277                         fwrite(&aShort, 1, sizeof(short), fp);
00278 
00279                         aShort = mTimesExecuted;
00280                         fwrite(&aShort, 1, sizeof(short), fp);
00281 
00282                         fclose(fp);
00283                 }
00284         }
00285 
00286         RegistryWriteInteger("LastVerCheckQueryTime", mLastVerCheckQueryTime);
00287         RegistryWriteInteger("TimesPlayed", mTimesPlayed);
00288         RegistryWriteInteger("TimesExecuted", mTimesExecuted);
00289 
00290         // This is for "compatibility"
00291         if ((mRegUserName.length() == 0) &&
00292                 (mUserName.length() > 0) &&
00293                 (mRegCode.length() > 0))
00294                 mRegUserName = mUserName;
00295 
00296         if (mRegUserName.length() > 0)
00297                 RegistryWriteString("RegName", mRegUserName);
00298 
00299         if (mRegCode.length() > 0)
00300                 RegistryWriteString("RegCode", mRegCode);
00301 }
00302 
00303 bool SexyApp::OpenHTMLTemplate(const std::string& theTemplateFile, const DefinesMap& theDefinesMap)
00304 {
00305         std::fstream anInStream(theTemplateFile.c_str(), std::ios::in);
00306 
00307         if (!anInStream.is_open())
00308                 return false;
00309 
00310         WIN32_FIND_DATA aFindData;
00311         HANDLE aHandle = FindFirstFile("temp\\tpl*.html", &aFindData);
00312         if (aHandle != NULL)
00313         {
00314                 do
00315                 {
00316                         std::string aFilePath = std::string("temp\\") + aFindData.cFileName;
00317                         DeleteFile(aFilePath.c_str());
00318                 }
00319                 while (FindNextFile(aHandle, &aFindData));
00320                 
00321                 FindClose(aHandle);
00322         }
00323 
00324         mkdir("temp");
00325 
00326         std::string anOutFilename = StrFormat("temp\\tpl%04d.html", rand()%10000);
00327 
00328         //TODO: A better failover case?
00329         std::fstream anOutStream(anOutFilename.c_str(), std::ios::out);
00330         if (!anOutStream.is_open())
00331                 return false;
00332 
00333         char aStr[4096];
00334         while (!anInStream.eof())
00335         {
00336                 anInStream.getline(aStr, 4096);
00337                 
00338                 std::string aNewString = Evaluate(aStr, theDefinesMap);
00339 
00340                 anOutStream << aNewString.c_str() << std::endl;
00341         }
00342         
00343         return OpenURL(GetFullPath(anOutFilename));
00344 }
00345 
00346 bool SexyApp::OpenRegisterPage(DefinesMap theStatsMap)
00347 {
00348 #ifdef ZYLOM
00349         ZylomGS_StandAlone_ShowBuyPage();
00350         return true;
00351 #endif
00352 
00353         // Insert standard defines 
00354         DefinesMap aDefinesMap;
00355         
00356         aDefinesMap.insert(DefinesMap::value_type("Src", mRegSource));
00357         aDefinesMap.insert(DefinesMap::value_type("ProdName", mProdName));
00358         aDefinesMap.insert(DefinesMap::value_type("Version", mProductVersion));
00359         aDefinesMap.insert(DefinesMap::value_type("Variation", mVariation));
00360         aDefinesMap.insert(DefinesMap::value_type("ReferId", mReferId));
00361         aDefinesMap.insert(DefinesMap::value_type("DownloadId", StrFormat("%d", mDownloadId)));
00362         aDefinesMap.insert(DefinesMap::value_type("TimesPlayed", StrFormat("%d", mTimesPlayed)));
00363         aDefinesMap.insert(DefinesMap::value_type("TimesExecuted", StrFormat("%d", mTimesExecuted)));
00364         aDefinesMap.insert(DefinesMap::value_type("TimedOut", mTimedOut ? "Y" : "N"));
00365 
00366         // Insert game specific stats 
00367         std::string aStatsString;
00368         DefinesMap::iterator anItr = theStatsMap.begin();
00369         while (anItr != theStatsMap.end())
00370         {
00371                 std::string aKeyString = anItr->first;
00372                 std::string aValueString = anItr->second;
00373 
00374                 aStatsString += 
00375                         StrFormat("%04X", aKeyString.length()) + aKeyString + 
00376                         "S" +
00377                         StrFormat("%04X", aValueString.length()) + aValueString;
00378 
00379                 ++anItr;
00380         }
00381 
00382         aDefinesMap.insert(DefinesMap::value_type("Stats", aStatsString));
00383 
00384         if (FileExists("register.tpl"))
00385         {
00386                 return OpenHTMLTemplate("register.tpl", aDefinesMap);
00387         }
00388         else
00389         {
00390                 return OpenURL(mRegisterLink);
00391         }       
00392 }
00393 
00394 bool SexyApp::ShouldCheckForUpdate()
00395 {
00396         if (mDontUpdate)
00397                 return false;
00398 
00399 #ifdef ZYLOM
00400         return ZylomUpdateCheckNeeded();
00401 #else
00402         time_t aTimeNow;
00403         time(&aTimeNow);
00404 
00405         // It is set to 0 if we crash, otherwise ask every week
00406         return ((mLastVerCheckQueryTime == 0) || 
00407                 (!mLastShutdownWasGraceful) ||
00408                 ((mLastVerCheckQueryTime != 0) && 
00409                 (aTimeNow - mLastVerCheckQueryTime > 7*24*60*60)));
00410 #endif
00411 }
00412 
00413 void SexyApp::UpdateCheckQueried()
00414 {
00415         time_t aTimeNow;
00416         time(&aTimeNow);
00417 
00418         mLastVerCheckQueryTime = aTimeNow;
00419 }
00420 
00421 void SexyApp::URLOpenSucceeded(const std::string& theURL)
00422 {
00423         SexyAppBase::URLOpenSucceeded(theURL);
00424 
00425         if (mShutdownOnURLOpen)
00426                 mSkipAd = true;
00427 }
00428 
00429 bool SexyApp::OpenRegisterPage()
00430 {
00431         DefinesMap aStatsMap;
00432         return OpenRegisterPage(aStatsMap);
00433 }
00434 
00435 bool SexyApp::CheckSignature(const Buffer& theBuffer, const std::string& theFileName)
00436 {
00437 #ifdef _DEBUG
00438         // Don't check signatures on debug version because it's annoying and the build number
00439         //  will probably be 0 anyway
00440         return true;
00441 #endif
00442 
00443         if (mSkipSignatureChecks)
00444                 return true;
00445 
00446         char aSigStr[25];
00447 
00448         FILE* aFP = fopen((theFileName + ".sig").c_str(), "rb");
00449         if (aFP == NULL)
00450                 return false;
00451 
00452         fread(aSigStr, 1, 24, aFP);
00453         aSigStr[24] = 0;
00454 
00455         fclose(aFP);
00456 
00457         char* aFileData = new char[theBuffer.GetDataLen()+4];
00458         int aFileDataPos = 0;
00459         
00460         char aStr[9] = {0};
00461         strncpy(aStr, SIGNATURE_CODE_MARKER, 8);
00462         int aSignatureCode = atoi(aStr);
00463 
00464         aFileData[aFileDataPos++] = (aSignatureCode & 0xFF);
00465         aFileData[aFileDataPos++] = ((aSignatureCode >> 8) & 0xFF);
00466         aFileData[aFileDataPos++] = ((aSignatureCode >> 16) & 0xFF);
00467         aFileData[aFileDataPos++] = ((aSignatureCode >> 24) & 0xFF);
00468 
00469         theBuffer.SeekFront();
00470         while (!theBuffer.AtEnd())
00471         {
00472                 unsigned char c = theBuffer.ReadByte();
00473                 fread(&c, 1, 1, aFP);
00474                 if (!::isspace(c))
00475                         aFileData[aFileDataPos++] = c;
00476         }       
00477 
00478         // Public RSA stuff
00479         BigInt n("D99BC76AB7B2578738E606F7");
00480         BigInt e("11");
00481                         
00482         BigInt aHash = HashData(aFileData, aFileDataPos, 94);
00483         delete aFileData;
00484         
00485         BigInt aSignature(aSigStr);
00486         BigInt aHashTest = aSignature.ModPow(e, n);
00487 
00488         return aHashTest == aHash;
00489 }
00490 
00491 void SexyApp::PreTerminate()
00492 {
00493 #ifdef ZYLOM
00494         ZylomShowAd();
00495 #else
00496         if ((!mSkipAd) && 
00497                 ((((!mIsRegistered) || (mInternetManager->HasNewAds())) && ((Rand()%2) == 0))))
00498         {
00499                 mInternetManager->TryShowAd();
00500         }
00501 #endif
00502 }
00503 
00504 void SexyApp::OpenUpdateURL()
00505 {
00506 #ifdef ZYLOM
00507         ZylomGS_StandAlone_ShowUpdatePage();
00508 #else
00509         OpenURL(mInternetManager->GetUpdateURL(), true);        
00510 #endif
00511         Shutdown();
00512 }
00513 
00514 void SexyApp::HandleCmdLineParam(const std::string& theParamName, const std::string& theParamValue)
00515 {
00516         if (theParamName == "-version")
00517         {
00518                 // Just print version info and then quit
00519                 
00520                 std::string aVersionString = 
00521                         "Product: " + mProdName + "\r\n" +
00522                         "Version: " + mProductVersion + "\r\n" +
00523                         "Build Num: " + StrFormat("%d", mBuildNum) + "\r\n" +
00524                         "Build Date: " + mBuildDate;
00525 
00526                 MessageBox(NULL, aVersionString.c_str(), "Version Info", MB_ICONINFORMATION | MB_OK);
00527                 DoExit(0);
00528         }
00529         else
00530                 SexyAppBase::HandleCmdLineParam(theParamName, theParamValue);
00531 }
00532 
00533 std::string SexyApp::GetGameSEHInfo()
00534 {
00535         char aGamesPlayedStr[16];
00536         sprintf(aGamesPlayedStr, "%d", mTimesPlayed);
00537 
00538         std::string anInfoString = SexyAppBase::GetGameSEHInfo() + 
00539                 "Times Played: " + std::string(aGamesPlayedStr) + "\r\n";
00540                 "Build Num: " + StrFormat("%d", mBuildNum) + "\r\n" +
00541                 "Build Date: " + mBuildDate + "\r\n";
00542 
00543         if (mReferId.length() != 0)
00544         {
00545                 anInfoString +=
00546                         "ReferId: " + mReferId + "\r\n";
00547         }
00548 
00549         return anInfoString;
00550 }
00551 
00552 void SexyApp::GetSEHWebParams(DefinesMap* theDefinesMap)
00553 {
00554         theDefinesMap->insert(DefinesMap::value_type("username", mUserName));
00555         theDefinesMap->insert(DefinesMap::value_type("buildnum", StrFormat("%d", mBuildNum)));
00556         theDefinesMap->insert(DefinesMap::value_type("builddate", mBuildDate));
00557         theDefinesMap->insert(DefinesMap::value_type("referid", mReferId));     
00558 }
00559 
00560 void SexyApp::PreDisplayHook()
00561 {
00562         if (mBetaValidate && !mBetaSupport->Validate())
00563         {
00564                 Shutdown();
00565                 DoExit(0);
00566                 return;
00567         }
00568 }
00569 
00570 void SexyApp::InitPropertiesHook()
00571 {
00572         // Load properties if we need to
00573         bool checkSig = !IsScreenSaver();
00574         LoadProperties("properties\\partner.xml", false, checkSig);
00575 
00576         // Check to see if this build is unlocked.
00577         if (GetBoolean("NoReg", false))
00578         {
00579                 mIsRegistered = true;
00580                 mBuildUnlocked = true;
00581         }
00582 
00583         mProdName = GetString("ProdName", mProdName);
00584         mIsWindowed = GetBoolean("DefaultWindowed", mIsWindowed);       
00585 
00586         std::string aNewTitle = GetString("Title", "");
00587         if (aNewTitle.length() > 0)
00588                 mTitle = aNewTitle + " " + mProductVersion;     
00589                 
00590         mInternetManager->Init();
00591         mBetaSupport = new BetaSupport(this);
00592 
00593 #ifdef ZYLOM
00594         LoadProperties();
00595         ZylomGS_StandAlone_Init(mZylomGameId, (char*) GetString("BUG_REPORT_TITLE").c_str(), (char*) GetString("BUG_REPORT_BODY").c_str());
00596 #endif
00597 }
00598 
00599 void SexyApp::Init()
00600 {
00601         SEHCatcher::mCrashMessage = 
00602                 "An unexpected error has occured!  Pressing 'Send Report' "
00603                 "will send us helpful debugging information that may help "
00604                 "us resolve this issue in the future.\r\n\r\n"
00605                 "You can also contact us directly at feedback@popcap.com.";
00606 
00607         SEHCatcher::mSubmitMessage = 
00608                 "Please help us out by providing as much information as "
00609                 "you can about this crash. Is this the first time it happened? "
00610                 "Have you used other PopCap Deluxe games successfully before? "
00611                 "Have you upgraded your drivers or any software recently that "
00612                 "may be interfering with this program?";
00613 
00614         SEHCatcher::mSubmitErrorMessage = 
00615                 "Failed to connect to PopCap servers.  Please check your Internet connection.\n"
00616                 "If you are on a dial-up connection, you may have to manually connect to your ISP.";
00617 
00618         SEHCatcher::mSubmitHost = "www.popcap.com";
00619 
00620         OutputDebugString(StrFormat("Product: %s\r\n", mProdName.c_str()).c_str());     
00621         OutputDebugString(StrFormat("BuildNum: %d\r\n", mBuildNum).c_str());
00622         OutputDebugString(StrFormat("BuildDate: %s\r\n", mBuildDate.c_str()).c_str());  
00623 
00624         SexyAppBase::Init();
00625 
00626         if (IsScreenSaver())    
00627                 mSkipAd = true; 
00628 
00629         mTimesExecuted++;
00630 }
00631 
00632 void SexyApp::UpdateFrames()
00633 {
00634         SexyAppBase::UpdateFrames();
00635 
00636         mInternetManager->Update();
00637 }
00638 
00639 #ifdef ZYLOM
00640 
00641 bool SexyApp::ZylomUpdateCheckNeeded()
00642 {
00643         return ZylomGS_StandAlone_UpdateCheckNeeded();
00644 }
00645 
00646 void SexyApp::ZylomShowAd()
00647 {
00648         ZylomGS_StandAlone_ShowAd(mIsRegistered);
00649 }
00650 
00651 #endif

Generated on Mon May 29 12:51:37 2006 for Popcap Framework by  doxygen 1.4.6-NO