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.
564 lines
12 KiB
564 lines
12 KiB
#include "stdafx.h"
|
|
#include "Compress.h"
|
|
char cCabName [MAX_PATH];
|
|
char CabPath[256];
|
|
ULONG g_CompressedPercentage=0;
|
|
BOOL g_CancelCompression = FALSE;
|
|
|
|
/*
|
|
* Memory allocation function
|
|
*/
|
|
FNFCIALLOC(mem_alloc)
|
|
{
|
|
return malloc(cb);
|
|
}
|
|
|
|
|
|
/*
|
|
* Memory free function
|
|
*/
|
|
FNFCIFREE(mem_free)
|
|
{
|
|
free(memory);
|
|
}
|
|
|
|
|
|
/*
|
|
* File i/o functions
|
|
*/
|
|
FNFCIOPEN(fci_open)
|
|
{
|
|
int result;
|
|
|
|
result = _open(pszFile, oflag, pmode);
|
|
|
|
if (result == -1)
|
|
*err = errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
FNFCIREAD(fci_read)
|
|
{
|
|
unsigned int result;
|
|
|
|
result = (unsigned int) _read((int)hf, memory, cb);
|
|
|
|
if (result != cb)
|
|
*err = errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
FNFCIWRITE(fci_write)
|
|
{
|
|
unsigned int result;
|
|
|
|
result = (unsigned int) _write((int)hf, memory, cb);
|
|
|
|
if (result != cb)
|
|
*err = errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
FNFCICLOSE(fci_close)
|
|
{
|
|
int result;
|
|
|
|
result = _close((int)hf);
|
|
|
|
if (result != 0)
|
|
*err = errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
FNFCISEEK(fci_seek)
|
|
{
|
|
long result;
|
|
|
|
result = _lseek((int)hf, dist, seektype);
|
|
|
|
if (result == -1)
|
|
*err = errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
FNFCIDELETE(fci_delete)
|
|
{
|
|
int result;
|
|
|
|
result = remove(pszFile);
|
|
|
|
if (result != 0)
|
|
*err = errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/*
|
|
* File placed function called when a file has been committed
|
|
* to a cabinet
|
|
*/
|
|
FNFCIFILEPLACED(file_placed)
|
|
{
|
|
/*printf(
|
|
" placed file '%s' (size %d) on cabinet '%s'\n",
|
|
pszFile,
|
|
cbFile,
|
|
pccab->szCab
|
|
);
|
|
|
|
if (fContinuation)
|
|
printf(" (Above file is a later segment of a continued file)\n");
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Function to obtain temporary files
|
|
*/
|
|
FNFCIGETTEMPFILE(get_temp_file)
|
|
{
|
|
char *psz;
|
|
|
|
psz = _tempnam("","xx"); // Get a name
|
|
if ((psz != NULL) && (strlen(psz) < (unsigned)cbTempName)) {
|
|
strcpy(pszTempName,psz); // Copy to caller's buffer
|
|
free(psz); // Free temporary name buffer
|
|
return TRUE; // Success
|
|
}
|
|
//** Failed
|
|
if (psz) {
|
|
free(psz);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Progress function
|
|
*/
|
|
FNFCISTATUS(progress)
|
|
{
|
|
client_state *cs;
|
|
|
|
cs = (client_state *) pv;
|
|
|
|
if (typeStatus == statusFile)
|
|
{
|
|
cs->total_compressed_size += cb1;
|
|
cs->total_uncompressed_size += cb2;
|
|
|
|
/*
|
|
* Compressing a block into a folder
|
|
*
|
|
* cb2 = uncompressed size of block
|
|
*/
|
|
/* printf(
|
|
"Compressing: %9ld -> %9ld \r",
|
|
cs->total_uncompressed_size,
|
|
cs->total_compressed_size
|
|
);
|
|
fflush(stdout);
|
|
*/
|
|
g_CompressedPercentage
|
|
= get_percentage(cs->total_uncompressed_size,cs->start_uncompressed_size);
|
|
|
|
|
|
}
|
|
else if (typeStatus == statusFolder)
|
|
{
|
|
int percentage;
|
|
|
|
/*
|
|
* Adding a folder to a cabinet
|
|
*
|
|
* cb1 = amount of folder copied to cabinet so far
|
|
* cb2 = total size of folder
|
|
*/
|
|
percentage = get_percentage(cb1, cb2);
|
|
|
|
cs->start_uncompressed_size = cb2;
|
|
// printf("Copying folder to cabinet: %d%% \r", percentage);
|
|
fflush(stdout);
|
|
}
|
|
|
|
if (g_CancelCompression)
|
|
{
|
|
// Abort the compression
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void store_cab_name(char *cabname, int iCab)
|
|
{
|
|
sprintf(cabname, cCabName, iCab);
|
|
}
|
|
|
|
|
|
FNFCIGETNEXTCABINET(get_next_cabinet)
|
|
{
|
|
/*
|
|
* Cabinet counter has been incremented already by FCI
|
|
*/
|
|
|
|
/*
|
|
* Store next cabinet name
|
|
*/
|
|
store_cab_name(pccab->szCab, pccab->iCab);
|
|
|
|
/*
|
|
* You could change the disk name here too, if you wanted
|
|
*/
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
FNFCIGETOPENINFO(get_open_info)
|
|
{
|
|
BY_HANDLE_FILE_INFORMATION finfo;
|
|
FILETIME filetime;
|
|
HANDLE handle;
|
|
DWORD attrs;
|
|
int hf;
|
|
client_state *cs;
|
|
|
|
cs = (client_state *) pv;
|
|
|
|
/*
|
|
* Need a Win32 type handle to get file date/time
|
|
* using the Win32 APIs, even though the handle we
|
|
* will be returning is of the type compatible with
|
|
* _open
|
|
*/
|
|
handle = CreateFileA(
|
|
pszName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL
|
|
);
|
|
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (GetFileInformationByHandle(handle, &finfo) == FALSE)
|
|
{
|
|
CloseHandle(handle);
|
|
return -1;
|
|
}
|
|
cs->start_uncompressed_size = finfo.nFileSizeLow;
|
|
|
|
FileTimeToLocalFileTime(
|
|
&finfo.ftLastWriteTime,
|
|
&filetime
|
|
);
|
|
|
|
FileTimeToDosDateTime(
|
|
&filetime,
|
|
pdate,
|
|
ptime
|
|
);
|
|
|
|
attrs = GetFileAttributesA(pszName);
|
|
|
|
if (attrs == 0xFFFFFFFF)
|
|
{
|
|
/* failure */
|
|
*pattribs = 0;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Mask out all other bits except these four, since other
|
|
* bits are used by the cabinet format to indicate a
|
|
* special meaning.
|
|
*/
|
|
*pattribs = (int) (attrs & (_A_RDONLY | _A_SYSTEM | _A_HIDDEN | _A_ARCH));
|
|
}
|
|
|
|
CloseHandle(handle);
|
|
|
|
|
|
/*
|
|
* Return handle using _open
|
|
*/
|
|
hf = _open( pszName, _O_RDONLY | _O_BINARY );
|
|
|
|
if (hf == -1)
|
|
return -1; // abort on error
|
|
|
|
return hf;
|
|
}
|
|
|
|
|
|
void set_cab_parameters(PCCAB cab_parms)
|
|
{
|
|
memset(cab_parms, 0, sizeof(CCAB));
|
|
|
|
cab_parms->cb = MEDIA_SIZE;
|
|
cab_parms->cbFolderThresh = FOLDER_THRESHOLD;
|
|
|
|
/*
|
|
* Don't reserve space for any extensions
|
|
*/
|
|
cab_parms->cbReserveCFHeader = 0;
|
|
cab_parms->cbReserveCFFolder = 0;
|
|
cab_parms->cbReserveCFData = 0;
|
|
|
|
/*
|
|
* We use this to create the cabinet name
|
|
*/
|
|
cab_parms->iCab = 1;
|
|
|
|
/*
|
|
* If you want to use disk names, use this to
|
|
* count disks
|
|
*/
|
|
cab_parms->iDisk = 0;
|
|
|
|
/*
|
|
* Choose your own number
|
|
*/
|
|
cab_parms->setID = 12345;
|
|
|
|
/*
|
|
* Only important if CABs are spanning multiple
|
|
* disks, in which case you will want to use a
|
|
* real disk name.
|
|
*
|
|
* Can be left as an empty string.
|
|
*/
|
|
strcpy(cab_parms->szDisk, "");
|
|
|
|
/* where to store the created CAB files */
|
|
strcpy(cab_parms->szCabPath, CabPath);
|
|
|
|
/* store name of first CAB file */
|
|
store_cab_name(cab_parms->szCab, cab_parms->iCab);
|
|
}
|
|
|
|
|
|
BOOL Compress (wchar_t *CabName, wchar_t *fileName, DWORD *UploadTime)
|
|
{
|
|
HFCI hfci;
|
|
ERF erf;
|
|
CCAB cab_parameters;
|
|
int i;
|
|
client_state cs;
|
|
char FileName [MAX_PATH];
|
|
|
|
int num_files = 1;
|
|
|
|
g_CompressedPercentage = 0;
|
|
g_CancelCompression = FALSE;
|
|
UnicodeToAnsi1(fileName,FileName);
|
|
UnicodeToAnsi1(CabName,cCabName);
|
|
/*
|
|
* Initialise our internal state
|
|
*/
|
|
cs.total_compressed_size = 0;
|
|
cs.total_uncompressed_size = 0;
|
|
cs.start_uncompressed_size = 0;
|
|
set_cab_parameters(&cab_parameters);
|
|
|
|
hfci = FCICreate(
|
|
&erf,
|
|
file_placed,
|
|
mem_alloc,
|
|
mem_free,
|
|
fci_open,
|
|
fci_read,
|
|
fci_write,
|
|
fci_close,
|
|
fci_seek,
|
|
fci_delete,
|
|
get_temp_file,
|
|
&cab_parameters,
|
|
&cs
|
|
);
|
|
|
|
if (hfci == NULL)
|
|
{
|
|
//printf("FCICreate() failed: code %d [%s]\n",
|
|
// erf.erfOper, return_fci_error_string(erf.erfOper)
|
|
//);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 0; i < num_files; i++)
|
|
{
|
|
char stripped_name[256];
|
|
|
|
/*
|
|
* Don't store the path name in the cabinet file!
|
|
*/
|
|
strip_path(FileName, stripped_name);
|
|
|
|
if (FALSE == FCIAddFile(
|
|
hfci,
|
|
FileName, /* file to add */
|
|
stripped_name, /* file name in cabinet file */
|
|
FALSE, /* file is not executable */
|
|
get_next_cabinet,
|
|
progress,
|
|
get_open_info,
|
|
COMPRESSION_TYPE))
|
|
{
|
|
// printf("FCIAddFile() failed: code %d [%s]\n",
|
|
// erf.erfOper, return_fci_error_string(erf.erfOper)
|
|
// );
|
|
|
|
(void) FCIDestroy(hfci);
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This will automatically flush the folder first
|
|
*/
|
|
if (FALSE == FCIFlushCabinet(
|
|
hfci,
|
|
FALSE,
|
|
get_next_cabinet,
|
|
progress))
|
|
{
|
|
// printf("FCIFlushCabinet() failed: code %d [%s]\n",
|
|
// erf.erfOper, return_fci_error_string(erf.erfOper)
|
|
// );
|
|
|
|
(void) FCIDestroy(hfci);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (FCIDestroy(hfci) != TRUE)
|
|
{
|
|
// printf("FCIDestroy() failed: code %d [%s]\n",
|
|
// erf.erfOper, return_fci_error_string(erf.erfOper)
|
|
// );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//printf(" \r");
|
|
// ***************** Add Upload Estimate Here ******************
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void strip_path(char *filename, char *stripped_name)
|
|
{
|
|
char *p;
|
|
|
|
p = strrchr(filename, '\\');
|
|
|
|
if (p == NULL)
|
|
strcpy(stripped_name, filename);
|
|
else
|
|
strcpy(stripped_name, p+1);
|
|
}
|
|
|
|
|
|
int get_percentage(unsigned long a, unsigned long b)
|
|
{
|
|
while (a > 10000000)
|
|
{
|
|
a >>= 3;
|
|
b >>= 3;
|
|
}
|
|
|
|
if (b == 0)
|
|
return 0;
|
|
|
|
return ((a*100)/b);
|
|
}
|
|
|
|
|
|
char *return_fci_error_string(FCIERROR err)
|
|
{
|
|
switch (err)
|
|
{
|
|
case FCIERR_NONE:
|
|
return "No error";
|
|
|
|
case FCIERR_OPEN_SRC:
|
|
return "Failure opening file to be stored in cabinet";
|
|
|
|
case FCIERR_READ_SRC:
|
|
return "Failure reading file to be stored in cabinet";
|
|
|
|
case FCIERR_ALLOC_FAIL:
|
|
return "Insufficient memory in FCI";
|
|
|
|
case FCIERR_TEMP_FILE:
|
|
return "Could not create a temporary file";
|
|
|
|
case FCIERR_BAD_COMPR_TYPE:
|
|
return "Unknown compression type";
|
|
|
|
case FCIERR_CAB_FILE:
|
|
return "Could not create cabinet file";
|
|
|
|
case FCIERR_USER_ABORT:
|
|
return "Client requested abort";
|
|
|
|
case FCIERR_MCI_FAIL:
|
|
return "Failure compressing data";
|
|
|
|
default:
|
|
return "Unknown error";
|
|
}
|
|
}
|
|
void UnicodeToAnsi1(wchar_t * pszW, LPSTR ppszA)
|
|
{
|
|
|
|
ULONG cbAnsi, cCharacters;
|
|
DWORD dwError;
|
|
|
|
// If input is null then just return the same.
|
|
|
|
// return;// NOERROR;
|
|
|
|
|
|
cCharacters = wcslen(pszW)+1;
|
|
// Determine number of bytes to be allocated for ANSI string. An
|
|
// ANSI string can have at most 2 bytes per character (for Double
|
|
// Byte Character Strings.)
|
|
cbAnsi = cCharacters*2;
|
|
|
|
// Use of the OLE allocator is not required because the resultant
|
|
// ANSI string will never be passed to another COM component. You
|
|
// can use your own allocator.
|
|
/// *ppszA = (LPSTR) CoTaskMemAlloc(cbAnsi);
|
|
// if (NULL == *ppszA)
|
|
// return E_OUTOFMEMORY;
|
|
|
|
// Convert to ANSI.
|
|
if (0 == WideCharToMultiByte(CP_ACP, 0, pszW, cCharacters, ppszA,
|
|
cbAnsi, NULL, NULL))
|
|
{
|
|
dwError = GetLastError();
|
|
return;// HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
|
|
//MessageBoxW(NULL,pszW,L"String conversion function recieved",MB_OK);
|
|
// MessageBox(NULL,*ppszA,"String Convert Function is returning.",MB_OK);
|
|
return;// NOERROR;
|
|
|
|
}
|