mirror of
https://github.com/quizhizhe/LiteLoaderBDS-1.16.40.git
synced 2025-06-01 11:43:41 +00:00
167 lines
5.9 KiB
C++
167 lines
5.9 KiB
C++
// Copyright 2011-2022, Molecular Matters GmbH <office@molecular-matters.com>
|
|
// See LICENSE.txt for licensing details (2-clause BSD License: https://opensource.org/licenses/BSD-2-Clause)
|
|
|
|
#include "PDB_PCH.h"
|
|
#include "PDB_CoalescedMSFStream.h"
|
|
#include "PDB_Util.h"
|
|
#include "PDB_DirectMSFStream.h"
|
|
#include "Foundation/PDB_PointerUtil.h"
|
|
#include "Foundation/PDB_Memory.h"
|
|
#include "Foundation/PDB_DisableWarningsPush.h"
|
|
#include <cstring>
|
|
#include "Foundation/PDB_DisableWarningsPop.h"
|
|
|
|
|
|
namespace
|
|
{
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
PDB_NO_DISCARD static bool AreBlockIndicesContiguous(const uint32_t* blockIndices, uint32_t blockSize, uint32_t streamSize) PDB_NO_EXCEPT
|
|
{
|
|
const uint32_t blockCount = PDB::ConvertSizeToBlockCount(streamSize, blockSize);
|
|
|
|
// start with the first index, checking if all following indices are contiguous (N, N+1, N+2, ...)
|
|
uint32_t expectedIndex = blockIndices[0];
|
|
for (uint32_t i = 1u; i < blockCount; ++i)
|
|
{
|
|
++expectedIndex;
|
|
if (blockIndices[i] != expectedIndex)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
PDB::CoalescedMSFStream::CoalescedMSFStream(void) PDB_NO_EXCEPT
|
|
: m_ownedData(nullptr)
|
|
, m_data(nullptr)
|
|
, m_size(0u)
|
|
{
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
PDB::CoalescedMSFStream::CoalescedMSFStream(CoalescedMSFStream&& other) PDB_NO_EXCEPT
|
|
: m_ownedData(PDB_MOVE(other.m_ownedData))
|
|
, m_data(PDB_MOVE(other.m_data))
|
|
, m_size(PDB_MOVE(other.m_size))
|
|
{
|
|
other.m_ownedData = nullptr;
|
|
other.m_data = nullptr;
|
|
other.m_size = 0u;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
PDB::CoalescedMSFStream& PDB::CoalescedMSFStream::operator=(CoalescedMSFStream&& other) PDB_NO_EXCEPT
|
|
{
|
|
if (this != &other)
|
|
{
|
|
PDB_DELETE_ARRAY(m_ownedData);
|
|
|
|
m_ownedData = PDB_MOVE(other.m_ownedData);
|
|
m_data = PDB_MOVE(other.m_data);
|
|
m_size = PDB_MOVE(other.m_size);
|
|
|
|
other.m_ownedData = nullptr;
|
|
other.m_data = nullptr;
|
|
other.m_size = 0u;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
PDB::CoalescedMSFStream::CoalescedMSFStream(const void* data, uint32_t blockSize, const uint32_t* blockIndices, uint32_t streamSize) PDB_NO_EXCEPT
|
|
: m_ownedData(nullptr)
|
|
, m_data(nullptr)
|
|
, m_size(streamSize)
|
|
{
|
|
if (AreBlockIndicesContiguous(blockIndices, blockSize, streamSize))
|
|
{
|
|
// fast path, all block indices are contiguous, so we don't have to copy any data at all.
|
|
// instead, we directly point into the memory-mapped file at the correct offset.
|
|
const uint32_t index = blockIndices[0];
|
|
const size_t fileOffset = PDB::ConvertBlockIndexToFileOffset(index, blockSize);
|
|
m_data = Pointer::Offset<const Byte*>(data, fileOffset);
|
|
}
|
|
else
|
|
{
|
|
// slower path, we need to copy disjunct blocks into our own data array, block by block
|
|
m_ownedData = PDB_NEW_ARRAY(Byte, streamSize);
|
|
m_data = m_ownedData;
|
|
|
|
Byte* destination = m_ownedData;
|
|
|
|
// copy full blocks first
|
|
const uint32_t fullBlockCount = streamSize / blockSize;
|
|
for (uint32_t i = 0u; i < fullBlockCount; ++i)
|
|
{
|
|
const uint32_t index = blockIndices[i];
|
|
|
|
// read one single block at the correct offset in the stream
|
|
const size_t fileOffset = PDB::ConvertBlockIndexToFileOffset(index, blockSize);
|
|
const void* sourceData = Pointer::Offset<const void*>(data, fileOffset);
|
|
std::memcpy(destination, sourceData, blockSize);
|
|
|
|
destination += blockSize;
|
|
}
|
|
|
|
// account for non-full blocks
|
|
const uint32_t remainingBytes = streamSize - (fullBlockCount * blockSize);
|
|
if (remainingBytes != 0u)
|
|
{
|
|
const uint32_t index = blockIndices[fullBlockCount];
|
|
|
|
// read remaining bytes at correct offset in the stream
|
|
const size_t fileOffset = PDB::ConvertBlockIndexToFileOffset(index, blockSize);
|
|
const void* sourceData = Pointer::Offset<const void*>(data, fileOffset);
|
|
std::memcpy(destination, sourceData, remainingBytes);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
PDB::CoalescedMSFStream::CoalescedMSFStream(const DirectMSFStream& directStream, uint32_t size, uint32_t offset) PDB_NO_EXCEPT
|
|
: m_ownedData(nullptr)
|
|
, m_data(nullptr)
|
|
, m_size(size)
|
|
{
|
|
const uint32_t* const blockIndicesForOffset = directStream.GetBlockIndicesForOffset(offset);
|
|
|
|
if (AreBlockIndicesContiguous(blockIndicesForOffset, directStream.GetBlockSize(), size))
|
|
{
|
|
// fast path, all block indices inside the direct stream from (data + offset) to (data + offset + size) are contiguous
|
|
const size_t offsetWithinData = directStream.GetDataOffsetForOffset(offset);
|
|
m_data = Pointer::Offset<const Byte*>(directStream.GetData(), offsetWithinData);
|
|
}
|
|
else
|
|
{
|
|
// slower path, we need to copy from disjunct blocks, which is performed by the direct stream
|
|
m_ownedData = PDB_NEW_ARRAY(Byte, size);
|
|
m_data = m_ownedData;
|
|
|
|
directStream.ReadAtOffset(m_ownedData, size, offset);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
PDB::CoalescedMSFStream::~CoalescedMSFStream(void) PDB_NO_EXCEPT
|
|
{
|
|
PDB_DELETE_ARRAY(m_ownedData);
|
|
}
|