Seregon/ShadPKG

A tool for deriving PKG packet encryption keys for ps4 written in c++

C++/47.3 KB/No license
gui/views/RIFView.cpp
ShadPKG / gui / views / RIFView.cpp
1// SPDX-FileCopyrightText: Copyright 2025 shadPKG
2// SPDX-License-Identifier: GPL-2.0-or-later
3 
4#include "../include/views/RIFView.h"
5#include "../include/GuiLogSink.h"
6#include "../include/StyleManager.h"
7#include "core/file_format/rif_generator.h"
8#include <assert.h>
9#include "common/assert.h"
10#ifndef IM_ASSERT
11#define IM_ASSERT(_EXPR) ASSERT(_EXPR)
12#endif
13#include "imgui.h"
14#include <cstring>
15#include <filesystem>
16 
17#ifdef _WIN32
18#include <commdlg.h>
19#include <shlobj.h>
20#include <windows.h>
21#endif
22 
23namespace ShadPKG::GUI {
24 
25// ╔═══════════════════════════════════════════════════════════════════════════╗
26// ║ RIFView::Draw - Main render function ║
27// ╚═══════════════════════════════════════════════════════════════════════════╝
28void RIFView::Draw(GUIContext &ctx) {
29 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 10));
30 
31 DrawGenerateSection();
32 
33 ImGui::Spacing();
34 ImGui::Separator();
35 ImGui::Spacing();
36 
37 DrawValidateSection();
38 
39 ImGui::PopStyleVar();
40}
41 
42// ┌─────────────────────────────────────────────────────────────────────────┐
43// │ Generate RIF Section │
44// └─────────────────────────────────────────────────────────────────────────┘
45void RIFView::DrawGenerateSection() {
46 ImGui::TextColored(Colors::Primary, ICON_FA_KEY " GENERATE RIF");
47 ImGui::Spacing();
48 
49 ImGui::Text("Content ID:");
50 ImGui::SetNextItemWidth(-1);
51 ImGui::InputTextWithHint("##contentid",
52 "EP0001-CUSA12345_00-GAMENAME00000001",
53 contentIdBuf_, sizeof(contentIdBuf_));
54 
55 ImGui::Spacing();
56 
57 ImGui::Text("Output Directory:");
58 ImGui::SetNextItemWidth(-100);
59 ImGui::InputTextWithHint("##rifoutdir", "Output directory (default: current)",
60 outputDirBuf_, sizeof(outputDirBuf_));
61 ImGui::SameLine();
62 if (ImGui::Button("Browse##rifout", ImVec2(90, 0))) {
63 ShowSelectFolderDialog("Select Output Directory", outputDirBuf_,
64 sizeof(outputDirBuf_));
65 }
66 
67 ImGui::Spacing();
68 
69 // Validate Content ID format
70 bool validFormat = RIFGenerator::ValidateContentID(contentIdBuf_);
71 bool canGenerate = strlen(contentIdBuf_) > 0 && validFormat;
72 
73 if (strlen(contentIdBuf_) > 0 && !validFormat) {
74 ImGui::TextColored(
75 Colors::Warning, ICON_FA_TRIANGLE_EXCLAMATION
76 " Content ID format: XX0000-CUSA00000_00-XXXXXXXXXXXXXXXX");
77 }
78 
79 // Generate button
80 ImGui::PushStyleColor(ImGuiCol_Button,
81 canGenerate ? Colors::Primary : Colors::FrameBg);
82 ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
83 canGenerate ? Colors::PrimaryHover : Colors::FrameBg);
84 
85 if (!canGenerate) {
86 ImGui::PushStyleColor(ImGuiCol_Text, Colors::TextDim);
87 }
88 
89 if (ImGui::Button(ICON_FA_KEY " Generate RIF", ImVec2(150, 35))) {
90 if (canGenerate) {
91 GenerateRif();
92 }
93 }
94 
95 if (!canGenerate) {
96 ImGui::PopStyleColor();
97 }
98 ImGui::PopStyleColor(2);
99 
100 // Result display
101 if (generateSuccess_) {
102 ImGui::Spacing();
103 ImGui::TextColored(Colors::Success,
104 ICON_FA_CHECK " RIF generated successfully!");
105 ImGui::TextColored(Colors::TextDim, "Saved to: %s", generatedPath_.c_str());
106 } else if (generateFailed_) {
107 ImGui::Spacing();
108 ImGui::TextColored(Colors::Error, ICON_FA_XMARK " Failed to generate RIF");
109 }
110}
111 
112// ┌─────────────────────────────────────────────────────────────────────────┐
113// │ Validate RIF Section │
114// └─────────────────────────────────────────────────────────────────────────┘
115void RIFView::DrawValidateSection() {
116 ImGui::TextColored(Colors::Primary, ICON_FA_CHECK " VALIDATE RIF");
117 ImGui::Spacing();
118 
119 ImGui::Text("RIF File:");
120 ImGui::SetNextItemWidth(-100);
121 
122 bool pathValid =
123 strlen(rifPathBuf_) > 0 && std::filesystem::exists(rifPathBuf_);
124 if (strlen(rifPathBuf_) > 0) {
125 ImGui::PushStyleColor(ImGuiCol_Border,
126 pathValid ? Colors::Success : Colors::Error);
127 ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.5f);
128 }
129 
130 if (ImGui::InputTextWithHint("##rifvalidpath", "Path to RIF file...",
131 rifPathBuf_, sizeof(rifPathBuf_))) {
132 validated_ = false; // Reset on change
133 }
134 
135 if (strlen(rifPathBuf_) > 0) {
136 ImGui::PopStyleVar();
137 ImGui::PopStyleColor();
138 }
139 
140 ImGui::SameLine();
141 if (ImGui::Button("Browse##rifvalid", ImVec2(90, 0))) {
142 if (ShowOpenFileDialog("Select RIF File",
143 "RIF Files\0*.rif\0All Files\0*.*\0", rifPathBuf_,
144 sizeof(rifPathBuf_))) {
145 validated_ = false;
146 }
147 }
148 
149 ImGui::Spacing();
150 
151 // Validate button
152 bool canValidate = strlen(rifPathBuf_) > 0 && pathValid;
153 
154 ImGui::PushStyleColor(ImGuiCol_Button,
155 canValidate ? Colors::Primary : Colors::FrameBg);
156 ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
157 canValidate ? Colors::PrimaryHover : Colors::FrameBg);
158 
159 if (!canValidate) {
160 ImGui::PushStyleColor(ImGuiCol_Text, Colors::TextDim);
161 }
162 
163 if (ImGui::Button(ICON_FA_MAGNIFYING_GLASS " Validate", ImVec2(120, 35))) {
164 if (canValidate) {
165 ValidateRif();
166 }
167 }
168 
169 if (!canValidate) {
170 ImGui::PopStyleColor();
171 }
172 ImGui::PopStyleColor(2);
173 
174 // Result display
175 if (validated_) {
176 ImGui::Spacing();
177 if (rifValid_) {
178 ImGui::TextColored(Colors::Success, ICON_FA_CHECK " Valid RIF file");
179 if (!rifInfo_.empty()) {
180 ImGui::TextColored(Colors::TextDim, "%s", rifInfo_.c_str());
181 }
182 } else {
183 ImGui::TextColored(Colors::Error, ICON_FA_XMARK " Invalid RIF file");
184 }
185 }
186}
187 
188// ┌─────────────────────────────────────────────────────────────────────────┐
189// │ Actions │
190// └─────────────────────────────────────────────────────────────────────────┘
191void RIFView::GenerateRif() {
192 generateSuccess_ = false;
193 generateFailed_ = false;
194 
195 std::string contentId = contentIdBuf_;
196 std::filesystem::path outputDir =
197 strlen(outputDirBuf_) > 0 ? outputDirBuf_ : ".";
198 
199 RIFGenerator generator;
200 if (generator.GenerateRIF(contentId, outputDir)) {
201 generateSuccess_ = true;
202 generatedPath_ = (outputDir / (contentId + ".rif")).string();
203 GuiLogSink::Instance().Info("Generated RIF: " + generatedPath_);
204 } else {
205 generateFailed_ = true;
206 GuiLogSink::Instance().Error("Failed to generate RIF for: " + contentId);
207 }
208}
209 
210void RIFView::ValidateRif() {
211 validated_ = true;
212 std::filesystem::path rifPath(rifPathBuf_);
213 rifValid_ = RIFGenerator::ValidateRIF(rifPath);
214 
215 if (rifValid_) {
216 // Get file size info
217 auto size = std::filesystem::file_size(rifPath);
218 rifInfo_ = "Size: " + std::to_string(size) + " bytes";
219 GuiLogSink::Instance().Info("RIF validated: " + std::string(rifPathBuf_));
220 } else {
221 rifInfo_.clear();
222 GuiLogSink::Instance().Warn("Invalid RIF: " + std::string(rifPathBuf_));
223 }
224}
225 
226// ┌─────────────────────────────────────────────────────────────────────────┐
227// │ File Dialogs (Platform-specific) │
228// └─────────────────────────────────────────────────────────────────────────┘
229#ifdef _WIN32
230bool RIFView::ShowOpenFileDialog(const char *title, const char *filter,
231 char *outPath, size_t pathSize) {
232 OPENFILENAMEA ofn = {};
233 ofn.lStructSize = sizeof(ofn);
234 ofn.lpstrFilter = filter;
235 ofn.lpstrFile = outPath;
236 ofn.nMaxFile = static_cast<DWORD>(pathSize);
237 ofn.lpstrTitle = title;
238 ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
239 return GetOpenFileNameA(&ofn) != 0;
240}
241 
242bool RIFView::ShowSelectFolderDialog(const char *title, char *outPath,
243 size_t pathSize) {
244 BROWSEINFOA bi = {};
245 bi.lpszTitle = title;
246 bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
247 
248 LPITEMIDLIST pidl = SHBrowseForFolderA(&bi);
249 if (pidl) {
250 SHGetPathFromIDListA(pidl, outPath);
251 CoTaskMemFree(pidl);
252 return true;
253 }
254 return false;
255}
256#else
257bool RIFView::ShowOpenFileDialog(const char *title, const char *filter,
258 char *outPath, size_t pathSize) {
259 GuiLogSink::Instance().Warn(
260 "File dialog not yet implemented for this platform");
261 return false;
262}
263 
264bool RIFView::ShowSelectFolderDialog(const char *title, char *outPath,
265 size_t pathSize) {
266 GuiLogSink::Instance().Warn(
267 "Folder dialog not yet implemented for this platform");
268 return false;
269}
270#endif
271 
272} // namespace ShadPKG::GUI
273