2273 lines
65 KiB
C++
2273 lines
65 KiB
C++
|
/*****************************************************************************\
|
||
|
* MODULE: gencdf.c
|
||
|
*
|
||
|
* The module contains routines for generating a CDF (Cabinet Directive File)
|
||
|
* for the IExpress utility.
|
||
|
*
|
||
|
* Work Items:
|
||
|
* ----------
|
||
|
* 1) Redo item-allocations to use single block-heap and append information
|
||
|
* to reduce heap-overhead.
|
||
|
*
|
||
|
*
|
||
|
* Copyright (C) 1996-1997 Microsoft Corporation
|
||
|
* Copyright (C) 1996-1997 Hewlett Packard
|
||
|
*
|
||
|
* History:
|
||
|
* 22-Nov-1996 HWP-Guys Created.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
|
||
|
#include "pch.h"
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_NextStr (Local Routine)
|
||
|
*
|
||
|
* Proceeds to the next string in a section-list.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
_inline LPTSTR cdf_NextStr(
|
||
|
LPTSTR lpszStr)
|
||
|
{
|
||
|
return (lpszStr + (lstrlen(lpszStr) + 1));
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************\
|
||
|
*
|
||
|
* GetDirectory (Local Routine)
|
||
|
*
|
||
|
* Returns the directory portion of a full pathname.
|
||
|
*
|
||
|
\******************************************************************************/
|
||
|
LPTSTR cdf_GetDirectoryWithSlash(LPTSTR lpszFile) {
|
||
|
|
||
|
LPTSTR lpszSlash;
|
||
|
LPTSTR lpszDir;
|
||
|
|
||
|
lpszSlash = genFindRChar(lpszFile, TEXT('\\'));
|
||
|
|
||
|
if (lpszSlash != NULL) {
|
||
|
|
||
|
if (NULL != (lpszDir = (LPTSTR)genGAlloc((UINT32) (lpszSlash - lpszFile + 2) * sizeof(TCHAR)))) {
|
||
|
|
||
|
lstrcpyn(lpszDir, lpszFile, (UINT32) (lpszSlash - lpszFile + 2));
|
||
|
return lpszDir;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/******************************************************************************\
|
||
|
*
|
||
|
* cdf_GetName (Local Routine)
|
||
|
*
|
||
|
* Returns the filename portion of a full pathname.
|
||
|
*
|
||
|
\******************************************************************************/
|
||
|
LPTSTR cdf_GetName(LPTSTR lpszFile) {
|
||
|
|
||
|
LPTSTR lpszSlash;
|
||
|
LPTSTR lpszName;
|
||
|
int nLength;
|
||
|
|
||
|
lpszSlash = genFindRChar(lpszFile, TEXT('\\'));
|
||
|
|
||
|
if (lpszSlash != NULL) {
|
||
|
|
||
|
nLength = lstrlen(lpszSlash);
|
||
|
|
||
|
if (NULL != (lpszName = (LPTSTR)genGAlloc((nLength * sizeof(TCHAR))))) {
|
||
|
|
||
|
lstrcpyn(lpszName, ++lpszSlash, nLength);
|
||
|
return lpszName;
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_SFLAdd (Local Routine)
|
||
|
*
|
||
|
* Adds a new section to our linked-list of sections. This adds it to the
|
||
|
* head of the list and returns a pointer to the new item (head).
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
LPSRCFILES cdf_SFLAdd(
|
||
|
LPSRCFILES psfList,
|
||
|
LPCTSTR lpszPath)
|
||
|
{
|
||
|
LPSRCFILES psfItem;
|
||
|
|
||
|
|
||
|
if (psfItem = (LPSRCFILES)genGAlloc(sizeof(SRCFILES))) {
|
||
|
|
||
|
if (psfItem->lpszPath = genGAllocStr(lpszPath)) {
|
||
|
|
||
|
// Allocate the files-list buffer.
|
||
|
//
|
||
|
if (psfItem->lpszFiles = (LPTSTR)genGAlloc(CDF_SRCFILE_BLOCK)) {
|
||
|
|
||
|
// Position our item at the head.
|
||
|
//
|
||
|
psfItem->cbMax = CDF_SRCFILE_BLOCK;
|
||
|
psfItem->cbSize = 0;
|
||
|
psfItem->pNext = psfList;
|
||
|
|
||
|
|
||
|
// Make sure our file beginning is zeroed.
|
||
|
//
|
||
|
*(psfItem->lpszFiles) = TEXT('\0');
|
||
|
|
||
|
return psfItem;
|
||
|
}
|
||
|
|
||
|
genGFree(psfItem->lpszPath, genGSize(psfItem->lpszPath));
|
||
|
}
|
||
|
|
||
|
genGFree(psfItem, sizeof(SRCFILES));
|
||
|
}
|
||
|
|
||
|
DBGMSG(DBG_ERROR, ("cdf_SFLAdd : Out of memory"));
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_SFLAddFile (Local Routine)
|
||
|
*
|
||
|
* Adds a file-item to the specified section-pointer.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdf_SFLAddFile(
|
||
|
LPSRCFILES psfList,
|
||
|
LPCTSTR lpszFile)
|
||
|
{
|
||
|
LPTSTR lpszList;
|
||
|
LPTSTR lpszPtr;
|
||
|
LPTSTR lpszNew;
|
||
|
DWORD cbSize;
|
||
|
DWORD cbOldSize;
|
||
|
DWORD cbNewSize;
|
||
|
|
||
|
|
||
|
// Determine if adding this file exceeds our current maximum
|
||
|
// buffer. If so, then realloc a bigger chunk. We are adding
|
||
|
// two extra characters to account for the '%' which are to
|
||
|
// be added to the lpszFile.
|
||
|
//
|
||
|
cbSize = (lstrlen(lpszFile) + 1 + 2) * sizeof(TCHAR);
|
||
|
|
||
|
if ((psfList->cbSize + cbSize) >= psfList->cbMax) {
|
||
|
|
||
|
cbOldSize = genGSize(psfList->lpszFiles);
|
||
|
cbNewSize = cbOldSize + CDF_SRCFILE_BLOCK;
|
||
|
|
||
|
lpszNew = (LPTSTR)genGRealloc(psfList->lpszFiles, cbOldSize, cbNewSize);
|
||
|
|
||
|
if (lpszNew == NULL) {
|
||
|
|
||
|
DBGMSG(DBG_ERROR, ("cdf_SFLAddFile : Out of memory"));
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Set new limit criteria.
|
||
|
//
|
||
|
psfList->lpszFiles = lpszNew;
|
||
|
psfList->cbMax = cbNewSize;
|
||
|
}
|
||
|
|
||
|
|
||
|
// We are appending the file to the end of the list.
|
||
|
//
|
||
|
lpszPtr = (LPTSTR)(((LPBYTE)psfList->lpszFiles) + psfList->cbSize);
|
||
|
|
||
|
wsprintf(lpszPtr, TEXT("%%%s%%\0"), lpszFile);
|
||
|
|
||
|
psfList->cbSize += cbSize;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_SFLFind (Local Routine)
|
||
|
*
|
||
|
* Looks for the existence of a section-name.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
LPSRCFILES cdf_SFLFind(
|
||
|
LPSRCFILES psfList,
|
||
|
LPCTSTR lpszPath)
|
||
|
{
|
||
|
while (psfList) {
|
||
|
|
||
|
if (lstrcmpi(psfList->lpszPath, lpszPath) == 0)
|
||
|
return psfList;
|
||
|
|
||
|
psfList = psfList->pNext;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_SFLFree (Local Routine)
|
||
|
*
|
||
|
* Frees up memory associated with the source-file-list.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdf_SFLFree(
|
||
|
LPSRCFILES psfList)
|
||
|
{
|
||
|
LPSRCFILES psfItem;
|
||
|
|
||
|
|
||
|
while (psfList) {
|
||
|
|
||
|
genGFree(psfList->lpszFiles, genGSize(psfList->lpszFiles));
|
||
|
genGFree(psfList->lpszPath , genGSize(psfList->lpszPath));
|
||
|
|
||
|
psfItem = psfList;
|
||
|
psfList = psfList->pNext;
|
||
|
|
||
|
genGFree(psfItem, genGSize(psfItem));
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_WriteStrings
|
||
|
*
|
||
|
* Outputs a string to the [Strings] section.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
_inline BOOL cdf_WriteStrings(
|
||
|
LPCTSTR lpszCdfFile,
|
||
|
LPCTSTR lpszKey,
|
||
|
LPCTSTR lpszStr)
|
||
|
{
|
||
|
return WritePrivateProfileString(g_szStrings, lpszKey, lpszStr, lpszCdfFile);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* itm_InitList (Local Routine)
|
||
|
*
|
||
|
* Initializes the file-item-list.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
_inline VOID itm_InitList(
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
pCdfInfo->pTop = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* itm_GetFirst (Local Routine)
|
||
|
*
|
||
|
* Returns the first PMYITEM in the list
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
_inline PFILEITEM itm_GetFirst(
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
return pCdfInfo->pTop;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* itm_GetNext (Local Routine)
|
||
|
*
|
||
|
* Given the current item, returns the next item in the list.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
_inline PFILEITEM itm_GetNext(
|
||
|
PFILEITEM pMyItem)
|
||
|
{
|
||
|
SPLASSERT((pMyItem != NULL));
|
||
|
|
||
|
return pMyItem->pNext;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* itm_GetString (Local Routine)
|
||
|
*
|
||
|
* Returns a string associated with an item. You pick the
|
||
|
* string by passing the number of the string.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
_inline LPTSTR itm_GetString(
|
||
|
PFILEITEM pMyItem,
|
||
|
UINT nItem)
|
||
|
{
|
||
|
SPLASSERT((pMyItem != NULL));
|
||
|
SPLASSERT((nItem <= FI_COL_LAST));
|
||
|
|
||
|
return pMyItem->aszCols[nItem];
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* itm_FullPath (Local Routine)
|
||
|
*
|
||
|
* Return a fully-qualified pathname for the item.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
_inline LPTSTR itm_FullPath(
|
||
|
PFILEITEM pItem)
|
||
|
{
|
||
|
LPTSTR lpszPath;
|
||
|
LPTSTR lpszFile;
|
||
|
|
||
|
|
||
|
// Gather the strings and build the name.
|
||
|
//
|
||
|
lpszPath = itm_GetString(pItem, FI_COL_PATH);
|
||
|
lpszFile = itm_GetString(pItem, FI_COL_FILENAME);
|
||
|
|
||
|
return genBuildFileName(NULL, lpszPath, lpszFile);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* itm_GetTime (Local Routine)
|
||
|
*
|
||
|
* Returns a time associated with an item.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
_inline FILETIME itm_GetTime(
|
||
|
PFILEITEM pMyItem)
|
||
|
{
|
||
|
SPLASSERT((pMyItem != NULL));
|
||
|
|
||
|
return pMyItem->ftLastModify;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* itm_SetTime (Local Routine)
|
||
|
*
|
||
|
* Sets the last modified time of the item.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
VOID itm_SetTime(
|
||
|
PFILEITEM pMyItem,
|
||
|
FILETIME ftLastModify)
|
||
|
{
|
||
|
SPLASSERT((pMyItem != NULL));
|
||
|
|
||
|
pMyItem->ftLastModify = ftLastModify;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* itm_Last (Local Routine)
|
||
|
*
|
||
|
* Used to end a while loop when we've reached the end of list
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
_inline BOOL itm_Last(
|
||
|
PFILEITEM pMyItem)
|
||
|
{
|
||
|
return (pMyItem == NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* itm_Free (Local Routine)
|
||
|
*
|
||
|
* Frees the memory associated with an item.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
VOID itm_Free(
|
||
|
PFILEITEM pItem)
|
||
|
{
|
||
|
LPTSTR lpszStr;
|
||
|
|
||
|
if (lpszStr = itm_GetString(pItem, FI_COL_FILENAME))
|
||
|
genGFree(lpszStr, genGSize(lpszStr));
|
||
|
|
||
|
if (lpszStr = itm_GetString(pItem, FI_COL_PATH))
|
||
|
genGFree(lpszStr, genGSize(lpszStr));
|
||
|
|
||
|
genGFree(pItem, sizeof(FILEITEM));
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* itm_DeleteAll (Local Routine)
|
||
|
*
|
||
|
* Deletes all the items from our file list.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
VOID itm_DeleteAll(
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
PFILEITEM pMyItem;
|
||
|
PFILEITEM pTempItem;
|
||
|
|
||
|
pMyItem = itm_GetFirst(pCdfInfo);
|
||
|
|
||
|
while (itm_Last(pMyItem) == FALSE) {
|
||
|
|
||
|
pTempItem = pMyItem;
|
||
|
pMyItem = itm_GetNext(pMyItem);
|
||
|
|
||
|
itm_Free(pTempItem);
|
||
|
}
|
||
|
|
||
|
itm_InitList(pCdfInfo);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* itm_Add (Local Routine)
|
||
|
*
|
||
|
* Adds an item to the list.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
PFILEITEM itm_Add(
|
||
|
LPCTSTR lpszFilename,
|
||
|
LPCTSTR lpszPath,
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
PFILEITEM pMyItem;
|
||
|
|
||
|
SPLASSERT((lpszFilename != NULL));
|
||
|
SPLASSERT((lpszPath != NULL));
|
||
|
|
||
|
|
||
|
if (pMyItem = (PFILEITEM)genGAlloc(sizeof(FILEITEM))) {
|
||
|
|
||
|
// Allocate the strings for the path/filename.
|
||
|
//
|
||
|
if (pMyItem->aszCols[FI_COL_FILENAME] = genGAllocStr(lpszFilename)) {
|
||
|
|
||
|
if (pMyItem->aszCols[FI_COL_PATH] = genGAllocStr(lpszPath)) {
|
||
|
|
||
|
pMyItem->pNext = pCdfInfo->pTop;
|
||
|
pCdfInfo->pTop = pMyItem;
|
||
|
|
||
|
return pMyItem;
|
||
|
}
|
||
|
|
||
|
genGFree(pMyItem->aszCols[FI_COL_FILENAME], genGSize(pMyItem->aszCols[FI_COL_FILENAME]));
|
||
|
}
|
||
|
|
||
|
genGFree(pMyItem, sizeof(FILEITEM));
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* itm_Find (Local Routine)
|
||
|
*
|
||
|
* To see if file is already in list
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
PFILEITEM itm_Find(
|
||
|
LPCTSTR lpszFindFile,
|
||
|
PCDFINFO pCdfInfo,
|
||
|
BOOL bMatchFullPath)
|
||
|
{
|
||
|
PFILEITEM pItem = itm_GetFirst(pCdfInfo);
|
||
|
LPTSTR lpszItmFile;
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
|
||
|
// Loop through our list of items looking for a file
|
||
|
// match.
|
||
|
//
|
||
|
while (pItem) {
|
||
|
|
||
|
// Build the file-name from the stored-strings.
|
||
|
//
|
||
|
if (bMatchFullPath)
|
||
|
lpszItmFile = itm_FullPath(pItem);
|
||
|
else
|
||
|
lpszItmFile = itm_GetString(pItem, FI_COL_FILENAME);
|
||
|
|
||
|
if (lpszItmFile) {
|
||
|
|
||
|
// Check for match.
|
||
|
//
|
||
|
if (lstrcmpi(lpszFindFile, lpszItmFile) == 0) {
|
||
|
|
||
|
// Found.
|
||
|
//
|
||
|
if (bMatchFullPath)
|
||
|
genGFree(lpszItmFile, genGSize(lpszItmFile));
|
||
|
|
||
|
return pItem;
|
||
|
}
|
||
|
|
||
|
if (bMatchFullPath)
|
||
|
genGFree(lpszItmFile, genGSize(lpszItmFile));
|
||
|
|
||
|
} else {
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
pItem = itm_GetNext(pItem);
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_WriteTimeStamps
|
||
|
*
|
||
|
* Outputs a struct to the [TimeStamps] section.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
_inline BOOL cdf_WriteTimeStamps(
|
||
|
LPCTSTR lpszCdfFile,
|
||
|
LPCTSTR lpszKey,
|
||
|
LPFILEITEM pFileItem)
|
||
|
{
|
||
|
FILETIME ft = itm_GetTime(pFileItem);
|
||
|
|
||
|
return WritePrivateProfileStruct(g_szTimeStamps, lpszKey, &ft, sizeof(FILETIME), lpszCdfFile);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_WriteSourceFiles
|
||
|
*
|
||
|
* Outputs a struct to the [SourceFiles] section.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
_inline BOOL cdf_WriteSourceFiles(
|
||
|
LPCTSTR lpszCdfFile,
|
||
|
LPCTSTR lpszKey,
|
||
|
LPCTSTR lpszStr)
|
||
|
{
|
||
|
return WritePrivateProfileString(g_szSourceFiles, lpszKey, lpszStr, lpszCdfFile);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_GetSection (Local Routine)
|
||
|
*
|
||
|
* Allocate a buffer which stores either all section-names or the list of
|
||
|
* items specified by (lpszSection) in an INF file. Currently, we attempt
|
||
|
* a realloc if the buffer is not big enough.
|
||
|
*
|
||
|
* NOTE: should we provide a limit for the amount of allocations before
|
||
|
* we accept failure?
|
||
|
*
|
||
|
* 09-Dec-1996 : ChrisWil
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
LPTSTR cdf_GetSection(
|
||
|
LPCTSTR lpszSct,
|
||
|
BOOL bString,
|
||
|
LPCTSTR lpszCdfFile)
|
||
|
{
|
||
|
DWORD dwCnt;
|
||
|
DWORD cch;
|
||
|
DWORD dwSize;
|
||
|
DWORD dwLimit;
|
||
|
LPTSTR lpszNames = NULL;
|
||
|
|
||
|
|
||
|
dwSize = 0;
|
||
|
dwLimit = 0;
|
||
|
|
||
|
while (dwLimit < CDF_SECTION_LIMIT) {
|
||
|
|
||
|
// We'll start this allocation with an assumed max-size. Upon
|
||
|
// successive tries, this buffer is increased each time by the
|
||
|
// original buffer allocation.
|
||
|
//
|
||
|
dwSize += (CDF_SECTION_BLOCK * sizeof(TCHAR));
|
||
|
dwLimit++;
|
||
|
|
||
|
|
||
|
// Alloc the buffer and attempt to get the names.
|
||
|
//
|
||
|
if (lpszNames = (LPTSTR)genGAlloc(dwSize)) {
|
||
|
|
||
|
// If a section-name is profided, use that. Otherwise,
|
||
|
// enumerate all section-names.
|
||
|
//
|
||
|
cch = dwSize / sizeof(TCHAR);
|
||
|
|
||
|
if (bString) {
|
||
|
|
||
|
dwCnt = GetPrivateProfileString(lpszSct,
|
||
|
NULL,
|
||
|
g_szEmptyStr,
|
||
|
lpszNames,
|
||
|
cch,
|
||
|
lpszCdfFile);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
dwCnt = GetPrivateProfileSection(lpszSct,
|
||
|
lpszNames,
|
||
|
cch,
|
||
|
lpszCdfFile);
|
||
|
}
|
||
|
|
||
|
|
||
|
// If the call says the buffer was OK, then we can
|
||
|
// assume the names are retrieved. According to spec's,
|
||
|
// if the return-count is equal to size-2, then buffer
|
||
|
// isn't quite big-enough (two NULL chars).
|
||
|
//
|
||
|
if (dwCnt < (cch - 2))
|
||
|
goto GetSectDone;
|
||
|
|
||
|
|
||
|
genGFree(lpszNames, dwSize);
|
||
|
lpszNames = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GetSectDone:
|
||
|
|
||
|
SPLASSERT((dwLimit < CDF_SECTION_LIMIT));
|
||
|
|
||
|
return lpszNames;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_GetValue (Local Routine)
|
||
|
*
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
LPTSTR cdf_GetValue(
|
||
|
LPCTSTR lpszSection,
|
||
|
LPCTSTR lpszKey,
|
||
|
LPCTSTR lpszCdfFile)
|
||
|
{
|
||
|
TCHAR szBuffer[STD_CDF_BUFFER];
|
||
|
DWORD cch;
|
||
|
LPTSTR lpszVal = NULL;
|
||
|
|
||
|
|
||
|
cch = GetPrivateProfileString(lpszSection,
|
||
|
lpszKey,
|
||
|
g_szEmptyStr,
|
||
|
szBuffer,
|
||
|
COUNTOF(szBuffer),
|
||
|
lpszCdfFile);
|
||
|
|
||
|
SPLASSERT((cch < STD_CDF_BUFFER));
|
||
|
|
||
|
return (cch ? genGAllocStr(szBuffer) : NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_GetCdfFile (Local Routine)
|
||
|
*
|
||
|
* Returns an allocated string to the CDF file (Full-Path)
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
LPTSTR cdf_GetCdfFile(
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
LPCTSTR lpszDstPath;
|
||
|
LPCTSTR lpszDstName;
|
||
|
|
||
|
|
||
|
// Retrieve the strings representing the destination path and name
|
||
|
// of the output file. These strings have already been validated
|
||
|
// by the INF object.
|
||
|
//
|
||
|
lpszDstPath = infGetDstPath(pCdfInfo->hInf);
|
||
|
lpszDstName = infGetDstName(pCdfInfo->hInf);
|
||
|
|
||
|
|
||
|
return genBuildFileName(lpszDstPath, lpszDstName, g_szDotSed);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_GetUncName (Local Routine)
|
||
|
*
|
||
|
* Returns an allocated string to the unc-name.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
LPTSTR cdf_GetUncName(
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
LPCTSTR lpszShrName;
|
||
|
LPTSTR lpszUncName = NULL;
|
||
|
|
||
|
static CONST TCHAR s_szFmt[] = TEXT("\\\\%s\\%s");
|
||
|
|
||
|
|
||
|
if (lpszShrName = infGetShareName(pCdfInfo->hInf)) {
|
||
|
|
||
|
cbSize = lstrlen(g_szPrintServerName) +
|
||
|
lstrlen(lpszShrName) +
|
||
|
lstrlen(s_szFmt) +
|
||
|
1;
|
||
|
|
||
|
if (lpszUncName = (LPTSTR)genGAlloc((cbSize * sizeof(TCHAR))))
|
||
|
wsprintf(lpszUncName, s_szFmt, g_szPrintServerName, lpszShrName);
|
||
|
}
|
||
|
|
||
|
return lpszUncName;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_BuildFriendlyName (Local Routine)
|
||
|
*
|
||
|
* Builds a \\machinename\friendly type string so that the client can
|
||
|
* refer to the printer as "friendly on machinename".
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
LPTSTR cdf_BuildFriendlyName(
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
LPCTSTR lpszFrnName;
|
||
|
LPTSTR lpszPtr;
|
||
|
LPTSTR lpszFmt;
|
||
|
LPTSTR lpszName = NULL;
|
||
|
|
||
|
static TCHAR s_szFmt0[] = TEXT("\\\\http://%s\\%s");
|
||
|
static TCHAR s_szFmt1[] = TEXT("\\\\https://%s\\%s");
|
||
|
|
||
|
|
||
|
if (lpszFrnName = infGetFriendlyName(pCdfInfo->hInf)) {
|
||
|
|
||
|
if (lpszPtr = genFindChar((LPTSTR)lpszFrnName, TEXT('\\'))) {
|
||
|
|
||
|
lpszPtr++;
|
||
|
lpszPtr++;
|
||
|
|
||
|
if (lpszPtr = genFindChar(lpszPtr, TEXT('\\'))) {
|
||
|
|
||
|
// Check if this is a secure request.
|
||
|
//
|
||
|
lpszFmt = (pCdfInfo->bSecure ? s_szFmt1 : s_szFmt0);
|
||
|
|
||
|
|
||
|
// This is the friendly name, not the port name, so we don't
|
||
|
// call GetWebpnpUrl to encode it.
|
||
|
//
|
||
|
cbSize = lstrlen(g_szHttpServerName) +
|
||
|
lstrlen(++lpszPtr) +
|
||
|
lstrlen(lpszFmt) +
|
||
|
1;
|
||
|
|
||
|
if (lpszName = (LPTSTR)genGAlloc(cbSize * sizeof(TCHAR)))
|
||
|
wsprintf(lpszName, lpszFmt, g_szHttpServerName, lpszPtr);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return lpszName;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_ReadFiles (Local Routine)
|
||
|
*
|
||
|
* Reads in the files under the specified src-path-key.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdf_ReadFiles(
|
||
|
LPCTSTR lpszSrcPathKey,
|
||
|
LPCTSTR lpszSrcFiles,
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
FILETIME ftFileTime;
|
||
|
PFILEITEM pFileItem;
|
||
|
LPTSTR lpszPath;
|
||
|
LPTSTR lpszFiles;
|
||
|
LPTSTR lpszFile;
|
||
|
LPTSTR lpszStr;
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
|
||
|
// For the specified SrcKeyPath, read in the list of files
|
||
|
// associated with the path.
|
||
|
//
|
||
|
lpszFiles = cdf_GetSection(lpszSrcPathKey, FALSE, pCdfInfo->lpszCdfFile);
|
||
|
|
||
|
if (lpszFiles) {
|
||
|
|
||
|
// Get the path-value associated with the SrcPathKey.
|
||
|
//
|
||
|
if (lpszPath = cdf_GetValue(lpszSrcFiles, lpszSrcPathKey, pCdfInfo->lpszCdfFile)) {
|
||
|
|
||
|
lpszFile = lpszFiles;
|
||
|
|
||
|
while (*lpszFile) {
|
||
|
|
||
|
// If the first-character doesn't specify a string-type
|
||
|
// then we can add it directly. Otherwise, we're going
|
||
|
// to have to get the file referenced by the string.
|
||
|
//
|
||
|
if (lpszFile[0] != TEXT('%')) {
|
||
|
|
||
|
// Store the path and filename in the list.
|
||
|
//
|
||
|
pFileItem = itm_Add(lpszFile, lpszPath, pCdfInfo);
|
||
|
//
|
||
|
// Fail if we have run out of memory
|
||
|
//
|
||
|
if (!pFileItem)
|
||
|
{
|
||
|
goto ReadFileError;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Read in file timestamp from .cdf.
|
||
|
//
|
||
|
if (GetPrivateProfileStruct(g_szTimeStamps,
|
||
|
lpszFile,
|
||
|
&ftFileTime,
|
||
|
sizeof(FILETIME),
|
||
|
pCdfInfo->lpszCdfFile)) {
|
||
|
// Store the timestamp.
|
||
|
//
|
||
|
itm_SetTime(pFileItem, ftFileTime);
|
||
|
|
||
|
lpszFile = cdf_NextStr(lpszFile);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
goto ReadFileError;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
// Handle %filename% names (localizable strings)
|
||
|
// If the filename is delimited by two percent (%)
|
||
|
// signs,it is not a literal, but needs to be
|
||
|
// looked up [Strings] section of the .cdf file.
|
||
|
//
|
||
|
// Replace the % on the end of the string
|
||
|
// with a null char, then move past the end-char.
|
||
|
//
|
||
|
lpszFile[lstrlen(lpszFile) - 1] = TEXT('\0');
|
||
|
lpszFile++;
|
||
|
|
||
|
|
||
|
lpszStr = cdf_GetValue(g_szStrings,
|
||
|
lpszFile,
|
||
|
pCdfInfo->lpszCdfFile);
|
||
|
|
||
|
if (lpszStr) {
|
||
|
|
||
|
pFileItem = itm_Add(lpszStr, lpszPath, pCdfInfo);
|
||
|
|
||
|
|
||
|
// Read in file timestamp from .cdf
|
||
|
//
|
||
|
GetPrivateProfileStruct(g_szTimeStamps,
|
||
|
lpszFile,
|
||
|
&ftFileTime,
|
||
|
sizeof(FILETIME),
|
||
|
pCdfInfo->lpszCdfFile);
|
||
|
|
||
|
genGFree(lpszStr, genGSize(lpszStr));
|
||
|
|
||
|
itm_SetTime(pFileItem, ftFileTime);
|
||
|
|
||
|
|
||
|
// We add 2 + len of string, because we put in an
|
||
|
// extra null to replace the % char
|
||
|
//
|
||
|
lpszFile = cdf_NextStr(lpszFile) + 1;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
goto ReadFileError;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bRet = TRUE;
|
||
|
|
||
|
ReadFileError:
|
||
|
|
||
|
genGFree(lpszPath, genGSize(lpszPath));
|
||
|
}
|
||
|
|
||
|
genGFree(lpszFiles, genGSize(lpszFiles));
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_ReadFileList (Local Routine)
|
||
|
*
|
||
|
* Reads in the file-list from the CDF-File.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdf_ReadFileList(
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
LPTSTR lpszSrcFiles;
|
||
|
LPTSTR lpszSrcPaths;
|
||
|
LPTSTR lpszPathKey;
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
|
||
|
// Initialize the head of the list.
|
||
|
//
|
||
|
itm_InitList(pCdfInfo);
|
||
|
|
||
|
|
||
|
// Get source files section of .cdf file
|
||
|
//
|
||
|
lpszSrcFiles = cdf_GetValue(g_szOptions,
|
||
|
g_szSourceFiles,
|
||
|
pCdfInfo->lpszCdfFile);
|
||
|
|
||
|
if (lpszSrcFiles) {
|
||
|
|
||
|
// Read in the entire SourceFiles section (as a list of keys).
|
||
|
//
|
||
|
lpszSrcPaths = cdf_GetSection(lpszSrcFiles,
|
||
|
TRUE,
|
||
|
pCdfInfo->lpszCdfFile);
|
||
|
|
||
|
if (lpszPathKey = lpszSrcPaths) {
|
||
|
|
||
|
// Each section name has a path associated with it.
|
||
|
// For each section name, read in and add all the
|
||
|
// files to the list
|
||
|
//
|
||
|
while (*lpszPathKey) {
|
||
|
|
||
|
if (cdf_ReadFiles(lpszPathKey, lpszSrcFiles, pCdfInfo) == FALSE)
|
||
|
goto ReadListExit;
|
||
|
|
||
|
lpszPathKey = cdf_NextStr(lpszPathKey);
|
||
|
}
|
||
|
|
||
|
bRet = TRUE;
|
||
|
|
||
|
ReadListExit:
|
||
|
|
||
|
genGFree(lpszSrcPaths, genGSize(lpszSrcPaths));
|
||
|
}
|
||
|
|
||
|
genGFree(lpszSrcFiles, genGSize(lpszSrcFiles));
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_AddCATFile (Local Routine)
|
||
|
*
|
||
|
* This is called by cdf_GetFileList for each file being added to the cdf.
|
||
|
* It uses the Catalog File Admin APIs to determine if the driver file was installed
|
||
|
* with an associated catalog file. If a corresponding catalog file (or files)
|
||
|
* is found, the catalog filename (or filenames), along with its timestamp,
|
||
|
* is added to the cdf file list.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdf_AddCATFile(LPTSTR lpszFile, LPCDFINFO pCdfInfo ) {
|
||
|
|
||
|
HCATADMIN hCatAdmin = pCdfInfo->hCatAdmin;
|
||
|
HCATINFO hCatInfo = NULL;
|
||
|
CATALOG_INFO CatInfo;
|
||
|
BYTE * pbHash;
|
||
|
DWORD dwBytes;
|
||
|
WIN32_FIND_DATA ffd;
|
||
|
PFILEITEM pFileItem;
|
||
|
HANDLE hFind, hFile;
|
||
|
LPTSTR pFullPath, pPath, pName;
|
||
|
|
||
|
// Find the catalog file associated with this file.
|
||
|
// If we can't find one, that's OK, it's not an error, just a file
|
||
|
// with no associated .cat file. The user can decide on the client-end
|
||
|
// whether or not he wants to install without the verification a .cat file
|
||
|
// would provide...
|
||
|
//
|
||
|
if (INVALID_HANDLE_VALUE != (HANDLE)hCatAdmin) {
|
||
|
|
||
|
hFind = FindFirstFile(lpszFile, &ffd);
|
||
|
|
||
|
if (hFind && (hFind != INVALID_HANDLE_VALUE)) {
|
||
|
|
||
|
FindClose(hFind);
|
||
|
|
||
|
// Open the file in order to hash it.
|
||
|
//
|
||
|
if (INVALID_HANDLE_VALUE != (hFile = CreateFile(lpszFile,
|
||
|
GENERIC_READ,
|
||
|
FILE_SHARE_READ,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL))) {
|
||
|
|
||
|
// Determine how many bytes we need for the hash
|
||
|
//
|
||
|
dwBytes = 0;
|
||
|
pbHash = NULL;
|
||
|
CryptCATAdminCalcHashFromFileHandle(hFile, &dwBytes, pbHash, 0);
|
||
|
|
||
|
if (NULL != (pbHash = (BYTE *)genGAlloc(dwBytes))) {
|
||
|
|
||
|
// Compute the hash for this file
|
||
|
//
|
||
|
if (CryptCATAdminCalcHashFromFileHandle(hFile, &dwBytes, pbHash, 0)) {
|
||
|
|
||
|
// Get the catalog file(s) associated with this file hash
|
||
|
//
|
||
|
hCatInfo = NULL;
|
||
|
|
||
|
do {
|
||
|
|
||
|
hCatInfo = CryptCATAdminEnumCatalogFromHash(hCatAdmin, pbHash, dwBytes, 0, &hCatInfo);
|
||
|
|
||
|
if (NULL != hCatInfo) {
|
||
|
|
||
|
// Split the cat name into file and path here
|
||
|
//
|
||
|
if (CryptCATCatalogInfoFromContext(hCatInfo, &CatInfo, NULL)) {
|
||
|
|
||
|
if (NULL != (pFullPath = genTCFromWC(CatInfo.wszCatalogFile))) {
|
||
|
|
||
|
if (NULL != (pPath = cdf_GetDirectoryWithSlash(pFullPath))) {
|
||
|
|
||
|
if (NULL != (pName = cdf_GetName(pFullPath))) {
|
||
|
|
||
|
// Make sure the file is not already in the cdf, so
|
||
|
// IExpress doesn't give out (see BUG: explanation in cdf_GetFileList() )
|
||
|
//
|
||
|
if (NULL == itm_Find(pName, pCdfInfo, FALSE)) {
|
||
|
// Add the catalog file and timestamp
|
||
|
|
||
|
pFileItem = itm_Add(pName, pPath, pCdfInfo);
|
||
|
itm_SetTime(pFileItem, ffd.ftLastWriteTime);
|
||
|
}
|
||
|
|
||
|
genGFree(pName, genGSize(pName) );
|
||
|
}
|
||
|
|
||
|
genGFree(pPath, genGSize(pPath) );
|
||
|
}
|
||
|
|
||
|
genGFree(pFullPath, genGSize(pFullPath) );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
} while (NULL != hCatInfo);
|
||
|
|
||
|
}
|
||
|
|
||
|
genGFree(pbHash, dwBytes);
|
||
|
}
|
||
|
|
||
|
CloseHandle(hFile);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_GetFileList (Local Routine)
|
||
|
*
|
||
|
* This is a callback function passed to infEnumItems()
|
||
|
* It reads in the list of files from the INF object, and reads
|
||
|
* the filetimes from the disk and adds these to the list also.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL CALLBACK cdf_GetFileList(
|
||
|
LPCTSTR lpszName,
|
||
|
LPCTSTR lpszPath,
|
||
|
BOOL bInf,
|
||
|
LPVOID lpData)
|
||
|
{
|
||
|
PCDFINFO pCdfInfo = (PCDFINFO)lpData;
|
||
|
HANDLE hFind;
|
||
|
PFILEITEM pFileItem;
|
||
|
LPTSTR lpszFile;
|
||
|
LPTSTR lpszPtr;
|
||
|
WIN32_FIND_DATA FindFileData;
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
// Build fully qualified file name.
|
||
|
//
|
||
|
if (lpszFile = genBuildFileName(lpszPath, lpszName, NULL)) {
|
||
|
|
||
|
hFind = FindFirstFile(lpszFile, &FindFileData);
|
||
|
|
||
|
if (hFind && (hFind != INVALID_HANDLE_VALUE)) {
|
||
|
|
||
|
FindClose(hFind);
|
||
|
|
||
|
// BUG : IExpress craps out when it encounters the
|
||
|
// same filename twice. To work-around this,
|
||
|
// we will prevent the inclusion of the second
|
||
|
// file. We will match the name-only.
|
||
|
//
|
||
|
if (itm_Find(lpszName, pCdfInfo, FALSE) == NULL) {
|
||
|
|
||
|
// Add the item to the list of CDF-Files. We
|
||
|
// store the path-name with the trailing '\'
|
||
|
// because the CDF format requires such.
|
||
|
//
|
||
|
lpszPtr = genFindRChar(lpszFile, TEXT('\\'));
|
||
|
|
||
|
// Is filename of right format?
|
||
|
//
|
||
|
if ( lpszPtr != NULL ) {
|
||
|
|
||
|
*(++lpszPtr) = TEXT('\0');
|
||
|
pFileItem = itm_Add(lpszName, lpszFile, pCdfInfo);
|
||
|
|
||
|
|
||
|
// Set the item-time. This should only fail if we couldn't allocate memory
|
||
|
//
|
||
|
if (pFileItem != NULL) {
|
||
|
itm_SetTime(pFileItem, FindFileData.ftLastWriteTime);
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
}
|
||
|
else
|
||
|
bRet = TRUE; // Item already exits, so TRUE
|
||
|
}
|
||
|
|
||
|
genGFree(lpszFile, genGSize(lpszFile));
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_CheckFiles (Local Routine)
|
||
|
*
|
||
|
* This is a callback function passed to infEnumItems()
|
||
|
* It checks each filename to see if it is in the .cdf list,
|
||
|
* and if it is up to date.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL CALLBACK cdf_CheckFiles(
|
||
|
LPCTSTR lpszName,
|
||
|
LPCTSTR lpszPath,
|
||
|
BOOL bInfFile,
|
||
|
LPVOID lpData)
|
||
|
{
|
||
|
PCDFINFO pCdfInfo = (PCDFINFO)lpData;
|
||
|
HANDLE hFind;
|
||
|
PFILEITEM pFileItem;
|
||
|
LPTSTR lpszFile;
|
||
|
LPTSTR lpszPtr;
|
||
|
WIN32_FIND_DATA FindFileData;
|
||
|
LONG lCompare;
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
|
||
|
// Build fully qualified filename.
|
||
|
//
|
||
|
if (lpszFile = genBuildFileName(lpszPath, lpszName, NULL)) {
|
||
|
|
||
|
// Locate the item, and see if the dates are out-of-sync.
|
||
|
//
|
||
|
if (pFileItem = itm_Find(lpszFile, pCdfInfo, TRUE)) {
|
||
|
|
||
|
hFind = FindFirstFile(lpszFile, &FindFileData);
|
||
|
|
||
|
if (hFind && (hFind != INVALID_HANDLE_VALUE)) {
|
||
|
|
||
|
FindClose(hFind);
|
||
|
|
||
|
|
||
|
// Compare the file-times.
|
||
|
//
|
||
|
lCompare = CompareFileTime(&FindFileData.ftLastWriteTime,
|
||
|
&pFileItem->ftLastModify);
|
||
|
|
||
|
|
||
|
// Skip over INF files since we are generating
|
||
|
// these in the INF object.
|
||
|
//
|
||
|
if (bInfFile || (lCompare == 0))
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
genGFree(lpszFile, genGSize(lpszFile));
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_get_datfile
|
||
|
*
|
||
|
* Returns the then name of the dat-file. The name built incorporates
|
||
|
* the sharename to distinguish it from other dat-files in the directory.
|
||
|
* any other files.
|
||
|
*
|
||
|
* <path>\<Share ChkSum>.dat
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
LPTSTR cdf_get_datfile(
|
||
|
LPCTSTR lpszDstPath,
|
||
|
LPCTSTR lpszShrName)
|
||
|
{
|
||
|
int cch;
|
||
|
TCHAR szName[MIN_CDF_BUFFER];
|
||
|
|
||
|
|
||
|
// Build the name using the checksum.
|
||
|
//
|
||
|
cch = wsprintf(szName, g_szDatName, genChkSum(lpszShrName));
|
||
|
|
||
|
SPLASSERT((cch < sizeof(szName)));
|
||
|
|
||
|
return genBuildFileName(lpszDstPath, szName, g_szDotDat);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_IsDatCurrent (Local Routine)
|
||
|
*
|
||
|
* Checks the port-name in the dat-file for match. If they do not, then we
|
||
|
* need to return FALSE to proceed with a new cab-generation.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdf_IsDatCurrent(
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
LPCTSTR lpszPrtName;
|
||
|
LPCTSTR lpszDstPath;
|
||
|
LPCTSTR lpszShrName;
|
||
|
LPTSTR lpszDatFile;
|
||
|
LPTSTR lpszDat;
|
||
|
LPTSTR lpszPtr;
|
||
|
LPTSTR lpszEnd;
|
||
|
DWORD cbSize;
|
||
|
DWORD cbRd;
|
||
|
HANDLE hFile;
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
|
||
|
// Get the information from the INF-object so we can determine the
|
||
|
// age of the dat-file.
|
||
|
//
|
||
|
lpszDstPath = infGetDstPath(pCdfInfo->hInf);
|
||
|
lpszPrtName = infGetPrtName(pCdfInfo->hInf);
|
||
|
lpszShrName = infGetShareName(pCdfInfo->hInf);
|
||
|
|
||
|
|
||
|
// Build the dat-file-name and open for reading.
|
||
|
//
|
||
|
if (lpszDatFile = cdf_get_datfile(lpszDstPath, lpszShrName)) {
|
||
|
|
||
|
hFile = gen_OpenFileRead(lpszDatFile);
|
||
|
|
||
|
if (hFile && (hFile != INVALID_HANDLE_VALUE)) {
|
||
|
|
||
|
cbSize = GetFileSize(hFile, NULL);
|
||
|
|
||
|
if (lpszDat = (LPTSTR)genGAlloc(cbSize)) {
|
||
|
|
||
|
if (ReadFile(hFile, lpszDat, cbSize, &cbRd, NULL)) {
|
||
|
|
||
|
lpszPtr = lpszDat;
|
||
|
|
||
|
while (lpszPtr = genFindChar(lpszPtr, TEXT('/'))) {
|
||
|
|
||
|
if (*(++lpszPtr) == TEXT('r')) {
|
||
|
|
||
|
lpszPtr++; // space
|
||
|
lpszPtr++; // quote
|
||
|
|
||
|
if (lpszEnd = genFindChar(++lpszPtr, TEXT('\"'))) {
|
||
|
|
||
|
*lpszEnd = TEXT('\0');
|
||
|
|
||
|
if (lstrcmpi(lpszPtr, lpszPrtName) == 0)
|
||
|
bRet = TRUE;
|
||
|
|
||
|
*lpszEnd = TEXT('\"');
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Position pointer to the next flag.
|
||
|
//
|
||
|
lpszPtr = genFindChar(lpszPtr, TEXT('\n'));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
genGFree(lpszDat, cbSize);
|
||
|
}
|
||
|
|
||
|
CloseHandle(hFile);
|
||
|
}
|
||
|
|
||
|
genGFree(lpszDatFile, genGSize(lpszDatFile));
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_IsUpToDate (Local Routine)
|
||
|
*
|
||
|
* Determines if the CDF is up-to-date, or needs to be regenerated for
|
||
|
* this printer
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdf_IsUpToDate(
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
BOOL bCurrent = FALSE;
|
||
|
|
||
|
|
||
|
if (genUpdIPAddr()) {
|
||
|
|
||
|
if (cdf_IsDatCurrent(pCdfInfo)) {
|
||
|
|
||
|
// Read filelist into CdfInfo structure from .cdf file
|
||
|
//
|
||
|
if (cdf_ReadFileList(pCdfInfo)) {
|
||
|
|
||
|
// Check files in .inf file to see if .cdf is still valid.
|
||
|
//
|
||
|
if (infEnumItems(pCdfInfo->hInf, cdf_CheckFiles, (LPVOID)pCdfInfo))
|
||
|
bCurrent = TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bCurrent;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_EnumICM (Local Routine)
|
||
|
*
|
||
|
* Callback to enumerate all ICM profiles in the BIN-File. We only need to
|
||
|
* add these profiles to our list of CDF-Files that we package up.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL CALLBACK cdf_EnumICM(
|
||
|
LPCTSTR lpszPath,
|
||
|
LPCTSTR lpszFile,
|
||
|
LPVOID lpParm)
|
||
|
{
|
||
|
return cdf_GetFileList(lpszFile, lpszPath, FALSE, lpParm);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_WriteSourceFilesSection (Local Routine)
|
||
|
*
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdf_WriteSourceFilesSection(
|
||
|
PCDFINFO pCdfInfo,
|
||
|
LPSRCFILES psfList)
|
||
|
{
|
||
|
TCHAR szSection[STD_CDF_BUFFER];
|
||
|
DWORD cch;
|
||
|
int idx;
|
||
|
BOOL bRet;
|
||
|
|
||
|
|
||
|
for (idx = 0, bRet = TRUE; psfList; psfList = psfList->pNext) {
|
||
|
|
||
|
// Build the section name (i.e. SourceFilesX).
|
||
|
//
|
||
|
cch = wsprintf(szSection, TEXT("%s%i"), g_szSourceFiles, idx++);
|
||
|
|
||
|
SPLASSERT((cch < STD_CDF_BUFFER));
|
||
|
|
||
|
|
||
|
// Write the source file section name in the [SourceFiles]
|
||
|
// section.
|
||
|
//
|
||
|
bRet = cdf_WriteSourceFiles(pCdfInfo->lpszCdfFile,
|
||
|
szSection,
|
||
|
psfList->lpszPath);
|
||
|
|
||
|
|
||
|
// Write out the [SourceFilesX] section.
|
||
|
//
|
||
|
if (bRet) {
|
||
|
|
||
|
bRet = WritePrivateProfileSection(szSection,
|
||
|
psfList->lpszFiles,
|
||
|
pCdfInfo->lpszCdfFile);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_WriteBinFile (Local Routine)
|
||
|
*
|
||
|
* Writes the .BIN file.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdf_WriteBinFile(
|
||
|
PCDFINFO pCdfInfo,
|
||
|
LPCTSTR lpszDstPath,
|
||
|
LPCTSTR lpszDstName)
|
||
|
{
|
||
|
LPCTSTR lpszFriendlyName;
|
||
|
LPTSTR lpszBinFile;
|
||
|
LPTSTR lpszBinName;
|
||
|
HANDLE hPrinter;
|
||
|
DWORD dwCliInfo;
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
|
||
|
if (lpszBinFile = genBuildFileName(lpszDstPath, lpszDstName, g_szDotBin)) {
|
||
|
|
||
|
if (lpszBinName = genFindRChar(lpszBinFile, TEXT('\\'))) {
|
||
|
|
||
|
// Increment to the next character for the name.
|
||
|
//
|
||
|
lpszBinName++;
|
||
|
|
||
|
|
||
|
// Retrieve the printer-handle and proceed
|
||
|
// to write the information to the BIN-File.
|
||
|
//
|
||
|
if (lpszFriendlyName = infGetFriendlyName(pCdfInfo->hInf)) {
|
||
|
|
||
|
if (OpenPrinter((LPTSTR)lpszFriendlyName, &hPrinter, NULL)) {
|
||
|
|
||
|
dwCliInfo = infGetCliInfo(pCdfInfo->hInf);
|
||
|
|
||
|
// Call the routine to generate the BIN-File.
|
||
|
//
|
||
|
if (webWritePrinterInfo(hPrinter, lpszBinFile)) {
|
||
|
|
||
|
// Add the bin-file to the list of CDF-Files.
|
||
|
// Then add ICM-profiles to our list.
|
||
|
//
|
||
|
if (cdf_GetFileList(lpszBinName, lpszDstPath, FALSE, (LPVOID)pCdfInfo)) {
|
||
|
|
||
|
bRet = webEnumPrinterInfo(hPrinter,
|
||
|
dwCliInfo,
|
||
|
WEB_ENUM_ICM,
|
||
|
(FARPROC)cdf_EnumICM,
|
||
|
(LPVOID)pCdfInfo);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Close the printer.
|
||
|
//
|
||
|
ClosePrinter(hPrinter);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
genGFree(lpszBinFile, genGSize(lpszBinFile));
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_WriteCdfCmd (Local Routine)
|
||
|
*
|
||
|
* Writes the .DAT file.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdf_WriteCdfCmd(
|
||
|
PCDFINFO pCdfInfo,
|
||
|
LPCTSTR lpszUncName,
|
||
|
LPCTSTR lpszDstPath,
|
||
|
LPCTSTR lpszDstName)
|
||
|
{
|
||
|
HANDLE hFile;
|
||
|
LPWSTR lpszCmd;
|
||
|
LPTSTR lpszTmp;
|
||
|
LPTSTR lpszBinName;
|
||
|
LPTSTR lpszDatFile;
|
||
|
LPTSTR lpszDatTmp;
|
||
|
LPTSTR lpszFrnName;
|
||
|
LPCTSTR lpszDrvName;
|
||
|
LPCTSTR lpszPrtName;
|
||
|
LPCTSTR lpszInfName;
|
||
|
LPCTSTR lpszShrName;
|
||
|
DWORD dwWr;
|
||
|
DWORD cbSize;
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
|
||
|
// Retrive the destination-file info. These strings have
|
||
|
// already been validated by the INF object.
|
||
|
//
|
||
|
lpszDrvName = infGetDrvName(pCdfInfo->hInf);
|
||
|
lpszPrtName = infGetPrtName(pCdfInfo->hInf);
|
||
|
lpszInfName = infGetInfName(pCdfInfo->hInf);
|
||
|
lpszShrName = infGetShareName(pCdfInfo->hInf);
|
||
|
|
||
|
|
||
|
// Build the dat-file.
|
||
|
//
|
||
|
if (lpszDatFile = cdf_get_datfile(lpszDstPath, lpszShrName)) {
|
||
|
|
||
|
// This is a temporary duplicate of the (lpszDatFile) that
|
||
|
// will be written to the cdf-command. This is necessary so
|
||
|
// that the client can have a static-name to use when the
|
||
|
// cab is expanded.
|
||
|
//
|
||
|
if (lpszDatTmp = genBuildFileName(lpszDstPath, g_szDatFile, NULL)) {
|
||
|
|
||
|
if (lpszBinName = genBuildFileName(NULL, lpszDstName, g_szDotBin)) {
|
||
|
|
||
|
if (lpszFrnName = cdf_BuildFriendlyName(pCdfInfo)) {
|
||
|
|
||
|
// Write out the devmode. If the DEVMODE-file (BIN) was
|
||
|
// written correctly, then we will go ahead and generate the
|
||
|
// dat-command-file.
|
||
|
//
|
||
|
if (cdf_WriteBinFile(pCdfInfo, lpszDstPath, lpszDstName)) {
|
||
|
|
||
|
cbSize = lstrlen(lpszFrnName) +
|
||
|
lstrlen(lpszInfName) +
|
||
|
lstrlen(lpszPrtName) +
|
||
|
lstrlen(lpszDrvName) +
|
||
|
lstrlen(lpszUncName) +
|
||
|
lstrlen(lpszBinName) +
|
||
|
lstrlen(g_szDatCmd) +
|
||
|
sizeof(WCHAR);
|
||
|
|
||
|
if (lpszTmp = (LPTSTR)genGAlloc(cbSize * sizeof(TCHAR))) {
|
||
|
|
||
|
// Build the Data-command.
|
||
|
//
|
||
|
wsprintf(lpszTmp,
|
||
|
g_szDatCmd,
|
||
|
lpszFrnName,
|
||
|
lpszInfName,
|
||
|
lpszPrtName,
|
||
|
lpszDrvName,
|
||
|
lpszUncName,
|
||
|
lpszBinName);
|
||
|
|
||
|
|
||
|
// Open the file for writing.
|
||
|
//
|
||
|
hFile = gen_OpenFileWrite(lpszDatFile);
|
||
|
|
||
|
if (hFile && (hFile != INVALID_HANDLE_VALUE)) {
|
||
|
|
||
|
// This is here to assure the file written
|
||
|
// is in byte-format. Otherwise, our strings
|
||
|
// written to the file would be in unicode
|
||
|
// format.
|
||
|
//
|
||
|
#ifdef UNICODE
|
||
|
if (lpszCmd = genGAllocStr(lpszTmp)) {
|
||
|
#else
|
||
|
if (lpszCmd = genWCFromMB(lpszTmp)) {
|
||
|
#endif
|
||
|
cbSize = (DWORD)SIGNATURE_UNICODE;
|
||
|
WriteFile(hFile, &cbSize, sizeof(WORD), &dwWr, NULL);
|
||
|
|
||
|
cbSize = genGSize(lpszCmd);
|
||
|
WriteFile(hFile, lpszCmd, cbSize, &dwWr, NULL);
|
||
|
|
||
|
genGFree(lpszCmd, genGSize(lpszCmd));
|
||
|
}
|
||
|
|
||
|
|
||
|
CloseHandle(hFile);
|
||
|
|
||
|
|
||
|
// Make a copy of the file to a static name
|
||
|
// that will be used in the cdf/cab file.
|
||
|
//
|
||
|
CopyFile(lpszDatFile, lpszDatTmp, FALSE);
|
||
|
|
||
|
|
||
|
// Add the DAT-File to the list of CDF-Files. Use
|
||
|
// the temporary file so that it is a static name
|
||
|
// as opposed to our check-sum generated file.
|
||
|
//
|
||
|
bRet = cdf_GetFileList(g_szDatFile,
|
||
|
lpszDstPath,
|
||
|
FALSE,
|
||
|
(LPVOID)pCdfInfo);
|
||
|
}
|
||
|
|
||
|
genGFree(lpszTmp, genGSize(lpszTmp));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
genGFree(lpszFrnName, genGSize(lpszFrnName));
|
||
|
}
|
||
|
|
||
|
genGFree(lpszBinName, genGSize(lpszBinName));
|
||
|
}
|
||
|
|
||
|
genGFree(lpszDatTmp, genGSize(lpszDatTmp));
|
||
|
}
|
||
|
|
||
|
genGFree(lpszDatFile, genGSize(lpszDatFile));
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
** cdf_GenerateSourceFiles (local routine)
|
||
|
**
|
||
|
** Find cases where the source and installed file names are diferent, copy the
|
||
|
** installed file to the cabs directory and rename it to the original target file
|
||
|
** name.
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
BOOL cdf_GenerateSourceFiles(
|
||
|
HANDLE hInf,
|
||
|
LPCTSTR lpszDstDir) {
|
||
|
|
||
|
LPINFINFO lpInf = (LPINFINFO)hInf;
|
||
|
BOOL bRet = lpInf != NULL;
|
||
|
|
||
|
if (bRet) {
|
||
|
DWORD dwItems = lpInf->lpInfItems->dwCount;
|
||
|
LPINFITEMINFO lpII = lpInf->lpInfItems;
|
||
|
|
||
|
for (DWORD idx = 0; idx < dwItems && bRet; idx++) {
|
||
|
// We check to see if the file exists as advertised, if it does then we don't
|
||
|
// change anything, otherwise, we search the system and windows directories to
|
||
|
// find it, if it exists, we change the path accordingly
|
||
|
LPTSTR lpszSource = lpII->aItems[idx].szSource;
|
||
|
|
||
|
if (*lpszSource) { // There was a source name, we know it is different
|
||
|
// from the target
|
||
|
LPTSTR lpszName = lpII->aItems[idx].szName;
|
||
|
LPTSTR lpszPath = lpII->aItems[idx].szPath;
|
||
|
LPTSTR lpszFile = genBuildFileName( lpszPath, lpszName, NULL);
|
||
|
LPTSTR lpszDestFile = genBuildFileName( lpszDstDir, lpszSource, NULL);
|
||
|
|
||
|
if (lpszFile && lpszDestFile) {
|
||
|
lstrcpyn( lpszPath, lpszDstDir, MAX_PATH);
|
||
|
lstrcpyn( lpszName, lpszSource, INF_MIN_BUFFER);
|
||
|
|
||
|
bRet = CopyFile( lpszFile, lpszDestFile, FALSE);
|
||
|
} else
|
||
|
bRet = FALSE;
|
||
|
|
||
|
if (lpszFile)
|
||
|
genGFree(lpszFile, genGSize(lpszFile));
|
||
|
|
||
|
if (lpszDestFile)
|
||
|
genGFree(lpszDestFile, genGSize(lpszDestFile) );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_WriteFilesSection (Local Routine)
|
||
|
*
|
||
|
* Writes the dynamic file information.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdf_WriteFilesSection(
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
TCHAR szFileX[MIN_CDF_BUFFER];
|
||
|
LPCTSTR lpszDstName;
|
||
|
LPCTSTR lpszDstPath;
|
||
|
LPTSTR lpszUncName;
|
||
|
LPTSTR lpszTmp;
|
||
|
LPTSTR lpszItem;
|
||
|
DWORD cbSize;
|
||
|
int idx;
|
||
|
int idxFile;
|
||
|
PFILEITEM pFileItem;
|
||
|
LPSRCFILES psfList;
|
||
|
LPSRCFILES psfItem;
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
|
||
|
static CONST TCHAR s_szFmt0[] = TEXT("\"%s\\%s.webpnp\"");
|
||
|
static CONST TCHAR s_szFmt1[] = TEXT("\"%s\"");
|
||
|
|
||
|
|
||
|
if (lpszUncName = cdf_GetUncName(pCdfInfo)) {
|
||
|
|
||
|
// Retreive the necessary strings from the INF object. These
|
||
|
// should already be validated as existing. Otherwise, the creation
|
||
|
// of the INF object would've failed.
|
||
|
//
|
||
|
lpszDstName = infGetDstName(pCdfInfo->hInf);
|
||
|
lpszDstPath = infGetDstPath(pCdfInfo->hInf);
|
||
|
|
||
|
|
||
|
// Build the TargetName and write to the CDF.
|
||
|
//
|
||
|
cbSize = lstrlen(lpszDstPath) +
|
||
|
lstrlen(lpszDstName) +
|
||
|
lstrlen(s_szFmt0) +
|
||
|
1;
|
||
|
|
||
|
if (lpszTmp = (LPTSTR)genGAlloc(cbSize * sizeof(TCHAR))) {
|
||
|
wsprintf(lpszTmp, s_szFmt0, lpszDstPath, lpszDstName);
|
||
|
bRet = cdf_WriteStrings(pCdfInfo->lpszCdfFile, g_szTargetName, lpszTmp);
|
||
|
genGFree(lpszTmp, genGSize(lpszTmp));
|
||
|
}
|
||
|
|
||
|
|
||
|
// Now build cdf-install command; Write it to the CDF.
|
||
|
//
|
||
|
cbSize = lstrlen(lpszDstName) + lstrlen(g_szSedCmd) + 1;
|
||
|
|
||
|
if (bRet && (lpszTmp = (LPTSTR)genGAlloc(cbSize * sizeof(TCHAR)))) {
|
||
|
wsprintf(lpszTmp, g_szSedCmd, lpszDstName);
|
||
|
bRet = cdf_WriteStrings(pCdfInfo->lpszCdfFile, g_szAppLaunched, lpszTmp);
|
||
|
genGFree(lpszTmp, genGSize(lpszTmp));
|
||
|
}
|
||
|
|
||
|
|
||
|
// Read in all files and filetimes from .inf file (inf object)
|
||
|
// Initialize the list.
|
||
|
//
|
||
|
itm_DeleteAll(pCdfInfo);
|
||
|
itm_InitList(pCdfInfo);
|
||
|
|
||
|
|
||
|
// Add all the files enumerated by the inf object.
|
||
|
// Note: This enumeration includes the inf file itself, so
|
||
|
// no need to make a special case for it.
|
||
|
//
|
||
|
if (bRet)
|
||
|
bRet = cdf_GenerateSourceFiles( pCdfInfo->hInf, lpszDstPath );
|
||
|
|
||
|
if (bRet) {
|
||
|
if (infEnumItems(pCdfInfo->hInf, cdf_GetFileList, (LPVOID)pCdfInfo)) {
|
||
|
|
||
|
|
||
|
// Generate the command-line for the URL rundll interface.
|
||
|
//
|
||
|
bRet = cdf_WriteCdfCmd(pCdfInfo,
|
||
|
lpszUncName,
|
||
|
lpszDstPath,
|
||
|
lpszDstName);
|
||
|
|
||
|
|
||
|
// Initialize the pointers/indexes that are used
|
||
|
// to track our section information.
|
||
|
//
|
||
|
idxFile = 0;
|
||
|
pFileItem = itm_GetFirst(pCdfInfo);
|
||
|
psfList = NULL;
|
||
|
|
||
|
|
||
|
// If the enumeration succeeded and we have files in the
|
||
|
// list to process, then proceed to build our sections.
|
||
|
//
|
||
|
while (bRet && pFileItem) {
|
||
|
|
||
|
// Build our FILEx string.
|
||
|
//
|
||
|
wsprintf(szFileX, TEXT("FILE%i"), idxFile++);
|
||
|
|
||
|
|
||
|
// Write out the quoted-item.
|
||
|
//
|
||
|
lpszItem = itm_GetString(pFileItem, FI_COL_FILENAME);
|
||
|
|
||
|
cbSize = lstrlen(lpszItem) + lstrlen(s_szFmt1) + 1;
|
||
|
|
||
|
if (lpszTmp = (LPTSTR)genGAlloc(cbSize * sizeof(TCHAR))) {
|
||
|
wsprintf(lpszTmp, s_szFmt1, lpszItem);
|
||
|
bRet = cdf_WriteStrings(pCdfInfo->lpszCdfFile, szFileX, lpszTmp);
|
||
|
genGFree(lpszTmp, genGSize(lpszTmp));
|
||
|
}
|
||
|
|
||
|
|
||
|
// Add timestamp to [TimeStamps] section for this file.
|
||
|
//
|
||
|
if (bRet) {
|
||
|
|
||
|
bRet = cdf_WriteTimeStamps(pCdfInfo->lpszCdfFile,
|
||
|
szFileX,
|
||
|
pFileItem);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Look for existence of section (path). If it exists,
|
||
|
// add the file to the section. Otherwise, create a
|
||
|
// new section and add the file.
|
||
|
//
|
||
|
if (bRet) {
|
||
|
|
||
|
lpszItem = itm_GetString(pFileItem, FI_COL_PATH);
|
||
|
|
||
|
if ((psfItem = cdf_SFLFind(psfList, lpszItem)) == NULL) {
|
||
|
|
||
|
if (psfItem = cdf_SFLAdd(psfList, lpszItem)) {
|
||
|
|
||
|
psfList = psfItem;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Add the file to the appropriate section.
|
||
|
//
|
||
|
if (bRet)
|
||
|
bRet = cdf_SFLAddFile(psfItem, szFileX);
|
||
|
|
||
|
// Get next file-item.
|
||
|
//
|
||
|
pFileItem = itm_GetNext(pFileItem);
|
||
|
|
||
|
}
|
||
|
|
||
|
// If all went OK in the enumeration, then we can write
|
||
|
// the sections to the CDF file.
|
||
|
//
|
||
|
|
||
|
|
||
|
if (bRet)
|
||
|
bRet = cdf_WriteSourceFilesSection(pCdfInfo, psfList);
|
||
|
|
||
|
// Free up the Source-Files-List.
|
||
|
//
|
||
|
cdf_SFLFree(psfList);
|
||
|
|
||
|
|
||
|
} else
|
||
|
bRet = FALSE;
|
||
|
|
||
|
}
|
||
|
genGFree(lpszUncName, genGSize(lpszUncName));
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_WriteVersionSection (Local Routine)
|
||
|
*
|
||
|
* Writes the [Version] section in the CDF file.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdf_WriteVersionSection(
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
UINT uCount;
|
||
|
UINT idx;
|
||
|
BOOL bRet;
|
||
|
|
||
|
static struct {
|
||
|
|
||
|
LPCTSTR lpszKey;
|
||
|
LPCTSTR lpszStr;
|
||
|
|
||
|
} aszVer[] = {
|
||
|
|
||
|
g_szClass , g_szIExpress,
|
||
|
g_szSEDVersion, g_szSEDVersionNumber
|
||
|
};
|
||
|
|
||
|
|
||
|
// Write out [Version] values.
|
||
|
//
|
||
|
uCount = sizeof(aszVer) / sizeof(aszVer[0]);
|
||
|
|
||
|
for (idx = 0, bRet = TRUE; (idx < uCount) && bRet; idx++) {
|
||
|
|
||
|
bRet = WritePrivateProfileString(g_szVersionSect,
|
||
|
aszVer[idx].lpszKey,
|
||
|
aszVer[idx].lpszStr,
|
||
|
pCdfInfo->lpszCdfFile);
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_WriteOptionsSection (Local Routine)
|
||
|
*
|
||
|
* Writess the [Options] section in the CDF file.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdf_WriteOptionsSection(
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
UINT uCount;
|
||
|
UINT idx;
|
||
|
BOOL bRet;
|
||
|
|
||
|
static struct {
|
||
|
|
||
|
LPCTSTR lpszKey;
|
||
|
LPCTSTR lpszStr;
|
||
|
|
||
|
} aszOpt[] = {
|
||
|
|
||
|
g_szPackagePurpose , g_szCreateCAB,
|
||
|
g_szExtractorStub , g_szNone,
|
||
|
g_szShowWindow , g_sz0,
|
||
|
g_szUseLongFileName , g_sz1,
|
||
|
g_szHideAnimate , g_sz1,
|
||
|
g_szRebootMode , g_szNoReboot,
|
||
|
g_szCompressionQuantum, g_szCompressionQuantVal,
|
||
|
g_szTargetName , g_szTargetNameSection,
|
||
|
g_szAppLaunched , g_szAppLaunchedSection,
|
||
|
g_szSourceFiles , g_szSourceFiles,
|
||
|
g_szPostInstallCmd , g_szNone,
|
||
|
g_szCompressionType , g_szCompressTypeVal,
|
||
|
g_szCompressionMemory , g_szCompressionValue
|
||
|
};
|
||
|
|
||
|
|
||
|
// Write out [Options] values.
|
||
|
//
|
||
|
uCount = sizeof(aszOpt) / sizeof(aszOpt[0]);
|
||
|
|
||
|
for (idx = 0, bRet = TRUE; (idx < uCount) && bRet; idx++) {
|
||
|
|
||
|
bRet = WritePrivateProfileString(g_szOptions,
|
||
|
aszOpt[idx].lpszKey,
|
||
|
aszOpt[idx].lpszStr,
|
||
|
pCdfInfo->lpszCdfFile);
|
||
|
}
|
||
|
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdf_Generate
|
||
|
*
|
||
|
* Creates a CDF file and writes it to disk.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdf_Generate(
|
||
|
PCDFINFO pCdfInfo)
|
||
|
{
|
||
|
if (cdf_WriteVersionSection(pCdfInfo) &&
|
||
|
cdf_WriteOptionsSection(pCdfInfo) &&
|
||
|
cdf_WriteFilesSection(pCdfInfo)) {
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdfCreate
|
||
|
*
|
||
|
* Creates a CDF object.
|
||
|
*
|
||
|
* Parameters
|
||
|
* ----------
|
||
|
* hinf - Handle to a INF object. The CDF will inherit information from
|
||
|
* the INF.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
HANDLE cdfCreate(
|
||
|
HANDLE hinf,
|
||
|
BOOL bSecure)
|
||
|
{
|
||
|
PCDFINFO pCdfInfo;
|
||
|
|
||
|
|
||
|
if (pCdfInfo = (PCDFINFO)genGAlloc(sizeof(CDFINFO))) {
|
||
|
|
||
|
// Initialize object-variables.
|
||
|
//
|
||
|
pCdfInfo->hInf = hinf;
|
||
|
pCdfInfo->bSecure = bSecure;
|
||
|
|
||
|
return (HANDLE) pCdfInfo;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdfProcess
|
||
|
*
|
||
|
* Process the CDF object.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdfProcess(
|
||
|
HANDLE hcdf)
|
||
|
{
|
||
|
HANDLE hFile;
|
||
|
PCDFINFO pCdfInfo;
|
||
|
DWORD dwErr;
|
||
|
|
||
|
if (pCdfInfo = (PCDFINFO)hcdf) {
|
||
|
|
||
|
if (pCdfInfo->lpszCdfFile = cdf_GetCdfFile(pCdfInfo)) {
|
||
|
|
||
|
// Check for existence of .cdf file
|
||
|
//
|
||
|
hFile = gen_OpenFileRead(pCdfInfo->lpszCdfFile);
|
||
|
|
||
|
if (hFile && (hFile != INVALID_HANDLE_VALUE)) {
|
||
|
|
||
|
// If we DO have a .cdf for this printer/architecture,
|
||
|
// check if it is up to date.
|
||
|
//
|
||
|
CloseHandle(hFile);
|
||
|
|
||
|
|
||
|
// If the .cdf we have is still up to
|
||
|
// date, we are done.
|
||
|
//
|
||
|
if (cdf_IsUpToDate(pCdfInfo)) {
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
// Delete the old .cdf if it exists
|
||
|
//
|
||
|
DeleteFile(pCdfInfo->lpszCdfFile);
|
||
|
|
||
|
CdfGenerate:
|
||
|
// Generate a new one.
|
||
|
//
|
||
|
if (cdf_Generate(pCdfInfo))
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
dwErr = GetLastError();
|
||
|
|
||
|
|
||
|
// Force an update of our machine ip-addr. Usually,
|
||
|
// this is called in the cdf_IsUpToDat() to verify
|
||
|
// the machine hasn't changed ip-addresses.
|
||
|
//
|
||
|
genUpdIPAddr();
|
||
|
|
||
|
|
||
|
// If we don't have a CDF already, generate one now.
|
||
|
//
|
||
|
if (dwErr == ERROR_FILE_NOT_FOUND)
|
||
|
goto CdfGenerate;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cdfSetError(pCdfInfo,GetLastError());
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdfDestroy
|
||
|
*
|
||
|
* Destroys the CDF object.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdfDestroy(
|
||
|
HANDLE hcdf)
|
||
|
{
|
||
|
PCDFINFO pCdfInfo;
|
||
|
BOOL bFree = FALSE;
|
||
|
|
||
|
|
||
|
if (pCdfInfo = (PCDFINFO)hcdf) {
|
||
|
|
||
|
// Free up any allocated objects.
|
||
|
//
|
||
|
if (pCdfInfo->lpszCdfFile)
|
||
|
genGFree(pCdfInfo->lpszCdfFile, genGSize(pCdfInfo->lpszCdfFile));
|
||
|
|
||
|
// Walk the list and free the file-item information.
|
||
|
//
|
||
|
itm_DeleteAll(pCdfInfo);
|
||
|
|
||
|
bFree = genGFree(pCdfInfo, sizeof(CDFINFO));
|
||
|
}
|
||
|
|
||
|
return bFree;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdfGetName
|
||
|
*
|
||
|
* Returns the name of the CDF file. This will not include any path
|
||
|
* information. This routine derives the filename from the stored full-path
|
||
|
* name in the CDF object.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
LPCTSTR cdfGetName(
|
||
|
HANDLE hcdf)
|
||
|
{
|
||
|
PCDFINFO pCdfInfo;
|
||
|
LPCTSTR lpszName = NULL;
|
||
|
|
||
|
|
||
|
if (pCdfInfo = (PCDFINFO)hcdf) {
|
||
|
|
||
|
if (lpszName = genFindRChar(pCdfInfo->lpszCdfFile, TEXT('\\')))
|
||
|
lpszName++;
|
||
|
}
|
||
|
|
||
|
return lpszName;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* cdfGetModTime
|
||
|
*
|
||
|
* Returns the time the CDF file was last modified.
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
BOOL cdfGetModTime(
|
||
|
HANDLE hcdf,
|
||
|
LPFILETIME lpftMod)
|
||
|
{
|
||
|
HANDLE hFile;
|
||
|
PCDFINFO pCdfInfo;
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
|
||
|
// Fill in struct-info.
|
||
|
//
|
||
|
lpftMod->dwLowDateTime = 0;
|
||
|
lpftMod->dwHighDateTime = 0;
|
||
|
|
||
|
|
||
|
// Check the pointer for validity.
|
||
|
//
|
||
|
if (pCdfInfo = (PCDFINFO)hcdf) {
|
||
|
|
||
|
// File should exist at this time, since cdfCreate should always
|
||
|
// create the file. Return false (error) if can't open file.
|
||
|
//
|
||
|
hFile = gen_OpenFileRead(pCdfInfo->lpszCdfFile);
|
||
|
|
||
|
if (hFile && (hFile != INVALID_HANDLE_VALUE)) {
|
||
|
|
||
|
// Get the file creation time.
|
||
|
//
|
||
|
bRet = GetFileTime(hFile, NULL, NULL, lpftMod);
|
||
|
|
||
|
CloseHandle(hFile);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
/*************************************************************************************
|
||
|
** cdfCleanUpSourceFiles
|
||
|
**
|
||
|
** This runs through all of the files that we returned from the inf file and in the
|
||
|
** case where there was a source we see if it is in the PrtCabs directory, if it is
|
||
|
** we delete it
|
||
|
**
|
||
|
*************************************************************************************/
|
||
|
VOID cdfCleanUpSourceFiles(
|
||
|
HANDLE hInf) {
|
||
|
|
||
|
LPINFINFO lpInf = (LPINFINFO)hInf;
|
||
|
|
||
|
if (lpInf) {
|
||
|
DWORD dwItems = lpInf->lpInfItems->dwCount;
|
||
|
LPINFITEMINFO lpII = lpInf->lpInfItems;
|
||
|
LPCTSTR lpszDstPath = infGetDstPath(hInf);
|
||
|
// This can't be NULL or we wouldn't have allocated the INF structure
|
||
|
|
||
|
if (*lpszDstPath) { // Might not have been set though
|
||
|
for (DWORD idx = 0; idx < dwItems; idx++) {
|
||
|
// We check to see if the file exists as advertised, if it does then we don't
|
||
|
// change anything, otherwise, we search the system and windows directories to
|
||
|
// find it, if it exists, we change the path accordingly
|
||
|
LPTSTR lpszSource = lpII->aItems[idx].szSource;
|
||
|
|
||
|
if (*lpszSource) { // If there was a source file different to the target
|
||
|
LPTSTR lpszName = lpII->aItems[idx].szName;
|
||
|
|
||
|
if (!lstrcmp(lpszName,lpszSource)) { // If we renamed the target to the source
|
||
|
LPTSTR lpszPath = lpII->aItems[idx].szPath;
|
||
|
|
||
|
if (!lstrcmp(lpszPath,lpszDstPath)) { // If we set the path on the source
|
||
|
LPTSTR lpszFile = (LPTSTR)genBuildFileName(lpszPath, lpszName, NULL);
|
||
|
|
||
|
if (lpszFile) {
|
||
|
WIN32_FIND_DATA FindFileData;
|
||
|
HANDLE hFind = FindFirstFile(lpszFile, &FindFileData);
|
||
|
|
||
|
if (hFind && (hFind != INVALID_HANDLE_VALUE)) {
|
||
|
FindClose(hFind);
|
||
|
DeleteFile(lpszFile);
|
||
|
}
|
||
|
|
||
|
genGFree(lpszFile, genGSize(lpszFile));
|
||
|
} // This is cleanup code, no point in failing it
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|