old_stuff removed
This commit is contained in:
parent
3141f3fa04
commit
699922f93e
Binary file not shown.
Before Width: | Height: | Size: 22 KiB |
|
@ -1,25 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.3.32929.385
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shadPS4", "shadPS4\shadPS4.vcxproj", "{F005E4D9-1FBE-40B3-9FBD-35CEC59081CD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F005E4D9-1FBE-40B3-9FBD-35CEC59081CD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F005E4D9-1FBE-40B3-9FBD-35CEC59081CD}.Debug|x64.Build.0 = Debug|x64
|
||||
{F005E4D9-1FBE-40B3-9FBD-35CEC59081CD}.Release|x64.ActiveCfg = Release|x64
|
||||
{F005E4D9-1FBE-40B3-9FBD-35CEC59081CD}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {82D83EC4-9F9E-4A77-9914-7A808ED5A3A7}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,46 +0,0 @@
|
|||
#pragma once
|
||||
#include <immintrin.h>
|
||||
|
||||
using S08 = char;
|
||||
using S16 = short;
|
||||
using S32 = int;
|
||||
using S64 = long long;
|
||||
|
||||
using U08 = unsigned char;
|
||||
using U16 = unsigned short;
|
||||
using U32 = unsigned int;
|
||||
using U64 = unsigned long long;
|
||||
|
||||
using F32 = float;
|
||||
using F64 = double;
|
||||
|
||||
|
||||
template< typename T > T inline LoadBE(T* src) { return *src; };
|
||||
template< typename T > inline void StoreBE(T* dst, T src) { *dst = src; };
|
||||
|
||||
inline S16 LoadBE(S16* src) { return _loadbe_i16(src); };
|
||||
inline S32 LoadBE(S32* src) { return _loadbe_i32(src); };
|
||||
inline S64 LoadBE(S64* src) { return _loadbe_i64(src); };
|
||||
|
||||
inline U16 LoadBE(U16* src) { return _load_be_u16(src); };
|
||||
inline U32 LoadBE(U32* src) { return _load_be_u32(src); };
|
||||
inline U64 LoadBE(U64* src) { return _load_be_u64(src); };
|
||||
|
||||
inline void StoreBE(S16* dst, S16 const src) { _storebe_i16(dst, src); };
|
||||
inline void StoreBE(S32* dst, S32 const src) { _storebe_i32(dst, src); };
|
||||
inline void StoreBE(S64* dst, S64 const src) { _storebe_i64(dst, src); };
|
||||
|
||||
inline void StoreBE(U16* dst, U16 const src) { _store_be_u16(dst, src); };
|
||||
inline void StoreBE(U32* dst, U32 const src) { _store_be_u32(dst, src); };
|
||||
inline void StoreBE(U64* dst, U64 const src) { _store_be_u64(dst, src); };
|
||||
|
||||
|
||||
template< typename T > inline void ReadBE(T& val)
|
||||
{
|
||||
val = LoadBE(&val); // swap inplace
|
||||
}
|
||||
|
||||
template< typename T > inline void WriteBE(T& val)
|
||||
{
|
||||
StoreBE(&val, val); // swap inplace
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
#include "FsFile.h"
|
||||
|
||||
FsFile::FsFile()
|
||||
{
|
||||
m_file = nullptr;
|
||||
}
|
||||
FsFile::FsFile(const std::string& path, fsOpenMode mode)
|
||||
{
|
||||
Open(path, mode);
|
||||
}
|
||||
bool FsFile::Open(const std::string& path, fsOpenMode mode)
|
||||
{
|
||||
Close();
|
||||
fopen_s(&m_file, path.c_str(), getOpenMode(mode));
|
||||
return IsOpen();
|
||||
}
|
||||
bool FsFile::Close()
|
||||
{
|
||||
if (!IsOpen() || std::fclose(m_file) != 0) {
|
||||
m_file = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_file = nullptr;
|
||||
return true;
|
||||
}
|
||||
FsFile::~FsFile()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
bool FsFile::Write(const void* src, U64 size)
|
||||
{
|
||||
if (!IsOpen() || std::fwrite(src, 1, size, m_file) != size) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FsFile::Read(void* dst, U64 size)
|
||||
{
|
||||
if (!IsOpen() || std::fread(dst, 1, size, m_file) != size) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
U32 FsFile::ReadBytes(void* dst, U64 size)
|
||||
{
|
||||
return std::fread(dst, 1, size, m_file);
|
||||
}
|
||||
|
||||
bool FsFile::Seek(S64 offset, fsSeekMode mode)
|
||||
{
|
||||
if (!IsOpen() || _fseeki64(m_file, offset, getSeekMode(mode)) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
U64 FsFile::Tell() const
|
||||
{
|
||||
if (IsOpen()) {
|
||||
return _ftelli64(m_file);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
U64 FsFile::getFileSize()
|
||||
{
|
||||
U64 pos = _ftelli64(m_file);
|
||||
if (_fseeki64(m_file, 0, SEEK_END) != 0) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U64 size = _ftelli64(m_file);
|
||||
if (_fseeki64(m_file, pos, SEEK_SET) != 0) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
bool FsFile::IsOpen() const
|
||||
{
|
||||
return m_file != nullptr;
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
#pragma once
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include "../Types.h"
|
||||
|
||||
enum fsOpenMode
|
||||
{
|
||||
fsRead = 0x1,
|
||||
fsWrite = 0x2,
|
||||
fsReadWrite = fsRead | fsWrite
|
||||
};
|
||||
|
||||
enum fsSeekMode
|
||||
{
|
||||
fsSeekSet,
|
||||
fsSeekCur,
|
||||
fsSeekEnd,
|
||||
};
|
||||
|
||||
class FsFile
|
||||
{
|
||||
std::FILE* m_file;
|
||||
public:
|
||||
FsFile();
|
||||
FsFile(const std::string& path, fsOpenMode mode = fsRead);
|
||||
bool Open(const std::string& path, fsOpenMode mode = fsRead);
|
||||
bool IsOpen() const;
|
||||
bool Close();
|
||||
bool Read(void* dst, U64 size);
|
||||
U32 ReadBytes(void* dst, U64 size);
|
||||
bool Write(const void* src, U64 size);
|
||||
bool Seek(S64 offset, fsSeekMode mode);
|
||||
U64 getFileSize();
|
||||
U64 Tell() const;
|
||||
~FsFile();
|
||||
|
||||
template< typename T > bool ReadBE(T& dst)
|
||||
{
|
||||
if (!Read(&dst, sizeof(T))) {
|
||||
return false;
|
||||
}
|
||||
::ReadBE(dst);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* getOpenMode(fsOpenMode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case fsRead: return "rb";
|
||||
case fsWrite: return "wb";
|
||||
case fsReadWrite: return "r+b";
|
||||
}
|
||||
|
||||
return "r";
|
||||
}
|
||||
|
||||
const int getSeekMode(fsSeekMode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case fsSeekSet: return SEEK_SET;
|
||||
case fsSeekCur: return SEEK_CUR;
|
||||
case fsSeekEnd: return SEEK_END;
|
||||
}
|
||||
|
||||
return SEEK_SET;
|
||||
}
|
||||
std::FILE* fileDescr()
|
||||
{
|
||||
return m_file;
|
||||
}
|
||||
};
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#include "Loader.h"
|
||||
#include "../core/FsFile.h"
|
||||
|
||||
FileTypes detectFileType(const std::string& filepath)
|
||||
{
|
||||
if (filepath.size() == 0)//no file loaded
|
||||
{
|
||||
return FILETYPE_UNKNOWN;
|
||||
}
|
||||
FsFile file;
|
||||
file.Open(filepath, fsRead);
|
||||
file.Seek(0, fsSeekSet);
|
||||
U32 magic;
|
||||
file.Read(&magic, sizeof(magic));
|
||||
file.Close();
|
||||
ReadBE(magic);//magic is BE make it LE
|
||||
switch (magic)
|
||||
{
|
||||
case 0x7F434E54://PS4 PKG
|
||||
return FILETYPE_PKG;
|
||||
}
|
||||
return FILETYPE_UNKNOWN;
|
||||
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
enum FileTypes
|
||||
{
|
||||
FILETYPE_UNKNOWN,
|
||||
FILETYPE_PKG
|
||||
};
|
||||
FileTypes detectFileType(const std::string& filepath);
|
|
@ -1,104 +0,0 @@
|
|||
#include "PKG.h"
|
||||
#include "../../core/FsFile.h"
|
||||
#include <direct.h>
|
||||
#include <QString>
|
||||
#include <QDir>
|
||||
|
||||
PKG::PKG()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PKG::~PKG()
|
||||
{
|
||||
}
|
||||
|
||||
bool PKG::open(const std::string& filepath) {
|
||||
FsFile file;
|
||||
if (!file.Open(filepath, fsRead))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
pkgSize = file.getFileSize();
|
||||
PKGHeader pkgheader;
|
||||
file.ReadBE(pkgheader);
|
||||
//we have already checked magic should be ok
|
||||
|
||||
//find title id it is part of pkg_content_id starting at offset 0x40
|
||||
file.Seek(0x47, fsSeekSet);//skip first 7 characters of content_id
|
||||
file.Read(&pkgTitleID, sizeof(pkgTitleID));
|
||||
|
||||
file.Close();
|
||||
|
||||
return true;
|
||||
}
|
||||
bool PKG::extract(const std::string& filepath, const std::string& extractPath, std::string& failreason)
|
||||
{
|
||||
this->extractPath = extractPath;
|
||||
FsFile file;
|
||||
if (!file.Open(filepath, fsRead))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
pkgSize = file.getFileSize();
|
||||
PKGHeader pkgheader;
|
||||
file.ReadBE(pkgheader);
|
||||
|
||||
if (pkgheader.pkg_size > pkgSize)
|
||||
{
|
||||
failreason = "PKG file size is different";
|
||||
return false;
|
||||
}
|
||||
if ((pkgheader.pkg_content_size + pkgheader.pkg_content_offset) > pkgheader.pkg_size)
|
||||
{
|
||||
failreason = "Content size is bigger than pkg size";
|
||||
return false;
|
||||
}
|
||||
file.Seek(0, fsSeekSet);
|
||||
pkg = (U08*)mmap(pkgSize, file.fileDescr());
|
||||
if (pkg == nullptr)
|
||||
{
|
||||
failreason = "Can't allocate size for image";
|
||||
return false;
|
||||
}
|
||||
|
||||
file.Read(pkg, pkgSize);
|
||||
|
||||
U32 offset = pkgheader.pkg_table_entry_offset;
|
||||
U32 n_files = pkgheader.pkg_table_entry_count;
|
||||
|
||||
|
||||
for (int i = 0; i < n_files; i++) {
|
||||
PKGEntry entry = (PKGEntry&)pkg[offset + i * 0x20];
|
||||
ReadBE(entry);
|
||||
//try to figure out the name
|
||||
std::string name = getEntryNameByType(entry.id);
|
||||
if (!name.empty())
|
||||
{
|
||||
QString filepath= QString::fromStdString(extractPath+ "/sce_sys/" + name);
|
||||
QDir dir = QFileInfo(filepath).dir();
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(dir.path());
|
||||
}
|
||||
FsFile out;
|
||||
out.Open(extractPath + "/sce_sys/" + name, fsWrite);
|
||||
out.Write(pkg + entry.offset, entry.size);
|
||||
out.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
//just print with id
|
||||
FsFile out;
|
||||
out.Open(extractPath + "/sce_sys/" + std::to_string(entry.id), fsWrite);
|
||||
out.Write(pkg + entry.offset, entry.size);
|
||||
out.Close();
|
||||
}
|
||||
}
|
||||
//extract pfs_image.dat
|
||||
FsFile out;
|
||||
out.Open(extractPath + "pfs_image.dat", fsWrite);
|
||||
out.Write(pkg + pkgheader.pfs_image_offset, pkgheader.pfs_image_size);
|
||||
out.Close();
|
||||
munmap(pkg);
|
||||
return true;
|
||||
}
|
|
@ -1,784 +0,0 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include "../../Types.h"
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct PKGHeader {
|
||||
/*BE*/U32 magic;// Magic
|
||||
/*BE*/U32 pkg_type;
|
||||
/*BE*/U32 pkg_0x8; //unknown field
|
||||
/*BE*/U32 pkg_file_count;
|
||||
/*BE*/U32 pkg_table_entry_count;
|
||||
/*BE*/U16 pkg_sc_entry_count;
|
||||
/*BE*/U16 pkg_table_entry_count_2;// same as pkg_entry_count
|
||||
/*BE*/U32 pkg_table_entry_offset;//file table offset
|
||||
/*BE*/U32 pkg_sc_entry_data_size;
|
||||
/*BE*/U64 pkg_body_offset;//offset of PKG entries
|
||||
/*BE*/U64 pkg_body_size;//length of all PKG entries
|
||||
/*BE*/U64 pkg_content_offset;
|
||||
/*BE*/U64 pkg_content_size;
|
||||
U08 pkg_content_id[0x24];//packages' content ID as a 36-byte string
|
||||
U08 pkg_padding[0xC];//padding
|
||||
/*BE*/U32 pkg_drm_type;//DRM type
|
||||
/*BE*/U32 pkg_content_type;//Content type
|
||||
/*BE*/U32 pkg_content_flags;//Content flags
|
||||
/*BE*/U32 pkg_promote_size;
|
||||
/*BE*/U32 pkg_version_date;
|
||||
/*BE*/U32 pkg_version_hash;
|
||||
/*BE*/U32 pkg_0x088;
|
||||
/*BE*/U32 pkg_0x08C;
|
||||
/*BE*/U32 pkg_0x090;
|
||||
/*BE*/U32 pkg_0x094;
|
||||
/*BE*/U32 pkg_iro_tag;
|
||||
/*BE*/U32 pkg_drm_type_version;
|
||||
|
||||
U08 pkg_zeroes_1[0x60];
|
||||
|
||||
/* Digest table */
|
||||
U08 digest_entries1[0x20]; // sha256 digest for main entry 1
|
||||
U08 digest_entries2[0x20]; // sha256 digest for main entry 2
|
||||
U08 digest_table_digest[0x20]; // sha256 digest for digest table
|
||||
U08 digest_body_digest[0x20]; // sha256 digest for main table
|
||||
|
||||
U08 pkg_zeroes_2[0x280];
|
||||
|
||||
U32 pkg_0x400;
|
||||
|
||||
U32 pfs_image_count; // count of PFS images
|
||||
U64 pfs_image_flags; // PFS flags
|
||||
U64 pfs_image_offset; // offset to start of external PFS image
|
||||
U64 pfs_image_size; // size of external PFS image
|
||||
U64 mount_image_offset;
|
||||
U64 mount_image_size;
|
||||
U64 pkg_size;
|
||||
U32 pfs_signed_size;
|
||||
U32 pfs_cache_size;
|
||||
U08 pfs_image_digest[0x20];
|
||||
U08 pfs_signed_digest[0x20];
|
||||
U64 pfs_split_size_nth_0;
|
||||
U64 pfs_split_size_nth_1;
|
||||
|
||||
U08 pkg_zeroes_3[0xB50];
|
||||
|
||||
U08 pkg_digest[0x20];
|
||||
|
||||
};
|
||||
|
||||
inline void ReadBE(PKGHeader& s)
|
||||
{
|
||||
ReadBE(s.magic);
|
||||
ReadBE(s.pkg_table_entry_offset);
|
||||
ReadBE(s.pkg_table_entry_count);
|
||||
ReadBE(s.pkg_content_offset);
|
||||
ReadBE(s.pkg_content_size);
|
||||
ReadBE(s.pfs_image_offset);
|
||||
ReadBE(s.pfs_image_size);
|
||||
ReadBE(s.pkg_size);
|
||||
}
|
||||
|
||||
struct PKGEntry {
|
||||
U32 id; // File ID, useful for files without a filename entry
|
||||
U32 filename_offset; // Offset into the filenames table (ID 0x200) where this file's name is located
|
||||
U32 flags1; // Flags including encrypted flag, etc
|
||||
U32 flags2; // Flags including encryption key index, etc
|
||||
U32 offset; // Offset into PKG to find the file
|
||||
U32 size; // Size of the file
|
||||
U64 padding; // blank padding
|
||||
};
|
||||
|
||||
inline void ReadBE(PKGEntry& s)
|
||||
{
|
||||
ReadBE(s.id);
|
||||
ReadBE(s.filename_offset);
|
||||
ReadBE(s.flags1);
|
||||
ReadBE(s.flags2);
|
||||
ReadBE(s.offset);
|
||||
ReadBE(s.size);
|
||||
ReadBE(s.padding);
|
||||
}
|
||||
|
||||
class PKG
|
||||
{
|
||||
private:
|
||||
U08* pkg;
|
||||
U64 pkgSize = 0;
|
||||
S08 pkgTitleID[9];
|
||||
std::string extractPath;
|
||||
|
||||
public:
|
||||
PKG();
|
||||
~PKG();
|
||||
bool open(const std::string& filepath);
|
||||
U64 getPkgSize()
|
||||
{
|
||||
return pkgSize;
|
||||
}
|
||||
std::string getTitleID()
|
||||
{
|
||||
return std::string(pkgTitleID,9);
|
||||
}
|
||||
bool extract(const std::string& filepath, const std::string& extractPath, std::string& failreason);
|
||||
|
||||
void* mmap(size_t sLength, std::FILE* nFd) {
|
||||
HANDLE hHandle;
|
||||
void* pStart;
|
||||
hHandle = CreateFileMapping(
|
||||
(HANDLE)_get_osfhandle(_fileno((nFd))),
|
||||
NULL, // default security
|
||||
PAGE_WRITECOPY, // read/write access
|
||||
0, // maximum object size (high-order DWORD)
|
||||
0, // maximum object size (low-order DWORD)
|
||||
NULL); // name of mapping object
|
||||
|
||||
if (hHandle != NULL) {
|
||||
pStart = MapViewOfFile(hHandle, FILE_MAP_COPY, 0, 0, sLength);
|
||||
}
|
||||
if(pStart == NULL)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return pStart;
|
||||
}
|
||||
int munmap(void* pStart) {
|
||||
if (UnmapViewOfFile(pStart) != 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
typedef struct {
|
||||
U32 type;
|
||||
std::string name;
|
||||
} pkg_entry_value;
|
||||
|
||||
std::string getEntryNameByType(U32 type)
|
||||
{
|
||||
pkg_entry_value entries[] = {
|
||||
{ 0x0001, "digests" },
|
||||
{ 0x0010, "entry_keys" },
|
||||
{ 0x0020, "image_key" },
|
||||
{ 0x0080, "general_digests" },
|
||||
{ 0x0100, "metas" },
|
||||
{ 0x0200, "entry_names" },
|
||||
{ 0x0400, "license.dat" },
|
||||
{ 0x0401, "license.info" },
|
||||
{ 0x0402, "nptitle.dat" },
|
||||
{ 0x0403, "npbind.dat" },
|
||||
{ 0x0404, "selfinfo.dat" },
|
||||
{ 0x0406, "imageinfo.dat" },
|
||||
{ 0x0407, "target-deltainfo.dat" },
|
||||
{ 0x0408, "origin-deltainfo.dat" },
|
||||
{ 0x0409, "psreserved.dat" },
|
||||
{ 0x1000, "param.sfo" },
|
||||
{ 0x1001, "playgo-chunk.dat" },
|
||||
{ 0x1002, "playgo-chunk.sha" },
|
||||
{ 0x1003, "playgo-manifest.xml" },
|
||||
{ 0x1004, "pronunciation.xml" },
|
||||
{ 0x1005, "pronunciation.sig" },
|
||||
{ 0x1006, "pic1.png" },
|
||||
{ 0x1007, "pubtoolinfo.dat" },
|
||||
{ 0x1008, "app/playgo-chunk.dat" },
|
||||
{ 0x1009, "app/playgo-chunk.sha" },
|
||||
{ 0x100A, "app/playgo-manifest.xml" },
|
||||
{ 0x100B, "shareparam.json" },
|
||||
{ 0x100C, "shareoverlayimage.png" },
|
||||
{ 0x100D, "save_data.png" },
|
||||
{ 0x100E, "shareprivacyguardimage.png"},
|
||||
{ 0x1200, "icon0.png" },
|
||||
{ 0x1201, "icon0_00.png" },
|
||||
{ 0x1202, "icon0_01.png" },
|
||||
{ 0x1203, "icon0_02.png" },
|
||||
{ 0x1204, "icon0_03.png" },
|
||||
{ 0x1205, "icon0_04.png" },
|
||||
{ 0x1206, "icon0_05.png" },
|
||||
{ 0x1207, "icon0_06.png" },
|
||||
{ 0x1208, "icon0_07.png" },
|
||||
{ 0x1209, "icon0_08.png" },
|
||||
{ 0x120A, "icon0_09.png" },
|
||||
{ 0x120B, "icon0_10.png" },
|
||||
{ 0x120C, "icon0_11.png" },
|
||||
{ 0x120D, "icon0_12.png" },
|
||||
{ 0x120E, "icon0_13.png" },
|
||||
{ 0x120F, "icon0_14.png" },
|
||||
{ 0x1210, "icon0_15.png" },
|
||||
{ 0x1211, "icon0_16.png" },
|
||||
{ 0x1212, "icon0_17.png" },
|
||||
{ 0x1213, "icon0_18.png" },
|
||||
{ 0x1214, "icon0_19.png" },
|
||||
{ 0x1215, "icon0_20.png" },
|
||||
{ 0x1216, "icon0_21.png" },
|
||||
{ 0x1217, "icon0_22.png" },
|
||||
{ 0x1218, "icon0_23.png" },
|
||||
{ 0x1219, "icon0_24.png" },
|
||||
{ 0x121A, "icon0_25.png" },
|
||||
{ 0x121B, "icon0_26.png" },
|
||||
{ 0x121C, "icon0_27.png" },
|
||||
{ 0x121D, "icon0_28.png" },
|
||||
{ 0x121E, "icon0_29.png" },
|
||||
{ 0x121F, "icon0_30.png" },
|
||||
{ 0x1220, "pic0.png" },
|
||||
{ 0x1240, "snd0.at9" },
|
||||
{ 0x1241, "pic1_00.png" },
|
||||
{ 0x1242, "pic1_01.png" },
|
||||
{ 0x1243, "pic1_02.png" },
|
||||
{ 0x1244, "pic1_03.png" },
|
||||
{ 0x1245, "pic1_04.png" },
|
||||
{ 0x1246, "pic1_05.png" },
|
||||
{ 0x1247, "pic1_06.png" },
|
||||
{ 0x1248, "pic1_07.png" },
|
||||
{ 0x1249, "pic1_08.png" },
|
||||
{ 0x124A, "pic1_09.png" },
|
||||
{ 0x124B, "pic1_10.png" },
|
||||
{ 0x124C, "pic1_11.png" },
|
||||
{ 0x124D, "pic1_12.png" },
|
||||
{ 0x124E, "pic1_13.png" },
|
||||
{ 0x124F, "pic1_14.png" },
|
||||
{ 0x1250, "pic1_15.png" },
|
||||
{ 0x1251, "pic1_16.png" },
|
||||
{ 0x1252, "pic1_17.png" },
|
||||
{ 0x1253, "pic1_18.png" },
|
||||
{ 0x1254, "pic1_19.png" },
|
||||
{ 0x1255, "pic1_20.png" },
|
||||
{ 0x1256, "pic1_21.png" },
|
||||
{ 0x1257, "pic1_22.png" },
|
||||
{ 0x1258, "pic1_23.png" },
|
||||
{ 0x1259, "pic1_24.png" },
|
||||
{ 0x125A, "pic1_25.png" },
|
||||
{ 0x125B, "pic1_26.png" },
|
||||
{ 0x125C, "pic1_27.png" },
|
||||
{ 0x125D, "pic1_28.png" },
|
||||
{ 0x125E, "pic1_29.png" },
|
||||
{ 0x125F, "pic1_30.png" },
|
||||
{ 0x1260, "changeinfo/changeinfo.xml" },
|
||||
{ 0x1261, "changeinfo/changeinfo_00.xml" },
|
||||
{ 0x1262, "changeinfo/changeinfo_01.xml" },
|
||||
{ 0x1263, "changeinfo/changeinfo_02.xml" },
|
||||
{ 0x1264, "changeinfo/changeinfo_03.xml" },
|
||||
{ 0x1265, "changeinfo/changeinfo_04.xml" },
|
||||
{ 0x1266, "changeinfo/changeinfo_05.xml" },
|
||||
{ 0x1267, "changeinfo/changeinfo_06.xml" },
|
||||
{ 0x1268, "changeinfo/changeinfo_07.xml" },
|
||||
{ 0x1269, "changeinfo/changeinfo_08.xml" },
|
||||
{ 0x126A, "changeinfo/changeinfo_09.xml" },
|
||||
{ 0x126B, "changeinfo/changeinfo_10.xml" },
|
||||
{ 0x126C, "changeinfo/changeinfo_11.xml" },
|
||||
{ 0x126D, "changeinfo/changeinfo_12.xml" },
|
||||
{ 0x126E, "changeinfo/changeinfo_13.xml" },
|
||||
{ 0x126F, "changeinfo/changeinfo_14.xml" },
|
||||
{ 0x1270, "changeinfo/changeinfo_15.xml" },
|
||||
{ 0x1271, "changeinfo/changeinfo_16.xml" },
|
||||
{ 0x1272, "changeinfo/changeinfo_17.xml" },
|
||||
{ 0x1273, "changeinfo/changeinfo_18.xml" },
|
||||
{ 0x1274, "changeinfo/changeinfo_19.xml" },
|
||||
{ 0x1275, "changeinfo/changeinfo_20.xml" },
|
||||
{ 0x1276, "changeinfo/changeinfo_21.xml" },
|
||||
{ 0x1277, "changeinfo/changeinfo_22.xml" },
|
||||
{ 0x1278, "changeinfo/changeinfo_23.xml" },
|
||||
{ 0x1279, "changeinfo/changeinfo_24.xml" },
|
||||
{ 0x127A, "changeinfo/changeinfo_25.xml" },
|
||||
{ 0x127B, "changeinfo/changeinfo_26.xml" },
|
||||
{ 0x127C, "changeinfo/changeinfo_27.xml" },
|
||||
{ 0x127D, "changeinfo/changeinfo_28.xml" },
|
||||
{ 0x127E, "changeinfo/changeinfo_29.xml" },
|
||||
{ 0x127F, "changeinfo/changeinfo_30.xml" },
|
||||
{ 0x1280, "icon0.dds" },
|
||||
{ 0x1281, "icon0_00.dds" },
|
||||
{ 0x1282, "icon0_01.dds" },
|
||||
{ 0x1283, "icon0_02.dds" },
|
||||
{ 0x1284, "icon0_03.dds" },
|
||||
{ 0x1285, "icon0_04.dds" },
|
||||
{ 0x1286, "icon0_05.dds" },
|
||||
{ 0x1287, "icon0_06.dds" },
|
||||
{ 0x1288, "icon0_07.dds" },
|
||||
{ 0x1289, "icon0_08.dds" },
|
||||
{ 0x128A, "icon0_09.dds" },
|
||||
{ 0x128B, "icon0_10.dds" },
|
||||
{ 0x128C, "icon0_11.dds" },
|
||||
{ 0x128D, "icon0_12.dds" },
|
||||
{ 0x128E, "icon0_13.dds" },
|
||||
{ 0x128F, "icon0_14.dds" },
|
||||
{ 0x1290, "icon0_15.dds" },
|
||||
{ 0x1291, "icon0_16.dds" },
|
||||
{ 0x1292, "icon0_17.dds" },
|
||||
{ 0x1293, "icon0_18.dds" },
|
||||
{ 0x1294, "icon0_19.dds" },
|
||||
{ 0x1295, "icon0_20.dds" },
|
||||
{ 0x1296, "icon0_21.dds" },
|
||||
{ 0x1297, "icon0_22.dds" },
|
||||
{ 0x1298, "icon0_23.dds" },
|
||||
{ 0x1299, "icon0_24.dds" },
|
||||
{ 0x129A, "icon0_25.dds" },
|
||||
{ 0x129B, "icon0_26.dds" },
|
||||
{ 0x129C, "icon0_27.dds" },
|
||||
{ 0x129D, "icon0_28.dds" },
|
||||
{ 0x129E, "icon0_29.dds" },
|
||||
{ 0x129F, "icon0_30.dds" },
|
||||
{ 0x12A0, "pic0.dds" },
|
||||
{ 0x12C0, "pic1.dds" },
|
||||
{ 0x12C1, "pic1_00.dds" },
|
||||
{ 0x12C2, "pic1_01.dds" },
|
||||
{ 0x12C3, "pic1_02.dds" },
|
||||
{ 0x12C4, "pic1_03.dds" },
|
||||
{ 0x12C5, "pic1_04.dds" },
|
||||
{ 0x12C6, "pic1_05.dds" },
|
||||
{ 0x12C7, "pic1_06.dds" },
|
||||
{ 0x12C8, "pic1_07.dds" },
|
||||
{ 0x12C9, "pic1_08.dds" },
|
||||
{ 0x12CA, "pic1_09.dds" },
|
||||
{ 0x12CB, "pic1_10.dds" },
|
||||
{ 0x12CC, "pic1_11.dds" },
|
||||
{ 0x12CD, "pic1_12.dds" },
|
||||
{ 0x12CE, "pic1_13.dds" },
|
||||
{ 0x12CF, "pic1_14.dds" },
|
||||
{ 0x12D0, "pic1_15.dds" },
|
||||
{ 0x12D1, "pic1_16.dds" },
|
||||
{ 0x12D2, "pic1_17.dds" },
|
||||
{ 0x12D3, "pic1_18.dds" },
|
||||
{ 0x12D4, "pic1_19.dds" },
|
||||
{ 0x12D5, "pic1_20.dds" },
|
||||
{ 0x12D6, "pic1_21.dds" },
|
||||
{ 0x12D7, "pic1_22.dds" },
|
||||
{ 0x12D8, "pic1_23.dds" },
|
||||
{ 0x12D9, "pic1_24.dds" },
|
||||
{ 0x12DA, "pic1_25.dds" },
|
||||
{ 0x12DB, "pic1_26.dds" },
|
||||
{ 0x12DC, "pic1_27.dds" },
|
||||
{ 0x12DD, "pic1_28.dds" },
|
||||
{ 0x12DE, "pic1_29.dds" },
|
||||
{ 0x12DF, "pic1_30.dds" },
|
||||
{ 0x1400, "trophy/trophy00.trp" },
|
||||
{ 0x1401, "trophy/trophy01.trp" },
|
||||
{ 0x1402, "trophy/trophy02.trp" },
|
||||
{ 0x1403, "trophy/trophy03.trp" },
|
||||
{ 0x1404, "trophy/trophy04.trp" },
|
||||
{ 0x1405, "trophy/trophy05.trp" },
|
||||
{ 0x1406, "trophy/trophy06.trp" },
|
||||
{ 0x1407, "trophy/trophy07.trp" },
|
||||
{ 0x1408, "trophy/trophy08.trp" },
|
||||
{ 0x1409, "trophy/trophy09.trp" },
|
||||
{ 0x140A, "trophy/trophy10.trp" },
|
||||
{ 0x140B, "trophy/trophy11.trp" },
|
||||
{ 0x140C, "trophy/trophy12.trp" },
|
||||
{ 0x140D, "trophy/trophy13.trp" },
|
||||
{ 0x140E, "trophy/trophy14.trp" },
|
||||
{ 0x140F, "trophy/trophy15.trp" },
|
||||
{ 0x1410, "trophy/trophy16.trp" },
|
||||
{ 0x1411, "trophy/trophy17.trp" },
|
||||
{ 0x1412, "trophy/trophy18.trp" },
|
||||
{ 0x1413, "trophy/trophy19.trp" },
|
||||
{ 0x1414, "trophy/trophy20.trp" },
|
||||
{ 0x1415, "trophy/trophy21.trp" },
|
||||
{ 0x1416, "trophy/trophy22.trp" },
|
||||
{ 0x1417, "trophy/trophy23.trp" },
|
||||
{ 0x1418, "trophy/trophy24.trp" },
|
||||
{ 0x1419, "trophy/trophy25.trp" },
|
||||
{ 0x141A, "trophy/trophy26.trp" },
|
||||
{ 0x141B, "trophy/trophy27.trp" },
|
||||
{ 0x141C, "trophy/trophy28.trp" },
|
||||
{ 0x141D, "trophy/trophy29.trp" },
|
||||
{ 0x141E, "trophy/trophy30.trp" },
|
||||
{ 0x141F, "trophy/trophy31.trp" },
|
||||
{ 0x1420, "trophy/trophy32.trp" },
|
||||
{ 0x1421, "trophy/trophy33.trp" },
|
||||
{ 0x1422, "trophy/trophy34.trp" },
|
||||
{ 0x1423, "trophy/trophy35.trp" },
|
||||
{ 0x1424, "trophy/trophy36.trp" },
|
||||
{ 0x1425, "trophy/trophy37.trp" },
|
||||
{ 0x1426, "trophy/trophy38.trp" },
|
||||
{ 0x1427, "trophy/trophy39.trp" },
|
||||
{ 0x1428, "trophy/trophy40.trp" },
|
||||
{ 0x1429, "trophy/trophy41.trp" },
|
||||
{ 0x142A, "trophy/trophy42.trp" },
|
||||
{ 0x142B, "trophy/trophy43.trp" },
|
||||
{ 0x142C, "trophy/trophy44.trp" },
|
||||
{ 0x142D, "trophy/trophy45.trp" },
|
||||
{ 0x142E, "trophy/trophy46.trp" },
|
||||
{ 0x142F, "trophy/trophy47.trp" },
|
||||
{ 0x1430, "trophy/trophy48.trp" },
|
||||
{ 0x1431, "trophy/trophy49.trp" },
|
||||
{ 0x1432, "trophy/trophy50.trp" },
|
||||
{ 0x1433, "trophy/trophy51.trp" },
|
||||
{ 0x1434, "trophy/trophy52.trp" },
|
||||
{ 0x1435, "trophy/trophy53.trp" },
|
||||
{ 0x1436, "trophy/trophy54.trp" },
|
||||
{ 0x1437, "trophy/trophy55.trp" },
|
||||
{ 0x1438, "trophy/trophy56.trp" },
|
||||
{ 0x1439, "trophy/trophy57.trp" },
|
||||
{ 0x143A, "trophy/trophy58.trp" },
|
||||
{ 0x143B, "trophy/trophy59.trp" },
|
||||
{ 0x143C, "trophy/trophy60.trp" },
|
||||
{ 0x143D, "trophy/trophy61.trp" },
|
||||
{ 0x143E, "trophy/trophy62.trp" },
|
||||
{ 0x143F, "trophy/trophy63.trp" },
|
||||
{ 0x1440, "trophy/trophy64.trp" },
|
||||
{ 0x1441, "trophy/trophy65.trp" },
|
||||
{ 0x1442, "trophy/trophy66.trp" },
|
||||
{ 0x1443, "trophy/trophy67.trp" },
|
||||
{ 0x1444, "trophy/trophy68.trp" },
|
||||
{ 0x1445, "trophy/trophy69.trp" },
|
||||
{ 0x1446, "trophy/trophy70.trp" },
|
||||
{ 0x1447, "trophy/trophy71.trp" },
|
||||
{ 0x1448, "trophy/trophy72.trp" },
|
||||
{ 0x1449, "trophy/trophy73.trp" },
|
||||
{ 0x144A, "trophy/trophy74.trp" },
|
||||
{ 0x144B, "trophy/trophy75.trp" },
|
||||
{ 0x144C, "trophy/trophy76.trp" },
|
||||
{ 0x144D, "trophy/trophy77.trp" },
|
||||
{ 0x144E, "trophy/trophy78.trp" },
|
||||
{ 0x144F, "trophy/trophy79.trp" },
|
||||
{ 0x1450, "trophy/trophy80.trp" },
|
||||
{ 0x1451, "trophy/trophy81.trp" },
|
||||
{ 0x1452, "trophy/trophy82.trp" },
|
||||
{ 0x1453, "trophy/trophy83.trp" },
|
||||
{ 0x1454, "trophy/trophy84.trp" },
|
||||
{ 0x1455, "trophy/trophy85.trp" },
|
||||
{ 0x1456, "trophy/trophy86.trp" },
|
||||
{ 0x1457, "trophy/trophy87.trp" },
|
||||
{ 0x1458, "trophy/trophy88.trp" },
|
||||
{ 0x1459, "trophy/trophy89.trp" },
|
||||
{ 0x145A, "trophy/trophy90.trp" },
|
||||
{ 0x145B, "trophy/trophy91.trp" },
|
||||
{ 0x145C, "trophy/trophy92.trp" },
|
||||
{ 0x145D, "trophy/trophy93.trp" },
|
||||
{ 0x145E, "trophy/trophy94.trp" },
|
||||
{ 0x145F, "trophy/trophy95.trp" },
|
||||
{ 0x1460, "trophy/trophy96.trp" },
|
||||
{ 0x1461, "trophy/trophy97.trp" },
|
||||
{ 0x1462, "trophy/trophy98.trp" },
|
||||
{ 0x1463, "trophy/trophy99.trp" },
|
||||
{ 0x1600, "keymap_rp/001.png" },
|
||||
{ 0x1601, "keymap_rp/002.png" },
|
||||
{ 0x1602, "keymap_rp/003.png" },
|
||||
{ 0x1603, "keymap_rp/004.png" },
|
||||
{ 0x1604, "keymap_rp/005.png" },
|
||||
{ 0x1605, "keymap_rp/006.png" },
|
||||
{ 0x1606, "keymap_rp/007.png" },
|
||||
{ 0x1607, "keymap_rp/008.png" },
|
||||
{ 0x1608, "keymap_rp/009.png" },
|
||||
{ 0x1609, "keymap_rp/010.png" },
|
||||
{ 0x1610, "keymap_rp/00/001.png" },
|
||||
{ 0x1611, "keymap_rp/00/002.png" },
|
||||
{ 0x1612, "keymap_rp/00/003.png" },
|
||||
{ 0x1613, "keymap_rp/00/004.png" },
|
||||
{ 0x1614, "keymap_rp/00/005.png" },
|
||||
{ 0x1615, "keymap_rp/00/006.png" },
|
||||
{ 0x1616, "keymap_rp/00/007.png" },
|
||||
{ 0x1617, "keymap_rp/00/008.png" },
|
||||
{ 0x1618, "keymap_rp/00/009.png" },
|
||||
{ 0x1619, "keymap_rp/00/010.png" },
|
||||
{ 0x1620, "keymap_rp/01/001.png" },
|
||||
{ 0x1621, "keymap_rp/01/002.png" },
|
||||
{ 0x1622, "keymap_rp/01/003.png" },
|
||||
{ 0x1623, "keymap_rp/01/004.png" },
|
||||
{ 0x1624, "keymap_rp/01/005.png" },
|
||||
{ 0x1625, "keymap_rp/01/006.png" },
|
||||
{ 0x1626, "keymap_rp/01/007.png" },
|
||||
{ 0x1627, "keymap_rp/01/008.png" },
|
||||
{ 0x1628, "keymap_rp/01/009.png" },
|
||||
{ 0x1629, "keymap_rp/01/010.png" },
|
||||
{ 0x1630, "keymap_rp/02/001.png" },
|
||||
{ 0x1631, "keymap_rp/02/002.png" },
|
||||
{ 0x1632, "keymap_rp/02/003.png" },
|
||||
{ 0x1633, "keymap_rp/02/004.png" },
|
||||
{ 0x1634, "keymap_rp/02/005.png" },
|
||||
{ 0x1635, "keymap_rp/02/006.png" },
|
||||
{ 0x1636, "keymap_rp/02/007.png" },
|
||||
{ 0x1637, "keymap_rp/02/008.png" },
|
||||
{ 0x1638, "keymap_rp/02/009.png" },
|
||||
{ 0x1639, "keymap_rp/02/010.png" },
|
||||
{ 0x1640, "keymap_rp/03/001.png" },
|
||||
{ 0x1641, "keymap_rp/03/002.png" },
|
||||
{ 0x1642, "keymap_rp/03/003.png" },
|
||||
{ 0x1643, "keymap_rp/03/004.png" },
|
||||
{ 0x1644, "keymap_rp/03/005.png" },
|
||||
{ 0x1645, "keymap_rp/03/006.png" },
|
||||
{ 0x1646, "keymap_rp/03/007.png" },
|
||||
{ 0x1647, "keymap_rp/03/008.png" },
|
||||
{ 0x1648, "keymap_rp/03/0010.png"},
|
||||
{ 0x1650, "keymap_rp/04/001.png" },
|
||||
{ 0x1651, "keymap_rp/04/002.png" },
|
||||
{ 0x1652, "keymap_rp/04/003.png" },
|
||||
{ 0x1653, "keymap_rp/04/004.png" },
|
||||
{ 0x1654, "keymap_rp/04/005.png" },
|
||||
{ 0x1655, "keymap_rp/04/006.png" },
|
||||
{ 0x1656, "keymap_rp/04/007.png" },
|
||||
{ 0x1657, "keymap_rp/04/008.png" },
|
||||
{ 0x1658, "keymap_rp/04/009.png" },
|
||||
{ 0x1659, "keymap_rp/04/010.png" },
|
||||
{ 0x1660, "keymap_rp/05/001.png" },
|
||||
{ 0x1661, "keymap_rp/05/002.png" },
|
||||
{ 0x1662, "keymap_rp/05/003.png" },
|
||||
{ 0x1663, "keymap_rp/05/004.png" },
|
||||
{ 0x1664, "keymap_rp/05/005.png" },
|
||||
{ 0x1665, "keymap_rp/05/006.png" },
|
||||
{ 0x1666, "keymap_rp/05/007.png" },
|
||||
{ 0x1667, "keymap_rp/05/008.png" },
|
||||
{ 0x1668, "keymap_rp/05/009.png" },
|
||||
{ 0x1669, "keymap_rp/05/010.png" },
|
||||
{ 0x1670, "keymap_rp/06/001.png" },
|
||||
{ 0x1671, "keymap_rp/06/002.png" },
|
||||
{ 0x1672, "keymap_rp/06/003.png" },
|
||||
{ 0x1673, "keymap_rp/06/004.png" },
|
||||
{ 0x1674, "keymap_rp/06/005.png" },
|
||||
{ 0x1675, "keymap_rp/06/006.png" },
|
||||
{ 0x1676, "keymap_rp/06/007.png" },
|
||||
{ 0x1677, "keymap_rp/06/008.png" },
|
||||
{ 0x1678, "keymap_rp/06/009.png" },
|
||||
{ 0x1679, "keymap_rp/06/010.png" },
|
||||
{ 0x1680, "keymap_rp/07/001.png" },
|
||||
{ 0x1681, "keymap_rp/07/002.png" },
|
||||
{ 0x1682, "keymap_rp/07/003.png" },
|
||||
{ 0x1683, "keymap_rp/07/004.png" },
|
||||
{ 0x1684, "keymap_rp/07/005.png" },
|
||||
{ 0x1685, "keymap_rp/07/006.png" },
|
||||
{ 0x1686, "keymap_rp/07/007.png" },
|
||||
{ 0x1687, "keymap_rp/07/008.png" },
|
||||
{ 0x1688, "keymap_rp/07/009.png" },
|
||||
{ 0x1689, "keymap_rp/07/010.png" },
|
||||
{ 0x1690, "keymap_rp/08/001.png" },
|
||||
{ 0x1691, "keymap_rp/08/002.png" },
|
||||
{ 0x1692, "keymap_rp/08/003.png" },
|
||||
{ 0x1693, "keymap_rp/08/004.png" },
|
||||
{ 0x1694, "keymap_rp/08/005.png" },
|
||||
{ 0x1695, "keymap_rp/08/006.png" },
|
||||
{ 0x1696, "keymap_rp/08/007.png" },
|
||||
{ 0x1697, "keymap_rp/08/008.png" },
|
||||
{ 0x1698, "keymap_rp/08/009.png" },
|
||||
{ 0x1699, "keymap_rp/08/010.png" },
|
||||
{ 0x16A0, "keymap_rp/09/001.png" },
|
||||
{ 0x16A1, "keymap_rp/09/002.png" },
|
||||
{ 0x16A2, "keymap_rp/09/003.png" },
|
||||
{ 0x16A3, "keymap_rp/09/004.png" },
|
||||
{ 0x16A4, "keymap_rp/09/005.png" },
|
||||
{ 0x16A5, "keymap_rp/09/006.png" },
|
||||
{ 0x16A6, "keymap_rp/09/007.png" },
|
||||
{ 0x16A7, "keymap_rp/09/008.png" },
|
||||
{ 0x16A8, "keymap_rp/09/009.png" },
|
||||
{ 0x16A9, "keymap_rp/09/010.png" },
|
||||
{ 0x16B0, "keymap_rp/10/001.png" },
|
||||
{ 0x16B1, "keymap_rp/10/002.png" },
|
||||
{ 0x16B2, "keymap_rp/10/003.png" },
|
||||
{ 0x16B3, "keymap_rp/10/004.png" },
|
||||
{ 0x16B4, "keymap_rp/10/005.png" },
|
||||
{ 0x16B5, "keymap_rp/10/006.png" },
|
||||
{ 0x16B6, "keymap_rp/10/007.png" },
|
||||
{ 0x16B7, "keymap_rp/10/008.png" },
|
||||
{ 0x16B8, "keymap_rp/10/009.png" },
|
||||
{ 0x16B9, "keymap_rp/10/010.png" },
|
||||
{ 0x16C0, "keymap_rp/11/001.png" },
|
||||
{ 0x16C1, "keymap_rp/11/002.png" },
|
||||
{ 0x16C2, "keymap_rp/11/003.png" },
|
||||
{ 0x16C3, "keymap_rp/11/004.png" },
|
||||
{ 0x16C4, "keymap_rp/11/005.png" },
|
||||
{ 0x16C5, "keymap_rp/11/006.png" },
|
||||
{ 0x16C6, "keymap_rp/11/007.png" },
|
||||
{ 0x16C7, "keymap_rp/11/008.png" },
|
||||
{ 0x16C8, "keymap_rp/11/009.png" },
|
||||
{ 0x16C9, "keymap_rp/11/010.png" },
|
||||
{ 0x16D0, "keymap_rp/12/001.png" },
|
||||
{ 0x16D1, "keymap_rp/12/002.png" },
|
||||
{ 0x16D2, "keymap_rp/12/003.png" },
|
||||
{ 0x16D3, "keymap_rp/12/004.png" },
|
||||
{ 0x16D4, "keymap_rp/12/005.png" },
|
||||
{ 0x16D5, "keymap_rp/12/006.png" },
|
||||
{ 0x16D6, "keymap_rp/12/007.png" },
|
||||
{ 0x16D7, "keymap_rp/12/008.png" },
|
||||
{ 0x16D8, "keymap_rp/12/009.png" },
|
||||
{ 0x16D9, "keymap_rp/12/010.png" },
|
||||
{ 0x16E0, "keymap_rp/13/001.png" },
|
||||
{ 0x16E1, "keymap_rp/13/002.png" },
|
||||
{ 0x16E2, "keymap_rp/13/003.png" },
|
||||
{ 0x16E3, "keymap_rp/13/004.png" },
|
||||
{ 0x16E4, "keymap_rp/13/005.png" },
|
||||
{ 0x16E5, "keymap_rp/13/006.png" },
|
||||
{ 0x16E6, "keymap_rp/13/007.png" },
|
||||
{ 0x16E7, "keymap_rp/13/008.png" },
|
||||
{ 0x16E8, "keymap_rp/13/009.png" },
|
||||
{ 0x16E9, "keymap_rp/13/010.png" },
|
||||
{ 0x16F0, "keymap_rp/14/001.png" },
|
||||
{ 0x16F1, "keymap_rp/14/002.png" },
|
||||
{ 0x16F2, "keymap_rp/14/003.png" },
|
||||
{ 0x16F3, "keymap_rp/14/004.png" },
|
||||
{ 0x16F4, "keymap_rp/14/005.png" },
|
||||
{ 0x16F5, "keymap_rp/14/006.png" },
|
||||
{ 0x16F6, "keymap_rp/14/007.png" },
|
||||
{ 0x16F7, "keymap_rp/14/008.png" },
|
||||
{ 0x16F8, "keymap_rp/14/009.png" },
|
||||
{ 0x16F9, "keymap_rp/14/010.png" },
|
||||
{ 0x1700, "keymap_rp/15/001.png" },
|
||||
{ 0x1701, "keymap_rp/15/002.png" },
|
||||
{ 0x1702, "keymap_rp/15/003.png" },
|
||||
{ 0x1703, "keymap_rp/15/004.png" },
|
||||
{ 0x1704, "keymap_rp/15/005.png" },
|
||||
{ 0x1705, "keymap_rp/15/006.png" },
|
||||
{ 0x1706, "keymap_rp/15/007.png" },
|
||||
{ 0x1707, "keymap_rp/15/008.png" },
|
||||
{ 0x1708, "keymap_rp/15/009.png" },
|
||||
{ 0x1709, "keymap_rp/15/010.png" },
|
||||
{ 0x1710, "keymap_rp/16/001.png" },
|
||||
{ 0x1711, "keymap_rp/16/002.png" },
|
||||
{ 0x1712, "keymap_rp/16/003.png" },
|
||||
{ 0x1713, "keymap_rp/16/004.png" },
|
||||
{ 0x1714, "keymap_rp/16/005.png" },
|
||||
{ 0x1715, "keymap_rp/16/006.png" },
|
||||
{ 0x1716, "keymap_rp/16/007.png" },
|
||||
{ 0x1717, "keymap_rp/16/008.png" },
|
||||
{ 0x1718, "keymap_rp/16/009.png" },
|
||||
{ 0x1719, "keymap_rp/16/010.png" },
|
||||
{ 0x1720, "keymap_rp/17/001.png" },
|
||||
{ 0x1721, "keymap_rp/17/002.png" },
|
||||
{ 0x1722, "keymap_rp/17/003.png" },
|
||||
{ 0x1723, "keymap_rp/17/004.png" },
|
||||
{ 0x1724, "keymap_rp/17/005.png" },
|
||||
{ 0x1725, "keymap_rp/17/006.png" },
|
||||
{ 0x1726, "keymap_rp/17/007.png" },
|
||||
{ 0x1727, "keymap_rp/17/008.png" },
|
||||
{ 0x1728, "keymap_rp/17/009.png" },
|
||||
{ 0x1729, "keymap_rp/17/010.png" },
|
||||
{ 0x1730, "keymap_rp/18/001.png" },
|
||||
{ 0x1731, "keymap_rp/18/002.png" },
|
||||
{ 0x1732, "keymap_rp/18/003.png" },
|
||||
{ 0x1733, "keymap_rp/18/004.png" },
|
||||
{ 0x1734, "keymap_rp/18/005.png" },
|
||||
{ 0x1735, "keymap_rp/18/006.png" },
|
||||
{ 0x1736, "keymap_rp/18/007.png" },
|
||||
{ 0x1737, "keymap_rp/18/008.png" },
|
||||
{ 0x1738, "keymap_rp/18/009.png" },
|
||||
{ 0x1739, "keymap_rp/18/010.png" },
|
||||
{ 0x1740, "keymap_rp/19/001.png" },
|
||||
{ 0x1741, "keymap_rp/19/002.png" },
|
||||
{ 0x1742, "keymap_rp/19/003.png" },
|
||||
{ 0x1743, "keymap_rp/19/004.png" },
|
||||
{ 0x1744, "keymap_rp/19/005.png" },
|
||||
{ 0x1745, "keymap_rp/19/006.png" },
|
||||
{ 0x1746, "keymap_rp/19/007.png" },
|
||||
{ 0x1747, "keymap_rp/19/008.png" },
|
||||
{ 0x1748, "keymap_rp/19/009.png" },
|
||||
{ 0x1749, "keymap_rp/19/010.png" },
|
||||
{ 0x1750, "keymap_rp/20/001.png" },
|
||||
{ 0x1751, "keymap_rp/20/002.png" },
|
||||
{ 0x1752, "keymap_rp/20/003.png" },
|
||||
{ 0x1753, "keymap_rp/20/004.png" },
|
||||
{ 0x1754, "keymap_rp/20/005.png" },
|
||||
{ 0x1755, "keymap_rp/20/006.png" },
|
||||
{ 0x1756, "keymap_rp/20/007.png" },
|
||||
{ 0x1757, "keymap_rp/20/008.png" },
|
||||
{ 0x1758, "keymap_rp/20/009.png" },
|
||||
{ 0x1759, "keymap_rp/20/010.png" },
|
||||
{ 0x1760, "keymap_rp/21/001.png" },
|
||||
{ 0x1761, "keymap_rp/21/002.png" },
|
||||
{ 0x1762, "keymap_rp/21/003.png" },
|
||||
{ 0x1763, "keymap_rp/21/004.png" },
|
||||
{ 0x1764, "keymap_rp/21/005.png" },
|
||||
{ 0x1765, "keymap_rp/21/006.png" },
|
||||
{ 0x1766, "keymap_rp/21/007.png" },
|
||||
{ 0x1767, "keymap_rp/21/008.png" },
|
||||
{ 0x1768, "keymap_rp/21/009.png" },
|
||||
{ 0x1769, "keymap_rp/21/010.png" },
|
||||
{ 0x1770, "keymap_rp/22/001.png" },
|
||||
{ 0x1771, "keymap_rp/22/002.png" },
|
||||
{ 0x1772, "keymap_rp/22/003.png" },
|
||||
{ 0x1773, "keymap_rp/22/004.png" },
|
||||
{ 0x1774, "keymap_rp/22/005.png" },
|
||||
{ 0x1775, "keymap_rp/22/006.png" },
|
||||
{ 0x1776, "keymap_rp/22/007.png" },
|
||||
{ 0x1777, "keymap_rp/22/008.png" },
|
||||
{ 0x1778, "keymap_rp/22/009.png" },
|
||||
{ 0x1779, "keymap_rp/22/010.png" },
|
||||
{ 0x1780, "keymap_rp/23/001.png" },
|
||||
{ 0x1781, "keymap_rp/23/002.png" },
|
||||
{ 0x1782, "keymap_rp/23/003.png" },
|
||||
{ 0x1783, "keymap_rp/23/004.png" },
|
||||
{ 0x1784, "keymap_rp/23/005.png" },
|
||||
{ 0x1785, "keymap_rp/23/006.png" },
|
||||
{ 0x1786, "keymap_rp/23/007.png" },
|
||||
{ 0x1787, "keymap_rp/23/008.png" },
|
||||
{ 0x1788, "keymap_rp/23/009.png" },
|
||||
{ 0x1789, "keymap_rp/23/010.png" },
|
||||
{ 0x1790, "keymap_rp/24/001.png" },
|
||||
{ 0x1791, "keymap_rp/24/002.png" },
|
||||
{ 0x1792, "keymap_rp/24/003.png" },
|
||||
{ 0x1793, "keymap_rp/24/004.png" },
|
||||
{ 0x1794, "keymap_rp/24/005.png" },
|
||||
{ 0x1795, "keymap_rp/24/006.png" },
|
||||
{ 0x1796, "keymap_rp/24/007.png" },
|
||||
{ 0x1797, "keymap_rp/24/008.png" },
|
||||
{ 0x1798, "keymap_rp/24/009.png" },
|
||||
{ 0x1799, "keymap_rp/24/010.png" },
|
||||
{ 0x17A0, "keymap_rp/25/001.png" },
|
||||
{ 0x17A1, "keymap_rp/25/002.png" },
|
||||
{ 0x17A2, "keymap_rp/25/003.png" },
|
||||
{ 0x17A3, "keymap_rp/25/004.png" },
|
||||
{ 0x17A4, "keymap_rp/25/005.png" },
|
||||
{ 0x17A5, "keymap_rp/25/006.png" },
|
||||
{ 0x17A6, "keymap_rp/25/007.png" },
|
||||
{ 0x17A7, "keymap_rp/25/008.png" },
|
||||
{ 0x17A8, "keymap_rp/25/009.png" },
|
||||
{ 0x17A9, "keymap_rp/25/010.png" },
|
||||
{ 0x17B0, "keymap_rp/26/001.png" },
|
||||
{ 0x17B1, "keymap_rp/26/002.png" },
|
||||
{ 0x17B2, "keymap_rp/26/003.png" },
|
||||
{ 0x17B3, "keymap_rp/26/004.png" },
|
||||
{ 0x17B4, "keymap_rp/26/005.png" },
|
||||
{ 0x17B5, "keymap_rp/26/006.png" },
|
||||
{ 0x17B6, "keymap_rp/26/007.png" },
|
||||
{ 0x17B7, "keymap_rp/26/008.png" },
|
||||
{ 0x17B8, "keymap_rp/26/009.png" },
|
||||
{ 0x17B9, "keymap_rp/26/010.png" },
|
||||
{ 0x17C0, "keymap_rp/27/001.png" },
|
||||
{ 0x17C1, "keymap_rp/27/002.png" },
|
||||
{ 0x17C2, "keymap_rp/27/003.png" },
|
||||
{ 0x17C3, "keymap_rp/27/004.png" },
|
||||
{ 0x17C4, "keymap_rp/27/005.png" },
|
||||
{ 0x17C5, "keymap_rp/27/006.png" },
|
||||
{ 0x17C6, "keymap_rp/27/007.png" },
|
||||
{ 0x17C7, "keymap_rp/27/008.png" },
|
||||
{ 0x17C8, "keymap_rp/27/009.png" },
|
||||
{ 0x17C9, "keymap_rp/27/010.png" },
|
||||
{ 0x17D0, "keymap_rp/28/001.png" },
|
||||
{ 0x17D1, "keymap_rp/28/002.png" },
|
||||
{ 0x17D2, "keymap_rp/28/003.png" },
|
||||
{ 0x17D3, "keymap_rp/28/004.png" },
|
||||
{ 0x17D4, "keymap_rp/28/005.png" },
|
||||
{ 0x17D5, "keymap_rp/28/006.png" },
|
||||
{ 0x17D6, "keymap_rp/28/007.png" },
|
||||
{ 0x17D7, "keymap_rp/28/008.png" },
|
||||
{ 0x17D8, "keymap_rp/28/009.png" },
|
||||
{ 0x17D9, "keymap_rp/28/010.png" },
|
||||
{ 0x17E0, "keymap_rp/29/001.png" },
|
||||
{ 0x17E1, "keymap_rp/29/002.png" },
|
||||
{ 0x17E2, "keymap_rp/29/003.png" },
|
||||
{ 0x17E3, "keymap_rp/29/004.png" },
|
||||
{ 0x17E4, "keymap_rp/29/005.png" },
|
||||
{ 0x17E5, "keymap_rp/29/006.png" },
|
||||
{ 0x17E6, "keymap_rp/29/007.png" },
|
||||
{ 0x17E7, "keymap_rp/29/008.png" },
|
||||
{ 0x17E8, "keymap_rp/29/009.png" },
|
||||
{ 0x17E9, "keymap_rp/29/010.png" },
|
||||
{ 0x17F0, "keymap_rp/30/001.png" },
|
||||
{ 0x17F1, "keymap_rp/30/002.png" },
|
||||
{ 0x17F2, "keymap_rp/30/003.png" },
|
||||
{ 0x17F3, "keymap_rp/30/004.png" },
|
||||
{ 0x17F4, "keymap_rp/30/005.png" },
|
||||
{ 0x17F5, "keymap_rp/30/006.png" },
|
||||
{ 0x17F6, "keymap_rp/30/007.png" },
|
||||
{ 0x17F7, "keymap_rp/30/008.png" },
|
||||
{ 0x17F8, "keymap_rp/30/009.png" },
|
||||
{ 0x17F9, "keymap_rp/30/010.png" },
|
||||
|
||||
};
|
||||
std::string entry_name="";
|
||||
|
||||
for (size_t i = 0; i < sizeof entries / sizeof entries[0]; i++) {
|
||||
if (type == entries[i].type) {
|
||||
entry_name = entries[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return entry_name;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
#include "PSF.h"
|
||||
#include "../../Core/FsFile.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
PSF::PSF()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PSF::~PSF()
|
||||
{
|
||||
}
|
||||
bool PSF::open(const std::string& filepath) {
|
||||
FsFile file;
|
||||
if (!file.Open(filepath, fsRead))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const U64 psfSize = file.getFileSize();
|
||||
psf.resize(psfSize);
|
||||
file.Seek(0, fsSeekSet);
|
||||
file.Read(&psf[0], psfSize);
|
||||
|
||||
// Parse file contents
|
||||
const auto& header = (PSFHeader&)psf[0];
|
||||
for (U32 i = 0; i < header.indexTableEntries; i++) {
|
||||
const U32 offset = sizeof(PSFHeader) + i * sizeof(PSFEntry);
|
||||
auto& entry = (PSFEntry&)psf[offset];
|
||||
|
||||
std::string key = (char*)&psf[header.keyTableOffset + entry.keyOffset];
|
||||
ReadBE(entry.param_fmt);//param_fmt is big endian convert it (this convert the original entry maybe we should store it elsewhere?)
|
||||
if (entry.param_fmt == PSFEntry::Fmt::TEXT_RAW ||
|
||||
entry.param_fmt == PSFEntry::Fmt::TEXT_NORMAL) {
|
||||
map_strings[key] = (char*)&psf[header.dataTableOffset + entry.dataOffset];
|
||||
}
|
||||
if (entry.param_fmt == PSFEntry::Fmt::INTEGER) {
|
||||
map_integers[key] = (U32&)psf[header.dataTableOffset + entry.dataOffset];
|
||||
}
|
||||
}
|
||||
//debug code print all keys
|
||||
std::ofstream out;
|
||||
out.open("psf.txt", std::fstream::out | std::fstream::app);
|
||||
out << "---------------------------------------------" << "\n";
|
||||
for (auto stringkey : map_strings)
|
||||
{
|
||||
out << " " << stringkey.first << " : " << stringkey.second << "\n";
|
||||
}
|
||||
for (auto integerkey : map_integers)
|
||||
{
|
||||
out << " " << integerkey.first << " : " << integerkey.second << "\n";
|
||||
}
|
||||
out << "---------------------------------------------" << "\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
std::string PSF::get_string(const std::string& key) {
|
||||
if (map_strings.find(key) != map_strings.end()) {
|
||||
return map_strings.at(key);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
U32 PSF::get_integer(const std::string& key)
|
||||
{
|
||||
if (map_integers.find(key) != map_integers.end()) {
|
||||
return map_integers.at(key); //TODO std::invalid_argument exception if it fails?
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "../../types.h"
|
||||
|
||||
struct PSFHeader {
|
||||
U32 magic; //big endian
|
||||
U32 version;
|
||||
U32 keyTableOffset;
|
||||
U32 dataTableOffset;
|
||||
U32 indexTableEntries;
|
||||
};
|
||||
|
||||
struct PSFEntry {
|
||||
enum Fmt : U16 {
|
||||
TEXT_RAW = 0x0400, // String in UTF-8 format and not NULL terminated
|
||||
TEXT_NORMAL = 0x0402, // String in UTF-8 format and NULL terminated
|
||||
INTEGER = 0x0404, // Unsigned 32-bit integer
|
||||
};
|
||||
|
||||
U16 keyOffset;
|
||||
U16 param_fmt;//big endian
|
||||
U32 paramLen;
|
||||
U32 paramMaxLen;
|
||||
U32 dataOffset;
|
||||
};
|
||||
|
||||
class PSF
|
||||
{
|
||||
std::vector<U08> psf;
|
||||
std::unordered_map<std::string, std::string> map_strings;
|
||||
std::unordered_map<std::string, U32> map_integers;
|
||||
|
||||
public:
|
||||
PSF();
|
||||
~PSF();
|
||||
bool open(const std::string& filepath);
|
||||
|
||||
// Access data
|
||||
std::string get_string(const std::string& key);
|
||||
U32 get_integer(const std::string& key);
|
||||
};
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
struct GameInfo
|
||||
{
|
||||
std::string path; //root path of game directory (normaly directory that contains eboot.bin)
|
||||
std::string icon_path;//path of icon0.png
|
||||
|
||||
//variables extracted from param.sfo
|
||||
std::string name = "Unknown";
|
||||
std::string serial = "Unknown";
|
||||
std::string app_ver = "Unknown";
|
||||
std::string version = "Unknown";
|
||||
std::string category = "Unknown";
|
||||
std::string fw = "Unknown";
|
||||
|
||||
};
|
|
@ -1,182 +0,0 @@
|
|||
#include "GameListViewer.h"
|
||||
#include <QFileInfo>
|
||||
#include <QHeaderView>
|
||||
#include <QMenu>
|
||||
#include <QThreadPool>
|
||||
#include <QVBoxLayout>
|
||||
#include <QDirIterator>
|
||||
#include <QLineEdit>
|
||||
#include <QRegularExpression>
|
||||
#include "../emulator/fileFormat/PSF.h"
|
||||
|
||||
GameListViewer::GameListViewer(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
QVBoxLayout* layout = new QVBoxLayout;
|
||||
QHBoxLayout* search_layout = new QHBoxLayout;
|
||||
proxyModel = new QSortFilterProxyModel;
|
||||
search_games = new QLineEdit;
|
||||
|
||||
tree_view = new QTreeView;
|
||||
item_model = new QStandardItemModel(tree_view);
|
||||
proxyModel->setSourceModel(item_model);
|
||||
tree_view->setModel(proxyModel);
|
||||
|
||||
tree_view->setAlternatingRowColors(true);
|
||||
tree_view->setSelectionMode(QHeaderView::SingleSelection);
|
||||
tree_view->setSelectionBehavior(QHeaderView::SelectRows);
|
||||
tree_view->setVerticalScrollMode(QHeaderView::ScrollPerPixel);
|
||||
tree_view->setHorizontalScrollMode(QHeaderView::ScrollPerPixel);
|
||||
tree_view->setSortingEnabled(true);
|
||||
tree_view->setEditTriggers(QHeaderView::NoEditTriggers);
|
||||
tree_view->setUniformRowHeights(true);
|
||||
tree_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
item_model->insertColumns(0, 7);
|
||||
item_model->setHeaderData(0, Qt::Horizontal, "Icon");
|
||||
item_model->setHeaderData(1, Qt::Horizontal, "Name");
|
||||
item_model->setHeaderData(2, Qt::Horizontal, "Serial");
|
||||
item_model->setHeaderData(3, Qt::Horizontal, "FW");
|
||||
item_model->setHeaderData(4, Qt::Horizontal, "App Version");
|
||||
item_model->setHeaderData(5, Qt::Horizontal, "Category");
|
||||
item_model->setHeaderData(6, Qt::Horizontal, "Path");
|
||||
|
||||
connect(tree_view, &QTreeView::activated, this, &GameListViewer::ValidateEntry);
|
||||
connect(search_games, &QLineEdit::textChanged, this, &GameListViewer::searchGame);
|
||||
connect(&watcher, &QFileSystemWatcher::directoryChanged, this, &GameListViewer::RefreshGameDirectory);
|
||||
|
||||
// We must register all custom types with the Qt Automoc system so that we are able to use it
|
||||
// with signals/slots. In this case, QList falls under the umbrells of custom types.
|
||||
qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>");
|
||||
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
QSpacerItem* item = new QSpacerItem(100, 1, QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
search_layout->setContentsMargins(0, 5, 0, 0);
|
||||
search_layout->addSpacerItem(item);
|
||||
search_layout->addWidget(search_games);
|
||||
layout->addLayout(search_layout);
|
||||
layout->addWidget(tree_view);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
GameListViewer::~GameListViewer()
|
||||
{
|
||||
emit ShouldCancelWorker();
|
||||
}
|
||||
void GameListViewer::searchGame(QString searchText)
|
||||
{
|
||||
proxyModel->setFilterKeyColumn(1); //filter Name column only
|
||||
QString strPattern = searchText;
|
||||
QRegularExpression regExp(strPattern, QRegularExpression::CaseInsensitiveOption);
|
||||
proxyModel->setFilterRegularExpression(regExp);
|
||||
}
|
||||
void GameListViewer::AddEntry(const QList<QStandardItem*>& entry_items) {
|
||||
item_model->invisibleRootItem()->appendRow(entry_items);
|
||||
}
|
||||
|
||||
void GameListViewer::ValidateEntry(const QModelIndex& item) {
|
||||
// We don't care about the individual QStandardItem that was selected, but its row.
|
||||
}
|
||||
|
||||
void GameListViewer::DonePopulating() {
|
||||
tree_view->setEnabled(true);
|
||||
tree_view->resizeColumnToContents(1);//resize tittle to fit the column
|
||||
}
|
||||
|
||||
void GameListViewer::PopulateAsync() {
|
||||
QDir game_folder(game_path);
|
||||
if (!game_folder.exists())
|
||||
{
|
||||
//game directory doesn't exist
|
||||
return;
|
||||
}
|
||||
|
||||
tree_view->setEnabled(false);
|
||||
// Delete any rows that might already exist if we're repopulating
|
||||
item_model->removeRows(0, item_model->rowCount());
|
||||
|
||||
emit ShouldCancelWorker();
|
||||
|
||||
auto watch_dirs = watcher.directories();
|
||||
if (!watch_dirs.isEmpty()) {
|
||||
watcher.removePaths(watch_dirs);
|
||||
}
|
||||
UpdateWatcherList(game_path.toStdString());
|
||||
GameListWorker* worker = new GameListWorker(game_path);
|
||||
|
||||
connect(worker, &GameListWorker::EntryReady, this, &GameListViewer::AddEntry, Qt::QueuedConnection);
|
||||
connect(worker, &GameListWorker::Finished, this, &GameListViewer::DonePopulating, Qt::QueuedConnection);
|
||||
// Use DirectConnection here because worker->Cancel() is thread-safe and we want it to cancel without delay.
|
||||
connect(this, &GameListViewer::ShouldCancelWorker, worker, &GameListWorker::Cancel, Qt::DirectConnection);
|
||||
|
||||
QThreadPool::globalInstance()->start(worker);
|
||||
current_worker = std::move(worker);
|
||||
}
|
||||
|
||||
void GameListViewer::RefreshGameDirectory() {
|
||||
QDir game_folder(game_path);
|
||||
bool empty = game_folder.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::DirsFirst).count() == 0;
|
||||
if (!empty && current_worker != nullptr) {
|
||||
//Change detected in the games directory. Reloading game list
|
||||
PopulateAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the game list folder to the QFileSystemWatcher to check for updates.
|
||||
*
|
||||
* The file watcher will fire off an update to the game list when a change is detected in the game
|
||||
* list folder.
|
||||
*
|
||||
* Notice: This method is run on the UI thread because QFileSystemWatcher is not thread safe and
|
||||
* this function is fast enough to not stall the UI thread. If performance is an issue, it should
|
||||
* be moved to another thread and properly locked to prevent concurrency issues.
|
||||
*
|
||||
* @param dir folder to check for changes in
|
||||
*/
|
||||
void GameListViewer::UpdateWatcherList(const std::string& dir) {
|
||||
/*watcher.addPath(QString::fromStdString(dir));
|
||||
QDir parent_folder(QString::fromStdString(dir));
|
||||
QFileInfoList fList = parent_folder.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::DirsFirst);
|
||||
foreach(QFileInfo item, fList)
|
||||
{
|
||||
UpdateWatcherList(item.absoluteFilePath().toStdString());
|
||||
}*/
|
||||
}
|
||||
|
||||
void GameListWorker::AddEntriesToGameList(const std::string& dir_path) {
|
||||
QDir parent_folder(QString::fromStdString(dir_path));
|
||||
QFileInfoList fList = parent_folder.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::DirsFirst);
|
||||
foreach(QFileInfo item, fList)
|
||||
{
|
||||
PSF psf;
|
||||
if (!psf.open(item.absoluteFilePath().toStdString() + "/sce_sys/PARAM.SFO"))
|
||||
continue;//if we can't open param.sfo go to the next entry
|
||||
|
||||
//TODO std::string test = psf.get_string("TITLE_ID");
|
||||
QString iconpath(item.absoluteFilePath() + "/sce_sys/ICON0.PNG");
|
||||
QString t;
|
||||
|
||||
emit EntryReady({
|
||||
new GameIconItem(iconpath),
|
||||
new GameListItem(QString::fromStdString(psf.get_string("TITLE"))),
|
||||
new GameListItem(QString::fromStdString(psf.get_string("TITLE_ID"))),
|
||||
new GameListItem((QString("%1").arg(psf.get_integer("SYSTEM_VER"), 8, 16, QLatin1Char('0'))).mid(1,3).insert(1,'.')),
|
||||
new GameListItem(QString::fromStdString(psf.get_string("APP_VER"))),
|
||||
new GameListItem(QString::fromStdString(psf.get_string("CATEGORY"))),
|
||||
new GameListItem(item.fileName())
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void GameListWorker::run() {
|
||||
stop_processing = false;
|
||||
AddEntriesToGameList(dir_path.toStdString());
|
||||
emit Finished();
|
||||
}
|
||||
|
||||
void GameListWorker::Cancel() {
|
||||
this->disconnect();
|
||||
stop_processing = true;
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
#pragma once
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QModelIndex>
|
||||
#include <QSettings>
|
||||
#include <QStandardItem>
|
||||
#include <QStandardItemModel>
|
||||
#include <QString>
|
||||
#include <QTreeView>
|
||||
#include <QWidget>
|
||||
#include <atomic>
|
||||
#include <QImage>
|
||||
#include <QRunnable>
|
||||
#include <QStandardItem>
|
||||
#include <QString>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class GameListWorker;
|
||||
|
||||
class GameListViewer : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GameListViewer(QWidget* parent = nullptr);
|
||||
~GameListViewer();
|
||||
void PopulateAsync();
|
||||
void SetGamePath(QString game_path)
|
||||
{
|
||||
this->game_path = game_path;
|
||||
}
|
||||
signals:
|
||||
void ShouldCancelWorker();
|
||||
|
||||
private:
|
||||
void AddEntry(const QList<QStandardItem*>& entry_items);
|
||||
void ValidateEntry(const QModelIndex& item);
|
||||
void DonePopulating();
|
||||
void UpdateWatcherList(const std::string& path);
|
||||
|
||||
QTreeView* tree_view = nullptr;
|
||||
QStandardItemModel* item_model = nullptr;
|
||||
GameListWorker* current_worker = nullptr;
|
||||
QLineEdit* search_games = nullptr;
|
||||
QSortFilterProxyModel* proxyModel = nullptr;
|
||||
QFileSystemWatcher watcher;
|
||||
QString game_path;
|
||||
public:
|
||||
void RefreshGameDirectory();
|
||||
|
||||
public slots:
|
||||
void searchGame(QString searchText);
|
||||
};
|
||||
class GameListItem : public QStandardItem {
|
||||
|
||||
public:
|
||||
GameListItem() : QStandardItem() {}
|
||||
GameListItem(const QString& string) : QStandardItem(string) {}
|
||||
virtual ~GameListItem() override {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A specialization of GameListItem for icons
|
||||
* If no icon found then create an empty one
|
||||
*/
|
||||
class GameIconItem : public GameListItem
|
||||
{
|
||||
public:
|
||||
GameIconItem() : GameListItem() {}
|
||||
GameIconItem(const QString& pix_path)
|
||||
: GameListItem() {
|
||||
|
||||
QPixmap icon(pix_path);
|
||||
if (icon.isNull())
|
||||
{
|
||||
QPixmap emptyicon(80, 44);
|
||||
emptyicon.fill(Qt::transparent);
|
||||
setData(emptyicon.scaled(80, 44, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::DecorationRole);
|
||||
}
|
||||
else
|
||||
{
|
||||
setData(icon.scaled(80, 44, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::DecorationRole);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Asynchronous worker object for populating the game list.
|
||||
* Communicates with other threads through Qt's signal/slot system.
|
||||
*/
|
||||
class GameListWorker : public QObject, public QRunnable {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GameListWorker(QString dir_path)
|
||||
: QObject(), QRunnable(), dir_path(dir_path) {}
|
||||
|
||||
public slots:
|
||||
/// Starts the processing of directory tree information.
|
||||
void run() override;
|
||||
/// Tells the worker that it should no longer continue processing. Thread-safe.
|
||||
void Cancel();
|
||||
|
||||
signals:
|
||||
/**
|
||||
* The `EntryReady` signal is emitted once an entry has been prepared and is ready
|
||||
* to be added to the game list.
|
||||
* @param entry_items a list with `QStandardItem`s that make up the columns of the new entry.
|
||||
*/
|
||||
void EntryReady(QList<QStandardItem*> entry_items);
|
||||
void Finished();
|
||||
|
||||
private:
|
||||
QString dir_path;
|
||||
std::atomic_bool stop_processing;
|
||||
|
||||
void AddEntriesToGameList(const std::string& dir_path);
|
||||
};
|
|
@ -1,67 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QStyleOption>
|
||||
#include <QPainter>
|
||||
|
||||
class custom_dock_widget : public QDockWidget
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<QWidget> m_title_bar_widget;
|
||||
bool m_is_title_bar_visible = true;
|
||||
|
||||
public:
|
||||
explicit custom_dock_widget(const QString& title, QWidget* parent = Q_NULLPTR, Qt::WindowFlags flags = Qt::WindowFlags())
|
||||
: QDockWidget(title, parent, flags)
|
||||
{
|
||||
m_title_bar_widget.reset(titleBarWidget());
|
||||
|
||||
connect(this, &QDockWidget::topLevelChanged, [this](bool/* topLevel*/)
|
||||
{
|
||||
SetTitleBarVisible(m_is_title_bar_visible);
|
||||
style()->unpolish(this);
|
||||
style()->polish(this);
|
||||
});
|
||||
}
|
||||
|
||||
void SetTitleBarVisible(bool visible)
|
||||
{
|
||||
if (visible || isFloating())
|
||||
{
|
||||
if (m_title_bar_widget.get() != titleBarWidget())
|
||||
{
|
||||
setTitleBarWidget(m_title_bar_widget.get());
|
||||
QMargins margins = widget()->contentsMargins();
|
||||
margins.setTop(0);
|
||||
widget()->setContentsMargins(margins);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setTitleBarWidget(new QWidget());
|
||||
QMargins margins = widget()->contentsMargins();
|
||||
margins.setTop(1);
|
||||
widget()->setContentsMargins(margins);
|
||||
}
|
||||
|
||||
m_is_title_bar_visible = visible;
|
||||
}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) override
|
||||
{
|
||||
// We need to repaint the dock widgets as plain widgets in floating mode.
|
||||
// Source: https://stackoverflow.com/questions/10272091/cannot-add-a-background-image-to-a-qdockwidget
|
||||
if (isFloating())
|
||||
{
|
||||
QStyleOption opt;
|
||||
opt.initFrom(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use inherited method for docked mode because otherwise the dock would lose the title etc.
|
||||
QDockWidget::paintEvent(event);
|
||||
}
|
||||
};
|
|
@ -1,70 +0,0 @@
|
|||
#include "custom_table_widget_item.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
custom_table_widget_item::custom_table_widget_item(const std::string& text, int sort_role, const QVariant& sort_value)
|
||||
: game_list_item(QString::fromStdString(text).simplified()) // simplified() forces single line text
|
||||
{
|
||||
if (sort_role != Qt::DisplayRole)
|
||||
{
|
||||
setData(sort_role, sort_value, true);
|
||||
}
|
||||
}
|
||||
|
||||
custom_table_widget_item::custom_table_widget_item(const QString& text, int sort_role, const QVariant& sort_value)
|
||||
: game_list_item(text.simplified()) // simplified() forces single line text
|
||||
{
|
||||
if (sort_role != Qt::DisplayRole)
|
||||
{
|
||||
setData(sort_role, sort_value, true);
|
||||
}
|
||||
}
|
||||
|
||||
bool custom_table_widget_item::operator<(const QTableWidgetItem& other) const
|
||||
{
|
||||
if (m_sort_role == Qt::DisplayRole)
|
||||
{
|
||||
return QTableWidgetItem::operator<(other);
|
||||
}
|
||||
|
||||
const QVariant data_l = data(m_sort_role);
|
||||
const QVariant data_r = other.data(m_sort_role);
|
||||
const QVariant::Type type_l = data_l.type();
|
||||
const QVariant::Type type_r = data_r.type();
|
||||
|
||||
switch (type_l)
|
||||
{
|
||||
case QVariant::Type::Bool:
|
||||
case QVariant::Type::Int:
|
||||
return data_l.toInt() < data_r.toInt();
|
||||
case QVariant::Type::UInt:
|
||||
return data_l.toUInt() < data_r.toUInt();
|
||||
case QVariant::Type::LongLong:
|
||||
return data_l.toLongLong() < data_r.toLongLong();
|
||||
case QVariant::Type::ULongLong:
|
||||
return data_l.toULongLong() < data_r.toULongLong();
|
||||
case QVariant::Type::Double:
|
||||
return data_l.toDouble() < data_r.toDouble();
|
||||
case QVariant::Type::Date:
|
||||
return data_l.toDate() < data_r.toDate();
|
||||
case QVariant::Type::Time:
|
||||
return data_l.toTime() < data_r.toTime();
|
||||
case QVariant::Type::DateTime:
|
||||
return data_l.toDateTime() < data_r.toDateTime();
|
||||
case QVariant::Type::Char:
|
||||
case QVariant::Type::String:
|
||||
return data_l.toString() < data_r.toString();
|
||||
default:
|
||||
throw std::runtime_error("unsupported type");
|
||||
}
|
||||
}
|
||||
|
||||
void custom_table_widget_item::setData(int role, const QVariant& value, bool assign_sort_role)
|
||||
{
|
||||
if (assign_sort_role)
|
||||
{
|
||||
m_sort_role = role;
|
||||
}
|
||||
QTableWidgetItem::setData(role, value);
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#pragma once
|
||||
#include "game_list_item.h"
|
||||
#include <QTableWidgetItem>
|
||||
|
||||
class custom_table_widget_item : public game_list_item
|
||||
{
|
||||
private:
|
||||
int m_sort_role = Qt::DisplayRole;
|
||||
|
||||
public:
|
||||
using QTableWidgetItem::setData;
|
||||
|
||||
custom_table_widget_item() = default;
|
||||
custom_table_widget_item(const std::string& text, int sort_role = Qt::DisplayRole, const QVariant& sort_value = 0);
|
||||
custom_table_widget_item(const QString& text, int sort_role = Qt::DisplayRole, const QVariant& sort_value = 0);
|
||||
|
||||
bool operator<(const QTableWidgetItem& other) const override;
|
||||
|
||||
void setData(int role, const QVariant& value, bool assign_sort_role);
|
||||
};
|
|
@ -1,783 +0,0 @@
|
|||
#include "game_list_frame.h"
|
||||
#include "gui_settings.h"
|
||||
#include "custom_table_widget_item.h"
|
||||
#include "qt_utils.h"
|
||||
#include "../emulator/fileFormat/PSF.h"
|
||||
#include <QPainter>
|
||||
#include <unordered_set>
|
||||
|
||||
game_list_frame::game_list_frame(std::shared_ptr<gui_settings> gui_settings, QWidget* parent)
|
||||
: custom_dock_widget(tr("Game List"), parent)
|
||||
, m_gui_settings(std::move(gui_settings))
|
||||
{
|
||||
m_icon_size = gui::game_list_icon_size_min; // ensure a valid size
|
||||
m_is_list_layout = m_gui_settings->GetValue(gui::game_list_listMode).toBool();
|
||||
m_margin_factor = m_gui_settings->GetValue(gui::game_list_marginFactor).toReal();
|
||||
m_text_factor = m_gui_settings->GetValue(gui::game_list_textFactor).toReal();
|
||||
m_icon_color = m_gui_settings->GetValue(gui::game_list_iconColor).value<QColor>();
|
||||
m_col_sort_order = m_gui_settings->GetValue(gui::game_list_sortAsc).toBool() ? Qt::AscendingOrder : Qt::DescendingOrder;
|
||||
m_sort_column = m_gui_settings->GetValue(gui::game_list_sortCol).toInt();
|
||||
|
||||
m_old_layout_is_list = m_is_list_layout;
|
||||
|
||||
// Save factors for first setup
|
||||
m_gui_settings->SetValue(gui::game_list_iconColor, m_icon_color);
|
||||
m_gui_settings->SetValue(gui::game_list_marginFactor, m_margin_factor);
|
||||
m_gui_settings->SetValue(gui::game_list_textFactor, m_text_factor);
|
||||
|
||||
m_game_dock = new QMainWindow(this);
|
||||
m_game_dock->setWindowFlags(Qt::Widget);
|
||||
setWidget(m_game_dock);
|
||||
|
||||
m_game_grid = new game_list_grid(QSize(), m_icon_color, m_margin_factor, m_text_factor, false);
|
||||
|
||||
m_game_list = new game_list_table();
|
||||
m_game_list->setShowGrid(false);
|
||||
m_game_list->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
m_game_list->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
m_game_list->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_game_list->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
m_game_list->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
m_game_list->verticalScrollBar()->installEventFilter(this);
|
||||
m_game_list->verticalScrollBar()->setSingleStep(20);
|
||||
m_game_list->horizontalScrollBar()->setSingleStep(20);
|
||||
m_game_list->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
|
||||
m_game_list->verticalHeader()->setVisible(false);
|
||||
m_game_list->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
m_game_list->horizontalHeader()->setHighlightSections(false);
|
||||
m_game_list->horizontalHeader()->setSortIndicatorShown(true);
|
||||
m_game_list->horizontalHeader()->setStretchLastSection(true);
|
||||
m_game_list->horizontalHeader()->setDefaultSectionSize(150);
|
||||
m_game_list->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
|
||||
m_game_list->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
m_game_list->setAlternatingRowColors(true);
|
||||
m_game_list->installEventFilter(this);
|
||||
m_game_list->setColumnCount(gui::column_count);
|
||||
|
||||
m_central_widget = new QStackedWidget(this);
|
||||
m_central_widget->addWidget(m_game_list);
|
||||
m_central_widget->addWidget(m_game_grid);
|
||||
m_central_widget->setCurrentWidget(m_is_list_layout ? m_game_list : m_game_grid);
|
||||
|
||||
m_game_dock->setCentralWidget(m_central_widget);
|
||||
|
||||
// Actions regarding showing/hiding columns
|
||||
auto add_column = [this](gui::game_list_columns col, const QString& header_text, const QString& action_text)
|
||||
{
|
||||
m_game_list->setHorizontalHeaderItem(col, new QTableWidgetItem(header_text));
|
||||
m_columnActs.append(new QAction(action_text, this));
|
||||
};
|
||||
|
||||
add_column(gui::column_icon, tr("Icon"), tr("Show Icons"));
|
||||
add_column(gui::column_name, tr("Name"), tr("Show Names"));
|
||||
add_column(gui::column_serial, tr("Serial"), tr("Show Serials"));
|
||||
add_column(gui::column_firmware, tr("Firmware"), tr("Show Firmwares"));
|
||||
add_column(gui::column_version, tr("Version"), tr("Show Versions"));
|
||||
add_column(gui::column_category, tr("Category"), tr("Show Categories"));
|
||||
add_column(gui::column_path, tr("Path"), tr("Show Paths"));
|
||||
|
||||
for (int col = 0; col < m_columnActs.count(); ++col)
|
||||
{
|
||||
m_columnActs[col]->setCheckable(true);
|
||||
|
||||
connect(m_columnActs[col], &QAction::triggered, this, [this, col](bool checked)
|
||||
{
|
||||
if (!checked) // be sure to have at least one column left so you can call the context menu at all time
|
||||
{
|
||||
int c = 0;
|
||||
for (int i = 0; i < m_columnActs.count(); ++i)
|
||||
{
|
||||
if (m_gui_settings->GetGamelistColVisibility(i) && ++c > 1)
|
||||
break;
|
||||
}
|
||||
if (c < 2)
|
||||
{
|
||||
m_columnActs[col]->setChecked(true); // re-enable the checkbox if we don't change the actual state
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_game_list->setColumnHidden(col, !checked); // Negate because it's a set col hidden and we have menu say show.
|
||||
m_gui_settings->SetGamelistColVisibility(col, checked);
|
||||
|
||||
if (checked) // handle hidden columns that have zero width after showing them (stuck between others)
|
||||
{
|
||||
FixNarrowColumns();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//events
|
||||
connect(m_game_list->horizontalHeader(), &QHeaderView::customContextMenuRequested, this, [this](const QPoint& pos)
|
||||
{
|
||||
QMenu* configure = new QMenu(this);
|
||||
configure->addActions(m_columnActs);
|
||||
configure->exec(m_game_list->horizontalHeader()->viewport()->mapToGlobal(pos));
|
||||
});
|
||||
connect(m_game_list->horizontalHeader(), &QHeaderView::sectionClicked, this, &game_list_frame::OnHeaderColumnClicked);
|
||||
connect(&m_repaint_watcher, &QFutureWatcher<game_list_item*>::resultReadyAt, this, [this](int index)
|
||||
{
|
||||
if (!m_is_list_layout) return;
|
||||
if (game_list_item* item = m_repaint_watcher.resultAt(index))
|
||||
{
|
||||
item->call_icon_func();
|
||||
}
|
||||
});
|
||||
connect(&m_repaint_watcher, &QFutureWatcher<game_list_item*>::finished, this, &game_list_frame::OnRepaintFinished);
|
||||
|
||||
connect(&m_refresh_watcher, &QFutureWatcher<void>::finished, this, &game_list_frame::OnRefreshFinished);
|
||||
connect(&m_refresh_watcher, &QFutureWatcher<void>::canceled, this, [this]()
|
||||
{
|
||||
gui::utils::stop_future_watcher(m_repaint_watcher, true);
|
||||
|
||||
m_path_list.clear();
|
||||
m_game_data.clear();
|
||||
m_games.clear();
|
||||
});
|
||||
}
|
||||
game_list_frame::~game_list_frame() {
|
||||
gui::utils::stop_future_watcher(m_repaint_watcher, true);
|
||||
gui::utils::stop_future_watcher(m_refresh_watcher, true);
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
void game_list_frame::OnRefreshFinished()
|
||||
{
|
||||
gui::utils::stop_future_watcher(m_repaint_watcher, true);
|
||||
for (auto&& g : m_games)
|
||||
{
|
||||
m_game_data.push_back(g);
|
||||
}
|
||||
m_games.clear();
|
||||
// Sort by name at the very least.
|
||||
std::sort(m_game_data.begin(), m_game_data.end(), [&](const game_info& game1, const game_info& game2)
|
||||
{
|
||||
const QString title1 = m_titles.value(QString::fromStdString(game1->info.serial), QString::fromStdString(game1->info.name));
|
||||
const QString title2 = m_titles.value(QString::fromStdString(game2->info.serial), QString::fromStdString(game2->info.name));
|
||||
return title1.toLower() < title2.toLower();
|
||||
});
|
||||
|
||||
m_path_list.clear();
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void game_list_frame::OnRepaintFinished()
|
||||
{
|
||||
if (m_is_list_layout)
|
||||
{
|
||||
// Fixate vertical header and row height
|
||||
m_game_list->verticalHeader()->setMinimumSectionSize(m_icon_size.height());
|
||||
m_game_list->verticalHeader()->setMaximumSectionSize(m_icon_size.height());
|
||||
|
||||
// Resize the icon column
|
||||
m_game_list->resizeColumnToContents(gui::column_icon);
|
||||
|
||||
// Shorten the last section to remove horizontal scrollbar if possible
|
||||
m_game_list->resizeColumnToContents(gui::column_count - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The game grid needs to be recreated from scratch
|
||||
int games_per_row = 0;
|
||||
|
||||
if (m_icon_size.width() > 0 && m_icon_size.height() > 0)
|
||||
{
|
||||
games_per_row = width() / (m_icon_size.width() + m_icon_size.width() * m_game_grid->getMarginFactor() * 2);
|
||||
}
|
||||
|
||||
const int scroll_position = m_game_grid->verticalScrollBar()->value();
|
||||
//TODO add connections
|
||||
PopulateGameGrid(games_per_row, m_icon_size, m_icon_color);
|
||||
m_central_widget->addWidget(m_game_grid);
|
||||
m_central_widget->setCurrentWidget(m_game_grid);
|
||||
m_game_grid->verticalScrollBar()->setValue(scroll_position);
|
||||
}
|
||||
}
|
||||
|
||||
bool game_list_frame::IsEntryVisible(const game_info& game)
|
||||
{
|
||||
const QString serial = QString::fromStdString(game->info.serial);
|
||||
return SearchMatchesApp(QString::fromStdString(game->info.name), serial);
|
||||
}
|
||||
|
||||
void game_list_frame::PopulateGameGrid(int maxCols, const QSize& image_size, const QColor& image_color)
|
||||
{
|
||||
int r = 0;
|
||||
int c = 0;
|
||||
|
||||
const std::string selected_item = CurrentSelectionPath();
|
||||
|
||||
// Release old data
|
||||
m_game_list->clear_list();
|
||||
m_game_grid->deleteLater();
|
||||
|
||||
const bool show_text = m_icon_size_index > gui::game_list_max_slider_pos * 2 / 5;
|
||||
|
||||
if (m_icon_size_index < gui::game_list_max_slider_pos * 2 / 3)
|
||||
{
|
||||
m_game_grid = new game_list_grid(image_size, image_color, m_margin_factor, m_text_factor * 2, show_text);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_game_grid = new game_list_grid(image_size, image_color, m_margin_factor, m_text_factor, show_text);
|
||||
}
|
||||
|
||||
// Get list of matching apps
|
||||
QList<game_info> matching_apps;
|
||||
|
||||
for (const auto& app : m_game_data)
|
||||
{
|
||||
if (IsEntryVisible(app))
|
||||
{
|
||||
matching_apps.push_back(app);
|
||||
}
|
||||
}
|
||||
|
||||
const int entries = matching_apps.count();
|
||||
|
||||
// Edge cases!
|
||||
if (entries == 0)
|
||||
{ // For whatever reason, 0%x is division by zero. Absolute nonsense by definition of modulus. But, I'll acquiesce.
|
||||
return;
|
||||
}
|
||||
|
||||
maxCols = std::clamp(maxCols, 1, entries);
|
||||
|
||||
const int needs_extra_row = (entries % maxCols) != 0;
|
||||
const int max_rows = needs_extra_row + entries / maxCols;
|
||||
m_game_grid->setRowCount(max_rows);
|
||||
m_game_grid->setColumnCount(maxCols);
|
||||
|
||||
for (const auto& app : matching_apps)
|
||||
{
|
||||
const QString serial = QString::fromStdString(app->info.serial);
|
||||
const QString title = m_titles.value(serial, QString::fromStdString(app->info.name));
|
||||
|
||||
game_list_item* item = m_game_grid->addItem(app, title, r, c);
|
||||
app->item = item;
|
||||
item->setData(gui::game_role, QVariant::fromValue(app));
|
||||
|
||||
item->setToolTip(tr("%0 [%1]").arg(title).arg(serial));
|
||||
|
||||
|
||||
if (selected_item == app->info.path + app->info.icon_path)
|
||||
{
|
||||
m_game_grid->setCurrentItem(item);
|
||||
}
|
||||
|
||||
if (++c >= maxCols)
|
||||
{
|
||||
c = 0;
|
||||
r++;
|
||||
}
|
||||
}
|
||||
|
||||
if (c != 0)
|
||||
{ // if left over games exist -- if empty entries exist
|
||||
for (int col = c; col < maxCols; ++col)
|
||||
{
|
||||
game_list_item* empty_item = new game_list_item();
|
||||
empty_item->setFlags(Qt::NoItemFlags);
|
||||
m_game_grid->setItem(r, col, empty_item);
|
||||
}
|
||||
}
|
||||
|
||||
m_game_grid->resizeColumnsToContents();
|
||||
m_game_grid->resizeRowsToContents();
|
||||
m_game_grid->installEventFilter(this);
|
||||
m_game_grid->verticalScrollBar()->installEventFilter(this);
|
||||
}
|
||||
void game_list_frame::Refresh(const bool from_drive, const bool scroll_after)
|
||||
{
|
||||
gui::utils::stop_future_watcher(m_repaint_watcher, true);
|
||||
gui::utils::stop_future_watcher(m_refresh_watcher, from_drive);
|
||||
|
||||
if (from_drive)
|
||||
{
|
||||
m_path_list.clear();
|
||||
m_game_data.clear();
|
||||
m_games.clear();
|
||||
|
||||
//TODO better ATM manually add path from 1 dir to m_paths_list
|
||||
QDir parent_folder(QString::fromStdString(QDir::currentPath().toStdString() + "/game/"));
|
||||
QFileInfoList fList = parent_folder.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::DirsFirst);
|
||||
foreach(QFileInfo item, fList)
|
||||
{
|
||||
m_path_list.emplace_back(item.absoluteFilePath().toStdString());
|
||||
}
|
||||
|
||||
m_refresh_watcher.setFuture(QtConcurrent::map(m_path_list, [this](const std::string& dir)
|
||||
{
|
||||
GameInfo game{};
|
||||
game.path = dir;
|
||||
PSF psf;
|
||||
if (psf.open(game.path + "/sce_sys/PARAM.SFO"))
|
||||
{
|
||||
QString iconpath(QString::fromStdString(game.path) + "/sce_sys/ICON0.PNG");
|
||||
game.icon_path = iconpath.toStdString();
|
||||
game.name = psf.get_string("TITLE");
|
||||
game.serial = psf.get_string("TITLE_ID");
|
||||
game.fw = (QString("%1").arg(psf.get_integer("SYSTEM_VER"), 8, 16, QLatin1Char('0'))).mid(1, 3).insert(1, '.').toStdString();
|
||||
game.version = psf.get_string("APP_VER");
|
||||
game.category = psf.get_string("CATEGORY");
|
||||
|
||||
m_titles.insert(QString::fromStdString(game.serial), QString::fromStdString(game.name));
|
||||
|
||||
gui_game_info info{};
|
||||
info.info = game;
|
||||
|
||||
m_games.push_back(std::make_shared<gui_game_info>(std::move(info)));
|
||||
}
|
||||
|
||||
}));
|
||||
return;
|
||||
}
|
||||
// Fill Game List / Game Grid
|
||||
|
||||
if (m_is_list_layout)
|
||||
{
|
||||
const int scroll_position = m_game_list->verticalScrollBar()->value();
|
||||
PopulateGameList();
|
||||
SortGameList();
|
||||
RepaintIcons();
|
||||
|
||||
if (scroll_after)
|
||||
{
|
||||
m_game_list->scrollTo(m_game_list->currentIndex(), QAbstractItemView::PositionAtCenter);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_game_list->verticalScrollBar()->setValue(scroll_position);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RepaintIcons();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
/**
|
||||
Cleans and readds entries to table widget in UI.
|
||||
*/
|
||||
void game_list_frame::PopulateGameList()
|
||||
{
|
||||
int selected_row = -1;
|
||||
|
||||
const std::string selected_item = CurrentSelectionPath();
|
||||
|
||||
// Release old data
|
||||
m_game_grid->clear_list();
|
||||
m_game_list->clear_list();
|
||||
|
||||
m_game_list->setRowCount(m_game_data.size());
|
||||
|
||||
int row = 0;
|
||||
int index = -1;
|
||||
for (const auto& game : m_game_data)
|
||||
{
|
||||
index++;
|
||||
|
||||
if (!IsEntryVisible(game))
|
||||
{
|
||||
game->item = nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
const QString serial = QString::fromStdString(game->info.serial);
|
||||
const QString title = m_titles.value(serial, QString::fromStdString(game->info.name));
|
||||
|
||||
// Icon
|
||||
custom_table_widget_item* icon_item = new custom_table_widget_item;
|
||||
game->item = icon_item;
|
||||
icon_item->set_icon_func([this, icon_item, game](int)
|
||||
{
|
||||
icon_item->setData(Qt::DecorationRole, game->pxmap);
|
||||
game->pxmap = {};
|
||||
});
|
||||
|
||||
icon_item->setData(Qt::UserRole, index, true);
|
||||
icon_item->setData(gui::custom_roles::game_role, QVariant::fromValue(game));
|
||||
|
||||
// Title
|
||||
custom_table_widget_item* title_item = new custom_table_widget_item(title);
|
||||
|
||||
// Serial
|
||||
custom_table_widget_item* serial_item = new custom_table_widget_item(serial);
|
||||
|
||||
// Version
|
||||
QString app_version = QString::fromStdString(game->info.version);
|
||||
|
||||
m_game_list->setItem(row, gui::column_icon, icon_item);
|
||||
m_game_list->setItem(row, gui::column_name, title_item);
|
||||
m_game_list->setItem(row, gui::column_serial, serial_item);
|
||||
m_game_list->setItem(row, gui::column_firmware, new custom_table_widget_item(game->info.fw));
|
||||
m_game_list->setItem(row, gui::column_version, new custom_table_widget_item(app_version));
|
||||
m_game_list->setItem(row, gui::column_category, new custom_table_widget_item(game->info.category));
|
||||
m_game_list->setItem(row, gui::column_path, new custom_table_widget_item(game->info.path));
|
||||
|
||||
if (selected_item == game->info.path + game->info.icon_path)
|
||||
{
|
||||
selected_row = row;
|
||||
}
|
||||
|
||||
row++;
|
||||
}
|
||||
m_game_list->setRowCount(row);
|
||||
m_game_list->selectRow(selected_row);
|
||||
}
|
||||
|
||||
std::string game_list_frame::CurrentSelectionPath()
|
||||
{
|
||||
std::string selection;
|
||||
|
||||
QTableWidgetItem* item = nullptr;
|
||||
|
||||
if (m_old_layout_is_list)
|
||||
{
|
||||
if (!m_game_list->selectedItems().isEmpty())
|
||||
{
|
||||
item = m_game_list->item(m_game_list->currentRow(), 0);
|
||||
}
|
||||
}
|
||||
else if (m_game_grid)
|
||||
{
|
||||
if (!m_game_grid->selectedItems().isEmpty())
|
||||
{
|
||||
item = m_game_grid->currentItem();
|
||||
}
|
||||
}
|
||||
|
||||
if (item)
|
||||
{
|
||||
if (const QVariant var = item->data(gui::game_role); var.canConvert<game_info>())
|
||||
{
|
||||
if (const game_info game = var.value<game_info>())
|
||||
{
|
||||
selection = game->info.path + game->info.icon_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_old_layout_is_list = m_is_list_layout;
|
||||
|
||||
return selection;
|
||||
}
|
||||
|
||||
void game_list_frame::RepaintIcons(const bool& from_settings)
|
||||
{
|
||||
gui::utils::stop_future_watcher(m_repaint_watcher, true);
|
||||
|
||||
if (from_settings)
|
||||
{
|
||||
//TODO m_icon_color = gui::utils::get_label_color("gamelist_icon_background_color");
|
||||
}
|
||||
|
||||
if (m_is_list_layout)
|
||||
{
|
||||
QPixmap placeholder(m_icon_size);
|
||||
placeholder.fill(Qt::transparent);
|
||||
|
||||
for (auto& game : m_game_data)
|
||||
{
|
||||
game->pxmap = placeholder;
|
||||
}
|
||||
|
||||
// Fixate vertical header and row height
|
||||
m_game_list->verticalHeader()->setMinimumSectionSize(m_icon_size.height());
|
||||
m_game_list->verticalHeader()->setMaximumSectionSize(m_icon_size.height());
|
||||
|
||||
// Resize the icon column
|
||||
m_game_list->resizeColumnToContents(gui::column_icon);
|
||||
|
||||
// Shorten the last section to remove horizontal scrollbar if possible
|
||||
m_game_list->resizeColumnToContents(gui::column_count - 1);
|
||||
}
|
||||
|
||||
const std::function func = [this](const game_info& game) -> game_list_item*
|
||||
{
|
||||
if (game->icon.isNull() && (game->info.icon_path.empty() || !game->icon.load(QString::fromStdString(game->info.icon_path))))
|
||||
{
|
||||
//TODO added warning message if no found
|
||||
}
|
||||
game->pxmap = PaintedPixmap(game->icon);
|
||||
return game->item;
|
||||
};
|
||||
m_repaint_watcher.setFuture(QtConcurrent::mapped(m_game_data, func));
|
||||
}
|
||||
|
||||
void game_list_frame::FixNarrowColumns() const
|
||||
{
|
||||
qApp->processEvents();
|
||||
|
||||
// handle columns (other than the icon column) that have zero width after showing them (stuck between others)
|
||||
for (int col = 1; col < m_columnActs.count(); ++col)
|
||||
{
|
||||
if (m_game_list->isColumnHidden(col))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_game_list->columnWidth(col) <= m_game_list->horizontalHeader()->minimumSectionSize())
|
||||
{
|
||||
m_game_list->setColumnWidth(col, m_game_list->horizontalHeader()->minimumSectionSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void game_list_frame::ResizeColumnsToContents(int spacing) const
|
||||
{
|
||||
if (!m_game_list)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_game_list->verticalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents);
|
||||
m_game_list->horizontalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents);
|
||||
|
||||
// Make non-icon columns slighty bigger for better visuals
|
||||
for (int i = 1; i < m_game_list->columnCount(); i++)
|
||||
{
|
||||
if (m_game_list->isColumnHidden(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const int size = m_game_list->horizontalHeader()->sectionSize(i) + spacing;
|
||||
m_game_list->horizontalHeader()->resizeSection(i, size);
|
||||
}
|
||||
}
|
||||
|
||||
void game_list_frame::OnHeaderColumnClicked(int col)
|
||||
{
|
||||
if (col == 0) return; // Don't "sort" icons.
|
||||
|
||||
if (col == m_sort_column)
|
||||
{
|
||||
m_col_sort_order = (m_col_sort_order == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_col_sort_order = Qt::AscendingOrder;
|
||||
}
|
||||
m_sort_column = col;
|
||||
|
||||
m_gui_settings->SetValue(gui::game_list_sortAsc, m_col_sort_order == Qt::AscendingOrder);
|
||||
m_gui_settings->SetValue(gui::game_list_sortCol, col);
|
||||
|
||||
SortGameList();
|
||||
}
|
||||
|
||||
void game_list_frame::SortGameList() const
|
||||
{
|
||||
// Back-up old header sizes to handle unwanted column resize in case of zero search results
|
||||
QList<int> column_widths;
|
||||
const int old_row_count = m_game_list->rowCount();
|
||||
const int old_game_count = m_game_data.count();
|
||||
|
||||
for (int i = 0; i < m_game_list->columnCount(); i++)
|
||||
{
|
||||
column_widths.append(m_game_list->columnWidth(i));
|
||||
}
|
||||
|
||||
// Sorting resizes hidden columns, so unhide them as a workaround
|
||||
QList<int> columns_to_hide;
|
||||
|
||||
for (int i = 0; i < m_game_list->columnCount(); i++)
|
||||
{
|
||||
if (m_game_list->isColumnHidden(i))
|
||||
{
|
||||
m_game_list->setColumnHidden(i, false);
|
||||
columns_to_hide << i;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the list by column and sort order
|
||||
m_game_list->sortByColumn(m_sort_column, m_col_sort_order);
|
||||
|
||||
// Hide columns again
|
||||
for (auto i : columns_to_hide)
|
||||
{
|
||||
m_game_list->setColumnHidden(i, true);
|
||||
}
|
||||
|
||||
// Don't resize the columns if no game is shown to preserve the header settings
|
||||
if (!m_game_list->rowCount())
|
||||
{
|
||||
for (int i = 0; i < m_game_list->columnCount(); i++)
|
||||
{
|
||||
m_game_list->setColumnWidth(i, column_widths[i]);
|
||||
}
|
||||
|
||||
m_game_list->horizontalHeader()->setSectionResizeMode(gui::column_icon, QHeaderView::Fixed);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fixate vertical header and row height
|
||||
m_game_list->verticalHeader()->setMinimumSectionSize(m_icon_size.height());
|
||||
m_game_list->verticalHeader()->setMaximumSectionSize(m_icon_size.height());
|
||||
m_game_list->resizeRowsToContents();
|
||||
|
||||
// Resize columns if the game list was empty before
|
||||
if (!old_row_count && !old_game_count)
|
||||
{
|
||||
ResizeColumnsToContents();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_game_list->resizeColumnToContents(gui::column_icon);
|
||||
}
|
||||
|
||||
// Fixate icon column
|
||||
m_game_list->horizontalHeader()->setSectionResizeMode(gui::column_icon, QHeaderView::Fixed);
|
||||
|
||||
// Shorten the last section to remove horizontal scrollbar if possible
|
||||
m_game_list->resizeColumnToContents(gui::column_count - 1);
|
||||
}
|
||||
|
||||
QPixmap game_list_frame::PaintedPixmap(const QPixmap& icon) const
|
||||
{
|
||||
const qreal device_pixel_ratio = devicePixelRatioF();
|
||||
QSize canvas_size(320, 176);
|
||||
QSize icon_size(icon.size());
|
||||
QPoint target_pos;
|
||||
|
||||
if (!icon.isNull())
|
||||
{
|
||||
// Let's upscale the original icon to at least fit into the outer rect of the size of PS3's ICON0.PNG
|
||||
if (icon_size.width() < 320 || icon_size.height() < 176)
|
||||
{
|
||||
icon_size.scale(320, 176, Qt::KeepAspectRatio);
|
||||
}
|
||||
|
||||
canvas_size = icon_size;
|
||||
|
||||
// Calculate the centered size and position of the icon on our canvas.
|
||||
if (icon_size.width() != 320 || icon_size.height() != 176)
|
||||
{
|
||||
constexpr double target_ratio = 320.0 / 176.0; // aspect ratio 20:11
|
||||
|
||||
if ((icon_size.width() / static_cast<double>(icon_size.height())) > target_ratio)
|
||||
{
|
||||
canvas_size.setHeight(std::ceil(icon_size.width() / target_ratio));
|
||||
}
|
||||
else
|
||||
{
|
||||
canvas_size.setWidth(std::ceil(icon_size.height() * target_ratio));
|
||||
}
|
||||
|
||||
target_pos.setX(std::max<int>(0, (canvas_size.width() - icon_size.width()) / 2.0));
|
||||
target_pos.setY(std::max<int>(0, (canvas_size.height() - icon_size.height()) / 2.0));
|
||||
}
|
||||
}
|
||||
|
||||
// Create a canvas large enough to fit our entire scaled icon
|
||||
QPixmap canvas(canvas_size * device_pixel_ratio);
|
||||
canvas.setDevicePixelRatio(device_pixel_ratio);
|
||||
canvas.fill(m_icon_color);
|
||||
|
||||
// Create a painter for our canvas
|
||||
QPainter painter(&canvas);
|
||||
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
|
||||
// Draw the icon onto our canvas
|
||||
if (!icon.isNull())
|
||||
{
|
||||
painter.drawPixmap(target_pos.x(), target_pos.y(), icon_size.width(), icon_size.height(), icon);
|
||||
}
|
||||
|
||||
// Finish the painting
|
||||
painter.end();
|
||||
|
||||
// Scale and return our final image
|
||||
return canvas.scaled(m_icon_size * device_pixel_ratio, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation);
|
||||
}
|
||||
void game_list_frame::SetListMode(const bool& is_list)
|
||||
{
|
||||
m_old_layout_is_list = m_is_list_layout;
|
||||
m_is_list_layout = is_list;
|
||||
|
||||
m_gui_settings->SetValue(gui::game_list_listMode, is_list);
|
||||
|
||||
Refresh(true);
|
||||
|
||||
m_central_widget->setCurrentWidget(m_is_list_layout ? m_game_list : m_game_grid);
|
||||
}
|
||||
void game_list_frame::SetSearchText(const QString& text)
|
||||
{
|
||||
m_search_text = text;
|
||||
Refresh();
|
||||
}
|
||||
void game_list_frame::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
QDockWidget::closeEvent(event);
|
||||
Q_EMIT GameListFrameClosed();
|
||||
}
|
||||
|
||||
void game_list_frame::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
if (!m_is_list_layout)
|
||||
{
|
||||
Refresh(false, m_game_grid->selectedItems().count());
|
||||
}
|
||||
QDockWidget::resizeEvent(event);
|
||||
}
|
||||
void game_list_frame::ResizeIcons(const int& slider_pos)
|
||||
{
|
||||
m_icon_size_index = slider_pos;
|
||||
m_icon_size = gui_settings::SizeFromSlider(slider_pos);
|
||||
|
||||
RepaintIcons();
|
||||
}
|
||||
|
||||
void game_list_frame::LoadSettings()
|
||||
{
|
||||
m_col_sort_order = m_gui_settings->GetValue(gui::game_list_sortAsc).toBool() ? Qt::AscendingOrder : Qt::DescendingOrder;
|
||||
m_sort_column = m_gui_settings->GetValue(gui::game_list_sortCol).toInt();
|
||||
|
||||
Refresh(true);
|
||||
|
||||
const QByteArray state = m_gui_settings->GetValue(gui::game_list_state).toByteArray();
|
||||
if (!m_game_list->horizontalHeader()->restoreState(state) && m_game_list->rowCount())
|
||||
{
|
||||
// If no settings exist, resize to contents.
|
||||
ResizeColumnsToContents();
|
||||
}
|
||||
|
||||
for (int col = 0; col < m_columnActs.count(); ++col)
|
||||
{
|
||||
const bool vis = m_gui_settings->GetGamelistColVisibility(col);
|
||||
m_columnActs[col]->setChecked(vis);
|
||||
m_game_list->setColumnHidden(col, !vis);
|
||||
}
|
||||
SortGameList();
|
||||
FixNarrowColumns();
|
||||
|
||||
m_game_list->horizontalHeader()->restoreState(m_game_list->horizontalHeader()->saveState());
|
||||
|
||||
}
|
||||
|
||||
void game_list_frame::SaveSettings()
|
||||
{
|
||||
for (int col = 0; col < m_columnActs.count(); ++col)
|
||||
{
|
||||
m_gui_settings->SetGamelistColVisibility(col, m_columnActs[col]->isChecked());
|
||||
}
|
||||
m_gui_settings->SetValue(gui::game_list_sortCol, m_sort_column);
|
||||
m_gui_settings->SetValue(gui::game_list_sortAsc, m_col_sort_order == Qt::AscendingOrder);
|
||||
m_gui_settings->SetValue(gui::game_list_state, m_game_list->horizontalHeader()->saveState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if the game should be hidden because it doesn't match search term in toolbar.
|
||||
*/
|
||||
bool game_list_frame::SearchMatchesApp(const QString& name, const QString& serial) const
|
||||
{
|
||||
if (!m_search_text.isEmpty())
|
||||
{
|
||||
const QString search_text = m_search_text.toLower();
|
||||
return m_titles.value(serial, name).toLower().contains(search_text) || serial.toLower().contains(search_text);
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "game_list_table.h"
|
||||
#include "custom_dock_widget.h"
|
||||
#include "shadps4gui.h"
|
||||
#include "game_list_grid.h"
|
||||
#include "game_list_item.h"
|
||||
#include <QHeaderView>
|
||||
#include <QScrollbar>
|
||||
#include <QStackedWidget>
|
||||
#include <QWidget>
|
||||
#include <deque>
|
||||
#include <QFutureWatcher>
|
||||
#include <QtConcurrent>
|
||||
|
||||
class game_list_frame : public custom_dock_widget
|
||||
{
|
||||
Q_OBJECT
|
||||
public :
|
||||
explicit game_list_frame(std::shared_ptr<gui_settings> gui_settings,QWidget* parent = nullptr);
|
||||
~game_list_frame();
|
||||
/** Fix columns with width smaller than the minimal section size */
|
||||
void FixNarrowColumns() const;
|
||||
|
||||
/** Loads from settings. Public so that main frame can easily reset these settings if needed. */
|
||||
void LoadSettings();
|
||||
|
||||
/** Saves settings. Public so that main frame can save this when a caching of column widths is needed for settings backup */
|
||||
void SaveSettings();
|
||||
|
||||
/** Resizes the columns to their contents and adds a small spacing */
|
||||
void ResizeColumnsToContents(int spacing = 20) const;
|
||||
|
||||
/** Refresh the gamelist with/without loading game data from files. Public so that main frame can refresh after vfs or install */
|
||||
void Refresh(const bool from_drive = false, const bool scroll_after = true);
|
||||
|
||||
/** Repaint Gamelist Icons with new background color */
|
||||
void RepaintIcons(const bool& from_settings = false);
|
||||
|
||||
/** Resize Gamelist Icons to size given by slider position */
|
||||
void ResizeIcons(const int& slider_pos);
|
||||
|
||||
public Q_SLOTS:
|
||||
void SetSearchText(const QString& text);
|
||||
void SetListMode(const bool& is_list);
|
||||
private Q_SLOTS:
|
||||
void OnHeaderColumnClicked(int col);
|
||||
void OnRepaintFinished();
|
||||
void OnRefreshFinished();
|
||||
Q_SIGNALS:
|
||||
void GameListFrameClosed();
|
||||
void RequestIconSizeChange(const int& val);
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
private:
|
||||
QPixmap PaintedPixmap(const QPixmap& icon) const;
|
||||
void SortGameList() const;
|
||||
std::string CurrentSelectionPath();
|
||||
void PopulateGameList();
|
||||
void PopulateGameGrid(int maxCols, const QSize& image_size, const QColor& image_color);
|
||||
bool SearchMatchesApp(const QString& name, const QString& serial) const;
|
||||
bool IsEntryVisible(const game_info& game);
|
||||
|
||||
// Which widget we are displaying depends on if we are in grid or list mode.
|
||||
QMainWindow* m_game_dock = nullptr;
|
||||
QStackedWidget* m_central_widget = nullptr;
|
||||
|
||||
// Game Grid
|
||||
game_list_grid* m_game_grid = nullptr;
|
||||
|
||||
// Game List
|
||||
game_list_table* m_game_list = nullptr;
|
||||
QList<QAction*> m_columnActs;
|
||||
Qt::SortOrder m_col_sort_order;
|
||||
int m_sort_column;
|
||||
QMap<QString, QString> m_titles;
|
||||
|
||||
// List Mode
|
||||
bool m_is_list_layout = true;
|
||||
bool m_old_layout_is_list = true;
|
||||
|
||||
// data
|
||||
std::shared_ptr<gui_settings> m_gui_settings;
|
||||
QList<game_info> m_game_data;
|
||||
std::vector<std::string> m_path_list;
|
||||
std::deque<game_info> m_games;
|
||||
QFutureWatcher<game_list_item*> m_repaint_watcher;
|
||||
QFutureWatcher<void> m_refresh_watcher;
|
||||
|
||||
// Search
|
||||
QString m_search_text;
|
||||
|
||||
// Icon Size
|
||||
int m_icon_size_index = 0;
|
||||
|
||||
// Icons
|
||||
QSize m_icon_size;
|
||||
QColor m_icon_color;
|
||||
qreal m_margin_factor;
|
||||
qreal m_text_factor;
|
||||
|
||||
};
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
#include "game_list_grid.h"
|
||||
#include "game_list_grid_delegate.h"
|
||||
#include "game_list_item.h"
|
||||
#include <QHeaderView>
|
||||
#include <QScrollBar>
|
||||
|
||||
game_list_grid::game_list_grid(const QSize& icon_size, QColor icon_color, const qreal& margin_factor, const qreal& text_factor, const bool& showText)
|
||||
: game_list_table()
|
||||
, m_icon_size(icon_size)
|
||||
, m_icon_color(std::move(icon_color))
|
||||
, m_margin_factor(margin_factor)
|
||||
, m_text_factor(text_factor)
|
||||
, m_text_enabled(showText)
|
||||
{
|
||||
setObjectName("game_grid");
|
||||
|
||||
QSize item_size;
|
||||
if (m_text_enabled)
|
||||
{
|
||||
item_size = m_icon_size + QSize(m_icon_size.width() * m_margin_factor * 2, m_icon_size.height() * m_margin_factor * (m_text_factor + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
item_size = m_icon_size + m_icon_size * m_margin_factor * 2;
|
||||
}
|
||||
|
||||
grid_item_delegate = new game_list_grid_delegate(item_size, m_margin_factor, m_text_factor, this);
|
||||
setItemDelegate(grid_item_delegate);
|
||||
setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
setSelectionBehavior(QAbstractItemView::SelectItems);
|
||||
setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
verticalScrollBar()->setSingleStep(20);
|
||||
horizontalScrollBar()->setSingleStep(20);
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
verticalHeader()->setVisible(false);
|
||||
horizontalHeader()->setVisible(false);
|
||||
setShowGrid(false);
|
||||
}
|
||||
|
||||
void game_list_grid::enableText(const bool& enabled)
|
||||
{
|
||||
m_text_enabled = enabled;
|
||||
}
|
||||
|
||||
void game_list_grid::setIconSize(const QSize& size) const
|
||||
{
|
||||
if (m_text_enabled)
|
||||
{
|
||||
grid_item_delegate->setItemSize(size + QSize(size.width() * m_margin_factor * 2, size.height() * m_margin_factor * (m_text_factor + 1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
grid_item_delegate->setItemSize(size + size * m_margin_factor * 2);
|
||||
}
|
||||
}
|
||||
|
||||
game_list_item* game_list_grid::addItem(const game_info& app, const QString& name,const int& row, const int& col)
|
||||
{
|
||||
game_list_item* item = new game_list_item;
|
||||
item->set_icon_func([this, app, item](int)
|
||||
{
|
||||
const qreal device_pixel_ratio = devicePixelRatioF();
|
||||
|
||||
// define size of expanded image, which is raw image size + margins
|
||||
QSizeF exp_size_f;
|
||||
if (m_text_enabled)
|
||||
{
|
||||
exp_size_f = m_icon_size + QSizeF(m_icon_size.width() * m_margin_factor * 2, m_icon_size.height() * m_margin_factor * (m_text_factor + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
exp_size_f = m_icon_size + m_icon_size * m_margin_factor * 2;
|
||||
}
|
||||
|
||||
// define offset for raw image placement
|
||||
QPoint offset(m_icon_size.width() * m_margin_factor, m_icon_size.height() * m_margin_factor);
|
||||
const QSize exp_size = (exp_size_f * device_pixel_ratio).toSize();
|
||||
|
||||
// create empty canvas for expanded image
|
||||
QImage exp_img(exp_size, QImage::Format_ARGB32);
|
||||
exp_img.setDevicePixelRatio(device_pixel_ratio);
|
||||
exp_img.fill(Qt::transparent);
|
||||
|
||||
// create background for image
|
||||
QImage bg_img(app->pxmap.size(), QImage::Format_ARGB32);
|
||||
bg_img.setDevicePixelRatio(device_pixel_ratio);
|
||||
bg_img.fill(m_icon_color);
|
||||
|
||||
// place raw image inside expanded image
|
||||
QPainter painter(&exp_img);
|
||||
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
painter.drawImage(offset, bg_img);
|
||||
painter.drawPixmap(offset, app->pxmap);
|
||||
app->pxmap = {};
|
||||
painter.end();
|
||||
|
||||
// create item with expanded image, title and position
|
||||
item->setData(Qt::ItemDataRole::DecorationRole, QPixmap::fromImage(exp_img));
|
||||
});
|
||||
if (m_text_enabled)
|
||||
{
|
||||
item->setData(Qt::ItemDataRole::DisplayRole, name);
|
||||
}
|
||||
|
||||
setItem(row, col, item);
|
||||
return item;
|
||||
}
|
||||
|
||||
qreal game_list_grid::getMarginFactor() const
|
||||
{
|
||||
return m_margin_factor;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "game_list_table.h"
|
||||
|
||||
class game_list_grid_delegate;
|
||||
|
||||
class game_list_grid : public game_list_table
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QSize m_icon_size;
|
||||
QColor m_icon_color;
|
||||
qreal m_margin_factor;
|
||||
qreal m_text_factor;
|
||||
bool m_text_enabled = true;
|
||||
|
||||
public:
|
||||
explicit game_list_grid(const QSize& icon_size, QColor icon_color, const qreal& margin_factor, const qreal& text_factor, const bool& showText);
|
||||
|
||||
void enableText(const bool& enabled);
|
||||
void setIconSize(const QSize& size) const;
|
||||
game_list_item* addItem(const game_info& app, const QString& name,const int& row, const int& col);
|
||||
|
||||
[[nodiscard]] qreal getMarginFactor() const;
|
||||
|
||||
private:
|
||||
game_list_grid_delegate* grid_item_delegate;
|
||||
};
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
#include "game_list_grid_delegate.h"
|
||||
|
||||
game_list_grid_delegate::game_list_grid_delegate(const QSize& size, const qreal& margin_factor, const qreal& text_factor, QObject* parent)
|
||||
: QStyledItemDelegate(parent), m_size(size), m_margin_factor(margin_factor), m_text_factor(text_factor)
|
||||
{
|
||||
}
|
||||
|
||||
void game_list_grid_delegate::initStyleOption(QStyleOptionViewItem* option, const QModelIndex& index) const
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
|
||||
// Remove the focus frame around selected items
|
||||
option->state &= ~QStyle::State_HasFocus;
|
||||
|
||||
// Call initStyleOption without a model index, since we want to paint the relevant data ourselves
|
||||
QStyledItemDelegate::initStyleOption(option, QModelIndex());
|
||||
}
|
||||
|
||||
void game_list_grid_delegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
const QRect r = option.rect;
|
||||
|
||||
painter->setRenderHints(QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
painter->eraseRect(r);
|
||||
|
||||
// Get title and image
|
||||
const QPixmap image = qvariant_cast<QPixmap>(index.data(Qt::DecorationRole));
|
||||
const QString title = index.data(Qt::DisplayRole).toString();
|
||||
|
||||
// Paint from our stylesheet
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
|
||||
// image
|
||||
if (image.isNull() == false)
|
||||
{
|
||||
painter->drawPixmap(option.rect, image);
|
||||
}
|
||||
|
||||
const int h = r.height() / (1 + m_margin_factor + m_margin_factor * m_text_factor);
|
||||
const int height = r.height() - h - h * m_margin_factor;
|
||||
const int top = r.bottom() - height;
|
||||
|
||||
// title
|
||||
if (option.state & QStyle::State_Selected)
|
||||
{
|
||||
painter->setPen(QPen(option.palette.color(QPalette::HighlightedText), 1, Qt::SolidLine));
|
||||
}
|
||||
else
|
||||
{
|
||||
painter->setPen(QPen(option.palette.color(QPalette::WindowText), 1, Qt::SolidLine));
|
||||
}
|
||||
|
||||
painter->setFont(option.font);
|
||||
painter->drawText(QRect(r.left(), top, r.width(), height), +Qt::TextWordWrap | +Qt::AlignCenter, title);
|
||||
}
|
||||
|
||||
QSize game_list_grid_delegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
Q_UNUSED(option)
|
||||
Q_UNUSED(index)
|
||||
return m_size;
|
||||
}
|
||||
|
||||
void game_list_grid_delegate::setItemSize(const QSize& size)
|
||||
{
|
||||
m_size = size;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
class game_list_grid_delegate : public QStyledItemDelegate
|
||||
{
|
||||
public:
|
||||
game_list_grid_delegate(const QSize& imageSize, const qreal& margin_factor, const qreal& margin_ratio, QObject* parent = nullptr);
|
||||
|
||||
void initStyleOption(QStyleOptionViewItem* option, const QModelIndex& index) const override;
|
||||
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
void setItemSize(const QSize& size);
|
||||
private:
|
||||
QSize m_size;
|
||||
qreal m_margin_factor;
|
||||
qreal m_text_factor;
|
||||
};
|
|
@ -1,44 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <QTableWidgetItem>
|
||||
#include <QObject>
|
||||
|
||||
#include <functional>
|
||||
|
||||
using icon_callback_t = std::function<void(int)>;
|
||||
|
||||
class game_list_item : public QTableWidgetItem
|
||||
{
|
||||
public:
|
||||
game_list_item() : QTableWidgetItem()
|
||||
{
|
||||
}
|
||||
game_list_item(const QString& text, int type = Type) : QTableWidgetItem(text, type)
|
||||
{
|
||||
}
|
||||
game_list_item(const QIcon& icon, const QString& text, int type = Type) : QTableWidgetItem(icon, text, type)
|
||||
{
|
||||
}
|
||||
|
||||
~game_list_item()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void call_icon_func() const
|
||||
{
|
||||
if (m_icon_callback)
|
||||
{
|
||||
m_icon_callback(0);
|
||||
}
|
||||
}
|
||||
|
||||
void set_icon_func(const icon_callback_t& func)
|
||||
{
|
||||
m_icon_callback = func;
|
||||
call_icon_func();
|
||||
}
|
||||
|
||||
private:
|
||||
icon_callback_t m_icon_callback = nullptr;
|
||||
};
|
|
@ -1,17 +0,0 @@
|
|||
#include "game_list_table.h"
|
||||
|
||||
void game_list_table ::clear_list()
|
||||
{
|
||||
clearSelection();
|
||||
clearContents();
|
||||
}
|
||||
|
||||
void game_list_table::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
if (QTableWidgetItem* item = itemAt(event->pos()); !item || !item->data(Qt::UserRole).isValid())
|
||||
{
|
||||
clearSelection();
|
||||
setCurrentItem(nullptr); // Needed for currentItemChanged
|
||||
}
|
||||
QTableWidget::mousePressEvent(event);
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <QTableWidget>
|
||||
#include <QMouseEvent>
|
||||
#include "../emulator/gameInfo.h"
|
||||
#include "game_list_item.h"
|
||||
|
||||
struct gui_game_info
|
||||
{
|
||||
GameInfo info{};
|
||||
QPixmap icon;
|
||||
QPixmap pxmap;
|
||||
game_list_item* item = nullptr;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<gui_game_info> game_info;
|
||||
Q_DECLARE_METATYPE(game_info)
|
||||
|
||||
class game_list_table : public QTableWidget
|
||||
{
|
||||
public:
|
||||
void clear_list();
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
};
|
|
@ -1,30 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
struct gui_save
|
||||
{
|
||||
QString key;
|
||||
QString name;
|
||||
QVariant def;
|
||||
|
||||
gui_save()
|
||||
{
|
||||
key = "";
|
||||
name = "";
|
||||
def = QVariant();
|
||||
}
|
||||
|
||||
gui_save(const QString& k, const QString& n, const QVariant& d)
|
||||
{
|
||||
key = k;
|
||||
name = n;
|
||||
def = d;
|
||||
}
|
||||
|
||||
bool operator==(const gui_save& rhs) const noexcept
|
||||
{
|
||||
return key == rhs.key && name == rhs.name && def == rhs.def;
|
||||
}
|
||||
};
|
|
@ -1,26 +0,0 @@
|
|||
#include "gui_settings.h"
|
||||
|
||||
|
||||
gui_settings::gui_settings(QObject* parent)
|
||||
{
|
||||
m_settings.reset(new QSettings("shadps4.ini", QSettings::Format::IniFormat, parent)); //TODO make the path configurable
|
||||
}
|
||||
|
||||
void gui_settings::SetGamelistColVisibility(int col, bool val) const
|
||||
{
|
||||
SetValue(GetGuiSaveForColumn(col), val);
|
||||
}
|
||||
|
||||
bool gui_settings::GetGamelistColVisibility(int col) const
|
||||
{
|
||||
return GetValue(GetGuiSaveForColumn(col)).toBool();
|
||||
}
|
||||
|
||||
gui_save gui_settings::GetGuiSaveForColumn(int col)
|
||||
{
|
||||
return gui_save{ gui::game_list, "visibility_" + gui::get_game_list_column_name(static_cast<gui::game_list_columns>(col)), true };
|
||||
}
|
||||
QSize gui_settings::SizeFromSlider(int pos)
|
||||
{
|
||||
return gui::game_list_icon_size_min + (gui::game_list_icon_size_max - gui::game_list_icon_size_min) * (1.f * pos / gui::game_list_max_slider_pos);
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "settings.h"
|
||||
#include <QColor>
|
||||
|
||||
namespace gui
|
||||
{
|
||||
enum custom_roles
|
||||
{
|
||||
game_role = Qt::UserRole + 1337,
|
||||
};
|
||||
|
||||
enum game_list_columns
|
||||
{
|
||||
column_icon,
|
||||
column_name,
|
||||
column_serial,
|
||||
column_firmware,
|
||||
column_version,
|
||||
column_category,
|
||||
column_path,
|
||||
|
||||
column_count
|
||||
};
|
||||
|
||||
inline QString get_game_list_column_name(game_list_columns col)
|
||||
{
|
||||
switch (col)
|
||||
{
|
||||
case column_icon:
|
||||
return "column_icon";
|
||||
case column_name:
|
||||
return "column_name";
|
||||
case column_serial:
|
||||
return "column_serial";
|
||||
case column_firmware:
|
||||
return "column_firmware";
|
||||
case column_version:
|
||||
return "column_version";
|
||||
case column_category:
|
||||
return "column_category";
|
||||
case column_path:
|
||||
return "column_path";
|
||||
case column_count:
|
||||
return "";
|
||||
}
|
||||
|
||||
throw std::exception("get_game_list_column_name: Invalid column");
|
||||
}
|
||||
|
||||
const QSize game_list_icon_size_min = QSize(40, 22);
|
||||
const QSize game_list_icon_size_small = QSize(80, 44);
|
||||
const QSize game_list_icon_size_medium = QSize(160, 88);
|
||||
const QSize game_list_icon_size_max = QSize(320, 176);
|
||||
|
||||
const int game_list_max_slider_pos = 100;
|
||||
|
||||
inline int get_Index(const QSize& current)
|
||||
{
|
||||
const int size_delta = game_list_icon_size_max.width() - game_list_icon_size_min.width();
|
||||
const int current_delta = current.width() - game_list_icon_size_min.width();
|
||||
return game_list_max_slider_pos * current_delta / size_delta;
|
||||
}
|
||||
|
||||
const QString main_window = "main_window";
|
||||
const QString game_list = "GameList";
|
||||
|
||||
const QColor game_list_icon_color = QColor(240, 240, 240, 255);
|
||||
|
||||
const gui_save main_window_gamelist_visible = gui_save(main_window, "gamelistVisible", true);
|
||||
const gui_save main_window_geometry = gui_save(main_window, "geometry", QByteArray());
|
||||
const gui_save main_window_windowState = gui_save(main_window, "windowState", QByteArray());
|
||||
const gui_save main_window_mwState = gui_save(main_window, "mwState", QByteArray());
|
||||
|
||||
const gui_save game_list_sortAsc = gui_save(game_list, "sortAsc", true);
|
||||
const gui_save game_list_sortCol = gui_save(game_list, "sortCol", 1);
|
||||
const gui_save game_list_state = gui_save(game_list, "state", QByteArray());
|
||||
const gui_save game_list_iconSize = gui_save(game_list, "iconSize", get_Index(game_list_icon_size_small));
|
||||
const gui_save game_list_iconSizeGrid = gui_save(game_list, "iconSizeGrid", get_Index(game_list_icon_size_small));
|
||||
const gui_save game_list_iconColor = gui_save(game_list, "iconColor", game_list_icon_color);
|
||||
const gui_save game_list_listMode = gui_save(game_list, "listMode", true);
|
||||
const gui_save game_list_textFactor = gui_save(game_list, "textFactor", qreal{ 2.0 });
|
||||
const gui_save game_list_marginFactor = gui_save(game_list, "marginFactor", qreal{ 0.09 });
|
||||
|
||||
|
||||
}
|
||||
|
||||
class gui_settings : public settings
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit gui_settings(QObject* parent = nullptr);
|
||||
|
||||
bool GetGamelistColVisibility(int col) const;
|
||||
|
||||
|
||||
public Q_SLOTS:
|
||||
void SetGamelistColVisibility(int col, bool val) const;
|
||||
static gui_save GetGuiSaveForColumn(int col);
|
||||
static QSize SizeFromSlider(int pos);
|
||||
};
|
||||
|
|
@ -1,272 +0,0 @@
|
|||
#include "game_list_frame.h"
|
||||
#include "main_window.h"
|
||||
#include "gui_settings.h"
|
||||
#include "ui_main_window.h"
|
||||
#include <QFileDialog>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include "../emulator/Loader.h"
|
||||
#include "../emulator/fileFormat/PKG.h"
|
||||
#include "../core/FsFile.h"
|
||||
|
||||
|
||||
main_window::main_window(std::shared_ptr<gui_settings> gui_settings, QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::main_window)
|
||||
, m_gui_settings(std::move(gui_settings))
|
||||
{
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
}
|
||||
|
||||
main_window::~main_window()
|
||||
{
|
||||
SaveWindowState();
|
||||
}
|
||||
|
||||
bool main_window::Init()
|
||||
{
|
||||
// add toolbar widgets
|
||||
ui->toolBar->setObjectName("mw_toolbar");
|
||||
ui->sizeSlider->setRange(0, gui::game_list_max_slider_pos);
|
||||
ui->toolBar->addWidget(ui->sizeSliderContainer);
|
||||
ui->toolBar->addWidget(ui->mw_searchbar);
|
||||
|
||||
CreateActions();
|
||||
CreateDockWindows();
|
||||
CreateConnects();
|
||||
|
||||
setMinimumSize(350, minimumSizeHint().height());
|
||||
setWindowTitle(QString::fromStdString("ShadPS4 v0.0.2"));
|
||||
|
||||
ConfigureGuiFromSettings();
|
||||
|
||||
show();
|
||||
|
||||
// Fix possible hidden game list columns. The game list has to be visible already. Use this after show()
|
||||
m_game_list_frame->FixNarrowColumns();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void main_window::CreateActions()
|
||||
{
|
||||
//create action group for icon size
|
||||
m_icon_size_act_group = new QActionGroup(this);
|
||||
m_icon_size_act_group->addAction(ui->setIconSizeTinyAct);
|
||||
m_icon_size_act_group->addAction(ui->setIconSizeSmallAct);
|
||||
m_icon_size_act_group->addAction(ui->setIconSizeMediumAct);
|
||||
m_icon_size_act_group->addAction(ui->setIconSizeLargeAct);
|
||||
|
||||
//create action group for list mode
|
||||
m_list_mode_act_group = new QActionGroup(this);
|
||||
m_list_mode_act_group->addAction(ui->setlistModeListAct);
|
||||
m_list_mode_act_group->addAction(ui->setlistModeGridAct);
|
||||
|
||||
}
|
||||
|
||||
void main_window::CreateDockWindows()
|
||||
{
|
||||
m_main_window = new QMainWindow();
|
||||
m_main_window->setContextMenuPolicy(Qt::PreventContextMenu);
|
||||
|
||||
m_game_list_frame = new game_list_frame(m_gui_settings,m_main_window);
|
||||
m_game_list_frame->setObjectName("gamelist");
|
||||
|
||||
m_main_window->addDockWidget(Qt::LeftDockWidgetArea, m_game_list_frame);
|
||||
|
||||
m_main_window->setDockNestingEnabled(true);
|
||||
|
||||
setCentralWidget(m_main_window);
|
||||
|
||||
connect(m_game_list_frame, &game_list_frame::GameListFrameClosed, this, [this]()
|
||||
{
|
||||
if (ui->showGameListAct->isChecked())
|
||||
{
|
||||
ui->showGameListAct->setChecked(false);
|
||||
m_gui_settings->SetValue(gui::main_window_gamelist_visible, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
void main_window::CreateConnects()
|
||||
{
|
||||
connect(ui->exitAct, &QAction::triggered, this, &QWidget::close);
|
||||
|
||||
connect(ui->showGameListAct, &QAction::triggered, this, [this](bool checked)
|
||||
{
|
||||
checked ? m_game_list_frame->show() : m_game_list_frame->hide();
|
||||
m_gui_settings->SetValue(gui::main_window_gamelist_visible, checked);
|
||||
});
|
||||
connect(ui->refreshGameListAct, &QAction::triggered, this, [this]
|
||||
{
|
||||
m_game_list_frame->Refresh(true);
|
||||
});
|
||||
|
||||
connect(m_icon_size_act_group, &QActionGroup::triggered, this, [this](QAction* act)
|
||||
{
|
||||
static const int index_small = gui::get_Index(gui::game_list_icon_size_small);
|
||||
static const int index_medium = gui::get_Index(gui::game_list_icon_size_medium);
|
||||
|
||||
int index;
|
||||
|
||||
if (act == ui->setIconSizeTinyAct)
|
||||
index = 0;
|
||||
else if (act == ui->setIconSizeSmallAct)
|
||||
index = index_small;
|
||||
else if (act == ui->setIconSizeMediumAct)
|
||||
index = index_medium;
|
||||
else
|
||||
index = gui::game_list_max_slider_pos;
|
||||
|
||||
m_save_slider_pos = true;
|
||||
ResizeIcons(index);
|
||||
});
|
||||
connect(m_game_list_frame, &game_list_frame::RequestIconSizeChange, this, [this](const int& val)
|
||||
{
|
||||
const int idx = ui->sizeSlider->value() + val;
|
||||
m_save_slider_pos = true;
|
||||
ResizeIcons(idx);
|
||||
});
|
||||
|
||||
connect(m_list_mode_act_group, &QActionGroup::triggered, this, [this](QAction* act)
|
||||
{
|
||||
const bool is_list_act = act == ui->setlistModeListAct;
|
||||
if (is_list_act == m_is_list_mode)
|
||||
return;
|
||||
|
||||
const int slider_pos = ui->sizeSlider->sliderPosition();
|
||||
ui->sizeSlider->setSliderPosition(m_other_slider_pos);
|
||||
SetIconSizeActions(m_other_slider_pos);
|
||||
m_other_slider_pos = slider_pos;
|
||||
|
||||
m_is_list_mode = is_list_act;
|
||||
m_game_list_frame->SetListMode(m_is_list_mode);
|
||||
});
|
||||
connect(ui->sizeSlider, &QSlider::valueChanged, this, &main_window::ResizeIcons);
|
||||
connect(ui->sizeSlider, &QSlider::sliderReleased, this, [this]
|
||||
{
|
||||
const int index = ui->sizeSlider->value();
|
||||
m_gui_settings->SetValue(m_is_list_mode ? gui::game_list_iconSize : gui::game_list_iconSizeGrid, index);
|
||||
SetIconSizeActions(index);
|
||||
});
|
||||
connect(ui->sizeSlider, &QSlider::actionTriggered, this, [this](int action)
|
||||
{
|
||||
if (action != QAbstractSlider::SliderNoAction && action != QAbstractSlider::SliderMove)
|
||||
{ // we only want to save on mouseclicks or slider release (the other connect handles this)
|
||||
m_save_slider_pos = true; // actionTriggered happens before the value was changed
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->mw_searchbar, &QLineEdit::textChanged, m_game_list_frame, &game_list_frame::SetSearchText);
|
||||
connect(ui->bootInstallPkgAct, &QAction::triggered, this, [this] {InstallPkg(); });
|
||||
}
|
||||
|
||||
void main_window::SetIconSizeActions(int idx) const
|
||||
{
|
||||
static const int threshold_tiny = gui::get_Index((gui::game_list_icon_size_small + gui::game_list_icon_size_min) / 2);
|
||||
static const int threshold_small = gui::get_Index((gui::game_list_icon_size_medium + gui::game_list_icon_size_small) / 2);
|
||||
static const int threshold_medium = gui::get_Index((gui::game_list_icon_size_max + gui::game_list_icon_size_medium) / 2);
|
||||
|
||||
if (idx < threshold_tiny)
|
||||
ui->setIconSizeTinyAct->setChecked(true);
|
||||
else if (idx < threshold_small)
|
||||
ui->setIconSizeSmallAct->setChecked(true);
|
||||
else if (idx < threshold_medium)
|
||||
ui->setIconSizeMediumAct->setChecked(true);
|
||||
else
|
||||
ui->setIconSizeLargeAct->setChecked(true);
|
||||
}
|
||||
void main_window::ResizeIcons(int index)
|
||||
{
|
||||
if (ui->sizeSlider->value() != index)
|
||||
{
|
||||
ui->sizeSlider->setSliderPosition(index);
|
||||
return; // ResizeIcons will be triggered again by setSliderPosition, so return here
|
||||
}
|
||||
|
||||
if (m_save_slider_pos)
|
||||
{
|
||||
m_save_slider_pos = false;
|
||||
m_gui_settings->SetValue(m_is_list_mode ? gui::game_list_iconSize : gui::game_list_iconSizeGrid, index);
|
||||
|
||||
// this will also fire when we used the actions, but i didn't want to add another boolean member
|
||||
SetIconSizeActions(index);
|
||||
}
|
||||
|
||||
m_game_list_frame->ResizeIcons(index);
|
||||
}
|
||||
void main_window::ConfigureGuiFromSettings()
|
||||
{
|
||||
// Restore GUI state if needed. We need to if they exist.
|
||||
if (!restoreGeometry(m_gui_settings->GetValue(gui::main_window_geometry).toByteArray()))
|
||||
{
|
||||
resize(QGuiApplication::primaryScreen()->availableSize() * 0.7);
|
||||
}
|
||||
|
||||
restoreState(m_gui_settings->GetValue(gui::main_window_windowState).toByteArray());
|
||||
m_main_window->restoreState(m_gui_settings->GetValue(gui::main_window_mwState).toByteArray());
|
||||
|
||||
ui->showGameListAct->setChecked(m_gui_settings->GetValue(gui::main_window_gamelist_visible).toBool());
|
||||
|
||||
m_game_list_frame->setVisible(ui->showGameListAct->isChecked());
|
||||
|
||||
// handle icon size options
|
||||
m_is_list_mode = m_gui_settings->GetValue(gui::game_list_listMode).toBool();
|
||||
if (m_is_list_mode)
|
||||
ui->setlistModeListAct->setChecked(true);
|
||||
else
|
||||
ui->setlistModeGridAct->setChecked(true);
|
||||
|
||||
const int icon_size_index = m_gui_settings->GetValue(m_is_list_mode ? gui::game_list_iconSize : gui::game_list_iconSizeGrid).toInt();
|
||||
m_other_slider_pos = m_gui_settings->GetValue(!m_is_list_mode ? gui::game_list_iconSize : gui::game_list_iconSizeGrid).toInt();
|
||||
ui->sizeSlider->setSliderPosition(icon_size_index);
|
||||
SetIconSizeActions(icon_size_index);
|
||||
|
||||
// Gamelist
|
||||
m_game_list_frame->LoadSettings();
|
||||
}
|
||||
|
||||
void main_window::SaveWindowState() const
|
||||
{
|
||||
// Save gui settings
|
||||
m_gui_settings->SetValue(gui::main_window_geometry, saveGeometry());
|
||||
m_gui_settings->SetValue(gui::main_window_windowState, saveState());
|
||||
m_gui_settings->SetValue(gui::main_window_mwState, m_main_window->saveState());
|
||||
|
||||
// Save column settings
|
||||
m_game_list_frame->SaveSettings();
|
||||
}
|
||||
|
||||
void main_window::InstallPkg()
|
||||
{
|
||||
std::string file(QFileDialog::getOpenFileName(this, tr("Install PKG File"), QDir::currentPath(), tr("PKG File (*.PKG)")).toStdString());
|
||||
if (detectFileType(file) == FILETYPE_PKG)
|
||||
{
|
||||
PKG pkg;
|
||||
pkg.open(file);
|
||||
//if pkg is ok we procced with extraction
|
||||
std::string failreason;
|
||||
QString gamedir = QDir::currentPath() + "/game/" + QString::fromStdString(pkg.getTitleID());
|
||||
QDir dir(gamedir);
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(".");
|
||||
}
|
||||
std::string extractpath = QDir::currentPath().toStdString() + "/game/" + pkg.getTitleID() + "/";
|
||||
if (!pkg.extract(file, extractpath, failreason))
|
||||
{
|
||||
QMessageBox::critical(this, "PKG ERROR", QString::fromStdString(failreason), QMessageBox::Ok, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::information(this, "Extraction Finished", "Game successfully installed at " + gamedir, QMessageBox::Ok, 0);
|
||||
m_game_list_frame->Refresh(true);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, "PKG ERROR", "File doesn't appear to be a valid PKG file", QMessageBox::Ok, 0);
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QActionGroup>
|
||||
|
||||
class gui_settings;
|
||||
class game_list_frame;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class main_window;
|
||||
}
|
||||
|
||||
class main_window : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
std::unique_ptr<Ui::main_window> ui;
|
||||
|
||||
bool m_is_list_mode = true;
|
||||
bool m_save_slider_pos = false;
|
||||
int m_other_slider_pos = 0;
|
||||
|
||||
public:
|
||||
explicit main_window(std::shared_ptr<gui_settings> gui_settings,QWidget* parent = nullptr);
|
||||
~main_window();
|
||||
bool Init();
|
||||
void InstallPkg();
|
||||
|
||||
private Q_SLOTS:
|
||||
void ConfigureGuiFromSettings();
|
||||
void SetIconSizeActions(int idx) const;
|
||||
void ResizeIcons(int index);
|
||||
void SaveWindowState() const;
|
||||
private:
|
||||
void CreateActions();
|
||||
void CreateDockWindows();
|
||||
void CreateConnects();
|
||||
|
||||
QActionGroup* m_icon_size_act_group = nullptr;
|
||||
QActionGroup* m_list_mode_act_group = nullptr;
|
||||
|
||||
// Dockable widget frames
|
||||
QMainWindow* m_main_window = nullptr;
|
||||
game_list_frame* m_game_list_frame = nullptr;
|
||||
|
||||
std::shared_ptr<gui_settings> m_gui_settings;
|
||||
|
||||
};
|
||||
|
|
@ -1,289 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>main_window</class>
|
||||
<widget class="QMainWindow" name="main_window">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1058</width>
|
||||
<height>580</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>4</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>RPCS3</string>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="animated">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dockNestingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dockOptions">
|
||||
<set>QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks|QMainWindow::GroupedDragging</set>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<widget class="QLineEdit" name="mw_searchbar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>480</x>
|
||||
<y>10</y>
|
||||
<width>251</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::ClickFocus</enum>
|
||||
</property>
|
||||
<property name="frame">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Search...</string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="sizeSliderContainer" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>280</x>
|
||||
<y>10</y>
|
||||
<width>181</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="sizeSliderContainer_layout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>14</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>14</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSlider" name="sizeSlider">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::ClickFocus</enum>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::NoTicks</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1058</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::PreventContextMenu</enum>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="bootInstallPkgAct"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="exitAct"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
<string>View</string>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuGame_List_Icons">
|
||||
<property name="title">
|
||||
<string>Game List Icons</string>
|
||||
</property>
|
||||
<addaction name="setIconSizeTinyAct"/>
|
||||
<addaction name="setIconSizeSmallAct"/>
|
||||
<addaction name="setIconSizeMediumAct"/>
|
||||
<addaction name="setIconSizeLargeAct"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuGame_List_Mode">
|
||||
<property name="title">
|
||||
<string>Game List Mode</string>
|
||||
</property>
|
||||
<addaction name="setlistModeListAct"/>
|
||||
<addaction name="setlistModeGridAct"/>
|
||||
</widget>
|
||||
<addaction name="showGameListAct"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="refreshGameListAct"/>
|
||||
<addaction name="menuGame_List_Mode"/>
|
||||
<addaction name="menuGame_List_Icons"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuView"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
<property name="windowTitle">
|
||||
<string>toolBar</string>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
<action name="bootInstallPkgAct">
|
||||
<property name="text">
|
||||
<string>Install Packages (PKG)</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Install application from a .pkg file</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="exitAct">
|
||||
<property name="text">
|
||||
<string>Exit</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Exit RPCS3</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Exit the application.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="showGameListAct">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show Game List</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="refreshGameListAct">
|
||||
<property name="text">
|
||||
<string>Game List Refresh</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="setIconSizeTinyAct">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Tiny</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="setIconSizeSmallAct">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Small</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="setIconSizeMediumAct">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Medium</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="setIconSizeLargeAct">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Large</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="setlistModeListAct">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>List View</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="setlistModeGridAct">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Grid View</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources>
|
||||
<include location="../../../rpcs3/rpcs3/resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -1,23 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <QFutureWatcher>
|
||||
|
||||
namespace gui
|
||||
{
|
||||
namespace utils
|
||||
{
|
||||
template <typename T>
|
||||
void stop_future_watcher(QFutureWatcher<T>& watcher, bool cancel)
|
||||
{
|
||||
if (watcher.isStarted() || watcher.isRunning())
|
||||
{
|
||||
if (cancel)
|
||||
{
|
||||
watcher.cancel();
|
||||
}
|
||||
watcher.waitForFinished();
|
||||
}
|
||||
}
|
||||
} // utils
|
||||
} // gui
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
#include "settings.h"
|
||||
|
||||
settings::settings(QObject* parent) : QObject(parent),
|
||||
m_settings_dir(ComputeSettingsDir())
|
||||
{
|
||||
}
|
||||
|
||||
settings::~settings()
|
||||
{
|
||||
if (m_settings)
|
||||
{
|
||||
m_settings->sync();
|
||||
}
|
||||
}
|
||||
|
||||
QString settings::GetSettingsDir() const
|
||||
{
|
||||
return m_settings_dir.absolutePath();
|
||||
}
|
||||
|
||||
QString settings::ComputeSettingsDir()
|
||||
{
|
||||
return ""; //TODO currently we configure same dir , make it configurable
|
||||
}
|
||||
|
||||
void settings::RemoveValue(const QString& key, const QString& name) const
|
||||
{
|
||||
if (m_settings)
|
||||
{
|
||||
m_settings->beginGroup(key);
|
||||
m_settings->remove(name);
|
||||
m_settings->endGroup();
|
||||
}
|
||||
}
|
||||
|
||||
void settings::RemoveValue(const gui_save& entry) const
|
||||
{
|
||||
RemoveValue(entry.key, entry.name);
|
||||
}
|
||||
|
||||
QVariant settings::GetValue(const QString& key, const QString& name, const QVariant& def) const
|
||||
{
|
||||
return m_settings ? m_settings->value(key + "/" + name, def) : def;
|
||||
}
|
||||
|
||||
QVariant settings::GetValue(const gui_save& entry) const
|
||||
{
|
||||
return GetValue(entry.key, entry.name, entry.def);
|
||||
}
|
||||
|
||||
QVariant settings::List2Var(const q_pair_list& list)
|
||||
{
|
||||
QByteArray ba;
|
||||
QDataStream stream(&ba, QIODevice::WriteOnly);
|
||||
stream << list;
|
||||
return QVariant(ba);
|
||||
}
|
||||
|
||||
q_pair_list settings::Var2List(const QVariant& var)
|
||||
{
|
||||
q_pair_list list;
|
||||
QByteArray ba = var.toByteArray();
|
||||
QDataStream stream(&ba, QIODevice::ReadOnly);
|
||||
stream >> list;
|
||||
return list;
|
||||
}
|
||||
|
||||
void settings::SetValue(const gui_save& entry, const QVariant& value) const
|
||||
{
|
||||
if (m_settings)
|
||||
{
|
||||
m_settings->beginGroup(entry.key);
|
||||
m_settings->setValue(entry.name, value);
|
||||
m_settings->endGroup();
|
||||
}
|
||||
}
|
||||
|
||||
void settings::SetValue(const QString& key, const QVariant& value) const
|
||||
{
|
||||
if (m_settings)
|
||||
{
|
||||
m_settings->setValue(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
void settings::SetValue(const QString& key, const QString& name, const QVariant& value) const
|
||||
{
|
||||
if (m_settings)
|
||||
{
|
||||
m_settings->beginGroup(key);
|
||||
m_settings->setValue(name, value);
|
||||
m_settings->endGroup();
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <QSettings>
|
||||
#include <QDir>
|
||||
#include <QVariant>
|
||||
#include <QSize>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "gui_save.h"
|
||||
|
||||
typedef QPair<QString, QString> q_string_pair;
|
||||
typedef QPair<QString, QSize> q_size_pair;
|
||||
typedef QList<q_string_pair> q_pair_list;
|
||||
typedef QList<q_size_pair> q_size_list;
|
||||
|
||||
// Parent Class for GUI settings
|
||||
class settings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit settings(QObject* parent = nullptr);
|
||||
~settings();
|
||||
|
||||
QString GetSettingsDir() const;
|
||||
|
||||
QVariant GetValue(const QString& key, const QString& name, const QVariant& def) const;
|
||||
QVariant GetValue(const gui_save& entry) const;
|
||||
static QVariant List2Var(const q_pair_list& list);
|
||||
static q_pair_list Var2List(const QVariant& var);
|
||||
|
||||
public Q_SLOTS:
|
||||
/** Remove entry */
|
||||
void RemoveValue(const QString& key, const QString& name) const;
|
||||
void RemoveValue(const gui_save& entry) const;
|
||||
|
||||
/** Write value to entry */
|
||||
void SetValue(const gui_save& entry, const QVariant& value) const;
|
||||
void SetValue(const QString& key, const QVariant& value) const;
|
||||
void SetValue(const QString& key, const QString& name, const QVariant& value) const;
|
||||
|
||||
protected:
|
||||
static QString ComputeSettingsDir();
|
||||
|
||||
std::unique_ptr<QSettings> m_settings;
|
||||
QDir m_settings_dir;
|
||||
};
|
|
@ -1,59 +0,0 @@
|
|||
#include "shadps4gui.h"
|
||||
#include "../emulator/Loader.h"
|
||||
#include "../emulator/fileFormat/PKG.h"
|
||||
#include "../core/FsFile.h"
|
||||
#include <QFileDialog>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QProgressDialog>
|
||||
|
||||
shadps4gui::shadps4gui(std::shared_ptr<gui_settings> gui_settings, QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
, m_gui_settings(std::move(gui_settings))
|
||||
{
|
||||
ui.setupUi(this);
|
||||
//game_list = new GameListViewer();
|
||||
//game_list->SetGamePath(QDir::currentPath() + "/game/");
|
||||
//ui.horizontalLayout->addWidget(game_list);
|
||||
//show();
|
||||
//game_list->PopulateAsync();
|
||||
game_list_frame* game_list2 = new game_list_frame(m_gui_settings);
|
||||
ui.horizontalLayout->addWidget(game_list2);
|
||||
game_list2->LoadSettings();
|
||||
show();
|
||||
}
|
||||
|
||||
shadps4gui::~shadps4gui()
|
||||
{}
|
||||
|
||||
void shadps4gui::installPKG()
|
||||
{
|
||||
std::string file(QFileDialog::getOpenFileName(this, tr("Install PKG File"), QDir::currentPath(), tr("PKG File (*.PKG)")).toStdString());
|
||||
if (detectFileType(file) == FILETYPE_PKG)
|
||||
{
|
||||
PKG pkg;
|
||||
pkg.open(file);
|
||||
//if pkg is ok we procced with extraction
|
||||
std::string failreason;
|
||||
QString gamedir = QDir::currentPath() + "/game/" + QString::fromStdString(pkg.getTitleID());
|
||||
QDir dir(gamedir);
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(".");
|
||||
}
|
||||
std::string extractpath = QDir::currentPath().toStdString() + "/game/" + pkg.getTitleID() + "/";
|
||||
if (!pkg.extract(file, extractpath, failreason))
|
||||
{
|
||||
QMessageBox::critical(this, "PKG ERROR", QString::fromStdString(failreason), QMessageBox::Ok, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::information(this, "Extraction Finished", "Game successfully installed at " + gamedir, QMessageBox::Ok, 0);
|
||||
game_list->RefreshGameDirectory();//force refreshing since filelistwatcher doesn't work properly
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, "PKG ERROR", "File doesn't appear to be a valid PKG file", QMessageBox::Ok, 0);
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
#include "ui_shadps4gui.h"
|
||||
#include "GameListViewer.h"
|
||||
#include "gui_settings.h"
|
||||
#include "game_list_frame.h"
|
||||
|
||||
class shadps4gui : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
shadps4gui(std::shared_ptr<gui_settings> gui_settings, QWidget* parent = nullptr);
|
||||
~shadps4gui();
|
||||
|
||||
public slots:
|
||||
void installPKG();
|
||||
|
||||
private:
|
||||
Ui::shadps4guiClass ui;
|
||||
GameListViewer* game_list;
|
||||
std::shared_ptr<gui_settings> m_gui_settings;
|
||||
};
|
|
@ -1,79 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>shadps4guiClass</class>
|
||||
<widget class="QMainWindow" name="shadps4guiClass">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>shadPS4</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuOpen">
|
||||
<property name="title">
|
||||
<string>Open</string>
|
||||
</property>
|
||||
<addaction name="actionInstall_PKG"/>
|
||||
</widget>
|
||||
<addaction name="menuOpen"/>
|
||||
</widget>
|
||||
<action name="actionInstall_PKG">
|
||||
<property name="text">
|
||||
<string>Install PKG</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>actionInstall_PKG</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>shadps4guiClass</receiver>
|
||||
<slot>installPKG()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>299</x>
|
||||
<y>199</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<slots>
|
||||
<slot>installPKG()</slot>
|
||||
<slot>installFW()</slot>
|
||||
</slots>
|
||||
</ui>
|
|
@ -1,15 +0,0 @@
|
|||
#include "gui/shadps4gui.h"
|
||||
#include <QtWidgets/QApplication>
|
||||
#include "gui/gui_settings.h"
|
||||
#include "gui/main_window.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
std::shared_ptr<gui_settings> m_gui_settings;
|
||||
m_gui_settings.reset(new gui_settings());
|
||||
main_window* m_main_window = new main_window(m_gui_settings, nullptr);
|
||||
m_main_window->Init();
|
||||
|
||||
return a.exec();
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="core\FsFile.cpp" />
|
||||
<ClCompile Include="emulator\fileFormat\PKG.cpp" />
|
||||
<ClCompile Include="emulator\fileFormat\PSF.cpp" />
|
||||
<ClCompile Include="emulator\Loader.cpp" />
|
||||
<ClCompile Include="gui\custom_table_widget_item.cpp" />
|
||||
<ClCompile Include="gui\GameListViewer.cpp" />
|
||||
<ClCompile Include="gui\game_list_frame.cpp" />
|
||||
<ClCompile Include="gui\game_list_grid.cpp" />
|
||||
<ClCompile Include="gui\game_list_grid_delegate.cpp" />
|
||||
<ClCompile Include="gui\game_list_table.cpp" />
|
||||
<ClCompile Include="gui\gui_settings.cpp" />
|
||||
<ClCompile Include="gui\main_window.cpp" />
|
||||
<ClCompile Include="gui\settings.cpp" />
|
||||
<ClCompile Include="gui\shadps4gui.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="gui\shadps4gui.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUic Include="gui\main_window.ui" />
|
||||
<QtUic Include="gui\shadps4gui.ui" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="gui\GameListViewer.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="core\FsFile.h" />
|
||||
<ClInclude Include="emulator\fileFormat\PKG.h" />
|
||||
<ClInclude Include="emulator\fileFormat\PSF.h" />
|
||||
<ClInclude Include="emulator\gameInfo.h" />
|
||||
<ClInclude Include="emulator\Loader.h" />
|
||||
<ClInclude Include="gui\custom_dock_widget.h" />
|
||||
<ClInclude Include="gui\custom_table_widget_item.h" />
|
||||
<QtMoc Include="gui\game_list_grid.h" />
|
||||
<QtMoc Include="gui\game_list_frame.h" />
|
||||
<ClInclude Include="gui\game_list_grid_delegate.h" />
|
||||
<ClInclude Include="gui\game_list_item.h" />
|
||||
<ClInclude Include="gui\game_list_table.h" />
|
||||
<ClInclude Include="gui\gui_save.h" />
|
||||
<QtMoc Include="gui\gui_settings.h" />
|
||||
<QtMoc Include="gui\settings.h" />
|
||||
<QtMoc Include="gui\main_window.h" />
|
||||
<ClInclude Include="gui\qt_utils.h" />
|
||||
<ClInclude Include="Types.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{F005E4D9-1FBE-40B3-9FBD-35CEC59081CD}</ProjectGuid>
|
||||
<Keyword>QtVS_v304</Keyword>
|
||||
<WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
<QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
|
||||
<Import Project="$(QtMsBuild)\qt_defaults.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
|
||||
<QtInstall>6.4.2</QtInstall>
|
||||
<QtModules>core;gui;widgets;concurrent</QtModules>
|
||||
<QtBuildConfig>debug</QtBuildConfig>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
|
||||
<QtInstall>6.4.2</QtInstall>
|
||||
<QtModules>core;gui;widgets;concurrent</QtModules>
|
||||
<QtBuildConfig>release</QtBuildConfig>
|
||||
</PropertyGroup>
|
||||
<Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
|
||||
<Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
|
||||
</Target>
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Label="Shared" />
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="$(QtMsBuild)\Qt.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="$(QtMsBuild)\Qt.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
|
||||
<ClCompile>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
|
||||
<ClCompile>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
|
||||
<Import Project="$(QtMsBuild)\qt.targets" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -1,162 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Form Files">
|
||||
<UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
|
||||
<Extensions>ui</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Translation Files">
|
||||
<UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
|
||||
<Extensions>ts</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="gui">
|
||||
<UniqueIdentifier>{29ee17bd-9ad4-44e8-b1cd-b4be13ec6509}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Core">
|
||||
<UniqueIdentifier>{73d07238-8864-48b5-9987-e455fa73c82f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="emulator">
|
||||
<UniqueIdentifier>{66864aec-390b-47a8-bddb-b52032630d7a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="emulator\fileFormat">
|
||||
<UniqueIdentifier>{ed31734c-f010-4590-9f01-18e0b2497ffb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="gui\game list">
|
||||
<UniqueIdentifier>{b4b58418-b124-41bb-96ef-610faa1c8812}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="gui\main window">
|
||||
<UniqueIdentifier>{731089fd-7d11-4f10-8f55-4854c2e42e9e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gui\shadps4gui.cpp">
|
||||
<Filter>gui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gui\GameListViewer.cpp">
|
||||
<Filter>gui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="core\FsFile.cpp">
|
||||
<Filter>Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="emulator\fileFormat\PSF.cpp">
|
||||
<Filter>emulator\fileFormat</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="emulator\Loader.cpp">
|
||||
<Filter>emulator</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="emulator\fileFormat\PKG.cpp">
|
||||
<Filter>emulator\fileFormat</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gui\gui_settings.cpp">
|
||||
<Filter>gui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gui\settings.cpp">
|
||||
<Filter>gui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gui\game_list_frame.cpp">
|
||||
<Filter>gui\game list</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gui\game_list_grid.cpp">
|
||||
<Filter>gui\game list</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gui\game_list_grid_delegate.cpp">
|
||||
<Filter>gui\game list</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gui\game_list_table.cpp">
|
||||
<Filter>gui\game list</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gui\custom_table_widget_item.cpp">
|
||||
<Filter>gui\game list</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gui\main_window.cpp">
|
||||
<Filter>gui\main window</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUic Include="gui\shadps4gui.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</QtUic>
|
||||
<QtUic Include="gui\main_window.ui">
|
||||
<Filter>gui\main window</Filter>
|
||||
</QtUic>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="gui\shadps4gui.h">
|
||||
<Filter>gui</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="gui\GameListViewer.h">
|
||||
<Filter>gui</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="gui\settings.h">
|
||||
<Filter>gui</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="gui\gui_settings.h">
|
||||
<Filter>gui</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="gui\game_list_frame.h">
|
||||
<Filter>gui\game list</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="gui\game_list_grid.h">
|
||||
<Filter>gui\game list</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="gui\main_window.h">
|
||||
<Filter>gui\main window</Filter>
|
||||
</QtMoc>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Types.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="core\FsFile.h">
|
||||
<Filter>Core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="emulator\fileFormat\PSF.h">
|
||||
<Filter>emulator\fileFormat</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="emulator\Loader.h">
|
||||
<Filter>emulator</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="emulator\fileFormat\PKG.h">
|
||||
<Filter>emulator\fileFormat</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="emulator\gameInfo.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gui\gui_save.h">
|
||||
<Filter>gui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gui\game_list_item.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gui\qt_utils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gui\custom_dock_widget.h">
|
||||
<Filter>gui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gui\game_list_table.h">
|
||||
<Filter>gui\game list</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gui\game_list_grid_delegate.h">
|
||||
<Filter>gui\game list</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gui\custom_table_widget_item.h">
|
||||
<Filter>gui\game list</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,90 +0,0 @@
|
|||
#include "FsFile.h"
|
||||
|
||||
FsFile::FsFile()
|
||||
{
|
||||
m_file = nullptr;
|
||||
}
|
||||
FsFile::FsFile(const std::string& path, fsOpenMode mode)
|
||||
{
|
||||
Open(path, mode);
|
||||
}
|
||||
bool FsFile::Open(const std::string& path, fsOpenMode mode)
|
||||
{
|
||||
Close();
|
||||
fopen_s(&m_file, path.c_str(), getOpenMode(mode));
|
||||
return IsOpen();
|
||||
}
|
||||
bool FsFile::Close()
|
||||
{
|
||||
if (!IsOpen() || std::fclose(m_file) != 0) {
|
||||
m_file = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_file = nullptr;
|
||||
return true;
|
||||
}
|
||||
FsFile::~FsFile()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
bool FsFile::Write(const void* src, U64 size)
|
||||
{
|
||||
if (!IsOpen() || std::fwrite(src, 1, size, m_file) != size) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FsFile::Read(void* dst, U64 size)
|
||||
{
|
||||
if (!IsOpen() || std::fread(dst, 1, size, m_file) != size) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
U32 FsFile::ReadBytes(void* dst, U64 size)
|
||||
{
|
||||
return std::fread(dst, 1, size, m_file);
|
||||
}
|
||||
|
||||
bool FsFile::Seek(S64 offset, fsSeekMode mode)
|
||||
{
|
||||
if (!IsOpen() || _fseeki64(m_file, offset, getSeekMode(mode)) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
U64 FsFile::Tell() const
|
||||
{
|
||||
if (IsOpen()) {
|
||||
return _ftelli64(m_file);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
U64 FsFile::getFileSize()
|
||||
{
|
||||
U64 pos = _ftelli64(m_file);
|
||||
if (_fseeki64(m_file, 0, SEEK_END) != 0) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U64 size = _ftelli64(m_file);
|
||||
if (_fseeki64(m_file, pos, SEEK_SET) != 0) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
bool FsFile::IsOpen() const
|
||||
{
|
||||
return m_file != nullptr;
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
#pragma once
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include "Types.h"
|
||||
|
||||
enum fsOpenMode
|
||||
{
|
||||
fsRead = 0x1,
|
||||
fsWrite = 0x2,
|
||||
fsReadWrite = fsRead | fsWrite
|
||||
};
|
||||
|
||||
enum fsSeekMode
|
||||
{
|
||||
fsSeekSet,
|
||||
fsSeekCur,
|
||||
fsSeekEnd,
|
||||
};
|
||||
|
||||
class FsFile
|
||||
{
|
||||
std::FILE* m_file;
|
||||
public:
|
||||
FsFile();
|
||||
FsFile(const std::string& path, fsOpenMode mode = fsRead);
|
||||
bool Open(const std::string& path, fsOpenMode mode = fsRead);
|
||||
bool IsOpen() const;
|
||||
bool Close();
|
||||
bool Read(void* dst, U64 size);
|
||||
U32 ReadBytes(void* dst, U64 size);
|
||||
bool Write(const void* src, U64 size);
|
||||
bool Seek(S64 offset, fsSeekMode mode);
|
||||
U64 getFileSize();
|
||||
U64 Tell() const;
|
||||
~FsFile();
|
||||
|
||||
template< typename T > bool ReadBE(T& dst)
|
||||
{
|
||||
if (!Read(&dst, sizeof(T))) {
|
||||
return false;
|
||||
}
|
||||
::ReadBE(dst);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* getOpenMode(fsOpenMode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case fsRead: return "rb";
|
||||
case fsWrite: return "wb";
|
||||
case fsReadWrite: return "r+b";
|
||||
}
|
||||
|
||||
return "r";
|
||||
}
|
||||
|
||||
const int getSeekMode(fsSeekMode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case fsSeekSet: return SEEK_SET;
|
||||
case fsSeekCur: return SEEK_CUR;
|
||||
case fsSeekEnd: return SEEK_END;
|
||||
}
|
||||
|
||||
return SEEK_SET;
|
||||
}
|
||||
std::FILE* fileDescr()
|
||||
{
|
||||
return m_file;
|
||||
}
|
||||
};
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#include "PFS.h"
|
||||
|
||||
PFS::PFS()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
PFS::~PFS()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool PFS::pfsOuterReadHeader(U08* psfOuterStart)
|
||||
{
|
||||
psfOuterheader = (PFS_HDR&)psfOuterStart[0];
|
||||
return true;
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include "Types.h"
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
enum PFSMode : U08 {
|
||||
PFS_MODE_NONE = 0,
|
||||
PFS_MODE_SIGNED = 0x1,
|
||||
PFS_MODE_64BIT = 0x2,
|
||||
PFS_MODE_ENCRYPTED = 0x4,
|
||||
PFS_MODE_UNKNOWN = 0x8,
|
||||
};
|
||||
struct PFS_HDR {
|
||||
U64 version;
|
||||
U64 magic;
|
||||
U64 id;
|
||||
U08 fmode;
|
||||
U08 clean;
|
||||
U08 ronly;
|
||||
U08 rsv;
|
||||
U16 mode;
|
||||
U16 unk1;
|
||||
U32 blocksz;
|
||||
U32 nbackup;
|
||||
U64 nblock;
|
||||
U64 ndinode;
|
||||
U64 ndblock;
|
||||
U64 ndinodeblock;
|
||||
U64 superroot_ino;
|
||||
};
|
||||
|
||||
class PFS
|
||||
{
|
||||
private:
|
||||
PFS_HDR psfOuterheader;
|
||||
public:
|
||||
PFS();
|
||||
~PFS();
|
||||
bool pfsOuterReadHeader(U08* psfOuterStart);
|
||||
|
||||
void printPsfOuterHeader()
|
||||
{
|
||||
printf("PS4 PSF Outer Header:\n");
|
||||
printf("- version: 0x%" PRIx64 "\n", psfOuterheader.version);
|
||||
printf("- magic: 0x%" PRIx64 "\n", psfOuterheader.magic);
|
||||
printf("- id: 0x%" PRIx64 "\n", psfOuterheader.id);
|
||||
printf("- fmode: 0x%X\n", psfOuterheader.fmode);
|
||||
printf("- clean: 0x%X\n", psfOuterheader.clean);
|
||||
printf("- ronly: 0x%X\n", psfOuterheader.ronly);
|
||||
printf("- rsv: 0x%X\n", psfOuterheader.rsv);
|
||||
printf("- mode: 0x%X", psfOuterheader.mode);
|
||||
if (psfOuterheader.mode & PFS_MODE_SIGNED)
|
||||
printf(" signed");
|
||||
if (psfOuterheader.mode & PFS_MODE_64BIT)
|
||||
printf(" 64-bit");
|
||||
if (psfOuterheader.mode & PFS_MODE_ENCRYPTED)
|
||||
printf(" encrypted");
|
||||
if (psfOuterheader.mode & PFS_MODE_UNKNOWN)
|
||||
printf(" unknown");
|
||||
printf("\n");
|
||||
printf("- unk1: 0x%X\n", psfOuterheader.unk1);
|
||||
printf("- blocksz: 0x%X\n", psfOuterheader.blocksz);
|
||||
printf("- nbackup: 0x%X\n", psfOuterheader.nbackup);
|
||||
printf("- nblock: 0x%" PRIx64 "\n", psfOuterheader.nblock);
|
||||
printf("- ndinode: 0x%" PRIx64 "\n", psfOuterheader.ndinode);
|
||||
printf("- ndblock: 0x%" PRIx64 "\n", psfOuterheader.ndblock);
|
||||
printf("- ndinodeblock: 0x%" PRIx64 "\n", psfOuterheader.ndinodeblock);
|
||||
printf("- superroot_ino: 0x%" PRIx64 "\n", psfOuterheader.superroot_ino);
|
||||
|
||||
printf("\n\n");
|
||||
}
|
||||
};
|
|
@ -1,117 +0,0 @@
|
|||
#include "PKG.h"
|
||||
#include "FsFile.h"
|
||||
#include "PFS.h"
|
||||
#include <direct.h>
|
||||
|
||||
PKG::PKG()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PKG::~PKG()
|
||||
{
|
||||
}
|
||||
|
||||
bool PKG::open(const std::string& filepath) {
|
||||
FsFile file;
|
||||
if (!file.Open(filepath, fsRead))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
pkgSize = file.getFileSize();
|
||||
file.ReadBE(pkgheader);
|
||||
//we have already checked magic should be ok
|
||||
|
||||
//find title id it is part of pkg_content_id starting at offset 0x40
|
||||
file.Seek(0x47, fsSeekSet);//skip first 7 characters of content_id
|
||||
file.Read(&pkgTitleID, sizeof(pkgTitleID));
|
||||
|
||||
file.Close();
|
||||
|
||||
return true;
|
||||
}
|
||||
bool PKG::extract(const std::string& filepath, const std::string& extractPath, std::string& failreason)
|
||||
{
|
||||
this->extractPath = extractPath;
|
||||
FsFile file;
|
||||
if (!file.Open(filepath, fsRead))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
pkgSize = file.getFileSize();
|
||||
|
||||
file.ReadBE(pkgheader);
|
||||
|
||||
if (pkgheader.pkg_size > pkgSize)
|
||||
{
|
||||
failreason = "PKG file size is different";
|
||||
return false;
|
||||
}
|
||||
if ((pkgheader.pkg_content_size + pkgheader.pkg_content_offset) > pkgheader.pkg_size)
|
||||
{
|
||||
failreason = "Content size is bigger than pkg size";
|
||||
return false;
|
||||
}
|
||||
file.Seek(0, fsSeekSet);
|
||||
pkg = (U08*)mmap(pkgSize, file.fileDescr());
|
||||
if (pkg == nullptr)
|
||||
{
|
||||
failreason = "Can't allocate size for image";
|
||||
return false;
|
||||
}
|
||||
|
||||
file.Read(pkg, pkgSize);
|
||||
|
||||
U32 offset = pkgheader.pkg_table_entry_offset;
|
||||
U32 n_files = pkgheader.pkg_table_entry_count;
|
||||
|
||||
|
||||
for (U32 i = 0; i < n_files; i++) {
|
||||
PKGEntry entry = (PKGEntry&)pkg[offset + i * 0x20];
|
||||
ReadBE(entry);
|
||||
//try to figure out the name
|
||||
std::string name = getEntryNameByType(entry.id);
|
||||
printPkgFileEntry(entry,name);
|
||||
if (!name.empty())
|
||||
{
|
||||
std::size_t pos = name.find("/");//check if we have a directory (assuming we only have 1 level of subdirectories)
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
//directory found
|
||||
std::string dir = name.substr(0, pos+1);//include '/' as well
|
||||
std::string path = extractPath + dir;
|
||||
_mkdir(path.c_str());//make dir
|
||||
std::string file = name.substr(pos + 1);//read filename
|
||||
FsFile out;
|
||||
out.Open(path + file, fsWrite);
|
||||
out.Write(pkg + entry.offset, entry.size);
|
||||
out.Close();
|
||||
|
||||
}
|
||||
//found an name use it
|
||||
FsFile out;
|
||||
out.Open(extractPath + name, fsWrite);
|
||||
out.Write(pkg + entry.offset, entry.size);
|
||||
out.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
//just print with id
|
||||
FsFile out;
|
||||
out.Open(extractPath + std::to_string(entry.id), fsWrite);
|
||||
out.Write(pkg + entry.offset, entry.size);
|
||||
out.Close();
|
||||
}
|
||||
}
|
||||
//PFS read
|
||||
PFS pfs;
|
||||
pfs.pfsOuterReadHeader(pkg + pkgheader.pfs_image_offset);
|
||||
pfs.printPsfOuterHeader();
|
||||
//extract pfs_image.dat
|
||||
FsFile out;
|
||||
out.Open(extractPath + "pfs_image.dat", fsWrite);
|
||||
out.Write(pkg + pkgheader.pfs_image_offset, pkgheader.pfs_image_size);
|
||||
out.Close();
|
||||
munmap(pkg);
|
||||
return true;
|
||||
}
|
|
@ -1,412 +0,0 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include "Types.h"
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
enum PKGFlags : U32 {
|
||||
PKG_FLAGS_UNKNOWN = 0x01,
|
||||
PKG_FLAGS_VER_1 = 0x01000000,
|
||||
PKG_FLAGS_VER_2 = 0x02000000,
|
||||
PKG_FLAGS_INTERNAL = 0x40000000,
|
||||
PKG_FLAGS_FINALIZED = 0x80000000,
|
||||
};
|
||||
|
||||
enum PKGDrmType : U32
|
||||
{
|
||||
PKG_DRM_TYPE_NONE = 0x0,
|
||||
PKG_DRM_TYPE_PS4 = 0xF,
|
||||
};
|
||||
|
||||
enum PKGContentType : U32
|
||||
{
|
||||
/* pkg_ps4_app, pkg_ps4_patch, pkg_ps4_remaster */
|
||||
PKG_CONTENT_TYPE_GD = 0x1A,
|
||||
/* pkg_ps4_ac_data, pkg_ps4_sf_theme, pkg_ps4_theme */
|
||||
PKG_CONTENT_TYPE_AC = 0x1B,
|
||||
/* pkg_ps4_ac_nodata */
|
||||
PKG_CONTENT_TYPE_AL = 0x1C,
|
||||
/* pkg_ps4_delta_patch */
|
||||
PKG_CONTENT_TYPE_DP = 0x1E,
|
||||
};
|
||||
|
||||
enum PKGContentFlags : U32
|
||||
{
|
||||
PKG_CONTENT_FLAGS_FIRST_PATCH = 0x00100000,
|
||||
PKG_CONTENT_FLAGS_PATCHGO = 0x00200000,
|
||||
PKG_CONTENT_FLAGS_REMASTER = 0x00400000,
|
||||
PKG_CONTENT_FLAGS_PS_CLOUD = 0x00800000,
|
||||
PKG_CONTENT_FLAGS_GD_AC = 0x02000000,
|
||||
PKG_CONTENT_FLAGS_NON_GAME = 0x04000000,
|
||||
PKG_CONTENT_FLAGS_Unk_x8000000 = 0x08000000,
|
||||
PKG_CONTENT_FLAGS_SUBSEQUENT_PATCH = 0x40000000,
|
||||
PKG_CONTENT_FLAGS_DELTA_PATCH = 0x41000000,
|
||||
PKG_CONTENT_FLAGS_CUMULATIVE_PATCH = 0x60000000,
|
||||
};
|
||||
enum IROTag : U32
|
||||
{
|
||||
PKG_IRO_TAG_NONE = 0,
|
||||
/* SHAREfactory theme */
|
||||
PKG_IRO_TAG_SF_THEME = 0x1,
|
||||
/* System Software theme */
|
||||
PKG_IRO_TAG_SS_THEME = 0x2,
|
||||
};
|
||||
|
||||
|
||||
struct PKGHeader {
|
||||
/*BE*/U32 magic;// Magic
|
||||
/*BE*/U32 pkg_flags;
|
||||
/*BE*/U32 pkg_0x8; //unknown field
|
||||
/*BE*/U32 pkg_file_count;
|
||||
/*BE*/U32 pkg_table_entry_count;
|
||||
/*BE*/U16 pkg_sc_entry_count;
|
||||
/*BE*/U16 pkg_table_entry_count_2;// same as pkg_entry_count
|
||||
/*BE*/U32 pkg_table_entry_offset;//file table offset
|
||||
/*BE*/U32 pkg_sc_entry_data_size;
|
||||
/*BE*/U64 pkg_body_offset;//offset of PKG entries
|
||||
/*BE*/U64 pkg_body_size;//length of all PKG entries
|
||||
/*BE*/U64 pkg_content_offset;
|
||||
/*BE*/U64 pkg_content_size;
|
||||
U08 pkg_content_id[0x24];//packages' content ID as a 36-byte string
|
||||
U08 pkg_padding[0xC];//padding
|
||||
/*BE*/U32 pkg_drm_type;//DRM type
|
||||
/*BE*/U32 pkg_content_type;//Content type
|
||||
/*BE*/U32 pkg_content_flags;//Content flags
|
||||
/*BE*/U32 pkg_promote_size;
|
||||
/*BE*/U32 pkg_version_date;
|
||||
/*BE*/U32 pkg_version_hash;
|
||||
/*BE*/U32 pkg_0x088;
|
||||
/*BE*/U32 pkg_0x08C;
|
||||
/*BE*/U32 pkg_0x090;
|
||||
/*BE*/U32 pkg_0x094;
|
||||
/*BE*/U32 pkg_iro_tag;
|
||||
/*BE*/U32 pkg_drm_type_version;
|
||||
|
||||
U08 pkg_zeroes_1[0x60];
|
||||
|
||||
/* Digest table */
|
||||
U08 digest_entries1[0x20]; // sha256 digest for main entry 1
|
||||
U08 digest_entries2[0x20]; // sha256 digest for main entry 2
|
||||
U08 digest_table_digest[0x20]; // sha256 digest for digest table
|
||||
U08 digest_body_digest[0x20]; // sha256 digest for main table
|
||||
|
||||
U08 pkg_zeroes_2[0x280];
|
||||
|
||||
U32 pkg_0x400;
|
||||
|
||||
U32 pfs_image_count; // count of PFS images
|
||||
U64 pfs_image_flags; // PFS flags
|
||||
U64 pfs_image_offset; // offset to start of external PFS image
|
||||
U64 pfs_image_size; // size of external PFS image
|
||||
U64 mount_image_offset;
|
||||
U64 mount_image_size;
|
||||
U64 pkg_size;
|
||||
U32 pfs_signed_size;
|
||||
U32 pfs_cache_size;
|
||||
U08 pfs_image_digest[0x20];
|
||||
U08 pfs_signed_digest[0x20];
|
||||
U64 pfs_split_size_nth_0;
|
||||
U64 pfs_split_size_nth_1;
|
||||
|
||||
U08 pkg_zeroes_3[0xB50];
|
||||
|
||||
U08 pkg_digest[0x20];
|
||||
|
||||
};
|
||||
|
||||
inline void ReadBE(PKGHeader& s)
|
||||
{
|
||||
ReadBE(s.magic);
|
||||
ReadBE(s.pkg_flags);
|
||||
ReadBE(s.pkg_0x8);
|
||||
ReadBE(s.pkg_file_count);
|
||||
ReadBE(s.pkg_table_entry_count);
|
||||
ReadBE(s.pkg_sc_entry_count);
|
||||
ReadBE(s.pkg_table_entry_count_2);
|
||||
ReadBE(s.pkg_table_entry_offset);
|
||||
ReadBE(s.pkg_sc_entry_data_size);
|
||||
ReadBE(s.pkg_body_offset);
|
||||
ReadBE(s.pkg_body_size);
|
||||
ReadBE(s.pkg_content_offset);
|
||||
ReadBE(s.pkg_content_size);
|
||||
ReadBE(s.pkg_drm_type);
|
||||
ReadBE(s.pkg_content_type);
|
||||
ReadBE(s.pkg_content_flags);
|
||||
ReadBE(s.pkg_promote_size);
|
||||
ReadBE(s.pkg_version_date);
|
||||
ReadBE(s.pkg_version_hash);
|
||||
ReadBE(s.pkg_0x088);
|
||||
ReadBE(s.pkg_0x08C);
|
||||
ReadBE(s.pkg_0x090);
|
||||
ReadBE(s.pkg_0x094);
|
||||
ReadBE(s.pkg_iro_tag);
|
||||
ReadBE(s.pkg_drm_type_version);
|
||||
ReadBE(s.pkg_0x400);
|
||||
ReadBE(s.pfs_image_count);
|
||||
ReadBE(s.pfs_image_flags);
|
||||
ReadBE(s.pfs_image_offset);
|
||||
ReadBE(s.pfs_image_size);
|
||||
ReadBE(s.mount_image_offset);
|
||||
ReadBE(s.mount_image_size);
|
||||
ReadBE(s.pfs_signed_size);
|
||||
ReadBE(s.pfs_cache_size);
|
||||
ReadBE(s.pkg_size);
|
||||
ReadBE(s.pfs_split_size_nth_0);
|
||||
ReadBE(s.pfs_split_size_nth_1);
|
||||
}
|
||||
|
||||
struct PKGEntry {
|
||||
U32 id; // File ID, useful for files without a filename entry
|
||||
U32 filename_offset; // Offset into the filenames table (ID 0x200) where this file's name is located
|
||||
U32 flags1; // Flags including encrypted flag, etc
|
||||
U32 flags2; // Flags including encryption key index, etc
|
||||
U32 offset; // Offset into PKG to find the file
|
||||
U32 size; // Size of the file
|
||||
U64 padding; // blank padding
|
||||
};
|
||||
|
||||
inline void ReadBE(PKGEntry& s)
|
||||
{
|
||||
ReadBE(s.id);
|
||||
ReadBE(s.filename_offset);
|
||||
ReadBE(s.flags1);
|
||||
ReadBE(s.flags2);
|
||||
ReadBE(s.offset);
|
||||
ReadBE(s.size);
|
||||
ReadBE(s.padding);
|
||||
}
|
||||
|
||||
class PKG
|
||||
{
|
||||
private:
|
||||
U08* pkg;
|
||||
U64 pkgSize = 0;
|
||||
S08 pkgTitleID[9];
|
||||
std::string extractPath;
|
||||
PKGHeader pkgheader;
|
||||
|
||||
public:
|
||||
PKG();
|
||||
~PKG();
|
||||
bool open(const std::string& filepath);
|
||||
U64 getPkgSize()
|
||||
{
|
||||
return pkgSize;
|
||||
}
|
||||
std::string getTitleID()
|
||||
{
|
||||
return std::string(pkgTitleID,9);
|
||||
}
|
||||
bool extract(const std::string& filepath, const std::string& extractPath, std::string& failreason);
|
||||
|
||||
void* mmap(size_t sLength, std::FILE* nFd) {
|
||||
HANDLE hHandle;
|
||||
void* pStart=nullptr;
|
||||
hHandle = CreateFileMapping(
|
||||
(HANDLE)_get_osfhandle(_fileno((nFd))),
|
||||
NULL, // default security
|
||||
PAGE_WRITECOPY, // read/write access
|
||||
0, // maximum object size (high-order DWORD)
|
||||
0, // maximum object size (low-order DWORD)
|
||||
NULL); // name of mapping object
|
||||
|
||||
if (hHandle != NULL) {
|
||||
pStart = MapViewOfFile(hHandle, FILE_MAP_COPY, 0, 0, sLength);
|
||||
}
|
||||
if(pStart == NULL)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return pStart;
|
||||
}
|
||||
int munmap(void* pStart) {
|
||||
if (UnmapViewOfFile(pStart) != 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
typedef struct {
|
||||
U32 type;
|
||||
std::string name;
|
||||
} pkg_entry_value;
|
||||
|
||||
std::string getEntryNameByType(U32 type)
|
||||
{
|
||||
pkg_entry_value entries[] = {
|
||||
{ 0x0001, "digests" },
|
||||
{ 0x0010, "entry_keys" },
|
||||
{ 0x0020, "image_key" },
|
||||
{ 0x0080, "general_digests" },
|
||||
{ 0x0100, "metas" },
|
||||
{ 0x0200, "entry_names" },
|
||||
{ 0x0400, "license.dat" },
|
||||
{ 0x0401, "license.info" },
|
||||
{ 0x0402, "nptitle.dat" },
|
||||
{ 0x0403, "npbind.dat" },
|
||||
{ 0x0409, "psreserved.dat" },
|
||||
{ 0x1000, "param.sfo" },
|
||||
{ 0x1001, "playgo-chunk.dat" },
|
||||
{ 0x1002, "playgo-chunk.sha" },
|
||||
{ 0x1003, "playgo-manifest.xml" },
|
||||
{ 0x1004, "pronunciation.xml" },
|
||||
{ 0x1005, "pronunciation.sig" },
|
||||
{ 0x1006, "pic1.png" },
|
||||
{ 0x1007, "pubtoolinfo.dat" },
|
||||
{ 0x100B, "shareparam.json" },
|
||||
{ 0x100C, "shareoverlayimage.png" },
|
||||
{ 0x100E, "shareprivacyguardimage.png"},
|
||||
{ 0x1200, "icon0.png" },
|
||||
{ 0x1220, "pic0.png" },
|
||||
{ 0x1240, "snd0.at9" },
|
||||
{ 0x1280, "icon0.dds" },
|
||||
{ 0x12A0, "pic0.dds" },
|
||||
{ 0x12C0, "pic1.dds" },
|
||||
{ 0x1400, "trophy/trophy00.trp" }
|
||||
};
|
||||
std::string entry_name="";
|
||||
|
||||
for (size_t i = 0; i < sizeof entries / sizeof entries[0]; i++) {
|
||||
if (type == entries[i].type) {
|
||||
entry_name = entries[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return entry_name;
|
||||
}
|
||||
|
||||
void printPkgHeader()
|
||||
{
|
||||
printf("PS4 PKG header:\n");
|
||||
printf("- PKG magic: 0x%X\n", pkgheader.magic);
|
||||
printf("- PKG flags: 0x%X", pkgheader.pkg_flags);
|
||||
if (pkgheader.pkg_flags & PKG_FLAGS_UNKNOWN)
|
||||
printf(" unknown");
|
||||
if (pkgheader.pkg_flags & PKG_FLAGS_VER_1)
|
||||
printf(" ver_1");
|
||||
if (pkgheader.pkg_flags & PKG_FLAGS_VER_2)
|
||||
printf(" ver_2");
|
||||
if (pkgheader.pkg_flags & PKG_FLAGS_INTERNAL)
|
||||
printf(" internal");
|
||||
if(pkgheader.pkg_flags & PKG_FLAGS_FINALIZED)
|
||||
printf(" finalized");
|
||||
printf("\n");
|
||||
printf("- PKG 0x8: 0x%X\n", pkgheader.pkg_0x8);
|
||||
printf("- PKG file count: %u\n", pkgheader.pkg_file_count);
|
||||
printf("- PKG table entries count: %u\n", pkgheader.pkg_table_entry_count);
|
||||
printf("- PKG system entries count: %u\n", pkgheader.pkg_sc_entry_count);
|
||||
printf("- PKG table entries2 count: %u\n", pkgheader.pkg_table_entry_count_2);
|
||||
printf("- PKG table offset: 0x%X\n", pkgheader.pkg_table_entry_offset);
|
||||
printf("- PKG table entry data size: 0x%X\n", pkgheader.pkg_sc_entry_data_size);
|
||||
printf("- PKG body offset: 0x%" PRIx64 "\n", pkgheader.pkg_body_offset);
|
||||
printf("- PKG body size: 0x%" PRIx64 "\n", pkgheader.pkg_body_size);
|
||||
printf("- PKG content offset: 0x%" PRIx64 "\n", pkgheader.pkg_content_offset);
|
||||
printf("- PKG content size: 0x%" PRIx64 "\n", pkgheader.pkg_content_offset);
|
||||
printf("- PKG pkg_content_id: %s\n", pkgheader.pkg_content_id);
|
||||
|
||||
printf("- PKG drm type: 0x%X", pkgheader.pkg_drm_type);
|
||||
if (pkgheader.pkg_drm_type == PKG_DRM_TYPE_NONE)
|
||||
printf(" None");
|
||||
if (pkgheader.pkg_drm_type == PKG_DRM_TYPE_PS4)
|
||||
printf(" PS4");
|
||||
printf("\n");
|
||||
printf("- PKG content type: 0x%X", pkgheader.pkg_content_type);
|
||||
if (pkgheader.pkg_content_type == PKG_CONTENT_TYPE_GD)
|
||||
printf(" GD");
|
||||
if (pkgheader.pkg_content_type == PKG_CONTENT_TYPE_AC)
|
||||
printf(" AC");
|
||||
if (pkgheader.pkg_content_type == PKG_CONTENT_TYPE_AL)
|
||||
printf(" AL");
|
||||
if (pkgheader.pkg_content_type == PKG_CONTENT_TYPE_DP)
|
||||
printf(" DP");
|
||||
printf("\n");
|
||||
printf("- PKG content flags: 0x%X", pkgheader.pkg_content_flags);
|
||||
if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_FIRST_PATCH)
|
||||
printf(" First_patch");
|
||||
if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_PATCHGO)
|
||||
printf(" Patch_go");
|
||||
if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_REMASTER)
|
||||
printf(" Remastered");
|
||||
if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_PS_CLOUD)
|
||||
printf(" Cloud");
|
||||
if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_GD_AC)
|
||||
printf(" AC");
|
||||
if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_NON_GAME)
|
||||
printf(" Non_game");
|
||||
if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_Unk_x8000000)
|
||||
printf(" Unk_x8000000");
|
||||
if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_SUBSEQUENT_PATCH)
|
||||
printf(" Subsequent_patch");
|
||||
if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_DELTA_PATCH)
|
||||
printf(" Delta_patch");
|
||||
if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_CUMULATIVE_PATCH)
|
||||
printf(" Cumulative_patch");
|
||||
printf("\n");
|
||||
printf("- PKG promote size: 0x%X\n", pkgheader.pkg_promote_size);
|
||||
printf("- PKG version date: 0x%X\n", pkgheader.pkg_version_date);
|
||||
printf("- PKG version hash: 0x%X\n", pkgheader.pkg_version_hash);
|
||||
printf("- PKG 0x088: 0x%X\n", pkgheader.pkg_0x088);
|
||||
printf("- PKG 0x08C: 0x%X\n", pkgheader.pkg_0x08C);
|
||||
printf("- PKG 0x090: 0x%X\n", pkgheader.pkg_0x090);
|
||||
printf("- PKG 0x094: 0x%X\n", pkgheader.pkg_0x094);
|
||||
printf("- PKG iro tag: 0x%X", pkgheader.pkg_iro_tag);
|
||||
if (pkgheader.pkg_iro_tag == PKG_IRO_TAG_NONE)
|
||||
printf(" None");
|
||||
if (pkgheader.pkg_iro_tag == PKG_IRO_TAG_SF_THEME)
|
||||
printf(" SF Theme");
|
||||
if (pkgheader.pkg_iro_tag == PKG_IRO_TAG_SS_THEME)
|
||||
printf(" SS Theme");
|
||||
printf("\n");
|
||||
printf("- PKG drm type version: 0x%X\n", pkgheader.pkg_drm_type_version);
|
||||
|
||||
printf("- PKG digest_entries1: ");
|
||||
for (U08 s = 0; s < 0x20; s++) printf("%X", pkgheader.digest_entries1[s]);
|
||||
printf("\n");
|
||||
printf("- PKG digest_entries2: ");
|
||||
for (U08 s = 0; s < 0x20; s++)printf("%X", pkgheader.digest_entries2[s]);
|
||||
printf("\n");
|
||||
printf("- PKG digest_table_digest: ");
|
||||
for (U08 s = 0; s < 0x20; s++)printf("%X", pkgheader.digest_table_digest[s]);
|
||||
printf("\n");
|
||||
printf("- PKG digest_body_digest: ");
|
||||
for (U08 s = 0; s < 0x20; s++)printf("%X", pkgheader.digest_body_digest[s]);
|
||||
printf("\n");
|
||||
printf("- PKG 0x400: 0x%X\n", pkgheader.pkg_0x400);
|
||||
printf("- PKG pfs_image_count: 0x%X\n", pkgheader.pfs_image_count);
|
||||
printf("- PKG pfs_image_flags: 0x%" PRIx64 "\n", pkgheader.pfs_image_flags);
|
||||
printf("- PKG pfs_image_offset: 0x%" PRIx64 "\n", pkgheader.pfs_image_offset);
|
||||
printf("- PKG mount_image_offset: 0x%" PRIx64 "\n", pkgheader.mount_image_offset);
|
||||
printf("- PKG mount_image_size: 0x%" PRIx64 "\n", pkgheader.mount_image_size);
|
||||
printf("- PKG size: 0x%" PRIx64 "\n", pkgheader.pkg_size);
|
||||
printf("- PKG pfs_signed_size: 0x%X\n", pkgheader.pfs_signed_size);
|
||||
printf("- PKG pfs_cache_size: 0x%X\n", pkgheader.pfs_cache_size);
|
||||
printf("- PKG pfs_image_digest: ");
|
||||
for (U08 s = 0; s < 0x20; s++)printf("%X", pkgheader.pfs_image_digest[s]);
|
||||
printf("\n");
|
||||
printf("- PKG pfs_signed_digest: ");
|
||||
for (U08 s = 0; s < 0x20; s++)printf("%X", pkgheader.pfs_signed_digest[s]);
|
||||
printf("\n");
|
||||
printf("- PKG pfs_split_size_nth_0: 0x%" PRIx64 "\n", pkgheader.pfs_split_size_nth_0);
|
||||
printf("- PKG pfs_split_size_nth_1: 0x%" PRIx64 "\n", pkgheader.pfs_split_size_nth_1);
|
||||
printf("- PKG pkg_digest: ");
|
||||
for (U08 s = 0; s < 0x20; s++)printf("%X", pkgheader.pkg_digest[s]);
|
||||
printf("\n");
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void printPkgFileEntry(PKGEntry entry, std::string name)
|
||||
{
|
||||
|
||||
printf("-PS4 File Entry:\n");
|
||||
printf("--found name: %s\n", name.c_str());
|
||||
printf("--id: 0x%X\n", entry.id);
|
||||
printf("--filename_offset: 0x%X\n", entry.filename_offset);
|
||||
printf("--flags1: 0x%X\n", entry.flags1);
|
||||
printf("--flags2: 0x%X\n", entry.flags2);
|
||||
printf("--offset: 0x%X\n", entry.offset);
|
||||
printf("--size: 0x%X\n", entry.size);
|
||||
}
|
||||
};
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
#pragma once
|
||||
#include <immintrin.h>
|
||||
|
||||
using S08 = char;
|
||||
using S16 = short;
|
||||
using S32 = int;
|
||||
using S64 = long long;
|
||||
|
||||
using U08 = unsigned char;
|
||||
using U16 = unsigned short;
|
||||
using U32 = unsigned int;
|
||||
using U64 = unsigned long long;
|
||||
|
||||
using F32 = float;
|
||||
using F64 = double;
|
||||
|
||||
|
||||
template< typename T > T inline LoadBE(T* src) { return *src; };
|
||||
template< typename T > inline void StoreBE(T* dst, T src) { *dst = src; };
|
||||
|
||||
inline S16 LoadBE(S16* src) { return _loadbe_i16(src); };
|
||||
inline S32 LoadBE(S32* src) { return _loadbe_i32(src); };
|
||||
inline S64 LoadBE(S64* src) { return _loadbe_i64(src); };
|
||||
|
||||
inline U16 LoadBE(U16* src) { return _load_be_u16(src); };
|
||||
inline U32 LoadBE(U32* src) { return _load_be_u32(src); };
|
||||
inline U64 LoadBE(U64* src) { return _load_be_u64(src); };
|
||||
|
||||
inline void StoreBE(S16* dst, S16 const src) { _storebe_i16(dst, src); };
|
||||
inline void StoreBE(S32* dst, S32 const src) { _storebe_i32(dst, src); };
|
||||
inline void StoreBE(S64* dst, S64 const src) { _storebe_i64(dst, src); };
|
||||
|
||||
inline void StoreBE(U16* dst, U16 const src) { _store_be_u16(dst, src); };
|
||||
inline void StoreBE(U32* dst, U32 const src) { _store_be_u32(dst, src); };
|
||||
inline void StoreBE(U64* dst, U64 const src) { _store_be_u64(dst, src); };
|
||||
|
||||
|
||||
template< typename T > inline void ReadBE(T& val)
|
||||
{
|
||||
val = LoadBE(&val); // swap inplace
|
||||
}
|
||||
|
||||
template< typename T > inline void WriteBE(T& val)
|
||||
{
|
||||
StoreBE(&val, val); // swap inplace
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
#include <iostream>
|
||||
#include <sys/stat.h>
|
||||
#include <direct.h>
|
||||
#include "PKG.h"
|
||||
int main()
|
||||
{
|
||||
PKG pkg;
|
||||
if (!pkg.open("test.pkg"))
|
||||
{
|
||||
std::cout << "Error reading test.pkg\n";
|
||||
return 0;
|
||||
}
|
||||
pkg.printPkgHeader();
|
||||
std::string gamedir = "game/" + pkg.getTitleID();
|
||||
struct stat sb;
|
||||
if (stat(gamedir.c_str(), &sb) != 0)
|
||||
{
|
||||
_mkdir(gamedir.c_str());
|
||||
}
|
||||
std::string extractpath = "game/" + pkg.getTitleID() + "/";
|
||||
std::string failreason;
|
||||
if (!pkg.extract("test.pkg", extractpath, failreason))
|
||||
{
|
||||
std::cout << "Error extraction " << failreason;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.4.33213.308
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pkgextract", "pkgextract.vcxproj", "{446E2603-4743-49E6-B4CB-56835155399E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{446E2603-4743-49E6-B4CB-56835155399E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{446E2603-4743-49E6-B4CB-56835155399E}.Debug|x64.Build.0 = Debug|x64
|
||||
{446E2603-4743-49E6-B4CB-56835155399E}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{446E2603-4743-49E6-B4CB-56835155399E}.Debug|x86.Build.0 = Debug|Win32
|
||||
{446E2603-4743-49E6-B4CB-56835155399E}.Release|x64.ActiveCfg = Release|x64
|
||||
{446E2603-4743-49E6-B4CB-56835155399E}.Release|x64.Build.0 = Release|x64
|
||||
{446E2603-4743-49E6-B4CB-56835155399E}.Release|x86.ActiveCfg = Release|Win32
|
||||
{446E2603-4743-49E6-B4CB-56835155399E}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3DFF47CF-BF9E-4143-A8C0-8ED0C43581CB}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,144 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{446e2603-4743-49e6-b4cb-56835155399e}</ProjectGuid>
|
||||
<RootNamespace>pkgextract</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="FsFile.cpp" />
|
||||
<ClCompile Include="PFS.cpp" />
|
||||
<ClCompile Include="PKG.cpp" />
|
||||
<ClCompile Include="pkgextract.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="FsFile.h" />
|
||||
<ClInclude Include="PFS.h" />
|
||||
<ClInclude Include="PKG.h" />
|
||||
<ClInclude Include="Types.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -1,45 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pkgextract.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PKG.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FsFile.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PFS.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="PKG.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FsFile.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Types.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PFS.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in New Issue