⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i5comp.c

📁 InstallShield v5.x Compression
💻 C
📖 第 1 页 / 共 4 页
字号:
///////////////////////////////////////////////////////////////////
// i5comp.c
//  
// InstallShield Compression and Maintenance util
// fOSSiL - 1999
//
// *Any use is authorized, granted the proper credit is given*
//
// No support will be provided for this code
//

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <zdata.h>
#include <is5cab.h>
#include "i5comp.h"


#define CSFG_MAX	512


// IShield functions
void ConvertToSingle();
void ExtractFiles();
void ReplaceFiles();
void DeleteFiles();
void AddFiles();
void ListFiles();
void ListSetupTypes();
void ListComponents();
void ListFileGroups();
HANDLE ReadCabHeaderFile(LPSTR cabfile, DWORD Access);
void ReadCabHeader(HANDLE hCab);
void InitCabFile(LPSTR cabfile, DWORD Access);
void SaveCabHeaders();
BOOL IsSingleVolume();
BOOL IsFirstVolume();

// ZData functions
int CALLBACK ReadData(LPVOID pbuf, LPDWORD size, LPRWHANDLES pHnd);
int CALLBACK WriteData(LPVOID pbuf, LPDWORD size, LPRWHANDLES pHnd);
void InitCompressLib();

// Utils
void StartMsg();
void Usage();
void CleanExit(int code);
void DispatchCommand(int argc, char* argv[]);
void DeleteCab(LPSTR cabname);
void TransferData(HANDLE hFrom, HANDLE hTo, DWORD Length, DWORD Crypt);
#define CRYPT_NONE		0
#define CRYPT_DECRYPT	1
#define CRYPT_ENCRYPT	2
BOOL AutoDetectFailed();
BOOL AutoDetectZData();
void InitZData(RWHANDLES* pHnds);
void CreateDir(LPSTR dirname);
HANDLE OpenForRead(LPSTR filename);
HANDLE OpenForWrite(LPSTR filename, DWORD Flags);
HANDLE OpenForAccess(LPSTR filename, DWORD Access);
BOOL TranslatePathToGroup(LPSTR* ppPath, LPSTR* ppFGName);
void CabBasedFileList(LPSTR CabParam, LPSTR DiskParam);
void DiskBasedFileList(LPSTR CabParam, LPSTR DiskParam);
BOOL WildMatch(LPSTR str, LPSTR wildcard);
long strtolong(char* str);
long atolong(char* str);
BOOL IsMask(LPSTR str);
LPFILEGROUPDESC GetGroupByFile(DWORD index);
LPSTR GetGroupNameByFile(DWORD Index);
DWORD GetGroupIndexByName(LPSTR GroupName);
void TranslateFileGroup();
BOOL DirExists(LPSTR DirName);
void RecurseBuildDiskList(LPSTR BegDP, LPSTR CurDP, LPSTR Mask, LPSTR CabPath);
void Free(LPVOID ptr);
LPVOID Alloc(DWORD NewSize);
LPVOID ReAlloc(LPVOID Ptr, DWORD NewSize);
LPDIRARRAY DirsArrayBuild();
long DirsArrayFind(LPDIRARRAY pDA, LPSTR DirName);
long DirsArrayAddDir(LPDIRARRAY* ppDA, LPSTR DirName);
void RebuildDFT(LPDWORD NextFile, LPDWORD ofsNextDesc, LPDWORD ofsNextName);
void CopyFileGroup(DFTABLE OldT, DFTABLE NewT, DWORD cNewDirs, DWORD FGIndex, LPDWORD NextFile, LPDWORD ofsNextDesc, LPDWORD ofsNextName);
void ShiftDataDown(LPSTR FileName, DWORD DataOfs, DWORD Shift);


// Errors
void CantReadFile(int code);
void CantWriteFile(int code);
void CantOpenFile(LPSTR filename);
void InvalidCab();
void NotIShield5();
void NoMemory();
void MultipleNotSupported();
void InvalidFileIndex();
void CantDecompress(LPSTR filename);
void CantCompressError(LPSTR filename);
void CantCompressStore(LPSTR filename);
void NotInAnyGroups(LPSTR filename);
void NotEnoughParams(LPSTR str);
void NoFilesMatched();
void ExceptInDecompress();
void NoMatchBytesOut();
void GeneralException();
void TooManyEntries(LPSTR str);
void BadFileGroup();

// Global Cab variables
HANDLE hCabFile = NULL;
HANDLE hCabHdr = NULL;
CABHEADER CabHdr;
CABHEADER _FirstVolHdr;
LPCABHEADER FirstVolHdr = &_FirstVolHdr;
LPCABDESC pCabDesc = NULL;
DFTABLE DFT = NULL;
SETUPTYPETABLE SetupTypes = NULL;
DWORD cSetupTypes = 0;
COMPONENTTABLE Components = NULL;
DWORD cComponents = 0;
FILEGROUPTABLE FileGroups = NULL;
DWORD cFileGroups = 0;
LPSTR pCabPattern = NULL;

// Globals
ISVersion ver = ver51;
LPSTR exename = NULL;
LPVOID pZBuf = NULL;
LPCABFILELIST pFileList = NULL;
LPDISKFILELIST pDiskList = NULL;
DWORD FileCount = 0;
DWORD FileAttrVals[4] = {FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_SYSTEM};
char FileAttrChars[] = "ARHS";

// Options
BOOL optRecurseSubdirs = FALSE;
BOOL optMatchWithDirs = FALSE;
DWORD optVersion = 0;
DWORD optFileGroup = (DWORD)-1;
BOOL optPrintAll = TRUE;
BOOL optFGasDir = FALSE;

void main(int argc, char* argv[])
{
	/*long i;
	for (i = 1; i < argc; i++) fprintf(stderr, "%s, ", argv[i]);
	fprintf(stderr, "\n");
	gets((char*)&i);
	*/

	exename = argv[0];
	
	if (argc < 3) {
		StartMsg();
		Usage();
	}

	__try {
		DispatchCommand(argc - 1, argv + 1);
	} __except(EXCEPTION_EXECUTE_HANDLER) {
		GeneralException();
	}
	CleanExit(0);
}

void StartMsg()
{
	if (optPrintAll)
		fprintf(stderr, "InstallShield 5.x Cabinet Compression & Maintenance Util\nVersion 2.01 -] fOSSiL - 1999 [-\n");
}

void Usage()
{
	if (optPrintAll) {
		LPSTR pName;
		pName = strrchr(exename, '\\');
		pName = pName ? pName + 1 : exename;

		fprintf(stdout, "\nUsage: %s <cmd> [-opts] <cab> [cab index|fmask|path] [disk fmask|path]\n", pName);
		fprintf(stdout, "Commands\n");
		fprintf(stdout, "\tl: list Files\n");
		fprintf(stdout, "\tt: list Setup Types\n");
		fprintf(stdout, "\tc: list Components\n");
		fprintf(stdout, "\tg: list File Groups\n");
		fprintf(stdout, "\ts: convert multi-volume cab to a single volume\n");
		fprintf(stdout, "\te: extract files (specify <cab index|mask> when specifying <disk path>)\n");
		fprintf(stdout, "\tx: same as 'e' with subdirs\n");
		fprintf(stdout, "\tr: replace files in cab (same syntax as 'e')\n");
		fprintf(stdout, "\td: delete files from cab (specify <cab index|mask>)\n");
		fprintf(stdout, "\ta: add files to cab (<cab path> is optional; must specify -g OR -f)\n");
		fprintf(stdout, "Options\n");
		fprintf(stdout, "\tv<n>: override/specify version of IShield ZData dll to use\n");
		fprintf(stdout, "\t  n=1: versions prior to 5.00.200\n");
		fprintf(stdout, "\t  n=2: versions after 5.00.200 (Default if autodetect fails)\n");
		fprintf(stdout, "\tr: extract subdirs/recurse and store subdirs\n");
		fprintf(stdout, "\td: include directories in cab matches\n");
		fprintf(stdout, "\tg<name|index>: specifies File Group to work with\n");
		fprintf(stdout, "\to: suppress supplementary output (start msg, comments, etc.)\n");
		fprintf(stdout, "\tf: treat File Groups as directories (usefull for GUI, wrappers)\n");
		fprintf(stdout, "\t   for Add, Delete and Replace only 1 File Groups may be used at a time\n");
	}
	CleanExit(100);
}

void CleanExit(int code)
{
	if (hCabFile)
		CloseHandle(hCabFile);
	if (hCabHdr)
		CloseHandle(hCabHdr);

	Free(pCabDesc);
	Free(DFT);
	Free(pCabPattern);
	Free(pZBuf);
	Free(Components);
	Free(FileGroups);

	if (pFileList) {
		LPCABFILELIST pTemp;
		while (pFileList) {
			pTemp = pFileList->pNext;
			Free(pFileList);
			pFileList = pTemp;
		}
	}
	if (pDiskList) {
		LPDISKFILELIST pTemp;
		while (pDiskList) {
			pTemp = pDiskList->pNext;
			Free(pDiskList);
			pDiskList = pTemp;
		}
	}
	ZDataDeinit();
	exit(code);
}

void DispatchCommand(int argc, char* argv[])
{
	int arg = 0;
	char cmd;
	char* cabname;

	cmd = toupper(argv[arg][0]);
	arg++;
	while (arg < argc && argv[arg][0] == '-') {
		switch (toupper(argv[arg][1])) {
			case 'R':
				optRecurseSubdirs = TRUE;
				break;
			case 'D':
				optMatchWithDirs = TRUE;
				break;
			case 'V':
				optVersion = atol(argv[arg] + 2);
				switch (optVersion) {
					case 1:
						optVersion = 50149;
						ver = ver50;
						break;
					case 2:
						optVersion = 51145;
						ver = ver51;
						break;
					default:
						StartMsg();
						fprintf(stderr, "\nInvalid -v option specified\n");
						Usage();
				}
				break;
			case 'G':
				optFileGroup = atolong(argv[arg] + 2);
				if (optFileGroup == (DWORD)-1)
					optFileGroup = (DWORD)(argv[arg] + 2);
				break;
			case 'O':
				optPrintAll = FALSE;
				break;
			case 'F':
				optFGasDir = TRUE;
				break;
			default:
				StartMsg();
				fprintf(stderr, "\nUnknown option specified\n");
				Usage();
		}
		arg++;
	}
	if (arg >= argc) {
		StartMsg();
		fprintf(stderr, "\nNo cab file specified\n");
		Usage();
	}
	
	StartMsg();

	cabname = argv[arg];
	arg++;

	switch (cmd) {
		case 'L':
			InitCabFile(cabname, GENERIC_READ);
			TranslateFileGroup();
			CabBasedFileList(arg < argc ? argv[arg] : NULL, NULL);
			arg += 1;
			ListFiles();
			break;
		case 'T':
			InitCabFile(cabname, GENERIC_READ);
			ListSetupTypes();
			break;
		case 'C':
			InitCabFile(cabname, GENERIC_READ);
			ListComponents();
			break;
		case 'G':
			InitCabFile(cabname, GENERIC_READ);
			TranslateFileGroup();
			ListFileGroups();
			break;
		case 'X':
			optRecurseSubdirs = TRUE;
		case 'E':
			InitCabFile(cabname, GENERIC_READ);
			TranslateFileGroup();
			CabBasedFileList(arg < argc ? argv[arg] : NULL, arg + 1 < argc ? argv[arg + 1] : NULL);
			arg += 2;
			ExtractFiles();
			break;
		case 'S':
			InitCabFile(cabname, GENERIC_READ | GENERIC_WRITE);
			ConvertToSingle();
			arg += 1;
			break;
		case 'R':
			InitCabFile(cabname, GENERIC_READ | GENERIC_WRITE);
			TranslateFileGroup();
			CabBasedFileList(arg < argc ? argv[arg] : NULL, arg + 1 < argc ? argv[arg + 1] : NULL);
			arg += 2;
			ReplaceFiles();
			break;
		case 'D':			
			InitCabFile(cabname, GENERIC_READ | GENERIC_WRITE);
			TranslateFileGroup();
			if (arg < argc)
				CabBasedFileList(argv[arg], NULL);
			else
				NotEnoughParams("'d': ");
			arg += 1;
			DeleteFiles();
			break;
		case 'A':
			InitCabFile(cabname, GENERIC_READ | GENERIC_WRITE);
			TranslateFileGroup();
			switch (argc - arg) {
				case 1:
					DiskBasedFileList(NULL, argv[arg]);
					arg += 1;
					break;
				case 2:
					DiskBasedFileList(argv[arg], argv[arg + 1]);
					arg += 2;
					break;
				default:
					NotEnoughParams("'a': ");
			}
			AddFiles();
			break;
		default:
			fprintf(stderr, "Unknown command specified\n");
			Usage();
	}
}

void ConvertToSingle()
{
	DWORD i;
	int vol = 1;
	HANDLE hMainCab;
	DWORD CabPtr;
	HANDLE hRead;
	LPFILEDESC pFile;
	char cabname[1024];
	DWORD ToCopy, FromOfs;
	CABHEADER curCabHdr;

	curCabHdr = *FirstVolHdr;

	if (IsSingleVolume()) {
		fprintf(stderr, "Already a single volume cab\n");
		CleanExit(11);
	}
	
	sprintf(cabname, pCabPattern, vol);
	hMainCab = OpenForWrite(cabname, OPEN_EXISTING);
	hRead = OpenForRead(cabname);

	CabPtr = FirstVolHdr->ofsLastData;
	SetFilePointer(hMainCab, CabPtr, NULL, FILE_BEGIN);

	for (i = FirstVolHdr->LastFile; i < pCabDesc->cFiles; i++) {
		pFile = GetFileDesc(DFT, pCabDesc->cDirs + i);
		
		if (pFile->DescStatus & DESC_INVALID)
			continue;
		
		// check if the file is split
		if (i == curCabHdr.LastFile &&
			i < pCabDesc->cFiles - 1 &&
			curCabHdr.cbLastHere != pFile->cbCompressed)
		{
			ToCopy = curCabHdr.cbLastHere;
			FromOfs = curCabHdr.ofsLastData;
		} else {
			ToCopy = pFile->cbCompressed;
			FromOfs = pFile->ofsData;
		}

		SetFilePointer(hRead, FromOfs, NULL, FILE_BEGIN);
		TransferData(hRead, hMainCab, ToCopy, CRYPT_NONE);

		// check if it is the last file in this volume
		if (i == curCabHdr.LastFile && i < pCabDesc->cFiles - 1) {
			DWORD dwRead;

			CloseHandle(hRead);
			if (vol > 1)
				DeleteCab(cabname);
			// go to next volume
			vol++;
			sprintf(cabname, pCabPattern, vol);
			hRead = OpenForRead(cabname);
			if (!ReadFile(hRead, &curCabHdr, sizeof(curCabHdr), &dwRead, NULL) ||
				dwRead != sizeof(curCabHdr))
					CantReadFile(GetLastError());

			// if current file is split
			if (i == curCabHdr.FirstFile) {
				SetFilePointer(hRead, curCabHdr.ofsFirstData, NULL, FILE_BEGIN);
				TransferData(hRead, hMainCab, curCabHdr.cbFirstHere, CRYPT_NONE);
			}
		}

		pFile->DescStatus &= ~(DWORD)DESC_NEXT_VOLUME;
		pFile->ofsData = CabPtr;
		CabPtr += pFile->cbCompressed;
	}

	CloseHandle(hRead);
	if (vol > 1)
		DeleteCab(cabname);

	CloseHandle(hMainCab);

	// Patch header to reflect the change to a single volume
	FirstVolHdr->NextVol = 0;
	FirstVolHdr->LastFile = pCabDesc->cFiles - 1;
	FirstVolHdr->ofsLastData = 0;
	FirstVolHdr->cbLastExpanded = 0;
	FirstVolHdr->cbLastHere = 0;

	{// Update FileGroups to reflect the change
		DWORD i;
		LPFILEGROUPDESC pFG;

		for (i=0; i < cFileGroups; i++) {
			pFG = GetFileGroupDesc(pCabDesc, FileGroups, i);
			if (pFG->FirstVolume > 0) {
				pFG->FirstVolume = 1;
				pFG->LastVolume = 1;
			}
		}
	}
	SaveCabHeaders();

	if (optPrintAll)
		fprintf(stderr, "Successfully converted to single volume.\n");
}

void DeleteCab(LPSTR cabname)
{
	if (!DeleteFile(cabname))
		fprintf(stderr, "Could not delete %s, error code %d\n", cabname, GetLastError());
}

void TransferData(HANDLE hFrom, HANDLE hTo, DWORD Length, DWORD Crypt)
{
	DWORD dwTran;
	LPBYTE pBuf;
	DWORD ToTran;
	DWORD Total = 0;

	if (Length > 262144)
		ToTran = 262144;
	else
		ToTran = Length;

	pBuf = Alloc(ToTran);

	while (Length) {
		if (ToTran > Length)
			ToTran = Length;
		if (!ReadFile(hFrom, pBuf, ToTran, &dwTran, NULL) || dwTran != ToTran)
			CantReadFile(GetLastError());
	
		if (Crypt == CRYPT_ENCRYPT) {
			DWORD i;
			BYTE ts;
			for (i=0; i < dwTran; i++) {
				ts = (BYTE)((Total + i) % 0x47) + pBuf[i];
				__asm { rol byte ptr ts, 2 };
				pBuf[i] = ts ^ 0xd5;
			}
			Total += dwTran;
		} else if (Crypt == CRYPT_DECRYPT) {
			DWORD i;
			BYTE ts;
			for (i=0; i < dwTran; i++) {
				ts = pBuf[i] ^ 0xd5;
				__asm { ror byte ptr ts, 2 };
				pBuf[i] = ts - (BYTE)((Total + i) % 0x47);
			}
			Total += dwTran;
		}

		if (!WriteFile(hTo, pBuf, ToTran, &dwTran, NULL) || dwTran != ToTran)
			CantWriteFile(GetLastError());
		Length -= dwTran;
	}
	Free(pBuf);
}

BOOL AutoDetectFailed()
{
	fprintf(stderr, "WARNING: ZData AutoDetect failed. Assuming v5.00.200+\n");
	optVersion = 51145;
	return TRUE;
}

BOOL AutoDetectZData()
{
	DWORD i = 0;
	LPFILEDESC pFile;
	DWORD NextOfs, Len = 0;

	if (ver == ver55) {
		// it's ver 5.5+
		optVersion = 51145;
		return TRUE;
	}
	
	// find a good compressed file, size > 0
	while (i < pCabDesc->cFiles && (

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -