Files
archived-Reclass/third_party/raw_pdb/src/PDB_CoalescedMSFStream.cpp
IChooseYou 1d7d384b93 feat: PDB import via RawPDB, no msdia140.dll dependency
Replace DIA SDK COM-based PDB importer with RawPDB (MolecularMatters)
which reads PDB files directly via memory-mapped I/O. Adds File menu
"Import PDB..." dialog with type filtering, selection, and progress.

- Vendor raw_pdb into third_party/
- Two-phase API: enumeratePdbTypes() + importPdbSelected()
- Full recursive import of structs/unions/arrays/pointers/bitfields
- PDB import dialog with name filter, select-all, type count
- Benchmark: 1654 types from ntkrnlmp.pdb in 16ms
- Reorganize import/export files into src/imports/
2026-02-21 17:18:24 -07:00

170 lines
6.4 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_CRT.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);
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);
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 DirectMSFStream::IndexAndOffset indexAndOffset = directStream.GetBlockIndexForOffset(offset);
// Note: we need to add the offset within the block to the size of the stream to determine if the block
// indices are contiguous. This is needed to deal with the case where reading the requested number of bytes
// from the specified offset would cross a block boundary. For example, if the offset within the block is
// 64 and we want to read 4096 bytes with a block size of 4096, we need to consider *two* block indices,
// not *one*, even though 4096 / 4096 = 1.
if (AreBlockIndicesContiguous(directStream.GetBlockIndices() + indexAndOffset.index, directStream.GetBlockSize(), indexAndOffset.offsetWithinBlock + size))
{
// fast path, all block indices inside the direct stream from (data + offset) to (data + offset + size) are contiguous
const size_t offsetWithinData = directStream.GetDataOffsetForIndexAndOffset(indexAndOffset);
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);
}