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.

1719 lines
41 KiB

  1. //
  2. // ParseInf.cpp
  3. //
  4. // Code that parses network INF files
  5. //
  6. // History:
  7. //
  8. // ?/??/1999 KenSh Created for JetNet
  9. // 9/29/1999 KenSh Repurposed for Home Networking Wizard
  10. //
  11. #include "stdafx.h"
  12. #include "ParseInf.h"
  13. #include "SortStr.h"
  14. #include "Registry.h"
  15. #define SECTION_BUFFER_SIZE (32 * 1024)
  16. // Non-localized strings
  17. #define SZ_INF_BACKUP_SUFFIX ".inf (HNW backup)"
  18. #define SZ_MODIFIED_INF_HEADER "; Modified by Home Networking Wizard\r\n" \
  19. "; Original version backed up to \""
  20. #define SZ_MODIFIED_INF_HEADER2 "\"\r\n"
  21. #define SZ_CHECK_MODIFIED_HEADER "; Modified by Home Networking Wizard"
  22. //////////////////////////////////////////////////////////////////////////////
  23. // Utility functions
  24. int GetInfDirectory(LPTSTR pszBuf, int cchBuf, BOOL bAppendBackslash)
  25. {
  26. CRegistry regWindows;
  27. int cch = 0;
  28. if (regWindows.OpenKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", KEY_QUERY_VALUE))
  29. {
  30. cch = regWindows.QueryStringValue("DevicePath", pszBuf, cchBuf);
  31. }
  32. // Fill in a default if the reg key is missing
  33. // REVIEW: Is this likely enough that we should even bother?
  34. if (cch == 0)
  35. {
  36. ASSERT(cchBuf > 8);
  37. cch = GetWindowsDirectory(pszBuf, cchBuf - 4);
  38. if (0!=cch)
  39. {
  40. if (pszBuf[cch-1] != '\\')
  41. pszBuf[cch++] = '\\';
  42. }
  43. lstrcpy(pszBuf + cch, "INF");
  44. cch += 3;
  45. }
  46. if (bAppendBackslash)
  47. {
  48. if (pszBuf[cch-1] != '\\')
  49. {
  50. pszBuf[cch++] = '\\';
  51. pszBuf[cch] = '\0';
  52. }
  53. }
  54. return cch;
  55. }
  56. int GetFullInfPath(LPCTSTR pszPartialPath, LPTSTR pszBuf, int cchBuf)
  57. {
  58. if (IsFullPath(pszPartialPath))
  59. {
  60. lstrcpyn(pszBuf, pszPartialPath, cchBuf);
  61. }
  62. else
  63. {
  64. int cch = GetInfDirectory(pszBuf, cchBuf, TRUE);
  65. lstrcpyn(pszBuf + cch, pszPartialPath, cchBuf - cch);
  66. }
  67. return lstrlen(pszBuf);
  68. }
  69. int AddCommaSeparatedValues(const CStringArray& rgTokens, CStringArray& rgValues, BOOL bIgnoreInfSections)
  70. {
  71. int cAdded = 0;
  72. for (int iToken = 2; iToken < rgTokens.GetSize(); iToken++)
  73. {
  74. CString& strTok = ((CStringArray&)rgTokens).ElementAt(iToken);
  75. if (strTok.Compare(",") == 0)
  76. continue;
  77. if (strTok.Compare(";") == 0)
  78. break;
  79. // Hack: ignore sections whose name ends in ".inf"
  80. if (bIgnoreInfSections)
  81. {
  82. if (0 == lstrcmpi(FindExtension(strTok), "inf"))
  83. continue;
  84. }
  85. rgValues.Add(strTok);
  86. cAdded++;
  87. }
  88. return cAdded;
  89. }
  90. // Builds a list of all files that need to be copied for the device
  91. BOOL GetDeviceCopyFiles(CInfParser& parser, LPCTSTR pszDeviceID, CDriverFileArray& rgDriverFiles)
  92. {
  93. if (!parser.GotoSection("Manufacturer"))
  94. return FALSE;
  95. CStringArray rgMfr;
  96. CStringArray rgLineTokens;
  97. while (parser.GetSectionLineTokens(rgLineTokens))
  98. {
  99. if (rgLineTokens.GetSize() >= 3 && rgLineTokens.ElementAt(1).Compare("=") == 0)
  100. rgMfr.Add(rgLineTokens.ElementAt(2));
  101. }
  102. CString strNdiSection;
  103. // Look in each manufacturer section (e.g. "[3COM]") for the given DeviceID
  104. for (int iMfr = 0; iMfr < rgMfr.GetSize(); iMfr++)
  105. {
  106. if (!parser.GotoSection(rgMfr[iMfr]))
  107. continue;
  108. while (parser.GetSectionLineTokens(rgLineTokens))
  109. {
  110. if (rgLineTokens.GetSize() >= 5 &&
  111. rgLineTokens.ElementAt(1).Compare("=") == 0 &&
  112. rgLineTokens.ElementAt(3).Compare(",") == 0)
  113. {
  114. if (rgLineTokens.ElementAt(4).CompareNoCase(pszDeviceID) == 0)
  115. {
  116. strNdiSection = rgLineTokens.ElementAt(2);
  117. break;
  118. }
  119. }
  120. }
  121. if (!strNdiSection.IsEmpty())
  122. break;
  123. }
  124. if (strNdiSection.IsEmpty())
  125. return FALSE;
  126. CStringArray rgCopySections;
  127. CStringArray rgAddRegSections;
  128. // Look in [DeviceID.ndi] section for AddReg= and CopyFiles=
  129. if (!parser.GotoSection(strNdiSection))
  130. return FALSE;
  131. while (parser.GetSectionLineTokens(rgLineTokens))
  132. {
  133. if (rgLineTokens.GetSize() >= 3 &&
  134. rgLineTokens.ElementAt(1).Compare("=") == 0)
  135. {
  136. CString& strKey = rgLineTokens.ElementAt(0);
  137. CString& strValue = rgLineTokens.ElementAt(2);
  138. if (strKey.CompareNoCase("AddReg") == 0)
  139. {
  140. AddCommaSeparatedValues(rgLineTokens, rgAddRegSections, FALSE);
  141. }
  142. else if (strKey.CompareNoCase("CopyFiles") == 0)
  143. {
  144. AddCommaSeparatedValues(rgLineTokens, rgCopySections, FALSE);
  145. }
  146. }
  147. }
  148. // Look through AddReg sections for HKR,Ndi\Install,,,"DeviceID.Install"
  149. for (int iAddReg = 0; iAddReg < rgAddRegSections.GetSize(); iAddReg++)
  150. {
  151. if (!parser.GotoSection(rgAddRegSections[iAddReg]))
  152. continue;
  153. while (parser.GetSectionLineTokens(rgLineTokens))
  154. {
  155. if (rgLineTokens.GetSize() >= 7 &&
  156. rgLineTokens.ElementAt(0).CompareNoCase("HKR") == 0 &&
  157. rgLineTokens.ElementAt(1).Compare(",") == 0 &&
  158. rgLineTokens.ElementAt(2).CompareNoCase("Ndi\\Install") == 0 &&
  159. rgLineTokens.ElementAt(3).Compare(",") == 0)
  160. {
  161. // Pull out the 5th comma-separated string, and pull the quotes off
  162. int iSection = 2;
  163. for (int iToken = 4; iToken < rgLineTokens.GetSize(); iToken++)
  164. {
  165. CString& strTok = rgLineTokens.ElementAt(iToken);
  166. if (strTok.Compare(";") == 0)
  167. break;
  168. if (strTok.Compare(",") == 0)
  169. {
  170. iSection++;
  171. continue;
  172. }
  173. if (iSection == 4)
  174. {
  175. CString strSection = strTok;
  176. if (strSection[0] == '\"')
  177. strSection = strSection.Mid(1, strSection.GetLength() - 2);
  178. rgCopySections.Add(strSection);
  179. break;
  180. }
  181. }
  182. }
  183. }
  184. }
  185. // Look in [DeviceID.Install], etc., sections for CopyFiles= lines
  186. for (int iCopyFiles = 0; iCopyFiles < rgCopySections.GetSize(); iCopyFiles++)
  187. {
  188. parser.GetFilesFromInstallSection(rgCopySections[iCopyFiles], rgDriverFiles);
  189. }
  190. parser.GetFilesFromCopyFilesSections(rgCopySections, rgDriverFiles);
  191. return TRUE;
  192. }
  193. BOOL GetDeviceCopyFiles(LPCTSTR pszInfFileName, LPCTSTR pszDeviceID, CDriverFileArray& rgDriverFiles)
  194. {
  195. CInfParser parser;
  196. if (!parser.LoadInfFile(pszInfFileName))
  197. return FALSE;
  198. return GetDeviceCopyFiles(parser, pszDeviceID, rgDriverFiles);
  199. }
  200. CDriverFileArray::~CDriverFileArray()
  201. {
  202. for (int i = 0; i < GetSize(); i++)
  203. {
  204. free((DRIVER_FILE_INFO*)GetAt(i));
  205. }
  206. }
  207. //////////////////////////////////////////////////////////////////////////////
  208. // CInfParser
  209. CInfParser::CInfParser()
  210. {
  211. m_pszFileData = NULL;
  212. }
  213. CInfParser::~CInfParser()
  214. {
  215. free(m_pszFileData);
  216. }
  217. BOOL CInfParser::LoadInfFile(LPCTSTR pszInfFile, LPCTSTR pszSeparators)
  218. {
  219. TCHAR szInfFile[MAX_PATH];
  220. GetFullInfPath(pszInfFile, szInfFile, _countof(szInfFile));
  221. free(m_pszFileData);
  222. m_pszFileData = (LPSTR)LoadFile(szInfFile, &m_cbFile);
  223. m_iPos = 0;
  224. m_strSeparators = pszSeparators;
  225. m_strExtSeparators = pszSeparators;
  226. m_strExtSeparators += " \t\r\n";
  227. m_strFileName = pszInfFile;
  228. return (BOOL)m_pszFileData;
  229. }
  230. BOOL CInfParser::Rewind()
  231. {
  232. ASSERT(m_pszFileData != NULL);
  233. m_iPos = 0;
  234. return (BOOL)m_pszFileData;
  235. }
  236. BOOL CInfParser::GotoNextLine()
  237. {
  238. ASSERT(m_pszFileData != NULL);
  239. for (LPTSTR pch = m_pszFileData + m_iPos; *pch != '\0' && *pch != '\r' && *pch != '\n'; pch++)
  240. NULL;
  241. if (*pch == '\r')
  242. pch++;
  243. if (*pch == '\n')
  244. pch++;
  245. DWORD iPos = (DWORD)(pch - m_pszFileData);
  246. if (iPos == m_iPos)
  247. return FALSE; // we were already at EOF
  248. m_iPos = iPos;
  249. return TRUE;
  250. }
  251. BOOL CInfParser::GetToken(CString& strTok)
  252. {
  253. strTok.Empty();
  254. if (m_pszFileData == NULL)
  255. {
  256. ASSERT(FALSE);
  257. return FALSE;
  258. }
  259. LPTSTR pch = m_pszFileData + m_iPos;
  260. TCHAR ch;
  261. BOOL bQuoted = FALSE;
  262. // Skip whitespace
  263. while ((ch = *pch) == ' ' || ch == '\t')
  264. pch++;
  265. if (ch == '\0')
  266. goto done;
  267. // Check for linebreak
  268. if (ch == '\r' || ch == '\n')
  269. {
  270. strTok = ch;
  271. pch++;
  272. if (ch == '\r' && *pch == '\n')
  273. {
  274. strTok += '\n';
  275. pch++;
  276. }
  277. goto done;
  278. }
  279. // Check for separator
  280. if (NULL != strchr(m_strSeparators, ch))
  281. {
  282. strTok = ch;
  283. pch++;
  284. goto done;
  285. }
  286. LPTSTR pszStart;
  287. for (pszStart = pch; (ch = *pch) != '\0'; pch++)
  288. {
  289. if (!bQuoted && NULL != strchr(m_strExtSeparators, ch))
  290. {
  291. break;
  292. }
  293. else if (ch == '\"')
  294. {
  295. bQuoted = !bQuoted;
  296. }
  297. }
  298. if (pch != pszStart)
  299. {
  300. DWORD cch = (DWORD)(pch - pszStart);
  301. LPTSTR pszToken = strTok.GetBufferSetLength(cch);
  302. lstrcpyn(pszToken, pszStart, cch+1);
  303. }
  304. done:
  305. m_iPos = (DWORD)(pch - m_pszFileData);
  306. return (BOOL)strTok.GetLength();
  307. }
  308. BOOL CInfParser::GetLineTokens(CStringArray& sa)
  309. {
  310. CString strToken;
  311. BOOL bResult = FALSE;
  312. sa.RemoveAll();
  313. while (GetToken(strToken))
  314. {
  315. bResult = TRUE; // not at EOF
  316. if (strToken[0] == '\r' || strToken[0] == '\n')
  317. break;
  318. sa.Add(strToken);
  319. }
  320. return bResult;
  321. }
  322. BOOL CInfParser::GetSectionLineTokens(CStringArray& sa)
  323. {
  324. begin:
  325. if (!GetLineTokens(sa))
  326. return FALSE;
  327. if (sa.GetSize() == 0)
  328. goto begin;
  329. CString& strFirst = sa.ElementAt(0);
  330. if (strFirst[0] == '[') // end of section
  331. return FALSE;
  332. if (strFirst.Compare(";") == 0) // comment
  333. {
  334. sa.RemoveAll();
  335. goto begin;
  336. }
  337. return TRUE;
  338. }
  339. BOOL CInfParser::GotoSection(LPCTSTR pszSection)
  340. {
  341. CString strSection;
  342. CString strToken;
  343. if (!Rewind())
  344. return FALSE;
  345. TCHAR ch;
  346. BOOL bStartOfLine = TRUE;
  347. int cchSection = lstrlen(pszSection) + 1;
  348. for (LPTSTR pch = m_pszFileData; (ch = *pch) != '\0'; pch++)
  349. {
  350. if (ch == '\r' || ch == '\n')
  351. {
  352. bStartOfLine = TRUE;
  353. }
  354. else if (bStartOfLine)
  355. {
  356. if (ch == '[')
  357. {
  358. LPTSTR pchCloseBracket = strchr(pch+1, ']');
  359. if ((int)(pchCloseBracket - pch) == cchSection)
  360. {
  361. CString str(pch+1, cchSection-1);
  362. if (str.CompareNoCase(pszSection) == 0)
  363. {
  364. pch = pchCloseBracket+1;
  365. if (*pch == '\r')
  366. pch++;
  367. if (*pch == '\n')
  368. pch++;
  369. m_iPos = (DWORD)(pch - m_pszFileData);
  370. return TRUE;
  371. }
  372. }
  373. }
  374. bStartOfLine = FALSE;
  375. }
  376. }
  377. return FALSE;
  378. }
  379. int CInfParser::GetProfileInt(LPCTSTR pszSection, LPCTSTR pszKey, int nDefault)
  380. {
  381. DWORD iPos = m_iPos;
  382. if (GotoSection(pszSection))
  383. {
  384. CStringArray rgTokens;
  385. while (GetSectionLineTokens(rgTokens))
  386. {
  387. if (rgTokens.GetSize() >= 3 &&
  388. rgTokens.ElementAt(0).CompareNoCase(pszKey) == 0&&
  389. rgTokens.ElementAt(1).Compare("=") == 0)
  390. {
  391. nDefault = MyAtoi(rgTokens.ElementAt(2));
  392. break;
  393. }
  394. }
  395. }
  396. m_iPos = iPos;
  397. return nDefault;
  398. }
  399. BOOL CInfParser::GetFilesFromInstallSection(LPCTSTR pszSection, CDriverFileArray& rgAllFiles)
  400. {
  401. CStringArray rgLineTokens;
  402. CStringArray rgCopyFilesSections;
  403. if (!GotoSection(pszSection))
  404. return FALSE;
  405. while (GetSectionLineTokens(rgLineTokens))
  406. {
  407. if (rgLineTokens.GetSize() >= 3 &&
  408. rgLineTokens.ElementAt(0).CompareNoCase("CopyFiles") == 0 &&
  409. rgLineTokens.ElementAt(1).Compare("=") == 0)
  410. {
  411. AddCommaSeparatedValues(rgLineTokens, rgCopyFilesSections, FALSE);
  412. // REVIEW: There can be AddReg= lines here. Do we need to
  413. // check the referenced sections for more CopyFiles= lines?
  414. }
  415. }
  416. GetFilesFromCopyFilesSections(rgCopyFilesSections, rgAllFiles);
  417. return TRUE;
  418. }
  419. // Looks in [DestinationDirs] for pszSectionName, fills pbDirNumber and pszSubDir with
  420. // the matching target directory and (optional) subdirectory.
  421. BOOL CInfParser::GetDestinationDir(LPCTSTR pszSectionName, BYTE* pbDirNumber, LPTSTR pszSubDir, UINT cchSubDir)
  422. {
  423. DWORD iSavedPos = m_iPos;
  424. BOOL bSuccess = FALSE;
  425. *pbDirNumber = 0;
  426. pszSubDir[0] = '\0';
  427. if (GotoSection("DestinationDirs"))
  428. {
  429. CStringArray rgTokens;
  430. while (GetSectionLineTokens(rgTokens))
  431. {
  432. if (rgTokens.GetSize() >= 3 &&
  433. rgTokens.ElementAt(0).CompareNoCase(pszSectionName) == 0 &&
  434. rgTokens.ElementAt(1).Compare("=") == 0)
  435. {
  436. *pbDirNumber = (BYTE)MyAtoi(rgTokens.ElementAt(2));
  437. if (rgTokens.GetSize() >= 5 && rgTokens.ElementAt(3).Compare(",") == 0)
  438. {
  439. lstrcpyn(pszSubDir, rgTokens.ElementAt(4), cchSubDir);
  440. }
  441. bSuccess = TRUE;
  442. break;
  443. }
  444. }
  445. }
  446. m_iPos = iSavedPos;
  447. return bSuccess;
  448. }
  449. void CInfParser::GetFilesFromCopyFilesSections(const CStringArray& rgCopyFiles, CDriverFileArray& rgAllFiles)
  450. {
  451. CStringArray rgLineTokens;
  452. for (int iSection = 0; iSection < rgCopyFiles.GetSize(); iSection++)
  453. {
  454. TCHAR szTargetSubDir[MAX_PATH];
  455. BYTE nTargetDir;
  456. GetDestinationDir(rgCopyFiles[iSection], &nTargetDir, szTargetSubDir, _countof(szTargetSubDir));
  457. // BYTE nTargetDir = (BYTE)GetProfileInt("DestinationDirs", rgCopyFiles[iSection], 0);
  458. #ifdef _DEBUG
  459. if (nTargetDir == 0)
  460. TRACE("Warning: CopyFiles section [%s] has no destination directory.\r\n", rgCopyFiles[iSection]);
  461. #endif
  462. if (!GotoSection(rgCopyFiles[iSection]))
  463. continue;
  464. // Get the first item from each line
  465. while (GetSectionLineTokens(rgLineTokens))
  466. {
  467. if (rgLineTokens.GetSize() == 1 ||
  468. (rgLineTokens.GetSize() >= 2 &&
  469. (rgLineTokens.ElementAt(1).Compare(",") == 0 ||
  470. rgLineTokens.ElementAt(1).Compare(";") == 0)))
  471. {
  472. CString& strFileName = rgLineTokens.ElementAt(0);
  473. // Don't install this INF file
  474. // REVIEW: might want to allow this based on a flag or something
  475. if (0 != lstrcmpi(FindFileTitle(strFileName), FindFileTitle(m_strFileName)))
  476. {
  477. UINT cbFileInfo = sizeof(DRIVER_FILE_INFO) + strFileName.GetLength() + lstrlen(szTargetSubDir) + 1;
  478. DRIVER_FILE_INFO* pFileInfo = (DRIVER_FILE_INFO*)malloc(cbFileInfo);
  479. TRACE("Error: Malloc failed on DRIVER_FILE_INFO.\r\n");
  480. if (pFileInfo)
  481. {
  482. pFileInfo->nTargetDir = nTargetDir;
  483. lstrcpy(pFileInfo->szFileTitle, strFileName);
  484. lstrcpy(pFileInfo->szFileTitle + strFileName.GetLength() + 1, szTargetSubDir);
  485. rgAllFiles.Add(pFileInfo);
  486. }
  487. }
  488. }
  489. }
  490. }
  491. // TODO: Remove duplicate files (maybe here, maybe not)
  492. }
  493. int CInfParser::GetNextSourceFile(LPTSTR pszBuf, BYTE* pDiskNumber)
  494. {
  495. LPTSTR pch = m_pszFileData + m_iPos;
  496. int cch = 0;
  497. BYTE bDiskNumber = 0;
  498. for (;;)
  499. {
  500. TCHAR ch;
  501. while ((ch = *pch) == '\r' || ch == '\n')
  502. pch++;
  503. if (ch == '\0' || ch == '[' || cch != 0)
  504. break;
  505. if (ch != ';')
  506. {
  507. LPTSTR pchStart = pch;
  508. while ((UCHAR)(ch = *pch) > 32 && ch != '=')
  509. pch++;
  510. cch = (int)(pch - pchStart);
  511. lstrcpyn(pszBuf, pchStart, cch+1);
  512. // skip whitespace while avoiding '\0'
  513. while ((UCHAR)(*pch-1) < 32)
  514. pch++;
  515. if (*pch == '=')
  516. {
  517. pch++;
  518. // skip whitespace while avoiding '\0'
  519. while ((UCHAR)(*pch-1) < 32)
  520. pch++;
  521. bDiskNumber = (BYTE)MyAtoi(pch);
  522. #if 1 // ignore files with disk number of 0
  523. if (bDiskNumber == 0)
  524. cch = 0;
  525. #endif
  526. }
  527. }
  528. // skip text up to newline
  529. while ((ch = *pch) != '\0' && ch != '\r' && ch != '\n')
  530. pch++;
  531. }
  532. *pDiskNumber = bDiskNumber;
  533. m_iPos = (DWORD)(pch - m_pszFileData);
  534. return cch;
  535. }
  536. /*
  537. int CInfParser::ReadSourceFilesSection(INF_LAYOUT_FILE* prgFiles, int cFiles)
  538. {
  539. WORD wOffset = (WORD)(cFiles * sizeof(INF_LAYOUT_FILE));
  540. LPTSTR pchDest = (LPTSTR)((LPBYTE)m_prgFiles + wOffset);
  541. INF_LAYOUT_FILE* pFile = prgFiles;
  542. INF_LAYOUT_FILE* pFileEnd = pFile + cFiles;
  543. while (pFile < pFileEnd)
  544. {
  545. pFile->wNameOffset = (WORD)((LPBYTE)pchDest - (LPBYTE)prgFiles);
  546. int cch = parser.GetNextSourceFile(pchDest, &pFile->iDisk);
  547. wOffset += cch+1;
  548. pchDest += cch+1;
  549. pFile++;
  550. }
  551. LPTSTR pch = m_pszFileData + m_iPos;
  552. int cch = 0;
  553. *pDiskNumber = 0;
  554. for (;;)
  555. {
  556. TCHAR ch;
  557. while ((ch = *pch) == '\r' || ch == '\n')
  558. pch++;
  559. if (ch == '\0' || ch == '[' || cch != 0)
  560. break;
  561. if (ch != ';')
  562. {
  563. LPTSTR pchStart = pch;
  564. while ((UCHAR)(ch = *pch) > 32 && ch != '=')
  565. pch++;
  566. cch = (int)(pch - pchStart);
  567. lstrcpyn(pszBuf, pchStart, cch+1);
  568. // skip whitespace while avoiding '\0'
  569. while ((UCHAR)(*pch-1) < 32)
  570. pch++;
  571. if (*pch == '=')
  572. {
  573. pch++;
  574. // skip whitespace while avoiding '\0'
  575. while ((UCHAR)(*pch-1) < 32)
  576. pch++;
  577. *pDiskNumber = (BYTE)atoi(pch);
  578. }
  579. }
  580. // skip text up to newline
  581. while ((ch = *pch) != '\0' && ch != '\r' && ch != '\n')
  582. pch++;
  583. }
  584. m_iPos = (DWORD)(pch - m_pszFileData);
  585. return cch;
  586. }
  587. */
  588. void CInfParser::ScanSourceFileList(int* pcFiles, int* pcchAllFileNames)
  589. {
  590. int cFiles = 0;
  591. int cchAllFileNames = 0;
  592. LPTSTR pch = m_pszFileData + m_iPos;
  593. for (;;)
  594. {
  595. TCHAR ch;
  596. while ((ch = *pch) == '\r' || ch == '\n')
  597. pch++;
  598. if (ch == '\0' || ch == '[')
  599. break;
  600. if (ch != ';')
  601. {
  602. cFiles += 1;
  603. LPTSTR pchStart = pch;
  604. while ((UCHAR)(ch = *pch) >= 32 && ch != '=')
  605. pch++;
  606. cchAllFileNames += (int)(pch - pchStart);
  607. }
  608. // skip text up to newline
  609. while ((ch = *pch) != '\0' && ch != '\r' && ch != '\n')
  610. pch++;
  611. }
  612. *pcFiles = cFiles;
  613. *pcchAllFileNames = cchAllFileNames;
  614. }
  615. //////////////////////////////////////////////////////////////////////////////
  616. // CInfLayoutFiles
  617. #define INF_LAYOUT_FILE_PADDING 40 // extra bytes at end of string data
  618. CInfLayoutFiles::CInfLayoutFiles()
  619. {
  620. m_prgFiles = NULL;
  621. m_pStringData = NULL;
  622. m_cFiles = 0;
  623. m_cbStringData = 0;
  624. #ifdef _DEBUG
  625. m_bSorted = FALSE;
  626. #endif
  627. }
  628. CInfLayoutFiles::~CInfLayoutFiles()
  629. {
  630. free(m_prgFiles);
  631. free(m_pStringData);
  632. for (int i = m_rgSourceDisks.GetSize()-1; i >= 0; i--)
  633. {
  634. delete m_rgSourceDisks[i];
  635. }
  636. }
  637. LPTSTR CInfLayoutFiles::s_pStringData;
  638. int __cdecl CInfLayoutFiles::CompareInfLayoutFiles(const void* pEl1, const void* pEl2)
  639. {
  640. LPCTSTR psz1 = s_pStringData + ((INF_LAYOUT_FILE*)pEl1)->dwNameOffset;
  641. LPCTSTR psz2 = s_pStringData + ((INF_LAYOUT_FILE*)pEl2)->dwNameOffset;
  642. return lstrcmpi(psz1, psz2);
  643. }
  644. BOOL CInfLayoutFiles::Add(CInfParser& parser, BOOL bLayoutFile)
  645. {
  646. // Check if we've already added this layout file
  647. if (-1 != m_rgLayoutFileNames.Find(parser.m_strFileName))
  648. return TRUE;
  649. BYTE iLayoutFile = (BYTE)m_rgLayoutFileNames.GetSize();
  650. if (parser.GotoSection("SourceDisksFiles"))
  651. {
  652. DWORD dwTicks1 = GetTickCount();
  653. int cFiles;
  654. int cchAllFileNames;
  655. parser.ScanSourceFileList(&cFiles, &cchAllFileNames);
  656. DWORD dwTicks2 = GetTickCount();
  657. DWORD dwOffset = (DWORD)m_cbStringData;
  658. int iFile = m_cFiles;
  659. cchAllFileNames += m_cbStringData + cFiles;
  660. cFiles += m_cFiles;
  661. INF_LAYOUT_FILE* pFile = (INF_LAYOUT_FILE*)realloc(m_prgFiles, cFiles * sizeof(INF_LAYOUT_FILE));
  662. LPTSTR pchDest = (LPTSTR)realloc(m_pStringData, cchAllFileNames + INF_LAYOUT_FILE_PADDING);
  663. if (pchDest)
  664. {
  665. m_pStringData = pchDest;
  666. }
  667. if (pFile)
  668. {
  669. m_prgFiles = pFile;
  670. }
  671. if (pchDest && pFile)
  672. {
  673. m_cFiles = cFiles;
  674. m_cbStringData = cchAllFileNames;
  675. pchDest += dwOffset;
  676. pFile += iFile;
  677. for ( ; iFile < m_cFiles; iFile++)
  678. {
  679. pFile->dwNameOffset = dwOffset;
  680. pFile->iLayout = iLayoutFile;
  681. int cch = parser.GetNextSourceFile(pchDest, &pFile->iDisk);
  682. dwOffset += cch+1;
  683. pchDest += cch+1;
  684. pFile++;
  685. }
  686. }
  687. else
  688. {
  689. return FALSE;
  690. }
  691. DWORD dwTicks3 = GetTickCount();
  692. CString str;
  693. str.Format("LoadLayout(%s) timings: %d ms, %d ms. Total time: %d ms",
  694. parser.m_strFileName, dwTicks2-dwTicks1, dwTicks3-dwTicks2, dwTicks3-dwTicks1);
  695. TRACE("%s\r\n", str);
  696. // AfxMessageBox(str);
  697. // for (int i = 0; i < cFiles; i++)
  698. // {
  699. // INF_LAYOUT_FILE* pFile = &m_prgFiles[i];
  700. // TRACE("File %d: %s=%d\r\n", i, m_pStringData + pFile->dwNameOffset), pFile->iDisk);
  701. // }
  702. #ifdef _DEBUG
  703. m_bSorted = FALSE;
  704. #endif
  705. }
  706. if (parser.GotoSection("SourceDisksNames"))
  707. {
  708. CStringArray rgTokens;
  709. while (parser.GetSectionLineTokens(rgTokens))
  710. {
  711. if (rgTokens.GetSize() >= 3)
  712. {
  713. BYTE iDiskNumber = (BYTE)MyAtoi(rgTokens.ElementAt(0));
  714. if (iDiskNumber != 0)
  715. {
  716. SOURCE_DISK_INFO* pDiskInfo = new SOURCE_DISK_INFO;
  717. pDiskInfo->wDiskID = MAKE_DISK_ID(iDiskNumber, iLayoutFile);
  718. // Get disk description, pull off quotes
  719. CString& strDesc = rgTokens.ElementAt(2);
  720. if (strDesc[0] == '\"')
  721. pDiskInfo->strDescription = strDesc.Mid(1, strDesc.GetLength()-2);
  722. else
  723. pDiskInfo->strDescription = strDesc;
  724. // If this is Layout*.inf, Get CAB filename, pull off quotes
  725. if (bLayoutFile && rgTokens.GetSize() >= 5)
  726. {
  727. CString& strCab = rgTokens.ElementAt(4);
  728. if (strCab[0] == '\"')
  729. pDiskInfo->strCabFile = strCab.Mid(1, strCab.GetLength()-2);
  730. else
  731. pDiskInfo->strCabFile = strCab;
  732. }
  733. m_rgSourceDisks.Add(pDiskInfo);
  734. }
  735. }
  736. }
  737. }
  738. //
  739. // Now add any referenced layout files
  740. //
  741. if (parser.GotoSection("version"))
  742. {
  743. CStringArray rgLayoutFiles;
  744. CStringArray rgLineTokens;
  745. while (parser.GetSectionLineTokens(rgLineTokens))
  746. {
  747. if (rgLineTokens.GetSize() >= 3 &&
  748. rgLineTokens.ElementAt(0).CompareNoCase("LayoutFile") == 0 &&
  749. rgLineTokens.ElementAt(1).Compare("=") == 0)
  750. {
  751. AddCommaSeparatedValues(rgLineTokens, rgLayoutFiles, FALSE);
  752. break;
  753. }
  754. }
  755. for (int i = 0; i < rgLayoutFiles.GetSize(); i++)
  756. {
  757. Add(rgLayoutFiles.ElementAt(i), TRUE);
  758. }
  759. }
  760. m_rgLayoutFileNames.Add(parser.m_strFileName, 0);
  761. return TRUE;
  762. }
  763. BOOL CInfLayoutFiles::Add(LPCTSTR pszInfFile, BOOL bLayoutFile)
  764. {
  765. CInfParser parser;
  766. if (!parser.LoadInfFile(pszInfFile))
  767. return FALSE;
  768. return Add(parser, bLayoutFile);
  769. }
  770. void CInfLayoutFiles::Sort()
  771. {
  772. s_pStringData = m_pStringData;
  773. qsort(m_prgFiles, m_cFiles, sizeof(INF_LAYOUT_FILE), CompareInfLayoutFiles);
  774. #ifdef _DEBUG
  775. m_bSorted = TRUE;
  776. #endif
  777. }
  778. SOURCE_DISK_INFO* CInfLayoutFiles::FindDriverFileSourceDisk(LPCTSTR pszDriverFileTitle)
  779. {
  780. ASSERT(m_bSorted);
  781. // Build a dummy layout-file key to allow the standard binary search to work
  782. // (Note that we've left INF_LAYOUT_FILE_PADDING chars at the end of the string data)
  783. ASSERT(lstrlen(pszDriverFileTitle) + 1 < INF_LAYOUT_FILE_PADDING);
  784. INF_LAYOUT_FILE key;
  785. key.dwNameOffset = m_cbStringData;
  786. lstrcpy(m_pStringData + m_cbStringData, pszDriverFileTitle);
  787. s_pStringData = m_pStringData;
  788. INF_LAYOUT_FILE* pResult = (INF_LAYOUT_FILE*)bsearch(
  789. &key, m_prgFiles, m_cFiles, sizeof(INF_LAYOUT_FILE), CompareInfLayoutFiles);
  790. if (pResult == NULL)
  791. {
  792. ASSERT(FALSE);
  793. return NULL;
  794. }
  795. // REVIEW: Is it worth making this a binary search?
  796. WORD wDiskID = MAKE_DISK_ID(pResult->iDisk, pResult->iLayout);
  797. for (int iDisk = 0; iDisk < m_rgSourceDisks.GetSize(); iDisk++)
  798. {
  799. SOURCE_DISK_INFO* pDiskInfo = m_rgSourceDisks[iDisk];
  800. if (pDiskInfo->wDiskID == wDiskID)
  801. return pDiskInfo;
  802. }
  803. ASSERT(FALSE);
  804. return NULL;
  805. }
  806. #ifdef _DEBUG
  807. void CInfLayoutFiles::Dump()
  808. {
  809. TRACE("CInfLayoutFiles (0x%08x)\r\n", (int)this);
  810. for (int i = 0; i < m_cFiles; i++)
  811. {
  812. INF_LAYOUT_FILE* pFile = &m_prgFiles[i];
  813. TRACE(" File %d: %s, layout %d, disk %d\r\n", i, m_pStringData + pFile->dwNameOffset, (int)pFile->iLayout, (int)pFile->iDisk);
  814. }
  815. }
  816. #endif // _DEBUG
  817. //////////////////////////////////////////////////////////////////////////////
  818. // CInfFileList
  819. CInfFileList::CInfFileList()
  820. {
  821. }
  822. CInfFileList::~CInfFileList()
  823. {
  824. for (int i = m_rgDriverFiles.GetSize()-1; i >= 0; i--)
  825. {
  826. free(m_rgDriverFiles[i]);
  827. }
  828. for (i = m_rgCabFiles.GetSize() - 1; i >= 0; i--)
  829. {
  830. free((LPTSTR)m_rgCabFiles.GetItemData(i));
  831. }
  832. }
  833. void CInfFileList::SetDriverSourceDir(LPCTSTR pszSourceDir)
  834. {
  835. m_strDriverSourceDir = pszSourceDir;
  836. }
  837. BOOL CInfFileList::AddBaseFiles(LPCTSTR pszInfFile)
  838. {
  839. CInfParser parser;
  840. if (!parser.LoadInfFile(pszInfFile))
  841. return FALSE;
  842. if (!parser.GotoSection("BaseWinOptions"))
  843. return FALSE;
  844. CStringArray rgSections;
  845. CStringArray rgLineTokens;
  846. while (parser.GetSectionLineTokens(rgLineTokens))
  847. {
  848. if (rgLineTokens.GetSize() >= 1)
  849. rgSections.Add(rgLineTokens.ElementAt(0));
  850. }
  851. int cSections = rgSections.GetSize();
  852. if (cSections == 0)
  853. return FALSE;
  854. // Walk through each major section, grabbing section names from CopyFiles= lines
  855. CStringArray rgCopyFiles;
  856. for (int iSection = 0; iSection < cSections; iSection++)
  857. {
  858. if (!parser.GotoSection(rgSections[iSection]))
  859. continue;
  860. // Look for "CopyFiles="
  861. while (parser.GetSectionLineTokens(rgLineTokens))
  862. {
  863. if (rgLineTokens.GetSize() >= 3 &&
  864. rgLineTokens.ElementAt(0).CompareNoCase("CopyFiles") == 0 &&
  865. rgLineTokens.ElementAt(1).Compare("=") == 0)
  866. {
  867. AddCommaSeparatedValues(rgLineTokens, rgCopyFiles, TRUE);
  868. }
  869. }
  870. }
  871. // Walk through each CopyFiles section, grabbing the names of files to copy
  872. parser.GetFilesFromCopyFilesSections(rgCopyFiles, m_rgDriverFiles);
  873. m_rgLayoutFiles.Add(parser);
  874. // for (int i = 0; i < rgAllFiles.GetSize(); i++)
  875. // {
  876. // TRACE("File %d: %s\r\n", i, rgAllFiles[i]);
  877. // }
  878. return TRUE;
  879. }
  880. BOOL CInfFileList::AddDeviceFiles(LPCTSTR pszInfFile, LPCTSTR pszDeviceID)
  881. {
  882. CInfParser parser;
  883. if (!parser.LoadInfFile(pszInfFile))
  884. return FALSE;
  885. if (!GetDeviceCopyFiles(parser, pszDeviceID, m_rgDriverFiles))
  886. return FALSE;
  887. // Build a list of all layout files, including current file
  888. m_rgLayoutFiles.Add(parser);
  889. return TRUE;
  890. }
  891. // Retrieves one of the standard setupx destination directories.
  892. // Always appends a backslash to the name.
  893. // Returns number of characters copied.
  894. //
  895. // See setupx.h for a list of valid LDID_ values.
  896. //
  897. int GetStandardTargetPath(int iDirNumber, LPCTSTR pszTargetSubDir, LPTSTR pszBuf)
  898. {
  899. int cch = GetWindowsDirectory(pszBuf, MAX_PATH);
  900. if (pszBuf[cch-1] != '\\')
  901. pszBuf[cch++] = '\\';
  902. switch (iDirNumber)
  903. {
  904. case 10: // LDID_WIN
  905. break;
  906. case 11: // LDID_SYS
  907. cch = GetSystemDirectory(pszBuf, MAX_PATH);
  908. if (pszBuf[cch-1] != '\\')
  909. pszBuf[cch++] = '\\';
  910. break;
  911. case 17: // LDID_INF
  912. lstrcpy(pszBuf + cch, "INF\\");
  913. cch += 4;
  914. break;
  915. case 18: // LDID_HELP
  916. lstrcpy(pszBuf + cch, "HELP\\");
  917. cch += 5;
  918. break;
  919. case 25: // LDID_SHARED (windows dir)
  920. break;
  921. case 26: // LDID_WINBOOT (windows dir)
  922. break;
  923. default:
  924. ASSERT(FALSE);
  925. cch = 0;
  926. break;
  927. }
  928. if (pszTargetSubDir != NULL && *pszTargetSubDir != '\0')
  929. {
  930. lstrcpy(pszBuf + cch, pszTargetSubDir);
  931. cch += lstrlen(pszTargetSubDir);
  932. if (pszBuf[cch-1] != '\\')
  933. pszBuf[cch++] = '\\';
  934. }
  935. pszBuf[cch] = '\0';
  936. return cch;
  937. }
  938. int GetDriverTargetPath(const DRIVER_FILE_INFO* pFileInfo, LPTSTR pszBuf)
  939. {
  940. LPCTSTR pszTargetSubDir = pFileInfo->szFileTitle + lstrlen(pFileInfo->szFileTitle) + 1;
  941. return GetStandardTargetPath(pFileInfo->nTargetDir, pszTargetSubDir, pszBuf);
  942. }
  943. // Returns number of CAB files (from Windows CD) that need to be copied.
  944. // Note that other files may still need to be copied from the driver source directory.
  945. int CInfFileList::BuildSourceFileList()
  946. {
  947. TCHAR szPath[MAX_PATH];
  948. CSortedStringArray& rgCabFiles = m_rgCabFiles;
  949. CSortedStringArray& rgSourceFiles = m_rgSourceFiles;
  950. m_rgLayoutFiles.Sort();
  951. #ifdef _DEBUG
  952. // m_rgLayoutFiles.Dump();
  953. #endif
  954. for (int iDriverFile = 0; iDriverFile < m_rgDriverFiles.GetSize(); iDriverFile++)
  955. {
  956. DRIVER_FILE_INFO* pDriverFileInfo = m_rgDriverFiles[iDriverFile];
  957. // Check if file is already installed
  958. // GetStandardTargetPath(pDriverFileInfo->nTargetDir, szPath);
  959. // MakePath(szPath, szPath, pDriverFileInfo->szFileTitle);
  960. // if (DoesFileExist(szPath))
  961. // continue; // skip this file
  962. if (!m_strDriverSourceDir.IsEmpty())
  963. {
  964. // Check if file exists in source directory
  965. MakePath(szPath, m_strDriverSourceDir, pDriverFileInfo->szFileTitle);
  966. if (DoesFileExist(szPath))
  967. {
  968. if (-1 == rgSourceFiles.Find(pDriverFileInfo->szFileTitle))
  969. {
  970. rgSourceFiles.Add(pDriverFileInfo->szFileTitle, 0);
  971. }
  972. continue;
  973. }
  974. }
  975. SOURCE_DISK_INFO* pSourceDiskInfo = m_rgLayoutFiles.FindDriverFileSourceDisk(pDriverFileInfo->szFileTitle);
  976. if (pSourceDiskInfo != NULL && !pSourceDiskInfo->strCabFile.IsEmpty())
  977. {
  978. if (-1 == rgCabFiles.Find(pSourceDiskInfo->strCabFile))
  979. {
  980. LPTSTR pszDiskName = lstrdup(pSourceDiskInfo->strDescription);
  981. rgCabFiles.Add(pSourceDiskInfo->strCabFile, (DWORD)pszDiskName);
  982. }
  983. continue;
  984. }
  985. }
  986. for (int i = 0; i < rgCabFiles.GetSize(); i++)
  987. {
  988. TRACE("%s\r\n", rgCabFiles[i]);
  989. }
  990. return rgCabFiles.GetSize();
  991. }
  992. #if NOT_FINISHED
  993. BOOL CInfFileList::CheckWindowsCD(LPCTSTR pszDirectory)
  994. {
  995. if (m_rgCabFiles.GetSize() == 0)
  996. return TRUE; // no files to copy
  997. UINT uPrevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  998. // Check for existence of one of the cabs on the CD
  999. // REVIEW: if it's a fixed disk, should check for all files
  1000. // REVIEW: if it's a network share, this could take a long time
  1001. TCHAR szPath[MAX_PATH];
  1002. BOOL bResult = FALSE;
  1003. MakePath(szPath, pszDirectory, ".");
  1004. if (DoesFileExist(szPath))
  1005. {
  1006. MakePath(szPath, pszDirectory, m_rgCabFiles[0]);
  1007. bResult = DoesFileExist(szPath);
  1008. if (!bResult)
  1009. {
  1010. // Search one level of subdirectories starting with "W"
  1011. WIN32_FIND_DATA Find;
  1012. HANDLE hFind;
  1013. MakePath(szPath, pszDirectory, "W*.*");
  1014. if (INVALID_HANDLE_VALUE != (hFind = FindFirstFile(szPath, &Find)))
  1015. {
  1016. do
  1017. {
  1018. MakePath(szPath, pszDirectory, Find.cFileName);
  1019. MakePath(szPath, szPath, m_rgCabFiles[0]);
  1020. if (DoesFileExist(szPath))
  1021. {
  1022. bResult = TRUE;
  1023. break;
  1024. }
  1025. }
  1026. while (FindNextFile(hFind, &Find));
  1027. FindClose(hFind);
  1028. }
  1029. }
  1030. }
  1031. SetErrorMode(uPrevErrorMode);
  1032. return bResult;
  1033. }
  1034. BOOL CInfFileList::FindWindowsCD(HWND hwndParent)
  1035. {
  1036. TCHAR szPath[MAX_PATH];
  1037. // check the version of the Windows source path that we've saved
  1038. if (theApp.GetProfileString(c_szRegVal_PrevSourcePath, szPath, _countof(szPath)))
  1039. {
  1040. if (CheckWindowsCD(szPath))
  1041. {
  1042. // goto success;
  1043. }
  1044. }
  1045. else
  1046. {
  1047. // Check the current Windows source path
  1048. CRegistry reg;
  1049. if (reg.OpenKey(HKEY_LOCAL_MACHINE, c_szSetupKey) &&
  1050. reg.QueryStringValue(c_szRegVal_SourcePath, szPath, _countof(szPath)))
  1051. {
  1052. if (CheckWindowsCD(szPath))
  1053. {
  1054. goto success;
  1055. }
  1056. }
  1057. }
  1058. if (!PromptWindowsCD(hwndParent, szPath, szPath))
  1059. return FALSE;
  1060. success:
  1061. m_strWindowsCD = szPath;
  1062. return TRUE;
  1063. }
  1064. BOOL CInfFileList::PromptWindowsCD(HWND hwndParent, LPCTSTR pszInitialDir, LPTSTR pszResultDir)
  1065. {
  1066. LPCTSTR pszDiskName = (LPCTSTR)m_rgCabFiles.GetItemData(0);
  1067. CWinPathDlg dlg(pszInitialDir, pszDiskName, CWnd::FromHandle(hwndParent));
  1068. // Loop until user types a path to a valid CD, or clicks Cancel
  1069. for (;;)
  1070. {
  1071. if (IDOK != dlg.DoModal())
  1072. return FALSE;
  1073. if (CheckWindowsCD(dlg.m_strPath))
  1074. {
  1075. lstrcpy(pszResultDir, dlg.m_strPath);
  1076. return TRUE;
  1077. }
  1078. }
  1079. }
  1080. BOOL CInfFileList::CopySourceFiles(HWND hwndParent, LPCTSTR pszDestDir, PROGRESS_CALLBACK pfnProgress, LPVOID pvProgressParam)
  1081. {
  1082. int cFiles = m_rgCabFiles.GetSize() + m_rgSourceFiles.GetSize();
  1083. if (m_rgCabFiles.GetSize() > 0)
  1084. {
  1085. }
  1086. return TRUE;
  1087. }
  1088. #endif
  1089. //////////////////////////////////////////////////////////////////////////////
  1090. // Modify system INF
  1091. class CInfUpdater : public CInfParser
  1092. {
  1093. public:
  1094. CInfUpdater(LPCTSTR pszRequire = NULL, LPCTSTR pszExclude = NULL);
  1095. ~CInfUpdater();
  1096. enum eUpdateType {
  1097. update_NoVersionConflict = 0x01,
  1098. update_NoCopyFiles = 0x02,
  1099. update_RequireExclude = 0x04,
  1100. };
  1101. BOOL IsModified();
  1102. BOOL UpdateInfFile(LPCTSTR pszBackupLocation, UINT updateType);
  1103. LPCTSTR m_pszRequire;
  1104. LPCTSTR m_pszExclude;
  1105. protected:
  1106. void WriteToCurPos();
  1107. void Write(LPCTSTR pszString);
  1108. void Write(const void* pvData, UINT cbData);
  1109. BOOL OpenTempFile();
  1110. BOOL CloseTempFile();
  1111. BOOL RenameTempFile();
  1112. protected:
  1113. CString m_strTempFile;
  1114. HANDLE m_hTempFile;
  1115. BOOL m_bWriteSuccess;
  1116. DWORD m_iWritePos;
  1117. };
  1118. CInfUpdater::CInfUpdater(LPCTSTR pszRequire /*=NULL*/, LPCTSTR pszExclude /*=NULL*/)
  1119. {
  1120. m_hTempFile = INVALID_HANDLE_VALUE;
  1121. m_pszRequire = pszRequire;
  1122. m_pszExclude = pszExclude;
  1123. }
  1124. CInfUpdater::~CInfUpdater()
  1125. {
  1126. CloseTempFile();
  1127. if (!m_strTempFile.IsEmpty())
  1128. {
  1129. DeleteFile(m_strTempFile);
  1130. }
  1131. }
  1132. BOOL CInfUpdater::IsModified()
  1133. {
  1134. ASSERT(m_pszFileData != NULL);
  1135. return !memcmp(SZ_CHECK_MODIFIED_HEADER, m_pszFileData, _lengthof(SZ_CHECK_MODIFIED_HEADER));
  1136. }
  1137. BOOL CInfUpdater::UpdateInfFile(LPCTSTR pszBackupLocation, UINT updateType)
  1138. {
  1139. ASSERT(m_pszFileData != NULL);
  1140. if (m_pszFileData == NULL)
  1141. return FALSE;
  1142. Rewind();
  1143. if (!OpenTempFile())
  1144. return FALSE;
  1145. Write(SZ_MODIFIED_INF_HEADER);
  1146. Write(pszBackupLocation);
  1147. Write(SZ_MODIFIED_INF_HEADER2);
  1148. BOOL bInSection = FALSE;
  1149. for (;;)
  1150. {
  1151. // Skip whitespace
  1152. while (m_pszFileData[m_iPos] == ' ' || m_pszFileData[m_iPos] == '\t')
  1153. m_iPos++;
  1154. // Note: we're always at the beginning of a line here.
  1155. TCHAR ch = m_pszFileData[m_iPos];
  1156. if (ch == '\0')
  1157. break;
  1158. if (updateType & update_NoVersionConflict)
  1159. {
  1160. if (ch != '[' && ch != ';' && (UINT)ch > ' ')
  1161. {
  1162. // Look for lines w/ just a filename, and append ",,,32" to them
  1163. LPTSTR pszLine = m_pszFileData + m_iPos;
  1164. LPTSTR pchEnd = pszLine;
  1165. while (*pchEnd != '\0' && *pchEnd != '\r' && *pchEnd != '\n' &&
  1166. *pchEnd != ';' && *pchEnd != '=' && *pchEnd != ',')
  1167. {
  1168. pchEnd++;
  1169. }
  1170. // don't change lines that already have ,,,16 or something
  1171. // also don't change lines like CatalogFile=nettrans.cat
  1172. if (*pchEnd != ',' && *pchEnd != '=')
  1173. {
  1174. // Backup over whitespace
  1175. while (*(pchEnd-1) == ' ' || *(pchEnd-1) == '\t')
  1176. pchEnd--;
  1177. // Is it a filename? Note that some filenames will be missed here, but
  1178. // we really only care about .dll, .386, .vxd, and a few others
  1179. CString str(pszLine, (int)(pchEnd - pszLine));
  1180. if (lstrlen(FindExtension(str)) == 3)
  1181. {
  1182. m_iPos = (DWORD)(pchEnd - m_pszFileData);
  1183. WriteToCurPos();
  1184. Write(",,,32");
  1185. }
  1186. }
  1187. }
  1188. }
  1189. if (updateType & update_NoCopyFiles)
  1190. {
  1191. if (0 == memcmp(m_pszFileData + m_iPos, "CopyFiles", _lengthof("CopyFiles")))
  1192. {
  1193. // Comment out the reference to the CopyFiles section
  1194. WriteToCurPos();
  1195. Write(";hc ");
  1196. }
  1197. }
  1198. if (updateType & update_RequireExclude)
  1199. {
  1200. ASSERT(m_pszRequire != NULL);
  1201. ASSERT(m_pszExclude != NULL);
  1202. const TCHAR c_szRequireAll[] = _T("HKR,Ndi\\Compatibility,RequireAll,,\"");
  1203. const TCHAR c_szExcludeAll[] = _T("HKR,Ndi\\Compatibility,ExcludeAll,,\"");
  1204. LPCTSTR pszInsert = NULL;
  1205. if (0 == memcmp(m_pszFileData + m_iPos, c_szRequireAll, _lengthof(c_szRequireAll)))
  1206. pszInsert = m_pszRequire;
  1207. else if (0 == memcmp(m_pszFileData + m_iPos, c_szExcludeAll, _lengthof(c_szExcludeAll)))
  1208. pszInsert = m_pszExclude;
  1209. if (pszInsert != NULL)
  1210. {
  1211. // Insert the appropriate string between the double-quotes
  1212. ASSERT(_lengthof(c_szRequireAll) == _lengthof(c_szExcludeAll));
  1213. m_iPos += _lengthof(c_szRequireAll);
  1214. WriteToCurPos();
  1215. Write(pszInsert);
  1216. // Skip to closing quote
  1217. while (m_pszFileData[m_iPos] != '\"' && m_pszFileData[m_iPos] != '\0')
  1218. m_iPos += 1;
  1219. m_iWritePos = m_iPos;
  1220. }
  1221. }
  1222. GotoNextLine();
  1223. }
  1224. WriteToCurPos();
  1225. if (!CloseTempFile())
  1226. return FALSE;
  1227. if (!RenameTempFile())
  1228. return FALSE;
  1229. return TRUE;
  1230. }
  1231. void CInfUpdater::WriteToCurPos()
  1232. {
  1233. ASSERT(m_iPos >= m_iWritePos);
  1234. Write(m_pszFileData + m_iWritePos, m_iPos - m_iWritePos);
  1235. m_iWritePos = m_iPos;
  1236. }
  1237. void CInfUpdater::Write(LPCTSTR pszString)
  1238. {
  1239. Write(pszString, lstrlen(pszString));
  1240. }
  1241. void CInfUpdater::Write(const void* pvData, UINT cbData)
  1242. {
  1243. DWORD cbWritten;
  1244. if (!WriteFile(m_hTempFile, pvData, cbData, &cbWritten, NULL) || cbData != cbWritten)
  1245. m_bWriteSuccess = FALSE;
  1246. }
  1247. BOOL CInfUpdater::OpenTempFile()
  1248. {
  1249. TCHAR szDirectory[MAX_PATH];
  1250. GetFullInfPath(m_strFileName, szDirectory, _countof(szDirectory));
  1251. *(FindFileTitle(szDirectory)) = '\0';
  1252. LPTSTR pszBuf = m_strTempFile.GetBuffer(MAX_PATH);
  1253. GetTempFileName(szDirectory, "inf", 0, pszBuf);
  1254. m_strTempFile.ReleaseBuffer();
  1255. ASSERT(m_hTempFile == INVALID_HANDLE_VALUE);
  1256. m_hTempFile = CreateFile(m_strTempFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  1257. if (m_hTempFile == INVALID_HANDLE_VALUE)
  1258. return FALSE;
  1259. m_iWritePos = 0;
  1260. m_bWriteSuccess = TRUE;
  1261. return TRUE;
  1262. }
  1263. BOOL CInfUpdater::CloseTempFile()
  1264. {
  1265. if (m_hTempFile == INVALID_HANDLE_VALUE)
  1266. return FALSE;
  1267. BOOL bResult = CloseHandle(m_hTempFile);
  1268. m_hTempFile = INVALID_HANDLE_VALUE;
  1269. if (m_bWriteSuccess)
  1270. m_bWriteSuccess = bResult;
  1271. return m_bWriteSuccess;
  1272. }
  1273. BOOL CInfUpdater::RenameTempFile()
  1274. {
  1275. TCHAR szInfPath[MAX_PATH];
  1276. GetFullInfPath(m_strFileName, szInfPath, _countof(szInfPath));
  1277. if (!DeleteFile(szInfPath))
  1278. return FALSE;
  1279. if (!MoveFile(m_strTempFile, szInfPath))
  1280. return FALSE;
  1281. return TRUE;
  1282. }
  1283. // Modifies the given INF file to avoid the Version Conflict dialog.
  1284. // Backs up original version in same directory, e.g. "Net (HomeClick backup).inf"
  1285. BOOL ModifyInf_Helper(LPCTSTR pszInfFile, UINT updateType, LPCTSTR pszRequire = NULL, LPCTSTR pszExclude = NULL)
  1286. {
  1287. CInfUpdater infUpdate(pszRequire, pszExclude);
  1288. if (!infUpdate.LoadInfFile(pszInfFile))
  1289. return FALSE;
  1290. // Already updated?
  1291. if (infUpdate.IsModified())
  1292. return FALSE; // already modified, don't modify again
  1293. TCHAR szInfPath[MAX_PATH];
  1294. GetFullInfPath(pszInfFile, szInfPath, _countof(szInfPath));
  1295. TCHAR szBackup[MAX_PATH];
  1296. lstrcpy(szBackup, szInfPath);
  1297. lstrcpy(FindExtension(szBackup)-1, SZ_INF_BACKUP_SUFFIX);
  1298. FILETIME ftSrcCreated;
  1299. FILETIME ftSrcModified;
  1300. HANDLE hFile = CreateFile(szInfPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  1301. GetFileTime(hFile, &ftSrcCreated, NULL, &ftSrcModified);
  1302. CloseHandle(hFile);
  1303. if (!CopyFile(szInfPath, szBackup, FALSE))
  1304. return FALSE;
  1305. BOOL bResult = infUpdate.UpdateInfFile(szBackup, updateType);
  1306. hFile = CreateFile(szInfPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  1307. DWORD dwFileSize = GetFileSize(hFile, NULL);
  1308. SetFileTime(hFile, &ftSrcCreated, NULL, &ftSrcModified);
  1309. CloseHandle(hFile);
  1310. return bResult;
  1311. }
  1312. BOOL ModifyInf_NoVersionConflict(LPCTSTR pszInfFile)
  1313. {
  1314. return ModifyInf_Helper(pszInfFile, CInfUpdater::update_NoVersionConflict);
  1315. }
  1316. BOOL ModifyInf_NoCopyFiles(LPCTSTR pszInfFile)
  1317. {
  1318. return ModifyInf_Helper(pszInfFile, CInfUpdater::update_NoCopyFiles);
  1319. }
  1320. BOOL ModifyInf_RequireExclude(LPCTSTR pszInfFile, LPCTSTR pszRequire, LPCTSTR pszExclude)
  1321. {
  1322. return ModifyInf_Helper(pszInfFile, CInfUpdater::update_RequireExclude, pszRequire, pszExclude);
  1323. }
  1324. BOOL ModifyInf_NoCopyAndRequireExclude(LPCTSTR pszInfFile, LPCTSTR pszRequire, LPCTSTR pszExclude)
  1325. {
  1326. return ModifyInf_Helper(pszInfFile,
  1327. CInfUpdater::update_NoCopyFiles | CInfUpdater::update_RequireExclude,
  1328. pszRequire, pszExclude);
  1329. }
  1330. BOOL RestoreInfBackup(LPCTSTR pszInfFile)
  1331. {
  1332. TCHAR szInfPath[MAX_PATH];
  1333. GetFullInfPath(pszInfFile, szInfPath, _countof(szInfPath));
  1334. TCHAR szBackup[MAX_PATH];
  1335. lstrcpy(szBackup, szInfPath);
  1336. lstrcpy(FindExtension(szBackup)-1, SZ_INF_BACKUP_SUFFIX);
  1337. /*
  1338. FILETIME ftSrcCreated;
  1339. FILETIME ftSrcModified;
  1340. HANDLE hFile = CreateFile(szInfPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  1341. GetFileTime(hFile, &ftSrcCreated, NULL, &ftSrcModified);
  1342. CloseHandle(hFile);
  1343. */
  1344. if (!DoesFileExist(szBackup))
  1345. return FALSE;
  1346. if (!DeleteFile(szInfPath))
  1347. return FALSE;
  1348. if (!MoveFile(szBackup, szInfPath))
  1349. return FALSE;
  1350. /*
  1351. hFile = CreateFile(szInfPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  1352. GetFileTime(hFile, &ftSrcCreated, NULL, &ftSrcModified);
  1353. CloseHandle(hFile);
  1354. */
  1355. return TRUE;
  1356. }
  1357. BOOL CheckInfSectionInstallation(LPCTSTR pszInfFile, LPCTSTR pszInfSection)
  1358. {
  1359. CInfParser parser;
  1360. if (!parser.LoadInfFile(pszInfFile))
  1361. {
  1362. ASSERT(FALSE);
  1363. return TRUE; // all known files are present even though it's an error
  1364. }
  1365. CDriverFileArray rgFiles;
  1366. if (!parser.GetFilesFromInstallSection(pszInfSection, rgFiles))
  1367. {
  1368. ASSERT(FALSE);
  1369. return TRUE; // all known files are present even though it's an error
  1370. }
  1371. TCHAR szPath[MAX_PATH];
  1372. int cFiles = rgFiles.GetSize();
  1373. for (int iFile = 0; iFile < cFiles; iFile++)
  1374. {
  1375. int cch = GetDriverTargetPath(rgFiles[iFile], szPath);
  1376. if (cch != 0)
  1377. {
  1378. lstrcpy(szPath + cch, rgFiles[iFile]->szFileTitle);
  1379. if (!DoesFileExist(szPath))
  1380. return FALSE;
  1381. }
  1382. }
  1383. return TRUE;
  1384. }
  1385. BOOL InstallInfSection(LPCTSTR pszInfFile, LPCTSTR pszInfSection, BOOL bWait)
  1386. {
  1387. // Make a modified copy of the INF
  1388. BOOL bModifiedInf = ModifyInf_NoVersionConflict(pszInfFile);
  1389. TCHAR szPath[MAX_PATH + 200];
  1390. int cch = GetWindowsDirectory(szPath, _countof(szPath));
  1391. #ifdef UNICODE
  1392. wnsprintf(szPath + cch, ARRAYSIZE(szPath) - cch, L"\\RunDll.exe setupx.dll,InstallHinfSection %s 0 %s", pszInfSection, pszInfFile);
  1393. #else
  1394. wsprintf(szPath + cch, "\\RunDll.exe setupx.dll,InstallHinfSection %s 0 %s", pszInfSection, pszInfFile);
  1395. #endif
  1396. STARTUPINFO si;
  1397. ZeroMemory(&si, sizeof(si));
  1398. si.cb = sizeof(si);
  1399. PROCESS_INFORMATION pi;
  1400. BOOL bResult = CreateProcess(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
  1401. if (bResult)
  1402. {
  1403. if (bWait)
  1404. {
  1405. WaitForSingleObject(pi.hProcess, INFINITE);
  1406. }
  1407. CloseHandle(pi.hProcess);
  1408. CloseHandle(pi.hThread);
  1409. }
  1410. if (bModifiedInf)
  1411. {
  1412. RestoreInfBackup(pszInfFile);
  1413. }
  1414. return bResult;
  1415. }