📄 i5comp.c
字号:
///////////////////////////////////////////////////////////////////
// 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 + -