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.
 
 
 
 
 
 

284 lines
9.0 KiB

#include <windows.h>
#include <winerror.h>
#include <ole2.h>
#include "cpldebug.h"
#include "cab_dll.h"
//typedef HRESULT (WINAPI *EXTRACT) (PSESSION psess, LPCSTR lpCabName);
VOID FreeFileList(PSESSION psess);
VOID FreeFileNode(PFNAME pfname);
BOOL IsFileInList(LPSTR pszFile, LPSTR pszFileList);
int PrepareFileList(LPSTR pszOutFileList, LPCSTR pszInFileList);
// BUGBUG: Minimum version of Cabinet DLL that supports the new Extract API
// the one that was formerly in URLMON.DLL.
//
#define MIN_CABINETDLL_MSVER 0
#define MIN_CABINETDLL_LSVER 0
//=--------------------------------------------------------------------------=
// ExtractFiles
//=--------------------------------------------------------------------------=
//
// Parameters:
// LPCSTR pszCabName - [in] full qualified filename to the .CAB file
// LPCSTR pszExpandDir- [in] full qualified path to where to extract the file(s)
// DWORD dwFlags - [in] Flags, currently not used
// LPCSTR pszFileList - [in] colon separated list of files to extract from pszCabName
// or NULL for all files
// LPVOID lpReserved - [in] currently not used
// DWORD dwReserved - [in] currently not used
//
// Return HRESULT:
// E_INVALIDARG - if pszCabName or pszExpandDir == NULL
// E_OUTOFMEMORY - if we could not allocate our memory
// E_FAIL - if no files in pszFileList and pszFileList!=NULL
// if not all files from pszFileList are in the .CAB file
// if Extract return S_FALSE
// any E_ code Extract returns
//
// Note: This function would not extract any file from the pszFileList, if not all
// of them are in the .CAB file. If one or more are not in the .CAB file
// the function does not extract any and returns E_FAIL
//
HRESULT WINAPI ExtractFiles( LPCSTR pszCabName, LPCSTR pszExpandDir, DWORD dwFlags,
LPCSTR pszFileList, LPVOID lpReserved, DWORD dwReserved)
{
HINSTANCE hinst;
PSESSION psess = NULL;
PFNAME pf = NULL;
PFNAME pfPriv = NULL;
HRESULT hr = E_FAIL; // Return error
LPSTR pszMyFileList = NULL;
PFN_EXTRACT fpExtract = NULL;
PFN_DLLGETVERSION fpGetVer = NULL;
int iFiles = 0; // number of files in list
CABINETDLLVERSIONINFO cabDllVer;
// Do checking for valid values??
if ((!pszCabName) || (!pszExpandDir))
return E_INVALIDARG;
hinst = LoadLibrary("CABINET.DLL");
if (hinst)
{
fpGetVer = (PFN_DLLGETVERSION)GetProcAddress(hinst, "DllGetVersion");
// Make sure this is the CABINET.DLL that supports the Extract API
//
if ( fpGetVer )
{
cabDllVer.cbStruct = sizeof(cabDllVer);
fpGetVer( &cabDllVer );
if ( (cabDllVer.dwFileVersionMS > MIN_CABINETDLL_MSVER) ||
(cabDllVer.dwFileVersionMS == MIN_CABINETDLL_MSVER) /* && (cabDllVer.dwFileVersionLS >= MIN_CABINETDLL_LSVER) */ )
{
fpExtract = (PFN_EXTRACT)GetProcAddress(hinst, "Extract");
}
}
if (!fpExtract)
FreeLibrary(hinst);
}
// If we did not get the Extract() API from cabinet.dll go for
// URLMON.DLL
//
if (!fpExtract)
{
hinst = LoadLibrary("URLMON.DLL");
if (hinst)
fpExtract = (PFN_EXTRACT)GetProcAddress(hinst, "Extract");
}
if (fpExtract)
{
psess = (PSESSION)LocalAlloc(LPTR, sizeof(SESSION));
if (psess)
{
lstrcpy(psess->achLocation, pszExpandDir);
// Initialize the structure
if (pszFileList == NULL)
{
// Extract all
psess->flags = SESSION_FLAG_EXTRACT_ALL|SESSION_FLAG_ENUMERATE;
hr = fpExtract(psess, pszCabName);
// BUGBUG: What if psess->erf reports an error??
}
else
{
// I append a '/0' therefor +2
pszMyFileList = (LPSTR)LocalAlloc(LPTR, lstrlen(pszFileList)+2);
if (pszMyFileList)
{
iFiles = PrepareFileList(pszMyFileList, pszFileList);
psess->flags = SESSION_FLAG_ENUMERATE;
if ((iFiles > 0) &&
( !FAILED(hr = fpExtract(psess, pszCabName)) ))
// What if psess->erf reports an error??
{
// If there are files in the list and we enumarated files
// Got the list of files in the cab
pfPriv = NULL;
pf = psess->pFileList;
while (pf != NULL )
{
if (!IsFileInList(pf->pszFilename, pszMyFileList))
{
// Delete the node from the list
if (pfPriv == NULL)
{
// Delete the head
psess->pFileList = pf->pNextName;
FreeFileNode(pf);
pf = psess->pFileList;
}
else
{
pfPriv->pNextName = pf->pNextName;
FreeFileNode(pf);
pf = pfPriv->pNextName;
}
}
else
{
// Just go to the next one
pfPriv = pf;
pf = pf->pNextName;
iFiles--;
}
}
if ((psess->pFileList) && (iFiles == 0))
{
// Reset the error flag
psess->erf.fError = FALSE;
psess->erf.erfOper = 0;
psess->pFilesToExtract = psess->pFileList;
psess->flags &= ~SESSION_FLAG_ENUMERATE; // already enumerated
hr = fpExtract(psess, pszCabName);
// BUGBUG: What if psess->erf reports an error??
}
else
hr = E_FAIL; // File(s) is not in cab.
}
LocalFree(pszMyFileList);
pszMyFileList = NULL;
}
else
hr = E_OUTOFMEMORY;
}
FreeFileList(psess);
LocalFree(psess);
psess = NULL;
}
else
hr = E_OUTOFMEMORY;
}
if (hinst)
FreeLibrary(hinst);
// Extract may only return S_FALSE in a failure case.
if (!FAILED(hr) && (hr == S_FALSE))
hr = E_FAIL;
return (hr);
}
VOID FreeFileList(PSESSION psess)
{
PFNAME rover = psess->pFileList;
PFNAME roverprev;
while (rover != NULL)
{
roverprev = rover; // save for free'ing current rover below
rover = rover->pNextName;
FreeFileNode(roverprev);
}
psess->pFileList = NULL; // prevent use after deletion!
}
VOID FreeFileNode(PFNAME pfname)
{
CoTaskMemFree(pfname->pszFilename);
CoTaskMemFree(pfname);
}
BOOL IsFileInList(LPSTR pszFile, LPSTR pszFileList)
{
char *p;
int iLenFile = lstrlen(pszFile);
BOOL bFound = FALSE;
p = pszFileList;
while ((*p != '\0') && (!bFound))
{
if (lstrlen(p) == iLenFile)
bFound = (lstrcmpi(p, pszFile) == 0);
if (!bFound)
p += lstrlen(p) + 1;
}
return (bFound);
}
int PrepareFileList(LPSTR pszOutFileList, LPCSTR pszInFileList)
{
int iFiles = 0; // number of files in list
char *p;
p = (LPSTR)pszInFileList; // p is used to point into both arrays
// trim leading spaces, tabs or :
while ((*p == ' ') || (*p == '\t') || (*p == ':'))
p++;
lstrcpy(pszOutFileList, p);
p = pszOutFileList;
if (lstrlen(pszOutFileList) > 0)
{
// Only if we have atleast one character left.
// This cannot be a space of tab, because we
// would have removed this above.
p += (lstrlen(pszOutFileList) - 1);
// trim railing spaces, tabs or :
while ((*p == ' ') || (*p == '\t') || (*p == ':'))
p--;
// Put a '\0' for the last space/tab
*(++p) = '\0';
}
if (*pszOutFileList)
{
iFiles++;
// Now replace ':' with '\0'
p = pszOutFileList;
while (*p != '\0')
{
if (*p == ':')
{
*p = '\0';
iFiles++;
}
p++;
}
// Make sure we have a double '\0' at the end.
*(++p) = '\0';
}
return iFiles;
}