ReXGlue SDK
Loading...
Searching...
No Matches
stfs.h
Go to the documentation of this file.
1
13
14#pragma once
15
16#include <array>
17#include <filesystem>
18#include <span>
19#include <string>
20#include <string_view>
21#include <memory>
22#include <optional>
23#include <utility>
24#include <vector>
25
26#include <rex/platform.h>
27#include <rex/assert.h>
28#include <rex/math.h>
29#include <rex/memory/endian.h>
30#include <rex/string/text.h>
31#include <rex/result.h>
32#include <rex/filesystem/xex.h>
35#include <rex/types.h>
37#include <rex/utility.h>
38
39namespace rex::filesystem {
40
42enum class XContentPackageType : u32 {
43 kCon = 0x434F4E20,
44 kPirs = 0x50495253,
45 kLive = 0x4C495645,
46};
47
48// NOLINTNEXTLINE(performance-enum-size): the on disk XContent header stores 4 bytes
49enum class XContentVolumeType : u32 {
50 kSTFS = 0,
51 kSVOD = 1,
52};
53
54inline constexpr u32 kSTFSBlockSize = 0x1000;
55
56inline constexpr u32 kSTFSMaxBlocks = 4913000;
57
59inline constexpr std::array<u32, 3> kSTFSBlocksPerHashLevel = {170, 28900, kSTFSMaxBlocks};
60
61#pragma pack(push, 1)
62
66 u8 version;
67 union {
68 u8 as_byte;
69 struct {
70 u8 read_only_format : 1;
71 u8 root_active_index : 1;
74 } bits;
75 } flags;
79 be_u32 total_block_count;
80 be_u32 free_block_count;
81
82 [[nodiscard]] constexpr u32 GetFileTableBlockNumber() const {
84 }
85
86 constexpr void SetFileTableBlockNumber(u32 value) {
88 }
89
90 [[nodiscard]] constexpr bool IsValid() const {
91 return descriptor_length == sizeof(STFSVolumeDescriptor);
92 }
93};
94REX_STATIC_ASSERT_SIZE(STFSVolumeDescriptor, 0x24);
95
96#pragma pack(pop)
97
98enum class STFSHashState : u8 {
99 kFree = 0,
101 kInUse = 2,
102};
103
106 u8 sha1[0x14];
107 be_u32 info_raw;
108
110 [[nodiscard]] u32 GetLevel0NextBlock() const { return info_raw & 0xFFFFFF; }
111
112 void SetLevel0NextBlock(u32 value) { info_raw = (info_raw & ~0xFFFFFFu) | (value & 0xFFFFFF); }
113
114 [[nodiscard]] STFSHashState GetLevel0AllocationState() const {
115 return static_cast<STFSHashState>(static_cast<u8>((info_raw >> 30) & 0x3));
116 }
117
118 void SetLevel0AllocationState(STFSHashState value) {
119 info_raw = (info_raw & ~0xC0000000u) | (static_cast<u32>(value) << 30);
120 }
121
122 [[nodiscard]] u32 GetLevelNFreeBlockCount() const { return info_raw & 0x7FFF; }
123
124 void SetLevelNNumBlocksFree(u32 value) { info_raw = (info_raw & ~0x7FFFu) | (value & 0x7FFF); }
125
126 [[nodiscard]] u32 GetLevelNNumBlocksUnk() const { return (info_raw >> 15) & 0x7FFF; }
127
128 void SetLevelNNumBlocksUnk(u32 value) {
129 info_raw = (info_raw & ~0x3FFF8000u) | ((value & 0x7FFF) << 15);
130 }
131
137 [[nodiscard]] bool IsLevelNActiveIndexSet() const { return (info_raw & 0x40000000) != 0; }
138
139 void SetLevelNActiveIndex(bool value) {
140 info_raw = (info_raw & ~0x40000000u) | (value ? 0x40000000u : 0u);
141 }
142
143 [[nodiscard]] bool IsLevelNWritable() const { return (info_raw & 0x80000000) != 0; }
144
145 void SetLevelNWriteable(bool value) {
146 info_raw = (info_raw & ~0x80000000u) | (value ? 0x80000000u : 0u);
147 }
148};
149REX_STATIC_ASSERT_SIZE(STFSHashEntry, 0x18);
150
153 be_u32 block_count;
154 u8 padding[12];
155};
156REX_STATIC_ASSERT_SIZE(STFSHashTable, 0x1000);
157
159 char name[40];
160 struct {
161 u8 name_length : 6;
162 u8 contiguous : 1;
163 u8 directory : 1;
169 be_u32 length;
170 be_u16 create_date;
171 be_u16 create_time;
174
175 [[nodiscard]] constexpr u32 GetValidDataBlocks() const {
177 }
178
179 constexpr void SetValidDataBlocks(u32 value) {
181 }
182
183 [[nodiscard]] constexpr u32 GetAllocatedDataBlocks() const {
185 }
186
187 constexpr void SetAllocatedDataBlocks(u32 value) {
189 }
190
191 [[nodiscard]] constexpr u32 GetStartBlockNumber() const {
193 }
194
195 constexpr void SetStartBlockNumber(u32 value) {
197 }
198};
199REX_STATIC_ASSERT_SIZE(STFSDirectoryEntry, 0x40);
200
205REX_STATIC_ASSERT_SIZE(STFSDirectoryBlock, 0x1000);
206
209 u8 descriptor_length;
212 u8 worker_thread_priority;
214 union {
215 u8 as_byte;
216 struct {
217 u8 must_be_zero_for_future_usage : 6;
218 u8 enhanced_gdf_layout : 1;
219 u8 zero_for_downlevel_clients : 1;
220 } bits;
221 } features;
224 u8 reserved[5];
225
226 [[nodiscard]] constexpr u32 GetDataBlockCount() const {
228 }
229
230 [[nodiscard]] constexpr u32 GetStartDataBlock() const {
232 }
233};
234REX_STATIC_ASSERT_SIZE(SVODDeviceDescriptor, 0x24);
235
237 be_u64 licensee_id;
238 be_u32 license_bits;
240};
241REX_STATIC_ASSERT_SIZE(XContentLicense, 0x10);
242
245 u8 series_id[0x10];
246 u8 season_id[0x10];
247 be_u16 season_number;
248 be_u16 episode_number;
249};
250REX_STATIC_ASSERT_SIZE(XContentMedia, 0x24);
251
254 be_u32 sub_category;
255 be_u32 colorizable;
256 u8 asset_id[0x10];
258 u8 reserved[0xB];
259};
260REX_STATIC_ASSERT_SIZE(XContentAvatarAsset, 0x24);
261
263 u8 profile_transfer : 1;
264 u8 device_transfer : 1;
266 u8 kinect_enabled : 1;
267 u8 disable_network_storage : 1;
268 u8 deep_link_supported : 1;
269 u8 reserved : 2;
270};
271REX_STATIC_ASSERT_SIZE(XContentAttributes, 1);
272
273#pragma pack(push, 1)
274
277 static constexpr u32 kThumbLengthV1 = 0x4000;
278 static constexpr u32 kThumbLengthV2 = 0x3D00;
279 static constexpr u32 kNumLanguagesV1 = 9;
281 static constexpr u32 kNumLanguagesV2 = 12;
282
283 BE<kernel::XContentType> content_type;
285 be_u64 content_size;
287 u8 console_id[5];
288 be_u64 profile_id;
294 be_u64 data_file_size;
295 BE<XContentVolumeType> volume_type;
297 be_u32 category;
298 u8 reserved2[0x20];
303 u8 device_id[0x14];
304 union {
305 be_u16 uint[kNumLanguagesV1][128];
306 char16_t chars[kNumLanguagesV1][128];
308 union {
309 be_u16 uint[kNumLanguagesV1][128];
310 char16_t chars[kNumLanguagesV1][128];
312 union {
313 be_u16 uint[64];
314 char16_t chars[64];
315 } publisher_raw;
316 union {
317 be_u16 uint[64];
318 char16_t chars[64];
319 } title_name_raw;
320 union {
321 u8 as_byte;
323 } flags;
326 u8 thumbnail[kThumbLengthV2];
327 union {
328 be_u16 uint[kNumLanguagesV2 - kNumLanguagesV1][128];
329 char16_t chars[kNumLanguagesV2 - kNumLanguagesV1][128];
331 u8 title_thumbnail[kThumbLengthV2];
332 union {
333 be_u16 uint[kNumLanguagesV2 - kNumLanguagesV1][128];
334 char16_t chars[kNumLanguagesV2 - kNumLanguagesV1][128];
336
341 [[nodiscard]] std::u16string GetDisplayName(kernel::XLanguage language) const;
342
347 [[nodiscard]] std::u16string GetDescription(kernel::XLanguage language) const;
348
349 [[nodiscard]] std::u16string GetPublisher() const;
350
351 [[nodiscard]] std::u16string GetTitleName() const;
352
358 bool SetDisplayName(kernel::XLanguage language, std::u16string_view value);
359
365 bool SetDescription(kernel::XLanguage language, std::u16string_view value);
366
368 void SetPublisher(std::u16string_view value);
369
371 void SetTitleName(std::u16string_view value);
372};
373REX_STATIC_ASSERT_SIZE(XContentMetadata, 0x93D6);
374
375namespace detail {
376
377inline std::u16string ReadBigEndianUnits(const be_u16* units, size_t count) {
378 std::u16string result;
379 for (size_t i = 0; i < count && units[i] != 0; ++i) {
380 result.push_back(static_cast<char16_t>(static_cast<u16>(units[i])));
381 }
382 return result;
383}
384
385inline std::optional<u32> FindLanguageSlot(kernel::XLanguage language) {
386 if (language == kernel::XLanguage::kSChinese) {
388 }
389 const u32 slot = static_cast<u32>(language) - 1;
390 if (language == kernel::XLanguage::kInvalid || slot >= XContentMetadata::kNumLanguagesV2) {
391 return std::nullopt;
392 }
393 return slot;
394}
395
396inline u32 LanguageSlot(kernel::XLanguage language) {
397 return FindLanguageSlot(language).value_or(std::to_underlying(kernel::XLanguage::kEnglish) - 1);
398}
399
400} // namespace detail
401
402inline std::u16string XContentMetadata::GetDisplayName(kernel::XLanguage language) const {
403 const u32 slot = detail::LanguageSlot(language);
404 if (slot < kNumLanguagesV1) {
405 return detail::ReadBigEndianUnits(display_name_raw.uint[slot], 128);
406 }
407 if (metadata_version >= 2) {
408 return detail::ReadBigEndianUnits(display_name_ex_raw.uint[slot - kNumLanguagesV1], 128);
409 }
410 return {};
411}
412
413inline std::u16string XContentMetadata::GetDescription(kernel::XLanguage language) const {
414 const u32 slot = detail::LanguageSlot(language);
415 if (slot < kNumLanguagesV1) {
416 return detail::ReadBigEndianUnits(description_raw.uint[slot], 128);
417 }
418 if (metadata_version >= 2) {
419 return detail::ReadBigEndianUnits(description_ex_raw.uint[slot - kNumLanguagesV1], 128);
420 }
421 return {};
422}
423
424inline std::u16string XContentMetadata::GetPublisher() const {
425 return detail::ReadBigEndianUnits(publisher_raw.uint, 64);
426}
427
428inline std::u16string XContentMetadata::GetTitleName() const {
429 return detail::ReadBigEndianUnits(title_name_raw.uint, 64);
430}
431
433 std::u16string_view value) {
434 const std::optional<u32> found = detail::FindLanguageSlot(language);
435 if (!found) {
436 return false;
437 }
438 const u32 slot = *found;
439 char16_t* destination = nullptr;
440 if (slot < kNumLanguagesV1) {
441 destination = display_name_raw.chars[slot];
442 } else if (metadata_version >= 2) {
443 destination = display_name_ex_raw.chars[slot - kNumLanguagesV1];
444 }
445 if (!destination) {
446 return false;
447 }
448 string::CopyAndSwapTruncating(destination, value, CountOf(display_name_raw.chars[0]));
449 return true;
450}
451
453 std::u16string_view value) {
454 const std::optional<u32> found = detail::FindLanguageSlot(language);
455 if (!found) {
456 return false;
457 }
458 const u32 slot = *found;
459 char16_t* destination = nullptr;
460 if (slot < kNumLanguagesV1) {
461 destination = description_raw.chars[slot];
462 } else if (metadata_version >= 2) {
463 destination = description_ex_raw.chars[slot - kNumLanguagesV1];
464 }
465 if (!destination) {
466 return false;
467 }
468 string::CopyAndSwapTruncating(destination, value, CountOf(description_raw.chars[0]));
469 return true;
470}
471
472inline void XContentMetadata::SetPublisher(std::u16string_view value) {
473 string::CopyAndSwapTruncating(publisher_raw.chars, value, CountOf(publisher_raw.chars));
474}
475
476inline void XContentMetadata::SetTitleName(std::u16string_view value) {
477 string::CopyAndSwapTruncating(title_name_raw.chars, value, CountOf(title_name_raw.chars));
478}
479
481 BE<XContentPackageType> magic;
482 u8 signature[0x228];
483 XContentLicense licenses[0x10];
484 u8 content_id[0x14];
485 be_u32 header_size;
486
488 [[nodiscard]] bool IsMagicValid() const {
490 return type == XContentPackageType::kCon || type == XContentPackageType::kLive ||
492 }
493};
494REX_STATIC_ASSERT_SIZE(XContentHeader, 0x344);
495
496#pragma pack(pop)
497
500 XContentHeader header;
501 XContentMetadata metadata;
502};
503REX_STATIC_ASSERT_SIZE(XContentPackageHeader, 0x971A);
504
505} // namespace rex::filesystem
506
507namespace rex::filesystem {
508
509enum class ContainerType : u8 {
512 kGDFX,
513};
514
517 u32 file = 0;
518 u64 offset = 0;
519 u64 length = 0;
520};
521
525 u32 parent = 0;
526 std::vector<u32> children;
527 std::vector<ContainerExtent> extents;
528};
529
532 public:
533 virtual ~IContainerImage() = default;
534
535 [[nodiscard]] virtual ContainerType GetType() const = 0;
536
540 [[nodiscard]] virtual const XContentPackageHeader* GetHeader() const = 0;
541
542 [[nodiscard]] virtual const std::filesystem::path& GetPath() const = 0;
543
545 [[nodiscard]] virtual u64 GetTotalSize() const = 0;
546
550 [[nodiscard]] virtual std::span<const ContainerNode> GetNodes() const = 0;
551
552 [[nodiscard]] virtual const ContainerNode& GetRoot() const = 0;
553
559 [[nodiscard]] virtual const ContainerNode* Find(std::string_view path) const = 0;
560
564 [[nodiscard]] virtual std::string GetNodePath(const ContainerNode& node) const = 0;
565
572 [[nodiscard]] virtual Result<size_t> Read(const ContainerNode& node, u64 offset,
573 std::span<u8> buffer) const = 0;
574
576 [[nodiscard]] virtual std::span<const u8> View(const ContainerNode& node) const = 0;
577
584 [[nodiscard]] virtual Result<void> Extract(const std::filesystem::path& destination) const = 0;
585};
586
587} // namespace rex::filesystem
virtual std::span< const u8 > View(const ContainerNode &node) const =0
virtual std::span< const ContainerNode > GetNodes() const =0
virtual u64 GetTotalSize() const =0
virtual std::string GetNodePath(const ContainerNode &node) const =0
virtual Result< size_t > Read(const ContainerNode &node, u64 offset, std::span< u8 > buffer) const =0
virtual const XContentPackageHeader * GetHeader() const =0
virtual Result< void > Extract(const std::filesystem::path &destination) const =0
virtual const ContainerNode * Find(std::string_view path) const =0
Content package and language IDs.
XEX image reader and PE image parsing.
@ kSTFS
Definition mount.h:33
XLanguage
Definition content.h:156
@ kSChineseDeprecated
Definition content.h:167
constexpr u32 LoadUint24LE(const u8 *p)
Definition endian.h:247
constexpr void StoreUint24LE(u8 *p, u32 value)
Definition endian.h:257
T load(const void *mem)
Definition endian.h:134
std::expected< T, Error > Result
Definition result.h:98
Platform flags, packing macros and export markers.
XContentVolumeType
Definition stfs.h:49
STFSHashState
Definition stfs.h:98
@ kFreePresent
Definition stfs.h:100
@ kFree
Definition stfs.h:99
ContainerType
Definition stfs.h:509
constexpr std::array< u32, 3 > kSTFSBlocksPerHashLevel
Definition stfs.h:59
XContentPackageType
Definition stfs.h:42
Definition stfs.h:522
FileStat info
Definition stfs.h:524
u32 parent
Definition stfs.h:525
std::vector< u32 > children
Definition stfs.h:526
std::vector< ContainerExtent > extents
Definition stfs.h:527
Definition file_stat.h:45
STFSDirectoryEntry entries[0x40]
Definition stfs.h:203
be_u16 create_date
Definition stfs.h:170
u8 valid_data_blocks_raw[3]
Definition stfs.h:165
be_u16 directory_index
Definition stfs.h:168
be_u16 modified_time
Definition stfs.h:173
struct rex::filesystem::STFSDirectoryEntry::@062356056335360040122271207357120140221040356220 flags
char name[40]
Definition stfs.h:159
u8 allocated_data_blocks_raw[3]
Definition stfs.h:166
be_u16 create_time
Definition stfs.h:171
be_u16 modified_date
Definition stfs.h:172
u8 start_block_number_raw[3]
Definition stfs.h:167
Definition stfs.h:105
u32 GetLevel0NextBlock() const
Definition stfs.h:110
be_u32 info_raw
Definition stfs.h:107
bool IsLevelNActiveIndexSet() const
Definition stfs.h:137
Definition stfs.h:151
STFSHashEntry entries[170]
Definition stfs.h:152
be_u32 block_count
Definition stfs.h:153
u16 file_table_block_count
Definition stfs.h:76
u8 top_hash_table_hash[0x14]
Definition stfs.h:78
u8 file_table_block_number_raw[3]
Definition stfs.h:77
u8 descriptor_length
Definition stfs.h:65
u8 block_cache_element_count
Definition stfs.h:210
u8 start_data_block_raw[3]
Definition stfs.h:223
u8 first_fragment_hash_entry[0x14]
Definition stfs.h:213
u8 worker_thread_processor
Definition stfs.h:211
u8 data_block_count_raw[3]
Definition stfs.h:222
u8 move_only_transfer
Definition stfs.h:265
be_u32 colorizable
Definition stfs.h:255
u8 skeleton_version_mask
Definition stfs.h:257
Definition stfs.h:480
u8 content_id[0x14]
Definition stfs.h:484
be_u32 header_size
Definition stfs.h:485
bool IsMagicValid() const
Definition stfs.h:488
be_u32 license_flags
Definition stfs.h:239
be_u64 licensee_id
Definition stfs.h:237
Definition stfs.h:244
static constexpr u32 kNumLanguagesV2
Definition stfs.h:281
union rex::filesystem::XContentMetadata::@077353323141217117134140232004315077054233260246 display_name_raw
union rex::filesystem::XContentMetadata::@165172350104132313155041062151030300324230002153 metadata_v2
be_u32 thumbnail_size
Definition stfs.h:324
std::u16string GetDisplayName(kernel::XLanguage language) const
Definition stfs.h:402
kernel::XEXOptExecutionInfo execution_info
Definition stfs.h:286
be_u64 online_creator
Definition stfs.h:296
void SetPublisher(std::u16string_view value)
Definition stfs.h:472
u8 title_thumbnail[kThumbLengthV2]
Definition stfs.h:331
bool SetDescription(kernel::XLanguage language, std::u16string_view value)
Definition stfs.h:452
u8 thumbnail[kThumbLengthV2]
Definition stfs.h:326
be_u32 metadata_version
Definition stfs.h:284
be_u32 data_file_count
Definition stfs.h:293
be_u32 title_thumbnail_size
Definition stfs.h:325
union rex::filesystem::XContentMetadata::@225215021171175152344323276024070143354070223171 display_name_ex_raw
union rex::filesystem::XContentMetadata::@234032230263246373276355357125165067155234216324 description_raw
union rex::filesystem::XContentMetadata::@041324034061221337154025105337152042276375360050 volume_descriptor
union rex::filesystem::XContentMetadata::@263073205202042234034376111102030200121123062057 description_ex_raw
std::u16string GetDescription(kernel::XLanguage language) const
Definition stfs.h:413
bool SetDisplayName(kernel::XLanguage language, std::u16string_view value)
Definition stfs.h:432
void SetTitleName(std::u16string_view value)
Definition stfs.h:476
ASCII and UTF-8 text operations, the string builder and the string keys.
size_t CopyAndSwapTruncating(char16_t *dest, const std::u16string_view source, size_t dest_buffer_count)
Definition text.h:207
Integer types, byte order wrappers and size literals.
char16_t chars[kNumLanguagesV2 - kNumLanguagesV1][128]
be_u16 uint[kNumLanguagesV2 - kNumLanguagesV1][128]
be_u16 uint[kNumLanguagesV2 - kNumLanguagesV1][128]
char16_t chars[kNumLanguagesV2 - kNumLanguagesV1][128]
Move only function, const propagating pointer and scope guard.