20 changed files with 855 additions and 521 deletions
-
8src/core/CMakeLists.txt
-
2src/core/hle/service/am/am.cpp
-
21src/core/hle/service/caps/caps.cpp
-
81src/core/hle/service/caps/caps.h
-
311src/core/hle/service/caps/caps_a.cpp
-
107src/core/hle/service/caps/caps_a.h
-
50src/core/hle/service/caps/caps_c.cpp
-
10src/core/hle/service/caps/caps_c.h
-
342src/core/hle/service/caps/caps_manager.cpp
-
72src/core/hle/service/caps/caps_manager.h
-
35src/core/hle/service/caps/caps_result.h
-
5src/core/hle/service/caps/caps_sc.cpp
-
6src/core/hle/service/caps/caps_sc.h
-
5src/core/hle/service/caps/caps_ss.cpp
-
6src/core/hle/service/caps/caps_ss.h
-
9src/core/hle/service/caps/caps_su.cpp
-
6src/core/hle/service/caps/caps_su.h
-
184src/core/hle/service/caps/caps_types.h
-
104src/core/hle/service/caps/caps_u.cpp
-
12src/core/hle/service/caps/caps_u.h
@ -0,0 +1,342 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
|
||||
|
#include <sstream>
|
||||
|
#include <stb_image.h>
|
||||
|
#include <stb_image_resize.h>
|
||||
|
|
||||
|
#include "common/fs/file.h"
|
||||
|
#include "common/fs/path_util.h"
|
||||
|
#include "common/logging/log.h"
|
||||
|
#include "core/hle/service/caps/caps_manager.h"
|
||||
|
#include "core/hle/service/caps/caps_result.h"
|
||||
|
|
||||
|
namespace Service::Capture { |
||||
|
|
||||
|
AlbumManager::AlbumManager() {} |
||||
|
|
||||
|
AlbumManager::~AlbumManager() = default; |
||||
|
|
||||
|
Result AlbumManager::DeleteAlbumFile(const AlbumFileId& file_id) { |
||||
|
if (file_id.storage > AlbumStorage::Sd) { |
||||
|
return ResultInvalidStorage; |
||||
|
} |
||||
|
|
||||
|
if (!is_mounted) { |
||||
|
return ResultIsNotMounted; |
||||
|
} |
||||
|
|
||||
|
std::filesystem::path path; |
||||
|
const auto result = GetFile(path, file_id); |
||||
|
|
||||
|
if (result.IsError()) { |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
if (!Common::FS::RemoveFile(path)) { |
||||
|
return ResultFileNotFound; |
||||
|
} |
||||
|
|
||||
|
return ResultSuccess; |
||||
|
} |
||||
|
|
||||
|
Result AlbumManager::IsAlbumMounted(AlbumStorage storage) { |
||||
|
if (storage > AlbumStorage::Sd) { |
||||
|
return ResultInvalidStorage; |
||||
|
} |
||||
|
|
||||
|
is_mounted = true; |
||||
|
|
||||
|
if (storage == AlbumStorage::Sd) { |
||||
|
FindScreenshots(); |
||||
|
} |
||||
|
|
||||
|
return is_mounted ? ResultSuccess : ResultIsNotMounted; |
||||
|
} |
||||
|
|
||||
|
Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, |
||||
|
u8 flags) const { |
||||
|
if (storage > AlbumStorage::Sd) { |
||||
|
return ResultInvalidStorage; |
||||
|
} |
||||
|
|
||||
|
if (!is_mounted) { |
||||
|
return ResultIsNotMounted; |
||||
|
} |
||||
|
|
||||
|
for (auto& [file_id, path] : album_files) { |
||||
|
if (file_id.storage != storage) { |
||||
|
continue; |
||||
|
} |
||||
|
if (out_entries.size() >= SdAlbumFileLimit) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
const auto entry_size = Common::FS::GetSize(path); |
||||
|
out_entries.push_back({ |
||||
|
.entry_size = entry_size, |
||||
|
.file_id = file_id, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return ResultSuccess; |
||||
|
} |
||||
|
|
||||
|
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, |
||||
|
ContentType contex_type, AlbumFileDateTime start_date, |
||||
|
AlbumFileDateTime end_date, u64 aruid) const { |
||||
|
if (!is_mounted) { |
||||
|
return ResultIsNotMounted; |
||||
|
} |
||||
|
|
||||
|
for (auto& [file_id, path] : album_files) { |
||||
|
if (file_id.type != contex_type) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (file_id.date > start_date) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (file_id.date < end_date) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (out_entries.size() >= SdAlbumFileLimit) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
const auto entry_size = Common::FS::GetSize(path); |
||||
|
ApplicationAlbumFileEntry entry{.entry = |
||||
|
{ |
||||
|
.size = entry_size, |
||||
|
.hash{}, |
||||
|
.datetime = file_id.date, |
||||
|
.storage = file_id.storage, |
||||
|
.content = contex_type, |
||||
|
.unknown = 1, |
||||
|
}, |
||||
|
.datetime = file_id.date, |
||||
|
.unknown = {}}; |
||||
|
out_entries.push_back(entry); |
||||
|
} |
||||
|
|
||||
|
return ResultSuccess; |
||||
|
} |
||||
|
|
||||
|
Result AlbumManager::GetAutoSavingStorage(bool& out_is_autosaving) const { |
||||
|
out_is_autosaving = false; |
||||
|
return ResultSuccess; |
||||
|
} |
||||
|
|
||||
|
Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, |
||||
|
std::vector<u8>& out_image, |
||||
|
const AlbumFileId& file_id, |
||||
|
const ScreenShotDecodeOption& decoder_options) const { |
||||
|
if (file_id.storage > AlbumStorage::Sd) { |
||||
|
return ResultInvalidStorage; |
||||
|
} |
||||
|
|
||||
|
if (!is_mounted) { |
||||
|
return ResultIsNotMounted; |
||||
|
} |
||||
|
|
||||
|
out_image_output = { |
||||
|
.width = 1280, |
||||
|
.height = 720, |
||||
|
.attribute = |
||||
|
{ |
||||
|
.unknown_0{}, |
||||
|
.orientation = AlbumImageOrientation::None, |
||||
|
.unknown_1{}, |
||||
|
.unknown_2{}, |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
std::filesystem::path path; |
||||
|
const auto result = GetFile(path, file_id); |
||||
|
|
||||
|
if (result.IsError()) { |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha); |
||||
|
|
||||
|
return LoadImage(out_image, path, static_cast<int>(out_image_output.width), |
||||
|
+static_cast<int>(out_image_output.height), decoder_options.flags); |
||||
|
} |
||||
|
|
||||
|
Result AlbumManager::LoadAlbumScreenShotThumbnail( |
||||
|
LoadAlbumScreenShotImageOutput& out_image_output, std::vector<u8>& out_image, |
||||
|
const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options) const { |
||||
|
if (file_id.storage > AlbumStorage::Sd) { |
||||
|
return ResultInvalidStorage; |
||||
|
} |
||||
|
|
||||
|
if (!is_mounted) { |
||||
|
return ResultIsNotMounted; |
||||
|
} |
||||
|
|
||||
|
out_image_output = { |
||||
|
.width = 320, |
||||
|
.height = 180, |
||||
|
.attribute = |
||||
|
{ |
||||
|
.unknown_0{}, |
||||
|
.orientation = AlbumImageOrientation::None, |
||||
|
.unknown_1{}, |
||||
|
.unknown_2{}, |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
std::filesystem::path path; |
||||
|
const auto result = GetFile(path, file_id); |
||||
|
|
||||
|
if (result.IsError()) { |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha); |
||||
|
|
||||
|
return LoadImage(out_image, path, static_cast<int>(out_image_output.width), |
||||
|
+static_cast<int>(out_image_output.height), decoder_options.flags); |
||||
|
} |
||||
|
|
||||
|
Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const { |
||||
|
const auto file = album_files.find(file_id); |
||||
|
|
||||
|
if (file == album_files.end()) { |
||||
|
return ResultFileNotFound; |
||||
|
} |
||||
|
|
||||
|
out_path = file->second; |
||||
|
return ResultSuccess; |
||||
|
} |
||||
|
|
||||
|
void AlbumManager::FindScreenshots() { |
||||
|
is_mounted = false; |
||||
|
album_files.clear(); |
||||
|
|
||||
|
// TODO: Swap this with a blocking operation.
|
||||
|
const auto screenshots_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ScreenshotsDir); |
||||
|
Common::FS::IterateDirEntries( |
||||
|
screenshots_dir, |
||||
|
[this](const std::filesystem::path& full_path) { |
||||
|
AlbumEntry entry; |
||||
|
if (GetAlbumEntry(entry, full_path).IsError()) { |
||||
|
return true; |
||||
|
} |
||||
|
while (album_files.contains(entry.file_id)) { |
||||
|
if (++entry.file_id.date.unique_id == 0) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
album_files[entry.file_id] = full_path; |
||||
|
return true; |
||||
|
}, |
||||
|
Common::FS::DirEntryFilter::File); |
||||
|
|
||||
|
is_mounted = true; |
||||
|
} |
||||
|
|
||||
|
Result AlbumManager::GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const { |
||||
|
std::istringstream line_stream(path.filename().string()); |
||||
|
std::string date; |
||||
|
std::string application; |
||||
|
std::string time; |
||||
|
|
||||
|
// Parse filename to obtain entry properties
|
||||
|
std::getline(line_stream, application, '_'); |
||||
|
std::getline(line_stream, date, '_'); |
||||
|
std::getline(line_stream, time, '_'); |
||||
|
|
||||
|
std::istringstream date_stream(date); |
||||
|
std::istringstream time_stream(time); |
||||
|
std::string year; |
||||
|
std::string month; |
||||
|
std::string day; |
||||
|
std::string hour; |
||||
|
std::string minute; |
||||
|
std::string second; |
||||
|
|
||||
|
std::getline(date_stream, year, '-'); |
||||
|
std::getline(date_stream, month, '-'); |
||||
|
std::getline(date_stream, day, '-'); |
||||
|
|
||||
|
std::getline(time_stream, hour, '-'); |
||||
|
std::getline(time_stream, minute, '-'); |
||||
|
std::getline(time_stream, second, '-'); |
||||
|
|
||||
|
try { |
||||
|
out_entry = { |
||||
|
.entry_size = 1, |
||||
|
.file_id{ |
||||
|
.application_id = static_cast<u64>(std::stoll(application, 0, 16)), |
||||
|
.date = |
||||
|
{ |
||||
|
.year = static_cast<u16>(std::stoi(year)), |
||||
|
.month = static_cast<u8>(std::stoi(month)), |
||||
|
.day = static_cast<u8>(std::stoi(day)), |
||||
|
.hour = static_cast<u8>(std::stoi(hour)), |
||||
|
.minute = static_cast<u8>(std::stoi(minute)), |
||||
|
.second = static_cast<u8>(std::stoi(second)), |
||||
|
.unique_id = 0, |
||||
|
}, |
||||
|
.storage = AlbumStorage::Sd, |
||||
|
.type = ContentType::Screenshot, |
||||
|
.unknown = 1, |
||||
|
}, |
||||
|
}; |
||||
|
} catch (const std::invalid_argument&) { |
||||
|
return ResultUnknown; |
||||
|
} catch (const std::out_of_range&) { |
||||
|
return ResultUnknown; |
||||
|
} catch (const std::exception&) { |
||||
|
return ResultUnknown; |
||||
|
} |
||||
|
|
||||
|
return ResultSuccess; |
||||
|
} |
||||
|
|
||||
|
Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::path& path, |
||||
|
int width, int height, ScreenShotDecoderFlag flag) const { |
||||
|
if (out_image.size() != static_cast<std::size_t>(width * height * STBI_rgb_alpha)) { |
||||
|
return ResultUnknown; |
||||
|
} |
||||
|
|
||||
|
const Common::FS::IOFile db_file{path, Common::FS::FileAccessMode::Read, |
||||
|
Common::FS::FileType::BinaryFile}; |
||||
|
|
||||
|
std::vector<u8> raw_file(db_file.GetSize()); |
||||
|
if (db_file.Read(raw_file) != raw_file.size()) { |
||||
|
return ResultUnknown; |
||||
|
} |
||||
|
|
||||
|
int filter_flag = STBIR_FILTER_DEFAULT; |
||||
|
int original_width, original_height, color_channels; |
||||
|
const auto dbi_image = |
||||
|
stbi_load_from_memory(raw_file.data(), static_cast<int>(raw_file.size()), &original_width, |
||||
|
&original_height, &color_channels, STBI_rgb_alpha); |
||||
|
|
||||
|
if (dbi_image == nullptr) { |
||||
|
return ResultUnknown; |
||||
|
} |
||||
|
|
||||
|
switch (flag) { |
||||
|
case ScreenShotDecoderFlag::EnableFancyUpsampling: |
||||
|
filter_flag = STBIR_FILTER_TRIANGLE; |
||||
|
break; |
||||
|
case ScreenShotDecoderFlag::EnableBlockSmoothing: |
||||
|
filter_flag = STBIR_FILTER_BOX; |
||||
|
break; |
||||
|
default: |
||||
|
filter_flag = STBIR_FILTER_DEFAULT; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
stbir_resize_uint8_srgb(dbi_image, original_width, original_height, 0, out_image.data(), width, |
||||
|
height, 0, STBI_rgb_alpha, 3, filter_flag); |
||||
|
|
||||
|
return ResultSuccess; |
||||
|
} |
||||
|
} // namespace Service::Capture
|
||||
@ -0,0 +1,72 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <unordered_map> |
||||
|
|
||||
|
#include "common/fs/fs.h" |
||||
|
#include "core/hle/result.h" |
||||
|
#include "core/hle/service/caps/caps_types.h" |
||||
|
|
||||
|
namespace Core { |
||||
|
class System; |
||||
|
} |
||||
|
|
||||
|
namespace std { |
||||
|
// Hash used to create lists from AlbumFileId data |
||||
|
template <> |
||||
|
struct hash<Service::Capture::AlbumFileId> { |
||||
|
size_t operator()(const Service::Capture::AlbumFileId& pad_id) const noexcept { |
||||
|
u64 hash_value = (static_cast<u64>(pad_id.date.year) << 8); |
||||
|
hash_value ^= (static_cast<u64>(pad_id.date.month) << 7); |
||||
|
hash_value ^= (static_cast<u64>(pad_id.date.day) << 6); |
||||
|
hash_value ^= (static_cast<u64>(pad_id.date.hour) << 5); |
||||
|
hash_value ^= (static_cast<u64>(pad_id.date.minute) << 4); |
||||
|
hash_value ^= (static_cast<u64>(pad_id.date.second) << 3); |
||||
|
hash_value ^= (static_cast<u64>(pad_id.date.unique_id) << 2); |
||||
|
hash_value ^= (static_cast<u64>(pad_id.storage) << 1); |
||||
|
hash_value ^= static_cast<u64>(pad_id.type); |
||||
|
return static_cast<size_t>(hash_value); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
} // namespace std |
||||
|
|
||||
|
namespace Service::Capture { |
||||
|
|
||||
|
class AlbumManager { |
||||
|
public: |
||||
|
explicit AlbumManager(); |
||||
|
~AlbumManager(); |
||||
|
|
||||
|
Result DeleteAlbumFile(const AlbumFileId& file_id); |
||||
|
Result IsAlbumMounted(AlbumStorage storage); |
||||
|
Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, |
||||
|
u8 flags) const; |
||||
|
Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, |
||||
|
ContentType contex_type, AlbumFileDateTime start_date, |
||||
|
AlbumFileDateTime end_date, u64 aruid) const; |
||||
|
Result GetAutoSavingStorage(bool& out_is_autosaving) const; |
||||
|
Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, |
||||
|
std::vector<u8>& out_image, const AlbumFileId& file_id, |
||||
|
const ScreenShotDecodeOption& decoder_options) const; |
||||
|
Result LoadAlbumScreenShotThumbnail(LoadAlbumScreenShotImageOutput& out_image_output, |
||||
|
std::vector<u8>& out_image, const AlbumFileId& file_id, |
||||
|
const ScreenShotDecodeOption& decoder_options) const; |
||||
|
|
||||
|
private: |
||||
|
static constexpr std::size_t NandAlbumFileLimit = 1000; |
||||
|
static constexpr std::size_t SdAlbumFileLimit = 10000; |
||||
|
|
||||
|
void FindScreenshots(); |
||||
|
Result GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const; |
||||
|
Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const; |
||||
|
Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width, |
||||
|
int height, ScreenShotDecoderFlag flag) const; |
||||
|
|
||||
|
bool is_mounted{}; |
||||
|
std::unordered_map<AlbumFileId, std::filesystem::path> album_files; |
||||
|
}; |
||||
|
|
||||
|
} // namespace Service::Capture |
||||
@ -0,0 +1,35 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include "core/hle/result.h" |
||||
|
|
||||
|
namespace Service::Capture { |
||||
|
|
||||
|
constexpr Result ResultWorkMemoryError(ErrorModule::Capture, 3); |
||||
|
constexpr Result ResultUnknown5(ErrorModule::Capture, 5); |
||||
|
constexpr Result ResultUnknown6(ErrorModule::Capture, 6); |
||||
|
constexpr Result ResultUnknown7(ErrorModule::Capture, 7); |
||||
|
constexpr Result ResultOutOfRange(ErrorModule::Capture, 8); |
||||
|
constexpr Result ResulInvalidTimestamp(ErrorModule::Capture, 12); |
||||
|
constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13); |
||||
|
constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14); |
||||
|
constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21); |
||||
|
constexpr Result ResultUnknown22(ErrorModule::Capture, 22); |
||||
|
constexpr Result ResultFileNotFound(ErrorModule::Capture, 23); |
||||
|
constexpr Result ResultInvalidFileData(ErrorModule::Capture, 24); |
||||
|
constexpr Result ResultUnknown25(ErrorModule::Capture, 25); |
||||
|
constexpr Result ResultReadBufferShortage(ErrorModule::Capture, 30); |
||||
|
constexpr Result ResultUnknown810(ErrorModule::Capture, 810); |
||||
|
constexpr Result ResultUnknown1024(ErrorModule::Capture, 1024); |
||||
|
constexpr Result ResultUnknown1202(ErrorModule::Capture, 1202); |
||||
|
constexpr Result ResultUnknown1203(ErrorModule::Capture, 1203); |
||||
|
constexpr Result ResultFileCountLimit(ErrorModule::Capture, 1401); |
||||
|
constexpr Result ResultUnknown1701(ErrorModule::Capture, 1701); |
||||
|
constexpr Result ResultUnknown1801(ErrorModule::Capture, 1801); |
||||
|
constexpr Result ResultUnknown1802(ErrorModule::Capture, 1802); |
||||
|
constexpr Result ResultUnknown1803(ErrorModule::Capture, 1803); |
||||
|
constexpr Result ResultUnknown1804(ErrorModule::Capture, 1804); |
||||
|
|
||||
|
} // namespace Service::Capture |
||||
@ -0,0 +1,184 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include "common/common_funcs.h" |
||||
|
#include "common/common_types.h" |
||||
|
|
||||
|
namespace Service::Capture { |
||||
|
|
||||
|
// This is nn::album::ImageOrientation |
||||
|
enum class AlbumImageOrientation { |
||||
|
None, |
||||
|
Rotate90, |
||||
|
Rotate180, |
||||
|
Rotate270, |
||||
|
}; |
||||
|
|
||||
|
// This is nn::album::AlbumReportOption |
||||
|
enum class AlbumReportOption : s32 { |
||||
|
Disable, |
||||
|
Enable, |
||||
|
}; |
||||
|
|
||||
|
enum class ContentType : u8 { |
||||
|
Screenshot = 0, |
||||
|
Movie = 1, |
||||
|
ExtraMovie = 3, |
||||
|
}; |
||||
|
|
||||
|
enum class AlbumStorage : u8 { |
||||
|
Nand, |
||||
|
Sd, |
||||
|
}; |
||||
|
|
||||
|
enum class ScreenShotDecoderFlag : u64 { |
||||
|
None = 0, |
||||
|
EnableFancyUpsampling = 1 << 0, |
||||
|
EnableBlockSmoothing = 1 << 1, |
||||
|
}; |
||||
|
|
||||
|
// This is nn::capsrv::AlbumFileDateTime |
||||
|
struct AlbumFileDateTime { |
||||
|
u16 year{}; |
||||
|
u8 month{}; |
||||
|
u8 day{}; |
||||
|
u8 hour{}; |
||||
|
u8 minute{}; |
||||
|
u8 second{}; |
||||
|
u8 unique_id{}; |
||||
|
|
||||
|
friend constexpr bool operator==(const AlbumFileDateTime&, const AlbumFileDateTime&) = default; |
||||
|
friend constexpr bool operator>(const AlbumFileDateTime& a, const AlbumFileDateTime& b) { |
||||
|
if (a.year > b.year) { |
||||
|
return true; |
||||
|
} |
||||
|
if (a.month > b.month) { |
||||
|
return true; |
||||
|
} |
||||
|
if (a.day > b.day) { |
||||
|
return true; |
||||
|
} |
||||
|
if (a.hour > b.hour) { |
||||
|
return true; |
||||
|
} |
||||
|
if (a.minute > b.minute) { |
||||
|
return true; |
||||
|
} |
||||
|
return a.second > b.second; |
||||
|
}; |
||||
|
friend constexpr bool operator<(const AlbumFileDateTime& a, const AlbumFileDateTime& b) { |
||||
|
if (a.year < b.year) { |
||||
|
return true; |
||||
|
} |
||||
|
if (a.month < b.month) { |
||||
|
return true; |
||||
|
} |
||||
|
if (a.day < b.day) { |
||||
|
return true; |
||||
|
} |
||||
|
if (a.hour < b.hour) { |
||||
|
return true; |
||||
|
} |
||||
|
if (a.minute < b.minute) { |
||||
|
return true; |
||||
|
} |
||||
|
return a.second < b.second; |
||||
|
}; |
||||
|
}; |
||||
|
static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime has incorrect size."); |
||||
|
|
||||
|
// This is nn::album::AlbumEntry |
||||
|
struct AlbumFileEntry { |
||||
|
u64 size{}; // Size of the entry |
||||
|
u64 hash{}; // AES256 with hardcoded key over AlbumEntry |
||||
|
AlbumFileDateTime datetime{}; |
||||
|
AlbumStorage storage{}; |
||||
|
ContentType content{}; |
||||
|
INSERT_PADDING_BYTES(5); |
||||
|
u8 unknown{}; // Set to 1 on official SW |
||||
|
}; |
||||
|
static_assert(sizeof(AlbumFileEntry) == 0x20, "AlbumFileEntry has incorrect size."); |
||||
|
|
||||
|
struct AlbumFileId { |
||||
|
u64 application_id{}; |
||||
|
AlbumFileDateTime date{}; |
||||
|
AlbumStorage storage{}; |
||||
|
ContentType type{}; |
||||
|
INSERT_PADDING_BYTES(0x5); |
||||
|
u8 unknown{}; |
||||
|
|
||||
|
friend constexpr bool operator==(const AlbumFileId&, const AlbumFileId&) = default; |
||||
|
}; |
||||
|
static_assert(sizeof(AlbumFileId) == 0x18, "AlbumFileId is an invalid size"); |
||||
|
|
||||
|
// This is nn::capsrv::AlbumEntry |
||||
|
struct AlbumEntry { |
||||
|
u64 entry_size{}; |
||||
|
AlbumFileId file_id{}; |
||||
|
}; |
||||
|
static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry has incorrect size."); |
||||
|
|
||||
|
// This is nn::capsrv::ApplicationAlbumEntry |
||||
|
struct ApplicationAlbumEntry { |
||||
|
u64 size{}; // Size of the entry |
||||
|
u64 hash{}; // AES256 with hardcoded key over AlbumEntry |
||||
|
AlbumFileDateTime datetime{}; |
||||
|
AlbumStorage storage{}; |
||||
|
ContentType content{}; |
||||
|
INSERT_PADDING_BYTES(5); |
||||
|
u8 unknown{1}; // Set to 1 on official SW |
||||
|
}; |
||||
|
static_assert(sizeof(ApplicationAlbumEntry) == 0x20, "ApplicationAlbumEntry has incorrect size."); |
||||
|
|
||||
|
// This is nn::capsrv::ApplicationAlbumFileEntry |
||||
|
struct ApplicationAlbumFileEntry { |
||||
|
ApplicationAlbumEntry entry{}; |
||||
|
AlbumFileDateTime datetime{}; |
||||
|
u64 unknown{}; |
||||
|
}; |
||||
|
static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30, |
||||
|
"ApplicationAlbumFileEntry has incorrect size."); |
||||
|
|
||||
|
struct ApplicationData { |
||||
|
std::array<u8, 0x400> data{}; |
||||
|
u32 data_size{}; |
||||
|
}; |
||||
|
static_assert(sizeof(ApplicationData) == 0x404, "ApplicationData is an invalid size"); |
||||
|
|
||||
|
struct ScreenShotAttribute { |
||||
|
u32 unknown_0{}; |
||||
|
AlbumImageOrientation orientation{}; |
||||
|
u32 unknown_1{}; |
||||
|
u32 unknown_2{}; |
||||
|
INSERT_PADDING_BYTES(0x30); |
||||
|
}; |
||||
|
static_assert(sizeof(ScreenShotAttribute) == 0x40, "ScreenShotAttribute is an invalid size"); |
||||
|
|
||||
|
struct ScreenShotDecodeOption { |
||||
|
ScreenShotDecoderFlag flags{}; |
||||
|
INSERT_PADDING_BYTES(0x18); |
||||
|
}; |
||||
|
static_assert(sizeof(ScreenShotDecodeOption) == 0x20, "ScreenShotDecodeOption is an invalid size"); |
||||
|
|
||||
|
struct LoadAlbumScreenShotImageOutput { |
||||
|
s64 width{}; |
||||
|
s64 height{}; |
||||
|
ScreenShotAttribute attribute{}; |
||||
|
INSERT_PADDING_BYTES(0x400); |
||||
|
}; |
||||
|
static_assert(sizeof(LoadAlbumScreenShotImageOutput) == 0x450, |
||||
|
"LoadAlbumScreenShotImageOutput is an invalid size"); |
||||
|
|
||||
|
struct LoadAlbumScreenShotImageOutputForApplication { |
||||
|
s64 width{}; |
||||
|
s64 height{}; |
||||
|
ScreenShotAttribute attribute{}; |
||||
|
ApplicationData data{}; |
||||
|
INSERT_PADDING_BYTES(0xAC); |
||||
|
}; |
||||
|
static_assert(sizeof(LoadAlbumScreenShotImageOutputForApplication) == 0x500, |
||||
|
"LoadAlbumScreenShotImageOutput is an invalid size"); |
||||
|
|
||||
|
} // namespace Service::Capture |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue