example of using the cabinet.dll

// .cab file compression and decompression demonstration program code.
#pragma once
#include 
#include 

#include // file control
#include 
#include 

#include 
#include 

#include "fci.h"
#include "fdi.h"

using namespace std;

/
// static global variables

const char*   gs_dir_targ           = NULL;
char          gs_cab_next[MAX_PATH] = {0};
unsigned long gu_size[2]            = {0};
unsigned long gu_count              = 0;

/
// general functions

unsigned long fnget_desired_access(int in_oflag)
{
	if(_O_RDWR & in_oflag)
		return GENERIC_READ|GENERIC_WRITE;
	if(_O_WRONLY & in_oflag)
		return GENERIC_WRITE;
 	return GENERIC_READ;
}

bool fnget_temp_filename(char* out_pbuf, unsigned long in_cbbuf)
{
	char szfile[MAX_PATH] = {0};
	char szpath[MAX_PATH] = {0};

	if(GetTempPath(MAX_PATH, szpath))
		if(GetTempFileName(szpath, "~Z_", 0, szfile))
			if(DeleteFile(szfile))
				if(out_pbuf == strcpy(out_pbuf, szfile))// note here: this is not a secure copy.
					return true;
	return false;
}

/
// gecallback functions

void* fncallback_alloc(unsigned long cb)
{
	return operator new(cb);
}

void fncallback_free(void* pbuf)
{
	operator delete(pbuf);
}

ptrdiff_t fncallback_fci_open(char* in_pszfile, int in_oflag, int in_mode, int* out_perr, void* in_pv)
{
	void* hf = NULL;

	UNREFERENCED_PARAMETER(in_pv);// correspond to call unname_func(pv);
	UNREFERENCED_PARAMETER(in_mode);

	hf = CreateFile(in_pszfile, fnget_desired_access(in_oflag), FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, 
		(_O_CREAT & in_oflag) ? CREATE_ALWAYS : OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);// CREATE_ALWAYS
	if(INVALID_HANDLE_VALUE == hf)
		*out_perr = GetLastError();
	return (ptrdiff_t)hf;// like integer type
}

unsigned int fncallback_fci_read(ptrdiff_t in_hf, void* out_pbuf, unsigned int in_cbbuf, int* out_perr, void* in_pv)
{
	unsigned long i = 0;

	UNREFERENCED_PARAMETER(in_pv);

	if(!ReadFile((void*)in_hf, out_pbuf, in_cbbuf, &i, NULL))
	{
		*out_perr = GetLastError();
		i = 0xFFFFFFFF;
	}
	return i;
}

unsigned int fncallback_fci_write(ptrdiff_t in_hf, void* in_pbuf, unsigned int in_cbbuf, int* out_perr, void* in_pv)
{
	unsigned long i = 0;

	UNREFERENCED_PARAMETER(in_pv);
	if(!WriteFile((void*)in_hf, in_pbuf, in_cbbuf, &i, NULL))
	{
		*out_perr = GetLastError();
		i = 0xFFFFFFFF;
	}
	return i;
}

int fncallback_fci_close(ptrdiff_t in_hf, int* out_perr, void* in_pv)
{
	int i = 0;

	UNREFERENCED_PARAMETER(in_pv);
	// the outpat .cab file has just been closed. reset it's handle.
	if(!CloseHandle((void*)in_hf))
	{
		*out_perr = GetLastError();
		i = -1;
	}
	return i;
}

// seek inside a file (move file pointer)
long fncallback_fci_seek(ptrdiff_t in_hf, long in_offset, int in_type, int* out_perr, void* in_pv)
{
	long i = 0;

	UNREFERENCED_PARAMETER(in_pv);
	i = SetFilePointer((void* )in_hf, in_offset, NULL, in_type);
	if(0xFFFFFFFF == i)
		*out_perr = GetLastError();
	return i;
}

int fncallback_fci_delete(char* in_pszfile, int* out_perr, void* in_pv)
{
	int i = 0;

	i = remove(in_pszfile);
	if(0 != i)
		*out_perr = errno;
	return i;
}

int fncallback_fci_file_placed(CCAB* pcab, char* pszfile, long cbfile, BOOL bcontination, void* pv)
{
	return 0;
}

// a function to obtain temporary file names.
// the filename returned should not occupy more than 'cbbuf' bytes.
// FCI may open several temporary files at once, so it is important to ensure 
// that a different filename is returned each time, and that the file does not already exist.
BOOL fncallback_fci_temp_file(char* out_pbuf, int cbbuf, void* pv)
{
	return fnget_temp_filename(out_pbuf, cbbuf) ? TRUE : FALSE;
}

// the function should return TRUE for success, or FALSE to abort cabinet creation.
BOOL fncallback_fci_get_next_cabinet(CCAB* pcab, unsigned long cbprev, void* pv)
{
	strcpy(pcab->szDisk, "Disk 1");
	pcab->iDisk++;
	return TRUE;
}

// returns anything other than -1;
long fncallback_fci_status(unsigned int itype_status, unsigned long cb1, unsigned long cb2, void* pv)
{
	return 0;
}

// open source file and return date / time / attributes
// exit-success: return file handle of open file to read
// exit-failure: return -1
ptrdiff_t fncallback_fci_get_open_info(char* in_pszfile, unsigned short* out_pdate, unsigned short* out_ptime, unsigned short* out_pattr, int* out_perr, void* in_pv)
{
	void* hfile = NULL;
	BY_HANDLE_FILE_INFORMATION fi = {0};
	FILETIME ft = {0};

	hfile = CreateFile(in_pszfile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
		FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL);
	if(INVALID_HANDLE_VALUE == hfile || 0 == GetFileInformationByHandle(hfile, &fi))
	{
		*out_perr = GetLastError();
		return -1;
	}
	CloseHandle(hfile);

	// the windows filesystem stores utc times
	ft = fi.ftLastWriteTime;
	FileTimeToDosDateTime(&ft, out_pdate, out_ptime);

	// mask out all other bits except these four, since other bite are used
	// by the cabinet format to indicate a special meaning.
	*out_pattr = (unsigned short)(fi.dwFileAttributes & (FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM));

	// now return a handle using fncallback_fci_open
	return fncallback_fci_open(in_pszfile, _O_RDONLY|_O_BINARY, _S_IREAD, out_perr, in_pv);
}

ptrdiff_t fncallback_fdi_open(char* pszfile, int oflag, int imode)
{
	return _open(pszfile, oflag, _S_IREAD);
}

unsigned int fncallback_fdi_read(ptrdiff_t in_hf, void* out_pbuf, unsigned int in_cbbuf)
{
	return (unsigned int)_read(in_hf, out_pbuf, in_cbbuf);
}

unsigned int fncallback_fdi_write(ptrdiff_t hf, void* pbuf, unsigned int cbbuf)
{
	unsigned int i = (unsigned int)_write(hf, pbuf, cbbuf);
	
	if(0xFFFFFFFF > i)
		gu_size[0] += i;// count copy size.
	return i;
}

int fncallback_fdi_close(ptrdiff_t hf)
{
	return _close(hf);
}

long fncallback_fdi_seek(ptrdiff_t hf, long ioffset, int itype)
{
	return _lseek(hf, ioffset, itype);
}

// callback function for the FDI context.
// this will get used when the 'fnfdi_copy' function is called.
// this function will call the appropriate handlers which can be overridden to change the default behaviour.
ptrdiff_t fncallback_fdi_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
{
	char szfile[MAX_PATH] = {0};
	int i = 0;// allow unsupported notifications to continue. default skip this file.

	switch(fdint)// relay the notifications.
	{
	case fdintCABINET_INFO:
// pfdin->psz1     = name of next cabinet
// pfdin->psz2     = name of next disk
// pfdin->psz3     = cabinet path name
// pfdin->setID    = cabinet set ID (a random 16-bit number)
// pfdin->iCabinet = cabinet number within cabinet set (0-based)
//      Exit-Success:
//          Return anything but -1
//      Exit-Failure:
//          Returns -1 => Abort FDICopy() call
		if(0 == strlen(gs_cab_next))
			strcpy(gs_cab_next, pfdin->psz1);
		break;
	case fdintCOPY_FILE:
//      Entry:
//          pfdin->psz1    = file name in cabinet
//          pfdin->cb      = uncompressed size of file
//          pfdin->date    = file date
//          pfdin->time    = file time
//          pfdin->attribs = file attributes
//          pfdin->iFolder = file's folder index
//      Exit-Success:
//          Return non-zero file handle for destination file; FDI writes
//          data to this file use the PFNWRITE function supplied to FDICreate,
//          and then calls fdintCLOSE_FILE_INFO to close the file and set
//          the date, time, and attributes.  NOTE: This file handle returned
//          must also be closeable by the PFNCLOSE function supplied to
//          FDICreate, since if an error occurs while writing to this handle,
//          FDI will use the PFNCLOSE function to close the file so that the
//          client may delete it.
//      Exit-Failure:
//          returns 0  => skip file, do not copy
//          returns -1 => abort FDICopy() call

		// combined path
		strcpy(szfile, gs_dir_targ);
		strcat(szfile, pfdin->psz1);
		i = _open(szfile, _O_TRUNC | _O_BINARY | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL, _S_IREAD | _S_IWRITE);
		gu_size[0] = 0;
		gu_size[1] = pfdin->cb;
		break;
	case fdintCLOSE_FILE_INFO:
// pfdin->psz1    = file name in cabinet
// pfdin->hf      = file handle
// pfdin->date    = file date
// pfdin->time    = file time
// pfdin->attribs = file attributes
// pfdin->iFolder = file's folder index
// pfdin->cb      = run after cabfdiact (0 - don't run, 1 Run)
//      Exit-Success:
//          Returns TRUE
//      Exit-Failure:
//          Returns FALSE, or -1 to abort;
		if(gu_size[0] == gu_size[1])
			gu_count++;
		i = TRUE;
		break;
	case fdintNEXT_CABINET:
// pfdin->psz1 = name of next cabinet where current file is continued
// pfdin->psz2 = name of next disk where current file is continued
// pfdin->psz3 = cabinet path name; FDI concatenates psz3 with psz1 
//               to produce the fully-qualified path for the cabinet
//               file.  The 256-byte buffer pointed at by psz3 may
//               be modified, but psz1 may not!
// pfdin->fdie = FDIERROR_WRONG_CABINET if the previous call to
//               fdintNEXT_CABINET specified a cabinet file that
//               did not match the setID/iCabinet that was expected.
//      Exit-Success:
//          Return anything but -1
//      Exit-Failure:
//          Returns -1 => Abort FDICopy() call
		strcpy(gs_cab_next, pfdin->psz1);
		break;
	case fdintPARTIAL_FILE:
	case fdintENUMERATE:
		break;
	}
	return i;
}

/
// library functions

// return FCI context handle
void* fnfci_create(ERF* out_perf, CCAB* out_pcab)
{
	typedef void* (__cdecl* FT)(ERF* , PFNFCIFILEPLACED, PFNFCIALLOC, PFNFCIFREE, PFNFCIOPEN, PFNFCIREAD, PFNFCIWRITE, PFNFCICLOSE, PFNFCISEEK, PFNFCIDELETE, PFNFCIGETTEMPFILE, PCCAB, void*);
	void*     hfci = NULL;
	HINSTANCE hlib = NULL;
	FT        func = NULL;

	hlib = LoadLibrary("cabinet.dll");
	if(NULL == hlib)
		return NULL;

	func = (FT)GetProcAddress(hlib, "FCICreate");
	if(func)
		hfci = func(out_perf,
		fncallback_fci_file_placed, // PFNFCIFILEPLACED
		fncallback_alloc,           // PFNFCIALLOC
		fncallback_free,            // PFNFCIFREE
		fncallback_fci_open,        // PFNFCIOPEN
		fncallback_fci_read,        // PFNFCIREAD
		fncallback_fci_write,       // PFNFCIWRITE
		fncallback_fci_close,       // PFNFCICLOSE
		fncallback_fci_seek,        // PFNFCISEEK
		fncallback_fci_delete,      // PFNFCIDELETE
		fncallback_fci_temp_file,   // PFNFCIGETTEMPFILE
		out_pcab,
		NULL);// user param

	FreeLibrary(hlib);
	return hfci;
}

// in_hfci      - FCI context handle
// in_pfile_src - name of file to add to folder
// in_pfile_ins - name to store into folder/cabinet
bool fnfci_add(void* in_hfci, const char* in_pfile_src, const char* in_pfile_ins)
{
	bool bret = false;
	typedef BOOL (__cdecl* FT)(void*, const char*, const char*, BOOL, PFNFCIGETNEXTCABINET, PFNFCISTATUS, PFNFCIGETOPENINFO, unsigned short);
	HINSTANCE hlib = NULL;
	FT        func = NULL;

	hlib = LoadLibrary("cabinet.dll");
	if(NULL == hlib)
		return false;
	func = (FT)GetProcAddress(hlib, "FCIAddFile");
	if(func)
		bret = func(in_hfci, in_pfile_src, in_pfile_ins, FALSE, fncallback_fci_get_next_cabinet, fncallback_fci_status, fncallback_fci_get_open_info, tcompTYPE_LZX|tcompLZX_WINDOW_HI) ? true : false;
	FreeLibrary(hlib);
	return bret;
}

bool fnfci_flush(void* in_hfci)
{
	bool bret = false;
	typedef BOOL (__cdecl* FT)(void*, BOOL, PFNFCIGETNEXTCABINET, PFNFCISTATUS);
	FT        func = NULL;
	HINSTANCE hlib = NULL;

	hlib = LoadLibrary("cabinet.dll");
	if(NULL == hlib)
		return false;
	func = (FT)GetProcAddress(hlib, "FCIFlushCabinet");
	if(func)
		bret = func(in_hfci, FALSE, fncallback_fci_get_next_cabinet, fncallback_fci_status) ? true : false;
	FreeLibrary(hlib);
	return bret;
}

bool fnfci_destroy(void* in_hfci)
{
	typedef BOOL (__cdecl* FT)(void* );
	bool      bret = false;
	FT        func = NULL;
	HINSTANCE hlib = LoadLibrary("cabinet.dll");

	if(NULL == hlib)
		return false;
	func = (FT)GetProcAddress(hlib, "FCIDestroy");
	if(func)
		bret = func(in_hfci) ? true : false;
	FreeLibrary(hlib);
	return bret;
}

void* fnfdi_create(ERF* out_perf)
{
	typedef void* (__cdecl* FT)(PFNALLOC, PFNFREE, PFNOPEN, PFNREAD, PFNWRITE, PFNCLOSE, PFNSEEK, int, ERF*);
	void*     hf   = NULL;
	HINSTANCE hlib = NULL;
	FT        func = NULL;

	hlib = LoadLibrary("cabinet.dll");
	if(NULL == hlib)
		return NULL;
	func = (FT)GetProcAddress(hlib, "FDICreate");
	if(func)
		hf = func(fncallback_alloc, fncallback_free,
		fncallback_fdi_open,
		fncallback_fdi_read,
		fncallback_fdi_write,
		fncallback_fdi_close,
		fncallback_fdi_seek,
		cpuUNKNOWN, out_perf);
	FreeLibrary(hlib);
	return hf;
}

bool fnfdi_copy(void* hfdi, const char* pszcabinet, const char* pszcab_path, void* pv)
{
	typedef BOOL (__cdecl* FT)(void*, const char*, const char*, int, PFNFDINOTIFY, PFNFDIDECRYPT, void*);
	bool      bret = false;
	HINSTANCE hlib = NULL;
	FT        func = NULL;

	hlib = LoadLibrary("cabinet.dll");
	if(NULL == hlib)
		return false;
	func = (FT)GetProcAddress(hlib, "FDICopy");
	if(func)
		bret = func(hfdi, pszcabinet, pszcab_path, 0, fncallback_fdi_notify, NULL, pv) ? true : false;
	FreeLibrary(hlib);
	return bret;
}

bool fnfdi_destroy(void* hf)
{
	typedef BOOL (__cdecl* FT)(void*);
	bool      bret = false;
	HINSTANCE hlib = NULL;
	FT        func = NULL;

	hlib = LoadLibrary("cabinet.dll");
	if(NULL == hlib)
		return false;
	func = (FT)GetProcAddress(hlib, "FDIDestroy");
	if(func)
		bret = func(hf) ? true : false;
	FreeLibrary(hlib);
	return bret;
}

/
// demo functions

// example 1.
bool fncabmake()
{
	void* hfci = NULL;
	CCAB  cab  = {0};
	ERF   erf  = {0};

	// assume that the following test file already exists:
	// 'debug\\test01.txt'
	// 'debug\\test02.txt'

	cab.cb             = 0;// split size
	cab.cbFolderThresh = 0x7FFFFFFF;
	cab.iCab           = 1;
	cab.iDisk          = 1;
	strcpy(cab.szCabPath, "debug\\");// create path name
	strcpy(cab.szCab, "pack.cab");// save file name

	hfci = fnfci_create(&erf, &cab);
	if(NULL == hfci)
		return false;

	fnfci_add(hfci, "debug\\test01.txt", "test01.txt");
	fnfci_add(hfci, "debug\\test02.txt", "test02.txt");

	fnfci_flush(hfci);
	fnfci_destroy(hfci);
	return true;
}

// example 2.
unsigned long fnextract()
{
	void*         hfdi = NULL;
	unsigned long i    = 0;
	ERF           erf  = {0};

	// assuming that 'debug\\pack.cab' file and 'debug\\dir' directory already exists.

	gs_dir_targ    = "debug\\dir\\";
	gs_cab_next[0] = '\0';
	gu_count       = 0;

	hfdi = fnfdi_create(&erf);
	if(NULL == hfdi)
		return 0;

	while(fnfdi_copy(hfdi, "pack.cab", "debug\\", NULL))
		if(0 == strlen(gs_cab_next))
			break;

	fnfdi_destroy(hfdi);
	return gu_count;
}

int main(int argc, char* argv[], char* envp[])
{
	try
	{
		if(fncabmake())
			cout << "example 1 success." << endl;
		else
			cout << "example 1 failure." << endl;
		cout << "example 2: " << fnextract() << endl;
	}
	catch(const char* p)
	{
		cout << p << endl;
	}
	cout << "press any key to quit." << endl;
	int i = _getch();
	return 0;
}

你可能感兴趣的:(vc,windows,cab,fdi,fci)