Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to DiscIO::CompressFileToBlob and DecompressBlobToFile #2155

Merged
merged 1 commit into from Mar 19, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
107 changes: 79 additions & 28 deletions Source/Core/DiscIO/CompressedBlob.cpp
Expand Up @@ -108,7 +108,7 @@ void CompressedBlobReader::GetBlock(u64 block_num, u8 *out_ptr)
u32 block_hash = HashAdler32(source, comp_block_size);
if (block_hash != m_hashes[block_num])
PanicAlert("Hash of block %" PRIu64 " is %08x instead of %08x.\n"
"Your ISO, %s, is corrupt.",
"Your ISO, \"%s\", is corrupt.",
block_num, block_hash, m_hashes[block_num],
m_file_name.c_str());

Expand Down Expand Up @@ -150,15 +150,31 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u

if (IsCompressedBlob(infile))
{
PanicAlertT("%s is already compressed! Cannot compress it further.", infile.c_str());
PanicAlertT("\"%s\" is already compressed! Cannot compress it further.", infile.c_str());
return false;
}

File::IOFile inf(infile, "rb");
if (!inf)
{
PanicAlertT("Failed to open the input file \"%s\".", infile.c_str());
return false;
}

File::IOFile f(outfile, "wb");
if (!f)
{
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.c_str());
return false;
}

if (sub_type == 1)
{
if (!DiscScrubber::SetupScrub(infile, block_size))
{
PanicAlertT("%s failed to be scrubbed. Probably the image is corrupt.", infile.c_str());
PanicAlertT("\"%s\" failed to be scrubbed. Probably the image is corrupt.", infile.c_str());
return false;
}

Expand All @@ -167,14 +183,8 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u

z_stream z = {};
if (deflateInit(&z, 9) != Z_OK)
return false;

File::IOFile inf(infile, "rb");
File::IOFile f(outfile, "wb");

if (!f || !inf)
{
deflateEnd(&z);
DiscScrubber::Cleanup();
return false;
}

Expand Down Expand Up @@ -204,7 +214,7 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u
int num_compressed = 0;
int num_stored = 0;
int progress_monitor = std::max<int>(1, header.num_blocks / 1000);
bool was_cancelled = false;
bool success = true;

for (u32 i = 0; i < header.num_blocks; i++)
{
Expand All @@ -216,9 +226,12 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u
ratio = (int)(100 * position / inpos);

std::string temp = StringFromFormat("%i of %i blocks. Compression ratio %i%%", i, header.num_blocks, ratio);
was_cancelled = !callback(temp, (float)i / (float)header.num_blocks, arg);
bool was_cancelled = !callback(temp, (float)i / (float)header.num_blocks, arg);
if (was_cancelled)
{
success = false;
break;
}
}

offsets[i] = position;
Expand All @@ -240,35 +253,51 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u
if (retval != Z_OK)
{
ERROR_LOG(DISCIO, "Deflate failed");
goto cleanup;
success = false;
break;
}

int status = deflate(&z, Z_FINISH);
int comp_size = block_size - z.avail_out;

u8* write_buf;
int write_size;
if ((status != Z_STREAM_END) || (z.avail_out < 10))
{
//PanicAlert("%i %i Store %i", i*block_size, position, comp_size);
// let's store uncompressed
write_buf = in_buf;
offsets[i] |= 0x8000000000000000ULL;
f.WriteBytes(in_buf, block_size);
hashes[i] = HashAdler32(in_buf, block_size);
position += block_size;
write_size = block_size;
num_stored++;
}
else
{
// let's store compressed
//PanicAlert("Comp %i to %i", block_size, comp_size);
f.WriteBytes(out_buf, comp_size);
hashes[i] = HashAdler32(out_buf, comp_size);
position += comp_size;
write_buf = out_buf;
write_size = comp_size;
num_compressed++;
}

if (!f.WriteBytes(write_buf, write_size))
{
PanicAlertT(
"Failed to write the output file \"%s\".\n"
"Check that you have enough space available on the target drive.",
outfile.c_str());
success = false;
break;
}

position += write_size;

hashes[i] = HashAdler32(write_buf, write_size);
}

header.compressed_data_size = position;

if (was_cancelled)
if (!success)
{
// Remove the incomplete output file.
f.Close();
Expand All @@ -283,18 +312,20 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u
f.WriteArray(hashes, header.num_blocks);
}

cleanup:
// Cleanup
delete[] in_buf;
delete[] out_buf;
delete[] offsets;
delete[] hashes;

deflateEnd(&z);

DiscScrubber::Cleanup();
callback("Done compressing disc image.", 1.0f, arg);
return true;

if (success)
{
callback("Done compressing disc image.", 1.0f, arg);
}
return success;
}

bool DecompressBlobToFile(const std::string& infile, const std::string& outfile, CompressCB callback, void* arg)
Expand All @@ -307,11 +338,20 @@ bool DecompressBlobToFile(const std::string& infile, const std::string& outfile,

std::unique_ptr<CompressedBlobReader> reader(CompressedBlobReader::Create(infile));
if (!reader)
{
PanicAlertT("Failed to open the input file \"%s\".", infile.c_str());
return false;
}

File::IOFile f(outfile, "wb");
if (!f)
{
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.c_str());
return false;
}

const CompressedBlobHeader &header = reader->GetHeader();
static const size_t BUFFER_BLOCKS = 32;
Expand All @@ -320,22 +360,33 @@ bool DecompressBlobToFile(const std::string& infile, const std::string& outfile,
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 was_cancelled = false;
bool success = true;

for (u64 i = 0; i < num_buffers; i++)
{
if (i % progress_monitor == 0)
{
was_cancelled = !callback("Unpacking", (float)i / (float)num_buffers, arg);
bool was_cancelled = !callback("Unpacking", (float)i / (float)num_buffers, arg);
if (was_cancelled)
{
success = false;
break;
}
}
const size_t sz = i == num_buffers - 1 ? last_buffer_size : buffer_size;
reader->Read(i * buffer_size, sz, buffer.data());
f.WriteBytes(buffer.data(), sz);
if (!f.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.c_str());
success = false;
break;
}
}

if (was_cancelled)
if (!success)
{
// Remove the incomplete output file.
f.Close();
Expand Down