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

2289 lines
68 KiB

  1. /*****************************************************************************\
  2. * MODULE: gencdf.c
  3. *
  4. * The module contains routines for generating a CDF (Cabinet Directive File)
  5. * for the IExpress utility.
  6. *
  7. * Work Items:
  8. * ----------
  9. * 1) Redo item-allocations to use single block-heap and append information
  10. * to reduce heap-overhead.
  11. *
  12. *
  13. * Copyright (C) 1996-1997 Microsoft Corporation
  14. * Copyright (C) 1996-1997 Hewlett Packard
  15. *
  16. * History:
  17. * 22-Nov-1996 HWP-Guys Created.
  18. *
  19. \*****************************************************************************/
  20. #include "pch.h"
  21. /*****************************************************************************\
  22. * cdf_NextStr (Local Routine)
  23. *
  24. * Proceeds to the next string in a section-list.
  25. *
  26. \*****************************************************************************/
  27. _inline LPTSTR cdf_NextStr(
  28. LPTSTR lpszStr)
  29. {
  30. return (lpszStr + (lstrlen(lpszStr) + 1));
  31. }
  32. /******************************************************************************\
  33. *
  34. * GetDirectory (Local Routine)
  35. *
  36. * Returns the directory portion of a full pathname.
  37. *
  38. \******************************************************************************/
  39. LPTSTR cdf_GetDirectoryWithSlash(LPTSTR lpszFile) {
  40. LPTSTR lpszSlash;
  41. LPTSTR lpszDir;
  42. lpszSlash = genFindRChar(lpszFile, TEXT('\\'));
  43. if (lpszSlash != NULL) {
  44. if (NULL != (lpszDir = (LPTSTR)genGAlloc((UINT32) (lpszSlash - lpszFile + 2) * sizeof(TCHAR)))) {
  45. StringCchCopy(lpszDir, (UINT32) (lpszSlash - lpszFile + 2), lpszFile);
  46. return lpszDir;
  47. }
  48. }
  49. return NULL;
  50. }
  51. /******************************************************************************\
  52. *
  53. * cdf_GetName (Local Routine)
  54. *
  55. * Returns the filename portion of a full pathname.
  56. *
  57. \******************************************************************************/
  58. LPTSTR cdf_GetName(LPTSTR lpszFile) {
  59. LPTSTR lpszSlash;
  60. LPTSTR lpszName;
  61. int nLength;
  62. lpszSlash = genFindRChar(lpszFile, TEXT('\\'));
  63. if (lpszSlash != NULL) {
  64. nLength = lstrlen(lpszSlash);
  65. if (NULL != (lpszName = (LPTSTR)genGAlloc((nLength * sizeof(TCHAR))))) {
  66. StringCchCopy(lpszName, nLength, ++lpszSlash);
  67. return lpszName;
  68. }
  69. }
  70. return NULL;
  71. }
  72. /*****************************************************************************\
  73. * cdf_SFLAdd (Local Routine)
  74. *
  75. * Adds a new section to our linked-list of sections. This adds it to the
  76. * head of the list and returns a pointer to the new item (head).
  77. *
  78. \*****************************************************************************/
  79. LPSRCFILES cdf_SFLAdd(
  80. LPSRCFILES psfList,
  81. LPCTSTR lpszPath)
  82. {
  83. LPSRCFILES psfItem;
  84. if (psfItem = (LPSRCFILES)genGAlloc(sizeof(SRCFILES))) {
  85. if (psfItem->lpszPath = genGAllocStr(lpszPath)) {
  86. // Allocate the files-list buffer.
  87. //
  88. if (psfItem->lpszFiles = (LPTSTR)genGAlloc(CDF_SRCFILE_BLOCK)) {
  89. // Position our item at the head.
  90. //
  91. psfItem->cbMax = CDF_SRCFILE_BLOCK;
  92. psfItem->cbSize = 0;
  93. psfItem->pNext = psfList;
  94. // Make sure our file beginning is zeroed.
  95. //
  96. *(psfItem->lpszFiles) = TEXT('\0');
  97. return psfItem;
  98. }
  99. genGFree(psfItem->lpszPath, genGSize(psfItem->lpszPath));
  100. }
  101. genGFree(psfItem, sizeof(SRCFILES));
  102. }
  103. DBGMSG(DBG_ERROR, ("cdf_SFLAdd : Out of memory"));
  104. return NULL;
  105. }
  106. /*****************************************************************************\
  107. * cdf_SFLAddFile (Local Routine)
  108. *
  109. * Adds a file-item to the specified section-pointer.
  110. *
  111. \*****************************************************************************/
  112. BOOL cdf_SFLAddFile(
  113. LPSRCFILES psfList,
  114. LPCTSTR lpszFile)
  115. {
  116. LPTSTR lpszList;
  117. LPTSTR lpszPtr;
  118. LPTSTR lpszNew;
  119. DWORD cbSize;
  120. DWORD cbOldSize;
  121. DWORD cbNewSize;
  122. HRESULT hr;
  123. // Determine if adding this file exceeds our current maximum
  124. // buffer. If so, then realloc a bigger chunk. We are adding
  125. // two extra characters to account for the '%' which are to
  126. // be added to the lpszFile.
  127. //
  128. cbSize = (lstrlen(lpszFile) + 1 + 2) * sizeof(TCHAR);
  129. if ((psfList->cbSize + cbSize) >= psfList->cbMax) {
  130. cbOldSize = genGSize(psfList->lpszFiles);
  131. cbNewSize = cbOldSize + CDF_SRCFILE_BLOCK;
  132. lpszNew = (LPTSTR)genGRealloc(psfList->lpszFiles, cbOldSize, cbNewSize);
  133. if (lpszNew == NULL) {
  134. DBGMSG(DBG_ERROR, ("cdf_SFLAddFile : Out of memory"));
  135. return FALSE;
  136. }
  137. // Set new limit criteria.
  138. //
  139. psfList->lpszFiles = lpszNew;
  140. psfList->cbMax = cbNewSize;
  141. }
  142. // We are appending the file to the end of the list.
  143. //
  144. lpszPtr = (LPTSTR)(((LPBYTE)psfList->lpszFiles) + psfList->cbSize);
  145. if (SUCCEEDED(hr = StringCbPrintf(lpszPtr, cbSize, TEXT("%%%s%%\0"), lpszFile)))
  146. {
  147. psfList->cbSize += cbSize;
  148. }
  149. return SUCCEEDED(hr);
  150. }
  151. /*****************************************************************************\
  152. * cdf_SFLFind (Local Routine)
  153. *
  154. * Looks for the existence of a section-name.
  155. *
  156. \*****************************************************************************/
  157. LPSRCFILES cdf_SFLFind(
  158. LPSRCFILES psfList,
  159. LPCTSTR lpszPath)
  160. {
  161. while (psfList) {
  162. if (lstrcmpi(psfList->lpszPath, lpszPath) == 0)
  163. return psfList;
  164. psfList = psfList->pNext;
  165. }
  166. return NULL;
  167. }
  168. /*****************************************************************************\
  169. * cdf_SFLFree (Local Routine)
  170. *
  171. * Frees up memory associated with the source-file-list.
  172. *
  173. \*****************************************************************************/
  174. BOOL cdf_SFLFree(
  175. LPSRCFILES psfList)
  176. {
  177. LPSRCFILES psfItem;
  178. while (psfList) {
  179. genGFree(psfList->lpszFiles, genGSize(psfList->lpszFiles));
  180. genGFree(psfList->lpszPath , genGSize(psfList->lpszPath));
  181. psfItem = psfList;
  182. psfList = psfList->pNext;
  183. genGFree(psfItem, genGSize(psfItem));
  184. }
  185. return TRUE;
  186. }
  187. /*****************************************************************************\
  188. * cdf_WriteStrings
  189. *
  190. * Outputs a string to the [Strings] section.
  191. *
  192. \*****************************************************************************/
  193. _inline BOOL cdf_WriteStrings(
  194. LPCTSTR lpszCdfFile,
  195. LPCTSTR lpszKey,
  196. LPCTSTR lpszStr)
  197. {
  198. return WritePrivateProfileString(g_szStrings, lpszKey, lpszStr, lpszCdfFile);
  199. }
  200. /*****************************************************************************\
  201. * itm_InitList (Local Routine)
  202. *
  203. * Initializes the file-item-list.
  204. *
  205. \*****************************************************************************/
  206. _inline VOID itm_InitList(
  207. PCDFINFO pCdfInfo)
  208. {
  209. pCdfInfo->pTop = NULL;
  210. }
  211. /*****************************************************************************\
  212. * itm_GetFirst (Local Routine)
  213. *
  214. * Returns the first PMYITEM in the list
  215. *
  216. \*****************************************************************************/
  217. _inline PFILEITEM itm_GetFirst(
  218. PCDFINFO pCdfInfo)
  219. {
  220. return pCdfInfo->pTop;
  221. }
  222. /*****************************************************************************\
  223. * itm_GetNext (Local Routine)
  224. *
  225. * Given the current item, returns the next item in the list.
  226. *
  227. \*****************************************************************************/
  228. _inline PFILEITEM itm_GetNext(
  229. PFILEITEM pMyItem)
  230. {
  231. SPLASSERT((pMyItem != NULL));
  232. return pMyItem->pNext;
  233. }
  234. /*****************************************************************************\
  235. * itm_GetString (Local Routine)
  236. *
  237. * Returns a string associated with an item. You pick the
  238. * string by passing the number of the string.
  239. *
  240. \*****************************************************************************/
  241. _inline LPTSTR itm_GetString(
  242. PFILEITEM pMyItem,
  243. UINT nItem)
  244. {
  245. SPLASSERT((pMyItem != NULL));
  246. SPLASSERT((nItem <= FI_COL_LAST));
  247. return pMyItem->aszCols[nItem];
  248. }
  249. /*****************************************************************************\
  250. * itm_FullPath (Local Routine)
  251. *
  252. * Return a fully-qualified pathname for the item.
  253. *
  254. \*****************************************************************************/
  255. _inline LPTSTR itm_FullPath(
  256. PFILEITEM pItem)
  257. {
  258. LPTSTR lpszPath;
  259. LPTSTR lpszFile;
  260. // Gather the strings and build the name.
  261. //
  262. lpszPath = itm_GetString(pItem, FI_COL_PATH);
  263. lpszFile = itm_GetString(pItem, FI_COL_FILENAME);
  264. return genBuildFileName(NULL, lpszPath, lpszFile);
  265. }
  266. /*****************************************************************************\
  267. * itm_GetTime (Local Routine)
  268. *
  269. * Returns a time associated with an item.
  270. *
  271. \*****************************************************************************/
  272. _inline FILETIME itm_GetTime(
  273. PFILEITEM pMyItem)
  274. {
  275. SPLASSERT((pMyItem != NULL));
  276. return pMyItem->ftLastModify;
  277. }
  278. /*****************************************************************************\
  279. * itm_SetTime (Local Routine)
  280. *
  281. * Sets the last modified time of the item.
  282. *
  283. \*****************************************************************************/
  284. VOID itm_SetTime(
  285. PFILEITEM pMyItem,
  286. FILETIME ftLastModify)
  287. {
  288. SPLASSERT((pMyItem != NULL));
  289. pMyItem->ftLastModify = ftLastModify;
  290. }
  291. /*****************************************************************************\
  292. * itm_Last (Local Routine)
  293. *
  294. * Used to end a while loop when we've reached the end of list
  295. *
  296. \*****************************************************************************/
  297. _inline BOOL itm_Last(
  298. PFILEITEM pMyItem)
  299. {
  300. return (pMyItem == NULL);
  301. }
  302. /*****************************************************************************\
  303. * itm_Free (Local Routine)
  304. *
  305. * Frees the memory associated with an item.
  306. *
  307. \*****************************************************************************/
  308. VOID itm_Free(
  309. PFILEITEM pItem)
  310. {
  311. LPTSTR lpszStr;
  312. if (lpszStr = itm_GetString(pItem, FI_COL_FILENAME))
  313. genGFree(lpszStr, genGSize(lpszStr));
  314. if (lpszStr = itm_GetString(pItem, FI_COL_PATH))
  315. genGFree(lpszStr, genGSize(lpszStr));
  316. genGFree(pItem, sizeof(FILEITEM));
  317. }
  318. /*****************************************************************************\
  319. * itm_DeleteAll (Local Routine)
  320. *
  321. * Deletes all the items from our file list.
  322. *
  323. \*****************************************************************************/
  324. VOID itm_DeleteAll(
  325. PCDFINFO pCdfInfo)
  326. {
  327. PFILEITEM pMyItem;
  328. PFILEITEM pTempItem;
  329. pMyItem = itm_GetFirst(pCdfInfo);
  330. while (itm_Last(pMyItem) == FALSE) {
  331. pTempItem = pMyItem;
  332. pMyItem = itm_GetNext(pMyItem);
  333. itm_Free(pTempItem);
  334. }
  335. itm_InitList(pCdfInfo);
  336. }
  337. /*****************************************************************************\
  338. * itm_Add (Local Routine)
  339. *
  340. * Adds an item to the list.
  341. *
  342. \*****************************************************************************/
  343. PFILEITEM itm_Add(
  344. LPCTSTR lpszFilename,
  345. LPCTSTR lpszPath,
  346. PCDFINFO pCdfInfo)
  347. {
  348. PFILEITEM pMyItem;
  349. SPLASSERT((lpszFilename != NULL));
  350. SPLASSERT((lpszPath != NULL));
  351. if (pMyItem = (PFILEITEM)genGAlloc(sizeof(FILEITEM))) {
  352. // Allocate the strings for the path/filename.
  353. //
  354. if (pMyItem->aszCols[FI_COL_FILENAME] = genGAllocStr(lpszFilename)) {
  355. if (pMyItem->aszCols[FI_COL_PATH] = genGAllocStr(lpszPath)) {
  356. pMyItem->pNext = pCdfInfo->pTop;
  357. pCdfInfo->pTop = pMyItem;
  358. return pMyItem;
  359. }
  360. genGFree(pMyItem->aszCols[FI_COL_FILENAME], genGSize(pMyItem->aszCols[FI_COL_FILENAME]));
  361. }
  362. genGFree(pMyItem, sizeof(FILEITEM));
  363. }
  364. return NULL;
  365. }
  366. /*****************************************************************************\
  367. * itm_Find (Local Routine)
  368. *
  369. * To see if file is already in list
  370. *
  371. \*****************************************************************************/
  372. PFILEITEM itm_Find(
  373. LPCTSTR lpszFindFile,
  374. PCDFINFO pCdfInfo,
  375. BOOL bMatchFullPath)
  376. {
  377. PFILEITEM pItem = itm_GetFirst(pCdfInfo);
  378. LPTSTR lpszItmFile;
  379. BOOL bRet = FALSE;
  380. // Loop through our list of items looking for a file
  381. // match.
  382. //
  383. while (pItem) {
  384. // Build the file-name from the stored-strings.
  385. //
  386. if (bMatchFullPath)
  387. lpszItmFile = itm_FullPath(pItem);
  388. else
  389. lpszItmFile = itm_GetString(pItem, FI_COL_FILENAME);
  390. if (lpszItmFile) {
  391. // Check for match.
  392. //
  393. if (lstrcmpi(lpszFindFile, lpszItmFile) == 0) {
  394. // Found.
  395. //
  396. if (bMatchFullPath)
  397. genGFree(lpszItmFile, genGSize(lpszItmFile));
  398. return pItem;
  399. }
  400. if (bMatchFullPath)
  401. genGFree(lpszItmFile, genGSize(lpszItmFile));
  402. } else {
  403. return NULL;
  404. }
  405. pItem = itm_GetNext(pItem);
  406. }
  407. return NULL;
  408. }
  409. /*****************************************************************************\
  410. * cdf_WriteTimeStamps
  411. *
  412. * Outputs a struct to the [TimeStamps] section.
  413. *
  414. \*****************************************************************************/
  415. _inline BOOL cdf_WriteTimeStamps(
  416. LPCTSTR lpszCdfFile,
  417. LPCTSTR lpszKey,
  418. LPFILEITEM pFileItem)
  419. {
  420. FILETIME ft = itm_GetTime(pFileItem);
  421. return WritePrivateProfileStruct(g_szTimeStamps, lpszKey, &ft, sizeof(FILETIME), lpszCdfFile);
  422. }
  423. /*****************************************************************************\
  424. * cdf_WriteSourceFiles
  425. *
  426. * Outputs a struct to the [SourceFiles] section.
  427. *
  428. \*****************************************************************************/
  429. _inline BOOL cdf_WriteSourceFiles(
  430. LPCTSTR lpszCdfFile,
  431. LPCTSTR lpszKey,
  432. LPCTSTR lpszStr)
  433. {
  434. return WritePrivateProfileString(g_szSourceFiles, lpszKey, lpszStr, lpszCdfFile);
  435. }
  436. /*****************************************************************************\
  437. * cdf_GetSection (Local Routine)
  438. *
  439. * Allocate a buffer which stores either all section-names or the list of
  440. * items specified by (lpszSection) in an INF file. Currently, we attempt
  441. * a realloc if the buffer is not big enough.
  442. *
  443. * NOTE: should we provide a limit for the amount of allocations before
  444. * we accept failure?
  445. *
  446. * 09-Dec-1996 : ChrisWil
  447. *
  448. \*****************************************************************************/
  449. LPTSTR cdf_GetSection(
  450. LPCTSTR lpszSct,
  451. BOOL bString,
  452. LPCTSTR lpszCdfFile)
  453. {
  454. DWORD dwCnt;
  455. DWORD cch;
  456. DWORD dwSize;
  457. DWORD dwLimit;
  458. LPTSTR lpszNames = NULL;
  459. dwSize = 0;
  460. dwLimit = 0;
  461. while (dwLimit < CDF_SECTION_LIMIT) {
  462. // We'll start this allocation with an assumed max-size. Upon
  463. // successive tries, this buffer is increased each time by the
  464. // original buffer allocation.
  465. //
  466. dwSize += (CDF_SECTION_BLOCK * sizeof(TCHAR));
  467. dwLimit++;
  468. // Alloc the buffer and attempt to get the names.
  469. //
  470. if (lpszNames = (LPTSTR)genGAlloc(dwSize)) {
  471. // If a section-name is profided, use that. Otherwise,
  472. // enumerate all section-names.
  473. //
  474. cch = dwSize / sizeof(TCHAR);
  475. if (bString) {
  476. dwCnt = GetPrivateProfileString(lpszSct,
  477. NULL,
  478. g_szEmptyStr,
  479. lpszNames,
  480. cch,
  481. lpszCdfFile);
  482. } else {
  483. dwCnt = GetPrivateProfileSection(lpszSct,
  484. lpszNames,
  485. cch,
  486. lpszCdfFile);
  487. }
  488. // If the call says the buffer was OK, then we can
  489. // assume the names are retrieved. According to spec's,
  490. // if the return-count is equal to size-2, then buffer
  491. // isn't quite big-enough (two NULL chars).
  492. //
  493. if (dwCnt < (cch - 2))
  494. goto GetSectDone;
  495. genGFree(lpszNames, dwSize);
  496. lpszNames = NULL;
  497. }
  498. }
  499. GetSectDone:
  500. SPLASSERT((dwLimit < CDF_SECTION_LIMIT));
  501. return lpszNames;
  502. }
  503. /*****************************************************************************\
  504. * cdf_GetValue (Local Routine)
  505. *
  506. *
  507. \*****************************************************************************/
  508. LPTSTR cdf_GetValue(
  509. LPCTSTR lpszSection,
  510. LPCTSTR lpszKey,
  511. LPCTSTR lpszCdfFile)
  512. {
  513. TCHAR szBuffer[STD_CDF_BUFFER];
  514. DWORD cch;
  515. LPTSTR lpszVal = NULL;
  516. cch = GetPrivateProfileString(lpszSection,
  517. lpszKey,
  518. g_szEmptyStr,
  519. szBuffer,
  520. COUNTOF(szBuffer),
  521. lpszCdfFile);
  522. SPLASSERT((cch < STD_CDF_BUFFER));
  523. return (cch ? genGAllocStr(szBuffer) : NULL);
  524. }
  525. /*****************************************************************************\
  526. * cdf_GetCdfFile (Local Routine)
  527. *
  528. * Returns an allocated string to the CDF file (Full-Path)
  529. *
  530. \*****************************************************************************/
  531. LPTSTR cdf_GetCdfFile(
  532. PCDFINFO pCdfInfo)
  533. {
  534. LPCTSTR lpszDstPath;
  535. LPCTSTR lpszDstName;
  536. // Retrieve the strings representing the destination path and name
  537. // of the output file. These strings have already been validated
  538. // by the INF object.
  539. //
  540. lpszDstPath = infGetDstPath(pCdfInfo->hInf);
  541. lpszDstName = infGetDstName(pCdfInfo->hInf);
  542. return genBuildFileName(lpszDstPath, lpszDstName, g_szDotSed);
  543. }
  544. /*****************************************************************************\
  545. * cdf_GetUncName (Local Routine)
  546. *
  547. * Returns an allocated string to the unc-name.
  548. *
  549. \*****************************************************************************/
  550. LPTSTR cdf_GetUncName(
  551. PCDFINFO pCdfInfo)
  552. {
  553. DWORD cchSize;
  554. LPCTSTR lpszShrName;
  555. LPTSTR lpszUncName = NULL;
  556. static CONST TCHAR s_szFmt[] = TEXT("\\\\%s\\%s");
  557. if (lpszShrName = infGetShareName(pCdfInfo->hInf)) {
  558. cchSize= lstrlen(g_szPrintServerName) +
  559. lstrlen(lpszShrName) +
  560. lstrlen(s_szFmt) +
  561. 1;
  562. if (lpszUncName = (LPTSTR)genGAlloc((cchSize * sizeof(TCHAR))))
  563. {
  564. if (FAILED(StringCchPrintf(lpszUncName, cchSize, s_szFmt, g_szPrintServerName, lpszShrName)))
  565. {
  566. genGFree(lpszUncName, genGSize(lpszUncName));
  567. lpszUncName = NULL;
  568. }
  569. }
  570. }
  571. return lpszUncName;
  572. }
  573. /*****************************************************************************\
  574. * cdf_BuildFriendlyName (Local Routine)
  575. *
  576. * Builds a \\machinename\friendly type string so that the client can
  577. * refer to the printer as "friendly on machinename".
  578. *
  579. \*****************************************************************************/
  580. LPTSTR cdf_BuildFriendlyName(
  581. PCDFINFO pCdfInfo)
  582. {
  583. DWORD cchSize;
  584. LPCTSTR lpszFrnName;
  585. LPTSTR lpszPtr;
  586. LPTSTR lpszFmt;
  587. LPTSTR lpszName = NULL;
  588. static TCHAR s_szFmt0[] = TEXT("\\\\http://%s\\%s");
  589. static TCHAR s_szFmt1[] = TEXT("\\\\https://%s\\%s");
  590. if (lpszFrnName = infGetFriendlyName(pCdfInfo->hInf)) {
  591. if (lpszPtr = genFindChar((LPTSTR)lpszFrnName, TEXT('\\'))) {
  592. lpszPtr++;
  593. lpszPtr++;
  594. if (lpszPtr = genFindChar(lpszPtr, TEXT('\\'))) {
  595. // Check if this is a secure request.
  596. //
  597. lpszFmt = (pCdfInfo->bSecure ? s_szFmt1 : s_szFmt0);
  598. // This is the friendly name, not the port name, so we don't
  599. // call GetWebpnpUrl to encode it.
  600. //
  601. cchSize= lstrlen(g_szHttpServerName) +
  602. lstrlen(++lpszPtr) +
  603. lstrlen(lpszFmt) +
  604. 1;
  605. if (lpszName = (LPTSTR)genGAlloc(cchSize * sizeof(TCHAR)))
  606. {
  607. if (FAILED(StringCchPrintf(lpszName, cchSize, lpszFmt, g_szHttpServerName, lpszPtr)))
  608. {
  609. genGFree(lpszName, genGSize(lpszName));
  610. lpszName = NULL;
  611. }
  612. }
  613. }
  614. }
  615. }
  616. return lpszName;
  617. }
  618. /*****************************************************************************\
  619. * cdf_ReadFiles (Local Routine)
  620. *
  621. * Reads in the files under the specified src-path-key.
  622. *
  623. \*****************************************************************************/
  624. BOOL cdf_ReadFiles(
  625. LPCTSTR lpszSrcPathKey,
  626. LPCTSTR lpszSrcFiles,
  627. PCDFINFO pCdfInfo)
  628. {
  629. FILETIME ftFileTime;
  630. PFILEITEM pFileItem;
  631. LPTSTR lpszPath;
  632. LPTSTR lpszFiles;
  633. LPTSTR lpszFile;
  634. LPTSTR lpszStr;
  635. BOOL bRet = FALSE;
  636. // For the specified SrcKeyPath, read in the list of files
  637. // associated with the path.
  638. //
  639. lpszFiles = cdf_GetSection(lpszSrcPathKey, FALSE, pCdfInfo->lpszCdfFile);
  640. if (lpszFiles) {
  641. // Get the path-value associated with the SrcPathKey.
  642. //
  643. if (lpszPath = cdf_GetValue(lpszSrcFiles, lpszSrcPathKey, pCdfInfo->lpszCdfFile)) {
  644. lpszFile = lpszFiles;
  645. while (*lpszFile) {
  646. // If the first-character doesn't specify a string-type
  647. // then we can add it directly. Otherwise, we're going
  648. // to have to get the file referenced by the string.
  649. //
  650. if (lpszFile[0] != TEXT('%')) {
  651. // Store the path and filename in the list.
  652. //
  653. pFileItem = itm_Add(lpszFile, lpszPath, pCdfInfo);
  654. //
  655. // Fail if we have run out of memory
  656. //
  657. if (!pFileItem)
  658. {
  659. goto ReadFileError;
  660. }
  661. // Read in file timestamp from .cdf.
  662. //
  663. if (GetPrivateProfileStruct(g_szTimeStamps,
  664. lpszFile,
  665. &ftFileTime,
  666. sizeof(FILETIME),
  667. pCdfInfo->lpszCdfFile)) {
  668. // Store the timestamp.
  669. //
  670. itm_SetTime(pFileItem, ftFileTime);
  671. lpszFile = cdf_NextStr(lpszFile);
  672. } else {
  673. goto ReadFileError;
  674. }
  675. } else {
  676. // Handle %filename% names (localizable strings)
  677. // If the filename is delimited by two percent (%)
  678. // signs,it is not a literal, but needs to be
  679. // looked up [Strings] section of the .cdf file.
  680. //
  681. // Replace the % on the end of the string
  682. // with a null char, then move past the end-char.
  683. //
  684. lpszFile[lstrlen(lpszFile) - 1] = TEXT('\0');
  685. lpszFile++;
  686. lpszStr = cdf_GetValue(g_szStrings,
  687. lpszFile,
  688. pCdfInfo->lpszCdfFile);
  689. if (lpszStr) {
  690. pFileItem = itm_Add(lpszStr, lpszPath, pCdfInfo);
  691. //
  692. // Fail if we have run out of memory
  693. //
  694. if (!pFileItem)
  695. {
  696. genGFree(lpszStr, genGSize(lpszStr));
  697. goto ReadFileError;
  698. }
  699. // Read in file timestamp from .cdf
  700. //
  701. GetPrivateProfileStruct(g_szTimeStamps,
  702. lpszFile,
  703. &ftFileTime,
  704. sizeof(FILETIME),
  705. pCdfInfo->lpszCdfFile);
  706. genGFree(lpszStr, genGSize(lpszStr));
  707. itm_SetTime(pFileItem, ftFileTime);
  708. // We add 2 + len of string, because we put in an
  709. // extra null to replace the % char
  710. //
  711. lpszFile = cdf_NextStr(lpszFile) + 1;
  712. } else {
  713. goto ReadFileError;
  714. }
  715. }
  716. }
  717. bRet = TRUE;
  718. ReadFileError:
  719. genGFree(lpszPath, genGSize(lpszPath));
  720. }
  721. genGFree(lpszFiles, genGSize(lpszFiles));
  722. }
  723. return bRet;
  724. }
  725. /*****************************************************************************\
  726. * cdf_ReadFileList (Local Routine)
  727. *
  728. * Reads in the file-list from the CDF-File.
  729. *
  730. \*****************************************************************************/
  731. BOOL cdf_ReadFileList(
  732. PCDFINFO pCdfInfo)
  733. {
  734. LPTSTR lpszSrcFiles;
  735. LPTSTR lpszSrcPaths;
  736. LPTSTR lpszPathKey;
  737. BOOL bRet = FALSE;
  738. // Initialize the head of the list.
  739. //
  740. itm_InitList(pCdfInfo);
  741. // Get source files section of .cdf file
  742. //
  743. lpszSrcFiles = cdf_GetValue(g_szOptions,
  744. g_szSourceFiles,
  745. pCdfInfo->lpszCdfFile);
  746. if (lpszSrcFiles) {
  747. // Read in the entire SourceFiles section (as a list of keys).
  748. //
  749. lpszSrcPaths = cdf_GetSection(lpszSrcFiles,
  750. TRUE,
  751. pCdfInfo->lpszCdfFile);
  752. if (lpszPathKey = lpszSrcPaths) {
  753. // Each section name has a path associated with it.
  754. // For each section name, read in and add all the
  755. // files to the list
  756. //
  757. while (*lpszPathKey) {
  758. if (cdf_ReadFiles(lpszPathKey, lpszSrcFiles, pCdfInfo) == FALSE)
  759. goto ReadListExit;
  760. lpszPathKey = cdf_NextStr(lpszPathKey);
  761. }
  762. bRet = TRUE;
  763. ReadListExit:
  764. genGFree(lpszSrcPaths, genGSize(lpszSrcPaths));
  765. }
  766. genGFree(lpszSrcFiles, genGSize(lpszSrcFiles));
  767. }
  768. return bRet;
  769. }
  770. /*****************************************************************************\
  771. * cdf_AddCATFile (Local Routine)
  772. *
  773. * This is called by cdf_GetFileList for each file being added to the cdf.
  774. * It uses the Catalog File Admin APIs to determine if the driver file was installed
  775. * with an associated catalog file. If a corresponding catalog file (or files)
  776. * is found, the catalog filename (or filenames), along with its timestamp,
  777. * is added to the cdf file list.
  778. *
  779. \*****************************************************************************/
  780. BOOL cdf_AddCATFile(LPTSTR lpszFile, LPCDFINFO pCdfInfo ) {
  781. HCATADMIN hCatAdmin = pCdfInfo->hCatAdmin;
  782. HCATINFO hCatInfo = NULL;
  783. CATALOG_INFO CatInfo;
  784. BYTE * pbHash;
  785. DWORD dwBytes;
  786. WIN32_FIND_DATA ffd;
  787. PFILEITEM pFileItem;
  788. HANDLE hFind, hFile;
  789. LPTSTR pFullPath, pPath, pName;
  790. // Find the catalog file associated with this file.
  791. // If we can't find one, that's OK, it's not an error, just a file
  792. // with no associated .cat file. The user can decide on the client-end
  793. // whether or not he wants to install without the verification a .cat file
  794. // would provide...
  795. //
  796. if (INVALID_HANDLE_VALUE != (HANDLE)hCatAdmin) {
  797. hFind = FindFirstFile(lpszFile, &ffd);
  798. if (hFind && (hFind != INVALID_HANDLE_VALUE)) {
  799. FindClose(hFind);
  800. // Open the file in order to hash it.
  801. //
  802. if (INVALID_HANDLE_VALUE != (hFile = CreateFile(lpszFile,
  803. GENERIC_READ,
  804. FILE_SHARE_READ,
  805. NULL,
  806. OPEN_EXISTING,
  807. FILE_ATTRIBUTE_NORMAL,
  808. NULL))) {
  809. // Determine how many bytes we need for the hash
  810. //
  811. dwBytes = 0;
  812. pbHash = NULL;
  813. CryptCATAdminCalcHashFromFileHandle(hFile, &dwBytes, pbHash, 0);
  814. if (NULL != (pbHash = (BYTE *)genGAlloc(dwBytes))) {
  815. // Compute the hash for this file
  816. //
  817. if (CryptCATAdminCalcHashFromFileHandle(hFile, &dwBytes, pbHash, 0)) {
  818. // Get the catalog file(s) associated with this file hash
  819. //
  820. hCatInfo = NULL;
  821. do {
  822. hCatInfo = CryptCATAdminEnumCatalogFromHash(hCatAdmin, pbHash, dwBytes, 0, &hCatInfo);
  823. if (NULL != hCatInfo) {
  824. // Split the cat name into file and path here
  825. //
  826. if (CryptCATCatalogInfoFromContext(hCatInfo, &CatInfo, NULL)) {
  827. if (NULL != (pFullPath = genTCFromWC(CatInfo.wszCatalogFile))) {
  828. if (NULL != (pPath = cdf_GetDirectoryWithSlash(pFullPath))) {
  829. if (NULL != (pName = cdf_GetName(pFullPath))) {
  830. // Make sure the file is not already in the cdf, so
  831. // IExpress doesn't give out (see BUG: explanation in cdf_GetFileList() )
  832. //
  833. if (NULL == itm_Find(pName, pCdfInfo, FALSE)) {
  834. // Add the catalog file and timestamp
  835. pFileItem = itm_Add(pName, pPath, pCdfInfo);
  836. if (pFileItem)
  837. {
  838. itm_SetTime(pFileItem, ffd.ftLastWriteTime);
  839. }
  840. }
  841. genGFree(pName, genGSize(pName) );
  842. }
  843. genGFree(pPath, genGSize(pPath) );
  844. }
  845. genGFree(pFullPath, genGSize(pFullPath) );
  846. }
  847. }
  848. }
  849. } while (NULL != hCatInfo);
  850. }
  851. genGFree(pbHash, dwBytes);
  852. }
  853. CloseHandle(hFile);
  854. }
  855. }
  856. }
  857. return TRUE;
  858. }
  859. /*****************************************************************************\
  860. * cdf_GetFileList (Local Routine)
  861. *
  862. * This is a callback function passed to infEnumItems()
  863. * It reads in the list of files from the INF object, and reads
  864. * the filetimes from the disk and adds these to the list also.
  865. *
  866. \*****************************************************************************/
  867. BOOL CALLBACK cdf_GetFileList(
  868. LPCTSTR lpszName,
  869. LPCTSTR lpszPath,
  870. BOOL bInf,
  871. LPVOID lpData)
  872. {
  873. PCDFINFO pCdfInfo = (PCDFINFO)lpData;
  874. HANDLE hFind;
  875. PFILEITEM pFileItem;
  876. LPTSTR lpszFile;
  877. LPTSTR lpszPtr;
  878. WIN32_FIND_DATA FindFileData;
  879. BOOL bRet = FALSE;
  880. // Build fully qualified file name.
  881. //
  882. if (lpszFile = genBuildFileName(lpszPath, lpszName, NULL)) {
  883. hFind = FindFirstFile(lpszFile, &FindFileData);
  884. if (hFind && (hFind != INVALID_HANDLE_VALUE)) {
  885. FindClose(hFind);
  886. // IExpress fails when it encounters the
  887. // same filename twice. To work-around this,
  888. // we will prevent the inclusion of the second
  889. // file. We will match the name-only.
  890. //
  891. if (itm_Find(lpszName, pCdfInfo, FALSE) == NULL) {
  892. // Add the item to the list of CDF-Files. We
  893. // store the path-name with the trailing '\'
  894. // because the CDF format requires such.
  895. //
  896. lpszPtr = genFindRChar(lpszFile, TEXT('\\'));
  897. // Is filename of right format?
  898. //
  899. if ( lpszPtr != NULL ) {
  900. *(++lpszPtr) = TEXT('\0');
  901. pFileItem = itm_Add(lpszName, lpszFile, pCdfInfo);
  902. // Set the item-time. This should only fail if we couldn't allocate memory
  903. //
  904. if (pFileItem != NULL) {
  905. itm_SetTime(pFileItem, FindFileData.ftLastWriteTime);
  906. bRet = TRUE;
  907. }
  908. }
  909. else
  910. SetLastError(ERROR_INVALID_PARAMETER);
  911. }
  912. else
  913. bRet = TRUE; // Item already exits, so TRUE
  914. }
  915. genGFree(lpszFile, genGSize(lpszFile));
  916. }
  917. return bRet;
  918. }
  919. /*****************************************************************************\
  920. * cdf_CheckFiles (Local Routine)
  921. *
  922. * This is a callback function passed to infEnumItems()
  923. * It checks each filename to see if it is in the .cdf list,
  924. * and if it is up to date.
  925. *
  926. \*****************************************************************************/
  927. BOOL CALLBACK cdf_CheckFiles(
  928. LPCTSTR lpszName,
  929. LPCTSTR lpszPath,
  930. BOOL bInfFile,
  931. LPVOID lpData)
  932. {
  933. PCDFINFO pCdfInfo = (PCDFINFO)lpData;
  934. HANDLE hFind;
  935. PFILEITEM pFileItem;
  936. LPTSTR lpszFile;
  937. LPTSTR lpszPtr;
  938. WIN32_FIND_DATA FindFileData;
  939. LONG lCompare;
  940. BOOL bRet = FALSE;
  941. // Build fully qualified filename.
  942. //
  943. if (lpszFile = genBuildFileName(lpszPath, lpszName, NULL)) {
  944. // Locate the item, and see if the dates are out-of-sync.
  945. //
  946. if (pFileItem = itm_Find(lpszFile, pCdfInfo, TRUE)) {
  947. hFind = FindFirstFile(lpszFile, &FindFileData);
  948. if (hFind && (hFind != INVALID_HANDLE_VALUE)) {
  949. FindClose(hFind);
  950. // Compare the file-times.
  951. //
  952. lCompare = CompareFileTime(&FindFileData.ftLastWriteTime,
  953. &pFileItem->ftLastModify);
  954. // Skip over INF files since we are generating
  955. // these in the INF object.
  956. //
  957. if (bInfFile || (lCompare == 0))
  958. bRet = TRUE;
  959. }
  960. }
  961. genGFree(lpszFile, genGSize(lpszFile));
  962. }
  963. return bRet;
  964. }
  965. /*****************************************************************************\
  966. * cdf_get_datfile
  967. *
  968. * Returns the then name of the dat-file. The name built incorporates
  969. * the sharename to distinguish it from other dat-files in the directory.
  970. * any other files.
  971. *
  972. * <path>\<Share ChkSum>.dat
  973. *
  974. \*****************************************************************************/
  975. LPTSTR cdf_get_datfile(
  976. LPCTSTR lpszDstPath,
  977. LPCTSTR lpszShrName)
  978. {
  979. TCHAR szName[MIN_CDF_BUFFER];
  980. // Build the name using the checksum.
  981. //
  982. StringCchPrintf(szName, COUNTOF(szName), g_szDatName, genChkSum(lpszShrName));
  983. return genBuildFileName(lpszDstPath, szName, g_szDotDat);
  984. }
  985. /*****************************************************************************\
  986. * cdf_IsDatCurrent (Local Routine)
  987. *
  988. * Checks the port-name in the dat-file for match. If they do not, then we
  989. * need to return FALSE to proceed with a new cab-generation.
  990. *
  991. \*****************************************************************************/
  992. BOOL cdf_IsDatCurrent(
  993. PCDFINFO pCdfInfo)
  994. {
  995. LPCTSTR lpszPrtName;
  996. LPCTSTR lpszDstPath;
  997. LPCTSTR lpszShrName;
  998. LPTSTR lpszDatFile;
  999. LPTSTR lpszDat;
  1000. LPTSTR lpszPtr;
  1001. LPTSTR lpszEnd;
  1002. DWORD cbSize;
  1003. DWORD cbRd;
  1004. HANDLE hFile;
  1005. BOOL bRet = FALSE;
  1006. // Get the information from the INF-object so we can determine the
  1007. // age of the dat-file.
  1008. //
  1009. lpszDstPath = infGetDstPath(pCdfInfo->hInf);
  1010. lpszPrtName = infGetPrtName(pCdfInfo->hInf);
  1011. lpszShrName = infGetShareName(pCdfInfo->hInf);
  1012. // Build the dat-file-name and open for reading.
  1013. //
  1014. if (lpszDatFile = cdf_get_datfile(lpszDstPath, lpszShrName)) {
  1015. hFile = gen_OpenFileRead(lpszDatFile);
  1016. if (hFile && (hFile != INVALID_HANDLE_VALUE)) {
  1017. cbSize = GetFileSize(hFile, NULL);
  1018. if (lpszDat = (LPTSTR)genGAlloc(cbSize)) {
  1019. if (ReadFile(hFile, lpszDat, cbSize, &cbRd, NULL)) {
  1020. lpszPtr = lpszDat;
  1021. while (lpszPtr = genFindChar(lpszPtr, TEXT('/'))) {
  1022. if (*(++lpszPtr) == TEXT('r')) {
  1023. lpszPtr++; // space
  1024. lpszPtr++; // quote
  1025. if (lpszEnd = genFindChar(++lpszPtr, TEXT('\"'))) {
  1026. *lpszEnd = TEXT('\0');
  1027. if (lstrcmpi(lpszPtr, lpszPrtName) == 0)
  1028. bRet = TRUE;
  1029. *lpszEnd = TEXT('\"');
  1030. }
  1031. break;
  1032. }
  1033. // Position pointer to the next flag.
  1034. //
  1035. lpszPtr = genFindChar(lpszPtr, TEXT('\n'));
  1036. }
  1037. }
  1038. genGFree(lpszDat, cbSize);
  1039. }
  1040. CloseHandle(hFile);
  1041. }
  1042. genGFree(lpszDatFile, genGSize(lpszDatFile));
  1043. }
  1044. return bRet;
  1045. }
  1046. /*****************************************************************************\
  1047. * cdf_IsUpToDate (Local Routine)
  1048. *
  1049. * Determines if the CDF is up-to-date, or needs to be regenerated for
  1050. * this printer
  1051. *
  1052. \*****************************************************************************/
  1053. BOOL cdf_IsUpToDate(
  1054. PCDFINFO pCdfInfo)
  1055. {
  1056. BOOL bCurrent = FALSE;
  1057. if (genUpdIPAddr()) {
  1058. if (cdf_IsDatCurrent(pCdfInfo)) {
  1059. // Read filelist into CdfInfo structure from .cdf file
  1060. //
  1061. if (cdf_ReadFileList(pCdfInfo)) {
  1062. // Check files in .inf file to see if .cdf is still valid.
  1063. //
  1064. if (infEnumItems(pCdfInfo->hInf, cdf_CheckFiles, (LPVOID)pCdfInfo))
  1065. bCurrent = TRUE;
  1066. }
  1067. }
  1068. }
  1069. return bCurrent;
  1070. }
  1071. /*****************************************************************************\
  1072. * cdf_EnumICM (Local Routine)
  1073. *
  1074. * Callback to enumerate all ICM profiles in the BIN-File. We only need to
  1075. * add these profiles to our list of CDF-Files that we package up.
  1076. *
  1077. \*****************************************************************************/
  1078. BOOL CALLBACK cdf_EnumICM(
  1079. LPCTSTR lpszPath,
  1080. LPCTSTR lpszFile,
  1081. LPVOID lpParm)
  1082. {
  1083. return cdf_GetFileList(lpszFile, lpszPath, FALSE, lpParm);
  1084. }
  1085. /*****************************************************************************\
  1086. * cdf_WriteSourceFilesSection (Local Routine)
  1087. *
  1088. *
  1089. \*****************************************************************************/
  1090. BOOL cdf_WriteSourceFilesSection(
  1091. PCDFINFO pCdfInfo,
  1092. LPSRCFILES psfList)
  1093. {
  1094. TCHAR szSection[STD_CDF_BUFFER];
  1095. int idx;
  1096. BOOL bRet;
  1097. for (idx = 0, bRet = TRUE; psfList; psfList = psfList->pNext) {
  1098. // Build the section name (i.e. SourceFilesX).
  1099. //
  1100. bRet = SUCCEEDED(StringCchPrintf(szSection, COUNTOF(szSection), TEXT("%s%i"), g_szSourceFiles, idx++));
  1101. // Write the source file section name in the [SourceFiles]
  1102. // section.
  1103. //
  1104. if (bRet)
  1105. {
  1106. bRet = cdf_WriteSourceFiles(pCdfInfo->lpszCdfFile,
  1107. szSection,
  1108. psfList->lpszPath);
  1109. }
  1110. // Write out the [SourceFilesX] section.
  1111. //
  1112. if (bRet) {
  1113. bRet = WritePrivateProfileSection(szSection,
  1114. psfList->lpszFiles,
  1115. pCdfInfo->lpszCdfFile);
  1116. }
  1117. }
  1118. return bRet;
  1119. }
  1120. /*****************************************************************************\
  1121. * cdf_WriteBinFile (Local Routine)
  1122. *
  1123. * Writes the .BIN file.
  1124. *
  1125. \*****************************************************************************/
  1126. BOOL cdf_WriteBinFile(
  1127. PCDFINFO pCdfInfo,
  1128. LPCTSTR lpszDstPath,
  1129. LPCTSTR lpszDstName)
  1130. {
  1131. LPCTSTR lpszFriendlyName;
  1132. LPTSTR lpszBinFile;
  1133. LPTSTR lpszBinName;
  1134. HANDLE hPrinter;
  1135. DWORD dwCliInfo;
  1136. BOOL bRet = FALSE;
  1137. if (lpszBinFile = genBuildFileName(lpszDstPath, lpszDstName, g_szDotBin)) {
  1138. if (lpszBinName = genFindRChar(lpszBinFile, TEXT('\\'))) {
  1139. // Increment to the next character for the name.
  1140. //
  1141. lpszBinName++;
  1142. // Retrieve the printer-handle and proceed
  1143. // to write the information to the BIN-File.
  1144. //
  1145. if (lpszFriendlyName = infGetFriendlyName(pCdfInfo->hInf)) {
  1146. if (OpenPrinter((LPTSTR)lpszFriendlyName, &hPrinter, NULL)) {
  1147. dwCliInfo = infGetCliInfo(pCdfInfo->hInf);
  1148. // Call the routine to generate the BIN-File.
  1149. //
  1150. if (webWritePrinterInfo(hPrinter, lpszBinFile)) {
  1151. // Add the bin-file to the list of CDF-Files.
  1152. // Then add ICM-profiles to our list.
  1153. //
  1154. if (cdf_GetFileList(lpszBinName, lpszDstPath, FALSE, (LPVOID)pCdfInfo)) {
  1155. bRet = webEnumPrinterInfo(hPrinter,
  1156. dwCliInfo,
  1157. WEB_ENUM_ICM,
  1158. (FARPROC)cdf_EnumICM,
  1159. (LPVOID)pCdfInfo);
  1160. }
  1161. }
  1162. // Close the printer.
  1163. //
  1164. ClosePrinter(hPrinter);
  1165. }
  1166. }
  1167. }
  1168. genGFree(lpszBinFile, genGSize(lpszBinFile));
  1169. }
  1170. return bRet;
  1171. }
  1172. /*****************************************************************************\
  1173. * cdf_WriteCdfCmd (Local Routine)
  1174. *
  1175. * Writes the .DAT file.
  1176. *
  1177. \*****************************************************************************/
  1178. BOOL cdf_WriteCdfCmd(
  1179. PCDFINFO pCdfInfo,
  1180. LPCTSTR lpszUncName,
  1181. LPCTSTR lpszDstPath,
  1182. LPCTSTR lpszDstName)
  1183. {
  1184. HANDLE hFile;
  1185. LPWSTR lpszCmd;
  1186. LPTSTR lpszTmp;
  1187. LPTSTR lpszBinName;
  1188. LPTSTR lpszDatFile;
  1189. LPTSTR lpszDatTmp;
  1190. LPTSTR lpszFrnName;
  1191. LPCTSTR lpszDrvName;
  1192. LPCTSTR lpszPrtName;
  1193. LPCTSTR lpszInfName;
  1194. LPCTSTR lpszShrName;
  1195. DWORD dwWr;
  1196. DWORD cchSize;
  1197. BOOL bRet = FALSE;
  1198. // Retrive the destination-file info. These strings have
  1199. // already been validated by the INF object.
  1200. //
  1201. lpszDrvName = infGetDrvName(pCdfInfo->hInf);
  1202. lpszPrtName = infGetPrtName(pCdfInfo->hInf);
  1203. lpszInfName = infGetInfName(pCdfInfo->hInf);
  1204. lpszShrName = infGetShareName(pCdfInfo->hInf);
  1205. // Build the dat-file.
  1206. //
  1207. if (lpszDatFile = cdf_get_datfile(lpszDstPath, lpszShrName)) {
  1208. // This is a temporary duplicate of the (lpszDatFile) that
  1209. // will be written to the cdf-command. This is necessary so
  1210. // that the client can have a static-name to use when the
  1211. // cab is expanded.
  1212. //
  1213. if (lpszDatTmp = genBuildFileName(lpszDstPath, g_szDatFile, NULL)) {
  1214. if (lpszBinName = genBuildFileName(NULL, lpszDstName, g_szDotBin)) {
  1215. if (lpszFrnName = cdf_BuildFriendlyName(pCdfInfo)) {
  1216. // Write out the devmode. If the DEVMODE-file (BIN) was
  1217. // written correctly, then we will go ahead and generate the
  1218. // dat-command-file.
  1219. //
  1220. if (cdf_WriteBinFile(pCdfInfo, lpszDstPath, lpszDstName)) {
  1221. cchSize= lstrlen(lpszFrnName) +
  1222. lstrlen(lpszInfName) +
  1223. lstrlen(lpszPrtName) +
  1224. lstrlen(lpszDrvName) +
  1225. lstrlen(lpszUncName) +
  1226. lstrlen(lpszBinName) +
  1227. lstrlen(g_szDatCmd) +
  1228. sizeof(WCHAR);
  1229. if (lpszTmp = (LPTSTR)genGAlloc(cchSize * sizeof(TCHAR))) {
  1230. // Build the Data-command.
  1231. //
  1232. StringCchPrintf(lpszTmp,
  1233. cchSize,
  1234. g_szDatCmd,
  1235. lpszFrnName,
  1236. lpszInfName,
  1237. lpszPrtName,
  1238. lpszDrvName,
  1239. lpszUncName,
  1240. lpszBinName);
  1241. // Open the file for writing.
  1242. //
  1243. hFile = gen_OpenFileWrite(lpszDatFile);
  1244. if (hFile && (hFile != INVALID_HANDLE_VALUE)) {
  1245. // This is here to assure the file written
  1246. // is in byte-format. Otherwise, our strings
  1247. // written to the file would be in unicode
  1248. // format.
  1249. //
  1250. if (lpszCmd = genGAllocStr(lpszTmp)) {
  1251. DWORD cbSize;
  1252. cbSize = (DWORD)SIGNATURE_UNICODE;
  1253. WriteFile(hFile, &cbSize, sizeof(WORD), &dwWr, NULL);
  1254. cbSize = genGSize(lpszCmd);
  1255. WriteFile(hFile, lpszCmd, cbSize, &dwWr, NULL);
  1256. genGFree(lpszCmd, genGSize(lpszCmd));
  1257. }
  1258. CloseHandle(hFile);
  1259. // Make a copy of the file to a static name
  1260. // that will be used in the cdf/cab file.
  1261. //
  1262. CopyFile(lpszDatFile, lpszDatTmp, FALSE);
  1263. // Add the DAT-File to the list of CDF-Files. Use
  1264. // the temporary file so that it is a static name
  1265. // as opposed to our check-sum generated file.
  1266. //
  1267. bRet = cdf_GetFileList(g_szDatFile,
  1268. lpszDstPath,
  1269. FALSE,
  1270. (LPVOID)pCdfInfo);
  1271. }
  1272. genGFree(lpszTmp, genGSize(lpszTmp));
  1273. }
  1274. }
  1275. genGFree(lpszFrnName, genGSize(lpszFrnName));
  1276. }
  1277. genGFree(lpszBinName, genGSize(lpszBinName));
  1278. }
  1279. genGFree(lpszDatTmp, genGSize(lpszDatTmp));
  1280. }
  1281. genGFree(lpszDatFile, genGSize(lpszDatFile));
  1282. }
  1283. return bRet;
  1284. }
  1285. /******************************************************************************
  1286. ** cdf_GenerateSourceFiles (local routine)
  1287. **
  1288. ** Find cases where the source and installed file names are diferent, copy the
  1289. ** installed file to the cabs directory and rename it to the original target file
  1290. ** name.
  1291. **
  1292. *******************************************************************************/
  1293. BOOL cdf_GenerateSourceFiles(
  1294. HANDLE hInf,
  1295. LPCTSTR lpszDstDir) {
  1296. LPINFINFO lpInf = (LPINFINFO)hInf;
  1297. BOOL bRet = lpInf != NULL;
  1298. if (bRet) {
  1299. DWORD dwItems = lpInf->lpInfItems->dwCount;
  1300. LPINFITEMINFO lpII = lpInf->lpInfItems;
  1301. for (DWORD idx = 0; idx < dwItems && bRet; idx++) {
  1302. // We check to see if the file exists as advertised, if it does then we don't
  1303. // change anything, otherwise, we search the system and windows directories to
  1304. // find it, if it exists, we change the path accordingly
  1305. LPTSTR lpszSource = lpII->aItems[idx].szSource;
  1306. if (*lpszSource) { // There was a source name, we know it is different
  1307. // from the target
  1308. LPTSTR lpszFile = genBuildFileName( lpII->aItems[idx].szPath, lpII->aItems[idx].szName, NULL);
  1309. LPTSTR lpszDestFile = genBuildFileName( lpszDstDir, lpszSource, NULL);
  1310. if (lpszFile && lpszDestFile) {
  1311. StringCchCopy( lpII->aItems[idx].szPath, COUNTOF(lpII->aItems[idx].szPath), lpszDstDir);
  1312. StringCchCopy( lpII->aItems[idx].szName, COUNTOF(lpII->aItems[idx].szName), lpszSource);
  1313. bRet = CopyFile( lpszFile, lpszDestFile, FALSE);
  1314. } else
  1315. bRet = FALSE;
  1316. if (lpszFile)
  1317. genGFree(lpszFile, genGSize(lpszFile));
  1318. if (lpszDestFile)
  1319. genGFree(lpszDestFile, genGSize(lpszDestFile) );
  1320. }
  1321. }
  1322. }
  1323. return bRet;
  1324. }
  1325. /*****************************************************************************\
  1326. * cdf_WriteFilesSection (Local Routine)
  1327. *
  1328. * Writes the dynamic file information.
  1329. *
  1330. \*****************************************************************************/
  1331. BOOL cdf_WriteFilesSection(
  1332. PCDFINFO pCdfInfo)
  1333. {
  1334. TCHAR szFileX[MIN_CDF_BUFFER];
  1335. LPCTSTR lpszDstName;
  1336. LPCTSTR lpszDstPath;
  1337. LPTSTR lpszUncName;
  1338. LPTSTR lpszTmp;
  1339. LPTSTR lpszItem;
  1340. DWORD cchSize;
  1341. int idx;
  1342. int idxFile;
  1343. PFILEITEM pFileItem;
  1344. LPSRCFILES psfList;
  1345. LPSRCFILES psfItem;
  1346. BOOL bRet = FALSE;
  1347. static CONST TCHAR s_szFmt0[] = TEXT("\"%s\\%s.webpnp\"");
  1348. static CONST TCHAR s_szFmt1[] = TEXT("\"%s\"");
  1349. if (lpszUncName = cdf_GetUncName(pCdfInfo)) {
  1350. // Retreive the necessary strings from the INF object. These
  1351. // should already be validated as existing. Otherwise, the creation
  1352. // of the INF object would've failed.
  1353. //
  1354. lpszDstName = infGetDstName(pCdfInfo->hInf);
  1355. lpszDstPath = infGetDstPath(pCdfInfo->hInf);
  1356. // Build the TargetName and write to the CDF.
  1357. //
  1358. cchSize= lstrlen(lpszDstPath) +
  1359. lstrlen(lpszDstName) +
  1360. lstrlen(s_szFmt0) +
  1361. 1;
  1362. if (lpszTmp = (LPTSTR)genGAlloc(cchSize * sizeof(TCHAR))) {
  1363. StringCchPrintf(lpszTmp, cchSize, s_szFmt0, lpszDstPath, lpszDstName);
  1364. bRet = cdf_WriteStrings(pCdfInfo->lpszCdfFile, g_szTargetName, lpszTmp);
  1365. genGFree(lpszTmp, genGSize(lpszTmp));
  1366. }
  1367. // Now build cdf-install command; Write it to the CDF.
  1368. //
  1369. cchSize = lstrlen(lpszDstName) + lstrlen(g_szSedCmd) + 1;
  1370. if (bRet && (lpszTmp = (LPTSTR)genGAlloc(cchSize * sizeof(TCHAR)))) {
  1371. StringCchPrintf(lpszTmp, cchSize, g_szSedCmd, lpszDstName);
  1372. bRet = cdf_WriteStrings(pCdfInfo->lpszCdfFile, g_szAppLaunched, lpszTmp);
  1373. genGFree(lpszTmp, genGSize(lpszTmp));
  1374. }
  1375. // Read in all files and filetimes from .inf file (inf object)
  1376. // Initialize the list.
  1377. //
  1378. itm_DeleteAll(pCdfInfo);
  1379. itm_InitList(pCdfInfo);
  1380. // Add all the files enumerated by the inf object.
  1381. // Note: This enumeration includes the inf file itself, so
  1382. // no need to make a special case for it.
  1383. //
  1384. if (bRet)
  1385. bRet = cdf_GenerateSourceFiles( pCdfInfo->hInf, lpszDstPath );
  1386. if (bRet) {
  1387. if (infEnumItems(pCdfInfo->hInf, cdf_GetFileList, (LPVOID)pCdfInfo)) {
  1388. // Generate the command-line for the URL rundll interface.
  1389. //
  1390. bRet = cdf_WriteCdfCmd(pCdfInfo,
  1391. lpszUncName,
  1392. lpszDstPath,
  1393. lpszDstName);
  1394. // Initialize the pointers/indexes that are used
  1395. // to track our section information.
  1396. //
  1397. idxFile = 0;
  1398. pFileItem = itm_GetFirst(pCdfInfo);
  1399. psfList = NULL;
  1400. // If the enumeration succeeded and we have files in the
  1401. // list to process, then proceed to build our sections.
  1402. //
  1403. while (bRet && pFileItem) {
  1404. // Build our FILEx string.
  1405. //
  1406. StringCchPrintf(szFileX, COUNTOF(szFileX), TEXT("FILE%i"), idxFile++);
  1407. // Write out the quoted-item.
  1408. //
  1409. lpszItem = itm_GetString(pFileItem, FI_COL_FILENAME);
  1410. cchSize = lstrlen(lpszItem) + lstrlen(s_szFmt1) + 1;
  1411. if (lpszTmp = (LPTSTR)genGAlloc(cchSize * sizeof(TCHAR))) {
  1412. StringCchPrintf(lpszTmp, cchSize, s_szFmt1, lpszItem);
  1413. bRet = cdf_WriteStrings(pCdfInfo->lpszCdfFile, szFileX, lpszTmp);
  1414. genGFree(lpszTmp, genGSize(lpszTmp));
  1415. }
  1416. // Add timestamp to [TimeStamps] section for this file.
  1417. //
  1418. if (bRet) {
  1419. bRet = cdf_WriteTimeStamps(pCdfInfo->lpszCdfFile,
  1420. szFileX,
  1421. pFileItem);
  1422. }
  1423. // Look for existence of section (path). If it exists,
  1424. // add the file to the section. Otherwise, create a
  1425. // new section and add the file.
  1426. //
  1427. if (bRet) {
  1428. lpszItem = itm_GetString(pFileItem, FI_COL_PATH);
  1429. if ((psfItem = cdf_SFLFind(psfList, lpszItem)) == NULL) {
  1430. if (psfItem = cdf_SFLAdd(psfList, lpszItem)) {
  1431. psfList = psfItem;
  1432. } else {
  1433. bRet = FALSE;
  1434. }
  1435. }
  1436. }
  1437. // Add the file to the appropriate section.
  1438. //
  1439. if (bRet)
  1440. bRet = cdf_SFLAddFile(psfItem, szFileX);
  1441. // Get next file-item.
  1442. //
  1443. pFileItem = itm_GetNext(pFileItem);
  1444. }
  1445. // If all went OK in the enumeration, then we can write
  1446. // the sections to the CDF file.
  1447. //
  1448. if (bRet)
  1449. bRet = cdf_WriteSourceFilesSection(pCdfInfo, psfList);
  1450. // Free up the Source-Files-List.
  1451. //
  1452. cdf_SFLFree(psfList);
  1453. } else
  1454. bRet = FALSE;
  1455. }
  1456. genGFree(lpszUncName, genGSize(lpszUncName));
  1457. }
  1458. return bRet;
  1459. }
  1460. /*****************************************************************************\
  1461. * cdf_WriteVersionSection (Local Routine)
  1462. *
  1463. * Writes the [Version] section in the CDF file.
  1464. *
  1465. \*****************************************************************************/
  1466. BOOL cdf_WriteVersionSection(
  1467. PCDFINFO pCdfInfo)
  1468. {
  1469. UINT uCount;
  1470. UINT idx;
  1471. BOOL bRet;
  1472. static struct {
  1473. LPCTSTR lpszKey;
  1474. LPCTSTR lpszStr;
  1475. } aszVer[] = {
  1476. g_szClass , g_szIExpress,
  1477. g_szSEDVersion, g_szSEDVersionNumber
  1478. };
  1479. // Write out [Version] values.
  1480. //
  1481. uCount = sizeof(aszVer) / sizeof(aszVer[0]);
  1482. for (idx = 0, bRet = TRUE; (idx < uCount) && bRet; idx++) {
  1483. bRet = WritePrivateProfileString(g_szVersionSect,
  1484. aszVer[idx].lpszKey,
  1485. aszVer[idx].lpszStr,
  1486. pCdfInfo->lpszCdfFile);
  1487. }
  1488. return bRet;
  1489. }
  1490. /*****************************************************************************\
  1491. * cdf_WriteOptionsSection (Local Routine)
  1492. *
  1493. * Writess the [Options] section in the CDF file.
  1494. *
  1495. \*****************************************************************************/
  1496. BOOL cdf_WriteOptionsSection(
  1497. PCDFINFO pCdfInfo)
  1498. {
  1499. UINT uCount;
  1500. UINT idx;
  1501. BOOL bRet;
  1502. static struct {
  1503. LPCTSTR lpszKey;
  1504. LPCTSTR lpszStr;
  1505. } aszOpt[] = {
  1506. g_szPackagePurpose , g_szCreateCAB,
  1507. g_szExtractorStub , g_szNone,
  1508. g_szShowWindow , g_sz0,
  1509. g_szUseLongFileName , g_sz1,
  1510. g_szHideAnimate , g_sz1,
  1511. g_szRebootMode , g_szNoReboot,
  1512. g_szCompressionQuantum, g_szCompressionQuantVal,
  1513. g_szTargetName , g_szTargetNameSection,
  1514. g_szAppLaunched , g_szAppLaunchedSection,
  1515. g_szSourceFiles , g_szSourceFiles,
  1516. g_szPostInstallCmd , g_szNone,
  1517. g_szCompressionType , g_szCompressTypeVal,
  1518. g_szCompressionMemory , g_szCompressionValue
  1519. };
  1520. // Write out [Options] values.
  1521. //
  1522. uCount = sizeof(aszOpt) / sizeof(aszOpt[0]);
  1523. for (idx = 0, bRet = TRUE; (idx < uCount) && bRet; idx++) {
  1524. bRet = WritePrivateProfileString(g_szOptions,
  1525. aszOpt[idx].lpszKey,
  1526. aszOpt[idx].lpszStr,
  1527. pCdfInfo->lpszCdfFile);
  1528. }
  1529. return bRet;
  1530. }
  1531. /*****************************************************************************\
  1532. * cdf_Generate
  1533. *
  1534. * Creates a CDF file and writes it to disk.
  1535. *
  1536. \*****************************************************************************/
  1537. BOOL cdf_Generate(
  1538. PCDFINFO pCdfInfo)
  1539. {
  1540. if (cdf_WriteVersionSection(pCdfInfo) &&
  1541. cdf_WriteOptionsSection(pCdfInfo) &&
  1542. cdf_WriteFilesSection(pCdfInfo)) {
  1543. return TRUE;
  1544. }
  1545. return FALSE;
  1546. }
  1547. /*****************************************************************************\
  1548. * cdfCreate
  1549. *
  1550. * Creates a CDF object.
  1551. *
  1552. * Parameters
  1553. * ----------
  1554. * hinf - Handle to a INF object. The CDF will inherit information from
  1555. * the INF.
  1556. *
  1557. \*****************************************************************************/
  1558. HANDLE cdfCreate(
  1559. HANDLE hinf,
  1560. BOOL bSecure)
  1561. {
  1562. PCDFINFO pCdfInfo;
  1563. if (pCdfInfo = (PCDFINFO)genGAlloc(sizeof(CDFINFO))) {
  1564. // Initialize object-variables.
  1565. //
  1566. pCdfInfo->hInf = hinf;
  1567. pCdfInfo->bSecure = bSecure;
  1568. return (HANDLE) pCdfInfo;
  1569. }
  1570. return NULL;
  1571. }
  1572. /*****************************************************************************\
  1573. * cdfProcess
  1574. *
  1575. * Process the CDF object.
  1576. *
  1577. \*****************************************************************************/
  1578. BOOL cdfProcess(
  1579. HANDLE hcdf)
  1580. {
  1581. HANDLE hFile;
  1582. PCDFINFO pCdfInfo;
  1583. DWORD dwErr;
  1584. if (pCdfInfo = (PCDFINFO)hcdf) {
  1585. if (pCdfInfo->lpszCdfFile = cdf_GetCdfFile(pCdfInfo)) {
  1586. // Check for existence of .cdf file
  1587. //
  1588. hFile = gen_OpenFileRead(pCdfInfo->lpszCdfFile);
  1589. if (hFile && (hFile != INVALID_HANDLE_VALUE)) {
  1590. // If we DO have a .cdf for this printer/architecture,
  1591. // check if it is up to date.
  1592. //
  1593. CloseHandle(hFile);
  1594. // If the .cdf we have is still up to
  1595. // date, we are done.
  1596. //
  1597. if (cdf_IsUpToDate(pCdfInfo)) {
  1598. return TRUE;
  1599. } else {
  1600. // Delete the old .cdf if it exists
  1601. //
  1602. DeleteFile(pCdfInfo->lpszCdfFile);
  1603. CdfGenerate:
  1604. // Generate a new one.
  1605. //
  1606. if (cdf_Generate(pCdfInfo))
  1607. return TRUE;
  1608. }
  1609. } else {
  1610. dwErr = GetLastError();
  1611. // Force an update of our machine ip-addr. Usually,
  1612. // this is called in the cdf_IsUpToDat() to verify
  1613. // the machine hasn't changed ip-addresses.
  1614. //
  1615. genUpdIPAddr();
  1616. // If we don't have a CDF already, generate one now.
  1617. //
  1618. if (dwErr == ERROR_FILE_NOT_FOUND)
  1619. goto CdfGenerate;
  1620. }
  1621. }
  1622. cdfSetError(pCdfInfo,GetLastError());
  1623. }
  1624. return FALSE;
  1625. }
  1626. /*****************************************************************************\
  1627. * cdfDestroy
  1628. *
  1629. * Destroys the CDF object.
  1630. *
  1631. \*****************************************************************************/
  1632. BOOL cdfDestroy(
  1633. HANDLE hcdf)
  1634. {
  1635. PCDFINFO pCdfInfo;
  1636. BOOL bFree = FALSE;
  1637. if (pCdfInfo = (PCDFINFO)hcdf) {
  1638. // Free up any allocated objects.
  1639. //
  1640. if (pCdfInfo->lpszCdfFile)
  1641. genGFree(pCdfInfo->lpszCdfFile, genGSize(pCdfInfo->lpszCdfFile));
  1642. // Walk the list and free the file-item information.
  1643. //
  1644. itm_DeleteAll(pCdfInfo);
  1645. bFree = genGFree(pCdfInfo, sizeof(CDFINFO));
  1646. }
  1647. return bFree;
  1648. }
  1649. /*****************************************************************************\
  1650. * cdfGetName
  1651. *
  1652. * Returns the name of the CDF file. This will not include any path
  1653. * information. This routine derives the filename from the stored full-path
  1654. * name in the CDF object.
  1655. *
  1656. \*****************************************************************************/
  1657. LPCTSTR cdfGetName(
  1658. HANDLE hcdf)
  1659. {
  1660. PCDFINFO pCdfInfo;
  1661. LPCTSTR lpszName = NULL;
  1662. if (pCdfInfo = (PCDFINFO)hcdf) {
  1663. if (lpszName = genFindRChar(pCdfInfo->lpszCdfFile, TEXT('\\')))
  1664. lpszName++;
  1665. }
  1666. return lpszName;
  1667. }
  1668. /*****************************************************************************\
  1669. * cdfGetModTime
  1670. *
  1671. * Returns the time the CDF file was last modified.
  1672. *
  1673. \*****************************************************************************/
  1674. BOOL cdfGetModTime(
  1675. HANDLE hcdf,
  1676. LPFILETIME lpftMod)
  1677. {
  1678. HANDLE hFile;
  1679. PCDFINFO pCdfInfo;
  1680. BOOL bRet = FALSE;
  1681. // Fill in struct-info.
  1682. //
  1683. lpftMod->dwLowDateTime = 0;
  1684. lpftMod->dwHighDateTime = 0;
  1685. // Check the pointer for validity.
  1686. //
  1687. if (pCdfInfo = (PCDFINFO)hcdf) {
  1688. // File should exist at this time, since cdfCreate should always
  1689. // create the file. Return false (error) if can't open file.
  1690. //
  1691. hFile = gen_OpenFileRead(pCdfInfo->lpszCdfFile);
  1692. if (hFile && (hFile != INVALID_HANDLE_VALUE)) {
  1693. // Get the file creation time.
  1694. //
  1695. bRet = GetFileTime(hFile, NULL, NULL, lpftMod);
  1696. CloseHandle(hFile);
  1697. }
  1698. }
  1699. return bRet;
  1700. }
  1701. /*************************************************************************************
  1702. ** cdfCleanUpSourceFiles
  1703. **
  1704. ** This runs through all of the files that we returned from the inf file and in the
  1705. ** case where there was a source we see if it is in the PrtCabs directory, if it is
  1706. ** we delete it
  1707. **
  1708. *************************************************************************************/
  1709. VOID cdfCleanUpSourceFiles(
  1710. HANDLE hInf) {
  1711. LPINFINFO lpInf = (LPINFINFO)hInf;
  1712. if (lpInf) {
  1713. DWORD dwItems = lpInf->lpInfItems->dwCount;
  1714. LPINFITEMINFO lpII = lpInf->lpInfItems;
  1715. LPCTSTR lpszDstPath = infGetDstPath(hInf);
  1716. // This can't be NULL or we wouldn't have allocated the INF structure
  1717. if (*lpszDstPath) { // Might not have been set though
  1718. for (DWORD idx = 0; idx < dwItems; idx++) {
  1719. // We check to see if the file exists as advertised, if it does then we don't
  1720. // change anything, otherwise, we search the system and windows directories to
  1721. // find it, if it exists, we change the path accordingly
  1722. LPTSTR lpszSource = lpII->aItems[idx].szSource;
  1723. if (*lpszSource) { // If there was a source file different to the target
  1724. LPTSTR lpszName = lpII->aItems[idx].szName;
  1725. if (!lstrcmp(lpszName,lpszSource)) { // If we renamed the target to the source
  1726. LPTSTR lpszPath = lpII->aItems[idx].szPath;
  1727. if (!lstrcmp(lpszPath,lpszDstPath)) { // If we set the path on the source
  1728. LPTSTR lpszFile = (LPTSTR)genBuildFileName(lpszPath, lpszName, NULL);
  1729. if (lpszFile) {
  1730. WIN32_FIND_DATA FindFileData;
  1731. HANDLE hFind = FindFirstFile(lpszFile, &FindFileData);
  1732. if (hFind && (hFind != INVALID_HANDLE_VALUE)) {
  1733. FindClose(hFind);
  1734. DeleteFile(lpszFile);
  1735. }
  1736. genGFree(lpszFile, genGSize(lpszFile));
  1737. } // This is cleanup code, no point in failing it
  1738. }
  1739. }
  1740. }
  1741. }
  1742. }
  1743. }
  1744. }