summaryrefslogtreecommitdiff
path: root/Source/Core/DiscIO/CompressedBlob.cpp
diff options
context:
space:
mode:
authorJosJuice <josjuice@gmail.com>2020-04-04 20:56:20 +0200
committerJosJuice <josjuice@gmail.com>2020-04-24 15:10:35 +0200
commit8a9597e32e98707d5bcdc1a41d8c45e3174d4047 (patch)
treee51bd533a154d4eac9b532aedee05f0a39dffb2b /Source/Core/DiscIO/CompressedBlob.cpp
parent0a71dda8a0c615e8f387dc12d519cf3415a5ef79 (diff)
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.
Diffstat (limited to 'Source/Core/DiscIO/CompressedBlob.cpp')
-rw-r--r--Source/Core/DiscIO/CompressedBlob.cpp94
1 files changed, 47 insertions, 47 deletions
diff --git a/Source/Core/DiscIO/CompressedBlob.cpp b/Source/Core/DiscIO/CompressedBlob.cpp
index 5248170683..33790ad3b0 100644
--- a/Source/Core/DiscIO/CompressedBlob.cpp
+++ b/Source/Core/DiscIO/CompressedBlob.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,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;
}