DiscIO: Allow converting from formats other than ISO and GCZ

The constant DESIRED_BUFFER_SIZE was determined by multiplying the
old hardcoded value 32 with the default GCZ block size 16 KiB.
Not sure if it actually is the best value, but it seems fine.
This commit is contained in:
JosJuice
2020-04-04 20:56:20 +02:00
parent 0a71dda8a0
commit 8a9597e32e
10 changed files with 80 additions and 96 deletions

View File

@ -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,24 +154,20 @@ 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(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;
}
std::unique_ptr<VolumeDisc> infile = CreateDisc(infile_path);
if (!infile)
{
PanicAlertT("Failed to open the input file \"%s\".", infile_path.c_str());
return false;
}
ASSERT(infile->IsSizeAccurate());
File::IOFile outfile(outfile_path, "wb");
if (!outfile)
{
@ -182,11 +179,9 @@ bool CompressFileToBlob(const std::string& infile_path, const std::string& outfi
}
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))
if (!disc_scrubber.SetupScrub(infile.get()))
{
PanicAlertT("\"%s\" failed to be scrubbed. Probably the image is corrupt.",
infile_path.c_str());
@ -206,7 +201,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->GetSize();
// round upwards!
header.num_blocks = (u32)((header.data_size + (block_size - 1)) / block_size);
@ -220,10 +215,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 +228,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 +245,18 @@ 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 = scrubbing && disc_scrubber.CanBlockBeScrubbed(inpos) ?
0 :
std::min<u64>(block_size, header.data_size - inpos);
success = infile->Read(inpos, bytes_to_read, in_buf.data(), PARTITION_NONE);
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 +303,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,27 +336,18 @@ 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)
bool ConvertToPlain(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);
}
std::unique_ptr<BlobReader> reader = CreateBlobReader(infile_path);
if (!reader)
{
PanicAlertT("Failed to open the input file \"%s\".", infile_path.c_str());
return false;
}
ASSERT(reader->IsDataSizeAccurate());
File::IOFile outfile(outfile_path, "wb");
if (!outfile)
{
@ -368,11 +358,20 @@ bool DecompressBlobToFile(const std::string& infile_path, const std::string& out
return false;
}
const CompressedBlobHeader& header = reader->GetHeader();
static const size_t BUFFER_BLOCKS = 32;
size_t buffer_size = header.block_size * BUFFER_BLOCKS;
constexpr size_t DESIRED_BUFFER_SIZE = 0x80000;
u64 buffer_size = reader->GetBlockSize();
if (buffer_size == 0)
{
buffer_size = DESIRED_BUFFER_SIZE;
}
else
{
while (buffer_size < DESIRED_BUFFER_SIZE)
buffer_size *= 2;
}
std::vector<u8> buffer(buffer_size);
u32 num_buffers = (header.num_blocks + BUFFER_BLOCKS - 1) / BUFFER_BLOCKS;
const u64 num_buffers = (reader->GetDataSize() + buffer_size - 1) / buffer_size;
int progress_monitor = std::max<int>(1, num_buffers / 100);
bool success = true;
@ -389,8 +388,13 @@ bool DecompressBlobToFile(const std::string& infile_path, const std::string& out
}
}
const u64 inpos = i * buffer_size;
const u64 sz = std::min<u64>(buffer_size, header.data_size - inpos);
reader->Read(inpos, sz, buffer.data());
const u64 sz = std::min(buffer_size, reader->GetDataSize() - inpos);
if (!reader->Read(inpos, sz, buffer.data()))
{
PanicAlertT("Failed to read from the input file \"%s\".", infile_path.c_str());
success = false;
break;
}
if (!outfile.WriteBytes(buffer.data(), sz))
{
PanicAlertT("Failed to write the output file \"%s\".\n"
@ -407,10 +411,6 @@ bool DecompressBlobToFile(const std::string& infile_path, const std::string& out
outfile.Close();
File::Delete(outfile_path);
}
else
{
outfile.Resize(header.data_size);
}
return success;
}