AutoDownload.cpp 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568
  1. /*-------------------------------------------------------------------------
  2. * clintlib\AutoDownload.cpp
  3. *
  4. * The implementation of IAutoDownload
  5. *
  6. * See AutoDownload.h for descriptions of all public functions.
  7. *
  8. * Owner:
  9. *
  10. * Copyright 1986-2000 Microsoft Corporation, All Rights Reserved
  11. *-----------------------------------------------------------------------*/
  12. #include "pch.h"
  13. // forward local functions
  14. class CAutoDownloadImpl;
  15. class CLocalFilesVerifier;
  16. CLocalFilesVerifier * CreateLocalFilesVerifier(CAutoDownloadImpl * p, bool bForceCRCCheck, int nOfficialCRC, char * szArtPath);
  17. void DestroyFilesVerifier(CLocalFilesVerifier * p);
  18. bool ContinueLocalFilesVerification(CLocalFilesVerifier * p, DWORD dwTimeAlloted);
  19. void SetLocalFileTime(HANDLE hFile, char *szFileName, SYSTEMTIME * psystime);
  20. void _debugf(const char* format, ...);
  21. /*
  22. Optimization ideas:
  23. Start downloading while we are still building filelist. This would allow for bottom two
  24. progress bars to move at the same time.
  25. */
  26. class CAutoDownloadImpl:
  27. public IAutoDownload,
  28. public IHTTPSessionSink
  29. {
  30. public:
  31. struct CFileInfo
  32. {
  33. int nCRC;
  34. int nSize;
  35. SYSTEMTIME stTime;
  36. };
  37. CAutoDownloadImpl():
  38. m_pHTTPSession(NULL),
  39. m_pLocalFilesVerifier(NULL),
  40. m_cFiles(0),
  41. m_bErrorHasOccurred(false),
  42. m_bReadmeUpdated(false),
  43. m_cBytesCompressionSavings(0),
  44. m_cHTTPServerFails(0),
  45. m_cTotalBytes(0)
  46. {
  47. m_szErrorMessage[0] = 0;
  48. strcpy(m_szURL, "FTPServer Key (in Server's Registry) is probably pointing to an invalid FTP/HTTP Site");
  49. m_cListAllocSize = 8;
  50. m_pszFileList = (char**)realloc(NULL, m_cListAllocSize * sizeof(char*));
  51. *m_pszFileList = NULL;
  52. m_pFileInfo = (CFileInfo*)realloc(NULL, m_cListAllocSize * sizeof(CFileInfo));
  53. m_szFilelistSubDir[0] = '\0';
  54. char path[MAX_PATH + 16];
  55. ::GetModuleFileName(NULL, path, MAX_PATH);
  56. char* p = strrchr(path, '\\');
  57. if (p)
  58. {
  59. p++;
  60. *p = 0; // erase filename
  61. strcpy(m_szEXEPath, path);
  62. }
  63. else
  64. {
  65. m_szEXEPath[0] = '\\';
  66. m_szEXEPath[1] = '\0';
  67. }
  68. }
  69. ~CAutoDownloadImpl()
  70. {
  71. m_pSink->OnAutoUpdateSystemTermination(m_bErrorHasOccurred, m_bNeedToRestart);
  72. if (m_pszFileList)
  73. {
  74. for (unsigned i = 0; i < m_cFiles; ++i)
  75. {
  76. free(m_pszFileList[i]);
  77. }
  78. free(m_pszFileList);
  79. }
  80. if (m_pFileInfo)
  81. free(m_pFileInfo);
  82. if (m_pHTTPSession)
  83. delete m_pHTTPSession;
  84. if(m_pLocalFilesVerifier)
  85. DestroyFilesVerifier(m_pLocalFilesVerifier);
  86. }
  87. public:
  88. ///////////////////////////////////////////////////////////////////////////////////////
  89. void SetFTPSite(const char * szFTPSite, const char * szInitialDirectory, const char * szUsername, const char * szPassword)
  90. {
  91. //
  92. // Prepare m_szURL
  93. //
  94. if (szFTPSite)
  95. {
  96. //
  97. // figure out FTP/HTTP
  98. //
  99. if (_strnicmp(szFTPSite, "ftp://", 6) == 0)
  100. {
  101. /* TODO: make Username and Password work for FTP
  102. if (szUsername && szUsername[0] != 0 && szPassword && szPassword[0] != 0)
  103. {
  104. }
  105. else
  106. */
  107. strcpy(m_szURL, szFTPSite);
  108. }
  109. else // http
  110. {
  111. if (_strnicmp(szFTPSite, "http://", 7) == 0)
  112. {
  113. strcpy(m_szURL, szFTPSite);
  114. }
  115. else
  116. {
  117. strcpy(m_szURL, "http://");
  118. strcat(m_szURL, szFTPSite);
  119. }
  120. }
  121. if (szInitialDirectory)
  122. {
  123. // ensure just one slash seperator
  124. if (m_szURL[0] != '\0' && m_szURL[strlen(m_szURL)-1] != '/' && szInitialDirectory[0] != '/')
  125. strcat(m_szURL, "/");
  126. strcat(m_szURL, szInitialDirectory);
  127. }
  128. // ensure last character is a slash
  129. if (m_szURL[0] != '\0' && m_szURL[strlen(m_szURL)-1] != '/')
  130. strcat(m_szURL, "/");
  131. }
  132. }
  133. ///////////////////////////////////////////////////////////////////////////////////////
  134. // Set the CRC we can verify that the FTP site has the correct FileList.txt
  135. void SetOfficialFileListAttributes(int nCRC, unsigned nFileSize)
  136. {
  137. m_nOfficialCRC = nCRC;
  138. m_nFileListSize = nFileSize;
  139. }
  140. ///////////////////////////////////////////////////////////////////////////////////////
  141. void SetArtPath(const char * szArtPath)
  142. {
  143. //
  144. // Make sure art path is in a friendly format as we copy it
  145. //
  146. int cLen = strlen(szArtPath);
  147. int i,j;
  148. for (i = 0, j = 0; i < cLen; ++i)
  149. if (szArtPath[i] == '/')
  150. m_szArtPath[j++] = '\\';
  151. else
  152. {
  153. if (szArtPath[i] != '\"')
  154. m_szArtPath[j++] = szArtPath[i];
  155. }
  156. if (m_szArtPath[j] != '\\')
  157. {
  158. m_szArtPath[j++] = '\\';
  159. m_szArtPath[j] = '\0';
  160. }
  161. }
  162. ///////////////////////////////////////////////////////////////////////////////////////
  163. void SetFilelistSubDir(const char * pszPath)
  164. {
  165. strncpy(m_szFilelistSubDir, pszPath, sizeof(m_szFilelistSubDir));
  166. // ensure last character is a slash
  167. if (m_szFilelistSubDir[0] != '\0' && m_szFilelistSubDir[strlen(m_szFilelistSubDir)-1] != '/')
  168. strcat(m_szFilelistSubDir, "/");
  169. }
  170. ///////////////////////////////////////////////////////////////////////////////////////
  171. void BeginUpdate(IAutoUpdateSink * pSink, bool bForceCRCCheck, bool bSkipReloader)
  172. {
  173. //
  174. // Make sure the current path is where Allegiance.exe is for the AutoUpdate:
  175. // For Download -AND- for Reloader.exe
  176. //
  177. char path[MAX_PATH + 16];
  178. ::GetModuleFileName(NULL, path, MAX_PATH);
  179. char* p = strrchr(path, '\\');
  180. if (!p)
  181. p = path;
  182. else
  183. p++;
  184. *p = 0; // erase filename
  185. ::SetCurrentDirectory(path);
  186. m_bNeedToMoveFiles = false;
  187. m_bNeedToRestart = false;
  188. m_bForceCRCCheck = bForceCRCCheck;
  189. m_cFilesDownloaded = 0;
  190. m_bSkipReloader = bSkipReloader;
  191. assert(pSink);
  192. m_pSink = pSink;
  193. m_phase = PHASE_GETTING_FILELIST;
  194. m_pSink->OnBeginRetrievingFileList();
  195. ::CreateDirectory("AutoUpdate", NULL);
  196. //
  197. // See if the correct file list happens to be in the AutoUpdate folder
  198. //
  199. char szBuffer[100+MAX_PATH];
  200. int nLocalCRC = FileCRC(".\\AutoUpdate\\FileList.txt", szBuffer);
  201. if(nLocalCRC == m_nOfficialCRC)
  202. {
  203. _debugf("Skipping download of FileList.txt since we already have the correct one in the AutoUpdate folder\n");
  204. m_pSink->OnRetrievingFileListProgress(m_nFileListSize, m_nFileListSize);
  205. BeginLocalFilesAnalysis();
  206. if (m_bErrorHasOccurred)
  207. delete this;
  208. return;
  209. }
  210. //
  211. // We need to download the File List
  212. //
  213. ConnectToHTTPSite();
  214. char szURL[256];
  215. strcpy(szURL, m_szURL);
  216. if (m_szFilelistSubDir[0] != '\0')
  217. {
  218. strcat(szURL, m_szFilelistSubDir);
  219. }
  220. strcat(szURL, "FileList.txt");
  221. char * szInitialList[] = { szURL, "FileList.txt", NULL };
  222. m_pHTTPSession->InitiateDownload(szInitialList, ".\\AutoUpdate\\");
  223. }
  224. ///////////////////////////////////////////////////////////////////////////////////////
  225. /****************************************************************************
  226. * Remarks:
  227. * On slow machines the graphics engine hogs CPU time when updating the
  228. * screen. But we don't want to completely starve it. We want the user
  229. * to be able to click on the "Abort" button if they want. So we give
  230. * the user about 2 frames per second for moving the mouse.
  231. *
  232. */
  233. void HandleAutoDownload(DWORD dwTimeAlloted)
  234. {
  235. DWORD timeStart = timeGetTime();
  236. do
  237. {
  238. if (m_bErrorHasOccurred)
  239. {
  240. delete this;
  241. return;
  242. }
  243. switch(m_phase)
  244. {
  245. case PHASE_VERIFYING_LOCAL:
  246. assert(m_pLocalFilesVerifier);
  247. if(!ContinueLocalFilesVerification(m_pLocalFilesVerifier, dwTimeAlloted))
  248. {
  249. DestroyFilesVerifier(m_pLocalFilesVerifier);
  250. m_pLocalFilesVerifier = NULL;
  251. OnFinishLocalFilesAnalysis();
  252. return;
  253. }
  254. break;
  255. case PHASE_MAIN_DOWNLOAD:
  256. case PHASE_GETTING_FILELIST:
  257. //
  258. // If downloading,
  259. // download another block
  260. //
  261. if(m_pHTTPSession && !m_pHTTPSession->ContinueDownload())
  262. {
  263. //
  264. // At this point we are done downloading either FileList.txt or the actual game files
  265. //
  266. if (m_bErrorHasOccurred)
  267. {
  268. delete this;
  269. return;
  270. }
  271. if (IsDownloadListBuilt())
  272. {
  273. MoveFilesThenRestartOrRelogOn();
  274. return;
  275. }
  276. //
  277. // Now that we are done downloading FileList.txt, scan it and determine what other
  278. // files need to be downloaded.
  279. //
  280. BeginLocalFilesAnalysis();
  281. }
  282. break;
  283. }
  284. } while (timeGetTime() < timeStart + dwTimeAlloted); // spend some time doing this
  285. }
  286. ///////////////////////////////////////////////////////////////////////////////////////
  287. void Abort()
  288. {
  289. if (m_pHTTPSession)
  290. m_pHTTPSession->Abort();
  291. // treat like error
  292. DoError("Aborted.");
  293. m_pSink->OnUserAbort();
  294. }
  295. public:
  296. ///////////////////////////////////////////////////////////////////////////////////////
  297. //
  298. // Methods used by CLocalFilesVerifier
  299. //
  300. ///////////////////////////////////////////////////////////////////////////////////////
  301. void DoError(char * szFormat, ...)
  302. {
  303. char szMsg[sizeof(m_szErrorMessage)];
  304. va_list pArg;
  305. va_start(pArg, szFormat);
  306. _vsnprintf(szMsg, sizeof(szMsg), szFormat, pArg);
  307. va_end(pArg);
  308. DoError(0, szMsg);
  309. }
  310. void DoError(int nInternalErrorCode, char * szFormat, ...)
  311. {
  312. if(!m_bErrorHasOccurred) // first error is most important
  313. {
  314. int nLastError = GetLastError();
  315. char szMsg[sizeof(m_szErrorMessage)];
  316. va_list pArg;
  317. va_start(pArg, szFormat);
  318. _vsnprintf(szMsg, sizeof(szMsg), szFormat, pArg);
  319. va_end(pArg);
  320. OutputDebugString(szMsg);
  321. // write to file
  322. char szFileData[sizeof(szMsg) + 200];
  323. SYSTEMTIME st;
  324. GetLocalTime(&st);
  325. sprintf(szFileData, "\r\n\r\nUpdate attempt at: %d/%d/%02d at %d:%02d:%02d (local time)\r\n%s\r\n\r\n", st.wMonth, st.wDay, st.wYear % 100, st.wHour, st.wMinute, st.wSecond, szMsg);
  326. bool bErrorFileSaved = UTL::AppendFile("UpdateError.txt", szFileData, strlen(szFileData));
  327. char szDisplayMsg[256] = {"?"};
  328. //
  329. // Suggest a resolution
  330. //
  331. if (_stricmp(szFormat, "Aborted.") == 0)
  332. {
  333. sprintf(szDisplayMsg, "Aborted.");
  334. }
  335. else
  336. {
  337. if (nInternalErrorCode == 1)
  338. {
  339. sprintf(szDisplayMsg, "Server is too busy. Try again later.");
  340. }
  341. else
  342. if (nLastError == ERROR_DISK_FULL)
  343. {
  344. sprintf(szDisplayMsg, "Disk didn't have enough space. Free up some space and try again.");
  345. }
  346. else
  347. if (nLastError == ERROR_INTERNET_DISCONNECTED)
  348. {
  349. sprintf(szDisplayMsg, "Disconnected. Reconnect and try again.");
  350. }
  351. else
  352. {
  353. sprintf(szDisplayMsg, "Try again later. As a last resort you may want to reinstall.");
  354. }
  355. if(bErrorFileSaved)
  356. {
  357. strcat(szDisplayMsg, "\n\nSee UpdateError.txt for details.");
  358. }
  359. else
  360. {
  361. strcat(szDisplayMsg, "\n\nUpdateError.txt could not be updated.");
  362. }
  363. }
  364. m_bErrorHasOccurred = true;
  365. strncpy(m_szErrorMessage, szMsg, sizeof(szMsg)-1);
  366. m_pSink->OnError(szDisplayMsg); // forward event
  367. }
  368. }
  369. ///////////////////////////////////////////////////////////////////////////////////////
  370. void AddFileToDownloadList(char * szFileName, unsigned long cFileSize, int nCRC, SYSTEMTIME * pstTime)
  371. {
  372. _debugf("Planning to download %s.\n", szFileName);
  373. if (_stricmp(szFileName, "FileList.txt") == 0)
  374. {
  375. DoError("FileList.txt is invalid. The file \"FileList.txt\" was found within FileList.txt. ");
  376. return;
  377. }
  378. //
  379. // Expand file list memory as needed (or initialize list memory)
  380. //
  381. if ((m_cFiles + 1) >= m_cListAllocSize)
  382. {
  383. m_cListAllocSize = max(32, m_cListAllocSize*2);
  384. m_pszFileList = (char**)realloc(m_pszFileList, m_cListAllocSize * sizeof(char*));
  385. m_pFileInfo = (CFileInfo*)realloc(m_pFileInfo, m_cListAllocSize * sizeof(CFileInfo));
  386. }
  387. //
  388. // Add to list
  389. //
  390. m_pszFileList[m_cFiles] = _strdup(szFileName); // Alloc space for filename and copy it
  391. m_pFileInfo[m_cFiles].nCRC = nCRC;
  392. m_pFileInfo[m_cFiles].nSize = cFileSize;
  393. m_pFileInfo[m_cFiles].stTime = *pstTime;
  394. m_cFiles++;
  395. m_pszFileList[m_cFiles] = NULL; // mark end of ptr list
  396. m_cTotalBytes += cFileSize;
  397. }
  398. ///////////////////////////////////////////////////////////////////////////////////////
  399. void OnAnalysisProgress(float fProgress)
  400. {
  401. m_pSink->OnAnalysisProgress(fProgress);
  402. }
  403. ///////////////////////////////////////////////////////////////////////////////////////
  404. inline bool HasErrorOccurred()
  405. {
  406. return m_bErrorHasOccurred;
  407. }
  408. ///////////////////////////////////////////////////////////////////////////////////////
  409. inline void SetNeedToMoveFiles(bool bNewValue)
  410. {
  411. m_bNeedToMoveFiles = bNewValue;
  412. }
  413. ///////////////////////////////////////////////////////////////////////////////////////
  414. virtual bool ShouldFilterFile(const char * szFileName) // if returns true, then file is not downloaded
  415. {
  416. return m_pSink->ShouldFilterFile(szFileName);
  417. }
  418. ///////////////////////////////////////////////////////////////////////////////////////
  419. bool ShouldRetry(char * szFilename)
  420. {
  421. ZFile file(szFilename);
  422. int n = file.GetLength(); // -1 means error
  423. if (n != -1 && n != 0 && n < 20*1024)
  424. {
  425. char * pData = new char[n+1];
  426. memcpy(pData, file.GetPointer(), n);
  427. pData[n] = 0;
  428. _strupr(pData);
  429. if (strstr(pData, "</HTML>"))
  430. {
  431. m_cHTTPServerFails++;
  432. if (m_cHTTPServerFails >= 10)
  433. {
  434. DoError(1, "Data for file %s is wrong. Tried to download %d times. The HTTP Update server may be too busy or missing the file. Or there may be a problem with your ISP or proxy server. Look at this file in a text editor/web browser for details.", szFilename, m_cHTTPServerFails);
  435. return false;
  436. }
  437. Sleep(500);
  438. return true;
  439. }
  440. }
  441. return false;
  442. }
  443. ///////////////////////////////////////////////////////////////////////////////////////
  444. public:
  445. ///////////////////////////////////////////////////////////////////////////////////////
  446. //
  447. // Events associated with IFTPSessionUpdateSink
  448. //
  449. ///////////////////////////////////////////////////////////////////////////////////////
  450. virtual void OnError(char *szErrorMessage)
  451. {
  452. DoError(szErrorMessage);
  453. }
  454. virtual bool OnFileCompleted(char * szFileName)
  455. {
  456. char szNewFileName[MAX_PATH+10];
  457. strcpy(szNewFileName, m_szEXEPath);
  458. strcat(szNewFileName, "AutoUpdate\\");
  459. strcat(szNewFileName, szFileName);
  460. char szOutOfSyncExplaination[] = {"Perhaps FileList.txt in Lobby server's folder is different than one at FTP Site -OR- Newer file(s) have been added to FTP Site without updating FileList.txt."};
  461. int nLength = CAutoDownloadUtil::GetFileLength(szNewFileName);
  462. if (nLength == (unsigned) -1)
  463. {
  464. DoError("Couldn't determine file length for %s (Error Code %d) ", szFileName, GetLastError());
  465. return true;
  466. }
  467. unsigned cbFilesize = (IsDownloadListBuilt() ? m_pFileInfo[m_cFilesDownloaded].nSize : m_nFileListSize);
  468. int cBytesSaved = cbFilesize - nLength;
  469. if (cBytesSaved < 0)
  470. {
  471. if (ShouldRetry(szNewFileName))
  472. return false;
  473. DoError("File %s was bigger than expected. Make sure FileList.txt is up-to-date. Make sure no compressed files at FTP site got bigger when compressed. Make sure lobby server's FileList.txt is the same as one on FTP Site. ", szFileName);
  474. return true;
  475. }
  476. if (cBytesSaved > 0)
  477. {
  478. //
  479. // Decompress the file.
  480. //
  481. char szDestFileName[MAX_PATH+11];
  482. strcpy(szDestFileName, szNewFileName);
  483. strcat(szDestFileName, "_");
  484. OFSTRUCT dum1/*, dum2*/;
  485. unsigned cbDone = 0;
  486. const int cbBuffer = 128*1024;
  487. INT nSourceHandle = LZOpenFile(szNewFileName, &dum1, OF_READ);
  488. if (nSourceHandle < 0)
  489. {
  490. DoError("Failed to open compressed file %s \n LZ Error Code: %d \n ", szNewFileName, nSourceHandle);
  491. return true;
  492. }
  493. HANDLE hDest = CreateFile(szDestFileName,
  494. GENERIC_WRITE,
  495. FILE_SHARE_READ,
  496. NULL,
  497. CREATE_ALWAYS,
  498. FILE_ATTRIBUTE_NORMAL,
  499. NULL);
  500. if (hDest == INVALID_HANDLE_VALUE)
  501. {
  502. DoError("Failed to create a file to decompress to. %s \n Error Code: %d \n ", szDestFileName, GetLastError());
  503. return true;
  504. }
  505. char * pBuffer = new char[cbBuffer];
  506. if (pBuffer == NULL)
  507. {
  508. DoError("Out of memory: bytes attempted: %d", cbBuffer);
  509. return true;
  510. }
  511. unsigned long cbWritten;
  512. //
  513. // This is where we actually decompress the file.
  514. //
  515. do
  516. {
  517. int nReadResult = LZRead(nSourceHandle, pBuffer, cbBuffer);
  518. if (nReadResult < 0) // a negative return value means error
  519. {
  520. delete[] pBuffer;
  521. LZClose(nSourceHandle);
  522. ::CloseHandle(hDest);
  523. DoError("Failed to Decompress File %s \n LZ Error Code: %d \n ", szNewFileName, nReadResult);
  524. return true;
  525. }
  526. if (!WriteFile(hDest, pBuffer, nReadResult, &cbWritten, NULL))
  527. {
  528. delete[] pBuffer;
  529. LZClose(nSourceHandle);
  530. ::CloseHandle(hDest);
  531. DoError("Failed to Decompress File %s \n Write Error Code: %d \n ", szDestFileName, GetLastError());
  532. return true;
  533. }
  534. assert((int)cbWritten == nReadResult);
  535. cbDone += cbWritten;
  536. } while (cbWritten != 0 && cbDone < cbFilesize);
  537. //
  538. // Post decompression
  539. //
  540. delete[] pBuffer;
  541. LZClose(nSourceHandle);
  542. if (!::CloseHandle(hDest))
  543. {
  544. DoError("Failed to close file after decompression; %s (Error Code:%d) \n ", szDestFileName, GetLastError());
  545. return true;
  546. }
  547. if (cbDone != cbFilesize)
  548. {
  549. if (ShouldRetry(szNewFileName))
  550. return false;
  551. if (cbDone == CAutoDownloadUtil::GetFileLength(szNewFileName))
  552. {
  553. DoError("File size for %s did not match size of file with same name in FileList.txt. %s", szNewFileName, szOutOfSyncExplaination);
  554. return true;
  555. }
  556. DoError("After decompression, file %s wasn't the size expected. %s", szDestFileName, szOutOfSyncExplaination);
  557. return true;
  558. }
  559. DeleteFile(szNewFileName);
  560. if (!MoveFile(szDestFileName, szNewFileName))
  561. {
  562. DoError("Rename file after decompression failed; %s to %s (Error Code:%d) \n ", szNewFileName, szDestFileName, GetLastError());
  563. return true;
  564. }
  565. }
  566. if (IsDownloadListBuilt()) // if szFileName != "FileList.txt"
  567. {
  568. // don't check CRC for FileList.txt here, it's done elsewhere -AND-
  569. // don't send progress update for FileList.txt, only for downloading real list of files
  570. //
  571. // Verify CRC
  572. //
  573. char szErrorMsgBuffer[100+MAX_PATH];
  574. int nCRC;
  575. nCRC = FileCRC(szNewFileName, szErrorMsgBuffer);
  576. if (nCRC == 0)
  577. {
  578. DoError("Couldn't verify downloaded file's CRC: %s\n", szErrorMsgBuffer);
  579. return true;
  580. }
  581. else
  582. if (nCRC != m_pFileInfo[m_cFilesDownloaded].nCRC)
  583. {
  584. if (ShouldRetry(szNewFileName))
  585. return false;
  586. DoError("CRC for %s did not match CRC of file with same name in FileList.txt. %s \n ", szFileName, szOutOfSyncExplaination);
  587. return true;
  588. }
  589. //
  590. // Correct filetime, to speed up next analysis
  591. //
  592. SetLocalFileTime(INVALID_HANDLE_VALUE, szNewFileName, &m_pFileInfo[m_cFilesDownloaded].stTime);
  593. m_cBytesCompressionSavings += cBytesSaved;
  594. m_cFilesDownloaded++;
  595. m_pSink->OnFileCompleted(szFileName); // forward event
  596. if (_stricmp(szFileName, "readme.txt") == 0)
  597. {
  598. m_bReadmeUpdated = true;
  599. ShellExecute(NULL, NULL, ".\\AutoUpdate\\readme.txt", NULL, NULL, SW_SHOWNORMAL);
  600. Sleep(1000); // delay so that Notepad has time to load the readme file before it is moved to the EXE Folder
  601. }
  602. }
  603. m_cHTTPServerFails = 0;
  604. return true;
  605. }
  606. ///////////////////////////////////////////////////////////////////////////////////////
  607. virtual void OnProgress(unsigned long cTotalBytes, const char* szCurrentFile, unsigned long cCurrentFileBytes)
  608. {
  609. if (IsDownloadListBuilt()) // don't send progress update for FileList.txt, only for downloading real list of files
  610. {
  611. // cbUncompressed == total bytes downloaded of already completed file and current file
  612. // (after decompression--except for current file.
  613. // We don't know if current file is compressed until we are done with it.)
  614. unsigned cbUncompressed = cTotalBytes + m_cBytesCompressionSavings;
  615. //
  616. // Estimate time left
  617. //
  618. unsigned cbCurrentReading = cbUncompressed;
  619. unsigned timeCurrent = timeGetTime();
  620. float ftimeElapsed = float(timeCurrent - m_timeLast);
  621. //
  622. // We don't update seconds left too often or else we can encounter precision errors.
  623. // Usually we update it about once a second, except at first. In the beginning we wait
  624. // five seconds to get a good initial reading.
  625. //
  626. if (ftimeElapsed >= (m_cSecsLeft == -1 ? 5000:1000) && cbCurrentReading != m_cbLastReading)
  627. {
  628. assert(ftimeElapsed > 0);
  629. float fCurrentBytesPerMillisecond = float(cbCurrentReading - m_cbLastReading) / ftimeElapsed;
  630. float fWeight = 0.05f;//0.0025f;//max(min(0.50f, ftimeElapsed / 100000.0f), 0.0025f);
  631. if (ftimeElapsed > 5000.0f)
  632. fWeight = 0.25f;
  633. if (m_cSecsLeft == -1)
  634. fWeight = 1.0f;
  635. m_fBytesPerMillisecond = m_fBytesPerMillisecond * (1.0f-fWeight) + fCurrentBytesPerMillisecond * fWeight;
  636. unsigned cbLeft = m_cTotalBytes - cbUncompressed;
  637. unsigned cSecsLeft = int(float(cbLeft-1)/(m_fBytesPerMillisecond*1000.0f)) + 1;
  638. if (cbLeft == 0) // if done, then make sure estimate is right
  639. cSecsLeft = 0;
  640. m_cbLastReading = cbCurrentReading;
  641. m_timeLast = timeCurrent;
  642. m_cSecsLeft = cSecsLeft;
  643. }
  644. else m_pSink->OnProgress(cbUncompressed, szCurrentFile, cCurrentFileBytes, m_cSecsLeft); // forward event
  645. }
  646. else
  647. {
  648. assert(_stricmp("FileList.txt", szCurrentFile) == 0);
  649. m_pSink->OnRetrievingFileListProgress(m_nFileListSize, cCurrentFileBytes);
  650. }
  651. }
  652. ///////////////////////////////////////////////////////////////////////////////////////
  653. virtual void OnTransferFinished()
  654. {
  655. if (IsDownloadListBuilt()) // don't send progress update for FileList.txt, only for downloading real list of files
  656. {
  657. m_pSink->OnTransferFinished(); // forward event
  658. }
  659. else
  660. {
  661. // if FileList is compressed than it's bar will be inaccurately small, so catch up now
  662. m_pSink->OnRetrievingFileListProgress(m_nFileListSize, m_nFileListSize);
  663. }
  664. }
  665. ///////////////////////////////////////////////////////////////////////////////////////
  666. private:
  667. ///////////////////////////////////////////////////////////////////////////////////////
  668. void ConnectToHTTPSite()
  669. {
  670. if (m_pHTTPSession == NULL)
  671. {
  672. m_pHTTPSession = CreateHTTPSession(this);
  673. }
  674. }
  675. ///////////////////////////////////////////////////////////////////////////////////////
  676. void BeginMainDownload()
  677. {
  678. assert(IsDownloadListBuilt());
  679. m_phase = PHASE_MAIN_DOWNLOAD;
  680. m_pSink->OnBeginDownloadProgressBar(m_cTotalBytes, m_cFiles);
  681. ConnectToHTTPSite();
  682. m_fBytesPerMillisecond = 1024.0f/1000.0f; // start off with what a slow modem would do; this will quickly change if true connection rate is different
  683. m_cbLastReading = 0;
  684. m_timeLast = timeGetTime();
  685. m_cSecsLeft = -1;
  686. //
  687. // Convert m_pszFileList be in a format that InitiateDownload() likes,
  688. // that is, make string pairs like so:
  689. // "URL1", "localfile1", "URL2", "localfile2", ..., NULL
  690. //
  691. char ** pszURLs = new char*[2*m_cFiles+1];
  692. pszURLs[2*m_cFiles] = NULL;
  693. char szURL[512];
  694. int nBaseLen = strlen(m_szURL);
  695. strcpy(szURL, m_szURL);
  696. for (unsigned i = 0; i < m_cFiles; i++)
  697. {
  698. strcpy(szURL + nBaseLen, m_pszFileList[i]);
  699. pszURLs[i*2] = _strdup(szURL);
  700. pszURLs[i*2+1] = _strdup(m_pszFileList[i]);
  701. }
  702. m_pHTTPSession->InitiateDownload(pszURLs, ".\\AutoUpdate\\");
  703. for (i = 0; i < m_cFiles * 2; i++)
  704. free(pszURLs[i]);
  705. delete[] pszURLs;
  706. }
  707. ///////////////////////////////////////////////////////////////////////////////////////
  708. void OnFinishLocalFilesAnalysis()
  709. {
  710. if(!m_bErrorHasOccurred)
  711. {
  712. if (IsDownloadListBuilt())
  713. {
  714. BeginMainDownload();
  715. }
  716. else
  717. {
  718. //
  719. // if no files need to be downloaded
  720. //
  721. if (m_bNeedToMoveFiles)
  722. {
  723. MoveFilesThenRestartOrRelogOn();
  724. return;
  725. }
  726. else
  727. {
  728. //
  729. // After analysis, we have determined that no files are
  730. // needed to be downloaded
  731. //
  732. ::DeleteFile("Filelist.txt");
  733. // Note: considered using MoveFileEx, but win95/98 doesn't support it
  734. BOOL bResult = ::MoveFile(".\\AutoUpdate\\FileList.txt", "FileList.txt");
  735. if (!bResult)
  736. {
  737. DoError("Unable to move FileList.txt from AutoUpdate folder to current one. Error Code: %d", GetLastError());
  738. }
  739. delete this;
  740. return;
  741. }
  742. }
  743. }
  744. if(m_bErrorHasOccurred)
  745. {
  746. delete this;
  747. return;
  748. }
  749. //
  750. // At this point we have finished building the file list. Time to download them.
  751. //
  752. }
  753. ///////////////////////////////////////////////////////////////////////////////////////
  754. void MoveFilesThenRestartOrRelogOn()
  755. {
  756. //
  757. // At this point we are done downloading everything.
  758. //
  759. if (!m_bSkipReloader)
  760. {
  761. // Set registry's MoveInProgress to one, meaning move is in progress
  762. HKEY hKey;
  763. DWORD dwValue = 1;
  764. if (ERROR_SUCCESS == ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, ALLEGIANCE_REGISTRY_KEY_ROOT, 0, KEY_WRITE, &hKey))
  765. {
  766. ::RegSetValueEx(hKey, "MoveInProgress", NULL, REG_DWORD, (unsigned char*)&dwValue, sizeof(DWORD));
  767. }
  768. }
  769. //
  770. // Move Files from AutoUpdate folder to Artwork (or EXE-containing) folder
  771. //
  772. char szErrorMsg[2*MAX_PATH+50];
  773. if (!CAutoDownloadUtil::MoveFiles(".\\AutoUpdate\\", m_szArtPath, !m_bSkipReloader, &m_bNeedToRestart, m_bSkipReloader, szErrorMsg, m_pSink))
  774. {
  775. DoError("Error while moving downloaded files (be sure dest file isn't already open): %s", szErrorMsg);
  776. }
  777. if (m_bNeedToRestart && !m_bSkipReloader)
  778. {
  779. // since we are going to exit process soon, we should signal restart
  780. m_pSink->OnAutoUpdateSystemTermination(m_bErrorHasOccurred, m_bNeedToRestart);
  781. if (!LaunchReloaderAndExit(m_bReadmeUpdated))
  782. {
  783. char * sz = "Couldn't complete update process; couldn't launch Reloader.exe.";
  784. DoError(sz);
  785. ::MessageBox(NULL, sz, "Fatal Error", MB_ICONERROR);
  786. ::ExitProcess(0);
  787. }
  788. }
  789. delete this;
  790. }
  791. ////////////////////////////////////////////////////////////////////////////
  792. inline bool IsDownloadListBuilt()
  793. {
  794. return !!m_cFiles;
  795. }
  796. //////////////////////////////////////////////////////////////////////////
  797. void BeginLocalFilesAnalysis()
  798. {
  799. assert(m_pLocalFilesVerifier == NULL);
  800. m_phase = PHASE_VERIFYING_LOCAL;
  801. m_pSink->OnBeginAnalysis();
  802. m_pLocalFilesVerifier = CreateLocalFilesVerifier(this, m_bForceCRCCheck, m_nOfficialCRC, m_szArtPath);
  803. }
  804. //////////////////////////////////////////////////////////////////////////
  805. private: // Data members
  806. char m_szArtPath[MAX_PATH];
  807. char m_szEXEPath[MAX_PATH];
  808. char m_szFilelistSubDir[MAX_PATH];
  809. bool m_bNeedToMoveFiles;
  810. bool m_bNeedToRestart;
  811. bool m_bErrorHasOccurred;
  812. bool m_bForceCRCCheck;
  813. bool m_bReadmeUpdated;
  814. bool m_bSkipReloader;
  815. float m_fBytesPerMillisecond;
  816. unsigned m_cbLastReading;
  817. unsigned m_timeLast;
  818. unsigned m_cSecsLeft;
  819. char m_szURL[256];
  820. char m_szUsername[128];
  821. char m_szPassword[128];
  822. char ** m_pszFileList; // list of files to download
  823. unsigned m_cFiles;
  824. unsigned long m_cListAllocSize; // number of bytes for alloc-ed pointers for list
  825. CFileInfo * m_pFileInfo; // pointer to array of FileInfo's
  826. unsigned m_cFilesDownloaded;
  827. unsigned m_cHTTPServerFails; // number of time http server returns a web page instead of the file
  828. unsigned long m_cTotalBytes; // total bytes of files in the list (uncompressed)
  829. unsigned m_cBytesCompressionSavings; // used to help keep progress bars accurate
  830. IHTTPSession * m_pHTTPSession;
  831. int m_nOfficialCRC; // CRC of lobby server's FileList.txt
  832. unsigned m_nFileListSize; // length of server's FileList.txt
  833. char m_szErrorMessage[1024];
  834. IAutoUpdateSink * m_pSink; // Event Sink for UI in wintrek/pigs
  835. CLocalFilesVerifier * m_pLocalFilesVerifier;
  836. enum PHASE
  837. {
  838. PHASE_GETTING_FILELIST,
  839. PHASE_VERIFYING_LOCAL,
  840. PHASE_MAIN_DOWNLOAD
  841. };
  842. PHASE m_phase;
  843. };
  844. IAutoDownload * CreateAutoDownload()
  845. {
  846. return new CAutoDownloadImpl();
  847. }
  848. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  849. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  850. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  851. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  852. /*-------------------------------------------------------------------------
  853. * CLocalFilesVerifier
  854. *-------------------------------------------------------------------------
  855. * Purpose:
  856. * Scan FileList.txt and figure out which files are different that is,
  857. * which files need to be downloaded.
  858. *
  859. */
  860. class CLocalFilesVerifier
  861. {
  862. public:
  863. CLocalFilesVerifier(CAutoDownloadImpl * pCreator, bool bForceCRCCheck, int nOfficialCRC, char * szArtPath) :
  864. m_pCreator(pCreator),
  865. m_file(".\\AutoUpdate\\FileList.txt"),
  866. m_szArtPath(szArtPath),
  867. m_bForceCRCCheck(bForceCRCCheck)
  868. {
  869. m_pStart = NULL; // set to null incase m_file.IsValid is invalid
  870. m_pCurrent = NULL;
  871. m_pEnd = NULL;
  872. m_nLineNumber = 0;
  873. //
  874. // Open and read FileList.txt
  875. //
  876. if(!m_file.IsValid())
  877. {
  878. m_pCreator->DoError("Couldn't open FileList.txt (Error Code: %d) ", GetLastError());
  879. return;
  880. }
  881. int nSize = m_file.GetLength();
  882. m_pStart = new char[nSize];
  883. m_pCurrent = m_pStart;
  884. if (m_file.Read(m_pCurrent, nSize) != (DWORD) nSize)
  885. {
  886. m_pCreator->DoError("Couldn't read FileList.txt (Error Code: %d) ", GetLastError());
  887. return;
  888. }
  889. // verify FileList.txt downloaded valid
  890. if (MemoryCRC(m_pStart, (unsigned)nSize) != nOfficialCRC)
  891. {
  892. m_pCreator->DoError("FileList.txt downloaded from FTP site is different than the one the Lobby Server has in its local directory. Make sure these files have the same CRC. ");
  893. return;
  894. }
  895. m_pEnd = m_pCurrent + nSize;
  896. }
  897. ~CLocalFilesVerifier()
  898. {
  899. if (m_pStart)
  900. {
  901. delete[] m_pStart;
  902. if (!m_pCreator->HasErrorOccurred() && m_pCurrent != m_pEnd)
  903. {
  904. m_pCreator->DoError("The file fileList.txt downloaded from server has a bad format near or at line: %d. ", m_nLineNumber);
  905. }
  906. }
  907. }
  908. /*-------------------------------------------------------------------------
  909. * ContinueAnalysis()
  910. *-------------------------------------------------------------------------
  911. * Returns:
  912. * true if analysis needs to be continued.
  913. * false if analysis is done or error occurs.
  914. *
  915. */
  916. bool ContinueAnalysis(DWORD dwTimeAlloted)
  917. {
  918. DWORD timeStart = timeGetTime();
  919. do
  920. {
  921. for (int i = 0; i < 50; ++i) // check up to 50 files before even calling timeGetTime()
  922. {
  923. //
  924. // Parse file data
  925. //
  926. if (m_pCurrent < m_pEnd - 40)
  927. {
  928. m_nLineNumber++;
  929. SYSTEMTIME systime;
  930. systime.wYear = atoi(m_pCurrent);
  931. m_pCurrent += 4;
  932. if (*(m_pCurrent++) != '/')
  933. return false;
  934. systime.wMonth = atoi(m_pCurrent);
  935. m_pCurrent += 2;
  936. if (*(m_pCurrent++) != '/')
  937. return false;
  938. systime.wDay = atoi(m_pCurrent);
  939. m_pCurrent += 2;
  940. if (*(m_pCurrent++) != ' ')
  941. return false;
  942. systime.wHour = atoi(m_pCurrent);
  943. m_pCurrent += 2;
  944. if (*(m_pCurrent++) != ':')
  945. return false;
  946. systime.wMinute = atoi(m_pCurrent);
  947. m_pCurrent += 2;
  948. if (*(m_pCurrent++) != ':')
  949. return false;
  950. systime.wSecond = atoi(m_pCurrent);
  951. m_pCurrent += 2;
  952. if (*(m_pCurrent++) != ' ')
  953. return false;
  954. int nFileLength = atol(m_pCurrent);
  955. m_pCurrent += 9;
  956. if (*(m_pCurrent++) != ' ')
  957. return false;
  958. int nCRC = UTL::hextoi(m_pCurrent);
  959. m_pCurrent += 8;
  960. if (*(m_pCurrent++) != ' ')
  961. return false;
  962. char * pLineEnd = strchr(m_pCurrent, '\r');
  963. *pLineEnd = '\0';
  964. char * szm_fileName = m_pCurrent;
  965. systime.wMilliseconds = 0;
  966. bool bTookAlotOfCPUTime = ConsiderDownloadingFile(m_pCurrent, &systime, nCRC, nFileLength);
  967. if (m_pCreator->HasErrorOccurred())
  968. return false;
  969. m_pCurrent = pLineEnd + 2; // + 2 to skip pass "\r\n"
  970. if(bTookAlotOfCPUTime)
  971. break; // had to check CRC for this file so check how long we've taken
  972. }
  973. else
  974. {
  975. m_pCreator->OnAnalysisProgress(1.0f);
  976. return false;
  977. }
  978. }
  979. } while (timeGetTime() < timeStart + dwTimeAlloted); // spend some time doing this
  980. float fProgress = float(m_pCurrent - m_pStart) / float(m_pEnd - m_pStart);
  981. m_pCreator->OnAnalysisProgress(fProgress);
  982. return true;
  983. }
  984. private:
  985. /*-------------------------------------------------------------------------
  986. * IsTimeClose()
  987. *-------------------------------------------------------------------------
  988. * Returns: true only if two system times are somewhat close, within a tolerance
  989. * of cSeconds. cSeconds must be low, less than 100 is definintely safe.
  990. * If you want to go higher and really want to know the max, do the math yourself
  991. *
  992. * Remarks: AutoUpdate needs this because Win98 is flakly, and sometimes
  993. * when I set the filetime, it's off by a second.
  994. */
  995. bool IsTimeClose(SYSTEMTIME * pst1, SYSTEMTIME * pst2, int cSeconds)
  996. {
  997. FILETIME ft1;
  998. FILETIME ft2;
  999. assert(cSeconds < 100 && cSeconds >= 0);
  1000. // converting to filetime takes care of leap year and all other weird date inconsistencies
  1001. SystemTimeToFileTime(pst1, &ft1);
  1002. SystemTimeToFileTime(pst2, &ft2);
  1003. __int64 t1 = *((__int64*)(&ft1));
  1004. __int64 t2 = *((__int64*)(&ft2));
  1005. __int64 diff = (t2 - t1);
  1006. if ((diff >= 0 ? diff : - diff) / 10000000 <= cSeconds)
  1007. return true;
  1008. return false;
  1009. }
  1010. /*-------------------------------------------------------------------------
  1011. * ConsiderDownloadingFile()
  1012. *-------------------------------------------------------------------------
  1013. * Parameters:
  1014. * szFileName: Raw filename without path.
  1015. * other params are ideal attributes of the file, attributes of the file located
  1016. * on the FTP server (in decompressed form)
  1017. *
  1018. * Purpose:
  1019. * Consider adding szFileName to the download list
  1020. *
  1021. * Returns:
  1022. * false: if file is was quickly considered
  1023. * true : if file took some CPU time to look at closely.
  1024. */
  1025. bool ConsiderDownloadingFile(char *szFileName, SYSTEMTIME * psystime, int nCRC, int nFileLength)
  1026. {
  1027. if (m_pCreator->ShouldFilterFile(szFileName))
  1028. return false;
  1029. SYSTEMTIME systimeLocal;
  1030. int nLocalFileLength;
  1031. char szFileNameWithPath[MAX_PATH+20];
  1032. CAutoDownloadUtil::GetFileNameWithPath(szFileNameWithPath, szFileName, m_szArtPath, ".\\");
  1033. HANDLE hFile = OpenAndGetFileInfo(szFileNameWithPath, &systimeLocal, &nLocalFileLength);
  1034. bool bNewFile;
  1035. if (hFile == INVALID_HANDLE_VALUE)
  1036. {
  1037. if(GetLastError() != ERROR_FILE_NOT_FOUND)
  1038. {
  1039. m_pCreator->DoError("Before determining if we needed to download a file, failed open local file (%s); Error Code: %d ", szFileName, GetLastError());
  1040. return false;
  1041. }
  1042. bNewFile = true;
  1043. }
  1044. else bNewFile = false;
  1045. bool bIsFileLengthWrong = nFileLength != nLocalFileLength;
  1046. if (bIsFileLengthWrong ||
  1047. bNewFile ||
  1048. !IsTimeClose(psystime, &systimeLocal, 3) || // if not within 3 seconds
  1049. m_bForceCRCCheck)
  1050. {
  1051. //
  1052. // Okay, times are different, let's be ultra-sure we need to download this file,
  1053. // let's do a CRC check
  1054. //
  1055. char szBuffer[100+MAX_PATH];
  1056. int nLocalCRC;
  1057. if (!bNewFile && (!bIsFileLengthWrong || m_bForceCRCCheck))
  1058. {
  1059. nLocalCRC = FileCRC(hFile, szBuffer);
  1060. if (nLocalCRC == 0)
  1061. {
  1062. m_pCreator->DoError("Error during gettings CRC: %s", szBuffer);
  1063. ::CloseHandle(hFile);
  1064. return true;
  1065. }
  1066. }
  1067. sprintf(szBuffer, ".\\AutoUpdate\\%s", szFileName);
  1068. if (bIsFileLengthWrong || nLocalCRC != nCRC || bNewFile)
  1069. {
  1070. //
  1071. // Let's see if the up-to-date file happens to be in the AutoUpdate folder
  1072. //
  1073. nLocalCRC = FileCRC(szBuffer, NULL);
  1074. if (nLocalCRC == nCRC)
  1075. {
  1076. // no need to download this one, we've already got it!
  1077. // but we still need to move it
  1078. m_pCreator->SetNeedToMoveFiles(true);
  1079. _debugf("%s with correct CRC was found in AutoUpdate folder. Planning to move it later. (Resetting filetime just in case.) \n", szBuffer);
  1080. // make sure has correct time; even though it's probably valid
  1081. SetLocalFileTime(INVALID_HANDLE_VALUE, szBuffer, psystime);
  1082. }
  1083. else
  1084. {
  1085. m_pCreator->AddFileToDownloadList(szFileName, nFileLength, nCRC, psystime);
  1086. }
  1087. }
  1088. else
  1089. {
  1090. //
  1091. // Okay, at this point, we already have the right file, it just has the
  1092. // wrong time.
  1093. //
  1094. if (!m_bForceCRCCheck)
  1095. _debugf("Correcting filetime for %s, which was found to have wrong time but correct CRC.\n", szFileName);
  1096. // Make sure file has right time so we don't get here again.
  1097. SetLocalFileTime(hFile, szFileNameWithPath, psystime);
  1098. // since we already have the right file in the EXE or Artwork folder, delete one
  1099. // of same name in AutoUpdate folder (in the rare event that a old copy of one exists there)
  1100. ::DeleteFile(szBuffer);
  1101. }
  1102. ::CloseHandle(hFile);
  1103. return true;
  1104. }
  1105. ::CloseHandle(hFile);
  1106. return false;
  1107. }
  1108. //////////////////////////////////////////////////////////////////////////
  1109. HANDLE OpenAndGetFileInfo(char * szFileName, SYSTEMTIME * psystimeTrue, int * pnLocalFileLength)
  1110. {
  1111. HANDLE hFile = CreateFile(szFileName,
  1112. GENERIC_READ | GENERIC_WRITE,
  1113. FILE_SHARE_READ,
  1114. NULL,
  1115. OPEN_EXISTING,
  1116. FILE_ATTRIBUTE_NORMAL,
  1117. NULL);
  1118. if (hFile == INVALID_HANDLE_VALUE)
  1119. {
  1120. // try again with just read rights
  1121. hFile = CreateFile(szFileName,
  1122. GENERIC_READ,
  1123. FILE_SHARE_READ,
  1124. NULL,
  1125. OPEN_EXISTING,
  1126. FILE_ATTRIBUTE_NORMAL,
  1127. NULL);
  1128. if (hFile == INVALID_HANDLE_VALUE)
  1129. return INVALID_HANDLE_VALUE;
  1130. }
  1131. FILETIME ft;
  1132. BOOL b = GetFileTime(hFile, NULL, NULL, &ft);
  1133. assert(b);
  1134. b = FileTimeToSystemTime(&ft, psystimeTrue);
  1135. assert(b);
  1136. *pnLocalFileLength = ::GetFileSize(hFile, NULL);
  1137. assert(*pnLocalFileLength != 0xFFFFFFFF);
  1138. return hFile;
  1139. }
  1140. private:
  1141. char * m_pStart;
  1142. char * m_pCurrent;
  1143. char * m_pEnd;
  1144. ZFile m_file;
  1145. int m_nLineNumber;
  1146. bool m_bForceCRCCheck;
  1147. char * m_szArtPath;
  1148. CAutoDownloadImpl * m_pCreator;
  1149. };
  1150. CLocalFilesVerifier * CreateLocalFilesVerifier(CAutoDownloadImpl * p, bool bForceCRCCheck, int nOfficialCRC, char * szArtPath)
  1151. {
  1152. return new CLocalFilesVerifier(p, bForceCRCCheck, nOfficialCRC, szArtPath);
  1153. }
  1154. void DestroyFilesVerifier(CLocalFilesVerifier * p)
  1155. {
  1156. delete p;
  1157. }
  1158. bool ContinueLocalFilesVerification(CLocalFilesVerifier * p, DWORD dwTimeAlloted)
  1159. {
  1160. return p->ContinueAnalysis(dwTimeAlloted);
  1161. }
  1162. bool LaunchReloaderAndExit(bool bReLaunchAllegianceAsMinimized)
  1163. {
  1164. // Need to restart allegiance
  1165. char szCommandLine[MAX_PATH];
  1166. char * szReadme = bReLaunchAllegianceAsMinimized ? "-Minimized" : "-Normal";
  1167. // This command-line needs to be in sync with the command-line reader in Reloader.exe
  1168. sprintf(szCommandLine, "%ld %s %s", ::GetCurrentProcessId(), szReadme, strchr(::GetCommandLine(), ' '));
  1169. //
  1170. // Launch Reloader.exe
  1171. //
  1172. int nRet = (int)ShellExecute(0,
  1173. "Open",
  1174. "Reloader.exe",
  1175. szCommandLine, // re-feed the original command-line back into Allegiance.exe
  1176. NULL,
  1177. SW_SHOWNORMAL);
  1178. if(nRet <= 32)
  1179. {
  1180. // check again for dev/manual builds
  1181. int nRet2 = (int)ShellExecute(0,
  1182. "Open",
  1183. "..\\Reloader\\Reloader.exe",
  1184. szCommandLine, // re-feed the original command-line back into Allegiance.exe
  1185. NULL,
  1186. SW_SHOWNORMAL);
  1187. if (nRet2 <= 32)
  1188. return false;
  1189. }
  1190. //
  1191. // At this point RELOADER is running so Client needs to shutdown.
  1192. //
  1193. // we don't need any destructors slowing us down...time to die
  1194. ::ExitProcess(0);
  1195. return true;
  1196. }
  1197. //////////////////////////////////////////////////////////////////////////
  1198. void SetLocalFileTime(HANDLE hFile, char *szFileName, SYSTEMTIME * psystime)
  1199. {
  1200. bool bOpenHere = hFile == INVALID_HANDLE_VALUE;
  1201. if (bOpenHere)
  1202. {
  1203. hFile = CreateFile(szFileName,
  1204. GENERIC_READ | GENERIC_WRITE,
  1205. FILE_SHARE_READ,
  1206. NULL,
  1207. OPEN_EXISTING,
  1208. FILE_ATTRIBUTE_NORMAL,
  1209. NULL);
  1210. if (hFile == INVALID_HANDLE_VALUE)
  1211. {
  1212. _debugf("Failed to open file before trying to reset filetime, (%s); Error Code: %d ", szFileName, GetLastError());
  1213. return;
  1214. }
  1215. }
  1216. FILETIME ft;
  1217. BOOL b = SystemTimeToFileTime(psystime, &ft);
  1218. assert(b);
  1219. b = SetFileTime(hFile, NULL, NULL, &ft);
  1220. if (!b)
  1221. _debugf("Unabled to reset file time; we must only have read access.\n");
  1222. if (bOpenHere)
  1223. ::CloseHandle(hFile);
  1224. }