1 // Copyright 2017 Citra Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4 
5 #pragma once
6 
7 #include <array>
8 #include <memory>
9 #include <string>
10 #include <vector>
11 #include "common/common_types.h"
12 #include "common/swap.h"
13 #include "core/file_sys/ticket.h"
14 #include "core/file_sys/title_metadata.h"
15 
16 namespace Loader {
17 enum class ResultStatus;
18 }
19 
20 ////////////////////////////////////////////////////////////////////////////////////////////////////
21 // FileSys namespace
22 
23 namespace FileSys {
24 
25 class FileBackend;
26 
27 constexpr std::size_t CIA_CONTENT_MAX_COUNT = 0x10000;
28 constexpr std::size_t CIA_CONTENT_BITS_SIZE = (CIA_CONTENT_MAX_COUNT / 8);
29 constexpr std::size_t CIA_HEADER_SIZE = 0x2020;
30 constexpr std::size_t CIA_DEPENDENCY_SIZE = 0x300;
31 constexpr std::size_t CIA_METADATA_SIZE = 0x400;
32 
33 /**
34  * Helper which implements an interface to read and write CTR Installable Archive (CIA) files.
35  * Data can either be loaded from a FileBackend, a string path, or from a data array. Data can
36  * also be partially loaded for CIAs which are downloading/streamed in and need some metadata
37  * read out.
38  */
39 class CIAContainer {
40 public:
41     // Load whole CIAs outright
42     Loader::ResultStatus Load(const FileBackend& backend);
43     Loader::ResultStatus Load(const std::string& filepath);
44     Loader::ResultStatus Load(const std::vector<u8>& header_data);
45 
46     // Load parts of CIAs (for CIAs streamed in)
47     Loader::ResultStatus LoadHeader(const std::vector<u8>& header_data, std::size_t offset = 0);
48     Loader::ResultStatus LoadTicket(const std::vector<u8>& ticket_data, std::size_t offset = 0);
49     Loader::ResultStatus LoadTitleMetadata(const std::vector<u8>& tmd_data, std::size_t offset = 0);
50     Loader::ResultStatus LoadMetadata(const std::vector<u8>& meta_data, std::size_t offset = 0);
51 
52     const Ticket& GetTicket() const;
53     const TitleMetadata& GetTitleMetadata() const;
54     std::array<u64, 0x30>& GetDependencies();
55     u32 GetCoreVersion() const;
56 
57     u64 GetCertificateOffset() const;
58     u64 GetTicketOffset() const;
59     u64 GetTitleMetadataOffset() const;
60     u64 GetMetadataOffset() const;
61     u64 GetContentOffset(std::size_t index = 0) const;
62 
63     u32 GetCertificateSize() const;
64     u32 GetTicketSize() const;
65     u32 GetTitleMetadataSize() const;
66     u32 GetMetadataSize() const;
67     u64 GetTotalContentSize() const;
68     u64 GetContentSize(std::size_t index = 0) const;
69 
70     void Print() const;
71 
72 private:
73     struct Header {
74         u32_le header_size;
75         u16_le type;
76         u16_le version;
77         u32_le cert_size;
78         u32_le tik_size;
79         u32_le tmd_size;
80         u32_le meta_size;
81         u64_le content_size;
82         std::array<u8, CIA_CONTENT_BITS_SIZE> content_present;
83 
IsContentPresentHeader84         bool IsContentPresent(std::size_t index) const {
85             // The content_present is a bit array which defines which content in the TMD
86             // is included in the CIA, so check the bit for this index and add if set.
87             // The bits in the content index are arranged w/ index 0 as the MSB, 7 as the LSB, etc.
88             return (content_present[index >> 3] & (0x80 >> (index & 7))) != 0;
89         }
90     };
91 
92     static_assert(sizeof(Header) == CIA_HEADER_SIZE, "CIA Header structure size is wrong");
93 
94     struct Metadata {
95         std::array<u64_le, 0x30> dependencies;
96         std::array<u8, 0x180> reserved;
97         u32_le core_version;
98         std::array<u8, 0xfc> reserved_2;
99     };
100 
101     static_assert(sizeof(Metadata) == CIA_METADATA_SIZE, "CIA Metadata structure size is wrong");
102 
103     Header cia_header;
104     Metadata cia_metadata;
105     Ticket cia_ticket;
106     TitleMetadata cia_tmd;
107 };
108 
109 } // namespace FileSys
110