[XAM] Allow content to read license from header

This commit is contained in:
Gliniak 2024-10-06 20:14:27 +02:00
parent 1cda06d5bf
commit 9e4b2e343f
5 changed files with 47 additions and 11 deletions

View File

@ -53,6 +53,26 @@ ContentPackage::~ContentPackage() {
fs->UnregisterDevice(device_path_);
}
void ContentPackage::LoadPackageLicenseMask(
const std::filesystem::path header_path) {
license_ = 0;
if (!std::filesystem::exists(header_path)) {
return;
}
auto file = xe::filesystem::OpenFile(header_path, "rb");
auto file_size = std::filesystem::file_size(header_path);
if (file_size < sizeof(XCONTENT_AGGREGATE_DATA) + sizeof(license_)) {
fclose(file);
return;
}
fseek(file, sizeof(XCONTENT_AGGREGATE_DATA), SEEK_SET);
size_t result = fread(&license_, 1, sizeof(license_), file);
fclose(file);
}
ContentManager::ContentManager(KernelState* kernel_state,
const std::filesystem::path& root_path)
: kernel_state_(kernel_state), root_path_(root_path) {}
@ -267,16 +287,17 @@ X_RESULT ContentManager::ReadContentHeaderFile(
std::array<uint8_t, header_size> buffer;
auto file_size = std::filesystem::file_size(header_file_path);
if (file_size != header_size && file_size != sizeof(XCONTENT_DATA)) {
if (file_size < header_size) {
fclose(file);
return X_STATUS_END_OF_FILE;
}
size_t result = fread(buffer.data(), 1, file_size, file);
if (result != file_size) {
size_t result = fread(buffer.data(), 1, header_size, file);
if (result != header_size) {
fclose(file);
return X_STATUS_END_OF_FILE;
}
fclose(file);
std::memcpy(&data, buffer.data(), buffer.size());
// It only reads basic info, however importing savefiles
@ -321,6 +342,7 @@ X_RESULT ContentManager::CreateContent(const std::string_view root_name,
X_RESULT ContentManager::OpenContent(const std::string_view root_name,
const uint64_t xuid,
const XCONTENT_AGGREGATE_DATA& data,
uint32_t& content_license,
const uint32_t disc_number) {
auto global_lock = global_critical_region_.Acquire();
@ -339,6 +361,11 @@ X_RESULT ContentManager::OpenContent(const std::string_view root_name,
auto package = ResolvePackage(root_name, xuid, data, disc_number);
assert_not_null(package);
package->LoadPackageLicenseMask(ResolvePackageHeaderPath(
data.file_name(), xuid, kernel_state_->title_id(), data.content_type));
content_license = package->GetPackageLicense();
open_packages_.insert({string_key::create(root_name), package.release()});
return X_ERROR_SUCCESS;

View File

@ -125,15 +125,21 @@ class ContentPackage {
const std::filesystem::path& package_path);
~ContentPackage();
void LoadPackageLicenseMask(const std::filesystem::path header_path);
const XCONTENT_AGGREGATE_DATA& GetPackageContentData() const {
return content_data_;
}
const uint32_t GetPackageLicense() const { return license_; }
private:
KernelState* kernel_state_;
std::string root_name_;
std::string device_path_;
XCONTENT_AGGREGATE_DATA content_data_;
uint32_t license_;
;
};
class ContentManager {
@ -161,6 +167,7 @@ class ContentManager {
const XCONTENT_AGGREGATE_DATA& data);
X_RESULT OpenContent(const std::string_view root_name, const uint64_t xuid,
const XCONTENT_AGGREGATE_DATA& data,
uint32_t& content_license,
const uint32_t disc_number = -1);
X_RESULT CloseContent(const std::string_view root_name);
X_RESULT GetContentThumbnail(const uint64_t xuid,

View File

@ -251,23 +251,19 @@ dword_result_t xeXamContentCreate(dword_t user_index, lpstring_t root_name,
break;
}
uint32_t content_license = 0;
if (disposition == kDispositionState::Create) {
result = content_manager->CreateContent(root_name, xuid, content_data);
if (XSUCCEEDED(result)) {
content_manager->WriteContentHeaderFile(xuid, &content_data);
}
} else if (disposition == kDispositionState::Open) {
result = content_manager->OpenContent(root_name, xuid, content_data);
result = content_manager->OpenContent(root_name, xuid, content_data,
content_license);
}
if (license_mask_ptr && XSUCCEEDED(result)) {
*license_mask_ptr = 0; // Stub!
// Set license only for DLCs and XBLA titles
if (content_data.content_type == xe::XContentType::kMarketplaceContent ||
content_data.content_type == xe::XContentType::kArcadeTitle) {
*license_mask_ptr = static_cast<uint32_t>(cvars::license_mask);
}
*license_mask_ptr = content_license;
}
extended_error = X_HRESULT_FROM_WIN32(result);

View File

@ -64,6 +64,9 @@ class XContentContainerDevice : public Device {
}
kernel::xam::XCONTENT_AGGREGATE_DATA content_header() const;
uint32_t license_mask() const {
return header_->content_header.licenses[0].license_bits;
}
protected:
XContentContainerDevice(const std::string_view mount_path,

View File

@ -437,8 +437,11 @@ void VirtualFileSystem::ExtractContentHeader(Device* device,
auto file = xe::filesystem::OpenFile(header_path, "wb");
kernel::xam::XCONTENT_AGGREGATE_DATA data =
xcontent_device->content_header();
uint32_t license_mask = xcontent_device->license_mask();
data.set_file_name(base_path.filename().string());
fwrite(&data, 1, sizeof(kernel::xam::XCONTENT_AGGREGATE_DATA), file);
fwrite(&license_mask, 1, sizeof(license_mask), file);
fclose(file);
}
return;