aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/raw_pdb/src/PDB_IPIStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/raw_pdb/src/PDB_IPIStream.cpp')
-rw-r--r--thirdparty/raw_pdb/src/PDB_IPIStream.cpp140
1 files changed, 140 insertions, 0 deletions
diff --git a/thirdparty/raw_pdb/src/PDB_IPIStream.cpp b/thirdparty/raw_pdb/src/PDB_IPIStream.cpp
new file mode 100644
index 000000000..dfd21bc56
--- /dev/null
+++ b/thirdparty/raw_pdb/src/PDB_IPIStream.cpp
@@ -0,0 +1,140 @@
+// Copyright 2011-2022, Molecular Matters GmbH <[email protected]>
+// See LICENSE.txt for licensing details (2-clause BSD License: https://opensource.org/licenses/BSD-2-Clause)
+
+#include "PDB_PCH.h"
+#include "PDB_IPIStream.h"
+#include "PDB_RawFile.h"
+#include "PDB_Util.h"
+#include "PDB_DirectMSFStream.h"
+#include "PDB_InfoStream.h"
+#include "Foundation/PDB_Memory.h"
+
+namespace
+{
+ // the IPI stream always resides at index 4
+ static constexpr const uint32_t IPIStreamIndex = 4u;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------------------------
+PDB::IPIStream::IPIStream(void) PDB_NO_EXCEPT
+ : m_header()
+ , m_stream()
+ , m_records(nullptr)
+ , m_recordCount(0u)
+{
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------------------------
+PDB::IPIStream::IPIStream(IPIStream&& other) PDB_NO_EXCEPT
+ : m_header(PDB_MOVE(other.m_header))
+ , m_stream(PDB_MOVE(other.m_stream))
+ , m_records(PDB_MOVE(other.m_records))
+ , m_recordCount(PDB_MOVE(other.m_recordCount))
+{
+ other.m_records = nullptr;
+ other.m_recordCount = 0u;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------------------------
+PDB::IPIStream& PDB::IPIStream::operator=(IPIStream&& other) PDB_NO_EXCEPT
+{
+ if (this != &other)
+ {
+ PDB_DELETE_ARRAY(m_records);
+
+ m_header = PDB_MOVE(other.m_header);
+ m_stream = PDB_MOVE(other.m_stream);
+ m_records = PDB_MOVE(other.m_records);
+ m_recordCount = PDB_MOVE(other.m_recordCount);
+
+ other.m_records = nullptr;
+ other.m_recordCount = 0u;
+ }
+
+ return *this;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------------------------
+PDB::IPIStream::IPIStream(const RawFile& file, const IPI::StreamHeader& header) PDB_NO_EXCEPT
+ : m_header(header)
+ , m_stream(file.CreateMSFStream<CoalescedMSFStream>(IPIStreamIndex))
+ , m_records(nullptr)
+ , m_recordCount(GetLastTypeIndex() - GetFirstTypeIndex())
+{
+ // types in the IPI stream are accessed by their index from other streams.
+ // however, the index is not stored with types in the IPI stream directly, but has to be built while walking the stream.
+ // similarly, because types are variable-length records, there are no direct offsets to access individual types.
+ // we therefore walk the IPI stream once, and store pointers to the records for trivial O(N) array lookup by index later.
+ m_records = PDB_NEW_ARRAY(const CodeView::IPI::Record*, m_recordCount);
+
+ // ignore the stream's header
+ size_t offset = sizeof(IPI::StreamHeader);
+
+ // parse the CodeView records
+ uint32_t typeIndex = 0u;
+ while (offset < m_stream.GetSize())
+ {
+ // https://llvm.org/docs/PDB/CodeViewTypes.html
+ const CodeView::IPI::Record* record = m_stream.GetDataAtOffset<const CodeView::IPI::Record>(offset);
+ const uint32_t recordSize = GetCodeViewRecordSize(record);
+ m_records[typeIndex] = record;
+
+ // position the stream offset at the next record
+ offset += sizeof(CodeView::IPI::RecordHeader) + recordSize;
+
+ ++typeIndex;
+ }
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------------------------
+PDB::IPIStream::~IPIStream(void) PDB_NO_EXCEPT
+{
+ PDB_DELETE_ARRAY(m_records);
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------------------------
+PDB_NO_DISCARD PDB::ErrorCode PDB::HasValidIPIStream(const RawFile& file) PDB_NO_EXCEPT
+{
+ const PDB::InfoStream infoStream(file);
+ if (!infoStream.HasIPIStream())
+ {
+ return ErrorCode::InvalidStream;
+ }
+
+ DirectMSFStream stream = file.CreateMSFStream<DirectMSFStream>(IPIStreamIndex);
+ if (stream.GetSize() < sizeof(IPI::StreamHeader))
+ {
+ return ErrorCode::InvalidStream;
+ }
+
+ const IPI::StreamHeader header = stream.ReadAtOffset<IPI::StreamHeader>(0u);
+ if (header.version != IPI::StreamHeader::Version::V80)
+ {
+ return ErrorCode::UnknownVersion;
+ }
+
+ return ErrorCode::Success;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------------------------
+PDB_NO_DISCARD PDB::IPIStream PDB::CreateIPIStream(const RawFile& file) PDB_NO_EXCEPT
+{
+ DirectMSFStream stream = file.CreateMSFStream<DirectMSFStream>(IPIStreamIndex);
+
+ const IPI::StreamHeader header = stream.ReadAtOffset<IPI::StreamHeader>(0u);
+ return IPIStream { file, header };
+}