mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-03-10 11:48:14 -07:00
Add a Verify tab to game properties
This commit is contained in:
@@ -140,6 +140,27 @@ public:
|
||||
|
||||
bool CreateTitleDirectories(u64 title_id, u16 group_id) const;
|
||||
|
||||
enum class VerifyContainerType
|
||||
{
|
||||
TMD,
|
||||
Ticket,
|
||||
Device,
|
||||
};
|
||||
enum class VerifyMode
|
||||
{
|
||||
// Whether or not new certificates should be added to the certificate store (/sys/cert.sys).
|
||||
DoNotUpdateCertStore,
|
||||
UpdateCertStore,
|
||||
};
|
||||
// On success, if issuer_handle is non-null, the IOSC object for the issuer will be written to it.
|
||||
// The caller is responsible for using IOSC_DeleteObject.
|
||||
ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode,
|
||||
const IOS::ES::SignedBlobReader& signed_blob,
|
||||
const std::vector<u8>& cert_chain, u32* issuer_handle = nullptr);
|
||||
ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode,
|
||||
const IOS::ES::CertReader& certificate,
|
||||
const std::vector<u8>& cert_chain, u32 certificate_iosc_handle);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
@@ -308,29 +329,9 @@ private:
|
||||
ReturnCode CheckStreamKeyPermissions(u32 uid, const u8* ticket_view,
|
||||
const IOS::ES::TMDReader& tmd) const;
|
||||
|
||||
enum class VerifyContainerType
|
||||
{
|
||||
TMD,
|
||||
Ticket,
|
||||
Device,
|
||||
};
|
||||
enum class VerifyMode
|
||||
{
|
||||
// Whether or not new certificates should be added to the certificate store (/sys/cert.sys).
|
||||
DoNotUpdateCertStore,
|
||||
UpdateCertStore,
|
||||
};
|
||||
bool IsIssuerCorrect(VerifyContainerType type, const IOS::ES::CertReader& issuer_cert) const;
|
||||
ReturnCode ReadCertStore(std::vector<u8>* buffer) const;
|
||||
ReturnCode WriteNewCertToStore(const IOS::ES::CertReader& cert);
|
||||
// On success, if issuer_handle is non-null, the IOSC object for the issuer will be written to it.
|
||||
// The caller is responsible for using IOSC_DeleteObject.
|
||||
ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode,
|
||||
const IOS::ES::SignedBlobReader& signed_blob,
|
||||
const std::vector<u8>& cert_chain, u32* issuer_handle = nullptr);
|
||||
ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode,
|
||||
const IOS::ES::CertReader& certificate,
|
||||
const std::vector<u8>& cert_chain, u32 certificate_iosc_handle);
|
||||
|
||||
// Start a title import.
|
||||
bool InitImport(const IOS::ES::TMDReader& tmd);
|
||||
|
||||
@@ -441,6 +441,11 @@ u64 TicketReader::GetTitleId() const
|
||||
return Common::swap64(m_bytes.data() + offsetof(Ticket, title_id));
|
||||
}
|
||||
|
||||
u8 TicketReader::GetCommonKeyIndex() const
|
||||
{
|
||||
return m_bytes[offsetof(Ticket, common_key_index)];
|
||||
}
|
||||
|
||||
std::array<u8, 16> TicketReader::GetTitleKey(const HLE::IOSC& iosc) const
|
||||
{
|
||||
u8 iv[16] = {};
|
||||
|
||||
@@ -240,6 +240,7 @@ public:
|
||||
|
||||
u32 GetDeviceId() const;
|
||||
u64 GetTitleId() const;
|
||||
u8 GetCommonKeyIndex() const;
|
||||
// Get the decrypted title key.
|
||||
std::array<u8, 16> GetTitleKey(const HLE::IOSC& iosc) const;
|
||||
// Same as the above version, but guesses the console type depending on the issuer
|
||||
|
||||
@@ -16,6 +16,7 @@ add_library(discio
|
||||
Volume.cpp
|
||||
VolumeFileBlobReader.cpp
|
||||
VolumeGC.cpp
|
||||
VolumeVerifier.cpp
|
||||
VolumeWad.cpp
|
||||
VolumeWii.cpp
|
||||
WiiSaveBanner.cpp
|
||||
|
||||
@@ -29,6 +29,11 @@ std::string NameForPartitionType(u32 partition_type, bool include_prefix)
|
||||
return "UPDATE";
|
||||
case PARTITION_CHANNEL:
|
||||
return "CHANNEL";
|
||||
case PARTITION_INSTALL:
|
||||
// wit doesn't recognize the name "INSTALL", so we can't use it when naming partition folders
|
||||
if (!include_prefix)
|
||||
return "INSTALL";
|
||||
// [[fallthrough]]
|
||||
default:
|
||||
const std::string type_as_game_id{static_cast<char>((partition_type >> 24) & 0xFF),
|
||||
static_cast<char>((partition_type >> 16) & 0xFF),
|
||||
|
||||
@@ -17,7 +17,8 @@ class Volume;
|
||||
|
||||
constexpr u32 PARTITION_DATA = 0;
|
||||
constexpr u32 PARTITION_UPDATE = 1;
|
||||
constexpr u32 PARTITION_CHANNEL = 2;
|
||||
constexpr u32 PARTITION_CHANNEL = 2; // Mario Kart Wii, Wii Fit, Wii Fit Plus, Rabbids Go Home
|
||||
constexpr u32 PARTITION_INSTALL = 3; // Dragon Quest X only
|
||||
|
||||
std::string NameForPartitionType(u32 partition_type, bool include_prefix);
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
<ClCompile Include="Volume.cpp" />
|
||||
<ClCompile Include="VolumeFileBlobReader.cpp" />
|
||||
<ClCompile Include="VolumeGC.cpp" />
|
||||
<ClCompile Include="VolumeVerifier.cpp" />
|
||||
<ClCompile Include="VolumeWad.cpp" />
|
||||
<ClCompile Include="VolumeWii.cpp" />
|
||||
<ClCompile Include="WbfsBlob.cpp" />
|
||||
@@ -75,6 +76,7 @@
|
||||
<ClInclude Include="Volume.h" />
|
||||
<ClInclude Include="VolumeFileBlobReader.h" />
|
||||
<ClInclude Include="VolumeGC.h" />
|
||||
<ClInclude Include="VolumeVerifier.h" />
|
||||
<ClInclude Include="VolumeWad.h" />
|
||||
<ClInclude Include="VolumeWii.h" />
|
||||
<ClInclude Include="WbfsBlob.h" />
|
||||
|
||||
@@ -84,6 +84,9 @@
|
||||
<ClCompile Include="WiiSaveBanner.cpp">
|
||||
<Filter>NAND</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VolumeVerifier.cpp">
|
||||
<Filter>Volume</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="DiscScrubber.h">
|
||||
@@ -149,6 +152,9 @@
|
||||
<ClInclude Include="WiiSaveBanner.h">
|
||||
<Filter>NAND</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VolumeVerifier.h">
|
||||
<Filter>Volume</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
|
||||
689
Source/Core/DiscIO/VolumeVerifier.cpp
Normal file
689
Source/Core/DiscIO/VolumeVerifier.cpp
Normal file
File diff suppressed because it is too large
Load Diff
94
Source/Core/DiscIO/VolumeVerifier.h
Normal file
94
Source/Core/DiscIO/VolumeVerifier.h
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "DiscIO/Volume.h"
|
||||
|
||||
// To be used as follows:
|
||||
//
|
||||
// VolumeVerifier verifier(volume);
|
||||
// verifier.Start();
|
||||
// while (verifier.GetBytesProcessed() != verifier.GetTotalBytes())
|
||||
// verifier.Process();
|
||||
// verifier.Finish();
|
||||
// auto result = verifier.GetResult();
|
||||
//
|
||||
// Start, Process and Finish may take some time to run.
|
||||
//
|
||||
// GetResult() can be called before the processing is finished, but the result will be incomplete.
|
||||
|
||||
namespace IOS::ES
|
||||
{
|
||||
class SignedBlobReader;
|
||||
}
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
class FileInfo;
|
||||
|
||||
class VolumeVerifier final
|
||||
{
|
||||
public:
|
||||
enum class Severity
|
||||
{
|
||||
None, // Only used internally
|
||||
Low,
|
||||
Medium,
|
||||
High,
|
||||
};
|
||||
|
||||
struct Problem
|
||||
{
|
||||
Severity severity;
|
||||
std::string text;
|
||||
};
|
||||
|
||||
struct Result
|
||||
{
|
||||
std::string summary_text;
|
||||
std::vector<Problem> problems;
|
||||
};
|
||||
|
||||
VolumeVerifier(const Volume& volume);
|
||||
void Start();
|
||||
void Process();
|
||||
u64 GetBytesProcessed() const;
|
||||
u64 GetTotalBytes() const;
|
||||
void Finish();
|
||||
const Result& GetResult() const;
|
||||
|
||||
private:
|
||||
void CheckPartitions();
|
||||
bool CheckPartition(const Partition& partition); // Returns false if partition should be ignored
|
||||
void CheckCorrectlySigned(const Partition& partition, const std::string& error_text);
|
||||
bool IsDebugSigned() const;
|
||||
bool ShouldHaveChannelPartition() const;
|
||||
bool ShouldHaveInstallPartition() const;
|
||||
bool ShouldHaveMasterpiecePartitions() const;
|
||||
bool ShouldBeDualLayer() const;
|
||||
void CheckDiscSize();
|
||||
u64 GetBiggestUsedOffset();
|
||||
u64 GetBiggestUsedOffset(const FileInfo& file_info) const;
|
||||
void CheckMisc();
|
||||
|
||||
void AddProblem(Severity severity, const std::string& text);
|
||||
|
||||
const Volume& m_volume;
|
||||
Result m_result;
|
||||
bool m_is_tgc;
|
||||
bool m_is_datel;
|
||||
bool m_is_not_retail;
|
||||
|
||||
bool m_started;
|
||||
bool m_done;
|
||||
u64 m_progress;
|
||||
u64 m_max_progress;
|
||||
};
|
||||
|
||||
} // namespace DiscIO
|
||||
@@ -78,6 +78,7 @@ add_executable(dolphin-emu
|
||||
Config/PatchesWidget.cpp
|
||||
Config/PropertiesDialog.cpp
|
||||
Config/SettingsWindow.cpp
|
||||
Config/VerifyWidget.cpp
|
||||
Debugger/BreakpointWidget.cpp
|
||||
Debugger/CodeViewWidget.cpp
|
||||
Debugger/CodeWidget.cpp
|
||||
|
||||
@@ -40,8 +40,8 @@ enum class EntryType
|
||||
};
|
||||
Q_DECLARE_METATYPE(EntryType);
|
||||
|
||||
FilesystemWidget::FilesystemWidget(const UICommon::GameFile& game)
|
||||
: m_game(game), m_volume(DiscIO::CreateVolumeFromFilename(game.GetFilePath()))
|
||||
FilesystemWidget::FilesystemWidget(std::shared_ptr<DiscIO::Volume> volume)
|
||||
: m_volume(std::move(volume))
|
||||
{
|
||||
CreateWidgets();
|
||||
ConnectWidgets();
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
#include <QIcon>
|
||||
#include <memory>
|
||||
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
class QStandardItem;
|
||||
class QStandardItemModel;
|
||||
class QTreeView;
|
||||
@@ -26,7 +24,7 @@ class FilesystemWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FilesystemWidget(const UICommon::GameFile& game);
|
||||
explicit FilesystemWidget(std::shared_ptr<DiscIO::Volume> volume);
|
||||
~FilesystemWidget() override;
|
||||
|
||||
private:
|
||||
@@ -52,8 +50,7 @@ private:
|
||||
QStandardItemModel* m_tree_model;
|
||||
QTreeView* m_tree_view;
|
||||
|
||||
UICommon::GameFile m_game;
|
||||
std::unique_ptr<DiscIO::Volume> m_volume;
|
||||
std::shared_ptr<DiscIO::Volume> m_volume;
|
||||
|
||||
QIcon m_folder_icon;
|
||||
QIcon m_file_icon;
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
#include <QTabWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "DiscIO/Enums.h"
|
||||
#include "DiscIO/Volume.h"
|
||||
|
||||
#include "DolphinQt/Config/ARCodeWidget.h"
|
||||
#include "DolphinQt/Config/FilesystemWidget.h"
|
||||
@@ -16,6 +19,7 @@
|
||||
#include "DolphinQt/Config/InfoWidget.h"
|
||||
#include "DolphinQt/Config/PatchesWidget.h"
|
||||
#include "DolphinQt/Config/PropertiesDialog.h"
|
||||
#include "DolphinQt/Config/VerifyWidget.h"
|
||||
#include "DolphinQt/QtUtils/WrapInScrollArea.h"
|
||||
|
||||
#include "UICommon/GameFile.h"
|
||||
@@ -54,11 +58,22 @@ PropertiesDialog::PropertiesDialog(QWidget* parent, const UICommon::GameFile& ga
|
||||
tr("Gecko Codes"));
|
||||
tab_widget->addTab(GetWrappedWidget(info, this, padding_width, padding_height), tr("Info"));
|
||||
|
||||
if (DiscIO::IsDisc(game.GetPlatform()))
|
||||
if (game.GetPlatform() != DiscIO::Platform::ELFOrDOL)
|
||||
{
|
||||
FilesystemWidget* filesystem = new FilesystemWidget(game);
|
||||
tab_widget->addTab(GetWrappedWidget(filesystem, this, padding_width, padding_height),
|
||||
tr("Filesystem"));
|
||||
std::shared_ptr<DiscIO::Volume> volume = DiscIO::CreateVolumeFromFilename(game.GetFilePath());
|
||||
if (volume)
|
||||
{
|
||||
VerifyWidget* verify = new VerifyWidget(volume);
|
||||
tab_widget->addTab(GetWrappedWidget(verify, this, padding_width, padding_height),
|
||||
tr("Verify"));
|
||||
|
||||
if (DiscIO::IsDisc(game.GetPlatform()))
|
||||
{
|
||||
FilesystemWidget* filesystem = new FilesystemWidget(volume);
|
||||
tab_widget->addTab(GetWrappedWidget(filesystem, this, padding_width, padding_height),
|
||||
tr("Filesystem"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
layout->addWidget(tab_widget);
|
||||
|
||||
116
Source/Core/DolphinQt/Config/VerifyWidget.cpp
Normal file
116
Source/Core/DolphinQt/Config/VerifyWidget.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinQt/Config/VerifyWidget.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QProgressDialog>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "DiscIO/Volume.h"
|
||||
#include "DiscIO/VolumeVerifier.h"
|
||||
|
||||
VerifyWidget::VerifyWidget(std::shared_ptr<DiscIO::Volume> volume) : m_volume(std::move(volume))
|
||||
{
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
|
||||
CreateWidgets();
|
||||
ConnectWidgets();
|
||||
|
||||
layout->addWidget(m_problems);
|
||||
layout->addWidget(m_summary_text);
|
||||
layout->addWidget(m_verify_button);
|
||||
|
||||
layout->setStretchFactor(m_problems, 5);
|
||||
layout->setStretchFactor(m_summary_text, 2);
|
||||
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void VerifyWidget::CreateWidgets()
|
||||
{
|
||||
m_problems = new QTableWidget(0, 2, this);
|
||||
m_problems->setHorizontalHeaderLabels({tr("Problem"), tr("Severity")});
|
||||
m_problems->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
m_problems->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
|
||||
m_problems->horizontalHeader()->setHighlightSections(false);
|
||||
m_problems->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
m_problems->verticalHeader()->hide();
|
||||
|
||||
m_summary_text = new QTextEdit(this);
|
||||
m_summary_text->setReadOnly(true);
|
||||
|
||||
m_verify_button = new QPushButton(tr("Verify Integrity"), this);
|
||||
}
|
||||
|
||||
void VerifyWidget::ConnectWidgets()
|
||||
{
|
||||
connect(m_verify_button, &QPushButton::clicked, this, &VerifyWidget::Verify);
|
||||
}
|
||||
|
||||
void VerifyWidget::Verify()
|
||||
{
|
||||
DiscIO::VolumeVerifier verifier(*m_volume);
|
||||
|
||||
// We have to divide the number of processed bytes with something so it won't make ints overflow
|
||||
constexpr int DIVISOR = 0x100;
|
||||
|
||||
QProgressDialog* progress = new QProgressDialog(tr("Verifying"), tr("Cancel"), 0,
|
||||
verifier.GetTotalBytes() / DIVISOR, this);
|
||||
progress->setWindowTitle(tr("Verifying"));
|
||||
progress->setWindowFlags(progress->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
progress->setMinimumDuration(500);
|
||||
progress->setWindowModality(Qt::WindowModal);
|
||||
|
||||
verifier.Start();
|
||||
while (verifier.GetBytesProcessed() != verifier.GetTotalBytes())
|
||||
{
|
||||
progress->setValue(verifier.GetBytesProcessed() / DIVISOR);
|
||||
if (progress->wasCanceled())
|
||||
return;
|
||||
|
||||
verifier.Process();
|
||||
}
|
||||
verifier.Finish();
|
||||
|
||||
DiscIO::VolumeVerifier::Result result = verifier.GetResult();
|
||||
progress->setValue(verifier.GetBytesProcessed() / DIVISOR);
|
||||
|
||||
m_summary_text->setText(QString::fromStdString(result.summary_text));
|
||||
|
||||
m_problems->setRowCount(static_cast<int>(result.problems.size()));
|
||||
for (int i = 0; i < m_problems->rowCount(); ++i)
|
||||
{
|
||||
const DiscIO::VolumeVerifier::Problem problem = result.problems[i];
|
||||
|
||||
QString severity;
|
||||
switch (problem.severity)
|
||||
{
|
||||
case DiscIO::VolumeVerifier::Severity::Low:
|
||||
severity = tr("Low");
|
||||
break;
|
||||
case DiscIO::VolumeVerifier::Severity::Medium:
|
||||
severity = tr("Medium");
|
||||
break;
|
||||
case DiscIO::VolumeVerifier::Severity::High:
|
||||
severity = tr("High");
|
||||
break;
|
||||
}
|
||||
|
||||
SetProblemCellText(i, 0, QString::fromStdString(problem.text));
|
||||
SetProblemCellText(i, 1, severity);
|
||||
}
|
||||
}
|
||||
|
||||
void VerifyWidget::SetProblemCellText(int row, int column, QString text)
|
||||
{
|
||||
QLabel* label = new QLabel(text);
|
||||
label->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
label->setWordWrap(true);
|
||||
label->setMargin(4);
|
||||
m_problems->setCellWidget(row, column, label);
|
||||
}
|
||||
37
Source/Core/DolphinQt/Config/VerifyWidget.h
Normal file
37
Source/Core/DolphinQt/Config/VerifyWidget.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QTableWidget>
|
||||
#include <QTextEdit>
|
||||
#include <QWidget>
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
class Volume;
|
||||
}
|
||||
|
||||
class VerifyWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit VerifyWidget(std::shared_ptr<DiscIO::Volume> volume);
|
||||
|
||||
private:
|
||||
void CreateWidgets();
|
||||
void ConnectWidgets();
|
||||
|
||||
void Verify();
|
||||
void SetProblemCellText(int row, int column, QString text);
|
||||
|
||||
std::shared_ptr<DiscIO::Volume> m_volume;
|
||||
QTableWidget* m_problems;
|
||||
QTextEdit* m_summary_text;
|
||||
QPushButton* m_verify_button;
|
||||
};
|
||||
@@ -109,6 +109,7 @@
|
||||
<QtMoc Include="Config\PatchesWidget.h" />
|
||||
<QtMoc Include="Config\PropertiesDialog.h" />
|
||||
<QtMoc Include="Config\SettingsWindow.h" />
|
||||
<QtMoc Include="Config\VerifyWidget.h" />
|
||||
<QtMoc Include="DiscordHandler.h" />
|
||||
<QtMoc Include="DiscordJoinRequestDialog.h" />
|
||||
<QtMoc Include="FIFO\FIFOAnalyzer.h" />
|
||||
@@ -267,6 +268,7 @@
|
||||
<ClCompile Include="$(QtMocOutPrefix)ToolBar.cpp" />
|
||||
<ClCompile Include="$(QtMocOutPrefix)USBDeviceAddToWhitelistDialog.cpp" />
|
||||
<ClCompile Include="$(QtMocOutPrefix)Updater.cpp" />
|
||||
<ClCompile Include="$(QtMocOutPrefix)VerifyWidget.cpp" />
|
||||
<ClCompile Include="$(QtMocOutPrefix)WatchWidget.cpp" />
|
||||
<ClCompile Include="$(QtMocOutPrefix)WiiPane.cpp" />
|
||||
<ClCompile Include="$(QtMocOutPrefix)WiiTASInputWindow.cpp" />
|
||||
@@ -329,6 +331,7 @@
|
||||
<ClCompile Include="Config\PatchesWidget.cpp" />
|
||||
<ClCompile Include="Config\PropertiesDialog.cpp" />
|
||||
<ClCompile Include="Config\SettingsWindow.cpp" />
|
||||
<ClCompile Include="Config\VerifyWidget.cpp" />
|
||||
<ClCompile Include="Debugger\CodeViewWidget.cpp" />
|
||||
<ClCompile Include="Debugger\CodeWidget.cpp" />
|
||||
<ClCompile Include="Debugger\JITWidget.cpp" />
|
||||
|
||||
Reference in New Issue
Block a user