aboutsummaryrefslogtreecommitdiff
path: root/dep/CascLib/src/CascReadFile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dep/CascLib/src/CascReadFile.cpp')
-rw-r--r--dep/CascLib/src/CascReadFile.cpp142
1 files changed, 106 insertions, 36 deletions
diff --git a/dep/CascLib/src/CascReadFile.cpp b/dep/CascLib/src/CascReadFile.cpp
index 83fdd0d2096..72eb2c4b647 100644
--- a/dep/CascLib/src/CascReadFile.cpp
+++ b/dep/CascLib/src/CascReadFile.cpp
@@ -98,9 +98,10 @@ static int LoadFileFrames(TCascFile * hf)
else
nError = GetLastError();
- // Note: Do not take the FileSize from the sum of frames.
- // This value is invalid when loading the ENCODING file.
-// hf->FileSize = FileSize;
+ // Note: on ENCODING file, this value is almost always bigger
+ // then the real size of ENCODING. We handle this problem
+ // by calculating size of the ENCODIG file from its header.
+ hf->FileSize = FileSize;
#ifdef CASCLIB_TEST
hf->FileSize_FrameSum = FileSize;
@@ -264,6 +265,85 @@ static PCASC_FILE_FRAME FindFileFrame(TCascFile * hf, DWORD FilePointer)
return NULL;
}
+static int ProcessFileFrame(
+ LPBYTE pbOutBuffer,
+ DWORD cbOutBuffer,
+ LPBYTE pbInBuffer,
+ DWORD cbInBuffer,
+ DWORD dwFrameIndex)
+{
+ LPBYTE pbTempBuffer;
+ LPBYTE pbWorkBuffer;
+ DWORD cbTempBuffer = CASCLIB_MAX(cbInBuffer, cbOutBuffer);
+ DWORD cbWorkBuffer = cbOutBuffer + 1;
+ DWORD dwStepCount = 0;
+ bool bWorkComplete = false;
+ int nError = ERROR_SUCCESS;
+
+ // Allocate the temporary buffer that will serve as output
+ pbWorkBuffer = pbTempBuffer = CASC_ALLOC(BYTE, cbTempBuffer);
+ if(pbWorkBuffer == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Perform the loop
+ for(;;)
+ {
+ // Set the output buffer.
+ // Even operations: extract to temporary buffer
+ // Odd operations: extract to output buffer
+ pbWorkBuffer = (dwStepCount & 0x01) ? pbOutBuffer : pbTempBuffer;
+ cbWorkBuffer = (dwStepCount & 0x01) ? cbOutBuffer : cbTempBuffer;
+
+ // Perform the operation specific to the operation ID
+ switch(pbInBuffer[0])
+ {
+ case 'E': // Encrypted files
+ nError = CascDecrypt(pbWorkBuffer, &cbWorkBuffer, pbInBuffer + 1, cbInBuffer - 1, dwFrameIndex);
+ bWorkComplete = (nError != ERROR_SUCCESS);
+ break;
+
+ case 'Z': // ZLIB compressed files
+ nError = CascDecompress(pbWorkBuffer, &cbWorkBuffer, pbInBuffer + 1, cbInBuffer - 1);
+ bWorkComplete = true;
+ break;
+
+ case 'N': // Normal stored files
+ nError = CascDirectCopy(pbWorkBuffer, &cbWorkBuffer, pbInBuffer + 1, cbInBuffer - 1);
+ bWorkComplete = true;
+ break;
+
+ case 'F': // Recursive frames - not supported
+ default: // Unrecognized - if we unpacked something, we consider it done
+ nError = ERROR_NOT_SUPPORTED;
+ bWorkComplete = true;
+ assert(false);
+ break;
+ }
+
+ // Are we done?
+ if(bWorkComplete)
+ break;
+
+ // Set the input buffer to the work buffer
+ pbInBuffer = pbWorkBuffer;
+ cbInBuffer = cbWorkBuffer;
+ dwStepCount++;
+ }
+
+ // If the data are currently in the temporary buffer,
+ // we need to copy them to output buffer
+ if(nError == ERROR_SUCCESS && pbWorkBuffer != pbOutBuffer)
+ {
+ if(cbWorkBuffer != cbOutBuffer)
+ nError = ERROR_INSUFFICIENT_BUFFER;
+ memcpy(pbOutBuffer, pbWorkBuffer, cbOutBuffer);
+ }
+
+ // Free the temporary buffer
+ CASC_FREE(pbTempBuffer);
+ return nError;
+}
+
//-----------------------------------------------------------------------------
// Public functions
@@ -299,7 +379,7 @@ DWORD WINAPI CascGetFileSize(HANDLE hFile, PDWORD pdwFileSizeHigh)
}
// Make sure that the file header area is loaded
- nError = EnsureHeaderAreaIsLoaded(hf);
+ nError = EnsureFrameHeadersLoaded(hf);
if(nError != ERROR_SUCCESS)
{
SetLastError(nError);
@@ -387,7 +467,6 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW
DWORD dwFilePointer = 0;
DWORD dwEndPointer = 0;
DWORD dwFrameSize;
- DWORD cbOutBuffer;
bool bReadResult;
int nError = ERROR_SUCCESS;
@@ -423,7 +502,7 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW
{
// Get the frame
pFrame = FindFileFrame(hf, hf->FilePointer);
- if(pFrame == NULL)
+ if(pFrame == NULL || pFrame->CompressedSize < 1)
nError = ERROR_FILE_CORRUPT;
}
@@ -439,7 +518,7 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW
// Perform block read from each file frame
while(dwFilePointer < dwEndPointer)
{
- LPBYTE pbRawData = NULL;
+ LPBYTE pbFrameData = NULL;
DWORD dwFrameStart = pFrame->FrameFileOffset;
DWORD dwFrameEnd = pFrame->FrameFileOffset + pFrame->FrameSize;
@@ -457,8 +536,8 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW
}
// We also need to allocate buffer for the raw data
- pbRawData = CASC_ALLOC(BYTE, pFrame->CompressedSize);
- if(pbRawData == NULL)
+ pbFrameData = CASC_ALLOC(BYTE, pFrame->CompressedSize);
+ if(pbFrameData == NULL)
{
nError = ERROR_NOT_ENOUGH_MEMORY;
break;
@@ -466,7 +545,7 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW
// Load the raw file data to memory
FileOffset = pFrame->FrameArchiveOffset;
- bReadResult = FileStream_Read(hf->pStream, &FileOffset, pbRawData, pFrame->CompressedSize);
+ bReadResult = FileStream_Read(hf->pStream, &FileOffset, pbFrameData, pFrame->CompressedSize);
// Note: The raw file data size could be less than expected
// Happened in WoW build 19342 with the ROOT file. MD5 in the frame header
@@ -484,43 +563,34 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW
// If the frame offset is before EOF and frame end is beyond EOF, correct it
if(FileOffset < StreamSize && dwFrameSize < pFrame->CompressedSize)
{
- memset(pbRawData + dwFrameSize, 0, (pFrame->CompressedSize - dwFrameSize));
+ memset(pbFrameData + dwFrameSize, 0, (pFrame->CompressedSize - dwFrameSize));
bReadResult = true;
}
}
// If the read result failed, we cannot finish reading it
- if(bReadResult == false)
- {
- CASC_FREE(pbRawData);
- nError = GetLastError();
- break;
- }
-
- // Verify the block MD5
- if(!VerifyDataBlockHash(pbRawData, pFrame->CompressedSize, pFrame->md5))
+ if(bReadResult && VerifyDataBlockHash(pbFrameData, pFrame->CompressedSize, pFrame->md5))
{
- CASC_FREE(pbRawData);
- nError = ERROR_FILE_CORRUPT;
- break;
+ // Convert the source frame to the file cache
+ nError = ProcessFileFrame(hf->pbFileCache,
+ pFrame->FrameSize,
+ pbFrameData,
+ pFrame->CompressedSize,
+ (DWORD)(pFrame - hf->pFrames));
+ if(nError == ERROR_SUCCESS)
+ {
+ // Set the start and end of the cache
+ hf->CacheStart = dwFrameStart;
+ hf->CacheEnd = dwFrameEnd;
+ }
}
-
- // Decompress the file frame
- cbOutBuffer = pFrame->FrameSize;
- nError = CascDecompress(hf->pbFileCache, &cbOutBuffer, pbRawData, pFrame->CompressedSize);
- if(nError != ERROR_SUCCESS || cbOutBuffer != pFrame->FrameSize)
+ else
{
- CASC_FREE(pbRawData);
nError = ERROR_FILE_CORRUPT;
- break;
}
- // Set the start and end of the cache
- hf->CacheStart = dwFrameStart;
- hf->CacheEnd = dwFrameEnd;
-
- // Free the decompress buffer, if needed
- CASC_FREE(pbRawData);
+ // Free the raw frame data
+ CASC_FREE(pbFrameData);
}
// Copy the decompressed data