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.
664 lines
21 KiB
664 lines
21 KiB
#include <windows.h>
|
|
#include <fusenetincludes.h>
|
|
#include <stdio.h>
|
|
#include <msxml2.h>
|
|
#include "list.h"
|
|
#include "patchapi.h"
|
|
#include "patchprv.h"
|
|
#include "patchlzx.h"
|
|
#include "xmlutil.h"
|
|
#include "pg.h"
|
|
|
|
#define DIRECTORY_PATH 0
|
|
#define FILE_PATH 1
|
|
|
|
#define HASHTABLE_SIZE 257
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// PathNormalize
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT PathNormalize(LPWSTR pwzPath, LPWSTR *ppwzAbsolutePath, DWORD dwFlag, BOOL bCreate)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR pwzTempDir[MAX_PATH], pwzAbsolutePath[MAX_PATH];
|
|
DWORD ccDir = MAX_PATH;
|
|
|
|
*ppwzAbsolutePath = NULL;
|
|
//If path is relative, prepend the current directory
|
|
if (PathIsRelative(pwzPath))
|
|
{
|
|
GetCurrentDirectory(ccDir, pwzTempDir);
|
|
StrCat(pwzTempDir, L"\\");
|
|
StrCat(pwzTempDir, pwzPath);
|
|
}
|
|
else
|
|
StrCpy(pwzTempDir, pwzPath);
|
|
|
|
|
|
if (!PathCanonicalize(pwzAbsolutePath, pwzTempDir))
|
|
{
|
|
printf("Dir \"%ws\" canonicalize error\n", pwzTempDir);
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
//If path is supposed to be a diesctory, append a trailing slash if not already there
|
|
ccDir = lstrlen(pwzAbsolutePath);
|
|
if (dwFlag == DIRECTORY_PATH && pwzAbsolutePath[ccDir -1] != L'\\')
|
|
{
|
|
pwzAbsolutePath[ccDir] = L'\\';
|
|
pwzAbsolutePath[ccDir +1] = L'\0';
|
|
}
|
|
|
|
//Make sure the direcotry exists
|
|
if (dwFlag == DIRECTORY_PATH && !bCreate)
|
|
{
|
|
if(!PathIsDirectory(pwzAbsolutePath))
|
|
{
|
|
printf("Dir \"%ws\" is not a valid directory\n", pwzPath);
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
}
|
|
//Make sure the file exists
|
|
else if (dwFlag == FILE_PATH)
|
|
{
|
|
if(!bCreate)
|
|
{
|
|
if(!PathFileExists(pwzAbsolutePath))
|
|
{
|
|
printf("File \"%ws\" does not exist\n", pwzPath);
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
}
|
|
if(PathIsDirectory(pwzAbsolutePath))
|
|
{
|
|
printf("File \"%ws\" is a directory\n", pwzPath);
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
(*ppwzAbsolutePath) = WSTRDupDynamic(pwzAbsolutePath);
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// IsValidManifestImport
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT IsValidManifestImport (LPWSTR pwzManifestPath)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IAssemblyManifestImport *pManImport = NULL;
|
|
IAssemblyIdentity *pAssemblyId = NULL;
|
|
if((hr = CreateAssemblyManifestImport(&pManImport, pwzManifestPath, NULL, 0)) != S_OK)
|
|
goto exit;
|
|
|
|
if((hr = pManImport->GetAssemblyIdentity(&pAssemblyId)) != S_OK)
|
|
goto exit;
|
|
|
|
exit:
|
|
SAFERELEASE(pAssemblyId);
|
|
SAFERELEASE(pManImport);
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// FindAllFiles
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT FindAllFiles (LPWSTR pwzDir, List<LPWSTR> *pFileList)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATA fdFile;
|
|
CString sSearchString, sFileName;
|
|
DWORD dwHash = 0;
|
|
DWORD dwLastError = 0;
|
|
|
|
// set up search string to find all files in the passed in directory
|
|
sSearchString.Assign(pwzDir);
|
|
sSearchString.Append(L"*");
|
|
|
|
if (sSearchString._cc > MAX_PATH)
|
|
{
|
|
hr = CO_E_PATHTOOLONG;
|
|
printf("Error: Search path too long\n");
|
|
goto exit;
|
|
}
|
|
|
|
hFind = FindFirstFile(sSearchString._pwz, &fdFile);
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
hr = E_FAIL;
|
|
printf("Find file error\n");
|
|
goto exit;
|
|
}
|
|
|
|
//enumerate through all the files in the directory,
|
|
// and recursivly call FindAllAssemblies on any directories encountered
|
|
while(TRUE)
|
|
{
|
|
LPWSTR pwzFileName = NULL;
|
|
if (StrCmp(fdFile.cFileName, L".") != 0 && StrCmp(fdFile.cFileName, L"..") != 0)
|
|
{
|
|
CString sFilePath;
|
|
|
|
//create absolute file name by appending the filename to the dir name
|
|
sFilePath.Assign(pwzDir);
|
|
sFilePath.Append(fdFile.cFileName);
|
|
|
|
if (sSearchString._cc > MAX_PATH)
|
|
{
|
|
hr = CO_E_PATHTOOLONG;
|
|
printf("Error: File path too long\n");
|
|
goto exit;
|
|
}
|
|
|
|
//If the file is a directory, recursivly call FindAllFiles
|
|
if ((fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
|
{
|
|
sFilePath.Append(L"\\");
|
|
if (FAILED(hr = FindAllFiles(sFilePath._pwz, pFileList)))
|
|
goto exit;
|
|
}
|
|
// If a file add it to our master list
|
|
else
|
|
{
|
|
if (StrCmp(sFilePath._pwz, g_sSourceManifest._pwz))
|
|
{
|
|
sFileName.Assign(sFilePath._pwz+ g_sSourceBase._cc -1);
|
|
dwHash = HashString(sFileName._pwz, HASHTABLE_SIZE, false);
|
|
sFileName.ReleaseOwnership(&pwzFileName);
|
|
pFileList[dwHash].AddTail(pwzFileName);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!FindNextFile(hFind, &fdFile))
|
|
{
|
|
dwLastError = GetLastError();
|
|
break;
|
|
}
|
|
|
|
if(dwLastError == ERROR_NO_MORE_FILES)
|
|
hr = S_OK;
|
|
else
|
|
hr = HRESULT_FROM_WIN32(dwLastError);
|
|
|
|
}
|
|
|
|
hr = S_OK;
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// CrossReferenceFiles
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT CrossReferenceFiles (LPWSTR pwzDir, List<LPWSTR> *pFileList, List<LPWSTR> *pPatchableFiles)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATA fdFile;
|
|
CString sSearchString, sFileName;
|
|
DWORD dwHash=0;
|
|
LISTNODE pos;
|
|
LPWSTR pwzBuf = NULL;
|
|
DWORD dwLastError = 0;
|
|
|
|
// set up search string to find all files in the passed in directory
|
|
sSearchString.Assign(pwzDir);
|
|
sSearchString.Append(L"*");
|
|
|
|
if (sSearchString._cc > MAX_PATH)
|
|
{
|
|
hr = CO_E_PATHTOOLONG;
|
|
printf("Error: Search path too long\n");
|
|
goto exit;
|
|
}
|
|
|
|
hFind = FindFirstFile(sSearchString._pwz, &fdFile);
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
hr = E_FAIL;
|
|
printf("Find file error\n");
|
|
goto exit;
|
|
}
|
|
|
|
//enumerate through all the files in the directory,
|
|
// and recursivly call FindAllAssemblies on any directories encountered
|
|
while(dwLastError != ERROR_NO_MORE_FILES)
|
|
{
|
|
LPWSTR pwzFileName = NULL;
|
|
if (StrCmp(fdFile.cFileName, L".") != 0 && StrCmp(fdFile.cFileName, L"..") != 0)
|
|
{
|
|
CString sFilePath;
|
|
|
|
//create absolute file name by appending the filename to the dir name
|
|
sFilePath.Assign(pwzDir);
|
|
sFilePath.Append(fdFile.cFileName);
|
|
|
|
if (sSearchString._cc > MAX_PATH)
|
|
{
|
|
hr = CO_E_PATHTOOLONG;
|
|
printf("Error: File path too long\n");
|
|
goto exit;
|
|
}
|
|
|
|
//If the file is a directory, recursivly call CrossReferenceFiles
|
|
if ((fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
|
{
|
|
sFilePath.Append(L"\\");
|
|
if (FAILED(hr = CrossReferenceFiles(sFilePath._pwz, pFileList, pPatchableFiles)))
|
|
goto exit;
|
|
}
|
|
// If a file, check to see if it can be patched
|
|
else
|
|
{
|
|
sFileName.Assign(sFilePath._pwz+g_sDestBase._cc -1);
|
|
dwHash = HashString(sFileName._pwz, HASHTABLE_SIZE, false);
|
|
|
|
pos = pFileList[dwHash].GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
pwzBuf = pFileList[dwHash].GetNext(pos);
|
|
|
|
//if equal, attempt to path file
|
|
if (!StrCmpI(pwzBuf, sFileName._pwz))
|
|
{
|
|
sFileName.ReleaseOwnership(&pwzFileName);
|
|
pPatchableFiles->AddTail(pwzFileName);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!FindNextFile(hFind, &fdFile))
|
|
{
|
|
dwLastError = GetLastError();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(dwLastError == ERROR_NO_MORE_FILES)
|
|
hr = S_OK;
|
|
else
|
|
hr = HRESULT_FROM_WIN32(dwLastError);
|
|
|
|
|
|
hr = S_OK;
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// MyProgressCallback
|
|
/////////////////////////////////////////////////////////////////////////
|
|
BOOL CALLBACK MyProgressCallback(PVOID CallbackContext, ULONG CurrentPosition,
|
|
ULONG MaximumPosition)
|
|
{
|
|
UNREFERENCED_PARAMETER( CallbackContext );
|
|
|
|
if ( MaximumPosition != 0 )
|
|
fprintf(stderr, "\r%6.2f%% complete", ( CurrentPosition * 100.0 ) / MaximumPosition );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// ApplyPatchToFiles
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT ApplyPatchToFiles (List<LPWSTR> *pPatchableFiles, /* out */ List<LPWSTR> *pPatchedFiles, LPWSTR pwzSourceDir, LPWSTR pwzDestDir, LPWSTR pwzPatchDir)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LISTNODE pos;
|
|
LPWSTR pwzBuf = NULL, pwzDestFile = NULL;
|
|
CString sSourceFile, sDestFile, sPatchFile, sRelativeDest, sRelativePatch;
|
|
|
|
PATCH_OPTION_DATA OptionData = { sizeof( PATCH_OPTION_DATA ) };
|
|
PATCH_OPTION_DATA *OptionDataPointer = &OptionData;
|
|
BOOL bSuccess = FALSE;
|
|
ULONG OldFileCount;
|
|
|
|
//CreatePatchFileEx allows you to create patchs file which
|
|
//can patch from multiple source files. You can have up to
|
|
// 256 different source files, hence the arrays with 256 elements.
|
|
//FileNameArray has 257 elemnts since the destination file (which
|
|
// there can only be one) is stored as the first element and all the
|
|
// source files, are stored in the remaining 256 elements.
|
|
|
|
// BUGBUG - t-peterf to document why 256, 257.
|
|
PATCH_OLD_FILE_INFO_W OldFileInfo[ 256 ];
|
|
LPWSTR FileNameArray[ 257 ];
|
|
LPSTR OldFileSymPathArray[256];
|
|
LPSTR NewFileSymPath = new CHAR[MAX_PATH];
|
|
|
|
ULONG OptionFlags = PATCH_OPTION_USE_LZX_BEST |
|
|
PATCH_OPTION_USE_LZX_LARGE |
|
|
PATCH_OPTION_FAIL_IF_SAME_FILE |
|
|
PATCH_OPTION_FAIL_IF_BIGGER |
|
|
PATCH_OPTION_INTERLEAVE_FILES;
|
|
|
|
//Step through list of patchable files
|
|
pos = pPatchableFiles->GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
|
|
pwzBuf = pPatchableFiles->GetNext(pos);
|
|
|
|
//Set up source file path
|
|
sSourceFile.Assign(pwzSourceDir);
|
|
sSourceFile.Append(pwzBuf);
|
|
|
|
//Set up dest file path
|
|
sDestFile.Assign(pwzDestDir);
|
|
sDestFile.Append(pwzBuf);
|
|
|
|
//set up patchfile path
|
|
sPatchFile.Assign(pwzPatchDir);
|
|
sPatchFile.Append(pwzBuf);
|
|
sPatchFile.Append(L"._p");
|
|
|
|
CreateDirectoryHierarchy(sPatchFile._pwz, NULL);
|
|
|
|
//Set up Patching Information
|
|
OldFileCount = 1;
|
|
OldFileInfo[0].SizeOfThisStruct = sizeof( PATCH_OLD_FILE_INFO);
|
|
OldFileInfo[0].OldFileName = sSourceFile._pwz;
|
|
OldFileInfo[0].IgnoreRangeArray = NULL;
|
|
OldFileInfo[0].IgnoreRangeCount = NULL;
|
|
OldFileInfo[0].RetainRangeArray = NULL;
|
|
OldFileInfo[0].RetainRangeCount = NULL;
|
|
|
|
|
|
OldFileSymPathArray[0] = new CHAR[MAX_PATH];
|
|
WideCharToMultiByte(CP_ACP, 0, pwzSourceDir, lstrlen(pwzSourceDir), OldFileSymPathArray[0], MAX_PATH, NULL, NULL);
|
|
WideCharToMultiByte(CP_ACP, 0, pwzDestDir, lstrlen(pwzDestDir), NewFileSymPath, MAX_PATH, NULL, NULL);
|
|
|
|
OptionData.SizeOfThisStruct = NULL;
|
|
OptionData.SymLoadCallback = NULL;
|
|
OptionData.SymLoadContext = FileNameArray;
|
|
|
|
OptionData.ExtendedOptionFlags = NULL;
|
|
OptionData.InterleaveMapArray = NULL;
|
|
OptionData.MaxLzxWindowSize = NULL;
|
|
OptionData.SymbolOptionFlags = NULL;
|
|
|
|
OptionData.NewFileSymbolPath = (LPCSTR)NewFileSymPath;
|
|
OptionData.OldFileSymbolPathArray = (LPCSTR *)OldFileSymPathArray;
|
|
|
|
FileNameArray[0] = WSTRDupDynamic(sDestFile._pwz);
|
|
FileNameArray[1] = WSTRDupDynamic(sSourceFile._pwz);
|
|
|
|
//Applypatch
|
|
bSuccess = CreatePatchFileEx(
|
|
OldFileCount,
|
|
OldFileInfo,
|
|
sDestFile._pwz,
|
|
sPatchFile._pwz,
|
|
OptionFlags,
|
|
OptionDataPointer,
|
|
MyProgressCallback,
|
|
NULL
|
|
);
|
|
|
|
sRelativeDest.Assign(sDestFile._pwz + g_sDestBase._cc-1);
|
|
sRelativePatch.Assign(sPatchFile._pwz + g_sDestBase._cc-1);
|
|
|
|
if(bSuccess)
|
|
{
|
|
fprintf(stderr, "\r%ws has been patched successfully to %ws\n", sRelativeDest._pwz, sRelativePatch._pwz);
|
|
sDestFile.ReleaseOwnership(&pwzDestFile);
|
|
pPatchedFiles->AddTail(pwzDestFile);
|
|
}
|
|
else
|
|
fprintf(stderr, "\rCould/would not patch %ws. Not adding file to patch manifest\n",sRelativeDest._pwz);
|
|
|
|
}
|
|
|
|
SAFEDELETEARRAY(NewFileSymPath);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// CheckForDuplicate
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT CheckForDuplicate(LPWSTR pwzSourceManifestPath, LPWSTR pwzDestManifestPath)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IXMLDOMDocument2 *pXMLDoc = NULL;
|
|
IXMLDOMNode *pNode = NULL;
|
|
IAssemblyManifestImport *pSourceManImport = NULL;
|
|
IAssemblyIdentity *pSourceAssemblyId = NULL;
|
|
CString sSearchString, sBuffer;
|
|
BSTR bstrSearchString = NULL;
|
|
LPWSTR pwzBuf=NULL;
|
|
DWORD ccBuf=0;
|
|
|
|
LPWSTR rpwzAttrNames[6] =
|
|
{
|
|
SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PROCESSOR_ARCHITECTURE,
|
|
SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME,
|
|
SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PUBLIC_KEY_TOKEN,
|
|
SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_VERSION,
|
|
SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_LANGUAGE,
|
|
SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_TYPE,
|
|
};
|
|
|
|
if(FAILED(hr = LoadXMLDocument(pwzDestManifestPath, &pXMLDoc)))
|
|
goto exit;
|
|
|
|
if(FAILED(hr = CreateAssemblyManifestImport(&pSourceManImport, pwzSourceManifestPath, NULL, 0)))
|
|
goto exit;
|
|
|
|
if(FAILED(hr = pSourceManImport->GetAssemblyIdentity(&pSourceAssemblyId)))
|
|
goto exit;
|
|
|
|
//set up search string
|
|
sSearchString.Assign(L"/assembly/Patch/SourceAssembly/assemblyIdentity[");
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
if (i)
|
|
sSearchString.Append(L" and ");
|
|
|
|
sSearchString.Append(L"@");
|
|
sSearchString.Append(rpwzAttrNames[i]);
|
|
sSearchString.Append(L"=\"");
|
|
|
|
if (FAILED(hr = pSourceAssemblyId->GetAttribute(rpwzAttrNames[i], &pwzBuf, &ccBuf)))
|
|
goto exit;
|
|
sBuffer.TakeOwnership(pwzBuf, ccBuf);
|
|
|
|
sSearchString.Append(sBuffer);
|
|
sSearchString.Append(L"\"");
|
|
}
|
|
sSearchString.Append(L"]");
|
|
|
|
bstrSearchString = ::SysAllocString(sSearchString._pwz);
|
|
if (!bstrSearchString)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
//if source assembly already exists, exit and do nothing
|
|
if (FAILED(hr = pXMLDoc->selectSingleNode(bstrSearchString, &pNode)))
|
|
goto exit;
|
|
else if (hr == S_OK)
|
|
{
|
|
fprintf(stderr, "Duplicate Source Assembly! Not adding to manfiest\n");
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
else if (hr == S_FALSE)
|
|
{
|
|
hr = S_OK;
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
if(bstrSearchString)
|
|
::SysFreeString(bstrSearchString);
|
|
|
|
SAFERELEASE(pXMLDoc);
|
|
SAFERELEASE(pNode);
|
|
SAFERELEASE(pSourceAssemblyId);
|
|
SAFERELEASE(pSourceManImport);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// Usage
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT GetPatchDirectory(LPWSTR pwzSourceManifestPath, LPWSTR *ppwzPatchDir)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IAssemblyManifestImport *pSourceManImport = NULL;
|
|
IAssemblyIdentity *pSourceAssemblyId = NULL;
|
|
LPWSTR pwzBuf=NULL;
|
|
DWORD ccBuf =0;
|
|
CString sBuffer, sPatchDir;
|
|
|
|
if(FAILED(hr = CreateAssemblyManifestImport(&pSourceManImport, pwzSourceManifestPath, NULL, 0)))
|
|
goto exit;
|
|
|
|
if(FAILED(hr = pSourceManImport->GetAssemblyIdentity(&pSourceAssemblyId)))
|
|
goto exit;
|
|
|
|
if (FAILED(hr = pSourceAssemblyId->GetDisplayName(ASMID_DISPLAYNAME_NOMANGLING, &pwzBuf, &ccBuf)))
|
|
goto exit;
|
|
sBuffer.TakeOwnership(pwzBuf, ccBuf);
|
|
|
|
sPatchDir.Assign(g_sDestBase);
|
|
sPatchDir.Append(L"__patch__\\");
|
|
sPatchDir.Append(pwzBuf);
|
|
sPatchDir.Append(L"\\");
|
|
|
|
sPatchDir.ReleaseOwnership(ppwzPatchDir);
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// Usage
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT Usage()
|
|
{
|
|
printf("Usage: \n"
|
|
"pg [source manifest path] [dest manifest path]:\n"
|
|
"\t[source manifest path] = path of the Application for which you want to generate a manifest for\n"
|
|
"\t[dest manifest path] = path of the Application for which you want to generate a manifest for\n");
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// wmain
|
|
/////////////////////////////////////////////////////////////////////////
|
|
int __cdecl wmain(int argc, WCHAR **argv)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
LPWSTR pwzSourceManifest=NULL, pwzDestManifest=NULL;
|
|
List <LPWSTR> pFileList[HASHTABLE_SIZE], PatchableFiles, PatchedFiles;
|
|
BOOL bCoInitialized = FALSE;
|
|
CString sPatchDir;
|
|
LPWSTR pwzBuf=NULL;
|
|
|
|
hr = CoInitialize(NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
bCoInitialized = TRUE;
|
|
|
|
if (!StrCmp(argv[1], L"-?") || !(argc == 3))
|
|
{
|
|
hr = Usage();
|
|
goto exit;
|
|
}
|
|
|
|
if (FAILED(hr = PathNormalize(argv[1], &pwzSourceManifest, FILE_PATH, FALSE)))
|
|
{
|
|
hr = Usage();
|
|
goto exit;
|
|
}
|
|
|
|
if (FAILED(hr = PathNormalize(argv[2], &pwzDestManifest, FILE_PATH, FALSE)))
|
|
{
|
|
hr = Usage();
|
|
goto exit;
|
|
}
|
|
|
|
g_sSourceManifest.Assign(pwzSourceManifest);
|
|
|
|
g_sSourceBase.Assign(g_sSourceManifest);
|
|
g_sSourceBase.RemoveLastElement();
|
|
g_sSourceBase.Append(L"\\");
|
|
|
|
g_sDestBase.Assign(pwzDestManifest);
|
|
g_sDestBase.RemoveLastElement();
|
|
g_sDestBase.Append(L"\\");
|
|
|
|
//Bugbug, could run into naming conflicts with the patch dir
|
|
sPatchDir.Assign(g_sDestBase);
|
|
sPatchDir.Append(L"__patch__\\");
|
|
|
|
|
|
if(FAILED(hr = IsValidManifestImport(pwzSourceManifest)))
|
|
{
|
|
fprintf(stderr, "%ws is not a valid application manifest\n", pwzSourceManifest);
|
|
goto exit;
|
|
}
|
|
if(FAILED(hr = IsValidManifestImport(pwzDestManifest)))
|
|
{
|
|
fprintf(stderr, "%ws is not a valid application manifest\n", pwzDestManifest);
|
|
goto exit;
|
|
}
|
|
|
|
if((hr = CheckForDuplicate(pwzSourceManifest, pwzDestManifest)) != S_OK)
|
|
goto exit;
|
|
|
|
if(FAILED(hr = GetPatchDirectory(g_sSourceManifest._pwz, &pwzBuf)))
|
|
goto exit;
|
|
sPatchDir.TakeOwnership(pwzBuf);
|
|
|
|
if(FAILED(hr = FindAllFiles(g_sSourceBase._pwz, pFileList)))
|
|
goto exit;
|
|
|
|
if(FAILED(hr = CrossReferenceFiles(g_sDestBase._pwz, pFileList, &PatchableFiles)))
|
|
goto exit;
|
|
|
|
if(FAILED(hr = ApplyPatchToFiles(&PatchableFiles, &PatchedFiles, g_sSourceBase._pwz, g_sDestBase._pwz, sPatchDir._pwz)))
|
|
goto exit;
|
|
|
|
if(FAILED(hr = CreatePatchManifest(&PatchedFiles, sPatchDir._pwz, pwzSourceManifest, pwzDestManifest)))
|
|
goto exit;
|
|
|
|
exit:
|
|
SAFEDELETEARRAY(pwzSourceManifest);
|
|
SAFEDELETEARRAY(pwzDestManifest);
|
|
|
|
|
|
if (bCoInitialized)
|
|
CoUninitialize();
|
|
|
|
if (FAILED(hr))
|
|
fprintf(stderr, "\nFailed with code 0x%x", hr);
|
|
|
|
return 0;
|
|
}
|