📄 i5comp.c
字号:
((pFile=GetFileDesc(DFT, pCabDesc->cDirs + i))->DescStatus & DESC_INVALID) ||
!(pFile->DescStatus & DESC_COMPRESSED) ||
pFile->cbCompressed == 0)
)
i++;
if (i >= pCabDesc->cFiles)
// none found
return AutoDetectFailed();
// newer compression lib uses a 2-byte block size value
// in front of every block of compressed data
// try to detect that
NextOfs = pFile->ofsData;
while (Len < pFile->cbCompressed) {
DWORD dwRead;
WORD BlockSize;
SetFilePointer(hCabFile, NextOfs, NULL, FILE_BEGIN);
if (!ReadFile(hCabFile, &BlockSize, sizeof(BlockSize), &dwRead, NULL) ||
dwRead != sizeof(BlockSize))
CantReadFile(GetLastError());
BlockSize += sizeof(BlockSize); // had me chasing this for a while =)
NextOfs += BlockSize;
Len += BlockSize;
}
// if sizes match - it's a new style lib
optVersion = Len == pFile->cbCompressed ? 51145 : 50149;
return TRUE;
}
void InitZData(RWHANDLES* pHnds)
{
if (optVersion == 0)
// version was not specified
// attemp to autodetect
AutoDetectZData();
InitCompressLib();
pZBuf = Alloc(STD_DECOMP_BUFFER);
ZDataSetInfo(INFO_BUFFER_PTR, (DWORD)pZBuf);
ZDataSetInfo(INFO_BUFFER_SIZE, STD_DECOMP_BUFFER);
ZDataSetInfo(INFO_READ_CALLBACK, (DWORD)ReadData);
ZDataSetInfo(INFO_WRITE_CALLBACK, (DWORD)WriteData);
ZDataSetInfo(INFO_CALLBACK_PARAM, (DWORD)pHnds);
}
void ExtractFiles()
{
LPFILEDESC pFile;
RWHANDLES rwHnd;
unsigned int i;
LPSTR pSlash;
LPSTR pName;
LPCABFILELIST pCurrent = pFileList;
FILETIME filetime;
DWORD Res;
if (!IsSingleVolume())
MultipleNotSupported();
InitZData(&rwHnd);
rwHnd.hRead = OpenForRead(pCabPattern);
while (pCurrent) {
i = pCurrent->CabIndex;
pName = pCurrent->FileName;
pFile = GetFileDesc(DFT, pCabDesc->cDirs + i);
SetFilePointer(rwHnd.hRead, pFile->ofsData, 0, 0);
pSlash = strrchr(pName, '\\');
if (pSlash) {
*pSlash = '\0';
if (!DirExists(pName))
CreateDir(pName);
*pSlash = '\\';
}
rwHnd.hWrite = OpenForWrite(pName, CREATE_ALWAYS);
if (pFile->DescStatus & DESC_COMPRESSED) {
rwHnd.BytesIn = pFile->cbCompressed;
rwHnd.BytesOut = 0;
__try {
if (ZDataStart(0))
CantDecompress(pName);
if (Res=ZDataDecompress(0))
CantDecompress(pName);
else {
if (optPrintAll || rwHnd.BytesOut != pFile->cbExpanded)
fprintf(stdout, "%s", pName);
if (rwHnd.BytesOut != pFile->cbExpanded)
NoMatchBytesOut();
if (optPrintAll || rwHnd.BytesOut != pFile->cbExpanded)
fprintf(stdout, "\n");
}
ZDataEnd();
} __except(EXCEPTION_EXECUTE_HANDLER) {
ExceptInDecompress();
}
} else {
TransferData(rwHnd.hRead,
rwHnd.hWrite,
pFile->cbExpanded,
pFile->DescStatus & DESC_ENCRYPTED ? CRYPT_DECRYPT : CRYPT_NONE);
if (optPrintAll)
fprintf(stdout, "%s\n", pName);
}
DosDateTimeToFileTime((WORD)pFile->FatDate, (WORD)pFile->FatTime, &filetime);
SetFileTime(rwHnd.hWrite, NULL, NULL, &filetime);
CloseHandle(rwHnd.hWrite);
SetFileAttributes(pName, pFile->Attrs);
pCurrent = pCurrent->pNext;
}
CloseHandle(rwHnd.hRead);
}
LPFILEGROUPDESC GetGroupByFile(DWORD index)
{
LPFILEGROUPDESC pFG;
DWORD i = 0;
while ( i < cFileGroups &&
(index < (pFG=GetFileGroupDesc(pCabDesc, FileGroups, i))->FirstFile ||
index > pFG->LastFile) )
i++;
return i < cFileGroups ? pFG : NULL;
}
void CreateDir(LPSTR dirname)
{
DWORD dwErr;
if (!CreateDirectory(dirname, NULL)) {
dwErr = GetLastError();
if (dwErr == ERROR_PATH_NOT_FOUND) {
LPSTR pSlash;
pSlash = strrchr(dirname, '\\');
if (pSlash) {
*pSlash = '\0';
CreateDir(dirname);
*pSlash = '\\';
CreateDir(dirname);
return;
}
}
if (dwErr == ERROR_ALREADY_EXISTS)
return;
fprintf(stderr, "Can not create directory %s\n", dirname);
CleanExit(9);
}
}
int CALLBACK ReadData(LPVOID pbuf, LPDWORD size, LPRWHANDLES pHnd)
{
DWORD dwRead;
if (!pHnd->BytesIn) {
*size = 0;
return 0;
}
if (pHnd->BytesIn < *size)
*size = pHnd->BytesIn;
if (ReadFile(pHnd->hRead, pbuf, *size, &dwRead, NULL)) {
pHnd->BytesIn -= dwRead;
*size = dwRead;
return 0;
} else
return GetLastError();
}
int CALLBACK WriteData(LPVOID pbuf, LPDWORD size, LPRWHANDLES pHnd)
{
DWORD dwWritten;
if (WriteFile(pHnd->hWrite, pbuf, *size, &dwWritten, NULL)) {
*size = dwWritten;
pHnd->BytesOut += dwWritten;
return 0;
} else
return GetLastError();
}
void ReplaceFiles()
{
LPFILEDESC pFile;
LPSTR pName;
LPFILEGROUPDESC pFG;
RWHANDLES rwHnd;
DWORD i;
LPCABFILELIST pCurrent = pFileList;
DWORD ofsNew;
DWORD sizeNew;
ZCOMPRESSBUF ZParam;
BOOL Store;
if (!IsSingleVolume())
MultipleNotSupported();
InitZData(&rwHnd);
rwHnd.hWrite = OpenForWrite(pCabPattern, OPEN_EXISTING);
while (pCurrent) {
i = pCurrent->CabIndex;
pName = pCurrent->FileName;
pFile = GetFileDesc(DFT, pCabDesc->cDirs + i);
pFG = GetGroupByFile(i);
rwHnd.hRead = OpenForRead(pName);
{// Clean out the old file from cab
HANDLE hCabRead;
DWORD MoveSize;
DWORD MoveShift;
DWORD i2;
DWORD FileSize;
DWORD Top, Bottom;
DWORD ofsTop;
DWORD ofsBottom;
LPFILEDESC pF;
hCabRead = OpenForRead(pCabPattern);
FileSize = ofsTop = GetFileSize(hCabRead, NULL);
ofsBottom = pFile->ofsData + pFile->cbCompressed;
// Find file right after the one removing and the last file
for (i2=0; i2 < pCabDesc->cFiles; i2++) {
pF = GetFileDesc(DFT, pCabDesc->cDirs + i2);
if (pF->DescStatus & DESC_INVALID)
continue;
if (pF->ofsData > pFile->ofsData && pF->ofsData < ofsTop) {
Top = i2;
ofsTop = pF->ofsData;
}
if (pF->ofsData > pFile->ofsData && pF->ofsData + pF->cbCompressed > ofsBottom) {
Bottom = i2;
ofsBottom = pF->ofsData + pF->cbCompressed;
}
}
MoveSize = FileSize - ofsTop;
MoveShift = ofsTop - pFile->ofsData;
SetFilePointer(rwHnd.hWrite, pFile->ofsData, NULL, FILE_BEGIN);
// Shift data up if necessary
if (MoveSize) {
SetFilePointer(hCabRead, ofsTop, NULL, FILE_BEGIN);
TransferData(hCabRead, rwHnd.hWrite, MoveSize, CRYPT_NONE);
}
CloseHandle(hCabRead);
ofsNew = SetFilePointer(rwHnd.hWrite, 0, NULL, FILE_CURRENT);
// Update file descriptors to reflect the change in file position
for (i2=0; i2 < pCabDesc->cFiles; i2++) {
pF = GetFileDesc(DFT, pCabDesc->cDirs + i2);
if (pF->DescStatus & DESC_INVALID)
continue;
if (pF->ofsData > pFile->ofsData)
pF->ofsData -= MoveShift;
}
}
sizeNew = GetFileSize(rwHnd.hRead, NULL);
if (pFile->DescStatus & DESC_COMPRESSED)
Store = FALSE;
else
Store = TRUE;
if (!Store) {
rwHnd.BytesIn = sizeNew;
rwHnd.BytesOut = 0;
if (ZDataStart(0))
CantCompressError(pName);
if (ZDataCompress(sizeof(ZParam), &ZParam) ||
sizeNew * 0.95 < rwHnd.BytesOut) {
CantCompressStore(pName);
pFile->DescStatus &= ~DESC_COMPRESSED;
Store = TRUE;
SetFilePointer(rwHnd.hWrite, ofsNew, NULL, FILE_BEGIN);
SetFilePointer(rwHnd.hRead, 0, NULL, FILE_BEGIN);
}
ZDataEnd();
}
if (Store) {
rwHnd.BytesOut = sizeNew;
TransferData(rwHnd.hRead,
rwHnd.hWrite,
sizeNew,
pFile->DescStatus & DESC_ENCRYPTED ? CRYPT_ENCRYPT : CRYPT_NONE);
}
CloseHandle(rwHnd.hRead);
if (optPrintAll)
fprintf(stdout, "%s\n", pName);
SetEndOfFile(rwHnd.hWrite);
if (pFG) {
pFG->cbExpanded += sizeNew - pFile->cbExpanded;
pFG->cbCompressed += rwHnd.BytesOut - pFile->cbCompressed;
}
pFile->cbExpanded = sizeNew;
pFile->cbCompressed = rwHnd.BytesOut;
pFile->ofsData = ofsNew;
pCurrent = pCurrent->pNext;
}
CloseHandle(rwHnd.hWrite);
SaveCabHeaders();
}
void AddFiles()
{
DWORD NextFile;
DWORD ofsNextDesc;
DWORD ofsNextName;
RWHANDLES rwHnd;
DWORD DataOfs;
ZCOMPRESSBUF ZParam;
LPDISKFILELIST pCurrent;
LPFILEDESC pFile;
LPFILEGROUPDESC pFG;
char DName[MAX_PATH];
DWORD Attrs;
FILETIME filetime;
DWORD Res;
// add new files
if (!IsSingleVolume())
MultipleNotSupported();
if (optFileGroup == -1) {
fprintf(stderr, "'a': Must specify File Group to add to with -g OR use -f\n");
CleanExit(25);
}
RebuildDFT(&NextFile, &ofsNextDesc, &ofsNextName);
InitZData(&rwHnd);
rwHnd.hWrite = OpenForWrite(pCabPattern, OPEN_EXISTING);
DataOfs = SetFilePointer(rwHnd.hWrite, 0, NULL, FILE_END);
pFG = GetFileGroupDesc(pCabDesc, FileGroups, optFileGroup);
pCurrent = pDiskList;
while (pCurrent) {
strcpy(DName, pCurrent->DiskDir);
strcat(DName, pCurrent->FileName);
rwHnd.hRead = OpenForRead(DName);
DFT[pCabDesc->cDirs + NextFile] = ofsNextDesc;
ofsNextDesc += sizeof(FILEDESC);
pFile = GetFileDesc(DFT, pCabDesc->cDirs + NextFile);
pFile->DescStatus = DESC_COMPRESSED;
pFile->ofsName = ofsNextName;
strcpy(GetString(DFT, ofsNextName), pCurrent->FileName);
ofsNextName += strlen(pCurrent->FileName) + 1;
pFile->ofsData = DataOfs;
pFile->DirIndex = pCurrent->CabDirInd;
rwHnd.BytesIn = GetFileSize(rwHnd.hRead, NULL);
pFile->cbExpanded = rwHnd.BytesIn;
rwHnd.BytesOut = 0;
if (ZDataStart(0))
CantCompressError(DName);
if ((Res=ZDataCompress(sizeof(ZParam), &ZParam)) ||
pFile->cbExpanded * 0.95 < rwHnd.BytesOut) {
CantCompressStore(DName);
pFile->DescStatus &= ~DESC_COMPRESSED;
SetFilePointer(rwHnd.hWrite, DataOfs, NULL, FILE_BEGIN);
SetFilePointer(rwHnd.hRead, 0, NULL, FILE_BEGIN);
rwHnd.BytesOut = pFile->cbExpanded;
TransferData(rwHnd.hRead, rwHnd.hWrite, rwHnd.BytesOut, CRYPT_NONE);
}
ZDataEnd();
if (optPrintAll)
fprintf(stdout, "%s\n", DName);
GetFileTime(rwHnd.hRead, NULL, NULL, &filetime);
CloseHandle(rwHnd.hRead);
pFile->FatDate = pFile->FatTime = 0;
FileTimeToDosDateTime(&filetime, (LPWORD)&pFile->FatDate, (LPWORD)&pFile->FatTime);
pFile->cbCompressed = rwHnd.BytesOut;
Attrs = GetFileAttributes(DName);
if (Attrs == -1) {
Attrs = 0;
fprintf(stderr, "Could not get file attributes of %s\n", DName);
}
pFile->Attrs = Attrs;
DataOfs = SetFilePointer(rwHnd.hWrite, 0, NULL, FILE_CURRENT);
// update headers
FirstVolHdr->LastFile = NextFile;
pCabDesc->cFiles = NextFile + 1;
pFG->LastFile = NextFile;
pFG->cbExpanded += pFile->cbExpanded;
pFG->cbCompressed += pFile->cbCompressed;
NextFile++;
SaveCabHeaders();
pCurrent = pCurrent->pNext;
}
CloseHandle(rwHnd.hWrite);
}
void RebuildDFT(LPDWORD NextFile, LPDWORD ofsNextDesc, LPDWORD ofsNextName)
{
LPDIRARRAY pDA;
LPDISKFILELIST pCurrent;
DWORD i;
DWORD NewSize;
DWORD OldDataOfs, NewDataOfs;
LPFILEDESC pFile;
DFTABLE NewDFT;
DWORD cFilesNew;
// take apart Dirs
pDA = DirsArrayBuild();
// insert new dirs in the list
pCurrent = pDiskList;
while (pCurrent) {
pCurrent->CabDirInd = DirsArrayAddDir(&pDA, pCurrent->CabDir);
pCurrent = pCurrent->pNext;
}
// calc new size of the DFT
cFilesNew = pCabDesc->cFiles + FileCount;
NewSize = (cFilesNew + pDA->Count) * sizeof(DWORD); // DF ofs table
// position of first File Desc.
*ofsNextDesc = NewSize;
NewSize += cFilesNew * sizeof(FILEDESC);
// position of first Name (Dir/File)
*ofsNextName = NewSize;
for (i=0; i < pCabDesc->cFiles; i++) {
pFile = GetFileDesc(DFT, pCabDesc->cDirs + i);
if (pFile->DescStatus & DESC_INVALID)
continue;
NewSize += strlen(GetString(DFT, pFile->ofsName)) + 1;
}
pCurrent = pDiskList;
while (pCurrent) {
NewSize += strlen(pCurrent->FileName) + 1;
pCurrent = pCurrent->pNext;
}
for (i=0; i < pDA->Count; i++)
NewSize += strlen(pDA->Dirs[i]) + 1;
// new position of compressed data in cab
NewDataOfs = CabHdr.ofsCabDesc + pCabDesc->ofsDFT + NewSize;
// allocate and build new DFT, while moving the optFileGroup to the bottom
NewDFT = Alloc(NewSize);
// copy dirs
for (i=0; i < pDA->Count; i++) {
NewDFT[i] = *ofsNextName;
strcpy(GetString(NewDFT, *ofsNextName), pDA->Dirs[i]);
*ofsNextName += strlen(pDA->Dirs[i]) + 1;
}
// copy files, update filegroups
*NextFile = 0;
for (i=0; i < cFileGroups; i++) {
if (i == optFileGroup)
continue;
CopyFileGroup(DFT, NewDFT, pDA->Count, i, NextFile, ofsNextDesc, ofsNextName);
}
CopyFileGroup(DFT, NewDFT, pDA->Count, optFileGroup, NextFile, ofsNextDesc, ofsNextName);
// update all headers
Free(DFT);
DFT = NewDFT;
pCabDesc->cDirs = pDA->Count;
Free(pDA);
pCabDesc->cbDFT = NewSize;
pCabDesc->cbDFT2 = NewSize;
OldDataOfs = CabHdr.ofsCompData;
if (NewDataOfs > OldDataOfs) {
// newer versions have relevant headers separately
if (ver < ver55) {
DWORD Shift = NewDataOfs - OldDataOfs;
// update file descriptors
for (i=0; i < pCabDesc->cFiles; i++) {
pFile = GetFileDesc(NewDFT, pCabDesc->cDirs + i);
pFile->ofsData += Shift;
}
// shift Z data down
ShiftDataDown(pCabPattern, OldDataOfs, Shift);
}
// update headers
CabHdr.ofsCompData = NewDataOfs;
}
SaveCabHeaders();
}
void ShiftDataDown(LPSTR FileName, DWORD DataOfs, DWORD Shift)
{
HANDLE hRead, hWrite;
DWORD MoveSize;
DWORD dwTran;
LPBYTE pBuf;
DWORD ToTran;
hRead = OpenForRead(FileName);
hWrite = OpenForWrite(FileName, OPEN_EXISTING);
MoveSize = GetFileSize(hRead, NULL) - DataOfs;
DataOfs += MoveSize;
if (MoveSize > 262144)
ToTran = 262144;
else
ToTran = MoveSize;
pBuf = Alloc(ToTran);
while (MoveSize) {
if (ToTran > MoveSize)
ToTran = MoveSize;
DataOfs -= ToTran;
SetFilePointer(hRead, DataOfs, NULL, FILE_BEGIN);
if (!ReadFile(hRead, pBuf, ToTran, &dwTran, NULL) || dwTran != ToTran)
CantReadFile(GetLastError());
SetFilePointer(hWrite, DataOfs + Shift, NULL, FILE_BEGIN);
if (!WriteFile(hWrite, pBuf, ToTran, &dwTran, NULL) || dwTran != ToTran)
CantWriteFile(GetLastError());
MoveSize -= dwTran;
}
Free(pBuf);
CloseHandle(hRead);
CloseHandle(hWrite);
}
void CopyFileGroup(DFTABLE OldT, DFTABLE NewT, DWORD cNewDirs, DWORD FGIndex, LPDWORD NextFile, LPDWORD ofsNextDesc, LPDWORD ofsNextName)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -