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.
2398 lines
57 KiB
2398 lines
57 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cablib.c
|
|
|
|
Abstract:
|
|
|
|
Implements wrappers for cabinet APIs
|
|
|
|
Author:
|
|
|
|
Calin Negreanu (calinn) 27-Apr-2000
|
|
|
|
Revision History:
|
|
|
|
<alias> <date> <comments>
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#include "migutilp.h"
|
|
|
|
#include <cablib.h>
|
|
#include <fci.h>
|
|
#include <fdi.h>
|
|
#include <fcntl.h>
|
|
#include <crt\sys\stat.h>
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
|
|
// None
|
|
|
|
#define DBG_CABLIB "CabLib"
|
|
|
|
//
|
|
// Strings
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
#define VERIFY_HANDLE ((HANDLE) (-2))
|
|
|
|
//
|
|
// Macros
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Types
|
|
//
|
|
|
|
typedef struct {
|
|
PCSTR CabPath;
|
|
PCSTR CabFileFormat;
|
|
PCSTR CabDiskFormat;
|
|
PCABGETCABINETNAMESA CabGetCabinetNames;
|
|
HFCI FciHandle;
|
|
ERF FciErrorStruct;
|
|
CCAB FciCabParams;
|
|
UINT FileCount;
|
|
UINT CabCount;
|
|
LONGLONG FileSize;
|
|
LONGLONG CompressedSize;
|
|
} FCI_CAB_HANDLEA, *PFCI_CAB_HANDLEA;
|
|
|
|
typedef struct {
|
|
PCWSTR CabPath;
|
|
PCWSTR CabFileFormat;
|
|
PCWSTR CabDiskFormat;
|
|
PCABGETCABINETNAMESW CabGetCabinetNames;
|
|
HFCI FciHandle;
|
|
ERF FciErrorStruct;
|
|
CCAB FciCabParams;
|
|
UINT FileCount;
|
|
UINT CabCount;
|
|
LONGLONG FileSize;
|
|
LONGLONG CompressedSize;
|
|
} FCI_CAB_HANDLEW, *PFCI_CAB_HANDLEW;
|
|
|
|
typedef struct {
|
|
PCSTR CabPath;
|
|
PCSTR CabFile;
|
|
HFDI FdiHandle;
|
|
ERF FdiErrorStruct;
|
|
FDICABINETINFO FdiCabinetInfo;
|
|
} FDI_CAB_HANDLEA, *PFDI_CAB_HANDLEA;
|
|
|
|
typedef struct {
|
|
PCWSTR CabPath;
|
|
PCWSTR CabFile;
|
|
HFDI FdiHandle;
|
|
ERF FdiErrorStruct;
|
|
FDICABINETINFO FdiCabinetInfo;
|
|
} FDI_CAB_HANDLEW, *PFDI_CAB_HANDLEW;
|
|
|
|
typedef struct {
|
|
PCSTR ExtractPath;
|
|
PCABNOTIFICATIONA CabNotificationA;
|
|
} CAB_DATAA, *PCAB_DATAA;
|
|
|
|
typedef struct {
|
|
PCWSTR ExtractPath;
|
|
PCABNOTIFICATIONW CabNotificationW;
|
|
BOOL VerifyMode;
|
|
} CAB_DATAW, *PCAB_DATAW;
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Macro expansion list
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Private function prototypes
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Macro expansion definition
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Code
|
|
//
|
|
|
|
INT
|
|
DIAMONDAPI
|
|
pCabFilePlacedA (
|
|
IN PCCAB FciCabParams,
|
|
IN PSTR FileName,
|
|
IN LONG FileSize,
|
|
IN BOOL Continuation,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCI_CAB_HANDLEA cabHandle;
|
|
|
|
MYASSERT(Context);
|
|
|
|
cabHandle = (PFCI_CAB_HANDLEA) Context;
|
|
if (!cabHandle) {
|
|
return 0;
|
|
}
|
|
|
|
cabHandle->FileCount++;
|
|
cabHandle->FileSize += FileSize;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
INT
|
|
DIAMONDAPI
|
|
pCabFilePlacedW (
|
|
IN PCCAB FciCabParams,
|
|
IN PSTR FileName,
|
|
IN LONG FileSize,
|
|
IN BOOL Continuation,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCI_CAB_HANDLEW cabHandle;
|
|
|
|
MYASSERT(Context);
|
|
|
|
cabHandle = (PFCI_CAB_HANDLEW) Context;
|
|
if (!cabHandle) {
|
|
return 0;
|
|
}
|
|
|
|
cabHandle->FileCount++;
|
|
cabHandle->FileSize += FileSize;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
PVOID
|
|
DIAMONDAPI
|
|
pCabAlloc (
|
|
IN ULONG Size
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
MYASSERT(Size);
|
|
|
|
return MemAlloc (g_hHeap, 0, Size);
|
|
}
|
|
|
|
VOID
|
|
DIAMONDAPI
|
|
pCabFree (
|
|
IN PVOID Memory
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
MYASSERT(Memory);
|
|
|
|
MemFree (g_hHeap, 0, Memory);
|
|
}
|
|
|
|
INT_PTR
|
|
DIAMONDAPI
|
|
pCabOpenA (
|
|
IN PSTR FileName,
|
|
IN INT oFlag,
|
|
IN INT pMode,
|
|
OUT PINT Error,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE fileHandle;
|
|
|
|
if(!FileName){
|
|
MYASSERT(FileName);
|
|
if(Error){
|
|
*Error = ERROR_FILE_NOT_FOUND;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// oFlag and pMode are prepared for using _open. We won't do that
|
|
// and it's a terrible waste of time to check each individual flags
|
|
// We'll just assert these values.
|
|
MYASSERT ((oFlag == (_O_CREAT | _O_TRUNC | _O_BINARY | _O_RDWR)) || (oFlag == (_O_CREAT | _O_EXCL | _O_BINARY | _O_RDWR)));
|
|
MYASSERT (pMode == (_S_IREAD | _S_IWRITE));
|
|
|
|
fileHandle = CreateFileA (
|
|
FileName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_ARCHIVE,
|
|
NULL
|
|
);
|
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
|
if(Error){
|
|
*Error = GetLastError ();
|
|
}
|
|
return -1;
|
|
}
|
|
if(Error){
|
|
*Error = 0;
|
|
}
|
|
|
|
return (INT_PTR)fileHandle;
|
|
}
|
|
|
|
INT_PTR
|
|
DIAMONDAPI
|
|
pCabOpen1A (
|
|
IN PSTR FileName,
|
|
IN INT oFlag,
|
|
IN INT pMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE fileHandle;
|
|
|
|
if(!FileName){
|
|
MYASSERT(FileName);
|
|
return -1;
|
|
}
|
|
|
|
// oFlag and pMode are prepared for using _open. We won't do that
|
|
// and it's a terrible waste of time to check each individual flags
|
|
// We'll just assert these values.
|
|
MYASSERT (oFlag == _O_BINARY);
|
|
|
|
fileHandle = CreateFileA (
|
|
FileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_ARCHIVE,
|
|
NULL
|
|
);
|
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
|
return -1;
|
|
}
|
|
return (INT_PTR)fileHandle;
|
|
}
|
|
|
|
UINT
|
|
DIAMONDAPI
|
|
pCabRead (
|
|
IN INT_PTR FileHandle,
|
|
IN PVOID Buffer,
|
|
IN UINT Size,
|
|
OUT PINT Error,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL result;
|
|
UINT bytesRead;
|
|
|
|
MYASSERT(((HANDLE)FileHandle) != INVALID_HANDLE_VALUE);
|
|
MYASSERT(Buffer);
|
|
MYASSERT(Size);
|
|
|
|
result = ReadFile ((HANDLE)FileHandle, Buffer, Size, &bytesRead, NULL);
|
|
if (!result) {
|
|
if(Error){
|
|
*Error = GetLastError ();
|
|
}
|
|
return ((UINT)(-1));
|
|
}
|
|
if(Error){
|
|
*Error = 0;
|
|
}
|
|
|
|
return bytesRead;
|
|
}
|
|
|
|
UINT
|
|
DIAMONDAPI
|
|
pCabRead1 (
|
|
IN INT_PTR FileHandle,
|
|
IN PVOID Buffer,
|
|
IN UINT Size
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL result;
|
|
UINT bytesRead;
|
|
|
|
MYASSERT(((HANDLE)FileHandle) != INVALID_HANDLE_VALUE);
|
|
MYASSERT(Buffer);
|
|
MYASSERT(Size);
|
|
|
|
result = ReadFile ((HANDLE)FileHandle, Buffer, Size, &bytesRead, NULL);
|
|
if (!result) {
|
|
return ((UINT)(-1));
|
|
}
|
|
return bytesRead;
|
|
}
|
|
|
|
UINT
|
|
DIAMONDAPI
|
|
pCabWrite (
|
|
IN INT_PTR FileHandle,
|
|
IN PVOID Buffer,
|
|
IN UINT Size,
|
|
OUT PINT Error,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL result;
|
|
DWORD dontCare;
|
|
|
|
MYASSERT(((HANDLE)FileHandle) != INVALID_HANDLE_VALUE);
|
|
MYASSERT(Buffer);
|
|
MYASSERT(Size);
|
|
|
|
if (FileHandle == (INT_PTR) VERIFY_HANDLE) {
|
|
return Size;
|
|
}
|
|
|
|
result = WriteFile ((HANDLE)FileHandle, Buffer, Size, &dontCare, NULL);
|
|
if (!result) {
|
|
if(Error){
|
|
*Error = GetLastError ();
|
|
}
|
|
return ((UINT)(-1));
|
|
}
|
|
|
|
if(Error){
|
|
*Error = 0;
|
|
}
|
|
|
|
return Size;
|
|
}
|
|
|
|
UINT
|
|
DIAMONDAPI
|
|
pCabWrite1 (
|
|
IN INT_PTR FileHandle,
|
|
IN PVOID Buffer,
|
|
IN UINT Size
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL result;
|
|
DWORD dontCare;
|
|
|
|
MYASSERT(((HANDLE)FileHandle) != INVALID_HANDLE_VALUE);
|
|
MYASSERT(Buffer);
|
|
MYASSERT(Size);
|
|
|
|
if (FileHandle == (INT_PTR) VERIFY_HANDLE) {
|
|
return Size;
|
|
}
|
|
|
|
result = WriteFile ((HANDLE)FileHandle, Buffer, Size, &dontCare, NULL);
|
|
if (!result) {
|
|
return ((UINT)(-1));
|
|
}
|
|
|
|
return Size;
|
|
}
|
|
|
|
INT
|
|
DIAMONDAPI
|
|
pCabClose (
|
|
IN INT_PTR FileHandle,
|
|
OUT PINT Error,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
MYASSERT(((HANDLE)FileHandle) != INVALID_HANDLE_VALUE);
|
|
|
|
CloseHandle ((HANDLE)FileHandle);
|
|
if(Error){
|
|
*Error = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
INT
|
|
DIAMONDAPI
|
|
pCabClose1 (
|
|
IN INT_PTR FileHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
MYASSERT(((HANDLE)FileHandle) != INVALID_HANDLE_VALUE);
|
|
|
|
CloseHandle ((HANDLE)FileHandle);
|
|
return 0;
|
|
}
|
|
|
|
LONG
|
|
DIAMONDAPI
|
|
pCabSeek (
|
|
IN INT_PTR FileHandle,
|
|
IN LONG Distance,
|
|
IN INT SeekType,
|
|
OUT PINT Error,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD result;
|
|
DWORD seekType = FILE_BEGIN;
|
|
|
|
MYASSERT(((HANDLE)FileHandle) != INVALID_HANDLE_VALUE);
|
|
|
|
switch (SeekType) {
|
|
case SEEK_SET:
|
|
seekType = FILE_BEGIN;
|
|
break;
|
|
case SEEK_CUR:
|
|
seekType = FILE_CURRENT;
|
|
break;
|
|
case SEEK_END:
|
|
seekType = FILE_END;
|
|
break;
|
|
}
|
|
|
|
result = SetFilePointer ((HANDLE)FileHandle, Distance, NULL, seekType);
|
|
|
|
if (result == INVALID_SET_FILE_POINTER) {
|
|
*Error = GetLastError ();
|
|
return -1;
|
|
}
|
|
*Error = 0;
|
|
return ((LONG)(result));
|
|
}
|
|
|
|
LONG
|
|
DIAMONDAPI
|
|
pCabSeek1 (
|
|
IN INT_PTR FileHandle,
|
|
IN LONG Distance,
|
|
IN INT SeekType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD result;
|
|
DWORD seekType = FILE_BEGIN;
|
|
|
|
MYASSERT(((HANDLE)FileHandle) != INVALID_HANDLE_VALUE);
|
|
|
|
switch (SeekType) {
|
|
case SEEK_SET:
|
|
seekType = FILE_BEGIN;
|
|
break;
|
|
case SEEK_CUR:
|
|
seekType = FILE_CURRENT;
|
|
break;
|
|
case SEEK_END:
|
|
seekType = FILE_END;
|
|
break;
|
|
}
|
|
|
|
result = SetFilePointer ((HANDLE)FileHandle, Distance, NULL, seekType);
|
|
|
|
if (result == INVALID_SET_FILE_POINTER) {
|
|
return -1;
|
|
}
|
|
return ((LONG)(result));
|
|
}
|
|
|
|
INT
|
|
DIAMONDAPI
|
|
pCabDeleteA (
|
|
IN PSTR FileName,
|
|
OUT PINT Error,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
MYASSERT(FileName);
|
|
MYASSERT(Error);
|
|
|
|
if (!DeleteFileA (FileName)) {
|
|
*Error = GetLastError ();
|
|
return -1;
|
|
}
|
|
*Error = 0;
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
DIAMONDAPI
|
|
pCabGetTempFileA (
|
|
OUT PSTR FileName,
|
|
IN INT FileNameLen,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR tempPath[MAX_PATH];
|
|
PSTR p;
|
|
|
|
MYASSERT(FileName);
|
|
|
|
if (!GetTempPathA (ARRAYSIZE(tempPath), tempPath)) {
|
|
return FALSE;
|
|
}
|
|
|
|
p = _mbsrchr (tempPath, '\\');
|
|
if (p && !p[1]) {
|
|
*p = 0;
|
|
}
|
|
|
|
if (!DoesFileExistA (tempPath)) {
|
|
CreateDirectoryA (tempPath, NULL);
|
|
}
|
|
|
|
if (!GetTempFileNameA (tempPath, "cab", 0, FileName)) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
DIAMONDAPI
|
|
pCabGetNextCabinetA (
|
|
IN PCCAB FciCabParams,
|
|
IN ULONG PrevCabinetSize,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCI_CAB_HANDLEA cabHandle;
|
|
CHAR cabFile [CB_MAX_CABINET_NAME];
|
|
CHAR cabDisk [CB_MAX_DISK_NAME];
|
|
|
|
MYASSERT(Context);
|
|
|
|
cabHandle = (PFCI_CAB_HANDLEA) Context;
|
|
if (!cabHandle) {
|
|
return FALSE;
|
|
}
|
|
if (cabHandle->CabGetCabinetNames) {
|
|
return cabHandle->CabGetCabinetNames (
|
|
FciCabParams->szCabPath,
|
|
CB_MAX_CAB_PATH,
|
|
FciCabParams->szCab,
|
|
CB_MAX_CABINET_NAME,
|
|
FciCabParams->szDisk,
|
|
CB_MAX_DISK_NAME,
|
|
FciCabParams->iCab,
|
|
&FciCabParams->iDisk
|
|
);
|
|
} else {
|
|
FciCabParams->iDisk = FciCabParams->iCab;
|
|
if (cabHandle->CabFileFormat) {
|
|
if(_snprintf(cabFile, CB_MAX_CABINET_NAME, cabHandle->CabFileFormat, FciCabParams->iCab) < 0){
|
|
cabFile[CB_MAX_CABINET_NAME - 1] = '\0';
|
|
DEBUGMSG((DBG_ERROR, "pCabGetNextCabinetW: _snprintf truncated cabfile %s", cabFile));
|
|
//BUGBUG: we have truncated path, what to do?
|
|
//return TRUE;
|
|
}
|
|
StringCopyByteCountA (FciCabParams->szCab, cabFile, CB_MAX_CABINET_NAME * sizeof (CHAR));
|
|
}
|
|
if (cabHandle->CabDiskFormat) {
|
|
if(_snprintf(cabDisk, CB_MAX_DISK_NAME, cabHandle->CabDiskFormat, FciCabParams->iDisk) < 0){
|
|
cabDisk[CB_MAX_DISK_NAME - 1] = '\0';
|
|
DEBUGMSG((DBG_ERROR, "pCabGetNextCabinetW: _snprintf truncated cabdisk %s", cabDisk));
|
|
//BUGBUG: we have truncated path, what to do?
|
|
//return TRUE;
|
|
}
|
|
StringCopyByteCountA (FciCabParams->szDisk, cabDisk, CB_MAX_DISK_NAME * sizeof (CHAR));
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
DIAMONDAPI
|
|
pCabGetNextCabinetW (
|
|
IN PCCAB FciCabParams,
|
|
IN ULONG PrevCabinetSize,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCI_CAB_HANDLEW cabHandle;
|
|
WCHAR cabPath [CB_MAX_CAB_PATH];
|
|
WCHAR cabFile [CB_MAX_CABINET_NAME];
|
|
WCHAR cabDisk [CB_MAX_DISK_NAME];
|
|
BOOL result;
|
|
|
|
MYASSERT(Context);
|
|
MYASSERT(FciCabParams);
|
|
|
|
cabHandle = (PFCI_CAB_HANDLEW) Context;
|
|
if (!cabHandle) {
|
|
return FALSE;
|
|
}
|
|
if (cabHandle->CabGetCabinetNames) {
|
|
result = cabHandle->CabGetCabinetNames (
|
|
cabPath,
|
|
CB_MAX_CAB_PATH,
|
|
cabFile,
|
|
CB_MAX_CABINET_NAME,
|
|
cabDisk,
|
|
CB_MAX_DISK_NAME,
|
|
FciCabParams->iCab,
|
|
&FciCabParams->iDisk
|
|
);
|
|
if (result) {
|
|
KnownSizeUnicodeToDbcs (FciCabParams->szCabPath, cabPath);
|
|
KnownSizeUnicodeToDbcs (FciCabParams->szCab, cabFile);
|
|
KnownSizeUnicodeToDbcs (FciCabParams->szDisk, cabDisk);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
} else {
|
|
FciCabParams->iDisk = FciCabParams->iCab;
|
|
if (cabHandle->CabFileFormat) {
|
|
if(_snwprintf(cabFile, CB_MAX_CABINET_NAME, cabHandle->CabFileFormat, FciCabParams->iCab) < 0){
|
|
cabFile[CB_MAX_CABINET_NAME - 1] = '\0';
|
|
DEBUGMSG((DBG_ERROR, "pCabGetNextCabinetW: _snwprintf truncated cabfile %s", cabFile));
|
|
//BUGBUG: we have truncated path, what to do?
|
|
//return TRUE;
|
|
}
|
|
KnownSizeUnicodeToDbcs (FciCabParams->szCab, cabFile);
|
|
}
|
|
if (cabHandle->CabDiskFormat) {
|
|
if(_snwprintf(cabDisk, CB_MAX_DISK_NAME, cabHandle->CabDiskFormat, FciCabParams->iDisk) < 0){
|
|
cabDisk[CB_MAX_DISK_NAME - 1] = '\0';
|
|
DEBUGMSG((DBG_ERROR, "pCabGetNextCabinetW: _snwprintf truncated cabdisk %s", cabDisk));
|
|
//BUGBUG: we have truncated path, what to do?
|
|
//return TRUE;
|
|
}
|
|
KnownSizeUnicodeToDbcs (FciCabParams->szDisk, cabDisk);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
LONG
|
|
DIAMONDAPI
|
|
pCabStatusA (
|
|
IN UINT StatusType,
|
|
IN ULONG Size1,
|
|
IN ULONG Size2,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCI_CAB_HANDLEA cabHandle;
|
|
|
|
if (StatusType == statusCabinet) {
|
|
|
|
MYASSERT(Context);
|
|
cabHandle = (PFCI_CAB_HANDLEA) Context;
|
|
if (!cabHandle) {
|
|
return 0;
|
|
}
|
|
|
|
cabHandle->CabCount++;
|
|
cabHandle->CompressedSize += (LONGLONG) Size2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LONG
|
|
DIAMONDAPI
|
|
pCabStatusW (
|
|
IN UINT StatusType,
|
|
IN ULONG Size1,
|
|
IN ULONG Size2,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCI_CAB_HANDLEW cabHandle;
|
|
|
|
if (StatusType == statusCabinet) {
|
|
|
|
MYASSERT(Context);
|
|
cabHandle = (PFCI_CAB_HANDLEW) Context;
|
|
if (!cabHandle) {
|
|
return 0;
|
|
}
|
|
|
|
cabHandle->CabCount++;
|
|
cabHandle->CompressedSize += (LONGLONG) Size2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
INT_PTR
|
|
DIAMONDAPI
|
|
pCabGetOpenInfoA (
|
|
IN PSTR FileName,
|
|
OUT USHORT *Date,
|
|
OUT USHORT *Time,
|
|
OUT USHORT *Attributes,
|
|
OUT PINT Error,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
WIN32_FIND_DATAA findData;
|
|
FILETIME fileTime;
|
|
HANDLE fileHandle;
|
|
|
|
MYASSERT(FileName);
|
|
MYASSERT(Error);
|
|
|
|
if (DoesFileExistExA (FileName, &findData)) {
|
|
|
|
FileTimeToLocalFileTime (&findData.ftLastWriteTime, &fileTime);
|
|
FileTimeToDosDateTime (&fileTime, Date, Time);
|
|
|
|
/*
|
|
* Mask out all other bits except these four, since other
|
|
* bits are used by the cabinet format to indicate a
|
|
* special meaning.
|
|
*/
|
|
*Attributes = (USHORT) (findData.dwFileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE));
|
|
|
|
fileHandle = CreateFileA (
|
|
FileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
|
*Error = GetLastError ();
|
|
return -1;
|
|
}
|
|
*Error = 0;
|
|
return (INT_PTR)fileHandle;
|
|
} else {
|
|
*Error = GetLastError ();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
pIsFullPathA (
|
|
IN PCSTR PathToTest
|
|
)
|
|
{
|
|
MBCHAR ch1;
|
|
MBCHAR ch2;
|
|
|
|
MYASSERT(PathToTest);
|
|
|
|
ch1 = _mbsnextc (PathToTest);
|
|
_mbsinc (PathToTest);
|
|
ch2 = _mbsnextc (PathToTest);
|
|
|
|
if ((ch1 == '\\' && ch2 == '\\') ||
|
|
(isalpha (ch1) && ch2 == '\\')
|
|
) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pIsFullPathW (
|
|
IN PCWSTR PathToTest
|
|
)
|
|
{
|
|
WCHAR ch1;
|
|
WCHAR ch2;
|
|
|
|
MYASSERT(PathToTest);
|
|
|
|
ch1 = *PathToTest++;
|
|
ch2 = *PathToTest;
|
|
|
|
if ((ch1 == '\\' && ch2 == '\\') ||
|
|
(isalpha (ch1) && ch2 == '\\')
|
|
) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
PCSTR
|
|
pComputeDestPathA (
|
|
IN PCSTR ExtractPath, OPTIONAL
|
|
IN PCSTR PathStoredInCab
|
|
)
|
|
{
|
|
PCSTR destFile;
|
|
|
|
MYASSERT(PathStoredInCab);
|
|
|
|
//
|
|
// If ExtractPath is NULL, then use the path stored in the cab.
|
|
// If the path stored in the cab is a full path, use only the file name.
|
|
// Otherwise join ExtractPath with PathStoredInCab.
|
|
//
|
|
|
|
if (!ExtractPath) {
|
|
|
|
destFile = DuplicatePathStringA (PathStoredInCab, 0);
|
|
|
|
} else if (pIsFullPathA (PathStoredInCab)) {
|
|
|
|
destFile = JoinPathsA (ExtractPath, GetFileNameFromPathA (PathStoredInCab));
|
|
|
|
} else {
|
|
|
|
destFile = JoinPathsA (ExtractPath, PathStoredInCab);
|
|
|
|
}
|
|
|
|
return destFile;
|
|
}
|
|
|
|
|
|
PCWSTR
|
|
pComputeDestPathW (
|
|
IN PCWSTR ExtractPath, OPTIONAL
|
|
IN PCWSTR PathStoredInCab
|
|
)
|
|
{
|
|
PCWSTR destFile;
|
|
|
|
MYASSERT(PathStoredInCab);
|
|
|
|
//
|
|
// If ExtractPath is NULL, then use the path stored in the cab.
|
|
// If the path stored in the cab is a full path, use only the file name.
|
|
// Otherwise join ExtractPath with PathStoredInCab.
|
|
//
|
|
|
|
if (!ExtractPath) {
|
|
|
|
destFile = DuplicatePathStringW (PathStoredInCab, 0);
|
|
|
|
} else if (pIsFullPathW (PathStoredInCab)) {
|
|
|
|
destFile = JoinPathsW (ExtractPath, GetFileNameFromPathW (PathStoredInCab));
|
|
|
|
} else {
|
|
|
|
destFile = JoinPathsW (ExtractPath, PathStoredInCab);
|
|
|
|
}
|
|
|
|
return destFile;
|
|
}
|
|
|
|
|
|
INT_PTR
|
|
DIAMONDAPI
|
|
pCabNotificationA (
|
|
IN FDINOTIFICATIONTYPE FdiNotificationType,
|
|
IN OUT PFDINOTIFICATION FdiNotification
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
PCSTR destFile = NULL;
|
|
HANDLE destHandle = NULL;
|
|
DWORD attributes;
|
|
FILETIME localFileTime;
|
|
FILETIME fileTime;
|
|
PCAB_DATAA cabData;
|
|
INT createFlag;
|
|
|
|
switch (FdiNotificationType) {
|
|
case fdintCABINET_INFO: // General information about cabinet
|
|
return 0;
|
|
case fdintCOPY_FILE: // File to be copied
|
|
|
|
cabData = (PCAB_DATAA)FdiNotification->pv;
|
|
|
|
destFile = pComputeDestPathA (cabData->ExtractPath, FdiNotification->psz1);
|
|
MYASSERT(destFile);
|
|
createFlag = TRUE;
|
|
|
|
if (cabData->CabNotificationA) {
|
|
createFlag = cabData->CabNotificationA (destFile);
|
|
}
|
|
|
|
if(-1 == createFlag){
|
|
FreePathStringA (destFile);
|
|
return -1;
|
|
}
|
|
|
|
if (createFlag) {
|
|
MakeSurePathExistsA (FdiNotification->psz1, FALSE);
|
|
|
|
SetFileAttributesA (destFile, FILE_ATTRIBUTE_NORMAL);
|
|
destHandle = CreateFileA (
|
|
destFile,
|
|
GENERIC_READ|GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
}
|
|
FreePathStringA (destFile);
|
|
return (INT_PTR)destHandle;
|
|
case fdintCLOSE_FILE_INFO: // close the file, set relevant info
|
|
cabData = (PCAB_DATAA)FdiNotification->pv;
|
|
if (DosDateTimeToFileTime (FdiNotification->date, FdiNotification->time, &localFileTime)) {
|
|
if (LocalFileTimeToFileTime (&localFileTime, &fileTime)) {
|
|
SetFileTime ((HANDLE)FdiNotification->hf, &fileTime, &fileTime, &fileTime);
|
|
}
|
|
}
|
|
|
|
destFile = pComputeDestPathA (cabData->ExtractPath, FdiNotification->psz1);
|
|
|
|
CloseHandle ((HANDLE)FdiNotification->hf);
|
|
attributes = (FdiNotification->attribs & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE));
|
|
SetFileAttributesA (destFile, attributes);
|
|
|
|
FreePathStringA (destFile);
|
|
return TRUE;
|
|
case fdintPARTIAL_FILE: // First file in cabinet is continuation
|
|
return 0;
|
|
case fdintENUMERATE: // Enumeration status
|
|
return 0;
|
|
case fdintNEXT_CABINET: // File continued to next cabinet
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
INT_PTR
|
|
DIAMONDAPI
|
|
pCabNotificationW (
|
|
IN FDINOTIFICATIONTYPE FdiNotificationType,
|
|
IN OUT PFDINOTIFICATION FdiNotification
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback for cabinet compression/decompression. For more information see fci.h/fdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
PCWSTR destFile = NULL;
|
|
HANDLE destHandle = NULL;
|
|
DWORD attributes;
|
|
FILETIME localFileTime;
|
|
FILETIME fileTime;
|
|
PCAB_DATAW cabData;
|
|
INT createFlag;
|
|
PCWSTR cabFileSpecW;
|
|
|
|
switch (FdiNotificationType) {
|
|
case fdintCABINET_INFO: // General information about cabinet
|
|
return 0;
|
|
case fdintCOPY_FILE: // File to be copied
|
|
|
|
cabFileSpecW = ConvertAtoW (FdiNotification->psz1);
|
|
cabData = (PCAB_DATAW)FdiNotification->pv;
|
|
|
|
destFile = pComputeDestPathW (cabData->ExtractPath, cabFileSpecW);
|
|
MYASSERT(destFile);
|
|
|
|
FreeConvertedStr (cabFileSpecW);
|
|
createFlag = TRUE;
|
|
|
|
if (cabData->CabNotificationW) {
|
|
createFlag = cabData->CabNotificationW (destFile);
|
|
}
|
|
|
|
if(-1 == createFlag){
|
|
FreePathStringW (destFile);
|
|
return -1;
|
|
}
|
|
|
|
if (createFlag) {
|
|
if (!cabData->VerifyMode) {
|
|
MakeSurePathExistsW (cabFileSpecW, FALSE);
|
|
|
|
SetFileAttributesW (destFile, FILE_ATTRIBUTE_NORMAL);
|
|
destHandle = CreateFileW (
|
|
destFile,
|
|
GENERIC_READ|GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
} else {
|
|
destHandle = VERIFY_HANDLE;
|
|
}
|
|
}
|
|
|
|
FreePathStringW (destFile);
|
|
return (INT_PTR)destHandle;
|
|
case fdintCLOSE_FILE_INFO: // close the file, set relevant info
|
|
cabData = (PCAB_DATAW)FdiNotification->pv;
|
|
if (DosDateTimeToFileTime (FdiNotification->date, FdiNotification->time, &localFileTime)) {
|
|
if (LocalFileTimeToFileTime (&localFileTime, &fileTime)) {
|
|
SetFileTime ((HANDLE)FdiNotification->hf, &fileTime, &fileTime, &fileTime);
|
|
}
|
|
}
|
|
|
|
cabFileSpecW = ConvertAtoW (FdiNotification->psz1);
|
|
destFile = pComputeDestPathW (cabData->ExtractPath, cabFileSpecW);
|
|
MYASSERT(destFile);
|
|
FreeConvertedStr (cabFileSpecW);
|
|
|
|
CloseHandle ((HANDLE)FdiNotification->hf);
|
|
attributes = (FdiNotification->attribs & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE));
|
|
SetFileAttributesW (destFile, attributes);
|
|
FreePathStringW (destFile);
|
|
return TRUE;
|
|
case fdintPARTIAL_FILE: // First file in cabinet is continuation
|
|
return 0;
|
|
case fdintENUMERATE: // Enumeration status
|
|
return 0;
|
|
case fdintNEXT_CABINET: // File continued to next cabinet
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
CCABHANDLE
|
|
CabCreateCabinetA (
|
|
IN PCSTR CabPath,
|
|
IN PCSTR CabFileFormat,
|
|
IN PCSTR CabDiskFormat,
|
|
IN LONG MaxFileSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a cabinet context. Caller may use this context for subsequent calls to
|
|
CabAddFile.
|
|
|
|
Arguments:
|
|
|
|
CabPath - Specifies the path where the new cabinet file will be.
|
|
|
|
CabFileFormat - Specifies (as for wsprintf) the format of the cabinet file name.
|
|
|
|
CabDiskFormat - Specifies (as for wsprintf) the format of the cabinet disk name.
|
|
|
|
MaxFileSize - Specifies maximum size of the cabinet file (limited to 2GB). if 0 => 2GB
|
|
|
|
Return Value:
|
|
|
|
a valid CCABHANDLE if successful, NULL otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCI_CAB_HANDLEA cabHandle;
|
|
CHAR cabFile [CB_MAX_CABINET_NAME];
|
|
CHAR cabDisk [CB_MAX_DISK_NAME];
|
|
|
|
if(!CabPath){
|
|
MYASSERT(CabPath);
|
|
return NULL;
|
|
}
|
|
|
|
if (!CabFileFormat) {
|
|
return NULL;
|
|
}
|
|
|
|
if (MaxFileSize < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (MaxFileSize == 0) {
|
|
MaxFileSize = 0x7FFFFFFF;
|
|
}
|
|
|
|
cabHandle = (PFCI_CAB_HANDLEA) MemAlloc (g_hHeap, 0, sizeof (FCI_CAB_HANDLEA));
|
|
ZeroMemory (cabHandle, sizeof (FCI_CAB_HANDLEA));
|
|
if (CabPath) {
|
|
cabHandle->CabPath = DuplicatePathStringA (CabPath, 0);
|
|
}
|
|
cabHandle->CabFileFormat = DuplicatePathStringA (CabFileFormat, 0);
|
|
if (CabDiskFormat) {
|
|
cabHandle->CabDiskFormat = DuplicatePathStringA (CabDiskFormat, 0);
|
|
}
|
|
|
|
// fill out the CCAB structure
|
|
cabHandle->FciCabParams.cb = MaxFileSize;
|
|
cabHandle->FciCabParams.cbFolderThresh = MaxFileSize;
|
|
cabHandle->FciCabParams.cbReserveCFHeader = 0;
|
|
cabHandle->FciCabParams.cbReserveCFFolder = 0;
|
|
cabHandle->FciCabParams.cbReserveCFData = 0;
|
|
cabHandle->FciCabParams.iCab = 1;
|
|
cabHandle->FciCabParams.iDisk = 1;
|
|
cabHandle->FciCabParams.setID = 0;
|
|
if (CabPath) {
|
|
StringCopyByteCountA (cabHandle->FciCabParams.szCabPath, CabPath, CB_MAX_CAB_PATH - 1);
|
|
AppendWackA (cabHandle->FciCabParams.szCabPath);
|
|
}
|
|
if (CabDiskFormat) {
|
|
if(_snprintf(cabDisk, CB_MAX_DISK_NAME, CabDiskFormat, cabHandle->FciCabParams.iDisk) < 0){
|
|
cabDisk[CB_MAX_DISK_NAME - 1] = '\0';
|
|
DEBUGMSG((DBG_ERROR, "CabCreateCabinetA: _snwprintf truncated cabdisk %s", cabDisk));
|
|
//BUGBUG: we have truncated path, what to do?
|
|
//return NULL;
|
|
}
|
|
StringCopyByteCountA (cabHandle->FciCabParams.szDisk, cabDisk, CB_MAX_DISK_NAME * sizeof (CHAR));
|
|
}
|
|
if(_snprintf(cabFile, CB_MAX_CABINET_NAME, CabFileFormat, cabHandle->FciCabParams.iCab) < 0){
|
|
cabFile[CB_MAX_CABINET_NAME - 1] = '\0';
|
|
DEBUGMSG((DBG_ERROR, "CabCreateCabinetA: _snwprintf truncated cabfile %s", cabFile));
|
|
//BUGBUG: we have truncated path, what to do?
|
|
//return NULL;
|
|
}
|
|
StringCopyByteCountA (cabHandle->FciCabParams.szCab, cabFile, CB_MAX_CABINET_NAME * sizeof (CHAR));
|
|
|
|
cabHandle->FciHandle = FCICreate (
|
|
&cabHandle->FciErrorStruct,
|
|
pCabFilePlacedA,
|
|
pCabAlloc,
|
|
pCabFree,
|
|
pCabOpenA,
|
|
pCabRead,
|
|
pCabWrite,
|
|
pCabClose,
|
|
pCabSeek,
|
|
pCabDeleteA,
|
|
pCabGetTempFileA,
|
|
&cabHandle->FciCabParams,
|
|
cabHandle
|
|
);
|
|
if (!cabHandle->FciHandle) {
|
|
if (cabHandle->CabPath) {
|
|
FreePathStringA (cabHandle->CabPath);
|
|
}
|
|
if (cabHandle->CabFileFormat) {
|
|
FreePathStringA (cabHandle->CabFileFormat);
|
|
}
|
|
if (cabHandle->CabDiskFormat) {
|
|
FreePathStringA (cabHandle->CabDiskFormat);
|
|
}
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
return NULL;
|
|
}
|
|
return ((CCABHANDLE)(cabHandle));
|
|
}
|
|
|
|
CCABHANDLE
|
|
CabCreateCabinetW (
|
|
IN PCWSTR CabPath,
|
|
IN PCWSTR CabFileFormat,
|
|
IN PCWSTR CabDiskFormat,
|
|
IN LONG MaxFileSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a cabinet context. Caller may use this context for subsequent calls to
|
|
CabAddFile.
|
|
|
|
Arguments:
|
|
|
|
CabPath - Specifies the path where the new cabinet file will be.
|
|
|
|
CabFileFormat - Specifies (as for wsprintf) the format of the cabinet file name.
|
|
|
|
CabDiskFormat - Specifies (as for wsprintf) the format of the cabinet disk name.
|
|
|
|
MaxFileSize - Specifies maximum size of the cabinet file (limited to 2GB). if 0 => 2GB
|
|
|
|
Return Value:
|
|
|
|
a valid CCABHANDLE if successful, NULL otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCI_CAB_HANDLEW cabHandle;
|
|
WCHAR cabFile [CB_MAX_CABINET_NAME];
|
|
WCHAR cabDisk [CB_MAX_DISK_NAME];
|
|
|
|
if(!CabPath){
|
|
MYASSERT(CabPath);
|
|
return NULL;
|
|
}
|
|
|
|
if (!CabFileFormat) {
|
|
return NULL;
|
|
}
|
|
|
|
if (MaxFileSize < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (MaxFileSize == 0) {
|
|
MaxFileSize = 0x7FFFFFFF;
|
|
}
|
|
|
|
cabHandle = (PFCI_CAB_HANDLEW) MemAlloc (g_hHeap, 0, sizeof (FCI_CAB_HANDLEW));
|
|
ZeroMemory (cabHandle, sizeof (FCI_CAB_HANDLEW));
|
|
if (CabPath) {
|
|
cabHandle->CabPath = DuplicatePathStringW (CabPath, 0);
|
|
}
|
|
cabHandle->CabFileFormat = DuplicatePathStringW (CabFileFormat, 0);
|
|
if (CabDiskFormat) {
|
|
cabHandle->CabDiskFormat = DuplicatePathStringW (CabDiskFormat, 0);
|
|
}
|
|
|
|
// fill out the CCAB structure
|
|
cabHandle->FciCabParams.cb = MaxFileSize;
|
|
cabHandle->FciCabParams.cbFolderThresh = MaxFileSize;
|
|
cabHandle->FciCabParams.cbReserveCFHeader = 0;
|
|
cabHandle->FciCabParams.cbReserveCFFolder = 0;
|
|
cabHandle->FciCabParams.cbReserveCFData = 0;
|
|
cabHandle->FciCabParams.iCab = 1;
|
|
cabHandle->FciCabParams.iDisk = 1;
|
|
cabHandle->FciCabParams.setID = 0;
|
|
if (CabPath) {
|
|
KnownSizeUnicodeToDbcs (cabHandle->FciCabParams.szCabPath, CabPath);
|
|
AppendWackA (cabHandle->FciCabParams.szCabPath);
|
|
}
|
|
if (CabDiskFormat) {
|
|
if(_snwprintf(cabDisk, CB_MAX_DISK_NAME, CabDiskFormat, cabHandle->FciCabParams.iDisk) < 0){
|
|
cabDisk[CB_MAX_DISK_NAME - 1] = '\0';
|
|
DEBUGMSG((DBG_ERROR, "CabCreateCabinetW: _snwprintf truncated cabdisk %s", cabDisk));
|
|
//BUGBUG: we have truncated path, what to do?
|
|
//return NULL;
|
|
}
|
|
KnownSizeUnicodeToDbcs (cabHandle->FciCabParams.szDisk, cabDisk);
|
|
}
|
|
if(_snwprintf(cabFile, CB_MAX_CABINET_NAME, CabFileFormat, cabHandle->FciCabParams.iCab) < 0){
|
|
cabFile[CB_MAX_CABINET_NAME - 1] = '\0';
|
|
DEBUGMSG((DBG_ERROR, "CabCreateCabinetW: _snwprintf truncated cabfile %s", cabFile));
|
|
//BUGBUG: we have truncated path, what to do?
|
|
//return NULL;
|
|
}
|
|
KnownSizeUnicodeToDbcs (cabHandle->FciCabParams.szCab, cabFile);
|
|
|
|
cabHandle->FciHandle = FCICreate (
|
|
&cabHandle->FciErrorStruct,
|
|
pCabFilePlacedW,
|
|
pCabAlloc,
|
|
pCabFree,
|
|
pCabOpenA,
|
|
pCabRead,
|
|
pCabWrite,
|
|
pCabClose,
|
|
pCabSeek,
|
|
pCabDeleteA,
|
|
pCabGetTempFileA,
|
|
&cabHandle->FciCabParams,
|
|
cabHandle
|
|
);
|
|
if (!cabHandle->FciHandle) {
|
|
if (cabHandle->CabPath) {
|
|
FreePathStringW (cabHandle->CabPath);
|
|
}
|
|
if (cabHandle->CabFileFormat) {
|
|
FreePathStringW (cabHandle->CabFileFormat);
|
|
}
|
|
if (cabHandle->CabDiskFormat) {
|
|
FreePathStringW (cabHandle->CabDiskFormat);
|
|
}
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
return NULL;
|
|
}
|
|
return ((CCABHANDLE)(cabHandle));
|
|
}
|
|
|
|
CCABHANDLE
|
|
CabCreateCabinetExA (
|
|
IN PCABGETCABINETNAMESA CabGetCabinetNames,
|
|
IN LONG MaxFileSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a cabinet context. Caller may use this context for subsequent calls to
|
|
CabAddFile.
|
|
|
|
Arguments:
|
|
|
|
CabGetCabinetNames - Specifies a callback used to decide cabinet path, cabinet name and disk name.
|
|
|
|
MaxFileSize - Specifies maximum size of the cabinet file (limited to 2GB). if 0 => 2GB
|
|
|
|
Return Value:
|
|
|
|
a valid CCABHANDLE if successful, NULL otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCI_CAB_HANDLEA cabHandle;
|
|
|
|
if (!CabGetCabinetNames) {
|
|
return NULL;
|
|
}
|
|
|
|
if (MaxFileSize < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (MaxFileSize == 0) {
|
|
MaxFileSize = 0x80000000;
|
|
}
|
|
|
|
cabHandle = MemAlloc (g_hHeap, 0, sizeof (FCI_CAB_HANDLEA));
|
|
ZeroMemory (cabHandle, sizeof (FCI_CAB_HANDLEA));
|
|
cabHandle->CabGetCabinetNames = CabGetCabinetNames;
|
|
|
|
// fill out the CCAB structure
|
|
cabHandle->FciCabParams.cb = MaxFileSize;
|
|
cabHandle->FciCabParams.cbFolderThresh = MaxFileSize;
|
|
cabHandle->FciCabParams.cbReserveCFHeader = 0;
|
|
cabHandle->FciCabParams.cbReserveCFFolder = 0;
|
|
cabHandle->FciCabParams.cbReserveCFData = 0;
|
|
cabHandle->FciCabParams.iCab = 1;
|
|
cabHandle->FciCabParams.iDisk = 1;
|
|
cabHandle->FciCabParams.setID = 0;
|
|
if (!CabGetCabinetNames (
|
|
cabHandle->FciCabParams.szCabPath,
|
|
CB_MAX_CAB_PATH,
|
|
cabHandle->FciCabParams.szCab,
|
|
CB_MAX_CABINET_NAME,
|
|
cabHandle->FciCabParams.szDisk,
|
|
CB_MAX_DISK_NAME,
|
|
cabHandle->FciCabParams.iCab,
|
|
&cabHandle->FciCabParams.iDisk
|
|
)) {
|
|
return NULL;
|
|
}
|
|
cabHandle->FciHandle = FCICreate (
|
|
&cabHandle->FciErrorStruct,
|
|
pCabFilePlacedA,
|
|
pCabAlloc,
|
|
pCabFree,
|
|
pCabOpenA,
|
|
pCabRead,
|
|
pCabWrite,
|
|
pCabClose,
|
|
pCabSeek,
|
|
pCabDeleteA,
|
|
pCabGetTempFileA,
|
|
&cabHandle->FciCabParams,
|
|
cabHandle
|
|
);
|
|
if (!cabHandle->FciHandle) {
|
|
if (cabHandle->CabPath) {
|
|
FreePathStringA (cabHandle->CabPath);
|
|
}
|
|
if (cabHandle->CabFileFormat) {
|
|
FreePathStringA (cabHandle->CabFileFormat);
|
|
}
|
|
if (cabHandle->CabDiskFormat) {
|
|
FreePathStringA (cabHandle->CabDiskFormat);
|
|
}
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
return NULL;
|
|
}
|
|
return ((CCABHANDLE)(cabHandle));
|
|
}
|
|
|
|
CCABHANDLE
|
|
CabCreateCabinetExW (
|
|
IN PCABGETCABINETNAMESW CabGetCabinetNames,
|
|
IN LONG MaxFileSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a cabinet context. Caller may use this context for subsequent calls to
|
|
CabAddFile.
|
|
|
|
Arguments:
|
|
|
|
CabGetCabinetNames - Specifies a callback used to decide cabinet path, cabinet name and disk name.
|
|
|
|
MaxFileSize - Specifies maximum size of the cabinet file (limited to 2GB). if 0 => 2GB
|
|
|
|
Return Value:
|
|
|
|
a valid CCABHANDLE if successful, NULL otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCI_CAB_HANDLEW cabHandle;
|
|
WCHAR cabPath [CB_MAX_CAB_PATH];
|
|
WCHAR cabFile [CB_MAX_CABINET_NAME];
|
|
WCHAR cabDisk [CB_MAX_DISK_NAME];
|
|
|
|
if (!CabGetCabinetNames) {
|
|
return NULL;
|
|
}
|
|
|
|
if (MaxFileSize < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (MaxFileSize == 0) {
|
|
MaxFileSize = 0x80000000;
|
|
}
|
|
|
|
cabHandle = MemAlloc (g_hHeap, 0, sizeof (FCI_CAB_HANDLEW));
|
|
ZeroMemory (cabHandle, sizeof (FCI_CAB_HANDLEW));
|
|
cabHandle->CabGetCabinetNames = CabGetCabinetNames;
|
|
|
|
// fill out the CCAB structure
|
|
cabHandle->FciCabParams.cb = MaxFileSize;
|
|
cabHandle->FciCabParams.cbFolderThresh = MaxFileSize;
|
|
cabHandle->FciCabParams.cbReserveCFHeader = 0;
|
|
cabHandle->FciCabParams.cbReserveCFFolder = 0;
|
|
cabHandle->FciCabParams.cbReserveCFData = 0;
|
|
cabHandle->FciCabParams.iCab = 1;
|
|
cabHandle->FciCabParams.iDisk = 1;
|
|
cabHandle->FciCabParams.setID = 0;
|
|
if (!CabGetCabinetNames (
|
|
cabPath,
|
|
CB_MAX_CAB_PATH,
|
|
cabFile,
|
|
CB_MAX_CABINET_NAME,
|
|
cabDisk,
|
|
CB_MAX_DISK_NAME,
|
|
cabHandle->FciCabParams.iCab,
|
|
&cabHandle->FciCabParams.iDisk
|
|
)) {
|
|
return NULL;
|
|
}
|
|
KnownSizeUnicodeToDbcs (cabHandle->FciCabParams.szCabPath, cabPath);
|
|
KnownSizeUnicodeToDbcs (cabHandle->FciCabParams.szCab, cabFile);
|
|
KnownSizeUnicodeToDbcs (cabHandle->FciCabParams.szDisk, cabDisk);
|
|
cabHandle->FciHandle = FCICreate (
|
|
&cabHandle->FciErrorStruct,
|
|
pCabFilePlacedW,
|
|
pCabAlloc,
|
|
pCabFree,
|
|
pCabOpenA,
|
|
pCabRead,
|
|
pCabWrite,
|
|
pCabClose,
|
|
pCabSeek,
|
|
pCabDeleteA,
|
|
pCabGetTempFileA,
|
|
&cabHandle->FciCabParams,
|
|
cabHandle
|
|
);
|
|
if (!cabHandle->FciHandle) {
|
|
if (cabHandle->CabPath) {
|
|
FreePathStringW (cabHandle->CabPath);
|
|
}
|
|
if (cabHandle->CabFileFormat) {
|
|
FreePathStringW (cabHandle->CabFileFormat);
|
|
}
|
|
if (cabHandle->CabDiskFormat) {
|
|
FreePathStringW (cabHandle->CabDiskFormat);
|
|
}
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
return NULL;
|
|
}
|
|
return ((CCABHANDLE)(cabHandle));
|
|
}
|
|
|
|
BOOL
|
|
CabAddFileToCabinetA (
|
|
IN CCABHANDLE CabHandle,
|
|
IN PCSTR FileName,
|
|
IN PCSTR StoredName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compresses and adds a file to a cabinet context.
|
|
|
|
Arguments:
|
|
|
|
CabHandle - Specifies cabinet context.
|
|
|
|
FileName - Specifies the file to be added.
|
|
|
|
StoredName - Specifies the name to be stored in the cabinet file.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCI_CAB_HANDLEA cabHandle;
|
|
|
|
cabHandle = (PFCI_CAB_HANDLEA) CabHandle;
|
|
if (cabHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
if (cabHandle->FciHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
return FCIAddFile (
|
|
cabHandle->FciHandle,
|
|
(PSTR)FileName,
|
|
(PSTR)StoredName,
|
|
FALSE,
|
|
pCabGetNextCabinetA,
|
|
pCabStatusA,
|
|
pCabGetOpenInfoA,
|
|
tcompTYPE_MSZIP
|
|
);
|
|
}
|
|
|
|
BOOL
|
|
CabAddFileToCabinetW (
|
|
IN CCABHANDLE CabHandle,
|
|
IN PCWSTR FileName,
|
|
IN PCWSTR StoredName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compresses and adds a file to a cabinet context.
|
|
|
|
Arguments:
|
|
|
|
CabHandle - Specifies cabinet context.
|
|
|
|
FileName - Specifies the file to be added.
|
|
|
|
StoredName - Specifies the name to be stored in the cabinet file.
|
|
|
|
FileCount - Specifies a count of files, receives the updated count
|
|
when cabinet files are created
|
|
|
|
FileSize - Specifies the number of bytes used by the file, receives
|
|
the updated size
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCI_CAB_HANDLEW cabHandle;
|
|
CHAR ansiFileName [1024];
|
|
CHAR ansiStoredName [1024];
|
|
|
|
cabHandle = (PFCI_CAB_HANDLEW) CabHandle;
|
|
if (cabHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
if (cabHandle->FciHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if(!StoredName || !FileName){
|
|
MYASSERT(FileName);
|
|
MYASSERT(StoredName);
|
|
return FALSE;
|
|
}
|
|
|
|
KnownSizeUnicodeToDbcs (ansiFileName, FileName);
|
|
KnownSizeUnicodeToDbcs (ansiStoredName, StoredName);
|
|
|
|
return FCIAddFile (
|
|
cabHandle->FciHandle,
|
|
ansiFileName,
|
|
ansiStoredName,
|
|
FALSE,
|
|
pCabGetNextCabinetW,
|
|
pCabStatusW,
|
|
pCabGetOpenInfoA,
|
|
tcompTYPE_MSZIP
|
|
);
|
|
}
|
|
|
|
BOOL
|
|
CabFlushAndCloseCabinetExA (
|
|
IN CCABHANDLE CabHandle,
|
|
OUT PUINT FileCount, OPTIONAL
|
|
OUT PLONGLONG FileSize, OPTIONAL
|
|
OUT PUINT CabFileCount, OPTIONAL
|
|
OUT PLONGLONG CabFileSize OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completes a cabinet file and closes its context.
|
|
|
|
Arguments:
|
|
|
|
CabHandle - Specifies cabinet context.
|
|
|
|
FileCount - Receives the number of files added to the cab
|
|
|
|
FileSize - Receives the size of all files before compression
|
|
|
|
CabFileCount - Receives the number of cabinet files created
|
|
|
|
CabFileSize - Receives the size of all cabinet files
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCI_CAB_HANDLEA cabHandle;
|
|
BOOL result = FALSE;
|
|
|
|
cabHandle = (PFCI_CAB_HANDLEA) CabHandle;
|
|
if (cabHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
if (cabHandle->FciHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
if (FCIFlushCabinet (
|
|
cabHandle->FciHandle,
|
|
FALSE,
|
|
pCabGetNextCabinetA,
|
|
pCabStatusA
|
|
)) {
|
|
if (cabHandle->CabPath) {
|
|
FreePathStringA (cabHandle->CabPath);
|
|
}
|
|
if (cabHandle->CabFileFormat) {
|
|
FreePathStringA (cabHandle->CabFileFormat);
|
|
}
|
|
if (cabHandle->CabDiskFormat) {
|
|
FreePathStringA (cabHandle->CabDiskFormat);
|
|
}
|
|
result = FCIDestroy (cabHandle->FciHandle);
|
|
|
|
if (FileCount) {
|
|
*FileCount = cabHandle->FileCount;
|
|
}
|
|
|
|
if (FileSize) {
|
|
*FileSize = cabHandle->FileSize;
|
|
}
|
|
|
|
if (CabFileCount) {
|
|
*CabFileCount = cabHandle->CabCount;
|
|
}
|
|
|
|
if (CabFileSize) {
|
|
*CabFileSize = cabHandle->CompressedSize;
|
|
}
|
|
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
CabFlushAndCloseCabinetExW (
|
|
IN CCABHANDLE CabHandle,
|
|
OUT PUINT FileCount, OPTIONAL
|
|
OUT PLONGLONG FileSize, OPTIONAL
|
|
OUT PUINT CabFileCount, OPTIONAL
|
|
OUT PLONGLONG CabFileSize OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completes a cabinet file and closes its context.
|
|
|
|
Arguments:
|
|
|
|
CabHandle - Specifies cabinet context.
|
|
|
|
FileCount - Receives the number of files added to the cab
|
|
|
|
FileSize - Receives the size of all files before compression
|
|
|
|
CabFileCount - Receives the number of cabinet files created
|
|
|
|
CabFileSize - Receives the size of all cabinet files
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCI_CAB_HANDLEW cabHandle;
|
|
BOOL result = FALSE;
|
|
|
|
cabHandle = (PFCI_CAB_HANDLEW) CabHandle;
|
|
if (cabHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
if (cabHandle->FciHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
if (FCIFlushCabinet (
|
|
cabHandle->FciHandle,
|
|
FALSE,
|
|
pCabGetNextCabinetW,
|
|
pCabStatusW
|
|
)) {
|
|
if (cabHandle->CabPath) {
|
|
FreePathStringW (cabHandle->CabPath);
|
|
}
|
|
if (cabHandle->CabFileFormat) {
|
|
FreePathStringW (cabHandle->CabFileFormat);
|
|
}
|
|
if (cabHandle->CabDiskFormat) {
|
|
FreePathStringW (cabHandle->CabDiskFormat);
|
|
}
|
|
result = FCIDestroy (cabHandle->FciHandle);
|
|
|
|
if (FileCount) {
|
|
*FileCount = cabHandle->FileCount;
|
|
}
|
|
|
|
if (FileSize) {
|
|
*FileSize = cabHandle->FileSize;
|
|
}
|
|
|
|
if (CabFileCount) {
|
|
*CabFileCount = cabHandle->CabCount;
|
|
}
|
|
|
|
if (CabFileSize) {
|
|
*CabFileSize = cabHandle->CompressedSize;
|
|
}
|
|
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
OCABHANDLE
|
|
CabOpenCabinetA (
|
|
IN PCSTR FileName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a cabinet context for an existent cabinet file.
|
|
|
|
Arguments:
|
|
|
|
FileName - Specifies cabinet file name.
|
|
|
|
Return Value:
|
|
|
|
a valid OCABHANDLE if successful, NULL otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFDI_CAB_HANDLEA cabHandle;
|
|
PSTR filePtr;
|
|
HANDLE fileHandle;
|
|
PCSTR fileName;
|
|
|
|
if(!FileName){
|
|
MYASSERT(FileName);
|
|
return NULL;
|
|
}
|
|
|
|
cabHandle = (PFDI_CAB_HANDLEA) MemAlloc (g_hHeap, 0, sizeof (FDI_CAB_HANDLEA));
|
|
ZeroMemory (cabHandle, sizeof (FDI_CAB_HANDLEA));
|
|
cabHandle->FdiHandle = FDICreate (
|
|
pCabAlloc,
|
|
pCabFree,
|
|
pCabOpen1A,
|
|
pCabRead1,
|
|
pCabWrite1,
|
|
pCabClose1,
|
|
pCabSeek1,
|
|
cpuUNKNOWN,
|
|
&cabHandle->FdiErrorStruct
|
|
);
|
|
if (!cabHandle->FdiHandle) {
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
return NULL;
|
|
}
|
|
fileName = DuplicatePathStringA (FileName, 0);
|
|
fileHandle = CreateFileA (
|
|
fileName,
|
|
GENERIC_READ|GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
|
FreePathStringA (fileName);
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
return NULL;
|
|
}
|
|
if (!FDIIsCabinet (cabHandle->FdiHandle, (INT_PTR)fileHandle, &cabHandle->FdiCabinetInfo)) {
|
|
FreePathStringA (fileName);
|
|
CloseHandle (fileHandle);
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
return NULL;
|
|
}
|
|
CloseHandle (fileHandle);
|
|
filePtr = (PSTR)GetFileNameFromPathA (fileName);
|
|
if (!filePtr) {
|
|
FreePathStringA (fileName);
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
return NULL;
|
|
}
|
|
cabHandle->CabFile = DuplicatePathStringA (filePtr, 0);
|
|
*filePtr = 0;
|
|
cabHandle->CabPath = DuplicatePathStringA (fileName, 0);
|
|
FreePathStringA (fileName);
|
|
return ((CCABHANDLE)(cabHandle));
|
|
}
|
|
|
|
OCABHANDLE
|
|
CabOpenCabinetW (
|
|
IN PCWSTR FileName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a cabinet context for an existent cabinet file.
|
|
|
|
Arguments:
|
|
|
|
FileName - Specifies cabinet file name.
|
|
|
|
Return Value:
|
|
|
|
a valid OCABHANDLE if successful, NULL otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFDI_CAB_HANDLEW cabHandle;
|
|
PWSTR filePtr;
|
|
HANDLE fileHandle;
|
|
PCWSTR fileName;
|
|
|
|
if(!FileName){
|
|
MYASSERT(FileName);
|
|
return NULL;
|
|
}
|
|
|
|
cabHandle = (PFDI_CAB_HANDLEW) MemAlloc (g_hHeap, 0, sizeof (FDI_CAB_HANDLEW));
|
|
ZeroMemory (cabHandle, sizeof (FDI_CAB_HANDLEW));
|
|
cabHandle->FdiHandle = FDICreate (
|
|
pCabAlloc,
|
|
pCabFree,
|
|
pCabOpen1A,
|
|
pCabRead1,
|
|
pCabWrite1,
|
|
pCabClose1,
|
|
pCabSeek1,
|
|
cpuUNKNOWN,
|
|
&cabHandle->FdiErrorStruct
|
|
);
|
|
if (!cabHandle->FdiHandle) {
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
return NULL;
|
|
}
|
|
fileName = DuplicatePathStringW (FileName, 0);
|
|
fileHandle = CreateFileW (
|
|
fileName,
|
|
GENERIC_READ|GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
|
FreePathStringW (fileName);
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
return NULL;
|
|
}
|
|
if (!FDIIsCabinet (cabHandle->FdiHandle, (INT_PTR)fileHandle, &cabHandle->FdiCabinetInfo)) {
|
|
FreePathStringW (fileName);
|
|
CloseHandle (fileHandle);
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
return NULL;
|
|
}
|
|
CloseHandle (fileHandle);
|
|
filePtr = (PWSTR)GetFileNameFromPathW (fileName);
|
|
if (!filePtr) {
|
|
FreePathStringW (fileName);
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
return NULL;
|
|
}
|
|
cabHandle->CabFile = DuplicatePathStringW (filePtr, 0);
|
|
*filePtr = 0;
|
|
cabHandle->CabPath = DuplicatePathStringW (fileName, 0);
|
|
FreePathStringW (fileName);
|
|
return ((CCABHANDLE)(cabHandle));
|
|
}
|
|
|
|
BOOL
|
|
CabExtractAllFilesExA (
|
|
IN OCABHANDLE CabHandle,
|
|
IN PCSTR ExtractPath, OPTIONAL
|
|
IN PCABNOTIFICATIONA CabNotification OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Extracts all files from a cabinet file.
|
|
|
|
Arguments:
|
|
|
|
CabHandle - Specifies cabinet context.
|
|
|
|
ExtractPath - Specifies the path to extract the files to.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFDI_CAB_HANDLEA cabHandle;
|
|
CAB_DATAA cabData;
|
|
|
|
cabHandle = (PFDI_CAB_HANDLEA)CabHandle;
|
|
if (!cabHandle) {
|
|
return FALSE;
|
|
}
|
|
if (!cabHandle->FdiHandle) {
|
|
return FALSE;
|
|
}
|
|
cabData.ExtractPath = ExtractPath;
|
|
cabData.CabNotificationA = CabNotification;
|
|
|
|
return FDICopy (
|
|
cabHandle->FdiHandle,
|
|
(PSTR)cabHandle->CabFile,
|
|
(PSTR)cabHandle->CabPath,
|
|
0,
|
|
pCabNotificationA,
|
|
NULL,
|
|
(PVOID)(&cabData)
|
|
);
|
|
}
|
|
|
|
|
|
BOOL
|
|
pCabExtractAllFilesExWorkerW (
|
|
IN OCABHANDLE CabHandle,
|
|
IN PCWSTR ExtractPath, OPTIONAL
|
|
IN PCABNOTIFICATIONW CabNotificationW, OPTIONAL
|
|
IN BOOL VerifyMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Extracts all files from a cabinet file.
|
|
|
|
Arguments:
|
|
|
|
CabHandle - Specifies cabinet context.
|
|
|
|
ExtractPath - Specifies the path to extract the files to.
|
|
|
|
CabNotification - Specifies the notification callback function that is
|
|
called for every file in the cab
|
|
|
|
VerifyMode - Specifies TRUE if the cab should be verified, FALSE if it
|
|
should be extracted
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFDI_CAB_HANDLEW cabHandle;
|
|
CAB_DATAW cabData;
|
|
BOOL result;
|
|
PCSTR cabFileAnsi;
|
|
PCSTR cabPathAnsi;
|
|
|
|
cabHandle = (PFDI_CAB_HANDLEW)CabHandle;
|
|
if (!cabHandle) {
|
|
return FALSE;
|
|
}
|
|
if (!cabHandle->FdiHandle) {
|
|
return FALSE;
|
|
}
|
|
cabData.ExtractPath = ExtractPath;
|
|
cabData.CabNotificationW = CabNotificationW;
|
|
cabData.VerifyMode = VerifyMode;
|
|
|
|
cabFileAnsi = ConvertWtoA (cabHandle->CabFile);
|
|
cabPathAnsi = ConvertWtoA (cabHandle->CabPath);
|
|
|
|
result = FDICopy (
|
|
cabHandle->FdiHandle,
|
|
(PSTR) cabFileAnsi,
|
|
(PSTR) cabPathAnsi,
|
|
0,
|
|
pCabNotificationW,
|
|
NULL,
|
|
(PVOID)(&cabData)
|
|
);
|
|
|
|
FreeConvertedStr (cabFileAnsi);
|
|
FreeConvertedStr (cabPathAnsi);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CabExtractAllFilesExW (
|
|
IN OCABHANDLE CabHandle,
|
|
IN PCWSTR ExtractPath, OPTIONAL
|
|
IN PCABNOTIFICATIONW CabNotificationW OPTIONAL
|
|
)
|
|
{
|
|
return pCabExtractAllFilesExWorkerW (CabHandle, ExtractPath, CabNotificationW, FALSE);
|
|
}
|
|
|
|
BOOL
|
|
CabVerifyCabinet (
|
|
IN OCABHANDLE CabHandle
|
|
)
|
|
{
|
|
return pCabExtractAllFilesExWorkerW (CabHandle, NULL, NULL, TRUE);
|
|
|
|
}
|
|
|
|
BOOL
|
|
CabCloseCabinetA (
|
|
IN OCABHANDLE CabHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Closes a cabinet file context.
|
|
|
|
Arguments:
|
|
|
|
CabHandle - Specifies cabinet context.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFDI_CAB_HANDLEA cabHandle;
|
|
|
|
cabHandle = (PFDI_CAB_HANDLEA) CabHandle;
|
|
if (!cabHandle) {
|
|
return FALSE;
|
|
}
|
|
if (!cabHandle->FdiHandle) {
|
|
return FALSE;
|
|
}
|
|
if (FDIDestroy (cabHandle->FdiHandle)) {
|
|
if (cabHandle->CabPath) {
|
|
FreePathStringA (cabHandle->CabPath);
|
|
}
|
|
if (cabHandle->CabFile) {
|
|
FreePathStringA (cabHandle->CabFile);
|
|
}
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
CabCloseCabinetW (
|
|
IN OCABHANDLE CabHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Closes a cabinet file context.
|
|
|
|
Arguments:
|
|
|
|
CabHandle - Specifies cabinet context.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFDI_CAB_HANDLEW cabHandle;
|
|
|
|
cabHandle = (PFDI_CAB_HANDLEW) CabHandle;
|
|
if (!cabHandle) {
|
|
return FALSE;
|
|
}
|
|
if (!cabHandle->FdiHandle) {
|
|
return FALSE;
|
|
}
|
|
if (FDIDestroy (cabHandle->FdiHandle)) {
|
|
if (cabHandle->CabPath) {
|
|
FreePathStringW (cabHandle->CabPath);
|
|
}
|
|
if (cabHandle->CabFile) {
|
|
FreePathStringW (cabHandle->CabFile);
|
|
}
|
|
MemFree (g_hHeap, 0, cabHandle);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|