Seregon/ShadPKG

A tool for deriving PKG packet encryption keys for ps4 written in c++

C++/47.3 KB/No license
common/io_file.h
ShadPKG / common / io_file.h
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3 
4#pragma once
5 
6#include <cstdio>
7#include <filesystem>
8#include <span>
9#include <type_traits>
10 
11#include "common/concepts.h"
12#include "common/shadpkg_types.h"
13#include "enum.h"
14 
15namespace Common::FS {
16 
17enum class FileAccessMode {
18 /**
19 * If the file at path exists, it opens the file for reading.
20 * If the file at path does not exist, it fails to open the file.
21 */
22 Read = 1 << 0,
23 /**
24 * If the file at path exists, the existing contents of the file are erased.
25 * The empty file is then opened for writing.
26 * If the file at path does not exist, it creates and opens a new empty file for writing.
27 */
28 Write = 1 << 1,
29 /**
30 * If the file at path exists, it opens the file for reading and writing.
31 * If the file at path does not exist, it fails to open the file.
32 */
33 ReadWrite = Read | Write,
34 /**
35 * If the file at path exists, it opens the file for appending.
36 * If the file at path does not exist, it creates and opens a new empty file for appending.
37 */
38 Append = 1 << 2,
39 /**
40 * If the file at path exists, it opens the file for both reading and appending.
41 * If the file at path does not exist, it creates and opens a new empty file for both
42 * reading and appending.
43 */
44 ReadAppend = Read | Append,
45};
46DECLARE_ENUM_FLAG_OPERATORS(FileAccessMode);
47 
48enum class FileType {
49 BinaryFile,
50 TextFile,
51};
52 
53enum class FileShareFlag {
54 ShareNone, // Provides exclusive access to the file.
55 ShareReadOnly, // Provides read only shared access to the file.
56 ShareWriteOnly, // Provides write only shared access to the file.
57 ShareReadWrite, // Provides read and write shared access to the file.
58};
59 
60enum class SeekOrigin : u32 {
61 SetOrigin, // Seeks from the start of the file.
62 CurrentPosition, // Seeks from the current file pointer position.
63 End, // Seeks from the end of the file.
64};
65 
66class IOFile final {
67public:
68 IOFile();
69 
70 explicit IOFile(const std::string& path, FileAccessMode mode,
71 FileType type = FileType::BinaryFile,
72 FileShareFlag flag = FileShareFlag::ShareReadOnly);
73 
74 explicit IOFile(std::string_view path, FileAccessMode mode,
75 FileType type = FileType::BinaryFile,
76 FileShareFlag flag = FileShareFlag::ShareReadOnly);
77 explicit IOFile(const std::filesystem::path& path, FileAccessMode mode,
78 FileType type = FileType::BinaryFile,
79 FileShareFlag flag = FileShareFlag::ShareReadOnly);
80 
81 ~IOFile();
82 
83 IOFile(const IOFile&) = delete;
84 IOFile& operator=(const IOFile&) = delete;
85 
86 IOFile(IOFile&& other) noexcept;
87 IOFile& operator=(IOFile&& other) noexcept;
88 
89 std::filesystem::path GetPath() const {
90 return file_path;
91 }
92 
93 FileAccessMode GetAccessMode() const {
94 return file_access_mode;
95 }
96 
97 FileType GetType() const {
98 return file_type;
99 }
100 
101 bool IsOpen() const {
102 return file != nullptr;
103 }
104 
105 uintptr_t GetFileMapping();
106 
107 int Open(const std::filesystem::path& path, FileAccessMode mode,
108 FileType type = FileType::BinaryFile,
109 FileShareFlag flag = FileShareFlag::ShareReadOnly);
110 void Close();
111 
112 void Unlink();
113 
114 bool Flush() const;
115 bool Commit() const;
116 
117 bool SetSize(u64 size) const;
118 u64 GetSize() const;
119 
120 bool Seek(s64 offset, SeekOrigin origin = SeekOrigin::SetOrigin) const;
121 s64 Tell() const;
122 
123 template <typename T>
124 size_t Read(T& data) const {
125 if constexpr (IsContiguousContainer<T>) {
126 using ContiguousType = typename T::value_type;
127 static_assert(std::is_trivially_copyable_v<ContiguousType>,
128 "Data type must be trivially copyable.");
129 return ReadSpan<ContiguousType>(data);
130 } else {
131 return ReadObject(data) ? 1 : 0;
132 }
133 }
134 
135 template <typename T>
136 size_t Write(const T& data) const {
137 if constexpr (IsContiguousContainer<T>) {
138 using ContiguousType = typename T::value_type;
139 static_assert(std::is_trivially_copyable_v<ContiguousType>,
140 "Data type must be trivially copyable.");
141 return WriteSpan<ContiguousType>(data);
142 } else {
143 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
144 return WriteObject(data) ? 1 : 0;
145 }
146 }
147 
148 template <typename T>
149 size_t ReadSpan(std::span<T> data) const {
150 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
151 
152 if (!IsOpen()) {
153 return 0;
154 }
155 
156 return ReadRaw<T>(data.data(), data.size());
157 }
158 
159 template <typename T>
160 size_t ReadRaw(void* data, size_t size) const {
161 return std::fread(data, sizeof(T), size, file);
162 }
163 
164 template <typename T>
165 size_t WriteSpan(std::span<const T> data) const {
166 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
167 
168 if (!IsOpen()) {
169 return 0;
170 }
171 
172 return std::fwrite(data.data(), sizeof(T), data.size(), file);
173 }
174 
175 template <typename T>
176 bool ReadObject(T& object) const {
177 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
178 static_assert(!std::is_pointer_v<T>, "T must not be a pointer to an object.");
179 
180 if (!IsOpen()) {
181 return false;
182 }
183 
184 return std::fread(&object, sizeof(T), 1, file) == 1;
185 }
186 
187 template <typename T>
188 size_t WriteRaw(const void* data, size_t size) const {
189 return std::fwrite(data, sizeof(T), size, file);
190 }
191 
192 template <typename T>
193 bool WriteObject(const T& object) const {
194 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
195 static_assert(!std::is_pointer_v<T>, "T must not be a pointer to an object.");
196 
197 if (!IsOpen()) {
198 return false;
199 }
200 
201 return std::fwrite(&object, sizeof(T), 1, file) == 1;
202 }
203 
204 std::string ReadString(size_t length) const;
205 
206 size_t WriteString(std::span<const char> string) const {
207 return WriteSpan(string);
208 }
209 
210 static size_t WriteBytes(const std::filesystem::path path, const auto& data) {
211 IOFile out(path, FileAccessMode::Write);
212 return out.Write(data);
213 }
214 
215private:
216 std::filesystem::path file_path;
217 FileAccessMode file_access_mode{};
218 FileType file_type{};
219 
220 std::FILE* file = nullptr;
221 uintptr_t file_mapping = 0;
222};
223 
224u64 GetDirectorySize(const std::filesystem::path& path);
225 
226} // namespace Common::FS
227