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;
}
Example #2
0
hlBool CNCFFile::GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const
{
	if(this->lpRootPath != 0)
	{
		hlChar lpTemp[512];
		this->GetPath(pFile, lpTemp, sizeof(lpTemp));

		hlUInt uiSize;
		if(HLLib::GetFileSize(lpTemp, uiSize))
		{
			if(uiSize < this->lpDirectoryEntries[pFile->GetID()].uiItemSize)
			{
				eValidation = HL_VALIDATES_INCOMPLETE;
			}
			else if(this->lpDirectoryEntries[pFile->GetID()].uiDirectoryFlags & HL_NCF_FLAG_ENCRYPTED)
			{
				// No way of checking, assume it's ok.
				eValidation = HL_VALIDATES_ASSUMED_OK;
			}
			else if(this->lpDirectoryEntries[pFile->GetID()].uiChecksumIndex == 0xffffffff)
			{
				// File has no checksum.
				eValidation = HL_VALIDATES_ASSUMED_OK;
			}
			else
			{
				Streams::CFileStream Stream = Streams::CFileStream(lpTemp);

				if(Stream.Open(HL_MODE_READ))
				{
					eValidation = HL_VALIDATES_OK;

					hlULongLong uiTotalBytes = 0, uiFileBytes = Stream.GetStreamSize();
					hlUInt uiBufferSize;
					hlByte *lpBuffer = new hlByte[this->pDirectoryHeader->uiChecksumDataLength];

					const NCFChecksumMapEntry *pChecksumMapEntry = this->lpChecksumMapEntries + this->lpDirectoryEntries[pFile->GetID()].uiChecksumIndex;

					hlBool bCancel = hlFalse;
					hlValidateFileProgress(const_cast<CDirectoryFile *>(pFile), uiTotalBytes, uiFileBytes, &bCancel);

					hlUInt i = 0;
					while((uiBufferSize = Stream.Read(lpBuffer, this->pDirectoryHeader->uiChecksumDataLength)) != 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++;
					}

					delete []lpBuffer;

					Stream.Close();
				}
				else
				{
					eValidation = HL_VALIDATES_ERROR;
				}
			}
		}
		else
		{
			// Not found.
			if(this->lpDirectoryEntries[pFile->GetID()].uiItemSize != 0)
			{
				eValidation = HL_VALIDATES_INCOMPLETE;
			}
			else
			{
				eValidation = HL_VALIDATES_OK;
			}
		}
	}
	else
	{
		eValidation = HL_VALIDATES_ASSUMED_OK;
	}

	return hlTrue;
}