Skip to content
Permalink
Browse files
Merge pull request #8738 from JosJuice/convert-dialog
Replace the compress/uncompress actions with a convert dialog
  • Loading branch information
JMC47 committed Apr 28, 2020
2 parents 165c2e3 + 99c8ce9 commit 116cef5
Show file tree
Hide file tree
Showing 26 changed files with 761 additions and 431 deletions.
@@ -41,11 +41,16 @@ class BlobReader
{
public:
virtual ~BlobReader() {}

virtual BlobType GetBlobType() const = 0;

virtual u64 GetRawSize() const = 0;
virtual u64 GetDataSize() const = 0;
virtual bool IsDataSizeAccurate() const = 0;

// Returns 0 if the format does not use blocks
virtual u64 GetBlockSize() const { return 0; }

// NOT thread-safe - can't call this from multiple threads.
virtual bool Read(u64 offset, u64 size, u8* out_ptr) = 0;
template <typename T>
@@ -160,10 +165,11 @@ std::unique_ptr<BlobReader> CreateBlobReader(const std::string& filename);

typedef bool (*CompressCB)(const std::string& text, float percent, void* arg);

bool CompressFileToBlob(const std::string& infile_path, const std::string& outfile_path,
u32 sub_type = 0, int sector_size = 16384, CompressCB callback = nullptr,
void* arg = nullptr);
bool DecompressBlobToFile(const std::string& infile_path, const std::string& outfile_path,
CompressCB callback = nullptr, void* arg = nullptr);
bool ConvertToGCZ(BlobReader* infile, const std::string& infile_path,
const std::string& outfile_path, u32 sub_type, int sector_size = 16384,
CompressCB callback = nullptr, void* arg = nullptr);
bool ConvertToPlain(BlobReader* infile, const std::string& infile_path,
const std::string& outfile_path, CompressCB callback = nullptr,
void* arg = nullptr);

} // namespace DiscIO
@@ -37,12 +37,15 @@ class CISOFileReader : public BlobReader
static std::unique_ptr<CISOFileReader> Create(File::IOFile file);

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

u64 GetRawSize() const override;
u64 GetBlockSize() const override { return m_block_size; }

bool Read(u64 offset, u64 nbytes, u8* out_ptr) override;

private:
@@ -23,6 +23,8 @@ add_library(discio
Filesystem.h
NANDImporter.cpp
NANDImporter.h
ScrubbedBlob.cpp
ScrubbedBlob.h
TGCBlob.cpp
TGCBlob.h
Volume.cpp
@@ -17,6 +17,7 @@
#include <vector>
#include <zlib.h>

#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/File.h"
#include "Common/FileUtil.h"
@@ -153,23 +154,11 @@ bool CompressedBlobReader::GetBlock(u64 block_num, u8* out_ptr)
return true;
}

bool CompressFileToBlob(const std::string& infile_path, const std::string& outfile_path,
u32 sub_type, int block_size, CompressCB callback, void* arg)
bool ConvertToGCZ(BlobReader* infile, const std::string& infile_path,
const std::string& outfile_path, u32 sub_type, int block_size,
CompressCB callback, void* arg)
{
bool scrubbing = false;

File::IOFile infile(infile_path, "rb");
if (IsGCZBlob(infile))
{
PanicAlertT("\"%s\" is already compressed! Cannot compress it further.", infile_path.c_str());
return false;
}

if (!infile)
{
PanicAlertT("Failed to open the input file \"%s\".", infile_path.c_str());
return false;
}
ASSERT(infile->IsDataSizeAccurate());

File::IOFile outfile(outfile_path, "wb");
if (!outfile)
@@ -181,21 +170,6 @@ bool CompressFileToBlob(const std::string& infile_path, const std::string& outfi
return false;
}

DiscScrubber disc_scrubber;
std::unique_ptr<VolumeDisc> volume;
if (sub_type == 1)
{
volume = CreateDisc(infile_path);
if (!volume || !disc_scrubber.SetupScrub(volume.get(), block_size))
{
PanicAlertT("\"%s\" failed to be scrubbed. Probably the image is corrupt.",
infile_path.c_str());
return false;
}

scrubbing = true;
}

z_stream z = {};
if (deflateInit(&z, 9) != Z_OK)
return false;
@@ -206,7 +180,7 @@ bool CompressFileToBlob(const std::string& infile_path, const std::string& outfi
header.magic_cookie = GCZ_MAGIC;
header.sub_type = sub_type;
header.block_size = block_size;
header.data_size = infile.GetSize();
header.data_size = infile->GetDataSize();

// round upwards!
header.num_blocks = (u32)((header.data_size + (block_size - 1)) / block_size);
@@ -220,10 +194,9 @@ bool CompressFileToBlob(const std::string& infile_path, const std::string& outfi
outfile.Seek(sizeof(CompressedBlobHeader), SEEK_CUR);
// seek past the offset and hash tables (we will write them at the end)
outfile.Seek((sizeof(u64) + sizeof(u32)) * header.num_blocks, SEEK_CUR);
// seek to the start of the input file to make sure we get everything
infile.Seek(0, SEEK_SET);

// Now we are ready to write compressed data!
u64 inpos = 0;
u64 position = 0;
int num_compressed = 0;
int num_stored = 0;
@@ -234,7 +207,6 @@ bool CompressFileToBlob(const std::string& infile_path, const std::string& outfi
{
if (i % progress_monitor == 0)
{
const u64 inpos = infile.Tell();
int ratio = 0;
if (inpos != 0)
ratio = (int)(100 * position / inpos);
@@ -252,13 +224,16 @@ bool CompressFileToBlob(const std::string& infile_path, const std::string& outfi

offsets[i] = position;

size_t read_bytes;
if (scrubbing)
read_bytes = disc_scrubber.GetNextBlock(infile, in_buf.data());
else
infile.ReadArray(in_buf.data(), header.block_size, &read_bytes);
if (read_bytes < header.block_size)
std::fill(in_buf.begin() + read_bytes, in_buf.begin() + header.block_size, 0);
const u64 bytes_to_read = std::min<u64>(block_size, header.data_size - inpos);

success = infile->Read(inpos, bytes_to_read, in_buf.data());
if (!success)
{
PanicAlertT("Failed to read from the input file \"%s\".", infile_path.c_str());
break;
}

std::fill(in_buf.begin() + bytes_to_read, in_buf.begin() + header.block_size, 0);

int retval = deflateReset(&z);
z.next_in = in_buf.data();
@@ -305,6 +280,7 @@ bool CompressFileToBlob(const std::string& infile_path, const std::string& outfi
break;
}

inpos += block_size;
position += write_size;

hashes[i] = Common::HashAdler32(write_buf, write_size);
@@ -337,84 +313,6 @@ bool CompressFileToBlob(const std::string& infile_path, const std::string& outfi
return success;
}

bool DecompressBlobToFile(const std::string& infile_path, const std::string& outfile_path,
CompressCB callback, void* arg)
{
std::unique_ptr<CompressedBlobReader> reader;
{
File::IOFile infile(infile_path, "rb");
if (!IsGCZBlob(infile))
{
PanicAlertT("File not compressed");
return false;
}

reader = CompressedBlobReader::Create(std::move(infile), infile_path);
}

if (!reader)
{
PanicAlertT("Failed to open the input file \"%s\".", infile_path.c_str());
return false;
}

File::IOFile outfile(outfile_path, "wb");
if (!outfile)
{
PanicAlertT("Failed to open the output file \"%s\".\n"
"Check that you have permissions to write the target folder and that the media can "
"be written.",
outfile_path.c_str());
return false;
}

const CompressedBlobHeader& header = reader->GetHeader();
static const size_t BUFFER_BLOCKS = 32;
size_t buffer_size = header.block_size * BUFFER_BLOCKS;
std::vector<u8> buffer(buffer_size);
u32 num_buffers = (header.num_blocks + BUFFER_BLOCKS - 1) / BUFFER_BLOCKS;
int progress_monitor = std::max<int>(1, num_buffers / 100);
bool success = true;

for (u64 i = 0; i < num_buffers; i++)
{
if (i % progress_monitor == 0)
{
const bool was_cancelled =
!callback(Common::GetStringT("Unpacking"), (float)i / (float)num_buffers, arg);
if (was_cancelled)
{
success = false;
break;
}
}
const u64 inpos = i * buffer_size;
const u64 sz = std::min<u64>(buffer_size, header.data_size - inpos);
reader->Read(inpos, sz, buffer.data());
if (!outfile.WriteBytes(buffer.data(), sz))
{
PanicAlertT("Failed to write the output file \"%s\".\n"
"Check that you have enough space available on the target drive.",
outfile_path.c_str());
success = false;
break;
}
}

if (!success)
{
// Remove the incomplete output file.
outfile.Close();
File::Delete(outfile_path);
}
else
{
outfile.Resize(header.data_size);
}

return success;
}

bool IsGCZBlob(File::IOFile& file)
{
const u64 position = file.Tell();
@@ -52,6 +52,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; }
u64 GetBlockSize() const override { return m_header.block_size; }
u64 GetBlockCompressedSize(u64 block_num) const;
bool GetBlock(u64 block_num, u8* out_ptr) override;

@@ -56,6 +56,7 @@
<ClCompile Include="Filesystem.cpp" />
<ClCompile Include="FileSystemGCWii.cpp" />
<ClCompile Include="NANDImporter.cpp" />
<ClCompile Include="ScrubbedBlob.cpp" />
<ClCompile Include="TGCBlob.cpp" />
<ClCompile Include="Volume.cpp" />
<ClCompile Include="VolumeFileBlobReader.cpp" />
@@ -80,6 +81,7 @@
<ClInclude Include="Filesystem.h" />
<ClInclude Include="FileSystemGCWii.h" />
<ClInclude Include="NANDImporter.h" />
<ClInclude Include="ScrubbedBlob.h" />
<ClInclude Include="TGCBlob.h" />
<ClInclude Include="Volume.h" />
<ClInclude Include="VolumeFileBlobReader.h" />
@@ -87,6 +87,9 @@
<ClCompile Include="WiiEncryptionCache.cpp">
<Filter>Volume\Blob</Filter>
</ClCompile>
<ClCompile Include="ScrubbedBlob.cpp">
<Filter>Volume\Blob</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="DiscScrubber.h">
@@ -155,6 +158,9 @@
<ClInclude Include="WiiEncryptionCache.h">
<Filter>Volume\Blob</Filter>
</ClInclude>
<ClInclude Include="ScrubbedBlob.h">
<Filter>Volume\Blob</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />

0 comments on commit 116cef5

Please sign in to comment.