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.
 
 
 
 
 
 

485 lines
12 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
expandit.c
Abstract:
Expandit provides routines to expand a given file as much as possible.
It is useful for expanding cabinet files and executable files that may
themselves contain cabinet files.
Author:
Marc R. Whitten (marcw) 30-Jul-1998
Revision History:
--*/
#include "pch.h"
#include "migutilp.h"
UINT g_DirSequencer = 0;
BOOL
ExpandAllFilesW (
IN PCWSTR FileDir,
IN PCWSTR TempDir
);
BOOL
ExpandFileW (
IN PCWSTR FullPath,
IN PCWSTR TempDir
);
PWSTR
pGetExpandName (
VOID
)
{
static WCHAR rName[MAX_WCHAR_PATH];
g_DirSequencer++;
swprintf (rName, L"EXP%04x", g_DirSequencer);
return rName;
}
BOOL
pIsFileType (
IN PCWSTR FullPath,
IN PCWSTR TypePattern
)
{
PCWSTR p;
p = GetFileExtensionFromPathW (FullPath);
return p && IsPatternMatchW (TypePattern, p);
}
BOOL CALLBACK
pResNameCallback (
IN HANDLE hModule, // module handle
IN LPCWSTR lpszType, // pointer to resource type
IN LPWSTR lpszName, // pointer to resource name
IN LONG lParam // application-defined parameter
)
{
HRSRC hResource;
DWORD size;
HGLOBAL hGlobal;
HANDLE hFile;
PWSTR fileName;
PWSTR dirName;
PVOID srcBytes;
UINT dontCare;
BOOL rSuccess=TRUE;
hResource = FindResourceW (hModule, lpszName, lpszType);
if (hResource) {
size = SizeofResource (hModule, hResource);
if (size) {
hGlobal = LoadResource (hModule, hResource);
if (hGlobal) {
srcBytes = LockResource (hGlobal);
if (srcBytes) {
//
// Ok, lets see if this is a cabinet file..
//
if (size < 4 || *((PDWORD)srcBytes) != 0x4643534D) {
//
// Not a cabinet file.
//
return TRUE;
}
dirName = JoinPathsW ((PWSTR) lParam, pGetExpandName ());
fileName = JoinPathsW (dirName, L"temp.cab");
hFile = CreateFileW (
fileName,
GENERIC_READ | GENERIC_WRITE,
0, NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
DEBUGMSGW ((DBG_ERROR, "Unable to create file %s.", fileName));
return FALSE;
}
if (!WriteFile (hFile, srcBytes, size, &dontCare, NULL)) {
DEBUGMSGW ((DBG_ERROR, "Cannot write to file %s", fileName));
return FALSE;
}
CloseHandle (hFile);
//
// Expand this file.
//
rSuccess = ExpandFileW (fileName, dirName);
FreePathStringW (dirName);
FreePathStringW (fileName);
}
}
}
}
return rSuccess;
}
BOOL CALLBACK
pResTypeCallback (
IN HANDLE hModule, // resource-module handle
IN PWSTR lpszType, // pointer to resource type
IN LONG lParam // application-defined parameter
)
{
//
// Oh what a pain. All of the RT types are #defined without A/Ws.
// We need to converte the string to ansi, just to do this comparison.
//
PCSTR aString = ConvertWtoA (lpszType);
if ((aString != RT_ACCELERATOR ) &&
(aString != RT_ANICURSOR ) &&
(aString != RT_ANIICON ) &&
(aString != RT_BITMAP ) &&
(aString != RT_CURSOR ) &&
(aString != RT_DIALOG ) &&
(aString != RT_FONT ) &&
(aString != RT_FONTDIR ) &&
(aString != RT_GROUP_CURSOR ) &&
(aString != RT_GROUP_ICON ) &&
(aString != RT_HTML ) &&
(aString != RT_ICON ) &&
(aString != RT_MENU ) &&
(aString != RT_MESSAGETABLE ) &&
(aString != RT_PLUGPLAY ) &&
(aString != RT_STRING ) &&
(aString != RT_VERSION ) &&
(aString != RT_VXD ) &&
(aString != RT_HTML )
) {
//
// Unknown type. We assume it is a cabinet file and try to extract it.
// Since it may not be a cabinet file, we eat the error.
//
if (!EnumResourceNamesW (hModule, lpszType, pResNameCallback, lParam)) {
DEBUGMSGW ((DBG_ERROR, "Error enumerating resource names."));
}
}
FreeConvertedStr (aString);
return TRUE;
}
UINT CALLBACK
pCabFileCallback (
IN PVOID Context, //context used by the callback routine
IN UINT Notification, //notification sent to callback routine
IN UINT Param1, //additional notification information
IN UINT Param2 //additional notification information
)
{
PCWSTR tempDir = Context;
PCWSTR fileName = (PCWSTR)Param2 ;
PFILE_IN_CABINET_INFO_W fileInfo = (PFILE_IN_CABINET_INFO_W)Param1;
PCWSTR fromPtr, toPtr;
WCHAR tempStr [MEMDB_MAX];
if (Notification == SPFILENOTIFY_FILEINCABINET) {
if (toPtr = wcschr (fileInfo->NameInCabinet, L'\\')) {
StringCopyW (fileInfo->FullTargetName, tempDir);
fromPtr = fileInfo->NameInCabinet;
while (toPtr) {
StringCopyABW (tempStr, fromPtr, toPtr);
StringCatW (fileInfo->FullTargetName, L"\\");
StringCatW (fileInfo->FullTargetName, tempStr);
CreateDirectoryW (fileInfo->FullTargetName, NULL);
toPtr++;
fromPtr = toPtr;
toPtr = wcschr (toPtr, L'\\');
}
}
swprintf (fileInfo->FullTargetName, L"%ws\\%ws", tempDir, fileInfo->NameInCabinet);
return FILEOP_DOIT;
}
return NO_ERROR;
}
BOOL
ExpandFileW (
IN PCWSTR FullPath,
IN PCWSTR TempDir
)
{
BOOL rSuccess = TRUE;
PWSTR dirName = NULL;
PWSTR fileName = NULL;
HANDLE exeModule = NULL;
HANDLE hFile = INVALID_HANDLE_VALUE;
CHAR aName[MAX_MBCHAR_PATH];
PCWSTR uName = NULL;
UINT bytesRead = 0;
if (pIsFileType (FullPath, L"CAB")) {
//
// Expand this cabinet file and recursively handle all of its files.
//
dirName = JoinPathsW (TempDir, pGetExpandName());
__try {
if (!CreateDirectoryW (dirName, NULL)) {
DEBUGMSGW ((DBG_ERROR, "ExpandFile: Cannot create directory %s", dirName));
rSuccess = FALSE;
__leave;
}
//
// Expand the cabinet file into the temporary directory.
//
SetLastError (ERROR_SUCCESS);
if (!SetupIterateCabinetW (FullPath, 0, pCabFileCallback, dirName)) {
DEBUGMSGW ((DBG_ERROR, "ExpandFile: SetupIterateCabinet failed for file %s.", FullPath));
rSuccess = FALSE;
__leave;
}
//
// Now, make sure all of the files in this SubDirectory are expanded.
//
rSuccess = ExpandAllFilesW (dirName, dirName);
}
__finally {
FreePathStringW (dirName);
}
} else if (pIsFileType (FullPath, L"EXE")) {
//
// This is an executable file. Check to make sure that they aren't any cabinet files hanging out
// inside of it.
//
exeModule = LoadLibraryExW (FullPath, NULL, LOAD_LIBRARY_AS_DATAFILE);
if (!exeModule) {
DEBUGMSGW ((DBG_ERROR, "ExpandFile: LoadLibraryEx failed for %s.", FullPath));
return FALSE;
}
if (!EnumResourceTypesW (exeModule, pResTypeCallback, (LONG) TempDir)) {
DEBUGMSGW ((DBG_ERROR, "ExpandFile: EnumResourceTypes failed for %s.", FullPath));
FreeLibrary (exeModule);
return FALSE;
}
} else if (pIsFileType (FullPath, L"*_")) {
//
// Compressed file. Decompress it.
//
hFile = CreateFileW (
FullPath,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
DEBUGMSGW ((DBG_ERROR, "ExpandFile: Unable to open file %s.", FullPath));
return FALSE;
}
__try {
//
// The real file name is stored at 0x3c.
//
if (0xffffffff == SetFilePointer (hFile, 0x3c, NULL, FILE_BEGIN)) {
DEBUGMSGW ((DBG_ERROR, "ExpandFile: Cannot get real file name for compressed file %s.", FullPath));
rSuccess = FALSE;
__leave;
}
if (!ReadFile (hFile, aName, sizeof(aName), &bytesRead, NULL)) {
DEBUGMSG ((DBG_ERROR, "ExpandFile: Cannot read real file name for compressed file %s.", FullPath));
rSuccess = FALSE;
__leave;
}
if (bytesRead >= ByteCountW (FullPath)) {
uName = ConvertAtoW (aName);
if (StringIMatchTcharCountW (FullPath, uName, TcharCountW (FullPath) - 1)) {
dirName = JoinPathsW (TempDir, pGetExpandName());
fileName = JoinPathsW (dirName, uName);
//
// Create directory for this file and decompress it.
//
if (!CreateDirectoryW (dirName, NULL)) {
DEBUGMSGW ((DBG_ERROR, "ExpandFile: Cannot create directory %s", dirName));
rSuccess = FALSE;
__leave;
}
if (SetupDecompressOrCopyFileW (FullPath, fileName, NULL) != ERROR_SUCCESS) {
DEBUGMSGW ((DBG_ERROR, "ExpandFile: Cannot decompreses %s => %s.", FullPath, fileName));
rSuccess = FALSE;
__leave;
}
//
// Now, run expand recursively on the decompressed file. Could be a CAB or an EXE.
//
rSuccess = ExpandFileW (fileName, dirName);
}
}
}
__finally {
CloseHandle (hFile);
FreePathStringW (dirName);
FreePathStringW (fileName);
}
}
return rSuccess;
}
BOOL
ExpandAllFilesW (
IN PCWSTR FileDir,
IN PCWSTR TempDir
)
{
BOOL rSuccess = TRUE;
TREE_ENUMW e;
if (EnumFirstFileInTreeW (&e, FileDir, L"*", FALSE)) {
do {
if (!e.Directory) {
rSuccess &= ExpandFileW (e.FullPath, TempDir);
}
} while (EnumNextFileInTreeW (&e));
}
DEBUGMSGW_IF ((!rSuccess,DBG_ERROR, "ExpandAllFilesW: One or more errors occurred while expanding all files in %s.", FileDir));
return rSuccess;
}
BOOL
ExpandFileA (
IN PCSTR FullPath,
IN PCSTR TempDir
)
{
PCWSTR wFullPath = NULL;
PCWSTR wTempDir = NULL;
BOOL rSuccess = TRUE;
MYASSERT(FullPath && TempDir);
//
// Convert args and call W version.
//
wFullPath = ConvertAtoW (FullPath);
wTempDir = ConvertAtoW (TempDir);
MYASSERT (wFullPath && wTempDir);
rSuccess = ExpandFileW (wFullPath, wTempDir);
FreeConvertedStr (wFullPath);
FreeConvertedStr (wTempDir);
return rSuccess;
}
BOOL
ExpandAllFilesA (
IN PCSTR FileDir,
IN PCSTR TempDir
)
{
PCWSTR wFileDir = NULL;
PCWSTR wTempDir = NULL;
BOOL rSuccess = TRUE;
MYASSERT(FileDir && TempDir);
//
// Convert args and call W version.
//
wFileDir = ConvertAtoW (FileDir);
wTempDir = ConvertAtoW (TempDir);
MYASSERT (wFileDir && wTempDir);
rSuccess = ExpandAllFilesW (wFileDir, wTempDir);
FreeConvertedStr (wFileDir);
FreeConvertedStr (wTempDir);
return rSuccess;
}