Merge pull request #10932 from JosJuice/nfs

DiscIO: Add support for the NFS format
This commit is contained in:
Admiral H. Curtiss
2022-08-04 22:20:08 +02:00
committed by GitHub
44 changed files with 637 additions and 143 deletions
@@ -30,7 +30,8 @@ import java.util.Set;
public final class FileBrowserHelper
{
public static final HashSet<String> GAME_EXTENSIONS = new HashSet<>(Arrays.asList(
"gcm", "tgc", "iso", "ciso", "gcz", "wbfs", "wia", "rvz", "wad", "dol", "elf", "json"));
"gcm", "tgc", "iso", "ciso", "gcz", "wbfs", "wia", "rvz", "nfs", "wad", "dol", "elf",
"json"));
public static final HashSet<String> GAME_LIKE_EXTENSIONS = new HashSet<>(GAME_EXTENSIONS);
+1 -1
View File
@@ -231,7 +231,7 @@ std::unique_ptr<BootParameters> BootParameters::GenerateFromFile(std::vector<std
#endif
static const std::unordered_set<std::string> disc_image_extensions = {
{".gcm", ".iso", ".tgc", ".wbfs", ".ciso", ".gcz", ".wia", ".rvz", ".dol", ".elf"}};
{".gcm", ".iso", ".tgc", ".wbfs", ".ciso", ".gcz", ".wia", ".rvz", ".nfs", ".dol", ".elf"}};
if (disc_image_extensions.find(extension) != disc_image_extensions.end() || is_drive)
{
std::unique_ptr<DiscIO::VolumeDisc> disc = DiscIO::CreateDisc(path);
+6 -7
View File
@@ -430,9 +430,9 @@ void Shutdown()
static u64 GetDiscEndOffset(const DiscIO::VolumeDisc& disc)
{
u64 size = disc.GetSize();
u64 size = disc.GetDataSize();
if (disc.IsSizeAccurate())
if (disc.GetDataSizeType() == DiscIO::DataSizeType::Accurate)
{
if (size == DiscIO::MINI_DVD_SIZE)
return DiscIO::MINI_DVD_SIZE;
@@ -464,7 +464,7 @@ void SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
if (has_disc)
{
s_disc_end_offset = GetDiscEndOffset(*disc);
if (!disc->IsSizeAccurate())
if (disc->GetDataSizeType() != DiscIO::DataSizeType::Accurate)
WARN_LOG_FMT(DVDINTERFACE, "Unknown disc size, guessing {0} bytes", s_disc_end_offset);
const DiscIO::BlobReader& blob = disc->GetBlobReader();
@@ -1482,10 +1482,9 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti
u32 buffered_blocks = 0;
u32 unbuffered_blocks = 0;
const u32 bytes_per_chunk =
partition != DiscIO::PARTITION_NONE && DVDThread::IsEncryptedAndHashed() ?
DiscIO::VolumeWii::BLOCK_DATA_SIZE :
DVD_ECC_BLOCK_SIZE;
const u32 bytes_per_chunk = partition != DiscIO::PARTITION_NONE && DVDThread::HasWiiHashes() ?
DiscIO::VolumeWii::BLOCK_DATA_SIZE :
DVD_ECC_BLOCK_SIZE;
do
{
+3 -3
View File
@@ -184,10 +184,10 @@ bool HasDisc()
return s_disc != nullptr;
}
bool IsEncryptedAndHashed()
bool HasWiiHashes()
{
// IsEncryptedAndHashed is thread-safe, so calling WaitUntilIdle isn't necessary.
return s_disc->IsEncryptedAndHashed();
// HasWiiHashes is thread-safe, so calling WaitUntilIdle isn't necessary.
return s_disc->HasWiiHashes();
}
DiscIO::Platform GetDiscType()
+1 -1
View File
@@ -41,7 +41,7 @@ void DoState(PointerWrap& p);
void SetDisc(std::unique_ptr<DiscIO::Volume> disc);
bool HasDisc();
bool IsEncryptedAndHashed();
bool HasWiiHashes();
DiscIO::Platform GetDiscType();
u64 PartitionOffsetToRawOffset(u64 offset, const DiscIO::Partition& partition);
IOS::ES::TMDReader GetTMD(const DiscIO::Partition& partition);
+5
View File
@@ -20,6 +20,7 @@
#include "DiscIO/DirectoryBlob.h"
#include "DiscIO/DriveBlob.h"
#include "DiscIO/FileBlob.h"
#include "DiscIO/NFSBlob.h"
#include "DiscIO/TGCBlob.h"
#include "DiscIO/WIABlob.h"
#include "DiscIO/WbfsBlob.h"
@@ -52,6 +53,8 @@ std::string GetName(BlobType blob_type, bool translate)
return "RVZ";
case BlobType::MOD_DESCRIPTOR:
return translate_str("Mod");
case BlobType::NFS:
return "NFS";
default:
return "";
}
@@ -242,6 +245,8 @@ std::unique_ptr<BlobReader> CreateBlobReader(const std::string& filename)
return WIAFileReader::Create(std::move(file), filename);
case RVZ_MAGIC:
return RVZFileReader::Create(std::move(file), filename);
case NFS_MAGIC:
return NFSFileReader::Create(std::move(file), filename);
default:
if (auto directory_blob = DirectoryBlobReader::Create(filename))
return std::move(directory_blob);
+14 -1
View File
@@ -40,6 +40,19 @@ enum class BlobType
WIA,
RVZ,
MOD_DESCRIPTOR,
NFS,
};
// If you convert an ISO file to another format and then call GetDataSize on it, what is the result?
enum class DataSizeType
{
// The result is the same as for the ISO.
Accurate,
// The result is not larger than for the ISO. (It's usually a little smaller than for the ISO.)
// Reads to offsets that are larger than the result will return some kind of "blank" data.
LowerBound,
// The result is not smaller than for the ISO. (It's usually much larger than for the ISO.)
UpperBound,
};
std::string GetName(BlobType blob_type, bool translate);
@@ -53,7 +66,7 @@ public:
virtual u64 GetRawSize() const = 0;
virtual u64 GetDataSize() const = 0;
virtual bool IsDataSizeAccurate() const = 0;
virtual DataSizeType GetDataSizeType() const = 0;
// Returns 0 if the format does not use blocks
virtual u64 GetBlockSize() const = 0;
+1 -3
View File
@@ -38,10 +38,8 @@ public:
BlobType GetBlobType() const override { return BlobType::CISO; }
u64 GetRawSize() const override;
// The CISO format does not save the original file size.
// This function returns an upper bound.
u64 GetDataSize() const override;
bool IsDataSizeAccurate() const override { return false; }
DataSizeType GetDataSizeType() const override { return DataSizeType::UpperBound; }
u64 GetBlockSize() const override { return m_block_size; }
bool HasFastRandomAccessInBlock() const override { return true; }
+2
View File
@@ -30,6 +30,8 @@ add_library(discio
MultithreadedCompressor.h
NANDImporter.cpp
NANDImporter.h
NFSBlob.cpp
NFSBlob.h
RiivolutionParser.cpp
RiivolutionParser.h
RiivolutionPatcher.cpp
+1 -1
View File
@@ -273,7 +273,7 @@ bool ConvertToGCZ(BlobReader* infile, const std::string& infile_path,
const std::string& outfile_path, u32 sub_type, int block_size,
CompressCB callback)
{
ASSERT(infile->IsDataSizeAccurate());
ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate);
File::IOFile outfile(outfile_path, "wb");
if (!outfile)
+1 -1
View File
@@ -53,7 +53,7 @@ public:
u64 GetRawSize() const override { return m_file_size; }
u64 GetDataSize() const override { return m_header.data_size; }
bool IsDataSizeAccurate() const override { return true; }
DataSizeType GetDataSizeType() const override { return DataSizeType::Accurate; }
u64 GetBlockSize() const override { return m_header.block_size; }
bool HasFastRandomAccessInBlock() const override { return false; }
+2 -2
View File
@@ -668,7 +668,7 @@ void DirectoryBlobReader::SetPartitions(std::vector<PartitionWithType>&& partiti
m_partitions.emplace(partition_data_offset, std::move(partitions[i].partition));
m_nonpartition_contents.Add(partition_data_offset, data_size,
ContentPartition{this, 0, partition_data_offset});
const u64 unaligned_next_partition_address = VolumeWii::EncryptedPartitionOffsetToRawOffset(
const u64 unaligned_next_partition_address = VolumeWii::OffsetInHashedPartitionToRawOffset(
data_size, Partition(partition_address), PARTITION_DATA_OFFSET);
partition_address = Common::AlignUp(unaligned_next_partition_address, 0x10000ull);
}
@@ -743,7 +743,7 @@ void DirectoryBlobReader::SetPartitionHeader(DirectoryBlobPartition* partition,
if (wrapped_partition)
{
if (m_wrapped_volume->IsEncryptedAndHashed())
if (m_wrapped_volume->HasWiiHashes())
{
const std::optional<u64> offset = m_wrapped_volume->ReadSwappedAndShifted(
wrapped_partition->offset + WII_PARTITION_H3_OFFSET_ADDRESS, PARTITION_NONE);
+1 -1
View File
@@ -284,7 +284,7 @@ public:
u64 GetRawSize() const override;
u64 GetDataSize() const override;
bool IsDataSizeAccurate() const override { return true; }
DataSizeType GetDataSizeType() const override { return DataSizeType::Accurate; }
u64 GetBlockSize() const override { return 0; }
bool HasFastRandomAccessInBlock() const override { return true; }
+1 -1
View File
@@ -286,7 +286,7 @@ bool ExportSystemData(const Volume& volume, const Partition& partition,
success &= ExportTicket(volume, partition, export_folder + "/ticket.bin");
success &= ExportTMD(volume, partition, export_folder + "/tmd.bin");
success &= ExportCertificateChain(volume, partition, export_folder + "/cert.bin");
if (volume.IsEncryptedAndHashed())
if (volume.HasWiiHashes())
success &= ExportH3Hashes(volume, partition, export_folder + "/h3.bin");
}
+7 -3
View File
@@ -30,7 +30,7 @@ bool DiscScrubber::SetupScrub(const Volume* disc)
return false;
m_disc = disc;
m_file_size = m_disc->GetSize();
m_file_size = m_disc->GetDataSize();
// Round up when diving by CLUSTER_SIZE, otherwise MarkAsUsed might write out of bounds
const size_t num_clusters = static_cast<size_t>((m_file_size + CLUSTER_SIZE - 1) / CLUSTER_SIZE);
@@ -47,7 +47,11 @@ bool DiscScrubber::SetupScrub(const Volume* disc)
bool DiscScrubber::CanBlockBeScrubbed(u64 offset) const
{
return m_is_scrubbing && m_free_table[offset / CLUSTER_SIZE];
if (!m_is_scrubbing)
return false;
const u64 cluster_index = offset / CLUSTER_SIZE;
return cluster_index >= m_free_table.size() || m_free_table[cluster_index];
}
void DiscScrubber::MarkAsUsed(u64 offset, u64 size)
@@ -92,7 +96,7 @@ void DiscScrubber::MarkAsUsedE(u64 partition_data_offset, u64 offset, u64 size)
// Compensate for 0x400 (SHA-1) per 0x8000 (cluster), and round to whole clusters
u64 DiscScrubber::ToClusterOffset(u64 offset) const
{
if (m_disc->IsEncryptedAndHashed())
if (m_disc->HasWiiHashes())
return offset / 0x7c00 * CLUSTER_SIZE;
else
return Common::AlignDown(offset, CLUSTER_SIZE);
+1 -1
View File
@@ -27,7 +27,7 @@ public:
u64 GetRawSize() const override { return m_size; }
u64 GetDataSize() const override { return m_size; }
bool IsDataSizeAccurate() const override { return true; }
DataSizeType GetDataSizeType() const override { return DataSizeType::Accurate; }
u64 GetBlockSize() const override { return ECC_BLOCK_SIZE; }
bool HasFastRandomAccessInBlock() const override { return false; }
+1 -1
View File
@@ -44,7 +44,7 @@ bool PlainFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
bool ConvertToPlain(BlobReader* infile, const std::string& infile_path,
const std::string& outfile_path, CompressCB callback)
{
ASSERT(infile->IsDataSizeAccurate());
ASSERT(infile->GetDataSizeType() == DataSizeType::Accurate);
File::IOFile outfile(outfile_path, "wb");
if (!outfile)
+1 -1
View File
@@ -22,7 +22,7 @@ public:
u64 GetRawSize() const override { return m_size; }
u64 GetDataSize() const override { return m_size; }
bool IsDataSizeAccurate() const override { return true; }
DataSizeType GetDataSizeType() const override { return DataSizeType::Accurate; }
u64 GetBlockSize() const override { return 0; }
bool HasFastRandomAccessInBlock() const override { return true; }
+306
View File
@@ -0,0 +1,306 @@
// Copyright 2022 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "DiscIO/NFSBlob.h"
#include <algorithm>
#include <array>
#include <cstring>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include <fmt/format.h>
#include "Common/Align.h"
#include "Common/CommonTypes.h"
#include "Common/Crypto/AES.h"
#include "Common/IOFile.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "Common/Swap.h"
namespace DiscIO
{
bool NFSFileReader::ReadKey(const std::string& path, const std::string& directory, Key* key_out)
{
const std::string_view directory_without_trailing_slash =
std::string_view(directory).substr(0, directory.size() - 1);
std::string parent, parent_name, parent_extension;
SplitPath(directory_without_trailing_slash, &parent, &parent_name, &parent_extension);
if (parent_name + parent_extension != "content")
{
ERROR_LOG_FMT(DISCIO, "hif_000000.nfs is not in a directory named 'content': {}", path);
return false;
}
const std::string key_path = parent + "code/htk.bin";
File::IOFile key_file(key_path, "rb");
if (!key_file.ReadBytes(key_out->data(), key_out->size()))
{
ERROR_LOG_FMT(DISCIO, "Failed to read from {}", key_path);
return false;
}
return true;
}
std::vector<NFSLBARange> NFSFileReader::GetLBARanges(const NFSHeader& header)
{
const size_t lba_range_count =
std::min<size_t>(Common::swap32(header.lba_range_count), header.lba_ranges.size());
std::vector<NFSLBARange> lba_ranges;
lba_ranges.reserve(lba_range_count);
for (size_t i = 0; i < lba_range_count; ++i)
{
const NFSLBARange& unswapped_lba_range = header.lba_ranges[i];
lba_ranges.push_back(NFSLBARange{Common::swap32(unswapped_lba_range.start_block),
Common::swap32(unswapped_lba_range.num_blocks)});
}
return lba_ranges;
}
std::vector<File::IOFile> NFSFileReader::OpenFiles(const std::string& directory,
File::IOFile first_file, u64 expected_raw_size,
u64* raw_size_out)
{
const u64 file_count = Common::AlignUp(expected_raw_size, MAX_FILE_SIZE) / MAX_FILE_SIZE;
std::vector<File::IOFile> files;
files.reserve(file_count);
u64 raw_size = first_file.GetSize();
files.emplace_back(std::move(first_file));
for (u64 i = 1; i < file_count; ++i)
{
const std::string child_path = fmt::format("{}hif_{:06}.nfs", directory, i);
File::IOFile child(child_path, "rb");
if (!child)
{
ERROR_LOG_FMT(DISCIO, "Failed to open {}", child_path);
return {};
}
raw_size += child.GetSize();
files.emplace_back(std::move(child));
}
if (raw_size < expected_raw_size)
{
ERROR_LOG_FMT(
DISCIO,
"Expected sum of NFS file sizes for {} to be at least {} bytes, but it was {} bytes",
directory, expected_raw_size, raw_size);
return {};
}
return files;
}
u64 NFSFileReader::CalculateExpectedRawSize(const std::vector<NFSLBARange>& lba_ranges)
{
u64 total_blocks = 0;
for (const NFSLBARange& range : lba_ranges)
total_blocks += range.num_blocks;
return sizeof(NFSHeader) + total_blocks * BLOCK_SIZE;
}
u64 NFSFileReader::CalculateExpectedDataSize(const std::vector<NFSLBARange>& lba_ranges)
{
u32 greatest_block_index = 0;
for (const NFSLBARange& range : lba_ranges)
greatest_block_index = std::max(greatest_block_index, range.start_block + range.num_blocks);
return u64(greatest_block_index) * BLOCK_SIZE;
}
std::unique_ptr<NFSFileReader> NFSFileReader::Create(File::IOFile first_file,
const std::string& path)
{
std::string directory, filename, extension;
SplitPath(path, &directory, &filename, &extension);
if (filename + extension != "hif_000000.nfs")
return nullptr;
std::array<u8, 16> key;
if (!ReadKey(path, directory, &key))
return nullptr;
NFSHeader header;
if (!first_file.Seek(0, File::SeekOrigin::Begin) ||
!first_file.ReadArray(&header, 1) && header.magic != NFS_MAGIC)
{
return nullptr;
}
std::vector<NFSLBARange> lba_ranges = GetLBARanges(header);
const u64 expected_raw_size = CalculateExpectedRawSize(lba_ranges);
u64 raw_size;
std::vector<File::IOFile> files =
OpenFiles(directory, std::move(first_file), expected_raw_size, &raw_size);
if (files.empty())
return nullptr;
return std::unique_ptr<NFSFileReader>(
new NFSFileReader(std::move(lba_ranges), std::move(files), key, raw_size));
}
NFSFileReader::NFSFileReader(std::vector<NFSLBARange> lba_ranges, std::vector<File::IOFile> files,
Key key, u64 raw_size)
: m_lba_ranges(std::move(lba_ranges)), m_files(std::move(files)),
m_aes_context(Common::AES::CreateContextDecrypt(key.data())), m_raw_size(raw_size)
{
m_data_size = CalculateExpectedDataSize(m_lba_ranges);
}
u64 NFSFileReader::GetDataSize() const
{
return m_data_size;
}
u64 NFSFileReader::GetRawSize() const
{
return m_raw_size;
}
u64 NFSFileReader::ToPhysicalBlockIndex(u64 logical_block_index)
{
u64 physical_blocks_so_far = 0;
for (const NFSLBARange& range : m_lba_ranges)
{
if (logical_block_index >= range.start_block &&
logical_block_index < range.start_block + range.num_blocks)
{
return physical_blocks_so_far + (logical_block_index - range.start_block);
}
physical_blocks_so_far += range.num_blocks;
}
return std::numeric_limits<u64>::max();
}
bool NFSFileReader::ReadEncryptedBlock(u64 physical_block_index)
{
constexpr u64 BLOCKS_PER_FILE = MAX_FILE_SIZE / BLOCK_SIZE;
const u64 file_index = physical_block_index / BLOCKS_PER_FILE;
const u64 block_in_file = physical_block_index % BLOCKS_PER_FILE;
if (block_in_file == BLOCKS_PER_FILE - 1)
{
// Special case. Because of the 0x200 byte header at the very beginning,
// the last block of each file has its last 0x200 bytes stored in the next file.
constexpr size_t PART_1_SIZE = BLOCK_SIZE - sizeof(NFSHeader);
constexpr size_t PART_2_SIZE = sizeof(NFSHeader);
File::IOFile& file_1 = m_files[file_index];
File::IOFile& file_2 = m_files[file_index + 1];
if (!file_1.Seek(sizeof(NFSHeader) + block_in_file * BLOCK_SIZE, File::SeekOrigin::Begin) ||
!file_1.ReadBytes(m_current_block_encrypted.data(), PART_1_SIZE))
{
file_1.ClearError();
return false;
}
if (!file_2.Seek(0, File::SeekOrigin::Begin) ||
!file_2.ReadBytes(m_current_block_encrypted.data() + PART_1_SIZE, PART_2_SIZE))
{
file_2.ClearError();
return false;
}
}
else
{
// Normal case. The read is offset by 0x200 bytes, but it's all within one file.
File::IOFile& file = m_files[file_index];
if (!file.Seek(sizeof(NFSHeader) + block_in_file * BLOCK_SIZE, File::SeekOrigin::Begin) ||
!file.ReadBytes(m_current_block_encrypted.data(), BLOCK_SIZE))
{
file.ClearError();
return false;
}
}
return true;
}
void NFSFileReader::DecryptBlock(u64 logical_block_index)
{
std::array<u8, 16> iv{};
const u64 swapped_block_index = Common::swap64(logical_block_index);
std::memcpy(iv.data() + iv.size() - sizeof(swapped_block_index), &swapped_block_index,
sizeof(swapped_block_index));
m_aes_context->Crypt(iv.data(), m_current_block_encrypted.data(),
m_current_block_decrypted.data(), BLOCK_SIZE);
}
bool NFSFileReader::ReadAndDecryptBlock(u64 logical_block_index)
{
const u64 physical_block_index = ToPhysicalBlockIndex(logical_block_index);
if (physical_block_index == std::numeric_limits<u64>::max())
{
// The block isn't physically present. Treat its contents as all zeroes.
m_current_block_decrypted.fill(0);
}
else
{
if (!ReadEncryptedBlock(physical_block_index))
return false;
DecryptBlock(logical_block_index);
}
// Small hack: Set 0x61 of the header to 1 so that VolumeWii realizes that the disc is unencrypted
if (logical_block_index == 0)
m_current_block_decrypted[0x61] = 1;
return true;
}
bool NFSFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
{
while (nbytes != 0)
{
const u64 logical_block_index = offset / BLOCK_SIZE;
const u64 offset_in_block = offset % BLOCK_SIZE;
if (logical_block_index != m_current_logical_block_index)
{
if (!ReadAndDecryptBlock(logical_block_index))
return false;
m_current_logical_block_index = logical_block_index;
}
const u64 bytes_to_copy = std::min(nbytes, BLOCK_SIZE - offset_in_block);
std::memcpy(out_ptr, m_current_block_decrypted.data() + offset_in_block, bytes_to_copy);
offset += bytes_to_copy;
nbytes -= bytes_to_copy;
out_ptr += bytes_to_copy;
}
return true;
}
} // namespace DiscIO
+91
View File
@@ -0,0 +1,91 @@
// Copyright 2022 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <limits>
#include <memory>
#include <string>
#include <vector>
#include "Common/CommonTypes.h"
#include "Common/Crypto/AES.h"
#include "Common/IOFile.h"
#include "DiscIO/Blob.h"
// This is the file format used for Wii games released on the Wii U eShop.
namespace DiscIO
{
static constexpr u32 NFS_MAGIC = 0x53474745; // "EGGS" (byteswapped to little endian)
struct NFSLBARange
{
u32 start_block;
u32 num_blocks;
};
struct NFSHeader
{
u32 magic; // EGGS
u32 version;
u32 unknown_1;
u32 unknown_2;
u32 lba_range_count;
std::array<NFSLBARange, 61> lba_ranges;
u32 end_magic; // SGGE
};
static_assert(sizeof(NFSHeader) == 0x200);
class NFSFileReader : public BlobReader
{
public:
static std::unique_ptr<NFSFileReader> Create(File::IOFile first_file,
const std::string& directory_path);
BlobType GetBlobType() const override { return BlobType::NFS; }
u64 GetRawSize() const override;
u64 GetDataSize() const override;
DataSizeType GetDataSizeType() const override { return DataSizeType::LowerBound; }
u64 GetBlockSize() const override { return BLOCK_SIZE; }
bool HasFastRandomAccessInBlock() const override { return false; }
std::string GetCompressionMethod() const override { return {}; }
std::optional<int> GetCompressionLevel() const override { return std::nullopt; }
bool Read(u64 offset, u64 nbytes, u8* out_ptr) override;
private:
using Key = std::array<u8, Common::AES::Context::KEY_SIZE>;
static constexpr u32 BLOCK_SIZE = 0x8000;
static constexpr u32 MAX_FILE_SIZE = 0xFA00000;
static bool ReadKey(const std::string& path, const std::string& directory, Key* key_out);
static std::vector<NFSLBARange> GetLBARanges(const NFSHeader& header);
static std::vector<File::IOFile> OpenFiles(const std::string& directory, File::IOFile first_file,
u64 expected_raw_size, u64* raw_size_out);
static u64 CalculateExpectedRawSize(const std::vector<NFSLBARange>& lba_ranges);
static u64 CalculateExpectedDataSize(const std::vector<NFSLBARange>& lba_ranges);
NFSFileReader(std::vector<NFSLBARange> lba_ranges, std::vector<File::IOFile> files, Key key,
u64 raw_size);
u64 ToPhysicalBlockIndex(u64 logical_block_index);
bool ReadEncryptedBlock(u64 physical_block_index);
void DecryptBlock(u64 logical_block_index);
bool ReadAndDecryptBlock(u64 logical_block_index);
std::array<u8, BLOCK_SIZE> m_current_block_encrypted;
std::array<u8, BLOCK_SIZE> m_current_block_decrypted;
u64 m_current_logical_block_index = std::numeric_limits<u64>::max();
std::vector<NFSLBARange> m_lba_ranges;
std::vector<File::IOFile> m_files;
std::unique_ptr<Common::AES::Context> m_aes_context;
u64 m_raw_size;
u64 m_data_size;
};
} // namespace DiscIO

Some files were not shown because too many files have changed in this diff Show More