Source code of Windows XP (NT5)
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.

1697 lines
39 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. pFileInfo->nTargetDir = nTargetDir;
  480. lstrcpy(pFileInfo->szFileTitle, strFileName);
  481. lstrcpy(pFileInfo->szFileTitle + strFileName.GetLength() + 1, szTargetSubDir);
  482. rgAllFiles.Add(pFileInfo);
  483. }
  484. }
  485. }
  486. }
  487. // TODO: Remove duplicate files (maybe here, maybe not)
  488. }
  489. int CInfParser::GetNextSourceFile(LPTSTR pszBuf, BYTE* pDiskNumber)
  490. {
  491. LPTSTR pch = m_pszFileData + m_iPos;
  492. int cch = 0;
  493. BYTE bDiskNumber = 0;
  494. for (;;)
  495. {
  496. TCHAR ch;
  497. while ((ch = *pch) == '\r' || ch == '\n')
  498. pch++;
  499. if (ch == '\0' || ch == '[' || cch != 0)
  500. break;
  501. if (ch != ';')
  502. {
  503. LPTSTR pchStart = pch;
  504. while ((UCHAR)(ch = *pch) > 32 && ch != '=')
  505. pch++;
  506. cch = (int)(pch - pchStart);
  507. lstrcpyn(pszBuf, pchStart, cch+1);
  508. // skip whitespace while avoiding '\0'
  509. while ((UCHAR)(*pch-1) < 32)
  510. pch++;
  511. if (*pch == '=')
  512. {
  513. pch++;
  514. // skip whitespace while avoiding '\0'
  515. while ((UCHAR)(*pch-1) < 32)
  516. pch++;
  517. bDiskNumber = (BYTE)MyAtoi(pch);
  518. #if 1 // ignore files with disk number of 0
  519. if (bDiskNumber == 0)
  520. cch = 0;
  521. #endif
  522. }
  523. }
  524. // skip text up to newline
  525. while ((ch = *pch) != '\0' && ch != '\r' && ch != '\n')
  526. pch++;
  527. }
  528. *pDiskNumber = bDiskNumber;
  529. m_iPos = (DWORD)(pch - m_pszFileData);
  530. return cch;
  531. }
  532. /*
  533. int CInfParser::ReadSourceFilesSection(INF_LAYOUT_FILE* prgFiles, int cFiles)
  534. {
  535. WORD wOffset = (WORD)(cFiles * sizeof(INF_LAYOUT_FILE));
  536. LPTSTR pchDest = (LPTSTR)((LPBYTE)m_prgFiles + wOffset);
  537. INF_LAYOUT_FILE* pFile = prgFiles;
  538. INF_LAYOUT_FILE* pFileEnd = pFile + cFiles;
  539. while (pFile < pFileEnd)
  540. {
  541. pFile->wNameOffset = (WORD)((LPBYTE)pchDest - (LPBYTE)prgFiles);
  542. int cch = parser.GetNextSourceFile(pchDest, &pFile->iDisk);
  543. wOffset += cch+1;
  544. pchDest += cch+1;
  545. pFile++;
  546. }
  547. LPTSTR pch = m_pszFileData + m_iPos;
  548. int cch = 0;
  549. *pDiskNumber = 0;
  550. for (;;)
  551. {
  552. TCHAR ch;
  553. while ((ch = *pch) == '\r' || ch == '\n')
  554. pch++;
  555. if (ch == '\0' || ch == '[' || cch != 0)
  556. break;
  557. if (ch != ';')
  558. {
  559. LPTSTR pchStart = pch;
  560. while ((UCHAR)(ch = *pch) > 32 && ch != '=')
  561. pch++;
  562. cch = (int)(pch - pchStart);
  563. lstrcpyn(pszBuf, pchStart, cch+1);
  564. // skip whitespace while avoiding '\0'
  565. while ((UCHAR)(*pch-1) < 32)
  566. pch++;
  567. if (*pch == '=')
  568. {
  569. pch++;
  570. // skip whitespace while avoiding '\0'
  571. while ((UCHAR)(*pch-1) < 32)
  572. pch++;
  573. *pDiskNumber = (BYTE)atoi(pch);
  574. }
  575. }
  576. // skip text up to newline
  577. while ((ch = *pch) != '\0' && ch != '\r' && ch != '\n')
  578. pch++;
  579. }
  580. m_iPos = (DWORD)(pch - m_pszFileData);
  581. return cch;
  582. }
  583. */
  584. void CInfParser::ScanSourceFileList(int* pcFiles, int* pcchAllFileNames)
  585. {
  586. int cFiles = 0;
  587. int cchAllFileNames = 0;
  588. LPTSTR pch = m_pszFileData + m_iPos;
  589. for (;;)
  590. {
  591. TCHAR ch;
  592. while ((ch = *pch) == '\r' || ch == '\n')
  593. pch++;
  594. if (ch == '\0' || ch == '[')
  595. break;
  596. if (ch != ';')
  597. {
  598. cFiles += 1;
  599. LPTSTR pchStart = pch;
  600. while ((UCHAR)(ch = *pch) >= 32 && ch != '=')
  601. pch++;
  602. cchAllFileNames += (int)(pch - pchStart);
  603. }
  604. // skip text up to newline
  605. while ((ch = *pch) != '\0' && ch != '\r' && ch != '\n')
  606. pch++;
  607. }
  608. *pcFiles = cFiles;
  609. *pcchAllFileNames = cchAllFileNames;
  610. }
  611. //////////////////////////////////////////////////////////////////////////////
  612. // CInfLayoutFiles
  613. #define INF_LAYOUT_FILE_PADDING 40 // extra bytes at end of string data
  614. CInfLayoutFiles::CInfLayoutFiles()
  615. {
  616. m_prgFiles = NULL;
  617. m_pStringData = NULL;
  618. m_cFiles = 0;
  619. m_cbStringData = 0;
  620. #ifdef _DEBUG
  621. m_bSorted = FALSE;
  622. #endif
  623. }
  624. CInfLayoutFiles::~CInfLayoutFiles()
  625. {
  626. free(m_prgFiles);
  627. free(m_pStringData);
  628. for (int i = m_rgSourceDisks.GetSize()-1; i >= 0; i--)
  629. {
  630. delete m_rgSourceDisks[i];
  631. }
  632. }
  633. LPTSTR CInfLayoutFiles::s_pStringData;
  634. int __cdecl CInfLayoutFiles::CompareInfLayoutFiles(const void* pEl1, const void* pEl2)
  635. {
  636. LPCTSTR psz1 = s_pStringData + ((INF_LAYOUT_FILE*)pEl1)->dwNameOffset;
  637. LPCTSTR psz2 = s_pStringData + ((INF_LAYOUT_FILE*)pEl2)->dwNameOffset;
  638. return lstrcmpi(psz1, psz2);
  639. }
  640. BOOL CInfLayoutFiles::Add(CInfParser& parser, BOOL bLayoutFile)
  641. {
  642. // Check if we've already added this layout file
  643. if (-1 != m_rgLayoutFileNames.Find(parser.m_strFileName))
  644. return TRUE;
  645. BYTE iLayoutFile = (BYTE)m_rgLayoutFileNames.GetSize();
  646. m_rgLayoutFileNames.Add(parser.m_strFileName, 0);
  647. if (parser.GotoSection("SourceDisksFiles"))
  648. {
  649. DWORD dwTicks1 = GetTickCount();
  650. int cFiles;
  651. int cchAllFileNames;
  652. parser.ScanSourceFileList(&cFiles, &cchAllFileNames);
  653. DWORD dwTicks2 = GetTickCount();
  654. DWORD dwOffset = (DWORD)m_cbStringData;
  655. int iFile = m_cFiles;
  656. m_cFiles += cFiles;
  657. m_cbStringData += cchAllFileNames + cFiles;
  658. m_prgFiles = (INF_LAYOUT_FILE*)realloc(m_prgFiles, m_cFiles * sizeof(INF_LAYOUT_FILE));
  659. m_pStringData = (LPTSTR)realloc(m_pStringData, m_cbStringData + INF_LAYOUT_FILE_PADDING);
  660. LPTSTR pchDest = m_pStringData + dwOffset;
  661. INF_LAYOUT_FILE* pFile = m_prgFiles + iFile;
  662. for ( ; iFile < m_cFiles; iFile++)
  663. {
  664. pFile->dwNameOffset = dwOffset;
  665. pFile->iLayout = iLayoutFile;
  666. int cch = parser.GetNextSourceFile(pchDest, &pFile->iDisk);
  667. dwOffset += cch+1;
  668. pchDest += cch+1;
  669. pFile++;
  670. }
  671. DWORD dwTicks3 = GetTickCount();
  672. CString str;
  673. str.Format("LoadLayout(%s) timings: %d ms, %d ms. Total time: %d ms",
  674. parser.m_strFileName, dwTicks2-dwTicks1, dwTicks3-dwTicks2, dwTicks3-dwTicks1);
  675. TRACE("%s\r\n", str);
  676. // AfxMessageBox(str);
  677. // for (int i = 0; i < cFiles; i++)
  678. // {
  679. // INF_LAYOUT_FILE* pFile = &m_prgFiles[i];
  680. // TRACE("File %d: %s=%d\r\n", i, m_pStringData + pFile->dwNameOffset), pFile->iDisk);
  681. // }
  682. #ifdef _DEBUG
  683. m_bSorted = FALSE;
  684. #endif
  685. }
  686. if (parser.GotoSection("SourceDisksNames"))
  687. {
  688. CStringArray rgTokens;
  689. while (parser.GetSectionLineTokens(rgTokens))
  690. {
  691. if (rgTokens.GetSize() >= 3)
  692. {
  693. BYTE iDiskNumber = (BYTE)MyAtoi(rgTokens.ElementAt(0));
  694. if (iDiskNumber != 0)
  695. {
  696. SOURCE_DISK_INFO* pDiskInfo = new SOURCE_DISK_INFO;
  697. pDiskInfo->wDiskID = MAKE_DISK_ID(iDiskNumber, iLayoutFile);
  698. // Get disk description, pull off quotes
  699. CString& strDesc = rgTokens.ElementAt(2);
  700. if (strDesc[0] == '\"')
  701. pDiskInfo->strDescription = strDesc.Mid(1, strDesc.GetLength()-2);
  702. else
  703. pDiskInfo->strDescription = strDesc;
  704. // If this is Layout*.inf, Get CAB filename, pull off quotes
  705. if (bLayoutFile && rgTokens.GetSize() >= 5)
  706. {
  707. CString& strCab = rgTokens.ElementAt(4);
  708. if (strCab[0] == '\"')
  709. pDiskInfo->strCabFile = strCab.Mid(1, strCab.GetLength()-2);
  710. else
  711. pDiskInfo->strCabFile = strCab;
  712. }
  713. m_rgSourceDisks.Add(pDiskInfo);
  714. }
  715. }
  716. }
  717. }
  718. //
  719. // Now add any referenced layout files
  720. //
  721. if (parser.GotoSection("version"))
  722. {
  723. CStringArray rgLayoutFiles;
  724. CStringArray rgLineTokens;
  725. while (parser.GetSectionLineTokens(rgLineTokens))
  726. {
  727. if (rgLineTokens.GetSize() >= 3 &&
  728. rgLineTokens.ElementAt(0).CompareNoCase("LayoutFile") == 0 &&
  729. rgLineTokens.ElementAt(1).Compare("=") == 0)
  730. {
  731. AddCommaSeparatedValues(rgLineTokens, rgLayoutFiles, FALSE);
  732. break;
  733. }
  734. }
  735. for (int i = 0; i < rgLayoutFiles.GetSize(); i++)
  736. {
  737. Add(rgLayoutFiles.ElementAt(i), TRUE);
  738. }
  739. }
  740. return TRUE;
  741. }
  742. BOOL CInfLayoutFiles::Add(LPCTSTR pszInfFile, BOOL bLayoutFile)
  743. {
  744. CInfParser parser;
  745. if (!parser.LoadInfFile(pszInfFile))
  746. return FALSE;
  747. return Add(parser, bLayoutFile);
  748. }
  749. void CInfLayoutFiles::Sort()
  750. {
  751. s_pStringData = m_pStringData;
  752. qsort(m_prgFiles, m_cFiles, sizeof(INF_LAYOUT_FILE), CompareInfLayoutFiles);
  753. #ifdef _DEBUG
  754. m_bSorted = TRUE;
  755. #endif
  756. }
  757. SOURCE_DISK_INFO* CInfLayoutFiles::FindDriverFileSourceDisk(LPCTSTR pszDriverFileTitle)
  758. {
  759. ASSERT(m_bSorted);
  760. // Build a dummy layout-file key to allow the standard binary search to work
  761. // (Note that we've left INF_LAYOUT_FILE_PADDING chars at the end of the string data)
  762. ASSERT(lstrlen(pszDriverFileTitle) + 1 < INF_LAYOUT_FILE_PADDING);
  763. INF_LAYOUT_FILE key;
  764. key.dwNameOffset = m_cbStringData;
  765. lstrcpy(m_pStringData + m_cbStringData, pszDriverFileTitle);
  766. s_pStringData = m_pStringData;
  767. INF_LAYOUT_FILE* pResult = (INF_LAYOUT_FILE*)bsearch(
  768. &key, m_prgFiles, m_cFiles, sizeof(INF_LAYOUT_FILE), CompareInfLayoutFiles);
  769. if (pResult == NULL)
  770. {
  771. ASSERT(FALSE);
  772. return NULL;
  773. }
  774. // REVIEW: Is it worth making this a binary search?
  775. WORD wDiskID = MAKE_DISK_ID(pResult->iDisk, pResult->iLayout);
  776. for (int iDisk = 0; iDisk < m_rgSourceDisks.GetSize(); iDisk++)
  777. {
  778. SOURCE_DISK_INFO* pDiskInfo = m_rgSourceDisks[iDisk];
  779. if (pDiskInfo->wDiskID == wDiskID)
  780. return pDiskInfo;
  781. }
  782. ASSERT(FALSE);
  783. return NULL;
  784. }
  785. #ifdef _DEBUG
  786. void CInfLayoutFiles::Dump()
  787. {
  788. TRACE("CInfLayoutFiles (0x%08x)\r\n", (int)this);
  789. for (int i = 0; i < m_cFiles; i++)
  790. {
  791. INF_LAYOUT_FILE* pFile = &m_prgFiles[i];
  792. TRACE(" File %d: %s, layout %d, disk %d\r\n", i, m_pStringData + pFile->dwNameOffset, (int)pFile->iLayout, (int)pFile->iDisk);
  793. }
  794. }
  795. #endif // _DEBUG
  796. //////////////////////////////////////////////////////////////////////////////
  797. // CInfFileList
  798. CInfFileList::CInfFileList()
  799. {
  800. }
  801. CInfFileList::~CInfFileList()
  802. {
  803. for (int i = m_rgDriverFiles.GetSize()-1; i >= 0; i--)
  804. {
  805. free(m_rgDriverFiles[i]);
  806. }
  807. for (i = m_rgCabFiles.GetSize() - 1; i >= 0; i--)
  808. {
  809. free((LPTSTR)m_rgCabFiles.GetItemData(i));
  810. }
  811. }
  812. void CInfFileList::SetDriverSourceDir(LPCTSTR pszSourceDir)
  813. {
  814. m_strDriverSourceDir = pszSourceDir;
  815. }
  816. BOOL CInfFileList::AddBaseFiles(LPCTSTR pszInfFile)
  817. {
  818. CInfParser parser;
  819. if (!parser.LoadInfFile(pszInfFile))
  820. return FALSE;
  821. if (!parser.GotoSection("BaseWinOptions"))
  822. return FALSE;
  823. CStringArray rgSections;
  824. CStringArray rgLineTokens;
  825. while (parser.GetSectionLineTokens(rgLineTokens))
  826. {
  827. if (rgLineTokens.GetSize() >= 1)
  828. rgSections.Add(rgLineTokens.ElementAt(0));
  829. }
  830. int cSections = rgSections.GetSize();
  831. if (cSections == 0)
  832. return FALSE;
  833. // Walk through each major section, grabbing section names from CopyFiles= lines
  834. CStringArray rgCopyFiles;
  835. for (int iSection = 0; iSection < cSections; iSection++)
  836. {
  837. if (!parser.GotoSection(rgSections[iSection]))
  838. continue;
  839. // Look for "CopyFiles="
  840. while (parser.GetSectionLineTokens(rgLineTokens))
  841. {
  842. if (rgLineTokens.GetSize() >= 3 &&
  843. rgLineTokens.ElementAt(0).CompareNoCase("CopyFiles") == 0 &&
  844. rgLineTokens.ElementAt(1).Compare("=") == 0)
  845. {
  846. AddCommaSeparatedValues(rgLineTokens, rgCopyFiles, TRUE);
  847. }
  848. }
  849. }
  850. // Walk through each CopyFiles section, grabbing the names of files to copy
  851. parser.GetFilesFromCopyFilesSections(rgCopyFiles, m_rgDriverFiles);
  852. m_rgLayoutFiles.Add(parser);
  853. // for (int i = 0; i < rgAllFiles.GetSize(); i++)
  854. // {
  855. // TRACE("File %d: %s\r\n", i, rgAllFiles[i]);
  856. // }
  857. return TRUE;
  858. }
  859. BOOL CInfFileList::AddDeviceFiles(LPCTSTR pszInfFile, LPCTSTR pszDeviceID)
  860. {
  861. CInfParser parser;
  862. if (!parser.LoadInfFile(pszInfFile))
  863. return FALSE;
  864. if (!GetDeviceCopyFiles(parser, pszDeviceID, m_rgDriverFiles))
  865. return FALSE;
  866. // Build a list of all layout files, including current file
  867. m_rgLayoutFiles.Add(parser);
  868. return TRUE;
  869. }
  870. // Retrieves one of the standard setupx destination directories.
  871. // Always appends a backslash to the name.
  872. // Returns number of characters copied.
  873. //
  874. // See setupx.h for a list of valid LDID_ values.
  875. //
  876. int GetStandardTargetPath(int iDirNumber, LPCTSTR pszTargetSubDir, LPTSTR pszBuf)
  877. {
  878. int cch = GetWindowsDirectory(pszBuf, MAX_PATH);
  879. if (pszBuf[cch-1] != '\\')
  880. pszBuf[cch++] = '\\';
  881. switch (iDirNumber)
  882. {
  883. case 10: // LDID_WIN
  884. break;
  885. case 11: // LDID_SYS
  886. cch = GetSystemDirectory(pszBuf, MAX_PATH);
  887. if (pszBuf[cch-1] != '\\')
  888. pszBuf[cch++] = '\\';
  889. break;
  890. case 17: // LDID_INF
  891. lstrcpy(pszBuf + cch, "INF\\");
  892. cch += 4;
  893. break;
  894. case 18: // LDID_HELP
  895. lstrcpy(pszBuf + cch, "HELP\\");
  896. cch += 5;
  897. break;
  898. case 25: // LDID_SHARED (windows dir)
  899. break;
  900. case 26: // LDID_WINBOOT (windows dir)
  901. break;
  902. default:
  903. ASSERT(FALSE);
  904. cch = 0;
  905. break;
  906. }
  907. if (pszTargetSubDir != NULL && *pszTargetSubDir != '\0')
  908. {
  909. lstrcpy(pszBuf + cch, pszTargetSubDir);
  910. cch += lstrlen(pszTargetSubDir);
  911. if (pszBuf[cch-1] != '\\')
  912. pszBuf[cch++] = '\\';
  913. }
  914. pszBuf[cch] = '\0';
  915. return cch;
  916. }
  917. int GetDriverTargetPath(const DRIVER_FILE_INFO* pFileInfo, LPTSTR pszBuf)
  918. {
  919. LPCTSTR pszTargetSubDir = pFileInfo->szFileTitle + lstrlen(pFileInfo->szFileTitle) + 1;
  920. return GetStandardTargetPath(pFileInfo->nTargetDir, pszTargetSubDir, pszBuf);
  921. }
  922. // Returns number of CAB files (from Windows CD) that need to be copied.
  923. // Note that other files may still need to be copied from the driver source directory.
  924. int CInfFileList::BuildSourceFileList()
  925. {
  926. TCHAR szPath[MAX_PATH];
  927. CSortedStringArray& rgCabFiles = m_rgCabFiles;
  928. CSortedStringArray& rgSourceFiles = m_rgSourceFiles;
  929. m_rgLayoutFiles.Sort();
  930. #ifdef _DEBUG
  931. // m_rgLayoutFiles.Dump();
  932. #endif
  933. for (int iDriverFile = 0; iDriverFile < m_rgDriverFiles.GetSize(); iDriverFile++)
  934. {
  935. DRIVER_FILE_INFO* pDriverFileInfo = m_rgDriverFiles[iDriverFile];
  936. // Check if file is already installed
  937. // GetStandardTargetPath(pDriverFileInfo->nTargetDir, szPath);
  938. // MakePath(szPath, szPath, pDriverFileInfo->szFileTitle);
  939. // if (DoesFileExist(szPath))
  940. // continue; // skip this file
  941. if (!m_strDriverSourceDir.IsEmpty())
  942. {
  943. // Check if file exists in source directory
  944. MakePath(szPath, m_strDriverSourceDir, pDriverFileInfo->szFileTitle);
  945. if (DoesFileExist(szPath))
  946. {
  947. if (-1 == rgSourceFiles.Find(pDriverFileInfo->szFileTitle))
  948. {
  949. rgSourceFiles.Add(pDriverFileInfo->szFileTitle, 0);
  950. }
  951. continue;
  952. }
  953. }
  954. SOURCE_DISK_INFO* pSourceDiskInfo = m_rgLayoutFiles.FindDriverFileSourceDisk(pDriverFileInfo->szFileTitle);
  955. if (pSourceDiskInfo != NULL && !pSourceDiskInfo->strCabFile.IsEmpty())
  956. {
  957. if (-1 == rgCabFiles.Find(pSourceDiskInfo->strCabFile))
  958. {
  959. LPTSTR pszDiskName = lstrdup(pSourceDiskInfo->strDescription);
  960. rgCabFiles.Add(pSourceDiskInfo->strCabFile, (DWORD)pszDiskName);
  961. }
  962. continue;
  963. }
  964. }
  965. for (int i = 0; i < rgCabFiles.GetSize(); i++)
  966. {
  967. TRACE("%s\r\n", rgCabFiles[i]);
  968. }
  969. return rgCabFiles.GetSize();
  970. }
  971. #if NOT_FINISHED
  972. BOOL CInfFileList::CheckWindowsCD(LPCTSTR pszDirectory)
  973. {
  974. if (m_rgCabFiles.GetSize() == 0)
  975. return TRUE; // no files to copy
  976. UINT uPrevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  977. // Check for existence of one of the cabs on the CD
  978. // REVIEW: if it's a fixed disk, should check for all files
  979. // REVIEW: if it's a network share, this could take a long time
  980. TCHAR szPath[MAX_PATH];
  981. BOOL bResult = FALSE;
  982. MakePath(szPath, pszDirectory, ".");
  983. if (DoesFileExist(szPath))
  984. {
  985. MakePath(szPath, pszDirectory, m_rgCabFiles[0]);
  986. bResult = DoesFileExist(szPath);
  987. if (!bResult)
  988. {
  989. // Search one level of subdirectories starting with "W"
  990. WIN32_FIND_DATA Find;
  991. HANDLE hFind;
  992. MakePath(szPath, pszDirectory, "W*.*");
  993. if (INVALID_HANDLE_VALUE != (hFind = FindFirstFile(szPath, &Find)))
  994. {
  995. do
  996. {
  997. MakePath(szPath, pszDirectory, Find.cFileName);
  998. MakePath(szPath, szPath, m_rgCabFiles[0]);
  999. if (DoesFileExist(szPath))
  1000. {
  1001. bResult = TRUE;
  1002. break;
  1003. }
  1004. }
  1005. while (FindNextFile(hFind, &Find));
  1006. FindClose(hFind);
  1007. }
  1008. }
  1009. }
  1010. SetErrorMode(uPrevErrorMode);
  1011. return bResult;
  1012. }
  1013. BOOL CInfFileList::FindWindowsCD(HWND hwndParent)
  1014. {
  1015. TCHAR szPath[MAX_PATH];
  1016. // check the version of the Windows source path that we've saved
  1017. if (theApp.GetProfileString(c_szRegVal_PrevSourcePath, szPath, _countof(szPath)))
  1018. {
  1019. if (CheckWindowsCD(szPath))
  1020. {
  1021. // goto success;
  1022. }
  1023. }
  1024. else
  1025. {
  1026. // Check the current Windows source path
  1027. CRegistry reg;
  1028. if (reg.OpenKey(HKEY_LOCAL_MACHINE, c_szSetupKey) &&
  1029. reg.QueryStringValue(c_szRegVal_SourcePath, szPath, _countof(szPath)))
  1030. {
  1031. if (CheckWindowsCD(szPath))
  1032. {
  1033. goto success;
  1034. }
  1035. }
  1036. }
  1037. if (!PromptWindowsCD(hwndParent, szPath, szPath))
  1038. return FALSE;
  1039. success:
  1040. m_strWindowsCD = szPath;
  1041. return TRUE;
  1042. }
  1043. BOOL CInfFileList::PromptWindowsCD(HWND hwndParent, LPCTSTR pszInitialDir, LPTSTR pszResultDir)
  1044. {
  1045. LPCTSTR pszDiskName = (LPCTSTR)m_rgCabFiles.GetItemData(0);
  1046. CWinPathDlg dlg(pszInitialDir, pszDiskName, CWnd::FromHandle(hwndParent));
  1047. // Loop until user types a path to a valid CD, or clicks Cancel
  1048. for (;;)
  1049. {
  1050. if (IDOK != dlg.DoModal())
  1051. return FALSE;
  1052. if (CheckWindowsCD(dlg.m_strPath))
  1053. {
  1054. lstrcpy(pszResultDir, dlg.m_strPath);
  1055. return TRUE;
  1056. }
  1057. }
  1058. }
  1059. BOOL CInfFileList::CopySourceFiles(HWND hwndParent, LPCTSTR pszDestDir, PROGRESS_CALLBACK pfnProgress, LPVOID pvProgressParam)
  1060. {
  1061. int cFiles = m_rgCabFiles.GetSize() + m_rgSourceFiles.GetSize();
  1062. if (m_rgCabFiles.GetSize() > 0)
  1063. {
  1064. }
  1065. return TRUE;
  1066. }
  1067. #endif
  1068. //////////////////////////////////////////////////////////////////////////////
  1069. // Modify system INF
  1070. class CInfUpdater : public CInfParser
  1071. {
  1072. public:
  1073. CInfUpdater(LPCTSTR pszRequire = NULL, LPCTSTR pszExclude = NULL);
  1074. ~CInfUpdater();
  1075. enum eUpdateType {
  1076. update_NoVersionConflict = 0x01,
  1077. update_NoCopyFiles = 0x02,
  1078. update_RequireExclude = 0x04,
  1079. };
  1080. BOOL IsModified();
  1081. BOOL UpdateInfFile(LPCTSTR pszBackupLocation, UINT updateType);
  1082. LPCTSTR m_pszRequire;
  1083. LPCTSTR m_pszExclude;
  1084. protected:
  1085. void WriteToCurPos();
  1086. void Write(LPCTSTR pszString);
  1087. void Write(const void* pvData, UINT cbData);
  1088. BOOL OpenTempFile();
  1089. BOOL CloseTempFile();
  1090. BOOL RenameTempFile();
  1091. protected:
  1092. CString m_strTempFile;
  1093. HANDLE m_hTempFile;
  1094. BOOL m_bWriteSuccess;
  1095. DWORD m_iWritePos;
  1096. };
  1097. CInfUpdater::CInfUpdater(LPCTSTR pszRequire /*=NULL*/, LPCTSTR pszExclude /*=NULL*/)
  1098. {
  1099. m_hTempFile = INVALID_HANDLE_VALUE;
  1100. m_pszRequire = pszRequire;
  1101. m_pszExclude = pszExclude;
  1102. }
  1103. CInfUpdater::~CInfUpdater()
  1104. {
  1105. CloseTempFile();
  1106. if (!m_strTempFile.IsEmpty())
  1107. {
  1108. DeleteFile(m_strTempFile);
  1109. }
  1110. }
  1111. BOOL CInfUpdater::IsModified()
  1112. {
  1113. ASSERT(m_pszFileData != NULL);
  1114. return !memcmp(SZ_CHECK_MODIFIED_HEADER, m_pszFileData, _lengthof(SZ_CHECK_MODIFIED_HEADER));
  1115. }
  1116. BOOL CInfUpdater::UpdateInfFile(LPCTSTR pszBackupLocation, UINT updateType)
  1117. {
  1118. ASSERT(m_pszFileData != NULL);
  1119. if (m_pszFileData == NULL)
  1120. return FALSE;
  1121. Rewind();
  1122. if (!OpenTempFile())
  1123. return FALSE;
  1124. Write(SZ_MODIFIED_INF_HEADER);
  1125. Write(pszBackupLocation);
  1126. Write(SZ_MODIFIED_INF_HEADER2);
  1127. BOOL bInSection = FALSE;
  1128. for (;;)
  1129. {
  1130. // Skip whitespace
  1131. while (m_pszFileData[m_iPos] == ' ' || m_pszFileData[m_iPos] == '\t')
  1132. m_iPos++;
  1133. // Note: we're always at the beginning of a line here.
  1134. TCHAR ch = m_pszFileData[m_iPos];
  1135. if (ch == '\0')
  1136. break;
  1137. if (updateType & update_NoVersionConflict)
  1138. {
  1139. if (ch != '[' && ch != ';' && (UINT)ch > ' ')
  1140. {
  1141. // Look for lines w/ just a filename, and append ",,,32" to them
  1142. LPTSTR pszLine = m_pszFileData + m_iPos;
  1143. LPTSTR pchEnd = pszLine;
  1144. while (*pchEnd != '\0' && *pchEnd != '\r' && *pchEnd != '\n' &&
  1145. *pchEnd != ';' && *pchEnd != '=' && *pchEnd != ',')
  1146. {
  1147. pchEnd++;
  1148. }
  1149. // don't change lines that already have ,,,16 or something
  1150. // also don't change lines like CatalogFile=nettrans.cat
  1151. if (*pchEnd != ',' && *pchEnd != '=')
  1152. {
  1153. // Backup over whitespace
  1154. while (*(pchEnd-1) == ' ' || *(pchEnd-1) == '\t')
  1155. pchEnd--;
  1156. // Is it a filename? Note that some filenames will be missed here, but
  1157. // we really only care about .dll, .386, .vxd, and a few others
  1158. CString str(pszLine, (int)(pchEnd - pszLine));
  1159. if (lstrlen(FindExtension(str)) == 3)
  1160. {
  1161. m_iPos = (DWORD)(pchEnd - m_pszFileData);
  1162. WriteToCurPos();
  1163. Write(",,,32");
  1164. }
  1165. }
  1166. }
  1167. }
  1168. if (updateType & update_NoCopyFiles)
  1169. {
  1170. if (0 == memcmp(m_pszFileData + m_iPos, "CopyFiles", _lengthof("CopyFiles")))
  1171. {
  1172. // Comment out the reference to the CopyFiles section
  1173. WriteToCurPos();
  1174. Write(";hc ");
  1175. }
  1176. }
  1177. if (updateType & update_RequireExclude)
  1178. {
  1179. ASSERT(m_pszRequire != NULL);
  1180. ASSERT(m_pszExclude != NULL);
  1181. const TCHAR c_szRequireAll[] = _T("HKR,Ndi\\Compatibility,RequireAll,,\"");
  1182. const TCHAR c_szExcludeAll[] = _T("HKR,Ndi\\Compatibility,ExcludeAll,,\"");
  1183. LPCTSTR pszInsert = NULL;
  1184. if (0 == memcmp(m_pszFileData + m_iPos, c_szRequireAll, _lengthof(c_szRequireAll)))
  1185. pszInsert = m_pszRequire;
  1186. else if (0 == memcmp(m_pszFileData + m_iPos, c_szExcludeAll, _lengthof(c_szExcludeAll)))
  1187. pszInsert = m_pszExclude;
  1188. if (pszInsert != NULL)
  1189. {
  1190. // Insert the appropriate string between the double-quotes
  1191. ASSERT(_lengthof(c_szRequireAll) == _lengthof(c_szExcludeAll));
  1192. m_iPos += _lengthof(c_szRequireAll);
  1193. WriteToCurPos();
  1194. Write(pszInsert);
  1195. // Skip to closing quote
  1196. while (m_pszFileData[m_iPos] != '\"' && m_pszFileData[m_iPos] != '\0')
  1197. m_iPos += 1;
  1198. m_iWritePos = m_iPos;
  1199. }
  1200. }
  1201. GotoNextLine();
  1202. }
  1203. WriteToCurPos();
  1204. if (!CloseTempFile())
  1205. return FALSE;
  1206. if (!RenameTempFile())
  1207. return FALSE;
  1208. return TRUE;
  1209. }
  1210. void CInfUpdater::WriteToCurPos()
  1211. {
  1212. ASSERT(m_iPos >= m_iWritePos);
  1213. Write(m_pszFileData + m_iWritePos, m_iPos - m_iWritePos);
  1214. m_iWritePos = m_iPos;
  1215. }
  1216. void CInfUpdater::Write(LPCTSTR pszString)
  1217. {
  1218. Write(pszString, lstrlen(pszString));
  1219. }
  1220. void CInfUpdater::Write(const void* pvData, UINT cbData)
  1221. {
  1222. DWORD cbWritten;
  1223. if (!WriteFile(m_hTempFile, pvData, cbData, &cbWritten, NULL) || cbData != cbWritten)
  1224. m_bWriteSuccess = FALSE;
  1225. }
  1226. BOOL CInfUpdater::OpenTempFile()
  1227. {
  1228. TCHAR szDirectory[MAX_PATH];
  1229. GetFullInfPath(m_strFileName, szDirectory, _countof(szDirectory));
  1230. *(FindFileTitle(szDirectory)) = '\0';
  1231. LPTSTR pszBuf = m_strTempFile.GetBuffer(MAX_PATH);
  1232. GetTempFileName(szDirectory, "inf", 0, pszBuf);
  1233. m_strTempFile.ReleaseBuffer();
  1234. ASSERT(m_hTempFile == INVALID_HANDLE_VALUE);
  1235. m_hTempFile = CreateFile(m_strTempFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  1236. if (m_hTempFile == INVALID_HANDLE_VALUE)
  1237. return FALSE;
  1238. m_iWritePos = 0;
  1239. m_bWriteSuccess = TRUE;
  1240. return TRUE;
  1241. }
  1242. BOOL CInfUpdater::CloseTempFile()
  1243. {
  1244. if (m_hTempFile == INVALID_HANDLE_VALUE)
  1245. return FALSE;
  1246. BOOL bResult = CloseHandle(m_hTempFile);
  1247. m_hTempFile = INVALID_HANDLE_VALUE;
  1248. if (m_bWriteSuccess)
  1249. m_bWriteSuccess = bResult;
  1250. return m_bWriteSuccess;
  1251. }
  1252. BOOL CInfUpdater::RenameTempFile()
  1253. {
  1254. TCHAR szInfPath[MAX_PATH];
  1255. GetFullInfPath(m_strFileName, szInfPath, _countof(szInfPath));
  1256. if (!DeleteFile(szInfPath))
  1257. return FALSE;
  1258. if (!MoveFile(m_strTempFile, szInfPath))
  1259. return FALSE;
  1260. return TRUE;
  1261. }
  1262. // Modifies the given INF file to avoid the Version Conflict dialog.
  1263. // Backs up original version in same directory, e.g. "Net (HomeClick backup).inf"
  1264. BOOL ModifyInf_Helper(LPCTSTR pszInfFile, UINT updateType, LPCTSTR pszRequire = NULL, LPCTSTR pszExclude = NULL)
  1265. {
  1266. CInfUpdater infUpdate(pszRequire, pszExclude);
  1267. if (!infUpdate.LoadInfFile(pszInfFile))
  1268. return FALSE;
  1269. // Already updated?
  1270. if (infUpdate.IsModified())
  1271. return FALSE; // already modified, don't modify again
  1272. TCHAR szInfPath[MAX_PATH];
  1273. GetFullInfPath(pszInfFile, szInfPath, _countof(szInfPath));
  1274. TCHAR szBackup[MAX_PATH];
  1275. lstrcpy(szBackup, szInfPath);
  1276. lstrcpy(FindExtension(szBackup)-1, SZ_INF_BACKUP_SUFFIX);
  1277. FILETIME ftSrcCreated;
  1278. FILETIME ftSrcModified;
  1279. HANDLE hFile = CreateFile(szInfPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  1280. GetFileTime(hFile, &ftSrcCreated, NULL, &ftSrcModified);
  1281. CloseHandle(hFile);
  1282. if (!CopyFile(szInfPath, szBackup, FALSE))
  1283. return FALSE;
  1284. BOOL bResult = infUpdate.UpdateInfFile(szBackup, updateType);
  1285. hFile = CreateFile(szInfPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  1286. DWORD dwFileSize = GetFileSize(hFile, NULL);
  1287. SetFileTime(hFile, &ftSrcCreated, NULL, &ftSrcModified);
  1288. CloseHandle(hFile);
  1289. return bResult;
  1290. }
  1291. BOOL ModifyInf_NoVersionConflict(LPCTSTR pszInfFile)
  1292. {
  1293. return ModifyInf_Helper(pszInfFile, CInfUpdater::update_NoVersionConflict);
  1294. }
  1295. BOOL ModifyInf_NoCopyFiles(LPCTSTR pszInfFile)
  1296. {
  1297. return ModifyInf_Helper(pszInfFile, CInfUpdater::update_NoCopyFiles);
  1298. }
  1299. BOOL ModifyInf_RequireExclude(LPCTSTR pszInfFile, LPCTSTR pszRequire, LPCTSTR pszExclude)
  1300. {
  1301. return ModifyInf_Helper(pszInfFile, CInfUpdater::update_RequireExclude, pszRequire, pszExclude);
  1302. }
  1303. BOOL ModifyInf_NoCopyAndRequireExclude(LPCTSTR pszInfFile, LPCTSTR pszRequire, LPCTSTR pszExclude)
  1304. {
  1305. return ModifyInf_Helper(pszInfFile,
  1306. CInfUpdater::update_NoCopyFiles | CInfUpdater::update_RequireExclude,
  1307. pszRequire, pszExclude);
  1308. }
  1309. BOOL RestoreInfBackup(LPCTSTR pszInfFile)
  1310. {
  1311. TCHAR szInfPath[MAX_PATH];
  1312. GetFullInfPath(pszInfFile, szInfPath, _countof(szInfPath));
  1313. TCHAR szBackup[MAX_PATH];
  1314. lstrcpy(szBackup, szInfPath);
  1315. lstrcpy(FindExtension(szBackup)-1, SZ_INF_BACKUP_SUFFIX);
  1316. /*
  1317. FILETIME ftSrcCreated;
  1318. FILETIME ftSrcModified;
  1319. HANDLE hFile = CreateFile(szInfPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  1320. GetFileTime(hFile, &ftSrcCreated, NULL, &ftSrcModified);
  1321. CloseHandle(hFile);
  1322. */
  1323. if (!DoesFileExist(szBackup))
  1324. return FALSE;
  1325. if (!DeleteFile(szInfPath))
  1326. return FALSE;
  1327. if (!MoveFile(szBackup, szInfPath))
  1328. return FALSE;
  1329. /*
  1330. hFile = CreateFile(szInfPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  1331. GetFileTime(hFile, &ftSrcCreated, NULL, &ftSrcModified);
  1332. CloseHandle(hFile);
  1333. */
  1334. return TRUE;
  1335. }
  1336. BOOL CheckInfSectionInstallation(LPCTSTR pszInfFile, LPCTSTR pszInfSection)
  1337. {
  1338. CInfParser parser;
  1339. if (!parser.LoadInfFile(pszInfFile))
  1340. {
  1341. ASSERT(FALSE);
  1342. return TRUE; // all known files are present even though it's an error
  1343. }
  1344. CDriverFileArray rgFiles;
  1345. if (!parser.GetFilesFromInstallSection(pszInfSection, rgFiles))
  1346. {
  1347. ASSERT(FALSE);
  1348. return TRUE; // all known files are present even though it's an error
  1349. }
  1350. TCHAR szPath[MAX_PATH];
  1351. int cFiles = rgFiles.GetSize();
  1352. for (int iFile = 0; iFile < cFiles; iFile++)
  1353. {
  1354. int cch = GetDriverTargetPath(rgFiles[iFile], szPath);
  1355. if (cch != 0)
  1356. {
  1357. lstrcpy(szPath + cch, rgFiles[iFile]->szFileTitle);
  1358. if (!DoesFileExist(szPath))
  1359. return FALSE;
  1360. }
  1361. }
  1362. return TRUE;
  1363. }
  1364. BOOL InstallInfSection(LPCTSTR pszInfFile, LPCTSTR pszInfSection, BOOL bWait)
  1365. {
  1366. // Make a modified copy of the INF
  1367. BOOL bModifiedInf = ModifyInf_NoVersionConflict(pszInfFile);
  1368. TCHAR szPath[MAX_PATH + 200];
  1369. int cch = GetWindowsDirectory(szPath, _countof(szPath));
  1370. #ifdef UNICODE
  1371. wnsprintf(szPath + cch, ARRAYSIZE(szPath) - cch, L"\\RunDll.exe setupx.dll,InstallHinfSection %s 0 %s", pszInfSection, pszInfFile);
  1372. #else
  1373. wsprintf(szPath + cch, "\\RunDll.exe setupx.dll,InstallHinfSection %s 0 %s", pszInfSection, pszInfFile);
  1374. #endif
  1375. STARTUPINFO si;
  1376. ZeroMemory(&si, sizeof(si));
  1377. si.cb = sizeof(si);
  1378. PROCESS_INFORMATION pi;
  1379. BOOL bResult = CreateProcess(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
  1380. if (bResult)
  1381. {
  1382. if (bWait)
  1383. {
  1384. WaitForSingleObject(pi.hProcess, INFINITE);
  1385. }
  1386. CloseHandle(pi.hProcess);
  1387. CloseHandle(pi.hThread);
  1388. }
  1389. if (bModifiedInf)
  1390. {
  1391. RestoreInfBackup(pszInfFile);
  1392. }
  1393. return bResult;
  1394. }