private unsafe byte[] ApplyBsd0Patch(ref PatchInfoHeader patchInfoHeader, ref PatchHeader patchHeader, uint patchLength, byte[] originalData)
{
byte[] patchData;
if (patchLength < patchHeader.PatchLength) patchData = UnpackRle(patchLength);
else
{
patchData = new byte[patchLength];
if (Read(patchData, 0, checked((int)patchLength)) != patchLength) throw new EndOfStreamException();
}
fixed (byte* patchDataPointer = patchData)
{
var bsdiffHeader = (PatchBsdiff40Header*)patchDataPointer;
if (!BitConverter.IsLittleEndian) CommonMethods.SwapBytes((ulong*)patchDataPointer, sizeof(PatchBsdiff40Header)/sizeof(ulong));
if (bsdiffHeader->Signature != 0x3034464649445342 /* 'BSDIFF40' */) throw new InvalidDataException(ErrorMessages.GetString("Bsd0PatchHeaderInvalidSignature"));
var controlBlock = (uint*)(patchDataPointer + sizeof(PatchBsdiff40Header));
var differenceBlock = (byte*)controlBlock + bsdiffHeader->ControlBlockLength;
var extraBlock = differenceBlock + bsdiffHeader->DifferenceBlockLength;
if (!BitConverter.IsLittleEndian) CommonMethods.SwapBytes(controlBlock, bsdiffHeader->ControlBlockLength/sizeof(uint));
var patchedBuffer = new byte[bsdiffHeader->PatchedFileSize];
uint o = 0;
uint n = 0;
try
{
while (n < patchedBuffer.Length)
{
uint differenceLength = *controlBlock++;
uint extraLength = *controlBlock++;
uint sourceOffset = *controlBlock++;
// Apply the difference patch (Patched Data = Original data + Difference data)
for (uint i = 0; i < differenceLength; i++, n++, o++)
{
patchedBuffer[n] = differenceBlock[i];
if (o < originalData.Length)
patchedBuffer[n] += originalData[o];
}
differenceBlock += differenceLength;
// Apply the extra data patch (New data)
for (int e = 0; e < extraLength; e++)
patchedBuffer[n++] = extraBlock[e];
extraBlock += extraLength;
unchecked
{
o += (sourceOffset & 0x80000000) != 0 ? (0x80000000 - sourceOffset) : sourceOffset;
}
}
}
catch (IndexOutOfRangeException ex)
{
throw new InvalidDataException(ErrorMessages.GetString("Bsd0PatchInvalidData"), ex);
}
return patchedBuffer;
}
}