Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #10932 from JosJuice/nfs
DiscIO: Add support for the NFS format
  • Loading branch information
AdmiralCurtiss committed Aug 4, 2022
2 parents ceae42b + 6fc3bbb commit 5508c52
Show file tree
Hide file tree
Showing 44 changed files with 635 additions and 141 deletions.
Expand Up @@ -30,7 +30,8 @@
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);

Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Boot/Boot.cpp
Expand Up @@ -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);
Expand Down
13 changes: 6 additions & 7 deletions Source/Core/Core/HW/DVD/DVDInterface.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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
{
Expand Down
6 changes: 3 additions & 3 deletions Source/Core/Core/HW/DVD/DVDThread.cpp
Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/DVD/DVDThread.h
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions Source/Core/DiscIO/Blob.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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 "";
}
Expand Down Expand Up @@ -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);
Expand Down
15 changes: 14 additions & 1 deletion Source/Core/DiscIO/Blob.h
Expand Up @@ -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);
Expand All @@ -53,7 +66,7 @@ class BlobReader

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;
Expand Down
4 changes: 1 addition & 3 deletions Source/Core/DiscIO/CISOBlob.h
Expand Up @@ -38,10 +38,8 @@ class CISOFileReader : public BlobReader
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; }
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DiscIO/CMakeLists.txt
Expand Up @@ -30,6 +30,8 @@ add_library(discio
MultithreadedCompressor.h
NANDImporter.cpp
NANDImporter.h
NFSBlob.cpp
NFSBlob.h
RiivolutionParser.cpp
RiivolutionParser.h
RiivolutionPatcher.cpp
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/DiscIO/CompressedBlob.cpp
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/DiscIO/CompressedBlob.h
Expand Up @@ -53,7 +53,7 @@ class CompressedBlobReader : public SectorReader

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; }
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/DiscIO/DirectoryBlob.cpp
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/DiscIO/DirectoryBlob.h
Expand Up @@ -284,7 +284,7 @@ class DirectoryBlobReader : public BlobReader

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; }
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/DiscIO/DiscExtractor.cpp
Expand Up @@ -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");
}

Expand Down
10 changes: 7 additions & 3 deletions Source/Core/DiscIO/DiscScrubber.cpp
Expand Up @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/DiscIO/DriveBlob.h
Expand Up @@ -27,7 +27,7 @@ class DriveReader : public SectorReader

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; }
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/DiscIO/FileBlob.cpp
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/DiscIO/FileBlob.h
Expand Up @@ -22,7 +22,7 @@ class PlainFileReader : public BlobReader

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; }
Expand Down

0 comments on commit 5508c52

Please sign in to comment.