📄 archiverecovery.cpp
字号:
return retVal;
}
bool CArchiveRecovery::IsFilled(uint32 start, uint32 end, CTypedPtrList<CPtrList, Gap_Struct*> *filled)
{
POSITION pos = filled->GetHeadPosition();
Gap_Struct *fill;
while (pos != NULL)
{
fill = filled->GetNext(pos);
if (fill->start > start)
return false;
if (fill->end >= end)
return true;
}
return false;
}
// This will find the marker in the file and leave it positioned at the position to read the marker again
bool CArchiveRecovery::scanForZipMarker(CFile *input, uint32 marker, uint32 available)
{
try
{
//uint32 originalOffset = input->GetPosition();
int lenChunk = 51200; // 50k buffer
BYTE chunk[51200];
BYTE *foundPos = NULL;
int pos = 0;
while ((available > 0) && ((lenChunk = input->Read(chunk, lenChunk)) > 0))
{
available -= lenChunk;
foundPos = &chunk[0];
// Move back one, will be incremented in loop
foundPos--;
while (foundPos != NULL)
{
// Find first matching byte
foundPos = (BYTE*)memchr( foundPos+1, (marker & 0xFF), (lenChunk - (foundPos+1 - (&chunk[0]))) );
if (foundPos == NULL)
continue;
// Test for end of buffer
pos = foundPos - (&chunk[0]);
if ((pos + 3) > lenChunk)
{
// Re-read buffer starting from found first byte position
input->Seek(pos - lenChunk, CFile::current);
break;
}
// Check for other bytes
if (chunk[pos + 1] == ((marker >> 8) & 0xFF))
{
if (chunk[pos + 2] == ((marker >> 16) & 0xFF))
{
if (chunk[pos + 3] == ((marker >> 24) & 0xFF))
{
// Found it
input->Seek(pos - lenChunk, CFile::current);
return true;
}
}
}
}
}
}
catch (CFileException* error){
error->Delete();
}
catch (...){
ASSERT(0);
}
return false;
}
// This will find a file block in the file and leave it positioned at the end of the filename
RAR_BlockFile *CArchiveRecovery::scanForRarFileHeader(CFile *input, uint32 available)
{
RAR_BlockFile *retVal = NULL;
try
{
int lenChunk = 51200; // 50k buffer
BYTE chunk[51200];
BYTE *foundPos = NULL;
int pos = 0;
ULONGLONG searchOffset;
ULONGLONG foundOffset;
uint16 headCRC;
BYTE checkCRC[38];
uint16 lenFileName;
BYTE *fileName;
uint32 crc;
while ((available > 0) && ((lenChunk = input->Read(chunk, lenChunk)) > 0))
{
available -= lenChunk;
foundPos = &chunk[0];
searchOffset = input->GetPosition() - lenChunk;
// Move back one, will be incremented in loop
foundPos--;
while (foundPos != NULL)
{
// Find rar head block marker
foundPos = (BYTE*)memchr( foundPos+1, RAR_HEAD_FILE, (lenChunk - (foundPos+1 - (&chunk[0]))) );
if (foundPos == NULL)
continue;
// Move back 2 bytes to get crc and read block
pos = (int)(foundPos - (&chunk[0]) - 2);
input->Seek(pos - lenChunk, CFile::current);
foundOffset = input->GetPosition();
headCRC = readUInt16(input); // CRC of fields from HEAD_TYPE to ATTR + filename
input->Read(&checkCRC[0], 30);
// Also need filename for crc
lenFileName = (((uint16)checkCRC[25]) << 8) + ((uint16)checkCRC[24]);
fileName = new BYTE[lenFileName];
if (checkCRC[2] & 0x1) // If HEAD_FLAG & 0x100
input->Read(&checkCRC[30], 8);
input->Read(fileName, lenFileName);
crc = crc32(0, &checkCRC[0], 30);
crc = crc32(crc, fileName, lenFileName);
if ((crc & 0xFFFF) == headCRC)
{
// Found valid crc, build block and return
// Note that it may still be invalid data, so more checks should be performed
retVal = new RAR_BlockFile;
retVal->HEAD_CRC = headCRC;
retVal->HEAD_TYPE = 0x74;
retVal->HEAD_FLAGS = calcUInt16(&checkCRC[ 1]);
retVal->HEAD_SIZE = calcUInt16(&checkCRC[ 3]);
retVal->PACK_SIZE = calcUInt32(&checkCRC[ 5]);
retVal->UNP_SIZE = calcUInt32(&checkCRC[ 9]);
retVal->HOST_OS = checkCRC[13];
retVal->FILE_CRC = calcUInt32(&checkCRC[14]);
retVal->FTIME = calcUInt32(&checkCRC[18]);
retVal->UNP_VER = checkCRC[22];
retVal->METHOD = checkCRC[23];
retVal->NAME_SIZE = lenFileName;
retVal->ATTR = calcUInt32(&checkCRC[26]);
// Optional values, present only if bit 0x100 in HEAD_FLAGS is set.
if ((retVal->HEAD_FLAGS & 0x100) == 0x100)
{
retVal->HIGH_PACK_SIZE = calcUInt32(&checkCRC[30]);
retVal->HIGH_UNP_SIZE = calcUInt32(&checkCRC[34]);
}
retVal->FILE_NAME = fileName;
// Run some quick checks
if (validateRarFileBlock(retVal))
{
// Set some useful markers in the block
retVal->offsetData = input->GetPosition();
uint32 dataLength = retVal->PACK_SIZE;
// If comment present find length
if ((retVal->HEAD_FLAGS & 0x08) == 0x08)
{
// Skip start of comment block
input->Seek(5, CFile::current);
// Read comment length
dataLength += readUInt16(input);
}
retVal->dataLength = dataLength;
return retVal;
}
}
// If not valid, return to original position, re-read and continue searching
delete [] fileName;
if (retVal != NULL)
delete retVal;
retVal = NULL;
input->Seek(searchOffset, CFile::begin);
input->Read(chunk, lenChunk);
}
}
}
catch (CFileException* error){
error->Delete();
}
catch (...){
ASSERT(0);
}
return false;
}
// This assumes that head crc has already been checked
bool CArchiveRecovery::validateRarFileBlock(RAR_BlockFile *block)
{
if (block->HEAD_TYPE != 0x74)
return false;
if (block->UNP_SIZE < block->PACK_SIZE)
return false;
if (block->HOST_OS > 5)
return false;
switch (block->METHOD)
{
case 0x30: // storing
case 0x31: // fastest compression
case 0x32: // fast compression
case 0x33: // normal compression
case 0x34: // good compression
case 0x35: // best compression
break;
default:
return false;
}
if (block->NAME_SIZE > MAX_PATH)
return false;
// Check directory entry has no size
if (((block->HEAD_FLAGS & 0xE0) == 0xE0) && ((block->PACK_SIZE + block->UNP_SIZE + block->FILE_CRC) > 0))
return false;
return true;
}
void CArchiveRecovery::writeRarBlock(CFile *input, CFile *output, RAR_BlockFile *block)
{
ULONGLONG offsetStart = output->GetPosition();
try
{
writeUInt16(output, block->HEAD_CRC);
output->Write(&block->HEAD_TYPE, 1);
writeUInt16(output, block->HEAD_FLAGS);
writeUInt16(output, block->HEAD_SIZE);
writeUInt32(output, block->PACK_SIZE);
writeUInt32(output, block->UNP_SIZE);
output->Write(&block->HOST_OS, 1);
writeUInt32(output, block->FILE_CRC);
writeUInt32(output, block->FTIME);
output->Write(&block->UNP_VER, 1);
output->Write(&block->METHOD, 1);
writeUInt16(output, block->NAME_SIZE);
writeUInt32(output, block->ATTR);
// Optional values, present only if bit 0x100 in HEAD_FLAGS is set.
if ((block->HEAD_FLAGS & 0x100) == 0x100)
{
writeUInt32(output, block->HIGH_PACK_SIZE);
writeUInt32(output, block->HIGH_UNP_SIZE);
}
output->Write(block->FILE_NAME, block->NAME_SIZE);
// Now copy compressed data from input file
uint32 lenToCopy = block->dataLength;
if (lenToCopy > 0)
{
input->Seek(block->offsetData, CFile::begin);
uint32 written = 0;
BYTE chunk[4096];
uint32 lenChunk = 4096;
while (written < lenToCopy)
{
lenChunk = (lenToCopy - written);
if (lenChunk > 4096)
lenChunk = 4096;
lenChunk = input->Read(chunk, lenChunk);
if (lenChunk == 0)
break;
written += lenChunk;
output->Write(chunk, lenChunk);
}
}
output->Flush();
}
catch (CFileException* error){
error->Delete();
try { output->SetLength(offsetStart); } catch (...) {ASSERT(0);}
}
catch (...){
ASSERT(0);
try { output->SetLength(offsetStart); } catch (...) {ASSERT(0);}
}
}
uint16 CArchiveRecovery::readUInt16(CFile *input)
{
uint16 retVal = 0;
BYTE b[2];
if (input->Read(&b, 2) > 0)
retVal = (b[1] << 8) + b[0];
return retVal;
}
uint32 CArchiveRecovery::readUInt32(CFile *input)
{
uint32 retVal = 0;
BYTE b[4];
if (input->Read(&b, 4) > 0)
retVal = (b[3] << 24) + (b[2] << 16) + (b[1] << 8) + b[0];
return retVal;
}
uint16 CArchiveRecovery::calcUInt16(BYTE *input)
{
uint16 retVal = 0;
try
{
retVal = (((uint16)input[1]) << 8) + ((uint16)input[0]);
} catch (...) {ASSERT(0);}
return retVal;
}
uint32 CArchiveRecovery::calcUInt32(BYTE *input)
{
uint32 retVal = 0;
try
{
retVal = (((uint32)input[3]) << 24) + (((uint32)input[2]) << 16) + (((uint32)input[1]) << 8) + ((uint32)input[0]);
} catch (...) {ASSERT(0);}
return retVal;
}
void CArchiveRecovery::writeUInt16(CFile *output, uint16 val)
{
BYTE b[2];
b[0] = (val & 0x000000ff);
b[1] = (val & 0x0000ff00) >> 8;
output->Write(&b, 2);
}
void CArchiveRecovery::writeUInt32(CFile *output, uint32 val)
{
BYTE b[4];
b[0] = (val & 0x000000ff);
b[1] = (val & 0x0000ff00) >> 8;
b[2] = (val & 0x00ff0000) >> 16;
b[3] = (val & 0xff000000) >> 24;
output->Write(&b, 4);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -