📄 archiverecovery.cpp
字号:
bool retVal = false;
try
{
// Ideally this zip file will not have a comment and the End-CD will be easy to find
zipInput->Seek(-22, CFile::end);
if (!(readUInt32(zipInput) == ZIP_END_CD_MAGIC))
{
// Have to look for it, comment could be up to 65535 chars but only try with less than 1k
zipInput->Seek(-1046, CFile::end);
if (!scanForZipMarker(zipInput, (uint32)ZIP_END_CD_MAGIC, 1046))
return false;
// Skip it again
readUInt32(zipInput);
}
// Found End-CD
// Only interested in offset of first CD
zipInput->Seek(12, CFile::current);
uint32 startOffset = readUInt32(zipInput);
if (!IsFilled(startOffset, zipInput->GetLength(), filled))
return false;
// Goto first CD and start reading
zipInput->Seek(startOffset, CFile::begin);
ZIP_CentralDirectory *cdEntry;
while (readUInt32(zipInput) == ZIP_CD_MAGIC)
{
cdEntry = new ZIP_CentralDirectory;
cdEntry->versionMadeBy = readUInt16(zipInput);
cdEntry->versionToExtract = readUInt16(zipInput);
cdEntry->generalPurposeFlag = readUInt16(zipInput);
cdEntry->compressionMethod = readUInt16(zipInput);
cdEntry->lastModFileTime = readUInt16(zipInput);
cdEntry->lastModFileDate = readUInt16(zipInput);
cdEntry->crc32 = readUInt32(zipInput);
cdEntry->lenCompressed = readUInt32(zipInput);
cdEntry->lenUnompressed = readUInt32(zipInput);
cdEntry->lenFilename = readUInt16(zipInput);
cdEntry->lenExtraField = readUInt16(zipInput);
cdEntry->lenComment = readUInt16(zipInput);
cdEntry->diskNumberStart = readUInt16(zipInput);
cdEntry->internalFileAttributes = readUInt16(zipInput);
cdEntry->externalFileAttributes = readUInt32(zipInput);
cdEntry->relativeOffsetOfLocalHeader= readUInt32(zipInput);
if (cdEntry->lenFilename > 0)
{
cdEntry->filename = new BYTE[cdEntry->lenFilename];
zipInput->Read(cdEntry->filename, cdEntry->lenFilename);
}
if (cdEntry->lenExtraField > 0)
{
cdEntry->extraField = new BYTE[cdEntry->lenExtraField];
zipInput->Read(cdEntry->extraField, cdEntry->lenExtraField);
}
if (cdEntry->lenComment > 0)
{
cdEntry->comment = new BYTE[cdEntry->lenComment];
zipInput->Read(cdEntry->comment, cdEntry->lenComment);
}
centralDirectoryEntries->AddTail(cdEntry);
}
retVal = true;
}
catch (CFileException* error){
error->Delete();
}
catch (...){
ASSERT(0);
}
return retVal;
}
bool CArchiveRecovery::processZipEntry(CFile *zipInput, CFile *zipOutput, uint32 available, CTypedPtrList<CPtrList, ZIP_CentralDirectory*> *centralDirectoryEntries)
{
if (available < 26)
return false;
bool retVal = false;
try
{
// Need to know where it started
long startOffset = zipOutput->GetPosition();
// Entry format :
// 4 2 bytes Version needed to extract
// 6 2 bytes General purpose bit flag
// 8 2 bytes Compression method
// 10 2 bytes Last mod file time
// 12 2 bytes Last mod file date
// 14 4 bytes CRC-32
// 18 4 bytes Compressed size (n)
// 22 4 bytes Uncompressed size
// 26 2 bytes Filename length (f)
// 28 2 bytes Extra field length (e)
// (f)bytes Filename
// (e)bytes Extra field
// (n)bytes Compressed data
// Read header
if (readUInt32(zipInput) != ZIP_LOCAL_HEADER_MAGIC)
return false;
ZIP_Entry entry={0};
entry.versionToExtract = readUInt16(zipInput);
entry.generalPurposeFlag = readUInt16(zipInput);
entry.compressionMethod = readUInt16(zipInput);
entry.lastModFileTime = readUInt16(zipInput);
entry.lastModFileDate = readUInt16(zipInput);
entry.crc32 = readUInt32(zipInput);
entry.lenCompressed = readUInt32(zipInput);
entry.lenUncompressed = readUInt32(zipInput);
entry.lenFilename = readUInt16(zipInput);
entry.lenExtraField = readUInt16(zipInput);
// Do some quick checks at this stage that data is looking ok
if ((entry.crc32 == 0) || (entry.lenCompressed == 0) || (entry.lenUncompressed == 0) || (entry.lenFilename == 0))
return false;
// Is this entry complete
if ((entry.lenFilename + entry.lenExtraField + entry.lenCompressed) > (available - 26))
{
// Move the file pointer to the start of the next entry
zipInput->Seek((entry.lenFilename + entry.lenExtraField + entry.lenCompressed), CFile::current);
return false;
}
// Filename
if (entry.lenFilename > MAX_PATH)
return false; // Possibly corrupt, don't allocate lots of memory
entry.filename = new BYTE[entry.lenFilename];
if (zipInput->Read(entry.filename, entry.lenFilename) != entry.lenFilename)
{
delete [] entry.filename;
return false;
}
// Extra data
if (entry.lenExtraField > 0)
{
entry.extraField = new BYTE[entry.lenExtraField];
zipInput->Read(entry.extraField, entry.lenExtraField);
}
// Output
writeUInt32(zipOutput, ZIP_LOCAL_HEADER_MAGIC);
writeUInt16(zipOutput, entry.versionToExtract);
writeUInt16(zipOutput, entry.generalPurposeFlag);
writeUInt16(zipOutput, entry.compressionMethod);
writeUInt16(zipOutput, entry.lastModFileTime);
writeUInt16(zipOutput, entry.lastModFileDate);
writeUInt32(zipOutput, entry.crc32);
writeUInt32(zipOutput, entry.lenCompressed);
writeUInt32(zipOutput, entry.lenUncompressed);
writeUInt16(zipOutput, entry.lenFilename);
writeUInt16(zipOutput, entry.lenExtraField);
if (entry.lenFilename > 0)
zipOutput->Write(entry.filename, entry.lenFilename);
if (entry.lenExtraField > 0)
zipOutput->Write(entry.extraField, entry.lenExtraField);
// Read and write compressed data to avoid reading all into memory
uint32 written = 0;
BYTE buf[4096];
uint32 lenChunk = 4096;
while (written < entry.lenCompressed)
{
lenChunk = (entry.lenCompressed - written);
if (lenChunk > 4096)
lenChunk = 4096;
lenChunk = zipInput->Read(buf, lenChunk);
if (lenChunk == 0)
break;
written += lenChunk;
zipOutput->Write(buf, lenChunk);
}
zipOutput->Flush();
//Central directory:
if (centralDirectoryEntries != NULL)
{
ZIP_CentralDirectory *cdEntry = new ZIP_CentralDirectory;
cdEntry->header = ZIP_CD_MAGIC;
cdEntry->versionMadeBy = entry.versionToExtract;
cdEntry->versionToExtract = entry.versionToExtract;
cdEntry->generalPurposeFlag = entry.generalPurposeFlag;
cdEntry->compressionMethod = entry.compressionMethod;
cdEntry->lastModFileTime = entry.lastModFileTime;
cdEntry->lastModFileDate = entry.lastModFileDate;
cdEntry->crc32 = entry.crc32;
cdEntry->lenCompressed = entry.lenCompressed;
cdEntry->lenUnompressed = entry.lenUncompressed;
cdEntry->lenFilename = entry.lenFilename;
cdEntry->lenExtraField = entry.lenExtraField;
cdEntry->lenComment = strlen(ZIP_COMMENT);
cdEntry->diskNumberStart = 0;
cdEntry->internalFileAttributes = 1;
cdEntry->externalFileAttributes = 0x81B60020;
cdEntry->relativeOffsetOfLocalHeader = startOffset;
cdEntry->filename = entry.filename;
if (entry.lenExtraField > 0)
cdEntry->extraField = entry.extraField;
cdEntry->comment = new BYTE[cdEntry->lenComment];
memcpy(cdEntry->comment, ZIP_COMMENT, cdEntry->lenComment);
centralDirectoryEntries->AddTail(cdEntry);
}
else
{
delete [] entry.filename;
if (entry.lenExtraField > 0)
delete [] entry.extraField;
}
retVal = true;
}
catch (CFileException* error){
error->Delete();
}
catch (...){
ASSERT(0);
}
return retVal;
}
void CArchiveRecovery::DeleteMemory(ThreadParam *tp)
{
POSITION pos = tp->filled->GetHeadPosition();
while (pos != NULL)
delete tp->filled->GetNext(pos);
tp->filled->RemoveAll();
delete tp->filled;
delete tp;
}
bool CArchiveRecovery::CopyFile(CPartFile *partFile, CTypedPtrList<CPtrList, Gap_Struct*> *filled, CString tempFileName)
{
bool retVal = false;
try
{
CFile srcFile;
if (!srcFile.Open(partFile->GetFilePath(), CFile::modeRead | CFile::shareDenyNone))
return false;
// Open destination file and set length to last filled end position
CFile destFile;
destFile.Open(tempFileName, CFile::modeWrite | CFile::shareDenyWrite | CFile::modeCreate);
Gap_Struct *fill = filled->GetTail();
destFile.SetLength(fill->end);
BYTE buffer[4096];
uint32 read;
uint32 copied;
// Loop through filled areas and copy data
partFile->m_bPreviewing = true;
POSITION pos = filled->GetHeadPosition();
while (pos != NULL)
{
fill = filled->GetNext(pos);
copied = 0;
srcFile.Seek(fill->start, CFile::begin);
destFile.Seek(fill->start, CFile::begin);
while ((read = srcFile.Read(buffer, 4096)) > 0)
{
destFile.Write(buffer, read);
copied += read;
// Stop when finished fill (don't worry about extra)
if (fill->start + copied >= fill->end)
break;
}
}
destFile.Close();
srcFile.Close();
partFile->m_bPreviewing = false;
retVal = true;
}
catch (CFileException* error){
error->Delete();
}
catch (...){
ASSERT(0);
}
return retVal;
}
bool CArchiveRecovery::recoverRar(CFile *rarInput, CFile *rarOutput, CTypedPtrList<CPtrList, Gap_Struct*> *filled)
{
bool retVal = false;
long fileCount = 0;
try
{
BYTE start[] = RAR_START_OF_FILE;
rarOutput->Write(start, sizeof(start));
RAR_BlockFile *block;
while ((block = scanForRarFileHeader(rarInput, (uint32)rarInput->GetLength())) != NULL)
{
if (IsFilled(block->offsetData, block->offsetData + block->dataLength, filled))
{
// Don't include directories in file count
if ((block->HEAD_FLAGS & 0xE0) != 0xE0)
fileCount++;
writeRarBlock(rarInput, rarOutput, block);
}
else
{
rarInput->Seek(block->offsetData + block->dataLength, CFile::begin);
}
delete [] block->FILE_NAME;
delete block;
}
retVal = true;
}
catch (CFileException* error){
error->Delete();
}
catch (...){
ASSERT(0);
}
// Tell the user how many files were recovered
CString msg;
if (fileCount == 1)
msg = GetResString(IDS_RECOVER_SINGLE);
else
msg.Format(GetResString(IDS_RECOVER_MULTIPLE), fileCount);
AddLogLine(true, _T("%s"), msg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -