mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-22 22:00:39 -06:00
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:
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user