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.

1879 lines
51 KiB

  1. // infgen.cpp : Defines the initialization routines for the DLL.
  2. //
  3. #include <windows.h>
  4. #include <stdio.h>
  5. #include <mbctype.h>
  6. #include <Shlwapi.h>
  7. #include "infgen.h"
  8. #include "message.h"
  9. #define DELETE_EMPTY 1
  10. #define MAX_LINE ( MAX_PATH * 2 )
  11. struct _SectionEntry
  12. {
  13. TCHAR *szLine;
  14. DWORD cRef;
  15. };
  16. // Track entries throughout the INF related to a section
  17. typedef struct _AssociatedEntries
  18. {
  19. PSECTIONENTRY pse;
  20. _AssociatedEntries *pNext;
  21. } ASSOCIATEDENTRIES, *PASSOCIATEDENTRIES;
  22. struct _SectionList
  23. {
  24. TCHAR szSectionName[ MAX_PATH ];
  25. PSECTIONENTRY pseSectionEntries;
  26. PASSOCIATEDENTRIES pAssociatedEntries;
  27. DWORD dwSectionEntries;
  28. DWORD cRef;
  29. struct _SectionList *Next;
  30. };
  31. struct _SectionAssociationList
  32. {
  33. _SectionList *pSection;
  34. _SectionAssociationList *pNext;
  35. };
  36. extern HINSTANCE g_hMyInstance;
  37. CUpdateInf::CUpdateInf(
  38. void
  39. ) : m_bGenInitCalled(FALSE), m_dwInfGenError(0),
  40. m_sectionList(NULL), m_bActiveDB(FALSE), m_hInf(INVALID_HANDLE_VALUE),
  41. m_pTypeInfo(NULL), m_cRef(1)
  42. {
  43. memset( m_rgNameHash, 0, sizeof( m_rgNameHash ) );
  44. // Default DB connection
  45. // WINSEQFE default DB with windows auth
  46. _tcscpy( m_szDataServer, _T("WINSEQFE") );
  47. m_szDatabase[0] = _T('\0');
  48. m_szUserName[0] = _T('\0');
  49. }
  50. CUpdateInf::~CUpdateInf(
  51. void
  52. )
  53. {
  54. if ( m_pTypeInfo ) {
  55. m_pTypeInfo->Release();
  56. m_pTypeInfo = NULL;
  57. }
  58. Cleanup();
  59. }
  60. //
  61. // IUnknown
  62. //
  63. ULONG
  64. CUpdateInf::AddRef( void )
  65. {
  66. return ++m_cRef;
  67. }
  68. ULONG
  69. CUpdateInf::Release( void )
  70. {
  71. if ( 0L == --m_cRef )
  72. {
  73. delete this;
  74. return 0;
  75. }
  76. return m_cRef;
  77. }
  78. HRESULT
  79. CUpdateInf::QueryInterface( REFIID riid, void **ppv )
  80. {
  81. if ( NULL == ppv )
  82. return E_POINTER;
  83. *ppv = NULL;
  84. if ( IID_IUnknown == riid )
  85. *ppv = (IUnknown *)this;
  86. else if ( IID_IDispatch == riid )
  87. *ppv = (IDispatch *)this;
  88. else if ( IID_IUpdateInf == riid )
  89. *ppv = (IUpdateInf *)this;
  90. else
  91. return E_NOINTERFACE;
  92. AddRef();
  93. return S_OK;
  94. }
  95. //
  96. // IDispatch
  97. //
  98. HRESULT
  99. CUpdateInf::GetTypeInfoCount( UINT *pCountTypeInfo )
  100. {
  101. *pCountTypeInfo = 1;
  102. return S_OK;
  103. }
  104. HRESULT
  105. CUpdateInf::GetTypeInfo( UINT iTypeInfo,
  106. LCID lcid,
  107. ITypeInfo **ppTypeInfo )
  108. {
  109. *ppTypeInfo = NULL;
  110. if ( 0 != iTypeInfo )
  111. return DISP_E_BADINDEX;
  112. m_pTypeInfo->AddRef();
  113. *ppTypeInfo = m_pTypeInfo;
  114. return S_OK;
  115. }
  116. HRESULT
  117. CUpdateInf::GetIDsOfNames( REFIID riid,
  118. LPOLESTR *aszNames,
  119. UINT cNames,
  120. LCID lcid,
  121. DISPID *aDispIDs )
  122. {
  123. if ( IID_NULL != riid )
  124. return DISP_E_UNKNOWNINTERFACE;
  125. return DispGetIDsOfNames( m_pTypeInfo,
  126. aszNames,
  127. cNames,
  128. aDispIDs );
  129. }
  130. HRESULT
  131. CUpdateInf::Invoke( DISPID dispIdMember,
  132. REFIID riid,
  133. LCID lcid,
  134. WORD wFlags,
  135. DISPPARAMS *pDispParams,
  136. VARIANT *pVarResult,
  137. EXCEPINFO *pExcepInfo,
  138. UINT *puArgErr )
  139. {
  140. if ( IID_NULL != riid )
  141. return DISP_E_UNKNOWNINTERFACE;
  142. return DispInvoke( this,
  143. m_pTypeInfo,
  144. dispIdMember,
  145. wFlags,
  146. pDispParams,
  147. pVarResult,
  148. pExcepInfo,
  149. puArgErr );
  150. }
  151. //
  152. // Initialization function so we can use type-library based
  153. // functions to handle the IDispatch calls
  154. //
  155. BOOL
  156. CUpdateInf::Init(
  157. void
  158. )
  159. {
  160. HRESULT hr;
  161. ITypeLib *pTypeLib = NULL;
  162. hr = LoadRegTypeLib( LIBID_InfGeneratorLib, (1), (0), LANG_NEUTRAL, &pTypeLib );
  163. if ( FAILED(hr) )
  164. {
  165. return FALSE;
  166. }
  167. hr = pTypeLib->GetTypeInfoOfGuid( IID_IUpdateInf, &m_pTypeInfo );
  168. if ( FAILED(hr) )
  169. {
  170. return FALSE;
  171. }
  172. // Cleanup
  173. pTypeLib->Release();
  174. return TRUE;
  175. }
  176. //
  177. // IUpdateInf
  178. //
  179. HRESULT
  180. CUpdateInf::InsertFile(
  181. BSTR bstrFileName
  182. )
  183. {
  184. HRESULT hr;
  185. BOOL bRet = FALSE;
  186. DWORD dwRecordCount;
  187. LPTSTR lpszSQL;
  188. CSimpleDBResults *prs;
  189. if ( !m_bActiveDB )
  190. {
  191. m_dwInfGenError = FAIL_NO_DATABASE;
  192. return E_FAIL;
  193. }
  194. if( NULL == bstrFileName ) {
  195. m_dwInfGenError = FAIL_INVALIDPARAM;
  196. return E_FAIL;
  197. }
  198. if( m_bGenInitCalled == FALSE ) {
  199. m_dwInfGenError = FAIL_NOINITGENCALL;
  200. return E_FAIL;
  201. }
  202. lpszSQL = new TCHAR [1000];
  203. if( NULL == lpszSQL ) {
  204. return E_OUTOFMEMORY;
  205. }
  206. #ifndef UNICODE
  207. char *szFileName;
  208. size_t lenFileName = SysStringLen(bstrFileName) + 1;
  209. szFileName = new char[lenFileName];
  210. if ( NULL == szFileName )
  211. {
  212. m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
  213. return E_FAIL;
  214. }
  215. if ( 0 == WideCharToMultiByte( CP_ACP,
  216. 0L,
  217. bstrFileName,
  218. lenFileName,
  219. szFileName,
  220. lenFileName,
  221. NULL,
  222. NULL ) ) {
  223. m_dwInfGenError = GetLastError();
  224. return E_FAIL;
  225. }
  226. #else
  227. wchar_t *szFileName = bstrFileName;
  228. #endif
  229. _stprintf( lpszSQL,
  230. _T("Select DISTINCT Section,Entry from Ref_SrcFileLocations,Ref_DefaultInstallerInf where Ref_SrcFileLocations.FileName = '%s' AND Ref_SrcFileLocations.FileID = Ref_DefaultInstallerInf.FileID"), szFileName );
  231. //sprintf( lpszSQL,
  232. // "Select * from Ref_SrcFileLocations" );
  233. if( SUCCEEDED(m_pdb->Execute( lpszSQL, &prs )) ) {
  234. if ( S_OK == (hr = prs->NextRow()) )
  235. {
  236. bRet = TRUE;
  237. do {
  238. // an entry can consist of one or more null-terminated
  239. // strings, so we clear the entry buffer here
  240. memset( m_textBuffer2, 0, sizeof(m_textBuffer2) );
  241. if ( FAILED(prs->GetFieldValue( _T("Section"), m_textBuffer, BUFFER_SIZE )) ||
  242. FAILED(prs->GetFieldValue( _T("Entry"), m_textBuffer2, BUFFER_SIZE )) ) {
  243. m_dwInfGenError = FAIL_RECORDSET;
  244. bRet = FALSE;
  245. break;
  246. }
  247. if ( !WritePrivateProfileSection( m_textBuffer, m_textBuffer2, m_szFilledInxFile ) ) {
  248. m_dwInfGenError = GetLastError();
  249. bRet = FALSE;
  250. break;
  251. }
  252. } while( S_OK == (hr = prs->NextRow()) );
  253. if ( FAILED(hr) )
  254. {
  255. m_dwInfGenError = hr;
  256. bRet = FALSE;
  257. }
  258. if ( bRet ) {
  259. // Write an entry in the [SourceDiskFiles] section for this file
  260. if ( !WritePrivateProfileString( _T("SourceDisksFiles"), szFileName, _T("1"), m_szFilledInxFile ) ) {
  261. m_dwInfGenError = GetLastError();
  262. bRet = FALSE;
  263. }
  264. }
  265. } else if ( SUCCEEDED(hr) ) {
  266. m_dwInfGenError = FAIL_NOSECTION;
  267. }
  268. else
  269. {
  270. m_dwInfGenError = hr;
  271. }
  272. delete prs;
  273. } else {
  274. m_dwInfGenError = FAIL_RECORDSET;
  275. }
  276. #ifndef UNICODE
  277. delete [] szFileName;
  278. #endif
  279. delete [] lpszSQL;
  280. if ( bRet ) {
  281. return S_OK;
  282. }
  283. else {
  284. return E_FAIL;
  285. }
  286. }
  287. HRESULT
  288. CUpdateInf::WriteSectionData(
  289. BSTR bstrSection,
  290. BSTR bstrValue
  291. )
  292. {
  293. BOOL bRet = TRUE;
  294. size_t lenSection = SysStringLen(bstrSection) + 1,
  295. lenValue = SysStringLen(bstrValue) + 1;
  296. if( m_bGenInitCalled == FALSE ) {
  297. m_dwInfGenError = FAIL_NOINITGENCALL;
  298. return E_FAIL;
  299. }
  300. if ( lenSection >= BUFFER_SIZE ||
  301. lenValue + 1 >= BUFFER_SIZE )
  302. {
  303. m_dwInfGenError = FAIL_MAX_BUFFER;
  304. return E_FAIL;
  305. }
  306. #ifndef UNICODE
  307. if ( 0 == WideCharToMultiByte( CP_ACP,
  308. 0L,
  309. bstrSection,
  310. lenSection,
  311. m_textBuffer,
  312. BUFFER_SIZE,
  313. NULL,
  314. NULL ) ) {
  315. m_dwInfGenError = GetLastError();
  316. return E_FAIL;
  317. }
  318. if ( 0 == WideCharToMultiByte( CP_ACP,
  319. 0L,
  320. bstrValue,
  321. lenValue,
  322. m_textBuffer2,
  323. BUFFER_SIZE,
  324. NULL,
  325. NULL ) ) {
  326. m_dwInfGenError = GetLastError();
  327. return E_FAIL;
  328. }
  329. #else
  330. memcpy( m_textBuffer, bstrSection, sizeof(wchar_t) * lenSection );
  331. memcpy( m_textBuffer2, bstrValue, sizeof(wchar_t) * lenValue );
  332. #endif
  333. m_textBuffer2[lenValue] = '\0'; // end with a double NULL
  334. if ( !WritePrivateProfileSection( m_textBuffer, m_textBuffer2, m_szFilledInxFile ) ) {
  335. m_dwInfGenError = GetLastError();
  336. bRet = FALSE;
  337. }
  338. if (bRet) {
  339. return S_OK;
  340. }
  341. else {
  342. return E_FAIL;
  343. }
  344. }
  345. HRESULT
  346. CUpdateInf::SetConfigurationField(
  347. BSTR bstrFieldName,
  348. BSTR bstrValue
  349. )
  350. {
  351. BOOL bRet = TRUE;
  352. size_t lenFieldName = SysStringLen(bstrFieldName) + 1,
  353. lenValue = SysStringLen(bstrValue) + 1;
  354. if( m_bGenInitCalled == FALSE ) {
  355. m_dwInfGenError = FAIL_NOINITGENCALL;
  356. return E_FAIL;
  357. }
  358. if ( lenFieldName >= BUFFER_SIZE ||
  359. lenValue >= BUFFER_SIZE )
  360. {
  361. m_dwInfGenError = FAIL_MAX_BUFFER;
  362. return E_FAIL;
  363. }
  364. #ifndef UNICODE
  365. if ( 0 == WideCharToMultiByte( CP_ACP,
  366. 0L,
  367. bstrFieldName,
  368. lenFieldName,
  369. m_textBuffer,
  370. BUFFER_SIZE,
  371. NULL,
  372. NULL ) ) {
  373. m_dwInfGenError = GetLastError();
  374. return E_FAIL;
  375. }
  376. if ( 0 == WideCharToMultiByte( CP_ACP,
  377. 0L,
  378. bstrValue,
  379. lenValue,
  380. m_textBuffer2,
  381. BUFFER_SIZE,
  382. NULL,
  383. NULL ) ) {
  384. m_dwInfGenError = GetLastError();
  385. return E_FAIL;
  386. }
  387. #else
  388. memcpy( m_textBuffer, bstrFieldName, sizeof(wchar_t) * lenFieldName );
  389. memcpy( m_textBuffer2, bstrValue, sizeof(wchar_t) * lenValue );
  390. #endif
  391. if ( !WritePrivateProfileString( _T("Configuration"), m_textBuffer, m_textBuffer2, m_szFilledInxFile ) ) {
  392. m_dwInfGenError = GetLastError();
  393. bRet = FALSE;
  394. }
  395. if (bRet) {
  396. return S_OK;
  397. }
  398. else {
  399. return E_FAIL;
  400. }
  401. }
  402. HRESULT
  403. CUpdateInf::SetVersionField(
  404. BSTR bstrFieldName,
  405. BSTR bstrValue
  406. )
  407. {
  408. BOOL bRet = TRUE;
  409. size_t lenFieldName = SysStringLen(bstrFieldName) + 1,
  410. lenValue = SysStringLen(bstrValue) + 1;
  411. if( m_bGenInitCalled == FALSE ) {
  412. m_dwInfGenError = FAIL_NOINITGENCALL;
  413. return E_FAIL;
  414. }
  415. if ( lenFieldName >= BUFFER_SIZE ||
  416. lenValue >= BUFFER_SIZE )
  417. {
  418. m_dwInfGenError = FAIL_MAX_BUFFER;
  419. return E_FAIL;
  420. }
  421. #ifndef UNICODE
  422. if ( 0 == WideCharToMultiByte( CP_ACP,
  423. 0L,
  424. bstrFieldName,
  425. lenFieldName,
  426. m_textBuffer,
  427. BUFFER_SIZE,
  428. NULL,
  429. NULL ) ) {
  430. m_dwInfGenError = GetLastError();
  431. return E_FAIL;
  432. }
  433. if ( 0 == WideCharToMultiByte( CP_ACP,
  434. 0L,
  435. bstrValue,
  436. lenValue,
  437. m_textBuffer2,
  438. BUFFER_SIZE,
  439. NULL,
  440. NULL ) ) {
  441. m_dwInfGenError = GetLastError();
  442. return E_FAIL;
  443. }
  444. #else
  445. memcpy( m_textBuffer, bstrFieldName, sizeof(wchar_t) * lenFieldName );
  446. memcpy( m_textBuffer2, bstrValue, sizeof(wchar_t) * lenValue );
  447. #endif
  448. if ( !WritePrivateProfileString( _T("Version"), m_textBuffer, m_textBuffer2, m_szFilledInxFile ) ) {
  449. m_dwInfGenError = GetLastError();
  450. bRet = FALSE;
  451. }
  452. if (bRet) {
  453. return S_OK;
  454. }
  455. else {
  456. return E_FAIL;
  457. }
  458. }
  459. HRESULT
  460. CUpdateInf::AddSourceDisksFilesEntry(
  461. BSTR bstrFile,
  462. BSTR bstrTag
  463. )
  464. {
  465. BOOL bRet = TRUE;
  466. size_t lenFile = SysStringLen(bstrFile) + 1,
  467. lenTag = SysStringLen(bstrTag) + 1;
  468. if( m_bGenInitCalled == FALSE ) {
  469. m_dwInfGenError = FAIL_NOINITGENCALL;
  470. return E_FAIL;
  471. }
  472. if ( lenFile >= BUFFER_SIZE ||
  473. lenTag >= BUFFER_SIZE )
  474. {
  475. m_dwInfGenError = FAIL_MAX_BUFFER;
  476. return E_FAIL;
  477. }
  478. #ifndef UNICODE
  479. if ( 0 == WideCharToMultiByte( CP_ACP,
  480. 0L,
  481. bstrFile,
  482. lenFile,
  483. m_textBuffer,
  484. BUFFER_SIZE,
  485. NULL,
  486. NULL ) ) {
  487. m_dwInfGenError = GetLastError();
  488. return E_FAIL;
  489. }
  490. if ( 0 == WideCharToMultiByte( CP_ACP,
  491. 0L,
  492. bstrTag,
  493. lenTag,
  494. m_textBuffer2,
  495. BUFFER_SIZE,
  496. NULL,
  497. NULL ) ) {
  498. m_dwInfGenError = GetLastError();
  499. return E_FAIL;
  500. }
  501. #else
  502. memcpy( m_textBuffer, bstrFile, sizeof(wchar_t) * lenFile );
  503. memcpy( m_textBuffer2, bstrTag, sizeof(wchar_t) * lenTag );
  504. #endif
  505. if ( !WritePrivateProfileString( _T("SourceDisksFiles"), m_textBuffer, m_textBuffer2, m_szFilledInxFile ) ) {
  506. m_dwInfGenError = GetLastError();
  507. bRet = FALSE;
  508. }
  509. if (bRet) {
  510. return S_OK;
  511. }
  512. else {
  513. return E_FAIL;
  514. }
  515. }
  516. HRESULT
  517. CUpdateInf::AddEquality(
  518. BSTR bstrSect,
  519. BSTR bstrLVal,
  520. BSTR bstrRVal
  521. )
  522. {
  523. BOOL bRet = TRUE;
  524. size_t lenSect = SysStringLen(bstrSect) + 1,
  525. lenLVal = SysStringLen(bstrLVal) + 1,
  526. lenRVal = SysStringLen(bstrRVal) + 1;
  527. if( m_bGenInitCalled == FALSE ) {
  528. m_dwInfGenError = FAIL_NOINITGENCALL;
  529. return E_FAIL;
  530. }
  531. if ( lenLVal >= BUFFER_SIZE ||
  532. lenRVal >= BUFFER_SIZE ||
  533. lenSect >= BUFFER_SIZE )
  534. {
  535. m_dwInfGenError = FAIL_MAX_BUFFER;
  536. return E_FAIL;
  537. }
  538. #ifndef UNICODE
  539. if ( 0 == WideCharToMultiByte( CP_ACP,
  540. 0L,
  541. bstrLVal,
  542. lenLVal,
  543. m_textBuffer,
  544. BUFFER_SIZE,
  545. NULL,
  546. NULL ) ) {
  547. m_dwInfGenError = GetLastError();
  548. return E_FAIL;
  549. }
  550. if ( 0 == WideCharToMultiByte( CP_ACP,
  551. 0L,
  552. bstrRVal,
  553. lenRVal,
  554. m_textBuffer2,
  555. BUFFER_SIZE,
  556. NULL,
  557. NULL ) ) {
  558. m_dwInfGenError = GetLastError();
  559. return E_FAIL;
  560. }
  561. if ( 0 == WideCharToMultiByte( CP_ACP,
  562. 0L,
  563. bstrSect,
  564. lenSect,
  565. m_textBuffer3,
  566. BUFFER_SIZE,
  567. NULL,
  568. NULL ) ) {
  569. m_dwInfGenError = GetLastError();
  570. return E_FAIL;
  571. }
  572. #else
  573. memcpy( m_textBuffer, bstrLVal, sizeof(wchar_t) * lenLVal );
  574. memcpy( m_textBuffer2, bstrRVal, sizeof(wchar_t) * lenRVal );
  575. memcpy( m_textBuffer3, bstrSect, sizeof(wchar_t) * lenSect );
  576. #endif
  577. if ( !WritePrivateProfileString( m_textBuffer3, m_textBuffer, m_textBuffer2, m_szFilledInxFile ) ) {
  578. m_dwInfGenError = GetLastError();
  579. bRet = FALSE;
  580. }
  581. if (bRet) {
  582. return S_OK;
  583. }
  584. else {
  585. return E_FAIL;
  586. }
  587. }
  588. void
  589. CUpdateInf::Cleanup(
  590. void
  591. )
  592. {
  593. PSECTION psRef = m_sectionList;
  594. OutputDebugString( _T("Freeing m_sectionList ...\n") );
  595. while( psRef ) {
  596. PSECTION psRef1 = psRef;
  597. PSECTIONENTRY pse = psRef1->pseSectionEntries;
  598. PASSOCIATEDENTRIES pAssoc = psRef1->pAssociatedEntries;
  599. psRef = psRef->Next;
  600. if ( NULL != pse ) {
  601. for ( DWORD i = 0; i < psRef1->dwSectionEntries; i++ ) {
  602. if ( pse[i].szLine ) delete [] pse[i].szLine;
  603. }
  604. delete [] pse;
  605. }
  606. while ( pAssoc ) {
  607. PASSOCIATEDENTRIES pDel = pAssoc;
  608. pAssoc = pAssoc->pNext;
  609. delete pDel;
  610. }
  611. delete psRef1;
  612. }
  613. m_sectionList = NULL;
  614. OutputDebugString( _T("Freeing m_rgNameHash ...\n") );
  615. for ( short i = 0; i < HASH_BUCKETS; i++ ) {
  616. if ( m_rgNameHash[i] ) {
  617. PSECTIONASSOCIATIONLIST pAssocList = m_rgNameHash[i];
  618. while ( pAssocList ) {
  619. PSECTIONASSOCIATIONLIST pDel = pAssocList;
  620. pAssocList = pAssocList->pNext;
  621. delete pDel;
  622. }
  623. m_rgNameHash[i] = NULL;
  624. }
  625. }
  626. OutputDebugString( _T("Cleanup finished\n") );
  627. }
  628. HRESULT
  629. CUpdateInf::CloseGen(
  630. BOOL bTrimInf
  631. )
  632. {
  633. BOOL bRet = TRUE;
  634. if( m_bGenInitCalled == FALSE ) {
  635. m_dwInfGenError = FAIL_NOINITGENCALL;
  636. return E_FAIL;
  637. }
  638. if ( bTrimInf ) {
  639. if ( !TrimInf( m_szFilledInxFile, m_szOutFile ) ) {
  640. bRet = FALSE;
  641. }
  642. }
  643. else {
  644. if ( !CopyFile( m_szFilledInxFile, m_szOutFile, FALSE ) ) {
  645. m_dwInfGenError = GetLastError();
  646. bRet = FALSE;
  647. }
  648. }
  649. if ( !DeleteFile( m_szFilledInxFile ) ) {
  650. m_dwInfGenError = GetLastError();
  651. return S_FALSE;
  652. }
  653. Cleanup();
  654. m_bGenInitCalled = FALSE;
  655. if ( bRet ) return S_OK;
  656. else return E_FAIL;
  657. }
  658. HRESULT
  659. CUpdateInf::SetDB(
  660. BSTR bstrServer,
  661. BSTR bstrDB,
  662. BSTR bstrUser,
  663. BSTR bstrPassword
  664. )
  665. {
  666. size_t lenServer = SysStringLen(bstrServer) + 1,
  667. lenDB = SysStringLen(bstrDB) + 1,
  668. lenUser = SysStringLen(bstrUser) + 1,
  669. lenPassword = SysStringLen(bstrPassword) + 1;
  670. if ( lenServer >= MAX_PATH ||
  671. lenDB >= MAX_PATH ||
  672. lenUser >= MAX_PATH ||
  673. lenPassword >= MAX_PATH )
  674. {
  675. m_dwInfGenError = FAIL_MAX_BUFFER;
  676. return E_FAIL;
  677. }
  678. // Server
  679. if ( lenServer > 1 )
  680. {
  681. #ifndef UNICODE
  682. if ( 0 == WideCharToMultiByte( CP_ACP,
  683. 0L,
  684. bstrServer,
  685. lenServer,
  686. m_szDataServer,
  687. MAX_PATH,
  688. NULL,
  689. NULL ) ) {
  690. m_dwInfGenError = GetLastError();
  691. return E_FAIL;
  692. }
  693. #else
  694. memcpy( m_szDataServer, bstrServer, sizeof(wchar_t) * lenServer );
  695. #endif
  696. }
  697. else
  698. {
  699. m_szDataServer[0] = _T('\0');
  700. }
  701. // Default DB
  702. if ( lenDB > 1 )
  703. {
  704. #ifndef UNICODE
  705. if ( 0 == WideCharToMultiByte( CP_ACP,
  706. 0L,
  707. bstrDB,
  708. lenDB,
  709. m_szDatabase,
  710. MAX_PATH,
  711. NULL,
  712. NULL ) ) {
  713. m_dwInfGenError = GetLastError();
  714. return E_FAIL;
  715. }
  716. #else
  717. memcpy( m_szDatabase, bstrDB, sizeof(wchar_t) * lenDB );
  718. #endif
  719. }
  720. else
  721. {
  722. m_szDatabase[0] = _T('\0');
  723. }
  724. // Username
  725. if ( lenUser > 1 )
  726. {
  727. #ifndef UNICODE
  728. if ( 0 == WideCharToMultiByte( CP_ACP,
  729. 0L,
  730. bstrUser,
  731. lenUser,
  732. m_szUserName,
  733. MAX_PATH,
  734. NULL,
  735. NULL ) ) {
  736. m_dwInfGenError = GetLastError();
  737. return E_FAIL;
  738. }
  739. #else
  740. memcpy( m_szUserName, bstrUser, sizeof(wchar_t) * lenUser );
  741. #endif
  742. }
  743. else
  744. {
  745. m_szUserName[0] = _T('\0');
  746. }
  747. // Password
  748. if ( lenPassword > 1 )
  749. {
  750. #ifndef UNICODE
  751. if ( 0 == WideCharToMultiByte( CP_ACP,
  752. 0L,
  753. bstrPassword,
  754. lenPassword,
  755. m_szPassword,
  756. MAX_PATH,
  757. NULL,
  758. NULL ) ) {
  759. m_dwInfGenError = GetLastError();
  760. return E_FAIL;
  761. }
  762. #else
  763. memcpy( m_szPassword, bstrPassword, sizeof(wchar_t) * lenPassword );
  764. #endif
  765. }
  766. else
  767. {
  768. m_szPassword[0] = _T('\0');
  769. }
  770. return S_OK;
  771. }
  772. HRESULT
  773. CUpdateInf::InitGen(
  774. BSTR bstrInxFile,
  775. BSTR bstrInfFile
  776. )
  777. {
  778. size_t lenInxFile = SysStringLen(bstrInxFile) + 1,
  779. lenInfFile = SysStringLen(bstrInfFile) + 1;
  780. if( lenInxFile <= 1 ||
  781. lenInfFile <= 1 )
  782. {
  783. m_dwInfGenError = FAIL_INVALIDPARAM;
  784. return E_FAIL;
  785. }
  786. else if ( lenInxFile >= MAX_PATH ||
  787. lenInfFile + 2 >= MAX_PATH ) // might need room to add '.\\'
  788. {
  789. m_dwInfGenError = FAIL_MAX_BUFFER;
  790. return E_FAIL;
  791. }
  792. #ifndef UNICODE
  793. char *szInxFile,
  794. *szInfFile;
  795. szInxFile = new char[lenInxFile];
  796. szInfFile = new char[lenInfFile];
  797. if ( NULL == szInxFile ||
  798. NULL == szInfFile )
  799. {
  800. m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
  801. return E_FAIL;
  802. }
  803. if ( 0 == WideCharToMultiByte( CP_ACP,
  804. 0L,
  805. bstrInxFile,
  806. lenInxFile,
  807. szInxFile,
  808. lenInxFile,
  809. NULL,
  810. NULL ) ) {
  811. m_dwInfGenError = GetLastError();
  812. return E_FAIL;
  813. }
  814. if ( 0 == WideCharToMultiByte( CP_ACP,
  815. 0L,
  816. bstrInfFile,
  817. lenInfFile,
  818. szInfFile,
  819. lenInfFile,
  820. NULL,
  821. NULL ) ) {
  822. delete [] szInxFile;
  823. m_dwInfGenError = GetLastError();
  824. return E_FAIL;
  825. }
  826. #else
  827. wchar_t *szInxFile = bstrInxFile,
  828. *szInfFile = bstrInfFile;
  829. #endif
  830. _tcscpy( m_szInxFile, szInxFile );
  831. _tcscpy( m_szOutFile,szInfFile );
  832. // The Setup* function will infer a path given only a
  833. // file, so we ensure that a path is always specified
  834. _stprintf( m_szFilledInxFile, _T("%s%s"), (!_tcschr( szInfFile, _T('\\') )?_T(".\\"):_T("")), szInfFile );
  835. _tcscpy( m_szFilledInxFile+_tcslen(m_szFilledInxFile)-3, _T("TMP") );
  836. if( CopyFile( m_szInxFile, m_szFilledInxFile, FALSE ) ) {
  837. SetFileAttributes( m_szFilledInxFile, FILE_ATTRIBUTE_NORMAL );
  838. #ifndef UNICODE
  839. delete [] szInfFile;
  840. delete [] szInxFile;
  841. #endif
  842. // Open up a DB connection if a server was specified
  843. if( m_szDataServer[0] ){
  844. m_pdb = new CSimpleDatabase();
  845. if ( SUCCEEDED(m_pdb->Connect( m_szDataServer,
  846. m_szDatabase[0]?m_szDatabase:NULL,
  847. m_szUserName[0]?m_szUserName:NULL,
  848. m_szPassword[0]?m_szPassword:NULL )) ) {
  849. m_bActiveDB = TRUE;
  850. }
  851. else {
  852. m_dwInfGenError = FAIL_DSNOPEN;
  853. return E_FAIL;
  854. }
  855. }
  856. m_bGenInitCalled = TRUE;
  857. return S_OK;
  858. }
  859. else {
  860. #ifndef UNICODE
  861. delete [] szInfFile;
  862. delete [] szInxFile;
  863. #endif
  864. m_dwInfGenError = FAIL_COPYBASEINF;
  865. return E_FAIL;
  866. }
  867. }
  868. HRESULT
  869. CUpdateInf::get_InfGenError(
  870. BSTR *bstrError
  871. )
  872. {
  873. LPVOID pErrorMsg;
  874. DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS;
  875. #ifndef UNICODE
  876. wchar_t *wszErrorMsg;
  877. size_t lenErrorMsg;
  878. #endif
  879. // assume system error codes will be win32-style or 0x8 stlye
  880. if ( m_dwInfGenError | 0xc0000000 )
  881. {
  882. dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
  883. }
  884. else
  885. {
  886. dwFormatFlags |= FORMAT_MESSAGE_FROM_SYSTEM;
  887. }
  888. if ( NULL == bstrError ) {
  889. return E_POINTER;
  890. }
  891. if ( !FormatMessage( dwFormatFlags,
  892. g_hMyInstance,
  893. m_dwInfGenError,
  894. NULL,
  895. (LPTSTR) &pErrorMsg,
  896. 0,
  897. NULL ) )
  898. {
  899. return E_FAIL;
  900. }
  901. #ifndef UNICODE
  902. lenErrorMsg = strlen((LPSTR)pErrorMsg) + 1;
  903. wszErrorMsg = new wchar_t[lenErrorMsg];
  904. if ( NULL == wszErrorMsg )
  905. {
  906. LocalFree( pErrorMsg );
  907. return E_OUTOFMEMORY;
  908. }
  909. if ( 0 == MultiByteToWideChar( _getmbcp(),
  910. 0L,
  911. (LPSTR)pErrorMsg,
  912. lenErrorMsg,
  913. wszErrorMsg,
  914. lenErrorMsg ) )
  915. {
  916. delete [] wszErrorMsg;
  917. LocalFree( pErrorMsg );
  918. return E_FAIL;
  919. }
  920. *bstrError = SysAllocString( wszErrorMsg );
  921. delete [] wszErrorMsg;
  922. #else
  923. *bstrError = SysAllocString( (LPWSTR)pErrorMsg );
  924. #endif
  925. LocalFree( pErrorMsg );
  926. if ( NULL == *bstrError ) {
  927. return E_OUTOFMEMORY;
  928. }
  929. return S_OK;
  930. }
  931. BOOL
  932. CUpdateInf::TrimInf(
  933. LPTSTR szINFIn,
  934. LPTSTR szINFOut
  935. )
  936. {
  937. BOOL bRet = TRUE;
  938. // Open a handle to the INF
  939. m_hInf = SetupOpenInfFile( szINFIn, NULL, INF_STYLE_WIN4 , NULL );
  940. if ( INVALID_HANDLE_VALUE == m_hInf ) {
  941. m_dwInfGenError = GetLastError();
  942. return FALSE;
  943. }
  944. if ( !GetSectionListFromInF( szINFIn ) ||
  945. !ReadSectionEntries( szINFIn ) ||
  946. !IdentifyUninstallSections() ||
  947. !DeleteUnusedEntries() ||
  948. !WriteSmallINF( szINFIn, szINFOut ) ) {
  949. bRet = FALSE;
  950. }
  951. SetupCloseInfFile( m_hInf );
  952. m_hInf = INVALID_HANDLE_VALUE;
  953. return bRet;
  954. }
  955. BOOL
  956. CUpdateInf::ReverseSectionList(
  957. void
  958. )
  959. {
  960. PSECTION pSectionList2 = NULL;
  961. PSECTION psRef,psRef2;
  962. psRef = m_sectionList;
  963. psRef2 = psRef->Next;
  964. while( psRef ) {
  965. psRef->Next = NULL;
  966. m_sectionList = psRef2;
  967. if( pSectionList2 == NULL ) {
  968. pSectionList2 = psRef;
  969. } else {
  970. psRef->Next = pSectionList2 ;
  971. pSectionList2 = psRef;
  972. }
  973. psRef = psRef2;
  974. if( psRef != NULL ) {
  975. psRef2 = psRef->Next;
  976. }
  977. }
  978. m_sectionList = pSectionList2;
  979. return TRUE;
  980. }
  981. BOOL
  982. CUpdateInf::WriteSmallINF(
  983. LPTSTR szINFIn,
  984. LPTSTR szINFOut
  985. )
  986. {
  987. BOOL bRet = FALSE;
  988. FILE *fp2 = NULL;
  989. PSECTION ps;
  990. ReverseSectionList();
  991. fp2 = _tfopen( szINFOut, _T("w+") );
  992. if( fp2 ) {
  993. // write all the entries from in file to out file excluding the empty sections from sectionlist
  994. ps = m_sectionList;
  995. while( ps ) {
  996. if( ps->cRef ) {
  997. if ( _ftprintf( fp2, _T("[%s]\n"),ps->szSectionName) < 0 ) {
  998. m_dwInfGenError = GetLastError();
  999. goto fail;
  1000. }
  1001. for( DWORD i=0; i < ps->dwSectionEntries ; i++ ) {
  1002. if( ps->pseSectionEntries[i].cRef ) {
  1003. if ( _ftprintf(fp2, _T(" %s\n"), ps->pseSectionEntries[i].szLine) < 0 ) {
  1004. m_dwInfGenError = GetLastError();
  1005. goto fail;
  1006. }
  1007. }
  1008. }
  1009. _ftprintf( fp2,_T("\n") );
  1010. }
  1011. ps = ps->Next;
  1012. }
  1013. bRet = TRUE;
  1014. }
  1015. fail:
  1016. if( fp2 ) {
  1017. fclose( fp2 );
  1018. }
  1019. return bRet ;
  1020. }
  1021. BOOL
  1022. CUpdateInf::DeleteUnusedEntries(
  1023. void
  1024. )
  1025. {
  1026. HINF hInf;
  1027. BOOL bRet = TRUE;
  1028. PSECTION ps, ps2;
  1029. if ( INVALID_HANDLE_VALUE == m_hInf ) {
  1030. return FALSE;
  1031. }
  1032. ps = m_sectionList;
  1033. while( ps ) {
  1034. if ( 0 == SetupGetLineCount( m_hInf, ps->szSectionName ) ) {
  1035. if ( 0 == --ps->cRef )
  1036. {
  1037. MarkAssociatedEntriesForDelete( ps );
  1038. }
  1039. }
  1040. ps = ps->Next;
  1041. }
  1042. ps2 = m_sectionList;
  1043. while( ps2 ) {
  1044. // If all the directives are marked delete, then mark this section
  1045. PSECTIONENTRY pse = ps2->pseSectionEntries;
  1046. // If this section has already been removed, ignore it
  1047. if ( ps2->cRef )
  1048. {
  1049. for( DWORD dwCount = 0; dwCount < ps2->dwSectionEntries ; dwCount++ ) {
  1050. if( pse[ dwCount ].cRef ) {
  1051. break;
  1052. }
  1053. }
  1054. if( dwCount == ps2->dwSectionEntries ) {
  1055. //All the directives are marked delete So mark this for delete.
  1056. if ( 0 == --ps2->cRef )
  1057. {
  1058. MarkAssociatedEntriesForDelete( ps2 );
  1059. }
  1060. }
  1061. }
  1062. ps2=ps2->Next;
  1063. }
  1064. // Determine if we can discard any AddDirId sections
  1065. DeleteUnusedDirIdSections();
  1066. return bRet;
  1067. }
  1068. /*
  1069. AddDirId sections are unused if their InstallFromSection entry has been marked
  1070. as deleted (as is the case if the corresponding section is empty). We identify
  1071. AddDirId sections by looking in the DirectoryId.Include section. This function
  1072. goes through all of the AddDirId section identified in the DirectoryId.Include
  1073. section and determines if the section is no longer used (based on whether
  1074. InstallFromSection has been marked deleted or not).
  1075. */
  1076. BOOL
  1077. CUpdateInf::DeleteUnusedDirIdSections(
  1078. void
  1079. )
  1080. {
  1081. HINF hInf;
  1082. BOOL bRet = TRUE;
  1083. INFCONTEXT Context;
  1084. TCHAR szDirIDSection[ MAX_PATH ];
  1085. if ( INVALID_HANDLE_VALUE == m_hInf )
  1086. {
  1087. return FALSE;
  1088. }
  1089. if ( SetupFindFirstLine( m_hInf, _T("DirectoryId.Include"), _T("AddDirId"), &Context ) ) {
  1090. do{
  1091. if( SetupGetLineText( &Context, NULL, NULL, NULL , szDirIDSection, MAX_PATH , NULL ) ) {
  1092. PSECTIONASSOCIATIONLIST pSectionAssoc;
  1093. DWORD dwHash = CalcHashFromSectionName( szDirIDSection );
  1094. pSectionAssoc = m_rgNameHash[dwHash];
  1095. while ( pSectionAssoc && _tcsicmp( szDirIDSection, pSectionAssoc->pSection->szSectionName ) )
  1096. {
  1097. pSectionAssoc = pSectionAssoc->pNext;
  1098. }
  1099. // If we found a matching section, find the InstallFromSection entry
  1100. if ( pSectionAssoc ) {
  1101. PSECTIONENTRY pse = pSectionAssoc->pSection->pseSectionEntries;
  1102. DWORD dwCount;
  1103. for( dwCount = 0; dwCount < pSectionAssoc->pSection->dwSectionEntries ; dwCount++ ) {
  1104. if( 0 == _tcsncicmp( _T("InstallFromSection="), pse[ dwCount ].szLine, 19 ) ) {
  1105. break;
  1106. }
  1107. }
  1108. // If we found the InstallFromSection entry and it is marked for delete
  1109. // then this section is no longer needed; remove it and its associated
  1110. // entries
  1111. if( dwCount < pSectionAssoc->pSection->dwSectionEntries &&
  1112. !pse[dwCount].cRef ) {
  1113. if ( 0 == --pSectionAssoc->pSection->cRef )
  1114. {
  1115. MarkAssociatedEntriesForDelete( pSectionAssoc->pSection );
  1116. }
  1117. }
  1118. else if ( dwCount < pSectionAssoc->pSection->dwSectionEntries )
  1119. {
  1120. // Can InstallFromSection have more than one
  1121. // comma-delimited entry?
  1122. }
  1123. }
  1124. }
  1125. } while( SetupFindNextLine( &Context, &Context ) );
  1126. }
  1127. return bRet;
  1128. }
  1129. BOOL
  1130. CUpdateInf::IdentifyUninstallSections(
  1131. void
  1132. )
  1133. {
  1134. PSECTIONASSOCIATIONLIST pSectionFinder;
  1135. DWORD dwHash = CalcHashFromSectionName( _T("UninstallSections") );
  1136. pSectionFinder = m_rgNameHash[dwHash];
  1137. while ( pSectionFinder && _tcsicmp( _T("UninstallSections"), pSectionFinder->pSection->szSectionName ) )
  1138. {
  1139. pSectionFinder = pSectionFinder->pNext;
  1140. }
  1141. // If we found the [UninstallSections] section, identify the other sections
  1142. if ( pSectionFinder ) {
  1143. DWORD dwCount;
  1144. PSECTION pUninstallSection = pSectionFinder->pSection;
  1145. // the uninstall section is used by the installer
  1146. pUninstallSection->cRef++;
  1147. // for each entry of <uninstall_name>,<current_name> update the current_name section
  1148. for( dwCount = 0; dwCount < pUninstallSection->dwSectionEntries ; dwCount++ ) {
  1149. PSECTIONASSOCIATIONLIST pAssocSection;
  1150. TCHAR *pCurName;
  1151. pCurName = _tcschr( pUninstallSection->pseSectionEntries[dwCount].szLine, _T(',') );
  1152. if ( pCurName ) {
  1153. pCurName++; // move past the ,
  1154. dwHash = CalcHashFromSectionName( pCurName );
  1155. pAssocSection = m_rgNameHash[dwHash];
  1156. while ( pAssocSection && _tcsicmp( pCurName, pAssocSection->pSection->szSectionName ) )
  1157. {
  1158. pAssocSection = pAssocSection->pNext;
  1159. }
  1160. if ( pAssocSection )
  1161. {
  1162. DWORD dwEntry = 0;
  1163. // Update reference count on section
  1164. // NOTE: this is only necessary if we want to keep
  1165. // empty sections around, but since we don't
  1166. // know a lot about the uninstall logic we
  1167. // are playing it safe
  1168. pAssocSection->pSection->cRef++;
  1169. // Update reference count on all of the section's entries
  1170. while ( dwEntry < pAssocSection->pSection->dwSectionEntries ) {
  1171. pAssocSection->pSection->pseSectionEntries[dwEntry++].cRef++;
  1172. }
  1173. // Associate the current entry with this found section
  1174. AssociateEntryWithSection( &pUninstallSection->pseSectionEntries[dwCount], pCurName, FALSE );
  1175. }
  1176. }
  1177. }
  1178. }
  1179. return TRUE;
  1180. }
  1181. BOOL
  1182. CUpdateInf::RemoveSectionFromMultiEntry(
  1183. PSECTIONENTRY pse,
  1184. LPCTSTR szSectionName
  1185. )
  1186. {
  1187. TCHAR *pSectionName = StrStrI( pse->szLine, szSectionName );
  1188. TCHAR *pEndSection;
  1189. if ( NULL != pSectionName )
  1190. {
  1191. pEndSection = _tcschr( pSectionName, _T(',') );
  1192. if ( pEndSection )
  1193. {
  1194. memmove( pSectionName, pEndSection + 1, sizeof(TCHAR) * (_tcslen(pEndSection+1) + 1) );
  1195. }
  1196. else
  1197. {
  1198. // We might be the last entry in the list
  1199. pSectionName--;
  1200. while ( pSectionName > pse->szLine &&
  1201. _istspace( *pSectionName ) ) pSectionName--;
  1202. if ( _T(',') == *pSectionName )
  1203. {
  1204. *pSectionName = _T('\0');
  1205. }
  1206. // We must be the only remaining entry
  1207. else
  1208. {
  1209. *(pSectionName+1) = _T('\0');
  1210. }
  1211. }
  1212. return TRUE;
  1213. }
  1214. else
  1215. {
  1216. // We didn't find the section name to remove it
  1217. return FALSE;
  1218. }
  1219. }
  1220. BOOL
  1221. CUpdateInf::MarkAssociatedEntriesForDelete(
  1222. PSECTION ps
  1223. )
  1224. {
  1225. PASSOCIATEDENTRIES pAssociatedEntries = ps->pAssociatedEntries;
  1226. while ( pAssociatedEntries )
  1227. {
  1228. if ( --pAssociatedEntries->pse->cRef )
  1229. {
  1230. // This line apparently references more than one section
  1231. // so remove ourselves so the line is still useable
  1232. RemoveSectionFromMultiEntry(pAssociatedEntries->pse, ps->szSectionName);
  1233. }
  1234. pAssociatedEntries = pAssociatedEntries->pNext;
  1235. }
  1236. return TRUE;
  1237. }
  1238. BOOL
  1239. CUpdateInf::ReadSectionEntries(
  1240. LPCTSTR szINF
  1241. )
  1242. {
  1243. HINF hInf;
  1244. INFCONTEXT Context;
  1245. BOOL bRet = TRUE;
  1246. DWORD dwSectionEntries;
  1247. DWORD dwNumChars;
  1248. PSECTION ps;
  1249. if ( INVALID_HANDLE_VALUE == m_hInf ) {
  1250. return FALSE;
  1251. }
  1252. ps = m_sectionList;
  1253. while( ps ) {
  1254. if( ps->cRef ) {
  1255. dwSectionEntries = SetupGetLineCount( m_hInf, ps->szSectionName );
  1256. if( dwSectionEntries > 0 ) {
  1257. ps->pseSectionEntries = new SECTIONENTRY [dwSectionEntries];
  1258. if ( NULL == ps->pseSectionEntries ) {
  1259. m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
  1260. return FALSE;
  1261. }
  1262. memset( ps->pseSectionEntries, 0 , dwSectionEntries * sizeof( SECTIONENTRY ) );
  1263. memset( m_textBuffer, 0 , sizeof( m_textBuffer ) );
  1264. dwNumChars = GetPrivateProfileSection(
  1265. ps->szSectionName,
  1266. m_textBuffer,
  1267. BUFFER_SIZE,
  1268. szINF
  1269. );
  1270. if ( dwNumChars + 2 == BUFFER_SIZE ) {
  1271. m_dwInfGenError = FAIL_MAX_BUFFER;
  1272. return FALSE;
  1273. }
  1274. TCHAR * pch = m_textBuffer;
  1275. while( *pch ) {
  1276. TCHAR *pCurPos = m_textBuffer2;
  1277. do
  1278. {
  1279. if ( _T(';') != pch[0] )
  1280. {
  1281. _tcscpy( pCurPos, pch );
  1282. pCurPos += _tcslen(pch);
  1283. if ( _T('\\') == *(pCurPos - 1) ) pCurPos--;
  1284. }
  1285. pch = pch + _tcslen( pch) +1 ;
  1286. } while ( *pch && _T('\\') == *pCurPos );
  1287. pCurPos = _T('\0');
  1288. if ( _tcslen( m_textBuffer2 ) &&
  1289. !AddEntryToSection( ps, m_textBuffer2 ) ) {
  1290. bRet = FALSE;
  1291. break;
  1292. }
  1293. }
  1294. }
  1295. }
  1296. ps = ps->Next;
  1297. }
  1298. return bRet;
  1299. }
  1300. BOOL
  1301. CUpdateInf::AddEntryToSection(
  1302. PSECTION ps,
  1303. LPCTSTR szEntry
  1304. )
  1305. {
  1306. static TCHAR *rgKeys[] = { _T("CopyFiles"),
  1307. _T("DelFiles"),
  1308. _T("AddReg"),
  1309. _T("DelReg"),
  1310. _T("AddDirId"),
  1311. _T("InstallFromSection") };
  1312. TCHAR szNewEntry[MAX_PATH],
  1313. *pNewEntry;
  1314. BOOL bInQuote = FALSE;
  1315. TCHAR *szPostKey;
  1316. TCHAR *szComment;
  1317. // Add entry to section
  1318. ps->pseSectionEntries[ps->dwSectionEntries].szLine = new TCHAR [_tcslen(szEntry) + 1];
  1319. if ( NULL == ps->pseSectionEntries[ps->dwSectionEntries].szLine )
  1320. {
  1321. m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
  1322. return FALSE;
  1323. }
  1324. _tcscpy( ps->pseSectionEntries[ps->dwSectionEntries].szLine, szEntry );
  1325. ps->pseSectionEntries[ps->dwSectionEntries].cRef = 1;
  1326. if ( _tcslen(szEntry) <= MAX_PATH )
  1327. {
  1328. pNewEntry = szNewEntry;
  1329. }
  1330. else
  1331. {
  1332. pNewEntry = new TCHAR [_tcslen(szEntry) + 1];
  1333. if ( NULL == pNewEntry )
  1334. {
  1335. m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
  1336. return FALSE;
  1337. }
  1338. }
  1339. _tcscpy( pNewEntry, szEntry );
  1340. // Remove any comments
  1341. szComment = pNewEntry;
  1342. while ( *szComment )
  1343. {
  1344. if ( _T('\"') == *szComment ) bInQuote = !bInQuote;
  1345. if ( !bInQuote && _T(';') == *szComment ) break;
  1346. szComment++;
  1347. }
  1348. if ( *szComment )
  1349. {
  1350. while ( szComment >= pNewEntry &&
  1351. _istspace( *szComment ) ) { szComment--; }
  1352. *(szComment + 1) = _T('\0');
  1353. }
  1354. // Find the key (if one exists)
  1355. szPostKey = _tcschr( pNewEntry, _T('=') );
  1356. if ( szPostKey )
  1357. {
  1358. *szPostKey = _T('\0');
  1359. // If we recognize the entry type, add it to list affecting specified section
  1360. if( _tcsicmp( ps->szSectionName , _T("DestinationDirs") ) == 0 ) {
  1361. // This entry is necessary only as long as it has associations
  1362. ps->pseSectionEntries[ps->dwSectionEntries].cRef = 0;
  1363. AssociateEntryWithSection( &ps->pseSectionEntries[ps->dwSectionEntries], pNewEntry, FALSE );
  1364. } else {
  1365. DWORD iKey;
  1366. szPostKey++;
  1367. for ( iKey = 0; iKey < sizeof(rgKeys) / sizeof(rgKeys[0]); iKey++ )
  1368. {
  1369. if ( !_tcsicmp( rgKeys[iKey], pNewEntry ) )
  1370. {
  1371. // The associated sections may appear in a comma-delimited list,
  1372. // so make sure to associate all of the entries
  1373. BOOL fMultiEntry = (NULL != _tcschr( szPostKey, _T(',') ));
  1374. TCHAR *pSection = _tcstok( szPostKey, _T(" ,") );
  1375. // This entry is necessary only as long as it has associations
  1376. ps->pseSectionEntries[ps->dwSectionEntries].cRef = 0;
  1377. do
  1378. {
  1379. AssociateEntryWithSection( &ps->pseSectionEntries[ps->dwSectionEntries], pSection, fMultiEntry );
  1380. } while ( pSection = _tcstok(NULL, _T(" ,")) );
  1381. break;
  1382. }
  1383. }
  1384. }
  1385. }
  1386. // Free up buffer if we were forced to allocate one
  1387. if ( pNewEntry != szNewEntry ) delete [] pNewEntry;
  1388. ps->dwSectionEntries++;
  1389. return TRUE;
  1390. }
  1391. BOOL
  1392. CUpdateInf::AssociateEntryWithSection(
  1393. PSECTIONENTRY pse,
  1394. LPCTSTR szSectionName,
  1395. BOOL fMultiSection
  1396. )
  1397. {
  1398. DWORD dwHash;
  1399. PSECTION pSection;
  1400. PSECTIONASSOCIATIONLIST pSectionAssoc;
  1401. PASSOCIATEDENTRIES pAssociation;
  1402. // Find our section to associate in the hash list
  1403. dwHash = CalcHashFromSectionName( szSectionName );
  1404. pSectionAssoc = m_rgNameHash[dwHash];
  1405. while ( pSectionAssoc && _tcsicmp( szSectionName, pSectionAssoc->pSection->szSectionName ) )
  1406. {
  1407. pSectionAssoc = pSectionAssoc->pNext;
  1408. }
  1409. // If we couldn't find the section, assume it doesn't exit and mark the entry for delete
  1410. if ( !pSectionAssoc )
  1411. {
  1412. if ( fMultiSection )
  1413. {
  1414. // Remove the section name from a multi-section
  1415. // comma-delimited list
  1416. RemoveSectionFromMultiEntry(pse, szSectionName);
  1417. }
  1418. return TRUE;
  1419. }
  1420. // Add new entry to section association
  1421. pAssociation = new ASSOCIATEDENTRIES;
  1422. if ( NULL == pAssociation )
  1423. {
  1424. m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
  1425. return FALSE;
  1426. }
  1427. // Update the ref count on the entry
  1428. pse->cRef++;
  1429. pAssociation->pse = pse;
  1430. pAssociation->pNext = NULL;
  1431. pSection = pSectionAssoc->pSection;
  1432. if ( pSection->pAssociatedEntries )
  1433. {
  1434. pAssociation->pNext = pSection->pAssociatedEntries;
  1435. pSection->pAssociatedEntries = pAssociation;
  1436. }
  1437. else
  1438. {
  1439. pSection->pAssociatedEntries = pAssociation;
  1440. }
  1441. return TRUE;
  1442. }
  1443. DWORD
  1444. CUpdateInf::CalcHashFromSectionName(
  1445. LPCTSTR szSectionName
  1446. )
  1447. {
  1448. TCHAR szSectionNameLC[ MAX_PATH ];
  1449. DWORD dwHash = 0L,
  1450. dwHashExtra = 0L;
  1451. BYTE *pData;
  1452. size_t bytesSectionName = sizeof( TCHAR ) * _tcslen( szSectionName );
  1453. size_t i;
  1454. // Dependent on sizeof(DWORD) = 4 * sizeof(BYTE) so put in a check
  1455. // which the compiler should optimize out
  1456. if ( sizeof(DWORD) != 4*sizeof(BYTE) ) DebugBreak();
  1457. // convert section name to lower-case
  1458. for ( i = 0; i < _tcslen( szSectionName ); i++ )
  1459. {
  1460. szSectionNameLC[i] = (_istupper(szSectionName[i])?_totlower(szSectionName[i]):szSectionName[i]);
  1461. }
  1462. pData = (PBYTE)szSectionNameLC;
  1463. for ( i = 0; i < bytesSectionName / sizeof(DWORD); i++ )
  1464. {
  1465. DWORD dwTempHash = 0L;
  1466. dwTempHash = pData[0] << 24 | pData[1] << 16 | pData[2] << 8 | pData[3];
  1467. #ifdef UNICODE
  1468. dwHash ^= i%2?dwTempHash >> 8:dwTempHash;
  1469. #else
  1470. dwHash ^= dwTempHash;
  1471. #endif
  1472. pData += sizeof(DWORD);
  1473. }
  1474. // Pick up any remaining bits that don't fit into a DWORD
  1475. for ( i = 0; i < bytesSectionName % sizeof(DWORD); i++ )
  1476. {
  1477. dwHashExtra <<= 8;
  1478. dwHashExtra += pData[i];
  1479. }
  1480. return (dwHash ^ dwHashExtra) % HASH_BUCKETS;
  1481. }
  1482. BOOL
  1483. CUpdateInf::GetSectionListFromInF(
  1484. LPTSTR szINF
  1485. )
  1486. {
  1487. BOOL bRet = TRUE;
  1488. PSECTION ps = NULL;
  1489. DWORD dwSize =0;
  1490. LPTSTR lpReturnedString;
  1491. DWORD dwResult;
  1492. TCHAR *pc;
  1493. DWORD dwHash;
  1494. BOOL fDuplicate;
  1495. PSECTIONASSOCIATIONLIST pAssociationList;
  1496. dwSize = GetFileSizeByName( szINF, NULL );
  1497. lpReturnedString = new TCHAR [dwSize];
  1498. dwResult = GetPrivateProfileString(
  1499. NULL, // section name
  1500. NULL, // key name
  1501. _T("1"), // default string
  1502. lpReturnedString, // destination buffer
  1503. dwSize, // size of destination buffer
  1504. szINF
  1505. );
  1506. pc = lpReturnedString;
  1507. if( dwResult > 0 ) {
  1508. // Form the list
  1509. while( ( bRet ) && ( _tcslen( pc ) != 0 ) ) {
  1510. ps = new SECTION;
  1511. if( ps ) {
  1512. fDuplicate = FALSE;
  1513. memset( ps, 0, sizeof( SECTION ) );
  1514. _tcscpy( ps->szSectionName, pc );
  1515. ps->cRef = 1;
  1516. // Add section to association hash
  1517. dwHash = CalcHashFromSectionName( ps->szSectionName );
  1518. if ( !m_rgNameHash[dwHash] )
  1519. {
  1520. m_rgNameHash[dwHash] = new SECTIONASSOCIATIONLIST;
  1521. if ( NULL == m_rgNameHash[dwHash] )
  1522. {
  1523. m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
  1524. bRet = FALSE;
  1525. break;
  1526. }
  1527. pAssociationList = m_rgNameHash[dwHash];
  1528. }
  1529. else
  1530. {
  1531. pAssociationList = m_rgNameHash[dwHash];
  1532. // Check for duplicate section name
  1533. do
  1534. {
  1535. if ( !_tcsicmp(pAssociationList->pSection->szSectionName, ps->szSectionName) )
  1536. {
  1537. fDuplicate = TRUE;
  1538. break;
  1539. }
  1540. }
  1541. while ( pAssociationList->pNext &&
  1542. NULL != (pAssociationList = pAssociationList->pNext) // should always be true
  1543. );
  1544. if ( !fDuplicate )
  1545. {
  1546. pAssociationList->pNext = new SECTIONASSOCIATIONLIST;
  1547. if ( NULL == pAssociationList->pNext )
  1548. {
  1549. m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
  1550. bRet = FALSE;
  1551. break;
  1552. }
  1553. pAssociationList = pAssociationList->pNext;
  1554. }
  1555. }
  1556. if ( !fDuplicate )
  1557. {
  1558. pAssociationList->pSection = ps;
  1559. pAssociationList->pNext = NULL;
  1560. //
  1561. // Add section to section list
  1562. //
  1563. if( m_sectionList == NULL ) {
  1564. m_sectionList = ps;
  1565. } else {
  1566. ps->Next = m_sectionList;
  1567. m_sectionList = ps;
  1568. }
  1569. }
  1570. else
  1571. {
  1572. // free duplicate section entry
  1573. delete ps;
  1574. }
  1575. } else{
  1576. bRet = FALSE;
  1577. }
  1578. pc += _tcslen( pc )+1 ;
  1579. }
  1580. } else {
  1581. bRet = FALSE;
  1582. }
  1583. if( lpReturnedString != NULL ) {
  1584. delete [] lpReturnedString;
  1585. }
  1586. TCHAR szDebug[50];
  1587. short cFilled = 0;
  1588. for ( short i = 0; i < HASH_BUCKETS; i++ ) { if ( m_rgNameHash[i] ) cFilled++; }
  1589. _stprintf( szDebug, _T("Buckets used: %u\n"), cFilled );
  1590. OutputDebugString( szDebug );
  1591. return bRet;
  1592. }
  1593. DWORD
  1594. CUpdateInf::GetFileSizeByName(
  1595. IN LPCTSTR pszFileName,
  1596. OUT PDWORD pdwFileSizeHigh
  1597. )
  1598. {
  1599. DWORD dwFileSizeLow = 0xFFFFFFFF;
  1600. HANDLE hFile;
  1601. hFile = CreateFile(
  1602. pszFileName,
  1603. GENERIC_READ,
  1604. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1605. NULL,
  1606. OPEN_EXISTING,
  1607. FILE_FLAG_NO_BUFFERING,
  1608. NULL
  1609. );
  1610. if ( hFile != INVALID_HANDLE_VALUE ) {
  1611. dwFileSizeLow = GetFileSize( hFile, pdwFileSizeHigh );
  1612. CloseHandle( hFile );
  1613. }
  1614. return dwFileSizeLow;
  1615. }