// Copyright 2016 Dolphin Emulator Project // Licensed under GPLv2+ // Refer to the license.txt file included. #include #include #include #include #include #include #include #include #include #include #include "DiscIO/Blob.h" #include "DiscIO/Enums.h" #include "DolphinQt2/Config/InfoWidget.h" InfoWidget::InfoWidget(const GameFile& game) : m_game(game) { QVBoxLayout* layout = new QVBoxLayout(); layout->addWidget(CreateISODetails()); layout->addWidget(CreateBannerDetails()); setLayout(layout); } QGroupBox* InfoWidget::CreateISODetails() { QGroupBox* group = new QGroupBox(tr("ISO Details")); QFormLayout* layout = new QFormLayout; QLineEdit* file_path = CreateValueDisplay(m_game.GetFilePath()); QLineEdit* internal_name = CreateValueDisplay(m_game.GetInternalName()); QLineEdit* game_id = CreateValueDisplay(m_game.GetGameID()); QLineEdit* country = CreateValueDisplay(m_game.GetCountry()); QLineEdit* maker = CreateValueDisplay(m_game.GetMaker()); QLineEdit* maker_id = CreateValueDisplay(QStringLiteral("0x") + m_game.GetMakerID()); QLineEdit* disc_number = CreateValueDisplay(QString::number(m_game.GetDiscNumber())); QLineEdit* revision = CreateValueDisplay(QString::number(m_game.GetRevision())); QLineEdit* apploader_date = CreateValueDisplay(m_game.GetApploaderDate()); QLineEdit* iso_size = CreateValueDisplay(FormatSize(m_game.GetFileSize())); QWidget* checksum = CreateChecksumComputer(); layout->addRow(tr("File Path:"), file_path); layout->addRow(tr("Internal Name:"), internal_name); layout->addRow(tr("Game ID:"), game_id); layout->addRow(tr("Country:"), country); layout->addRow(tr("Maker:"), maker); layout->addRow(tr("Maker ID:"), maker_id); layout->addRow(tr("Disc Number:"), disc_number); layout->addRow(tr("Revision:"), revision); layout->addRow(tr("Apploader Date:"), apploader_date); layout->addRow(tr("ISO Size:"), iso_size); layout->addRow(tr("MD5 Checksum:"), checksum); group->setLayout(layout); return group; } QGroupBox* InfoWidget::CreateBannerDetails() { QGroupBox* group = new QGroupBox(tr("%1 Banner Details").arg(m_game.GetPlatform())); QFormLayout* layout = new QFormLayout; m_long_name = CreateValueDisplay(); m_short_name = CreateValueDisplay(); m_short_maker = CreateValueDisplay(); m_long_maker = CreateValueDisplay(); m_description = new QTextEdit(); m_description->setReadOnly(true); QWidget* banner = CreateBannerGraphic(); CreateLanguageSelector(); layout->addRow(tr("Show Language:"), m_language_selector); if (m_game.GetPlatformID() == DiscIO::Platform::GAMECUBE_DISC) { layout->addRow(tr("Short Name:"), m_short_name); layout->addRow(tr("Short Maker:"), m_short_maker); layout->addRow(tr("Long Name:"), m_long_name); layout->addRow(tr("Long Maker:"), m_long_maker); layout->addRow(tr("Description:"), m_description); } else if (DiscIO::IsWii(m_game.GetPlatformID())) { layout->addRow(tr("Name:"), m_long_name); } layout->addRow(tr("Banner:"), banner); group->setLayout(layout); return group; } QWidget* InfoWidget::CreateBannerGraphic() { QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(); QLabel* banner = new QLabel(); banner->setPixmap(m_game.GetBanner()); QPushButton* save = new QPushButton(tr("Save as...")); connect(save, &QPushButton::clicked, this, &InfoWidget::SaveBanner); layout->addWidget(banner); layout->addWidget(save); widget->setLayout(layout); return widget; } void InfoWidget::SaveBanner() { QString path = QFileDialog::getSaveFileName(this, tr("Select a File"), QDir::currentPath(), tr("PNG image file (*.png);; All Files (*)")); m_game.GetBanner().save(path, "PNG"); } QLineEdit* InfoWidget::CreateValueDisplay(const QString& value) { QLineEdit* value_display = new QLineEdit(value); value_display->setReadOnly(true); value_display->setCursorPosition(0); return value_display; } void InfoWidget::CreateLanguageSelector() { m_language_selector = new QComboBox(); QList languages = m_game.GetAvailableLanguages(); for (int i = 0; i < languages.count(); i++) { DiscIO::Language language = languages.at(i); m_language_selector->addItem(m_game.GetLanguage(language), static_cast(language)); } if (m_language_selector->count() == 1) m_language_selector->setDisabled(true); connect(m_language_selector, static_cast(&QComboBox::currentIndexChanged), this, &InfoWidget::ChangeLanguage); ChangeLanguage(); } void InfoWidget::ChangeLanguage() { DiscIO::Language language = static_cast(m_language_selector->currentData().toInt()); m_short_name->setText(m_game.GetShortName(language)); m_short_maker->setText(m_game.GetShortMaker(language)); m_long_name->setText(m_game.GetLongName(language)); m_long_maker->setText(m_game.GetLongMaker(language)); m_description->setText(m_game.GetDescription(language)); } QWidget* InfoWidget::CreateChecksumComputer() { QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(); layout->setContentsMargins(0, 0, 0, 0); m_checksum_result = new QLineEdit(); QPushButton* calculate = new QPushButton(tr("Compute")); connect(calculate, &QPushButton::clicked, this, &InfoWidget::ComputeChecksum); layout->addWidget(m_checksum_result); layout->addWidget(calculate); widget->setLayout(layout); return widget; } void InfoWidget::ComputeChecksum() { QCryptographicHash hash(QCryptographicHash::Md5); hash.reset(); std::unique_ptr file( DiscIO::CreateBlobReader(m_game.GetFilePath().toStdString())); std::vector file_data(8 * 1080 * 1080); // read 1MB at a time u64 game_size = file->GetDataSize(); u64 read_offset = 0; // a maximum of 1000 is used instead of game_size because otherwise 8GB games overflow the int // typed maximum parameter QProgressDialog* progress = new QProgressDialog(tr("Computing MD5 Checksum"), tr("Cancel"), 0, 1000, this); progress->setWindowTitle(tr("Computing MD5 Checksum")); progress->setMinimumDuration(500); progress->setWindowModality(Qt::WindowModal); while (read_offset < game_size) { progress->setValue(static_cast(read_offset) / static_cast(game_size) * 1000); if (progress->wasCanceled()) return; u64 read_size = std::min(file_data.size(), game_size - read_offset); file->Read(read_offset, read_size, file_data.data()); hash.addData(reinterpret_cast(file_data.data()), read_size); read_offset += read_size; } m_checksum_result->setText(QString::fromUtf8(hash.result().toHex())); Q_ASSERT(read_offset == game_size); progress->setValue(1000); }