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.

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