hlBool CDirectoryFile::Extract(const hlChar *lpPath) const { hlExtractItemStart(this); hlChar *lpName = new hlChar[strlen(this->GetName()) + 1]; strcpy(lpName, this->GetName()); RemoveIllegalCharacters(lpName); hlChar *lpFileName; if(lpPath == 0 || *lpPath == '\0') { lpFileName = new hlChar[strlen(lpName) + 1]; strcpy(lpFileName, lpName); } else { lpFileName = new hlChar[strlen(lpPath) + 1 + strlen(lpName) + 1]; strcpy(lpFileName, lpPath); strcat(lpFileName, PATH_SEPARATOR_STRING); strcat(lpFileName, lpName); } FixupIllegalCharacters(lpFileName); hlBool bResult; if(!bOverwriteFiles && GetFileExists(lpFileName)) { bResult = hlTrue; } else { bResult = hlFalse; Streams::IStream *pInput = 0; if(this->GetPackage()->CreateStream(this, pInput)) { if(pInput->Open(HL_MODE_READ)) { Streams::CFileStream Output = Streams::CFileStream(lpFileName); if(Output.Open(HL_MODE_WRITE | HL_MODE_CREATE)) { hlUInt uiTotalBytes = 0, uiFileBytes = this->GetSize(); hlByte lpBuffer[HL_DEFAULT_COPY_BUFFER_SIZE]; hlBool bCancel = hlFalse; hlExtractFileProgress(this, uiTotalBytes, uiFileBytes, &bCancel); while(hlTrue) { if(bCancel) { LastError.SetErrorMessage("Canceled by user."); } hlUInt uiBytes = pInput->Read(lpBuffer, sizeof(lpBuffer)); if(uiBytes == 0) { bResult = uiTotalBytes == pInput->GetStreamSize(); break; } if(Output.Write(lpBuffer, uiBytes) != uiBytes) { break; } uiTotalBytes += uiBytes; hlExtractFileProgress(this, uiTotalBytes, uiFileBytes, &bCancel); } Output.Close(); } pInput->Close(); } this->GetPackage()->ReleaseStream(pInput); } } delete []lpFileName; delete []lpName; hlExtractItemEnd(this, bResult); return bResult; }
hlBool CVPKFile::GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const { hlBool bExtractable = hlFalse; if(GetFileExtractableInternal(pFile, bExtractable)) { if(bExtractable) { Streams::IStream *pStream = 0; if(this->CreateStreamInternal(pFile, pStream)) { if(pStream->Open(HL_MODE_READ)) { hlULong uiChecksum = 0; eValidation = HL_VALIDATES_OK; hlULongLong uiTotalBytes = 0, uiFileBytes = pStream->GetStreamSize(); hlUInt uiBufferSize; hlByte lpBuffer[HL_VPK_CHECKSUM_LENGTH]; hlBool bCancel = hlFalse; hlValidateFileProgress(const_cast<CDirectoryFile *>(pFile), uiTotalBytes, uiFileBytes, &bCancel); while((uiBufferSize = pStream->Read(lpBuffer, HL_VPK_CHECKSUM_LENGTH)) != 0) { if(bCancel) { // User canceled. eValidation = HL_VALIDATES_CANCELED; break; } uiChecksum = CRC32(lpBuffer, uiBufferSize, uiChecksum); uiTotalBytes += static_cast<hlULongLong>(uiBufferSize); hlValidateFileProgress(const_cast<CDirectoryFile *>(pFile), uiTotalBytes, uiFileBytes, &bCancel); } if(!bCancel) { const VPKDirectoryItem *pDirectoryItem = static_cast<const VPKDirectoryItem *>(pFile->GetData()); if(pDirectoryItem->pDirectoryEntry->uiCRC != uiChecksum) { eValidation = HL_VALIDATES_CORRUPT; } } pStream->Close(); } else { eValidation = HL_VALIDATES_ERROR; } this->ReleaseStreamInternal(*pStream); delete pStream; } else { eValidation = HL_VALIDATES_ERROR; } } else { eValidation = HL_VALIDATES_INCOMPLETE; } } else { eValidation = HL_VALIDATES_ERROR; } return hlTrue; }
hlBool CGCFFile::GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const { // Do we have enough data to validate? { hlUInt uiSize = 0; // Get the first data block. hlUInt uiBlockEntryIndex = this->lpDirectoryMapEntries[pFile->GetID()].uiFirstBlockIndex; // Loop through each data block. while(uiBlockEntryIndex != this->pDataBlockHeader->uiBlockCount) { uiSize += this->lpBlockEntries[uiBlockEntryIndex].uiFileDataSize; // Get the next data block. uiBlockEntryIndex = this->lpBlockEntries[uiBlockEntryIndex].uiNextBlockEntryIndex; } if(uiSize != this->lpDirectoryEntries[pFile->GetID()].uiItemSize) { // File is incomplete. eValidation = HL_VALIDATES_INCOMPLETE; return hlTrue; } } if((this->lpDirectoryEntries[pFile->GetID()].uiDirectoryFlags & HL_GCF_FLAG_ENCRYPTED) != 0) { // No way of checking, assume it's ok. eValidation = HL_VALIDATES_ASSUMED_OK; return hlTrue; } // File has no checksum. if(this->lpDirectoryEntries[pFile->GetID()].uiChecksumIndex == 0xffffffff) { eValidation = HL_VALIDATES_ASSUMED_OK; return hlTrue; } Streams::IStream *pStream = 0; if(this->CreateStreamInternal(pFile, pStream)) { if(pStream->Open(HL_MODE_READ)) { eValidation = HL_VALIDATES_OK; hlULongLong uiTotalBytes = 0, uiFileBytes = pStream->GetStreamSize(); hlUInt uiBufferSize; hlByte lpBuffer[HL_GCF_CHECKSUM_LENGTH]; const GCFChecksumMapEntry *pChecksumMapEntry = this->lpChecksumMapEntries + this->lpDirectoryEntries[pFile->GetID()].uiChecksumIndex; hlBool bCancel = hlFalse; hlValidateFileProgress(const_cast<CDirectoryFile *>(pFile), uiTotalBytes, uiFileBytes, &bCancel); hlUInt i = 0; while((uiBufferSize = pStream->Read(lpBuffer, HL_GCF_CHECKSUM_LENGTH)) != 0) { if(bCancel) { // User canceled. eValidation = HL_VALIDATES_CANCELED; break; } if(i >= pChecksumMapEntry->uiChecksumCount) { // Something bad happened. eValidation = HL_VALIDATES_ERROR; break; } hlULong uiChecksum = Adler32(lpBuffer, uiBufferSize) ^ CRC32(lpBuffer, uiBufferSize); if(uiChecksum != this->lpChecksumEntries[pChecksumMapEntry->uiFirstChecksumIndex + i].uiChecksum) { eValidation = HL_VALIDATES_CORRUPT; break; } uiTotalBytes += static_cast<hlULongLong>(uiBufferSize); hlValidateFileProgress(const_cast<CDirectoryFile *>(pFile), uiTotalBytes, uiFileBytes, &bCancel); i++; } pStream->Close(); } else { eValidation = HL_VALIDATES_ERROR; } this->ReleaseStreamInternal(*pStream); delete pStream; } else { eValidation = HL_VALIDATES_ERROR; } return hlTrue; }