Merge pull request #1597 from unknownbrackets/gcz-tweaks

Tweaks to gcz compression / decompression
This commit is contained in:
Lioncash 2014-12-01 03:18:24 -05:00
commit 6df67bf38f
6 changed files with 72 additions and 36 deletions

View File

@ -66,7 +66,7 @@ private:
// Factory function - examines the path to choose the right type of IBlobReader, and returns one. // Factory function - examines the path to choose the right type of IBlobReader, and returns one.
IBlobReader* CreateBlobReader(const std::string& filename); IBlobReader* CreateBlobReader(const std::string& filename);
typedef void (*CompressCB)(const std::string& text, float percent, void* arg); typedef bool (*CompressCB)(const std::string& text, float percent, void* arg);
bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u32 sub_type = 0, int sector_size = 16384, bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u32 sub_type = 0, int sector_size = 16384,
CompressCB callback = nullptr, void *arg = nullptr); CompressCB callback = nullptr, void *arg = nullptr);

View File

@ -163,11 +163,18 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u
scrubbing = true; scrubbing = true;
} }
z_stream z = {};
if (deflateInit(&z, 9) != Z_OK)
return false;
File::IOFile inf(infile, "rb"); File::IOFile inf(infile, "rb");
File::IOFile f(outfile, "wb"); File::IOFile f(outfile, "wb");
if (!f || !inf) if (!f || !inf)
{
deflateEnd(&z);
return false; return false;
}
callback("Files opened, ready to compress.", 0, arg); callback("Files opened, ready to compress.", 0, arg);
@ -195,6 +202,7 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u
int num_compressed = 0; int num_compressed = 0;
int num_stored = 0; int num_stored = 0;
int progress_monitor = std::max<int>(1, header.num_blocks / 1000); int progress_monitor = std::max<int>(1, header.num_blocks / 1000);
bool was_cancelled = false;
for (u32 i = 0; i < header.num_blocks; i++) for (u32 i = 0; i < header.num_blocks; i++)
{ {
@ -206,27 +214,26 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u
ratio = (int)(100 * position / inpos); ratio = (int)(100 * position / inpos);
std::string temp = StringFromFormat("%i of %i blocks. Compression ratio %i%%", i, header.num_blocks, ratio); std::string temp = StringFromFormat("%i of %i blocks. Compression ratio %i%%", i, header.num_blocks, ratio);
callback(temp, (float)i / (float)header.num_blocks, arg); was_cancelled = !callback(temp, (float)i / (float)header.num_blocks, arg);
if (was_cancelled)
break;
} }
offsets[i] = position; offsets[i] = position;
// u64 start = i * header.block_size;
// u64 size = header.block_size; size_t read_bytes;
std::fill(in_buf, in_buf + header.block_size, 0);
if (scrubbing) if (scrubbing)
DiscScrubber::GetNextBlock(inf, in_buf); read_bytes = DiscScrubber::GetNextBlock(inf, in_buf);
else else
inf.ReadBytes(in_buf, header.block_size); inf.ReadArray(in_buf, header.block_size, &read_bytes);
z_stream z; if (read_bytes < header.block_size)
memset(&z, 0, sizeof(z)); std::fill(in_buf + read_bytes, in_buf + header.block_size, 0);
z.zalloc = Z_NULL;
z.zfree = Z_NULL; int retval = deflateReset(&z);
z.opaque = Z_NULL;
z.next_in = in_buf; z.next_in = in_buf;
z.avail_in = header.block_size; z.avail_in = header.block_size;
z.next_out = out_buf; z.next_out = out_buf;
z.avail_out = block_size; z.avail_out = block_size;
int retval = deflateInit(&z, 9);
if (retval != Z_OK) if (retval != Z_OK)
{ {
@ -255,17 +262,24 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u
position += comp_size; position += comp_size;
num_compressed++; num_compressed++;
} }
deflateEnd(&z);
} }
header.compressed_data_size = position; header.compressed_data_size = position;
// Okay, go back and fill in headers if (was_cancelled)
f.Seek(0, SEEK_SET); {
f.WriteArray(&header, 1); // Remove the incomplete output file.
f.WriteArray(offsets, header.num_blocks); f.Close();
f.WriteArray(hashes, header.num_blocks); File::Delete(outfile);
}
else
{
// Okay, go back and fill in headers
f.Seek(0, SEEK_SET);
f.WriteArray(&header, 1);
f.WriteArray(offsets, header.num_blocks);
f.WriteArray(hashes, header.num_blocks);
}
cleanup: cleanup:
// Cleanup // Cleanup
@ -274,6 +288,8 @@ cleanup:
delete[] offsets; delete[] offsets;
delete[] hashes; delete[] hashes;
deflateEnd(&z);
DiscScrubber::Cleanup(); DiscScrubber::Cleanup();
callback("Done compressing disc image.", 1.0f, arg); callback("Done compressing disc image.", 1.0f, arg);
return true; return true;
@ -299,22 +315,37 @@ bool DecompressBlobToFile(const std::string& infile, const std::string& outfile,
} }
const CompressedBlobHeader &header = reader->GetHeader(); const CompressedBlobHeader &header = reader->GetHeader();
u8* buffer = new u8[header.block_size]; static const size_t BUFFER_BLOCKS = 32;
int progress_monitor = std::max<int>(1, header.num_blocks / 100); size_t buffer_size = header.block_size * BUFFER_BLOCKS;
u8* buffer = new u8[buffer_size];
u32 num_buffers = header.num_blocks / BUFFER_BLOCKS;
int progress_monitor = std::max<int>(1, num_buffers / 100);
bool was_cancelled = false;
for (u64 i = 0; i < header.num_blocks; i++) for (u64 i = 0; i < num_buffers; i++)
{ {
if (i % progress_monitor == 0) if (i % progress_monitor == 0)
{ {
callback("Unpacking", (float)i / (float)header.num_blocks, arg); was_cancelled = !callback("Unpacking", (float)i / (float)num_buffers, arg);
if (was_cancelled)
break;
} }
reader->Read(i * header.block_size, header.block_size, buffer); reader->Read(i * buffer_size, buffer_size, buffer);
f.WriteBytes(buffer, header.block_size); f.WriteBytes(buffer, buffer_size);
} }
delete[] buffer; delete[] buffer;
f.Resize(header.data_size); if (was_cancelled)
{
// Remove the incomplete output file.
f.Close();
File::Delete(outfile);
}
else
{
f.Resize(header.data_size);
}
delete reader; delete reader;

View File

@ -124,24 +124,27 @@ bool SetupScrub(const std::string& filename, int block_size)
return success; return success;
} }
void GetNextBlock(File::IOFile& in, u8* buffer) size_t GetNextBlock(File::IOFile& in, u8* buffer)
{ {
u64 CurrentOffset = m_BlockCount * m_BlockSize; u64 CurrentOffset = m_BlockCount * m_BlockSize;
u64 i = CurrentOffset / CLUSTER_SIZE; u64 i = CurrentOffset / CLUSTER_SIZE;
size_t ReadBytes = 0;
if (m_isScrubbing && m_FreeTable[i]) if (m_isScrubbing && m_FreeTable[i])
{ {
DEBUG_LOG(DISCIO, "Freeing 0x%016" PRIx64, CurrentOffset); DEBUG_LOG(DISCIO, "Freeing 0x%016" PRIx64, CurrentOffset);
std::fill(buffer, buffer + m_BlockSize, 0xFF); std::fill(buffer, buffer + m_BlockSize, 0xFF);
in.Seek(m_BlockSize, SEEK_CUR); in.Seek(m_BlockSize, SEEK_CUR);
ReadBytes = m_BlockSize;
} }
else else
{ {
DEBUG_LOG(DISCIO, "Used 0x%016" PRIx64, CurrentOffset); DEBUG_LOG(DISCIO, "Used 0x%016" PRIx64, CurrentOffset);
in.ReadBytes(buffer, m_BlockSize); in.ReadArray(buffer, m_BlockSize, &ReadBytes);
} }
m_BlockCount++; m_BlockCount++;
return ReadBytes;
} }
void Cleanup() void Cleanup()

View File

@ -25,7 +25,7 @@ namespace DiscScrubber
{ {
bool SetupScrub(const std::string& filename, int block_size); bool SetupScrub(const std::string& filename, int block_size);
void GetNextBlock(File::IOFile& in, u8* buffer); size_t GetNextBlock(File::IOFile& in, u8* buffer);
void Cleanup(); void Cleanup();
} // namespace DiscScrubber } // namespace DiscScrubber

View File

@ -1123,14 +1123,14 @@ void CGameListCtrl::OnWiki(wxCommandEvent& WXUNUSED (event))
WxUtils::Launch(wikiUrl); WxUtils::Launch(wikiUrl);
} }
void CGameListCtrl::MultiCompressCB(const std::string& text, float percent, void* arg) bool CGameListCtrl::MultiCompressCB(const std::string& text, float percent, void* arg)
{ {
percent = (((float)m_currentItem) + percent) / (float)m_numberItem; percent = (((float)m_currentItem) + percent) / (float)m_numberItem;
wxString textString(StrToWxStr(StringFromFormat("%s (%i/%i) - %s", wxString textString(StrToWxStr(StringFromFormat("%s (%i/%i) - %s",
m_currentFilename.c_str(), (int)m_currentItem+1, m_currentFilename.c_str(), (int)m_currentItem+1,
(int)m_numberItem, text.c_str()))); (int)m_numberItem, text.c_str())));
((wxProgressDialog*)arg)->Update((int)(percent*1000), textString); return ((wxProgressDialog*)arg)->Update((int)(percent*1000), textString);
} }
void CGameListCtrl::OnMultiCompressISO(wxCommandEvent& /*event*/) void CGameListCtrl::OnMultiCompressISO(wxCommandEvent& /*event*/)
@ -1162,6 +1162,7 @@ void CGameListCtrl::CompressSelection(bool _compress)
1000, 1000,
this, this,
wxPD_APP_MODAL | wxPD_APP_MODAL |
wxPD_CAN_ABORT |
wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME |
wxPD_SMOOTH wxPD_SMOOTH
); );
@ -1235,9 +1236,9 @@ void CGameListCtrl::CompressSelection(bool _compress)
Update(); Update();
} }
void CGameListCtrl::CompressCB(const std::string& text, float percent, void* arg) bool CGameListCtrl::CompressCB(const std::string& text, float percent, void* arg)
{ {
((wxProgressDialog*)arg)-> return ((wxProgressDialog*)arg)->
Update((int)(percent*1000), StrToWxStr(text)); Update((int)(percent*1000), StrToWxStr(text));
} }
@ -1300,6 +1301,7 @@ void CGameListCtrl::OnCompressISO(wxCommandEvent& WXUNUSED (event))
1000, 1000,
this, this,
wxPD_APP_MODAL | wxPD_APP_MODAL |
wxPD_CAN_ABORT |
wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME |
wxPD_SMOOTH wxPD_SMOOTH
); );

View File

@ -113,6 +113,6 @@ private:
static size_t m_currentItem; static size_t m_currentItem;
static std::string m_currentFilename; static std::string m_currentFilename;
static size_t m_numberItem; static size_t m_numberItem;
static void CompressCB(const std::string& text, float percent, void* arg); static bool CompressCB(const std::string& text, float percent, void* arg);
static void MultiCompressCB(const std::string& text, float percent, void* arg); static bool MultiCompressCB(const std::string& text, float percent, void* arg);
}; };