/
WIABlob.h
229 lines (185 loc) · 6.28 KB
/
WIABlob.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <memory>
#include <utility>
#include <bzlib.h>
#include <lzma.h>
#include "Common/CommonTypes.h"
#include "Common/File.h"
#include "Common/Swap.h"
#include "DiscIO/Blob.h"
namespace DiscIO
{
constexpr u32 WIA_MAGIC = 0x01414957; // "WIA\x1" (byteswapped to little endian)
class WIAFileReader : public BlobReader
{
public:
~WIAFileReader();
static std::unique_ptr<WIAFileReader> Create(File::IOFile file, const std::string& path);
BlobType GetBlobType() const override { return BlobType::WIA; }
u64 GetRawSize() const override { return Common::swap64(m_header_1.wia_file_size); }
u64 GetDataSize() const override { return Common::swap64(m_header_1.iso_file_size); }
bool IsDataSizeAccurate() const override { return true; }
bool Read(u64 offset, u64 size, u8* out_ptr) override;
bool SupportsReadWiiDecrypted() const override { return true; }
bool ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr, u64 partition_data_offset) override;
private:
explicit WIAFileReader(File::IOFile file, const std::string& path);
bool Initialize(const std::string& path);
bool ReadFromGroups(u64* offset, u64* size, u8** out_ptr, u32 chunk_size, u64 data_offset,
u64 data_size, u32 group_index, u32 number_of_groups, bool exception_list);
bool ReadCompressedData(u32 decompressed_data_size, u64 data_offset, u64 data_size, u8* out_ptr,
bool exception_list);
bool ReadCompressedData(u32 decompressed_data_size, u64 data_offset, u64 data_size,
u64 offset_in_data, u64 size_in_data, u8* out_ptr, bool exception_list);
// Returns the number of bytes read
std::optional<u64> ReadExceptionListFromFile();
static std::string VersionToString(u32 version);
using SHA1 = std::array<u8, 20>;
using WiiKey = std::array<u8, 16>;
#pragma pack(push, 1)
struct WIAHeader1
{
u32 magic;
u32 version;
u32 version_compatible;
u32 header2_size;
SHA1 header2_hash;
u64 iso_file_size;
u64 wia_file_size;
SHA1 header1_hash;
};
static_assert(sizeof(WIAHeader1) == 0x48, "Wrong size for WIA header 1");
struct WIAHeader2
{
u32 disc_type;
u32 compression_type;
u32 compression_level; // Informative only
u32 chunk_size;
std::array<u8, 0x80> disc_header;
u32 number_of_partition_entries;
u32 partition_entry_size;
u64 partition_entries_offset;
SHA1 partition_entries_hash;
u32 number_of_raw_data_entries;
u64 raw_data_entries_offset;
u32 raw_data_entries_size;
u32 number_of_group_entries;
u64 group_entries_offset;
u32 group_entries_size;
};
static_assert(sizeof(WIAHeader2) == 0xd4, "Wrong size for WIA header 2");
struct PartitionDataEntry
{
u32 first_sector;
u32 number_of_sectors;
u32 group_index;
u32 number_of_groups;
};
static_assert(sizeof(PartitionDataEntry) == 0x10, "Wrong size for WIA partition data entry");
struct PartitionEntry
{
WiiKey partition_key;
std::array<PartitionDataEntry, 2> data_entries;
};
static_assert(sizeof(PartitionEntry) == 0x30, "Wrong size for WIA partition entry");
struct RawDataEntry
{
u64 data_offset;
u64 data_size;
u32 group_index;
u32 number_of_groups;
};
static_assert(sizeof(RawDataEntry) == 0x18, "Wrong size for WIA raw data entry");
struct GroupEntry
{
u32 data_offset; // >> 2
u32 data_size;
};
static_assert(sizeof(GroupEntry) == 0x08, "Wrong size for WIA group entry");
struct HashExceptionEntry
{
u16 offset;
SHA1 hash;
};
static_assert(sizeof(HashExceptionEntry) == 0x16, "Wrong size for WIA hash exception entry");
struct PurgeSegment
{
u32 offset;
u32 size;
};
static_assert(sizeof(PurgeSegment) == 0x08, "Wrong size for WIA purge segment");
#pragma pack(pop)
enum class CompressionType : u32
{
None = 0,
Purge = 1,
Bzip2 = 2,
LZMA = 3,
LZMA2 = 4,
};
class Decompressor
{
public:
virtual ~Decompressor();
// Specifies the compressed data to read. The data must still be in memory when calling Read.
virtual bool Start(const u8* in_ptr, u64 size) = 0;
// Reads the specified number of bytes into out_ptr (or less, if there aren't that many bytes
// to output). Returns the number of bytes read. Start must be called before this.
virtual u64 Read(u8* out_ptr, u64 size) = 0;
// Returns whether every byte of the input data has been read.
virtual bool DoneReading() const = 0;
// Will be called automatically upon destruction, but can be called earlier if desired.
virtual void End() = 0;
};
class Bzip2Decompressor final : public Decompressor
{
public:
~Bzip2Decompressor();
bool Start(const u8* in_ptr, u64 size) override;
u64 Read(u8* out_ptr, u64 size) override;
bool DoneReading() const override;
void End() override;
private:
bz_stream m_stream;
bool m_started = false;
bool m_ended = false;
bool m_error_occurred = false;
};
class LZMADecompressor final : public Decompressor
{
public:
LZMADecompressor(bool lzma2, const std::vector<u8>& filter_options);
~LZMADecompressor();
bool Start(const u8* in_ptr, u64 size) override;
u64 Read(u8* out_ptr, u64 size) override;
bool DoneReading() const override;
void End() override;
private:
lzma_stream m_stream = LZMA_STREAM_INIT;
lzma_options_lzma m_options = {};
lzma_filter m_filters[2];
bool m_started = false;
bool m_ended = false;
bool m_error_occurred = false;
};
bool m_valid;
CompressionType m_compression_type;
File::IOFile m_file;
WIAHeader1 m_header_1;
WIAHeader2 m_header_2;
std::vector<u8> m_compressor_data;
std::vector<PartitionEntry> m_partition_entries;
std::vector<RawDataEntry> m_raw_data_entries;
std::vector<GroupEntry> m_group_entries;
static constexpr u32 WIA_VERSION = 0x01000000;
static constexpr u32 WIA_VERSION_WRITE_COMPATIBLE = 0x00090000;
static constexpr u32 WIA_VERSION_READ_COMPATIBLE = 0x00080000;
static constexpr u64 BLOCK_HEADER_SIZE = 0x0400;
static constexpr u64 BLOCK_DATA_SIZE = 0x7C00;
static constexpr u64 BLOCK_TOTAL_SIZE = BLOCK_HEADER_SIZE + BLOCK_DATA_SIZE;
};
} // namespace DiscIO