Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1005 lines
26 KiB

  1. #include "util.h"
  2. #include "patchdownload.h"
  3. #include "sdsutils.h"
  4. extern "C"
  5. {
  6. #include "crc32.h"
  7. }
  8. #define CR 13
  9. HANDLE g_hLogFile = NULL;
  10. extern HINF g_hInf;
  11. extern HINSTANCE g_hInstance;
  12. struct LangID
  13. {
  14. DWORD dwLangID;
  15. char szLanguage[3];
  16. };
  17. const LangID g_LangID [] =
  18. {
  19. {0x404, "TW"},
  20. {0x804, "CN"},
  21. {0x405, "CS"},
  22. {0x406, "DA"},
  23. {0x413, "NL"},
  24. {0x409, "EN"},
  25. {0x40B, "FI"},
  26. {0x40C, "FR"},
  27. {0x407, "DE"},
  28. {0x408, "EL"},
  29. {0x40E, "HU"},
  30. {0x410, "IT"},
  31. {0x411, "JA"},
  32. {0x412, "KO"},
  33. {0x414, "NO"},
  34. {0x415, "PL"},
  35. {0x416, "BR"},
  36. {0x816, "PT"},
  37. {0x419, "RU"},
  38. {0x424, "SL"},
  39. {0xC0A, "ES"},
  40. {0x41D, "SV"},
  41. {0x41E, "TH"},
  42. {0x41F, "TR"},
  43. {0x42A, "VI"},
  44. {0x41B, "SK"},
  45. {0x401, "AR"},
  46. {0x403, "CA"},
  47. {0x42D, "EU"},
  48. {0x40D, "HE"},
  49. {0x40F, "IS"},
  50. {-1, NULL}
  51. };
  52. extern PFSetupFindFirstLine pfSetupFindFirstLine;
  53. extern PFSetupGetStringField pfSetupGetStringField;
  54. extern PFSetupDecompressOrCopyFile pfSetupDecompressOrCopyFile;
  55. PVOID __fastcall MyVirtualAlloc(ULONG Size)
  56. {
  57. return VirtualAlloc( NULL, Size, MEM_COMMIT, PAGE_READWRITE );
  58. }
  59. VOID __fastcall MyVirtualFree(PVOID Allocation)
  60. {
  61. VirtualFree( Allocation, 0, MEM_RELEASE );
  62. }
  63. extern "C" HANDLE CreateSubAllocator(IN ULONG InitialCommitSize, IN ULONG GrowthCommitSize)
  64. {
  65. PSUBALLOCATOR SubAllocator;
  66. ULONG InitialSize;
  67. ULONG GrowthSize;
  68. InitialSize = ROUNDUP2( InitialCommitSize, MINIMUM_VM_ALLOCATION );
  69. GrowthSize = ROUNDUP2( GrowthCommitSize, MINIMUM_VM_ALLOCATION );
  70. SubAllocator = (PSUBALLOCATOR)MyVirtualAlloc( InitialSize );
  71. //
  72. // If can't allocate entire initial size, back off to minimum size.
  73. // Very large initial requests sometimes cannot be allocated simply
  74. // because there is not enough contiguous address space.
  75. //
  76. if ( SubAllocator == NULL )
  77. {
  78. SubAllocator = (PSUBALLOCATOR)MyVirtualAlloc( GrowthSize );
  79. }
  80. if ( SubAllocator == NULL )
  81. {
  82. SubAllocator = (PSUBALLOCATOR)MyVirtualAlloc( MINIMUM_VM_ALLOCATION );
  83. }
  84. if ( SubAllocator != NULL )
  85. {
  86. SubAllocator->NextAvailable = (PCHAR)SubAllocator + ROUNDUP2( sizeof( SUBALLOCATOR ), SUBALLOCATOR_ALIGNMENT );
  87. SubAllocator->LastAvailable = (PCHAR)SubAllocator + InitialSize;
  88. SubAllocator->VirtualList = (PVOID*)SubAllocator;
  89. SubAllocator->GrowSize = GrowthSize;
  90. }
  91. return (HANDLE) SubAllocator;
  92. }
  93. extern "C" PVOID __fastcall SubAllocate(IN HANDLE hAllocator, IN ULONG Size)
  94. {
  95. PSUBALLOCATOR SubAllocator = (PSUBALLOCATOR) hAllocator;
  96. PCHAR NewVirtual;
  97. PCHAR Allocation;
  98. ULONG AllocSize;
  99. ULONG Available;
  100. ULONG GrowSize;
  101. ASSERT( Size < (ULONG)( ~(( SUBALLOCATOR_ALIGNMENT * 2 ) - 1 )));
  102. AllocSize = ROUNDUP2( Size, SUBALLOCATOR_ALIGNMENT );
  103. Available = SubAllocator->LastAvailable - SubAllocator->NextAvailable;
  104. if ( AllocSize <= Available )
  105. {
  106. Allocation = SubAllocator->NextAvailable;
  107. SubAllocator->NextAvailable = Allocation + AllocSize;
  108. return Allocation;
  109. }
  110. //
  111. // Insufficient VM, so grow it. Make sure we grow it enough to satisfy
  112. // the allocation request in case the request is larger than the grow
  113. // size specified in CreateSubAllocator.
  114. //
  115. GrowSize = SubAllocator->GrowSize;
  116. if ( GrowSize < ( AllocSize + SUBALLOCATOR_ALIGNMENT ))
  117. {
  118. GrowSize = ROUNDUP2(( AllocSize + SUBALLOCATOR_ALIGNMENT ), MINIMUM_VM_ALLOCATION );
  119. }
  120. NewVirtual = (PCHAR)MyVirtualAlloc( GrowSize );
  121. // If failed to alloc GrowSize VM, and the allocation could be satisfied
  122. // with a minimum VM allocation, try allocating minimum VM to satisfy
  123. // this request.
  124. //
  125. if (( NewVirtual == NULL ) && ( AllocSize <= ( MINIMUM_VM_ALLOCATION - SUBALLOCATOR_ALIGNMENT )))
  126. {
  127. GrowSize = MINIMUM_VM_ALLOCATION;
  128. NewVirtual = (PCHAR)MyVirtualAlloc( GrowSize );
  129. }
  130. if ( NewVirtual != NULL )
  131. {
  132. // Set LastAvailable to end of new VM block.
  133. SubAllocator->LastAvailable = NewVirtual + GrowSize;
  134. // Link new VM into list of VM allocations.
  135. *(PVOID*)NewVirtual = SubAllocator->VirtualList;
  136. SubAllocator->VirtualList = (PVOID*)NewVirtual;
  137. // Requested allocation comes next.
  138. Allocation = NewVirtual + SUBALLOCATOR_ALIGNMENT;
  139. // Then set the NextAvailable for what's remaining.
  140. SubAllocator->NextAvailable = Allocation + AllocSize;
  141. // And return the allocation.
  142. return Allocation;
  143. }
  144. // Could not allocate enough VM to satisfy request.
  145. return NULL;
  146. }
  147. extern "C" VOID DestroySubAllocator(IN HANDLE hAllocator)
  148. {
  149. PSUBALLOCATOR SubAllocator = (PSUBALLOCATOR) hAllocator;
  150. PVOID VirtualBlock = SubAllocator->VirtualList;
  151. PVOID NextVirtualBlock;
  152. do
  153. {
  154. NextVirtualBlock = *(PVOID*)VirtualBlock;
  155. MyVirtualFree( VirtualBlock );
  156. VirtualBlock = NextVirtualBlock;
  157. }while (VirtualBlock != NULL);
  158. }
  159. HLOCAL ResizeBuffer(IN HLOCAL BufferHandle, IN DWORD Size, IN BOOL Moveable)
  160. {
  161. if (BufferHandle == NULL)
  162. {
  163. if (Size != 0)
  164. {
  165. BufferHandle = LocalAlloc(Moveable ? LMEM_MOVEABLE : LMEM_FIXED, Size);
  166. }
  167. }
  168. else if (Size == 0)
  169. {
  170. BufferHandle = LocalFree(BufferHandle);
  171. BufferHandle=NULL;
  172. }
  173. else
  174. {
  175. HLOCAL TempBufferHandle = LocalReAlloc(BufferHandle, Size, LMEM_MOVEABLE);
  176. if ( TempBufferHandle )
  177. {
  178. BufferHandle = TempBufferHandle;
  179. }
  180. else
  181. {
  182. LocalFree(BufferHandle);
  183. BufferHandle = NULL;
  184. }
  185. }
  186. return BufferHandle;
  187. }
  188. VOID MyLowercase(IN OUT LPSTR String)
  189. {
  190. LPSTR p;
  191. for ( p = String; *p; p++ )
  192. {
  193. if (( *p >= 'A' ) && ( *p <= 'Z' ))
  194. {
  195. *p |= 0x20;
  196. }
  197. }
  198. }
  199. void InitLogFile()
  200. {
  201. char szLogFileName[MAX_PATH], szTmp[MAX_PATH];
  202. HKEY hKey;
  203. BYTE cbData[MAX_PATH];
  204. DWORD dwSize = sizeof(cbData);
  205. if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Advanced INF Setup", 0,
  206. KEY_ALL_ACCESS, &hKey))
  207. {
  208. return;
  209. }
  210. if(ERROR_SUCCESS != RegQueryValueEx(hKey, "AdvpextLog", 0, 0, cbData, &dwSize) ||
  211. lstrcmpi((char*)cbData, "yes"))
  212. {
  213. RegCloseKey(hKey);
  214. return;
  215. }
  216. RegCloseKey(hKey);
  217. if (GetWindowsDirectory(szTmp, sizeof(szTmp)))
  218. {
  219. wsprintf(szLogFileName, "%s\\%s", szTmp, LOGFILENAME);
  220. if (GetFileAttributes(szLogFileName) != 0xFFFFFFFF)
  221. {
  222. // Make a backup of the current log file
  223. lstrcpyn(szTmp, szLogFileName, lstrlen(szLogFileName) - 2 ); // don't copy extension
  224. lstrcat(szTmp, "BAK");
  225. SetFileAttributes(szTmp, FILE_ATTRIBUTE_NORMAL);
  226. DeleteFile(szTmp);
  227. MoveFile(szLogFileName, szTmp);
  228. }
  229. g_hLogFile = CreateFile(szLogFileName, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0,0);
  230. }
  231. }
  232. void WriteToLog(char *pszFormatString, ...)
  233. {
  234. va_list args;
  235. char *pszFullErrMsg = NULL;
  236. DWORD dwBytesWritten;
  237. if (g_hLogFile && g_hLogFile != INVALID_HANDLE_VALUE)
  238. {
  239. va_start(args, pszFormatString);
  240. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_STRING,
  241. (LPCVOID) pszFormatString, 0, 0, (LPTSTR) &pszFullErrMsg, 0, &args);
  242. if (pszFullErrMsg)
  243. {
  244. WriteFile(g_hLogFile, pszFullErrMsg, lstrlen(pszFullErrMsg), &dwBytesWritten, NULL);
  245. LocalFree(pszFullErrMsg);
  246. }
  247. }
  248. }
  249. DWORD GenerateUniqueClientId()
  250. {
  251. CHAR MachineName[MAX_COMPUTERNAME_LENGTH + 1 ];
  252. DWORD MachineNameLength;
  253. DWORD UniqueId;
  254. MachineNameLength = sizeof( MachineName );
  255. GetComputerName( MachineName, &MachineNameLength );
  256. do
  257. {
  258. UniqueId = GetTickCount();
  259. UniqueId = Crc32( UniqueId, MachineName, MachineNameLength );
  260. UniqueId = UniqueId & 0xFFFFFFF0;
  261. }while ( UniqueId == 0 );
  262. return UniqueId;
  263. }
  264. BOOL MySetupDecompressOrCopyFile(IN LPCSTR SourceFile, IN LPCSTR TargetFile)
  265. {
  266. DWORD ErrorCode = pfSetupDecompressOrCopyFile( SourceFile, TargetFile, 0 );
  267. if ( ErrorCode != NO_ERROR ) {
  268. SetLastError( ErrorCode );
  269. return FALSE;
  270. }
  271. else {
  272. SetFileAttributes( TargetFile, FILE_ATTRIBUTE_NORMAL );
  273. return TRUE;
  274. }
  275. }
  276. ULONG __fastcall TextToUnsignedNum(IN LPCSTR Text)
  277. {
  278. LPCSTR p = Text;
  279. ULONG n = 0;
  280. //
  281. // Very simplistic conversion stops at first non digit character, does
  282. // not require null-terminated string, and does not skip any whitespace
  283. // or commas.
  284. //
  285. while (( *p >= '0' ) && ( *p <= '9' )) {
  286. n = ( n * 10 ) + ( *p++ - '0' );
  287. }
  288. return n;
  289. }
  290. LPSTR CombinePaths(
  291. IN LPCSTR ParentPath,
  292. IN LPCSTR ChildPath,
  293. OUT LPSTR TargetPath // can be same as ParentPath if want to append
  294. )
  295. {
  296. ULONG ParentLength = strlen( ParentPath );
  297. LPSTR p;
  298. if ( ParentPath != TargetPath ) {
  299. memcpy( TargetPath, ParentPath, ParentLength );
  300. }
  301. p = TargetPath + ParentLength;
  302. if (( ParentLength > 0 ) &&
  303. ( *( p - 1 ) != '\\' ) &&
  304. ( *( p - 1 ) != '/' )) {
  305. *p++ = '\\';
  306. }
  307. strcpy( p, ChildPath );
  308. return TargetPath;
  309. }
  310. BOOL FixTimeStampOnCompressedFile(IN LPCSTR FileName)
  311. {
  312. //
  313. // NT4 setupapi uses timestamp on compressed file to set on
  314. // the target decompressed file. With streaming download, we
  315. // lose the timestamp on the file. But, the correct timestamp
  316. // lives inside the compressed file, so we'll open the file
  317. // to see if it is a diamond compressed file and if so,
  318. // extract the timestamp and set it on the compressed file.
  319. // Then, when setupapi expands the compressed file, it will
  320. // use that timestamp on the expanded file.
  321. //
  322. // A better fix is probably to tunnel the timestamp in the
  323. // pstream protocol, but too late to change that at this
  324. // point.
  325. //
  326. FILETIME LocalFileTime;
  327. FILETIME UtcFileTime;
  328. BOOL TimeSuccess;
  329. BOOL MapSuccess;
  330. HANDLE hSourceFile;
  331. PUCHAR pSourceFileMapped;
  332. DWORD dwSourceFileSize;
  333. DWORD dwOffset;
  334. USHORT DosDate;
  335. USHORT DosTime;
  336. PUCHAR p;
  337. TimeSuccess = FALSE;
  338. MapSuccess = MyMapViewOfFile(FileName, &dwSourceFileSize, &hSourceFile, (void**)&pSourceFileMapped);
  339. if ( MapSuccess )
  340. {
  341. __try {
  342. p = pSourceFileMapped;
  343. if (( *(DWORD*)( p ) == 'FCSM' ) && // "MSCF"
  344. ( *(BYTE *)( p + 24 ) == 3 ) && // minor version
  345. ( *(BYTE *)( p + 25 ) == 1 ) && // major version
  346. ( *(WORD *)( p + 26 ) == 1 ) && // 1 folder
  347. ( *(WORD *)( p + 28 ) == 1 )) { // 1 file
  348. dwOffset = *(DWORD*)( p + 16 );
  349. if (( dwOffset + 16 ) < dwSourceFileSize ) {
  350. DosDate = *(UNALIGNED WORD*)( p + dwOffset + 10 );
  351. DosTime = *(UNALIGNED WORD*)( p + dwOffset + 12 );
  352. if ( DosDateTimeToFileTime( DosDate, DosTime, &LocalFileTime ) &&
  353. LocalFileTimeToFileTime( &LocalFileTime, &UtcFileTime )) {
  354. TimeSuccess = TRUE;
  355. }
  356. }
  357. }
  358. }
  359. __except(EXCEPTION_EXECUTE_HANDLER)
  360. {
  361. }
  362. MyUnmapViewOfFile( hSourceFile, pSourceFileMapped );
  363. }
  364. if ( TimeSuccess ) {
  365. hSourceFile = CreateFile(
  366. FileName,
  367. GENERIC_WRITE,
  368. FILE_SHARE_READ,
  369. NULL,
  370. OPEN_EXISTING,
  371. 0,
  372. NULL
  373. );
  374. if ( hSourceFile != INVALID_HANDLE_VALUE ) {
  375. if ( ! SetFileTime( hSourceFile, &UtcFileTime, &UtcFileTime, &UtcFileTime )) {
  376. TimeSuccess = FALSE;
  377. }
  378. CloseHandle( hSourceFile );
  379. }
  380. }
  381. return TimeSuccess;
  382. }
  383. BOOL Assert(LPCSTR szText, LPCSTR szFile, DWORD dwLine)
  384. {
  385. CHAR Buffer[ 256 ];
  386. wsprintf( Buffer, "ASSERT( %s ) FAILED, %s (%d)\n", szText, szFile, dwLine );
  387. OutputDebugString( Buffer );
  388. DebugBreak();
  389. return FALSE;
  390. }
  391. BOOL MyMapViewOfFileByHandle(IN HANDLE FileHandle, OUT ULONG *FileSize, OUT PVOID *MapBase)
  392. {
  393. ULONG InternalFileSize;
  394. ULONG InternalFileSizeHigh;
  395. HANDLE InternalMapHandle;
  396. PVOID InternalMapBase;
  397. InternalFileSize = GetFileSize( FileHandle, &InternalFileSizeHigh );
  398. if ( InternalFileSizeHigh != 0 )
  399. {
  400. SetLastError( ERROR_OUTOFMEMORY );
  401. return FALSE;
  402. }
  403. if ( InternalFileSize == 0 )
  404. {
  405. *MapBase = NULL;
  406. *FileSize = 0;
  407. return TRUE;
  408. }
  409. if ( InternalFileSize != 0xFFFFFFFF )
  410. {
  411. InternalMapHandle = CreateFileMapping(
  412. FileHandle,
  413. NULL,
  414. PAGE_WRITECOPY,
  415. 0,
  416. 0,
  417. NULL
  418. );
  419. if ( InternalMapHandle != NULL )
  420. {
  421. InternalMapBase = MapViewOfFile(InternalMapHandle, FILE_MAP_COPY, 0, 0, 0);
  422. CloseHandle( InternalMapHandle );
  423. if ( InternalMapBase != NULL )
  424. {
  425. DWORD dw = ROUNDUP2(InternalFileSize, 64);
  426. if(dw != InternalFileSize)
  427. {
  428. ZeroMemory((PBYTE)InternalMapBase + InternalFileSize, dw - InternalFileSize);
  429. }
  430. *MapBase = InternalMapBase;
  431. *FileSize = InternalFileSize;
  432. return TRUE;
  433. }
  434. }
  435. }
  436. return FALSE;
  437. }
  438. BOOL MyMapViewOfFile(IN LPCSTR FileName, OUT ULONG *FileSize, OUT HANDLE *FileHandle, OUT PVOID *MapBase)
  439. {
  440. HANDLE InternalFileHandle;
  441. BOOL Success;
  442. InternalFileHandle = CreateFileA(
  443. FileName,
  444. GENERIC_READ,
  445. FILE_SHARE_READ | FILE_SHARE_WRITE,
  446. NULL,
  447. OPEN_EXISTING,
  448. FILE_FLAG_SEQUENTIAL_SCAN,
  449. NULL
  450. );
  451. if ( InternalFileHandle != INVALID_HANDLE_VALUE )
  452. {
  453. Success = MyMapViewOfFileByHandle(InternalFileHandle, FileSize, MapBase);
  454. if ( Success )
  455. {
  456. *FileHandle = InternalFileHandle;
  457. return TRUE;
  458. }
  459. CloseHandle( InternalFileHandle );
  460. }
  461. return FALSE;
  462. }
  463. VOID MyUnmapViewOfFile(IN HANDLE FileHandle, IN PVOID MapBase )
  464. {
  465. ULONG LastError = GetLastError();
  466. UnmapViewOfFile( MapBase );
  467. CloseHandle( FileHandle );
  468. SetLastError( LastError );
  469. }
  470. VOID __fastcall ConvertToCompressedFileName(IN OUT LPSTR FileName)
  471. {
  472. ULONG NameLength = strlen( FileName );
  473. ULONG DotIndex = NameLength;
  474. while (( DotIndex > 0 ) && ( FileName[ --DotIndex ] != '.' )) {
  475. if ( FileName[ DotIndex ] == '\\' ) { // end of filename part of path
  476. DotIndex = 0; // name has no extension
  477. break;
  478. }
  479. }
  480. if ( DotIndex > 0 ) { // name has an extension
  481. if (( NameLength - DotIndex ) <= 3 ) { // extension less than 3 chars
  482. FileName[ NameLength++ ] = '_'; // append '_' to extension
  483. FileName[ NameLength ] = 0; // terminate
  484. }
  485. else { // extension more than 3 chars
  486. FileName[ NameLength - 1 ] = '_'; // replace last char with '_'
  487. }
  488. }
  489. else { // name has no extension
  490. FileName[ NameLength++ ] = '.'; // append '.'
  491. FileName[ NameLength++ ] = '_'; // append '_'
  492. FileName[ NameLength ] = 0; // terminate
  493. }
  494. }
  495. LPTSTR __fastcall MySubAllocStrDup(IN HANDLE SubAllocator, IN LPCSTR String)
  496. {
  497. ULONG Length = lstrlen( String );
  498. LPTSTR Buffer = (LPTSTR)SubAllocate( SubAllocator, Length + 1 );
  499. if ( Buffer )
  500. {
  501. memcpy( Buffer, String, Length ); // no need to copy NULL terminator
  502. }
  503. return Buffer;
  504. }
  505. //
  506. // Copied from Windows 95 unistal.exe cfg.c function CfgGetField
  507. BOOL GetFieldString(LPSTR lpszLine, int iField, LPSTR lpszField, int cbSize)
  508. {
  509. int cbField;
  510. LPSTR lpszChar, lpszEnd;
  511. // Find the field we are looking for
  512. lpszChar = lpszLine;
  513. // Each time we see a separator, decrement iField
  514. while (iField > 0 && (BYTE)*lpszChar > CR) {
  515. if (*lpszChar == '=' || *lpszChar == ',' || *lpszChar == ' ' ) {
  516. iField--;
  517. while (*lpszChar == '=' || *lpszChar== ',' || *lpszChar == ' ' && (BYTE)*lpszChar > 13)
  518. lpszChar++;
  519. }
  520. else
  521. lpszChar++;
  522. }
  523. // If we still have fields remaining then something went wrong
  524. if (iField)
  525. return FALSE;
  526. // Now find the end of this field
  527. lpszEnd = lpszChar;
  528. while (*lpszEnd != '=' && *lpszEnd != ',' && *lpszEnd != ' ' && (BYTE)*lpszEnd > CR)
  529. lpszEnd++;
  530. // Find the length of this field - make sure it'll fit in the buffer
  531. cbField = (int)((lpszEnd - lpszChar) + 1);
  532. if (cbField > cbSize) { // I return an error if the requested
  533. //cbField = cbSize; // data won't fit, rather than truncating
  534. return FALSE; // it at some random point! -JTP
  535. }
  536. // Note that the C runtime treats cbField as the number of characters
  537. // to copy from the source, and if that doesn't happen to transfer a NULL,
  538. // too bad. The Windows implementation of _lstrcpyn treats cbField as
  539. // the number of characters that can be stored in the destination, and
  540. // always copies a NULL (even if it means copying only cbField-1 characters
  541. // from the source).
  542. // The C runtime also pads the destination with NULLs if a NULL in the
  543. // source is found before cbField is exhausted. _lstrcpyn essentially quits
  544. // after copying a NULL.
  545. lstrcpyn(lpszField, lpszChar, cbField);
  546. return TRUE;
  547. }
  548. #define NUM_VERSION_NUM 4
  549. void ConvertVersionStrToDwords(LPSTR pszVer, LPDWORD pdwVer, LPDWORD pdwBuild)
  550. {
  551. WORD rwVer[NUM_VERSION_NUM];
  552. for(int i = 0; i < NUM_VERSION_NUM; i++)
  553. rwVer[i] = 0;
  554. for(i = 0; i < NUM_VERSION_NUM && pszVer; i++)
  555. {
  556. rwVer[i] = (WORD) StrToInt(pszVer);
  557. pszVer = ScanForChar(pszVer, '.', lstrlen(pszVer));
  558. if (pszVer)
  559. pszVer++;
  560. }
  561. *pdwVer = (rwVer[0]<< 16) + rwVer[1];
  562. *pdwBuild = (rwVer[2] << 16) + rwVer[3];
  563. }
  564. LPSTR FindChar(LPSTR pszStr, char ch)
  565. {
  566. while( *pszStr != 0 && *pszStr != ch )
  567. pszStr++;
  568. return pszStr;
  569. }
  570. DWORD GetStringField(LPSTR szStr, UINT uField, LPSTR szBuf, UINT cBufSize)
  571. {
  572. LPSTR pszBegin = szStr;
  573. LPSTR pszEnd;
  574. UINT i = 0;
  575. DWORD dwToCopy;
  576. if(cBufSize == 0)
  577. return 0;
  578. szBuf[0] = 0;
  579. if(szStr == NULL)
  580. return 0;
  581. while(*pszBegin != 0 && i < uField)
  582. {
  583. pszBegin = FindChar(pszBegin, ',');
  584. if(*pszBegin != 0)
  585. pszBegin++;
  586. i++;
  587. }
  588. // we reached end of string, no field
  589. if(*pszBegin == 0)
  590. {
  591. return 0;
  592. }
  593. pszEnd = FindChar(pszBegin, ',');
  594. while(pszBegin <= pszEnd && *pszBegin == ' ')
  595. pszBegin++;
  596. while(pszEnd > pszBegin && *(pszEnd - 1) == ' ')
  597. pszEnd--;
  598. if(pszEnd > (pszBegin + 1) && *pszBegin == '"' && *(pszEnd-1) == '"')
  599. {
  600. pszBegin++;
  601. pszEnd--;
  602. }
  603. dwToCopy = pszEnd - pszBegin + 1;
  604. if(dwToCopy > cBufSize)
  605. dwToCopy = cBufSize;
  606. lstrcpynA(szBuf, pszBegin, dwToCopy);
  607. return dwToCopy - 1;
  608. }
  609. BOOL GetHashidFromINF(LPCTSTR lpFileName, LPTSTR lpszHash, DWORD dwSize)
  610. {
  611. INFCONTEXT InfContext;
  612. if (pfSetupFindFirstLine(g_hInf, "SourceDisksFiles", lpFileName, &InfContext ))
  613. {
  614. if (pfSetupGetStringField(&InfContext, 5, lpszHash, dwSize, NULL ))
  615. {
  616. return TRUE;
  617. }
  618. }
  619. return FALSE;
  620. }
  621. #ifdef _M_IX86
  622. //
  623. // Stupid x86 compiler doesn't have an intrinsic memchr, so we'll do our own.
  624. //
  625. #pragma warning( disable: 4035 ) // no return value
  626. LPSTR ScanForChar(
  627. IN LPSTR Buffer,
  628. IN CHAR SearchFor,
  629. IN ULONG MaxLength
  630. )
  631. {
  632. __asm {
  633. mov edi, Buffer // pointer for scasb in edi
  634. mov al, SearchFor // looking for this char
  635. mov ecx, MaxLength // don't scan past this
  636. repne scasb // find the char
  637. lea eax, [edi-1] // edi points one past the found char
  638. jz RETURNIT // if didn't find it,
  639. xor eax, eax // return NULL
  640. RETURNIT:
  641. }
  642. }
  643. #pragma warning( default: 4035 ) // no return value
  644. #else // ! _M_IX86
  645. LPSTR ScanForChar(IN LPSTR Buffer, IN CHAR SearchFor, IN ULONG MaxLength)
  646. {
  647. return memchr( Buffer, SearchFor, MaxLength );
  648. }
  649. #endif // ! _M_IX86
  650. PCHAR ScanForSequence(IN PCHAR Buffer, IN ULONG BufferLength, IN PCHAR Sequence, IN ULONG SequenceLength)
  651. {
  652. if ( BufferLength >= SequenceLength )
  653. {
  654. PCHAR ScanEnd = Buffer + ( BufferLength - SequenceLength ) + 1;
  655. PCHAR ScanPtr = Buffer;
  656. while ( ScanPtr < ScanEnd )
  657. {
  658. ScanPtr = ScanForChar( ScanPtr, *Sequence, ScanEnd - ScanPtr );
  659. if ( ScanPtr == NULL )
  660. {
  661. return NULL;
  662. }
  663. if ( memcmp( ScanPtr, Sequence, SequenceLength ) == 0 )
  664. {
  665. return ScanPtr;
  666. }
  667. ++ScanPtr;
  668. }
  669. }
  670. return NULL;
  671. }
  672. //From shlwapi....
  673. #define FAST_CharNext(p) CharNext(p)
  674. #define FILENAME_SEPARATOR '\\'
  675. #define CH_WHACK TEXT(FILENAME_SEPARATOR)
  676. LPTSTR PathFindFileName(LPCTSTR pPath)
  677. {
  678. LPCTSTR pT = pPath;
  679. if (pPath)
  680. {
  681. for ( ; *pPath; pPath = FAST_CharNext(pPath))
  682. {
  683. if ((pPath[0] == TEXT('\\') || pPath[0] == TEXT(':') || pPath[0] == TEXT('/'))
  684. && pPath[1] && pPath[1] != TEXT('\\') && pPath[1] != TEXT('/'))
  685. pT = pPath + 1;
  686. }
  687. }
  688. return (LPTSTR)pT; // const -> non const
  689. }
  690. LPTSTR PathFindExtension(LPCTSTR pszPath)
  691. {
  692. LPCTSTR pszDot = NULL;
  693. if (pszPath)
  694. {
  695. for (; *pszPath; pszPath = FAST_CharNext(pszPath))
  696. {
  697. switch (*pszPath) {
  698. case TEXT('.'):
  699. pszDot = pszPath; // remember the last dot
  700. break;
  701. case CH_WHACK:
  702. case TEXT(' '): // extensions can't have spaces
  703. pszDot = NULL; // forget last dot, it was in a directory
  704. break;
  705. }
  706. }
  707. }
  708. // if we found the extension, return ptr to the dot, else
  709. // ptr to end of the string (NULL extension) (cast->non const)
  710. return pszDot ? (LPTSTR)pszDot : (LPTSTR)pszPath;
  711. }
  712. LPSTR StrDup(LPCSTR psz)
  713. {
  714. LPSTR pszRet = (LPSTR)LocalAlloc(LPTR, (lstrlenA(psz) + 1) * sizeof(*pszRet));
  715. if (pszRet)
  716. {
  717. lstrcpyA(pszRet, psz);
  718. }
  719. return pszRet;
  720. }
  721. DWORD MyFileSize( PCSTR pszFile )
  722. {
  723. HFILE hFile;
  724. OFSTRUCT ofStru;
  725. DWORD dwSize = 0;
  726. if ( *pszFile == 0 )
  727. return 0;
  728. hFile = OpenFile( pszFile, &ofStru, OF_READ );
  729. if ( hFile != HFILE_ERROR )
  730. {
  731. dwSize = GetFileSize( (HANDLE)hFile, NULL );
  732. _lclose( hFile );
  733. }
  734. return dwSize;
  735. }
  736. void GetLanguageString(LPTSTR lpszLang)
  737. {
  738. char szTmp[MAX_PATH];
  739. DWORD dwLang, dwCharSet;
  740. //default to EN
  741. lstrcpy(lpszLang, "EN");
  742. GetModuleFileName( g_hInstance, szTmp, sizeof(szTmp) );
  743. MyGetVersionFromFile(szTmp, &dwLang, &dwCharSet, FALSE);
  744. for(int i = 0; g_LangID[i].dwLangID != -1; i++)
  745. {
  746. if(g_LangID[i].dwLangID == dwLang)
  747. {
  748. lstrcpy(lpszLang, g_LangID[i].szLanguage);
  749. break;
  750. }
  751. }
  752. }
  753. BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
  754. {
  755. RECT rChild, rParent;
  756. int wChild, hChild, wParent, hParent;
  757. int wScreen, hScreen, xNew, yNew;
  758. HDC hdc;
  759. // Get the Height and Width of the child window
  760. GetWindowRect (hwndChild, &rChild);
  761. wChild = rChild.right - rChild.left;
  762. hChild = rChild.bottom - rChild.top;
  763. // Get the Height and Width of the parent window
  764. GetWindowRect (hwndParent, &rParent);
  765. wParent = rParent.right - rParent.left;
  766. hParent = rParent.bottom - rParent.top;
  767. // Get the display limits
  768. hdc = GetDC (hwndChild);
  769. wScreen = GetDeviceCaps (hdc, HORZRES);
  770. hScreen = GetDeviceCaps (hdc, VERTRES);
  771. ReleaseDC (hwndChild, hdc);
  772. // Calculate new X position, then adjust for screen
  773. xNew = rParent.left + ((wParent - wChild) /2);
  774. if (xNew < 0) {
  775. xNew = 0;
  776. } else if ((xNew+wChild) > wScreen) {
  777. xNew = wScreen - wChild;
  778. }
  779. // Calculate new Y position, then adjust for screen
  780. yNew = rParent.top + ((hParent - hChild) /2);
  781. if (yNew < 0) {
  782. yNew = 0;
  783. } else if ((yNew+hChild) > hScreen) {
  784. yNew = hScreen - hChild;
  785. }
  786. // Set it, and return
  787. return SetWindowPos (hwndChild, NULL,
  788. xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
  789. }