mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 16:19:28 +01:00
another patch from baby.lueshi: DiscScrubber doesn't modify original file anymore, and just returns the "real" or "free'd" buffer inline with compression - so it should be a little faster too :)
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5032 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
98ddeadbbf
commit
5f19fb22b2
@ -158,6 +158,8 @@ void CompressedBlobReader::GetBlock(u64 block_num, u8 *out_ptr)
|
|||||||
bool CompressFileToBlob(const char* infile, const char* outfile, u32 sub_type,
|
bool CompressFileToBlob(const char* infile, const char* outfile, u32 sub_type,
|
||||||
int block_size, CompressCB callback, void* arg)
|
int block_size, CompressCB callback, void* arg)
|
||||||
{
|
{
|
||||||
|
bool scrubbing = false;
|
||||||
|
|
||||||
if (IsCompressedBlob(infile))
|
if (IsCompressedBlob(infile))
|
||||||
{
|
{
|
||||||
PanicAlert("%s is already compressed! Cannot compress it further.", infile);
|
PanicAlert("%s is already compressed! Cannot compress it further.", infile);
|
||||||
@ -166,11 +168,13 @@ bool CompressFileToBlob(const char* infile, const char* outfile, u32 sub_type,
|
|||||||
|
|
||||||
if (sub_type == 1)
|
if (sub_type == 1)
|
||||||
{
|
{
|
||||||
if (!DiscScrubber::Scrub(infile, callback, arg))
|
if (!DiscScrubber::SetupScrub(infile, block_size))
|
||||||
{
|
{
|
||||||
PanicAlert("%s failed to be scrubbed. Probably the image is corrupt.", infile);
|
PanicAlert("%s failed to be scrubbed. Probably the image is corrupt.", infile);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scrubbing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* inf = fopen(infile, "rb");
|
FILE* inf = fopen(infile, "rb");
|
||||||
@ -230,7 +234,10 @@ bool CompressFileToBlob(const char* infile, const char* outfile, u32 sub_type,
|
|||||||
// u64 start = i * header.block_size;
|
// u64 start = i * header.block_size;
|
||||||
// u64 size = header.block_size;
|
// u64 size = header.block_size;
|
||||||
std::fill(in_buf, in_buf + header.block_size, 0);
|
std::fill(in_buf, in_buf + header.block_size, 0);
|
||||||
fread(in_buf, header.block_size, 1, inf);
|
if (scrubbing)
|
||||||
|
DiscScrubber::GetNextBlock(inf, in_buf);
|
||||||
|
else
|
||||||
|
fread(in_buf, header.block_size, 1, inf);
|
||||||
z_stream z;
|
z_stream z;
|
||||||
memset(&z, 0, sizeof(z));
|
memset(&z, 0, sizeof(z));
|
||||||
z.zalloc = Z_NULL;
|
z.zalloc = Z_NULL;
|
||||||
@ -289,6 +296,7 @@ cleanup:
|
|||||||
delete[] hashes;
|
delete[] hashes;
|
||||||
fclose(f);
|
fclose(f);
|
||||||
fclose(inf);
|
fclose(inf);
|
||||||
|
DiscScrubber::Cleanup();
|
||||||
callback("Done compressing disc image.", 1.0f, arg);
|
callback("Done compressing disc image.", 1.0f, arg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -32,12 +32,15 @@ namespace DiscScrubber
|
|||||||
|
|
||||||
#define CLUSTER_SIZE 0x8000
|
#define CLUSTER_SIZE 0x8000
|
||||||
|
|
||||||
static u8* m_Sector1;
|
u8* m_FreeTable = NULL;
|
||||||
static u8* m_FreeTable;
|
u64 m_FileSize;
|
||||||
static u64 m_FileSize;
|
u64 m_BlockCount;
|
||||||
|
u32 m_BlockSize;
|
||||||
|
int m_BlocksPerCluster;
|
||||||
|
bool m_isScrubbing = false;
|
||||||
|
|
||||||
static std::string m_Filename;
|
std::string m_Filename;
|
||||||
static IVolume* m_Disc = NULL;
|
IVolume* m_Disc = NULL;
|
||||||
|
|
||||||
struct SPartitionHeader
|
struct SPartitionHeader
|
||||||
{
|
{
|
||||||
@ -72,12 +75,11 @@ struct SPartitionGroup
|
|||||||
u64 PartitionsOffset;
|
u64 PartitionsOffset;
|
||||||
std::vector<SPartition> PartitionsVec;
|
std::vector<SPartition> PartitionsVec;
|
||||||
};
|
};
|
||||||
static SPartitionGroup PartitionGroup[4];
|
SPartitionGroup PartitionGroup[4];
|
||||||
|
|
||||||
|
|
||||||
void MarkAsUsed(u64 _Offset, u64 _Size);
|
void MarkAsUsed(u64 _Offset, u64 _Size);
|
||||||
void MarkAsUsedE(u64 _PartitionDataOffset, u64 _Offset, u64 _Size);
|
void MarkAsUsedE(u64 _PartitionDataOffset, u64 _Offset, u64 _Size);
|
||||||
bool MarkAsScrubbed(const char* filename);
|
|
||||||
void ReadFromDisc(u64 _Offset, u64 _Length, u32& _Buffer);
|
void ReadFromDisc(u64 _Offset, u64 _Length, u32& _Buffer);
|
||||||
void ReadFromDisc(u64 _Offset, u64 _Length, u64& _Buffer);
|
void ReadFromDisc(u64 _Offset, u64 _Length, u64& _Buffer);
|
||||||
void ReadFromVolume(u64 _Offset, u64 _Length, u32& _Buffer);
|
void ReadFromVolume(u64 _Offset, u64 _Length, u32& _Buffer);
|
||||||
@ -102,10 +104,19 @@ u32 IsScrubbed(const char* filename)
|
|||||||
return ScrubbedFlag;
|
return ScrubbedFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Scrub(const char* filename, CompressCB callback, void* arg)
|
bool SetupScrub(const char* filename, int block_size)
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
m_Filename = std::string(filename);
|
m_Filename = std::string(filename);
|
||||||
|
m_BlockSize = block_size;
|
||||||
|
|
||||||
|
if (CLUSTER_SIZE % m_BlockSize != 0)
|
||||||
|
{
|
||||||
|
ERROR_LOG(DISCIO, "block size %i is not a factor of 0x8000, scrubbing not possible", m_BlockSize);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_BlocksPerCluster = CLUSTER_SIZE / m_BlockSize;
|
||||||
|
|
||||||
u32 version = IsScrubbed(filename);
|
u32 version = IsScrubbed(filename);
|
||||||
if (version && version < SCRUBBER_VERSION)
|
if (version && version < SCRUBBER_VERSION)
|
||||||
@ -115,7 +126,6 @@ bool Scrub(const char* filename, CompressCB callback, void* arg)
|
|||||||
}
|
}
|
||||||
else if (version)
|
else if (version)
|
||||||
{
|
{
|
||||||
callback("DiscScrubber: This disc is already scrubbed", 0, arg);
|
|
||||||
NOTICE_LOG(DISCIO, "%s is already scrubbed, skipping...", filename);
|
NOTICE_LOG(DISCIO, "%s is already scrubbed, skipping...", filename);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
@ -132,75 +142,53 @@ bool Scrub(const char* filename, CompressCB callback, void* arg)
|
|||||||
// Table of free blocks
|
// Table of free blocks
|
||||||
m_FreeTable = new u8[numClusters];
|
m_FreeTable = new u8[numClusters];
|
||||||
std::fill(m_FreeTable, m_FreeTable + numClusters, 1);
|
std::fill(m_FreeTable, m_FreeTable + numClusters, 1);
|
||||||
// Fill the dummy all 1 block
|
|
||||||
m_Sector1 = new u8[CLUSTER_SIZE];
|
|
||||||
std::fill(m_Sector1, m_Sector1 + CLUSTER_SIZE, 0xFF);
|
|
||||||
|
|
||||||
// Fill out table of free blocks
|
// Fill out table of free blocks
|
||||||
callback("DiscScrubber: Parsing...", 0, arg);
|
|
||||||
success = ParseDisc();
|
success = ParseDisc();
|
||||||
// Done with it; need it closed for the next part
|
// Done with it; need it closed for the next part
|
||||||
delete m_Disc;
|
delete m_Disc;
|
||||||
m_Disc = NULL;
|
m_Disc = NULL;
|
||||||
|
m_BlockCount = 0;
|
||||||
// Open file
|
|
||||||
FILE* pFile = fopen(filename, "r+b");
|
|
||||||
if (!pFile)
|
|
||||||
{
|
|
||||||
ERROR_LOG(DISCIO, "DiscScrubber failed to open %s", filename);
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let's not touch the file if we've failed up to here :p
|
// Let's not touch the file if we've failed up to here :p
|
||||||
if (!success)
|
if (!success)
|
||||||
goto cleanup;
|
Cleanup();
|
||||||
|
|
||||||
// Modify file, obeying the table of free blocks
|
|
||||||
NOTICE_LOG(DISCIO, "Removing garbage data...go get some coffee :)");
|
|
||||||
for (u32 i = 0; i < numClusters; i++)
|
|
||||||
{
|
|
||||||
u64 CurrentOffset = (u64)i * CLUSTER_SIZE;
|
|
||||||
|
|
||||||
if (m_FreeTable[i])
|
|
||||||
{
|
|
||||||
DEBUG_LOG(DISCIO, "Freeing 0x%016llx", CurrentOffset);
|
|
||||||
// Area is unused so fill with 1s
|
|
||||||
fseek(pFile, CurrentOffset, SEEK_SET);
|
|
||||||
success |= fwrite(m_Sector1, CLUSTER_SIZE, 1, pFile) == CLUSTER_SIZE;
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
PanicAlert("DiscScrubber failure");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DEBUG_LOG(DISCIO, "Used 0x%016llx", CurrentOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update progress dialog
|
|
||||||
if (i % (numClusters / 1000) == 0)
|
|
||||||
{
|
|
||||||
char temp[512];
|
|
||||||
sprintf(temp, "DiscScrubber: %x/%x (%s)", i, numClusters, m_FreeTable[i] ? "Free" : "Used");
|
|
||||||
callback(temp, (float)i / (float)numClusters, arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NOTICE_LOG(DISCIO, "Done removing garbage data");
|
|
||||||
|
|
||||||
if (success)
|
|
||||||
if (!MarkAsScrubbed(filename))
|
|
||||||
ERROR_LOG(DISCIO, "Really weird - failed to mark scrubbed disk as scrubbed :s");
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
if (pFile) fclose(pFile);
|
|
||||||
delete[] m_Sector1;
|
|
||||||
delete[] m_FreeTable;
|
|
||||||
|
|
||||||
|
m_isScrubbing = success;
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetNextBlock(FILE* in, u8* buffer)
|
||||||
|
{
|
||||||
|
u64 CurrentOffset = m_BlockCount * m_BlockSize;
|
||||||
|
u64 i = CurrentOffset / CLUSTER_SIZE;
|
||||||
|
|
||||||
|
if (m_isScrubbing && m_FreeTable[i])
|
||||||
|
{
|
||||||
|
DEBUG_LOG(DISCIO, "Freeing 0x%016llx", CurrentOffset);
|
||||||
|
std::fill(buffer, buffer + m_BlockSize, 0xFF);
|
||||||
|
fseek(in, m_BlockSize, SEEK_CUR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DEBUG_LOG(DISCIO, "Used 0x%016llx", CurrentOffset);
|
||||||
|
fread(buffer, m_BlockSize, 1, in);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_BlockCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cleanup()
|
||||||
|
{
|
||||||
|
if (m_FreeTable) delete[] m_FreeTable;
|
||||||
|
m_FreeTable = NULL;
|
||||||
|
m_FileSize = 0;
|
||||||
|
m_BlockCount = 0;
|
||||||
|
m_BlockSize = 0;
|
||||||
|
m_BlocksPerCluster = 0;
|
||||||
|
m_isScrubbing = false;
|
||||||
|
}
|
||||||
|
|
||||||
void MarkAsUsed(u64 _Offset, u64 _Size)
|
void MarkAsUsed(u64 _Offset, u64 _Size)
|
||||||
{
|
{
|
||||||
u64 CurrentOffset = _Offset;
|
u64 CurrentOffset = _Offset;
|
||||||
@ -233,20 +221,6 @@ void MarkAsUsedE(u64 _PartitionDataOffset, u64 _Offset, u64 _Size)
|
|||||||
MarkAsUsed(Offset, Size);
|
MarkAsUsed(Offset, Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MarkAsScrubbed(const char* filename)
|
|
||||||
{
|
|
||||||
FILE* f = fopen(filename, "r+b");
|
|
||||||
|
|
||||||
if (!f)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
u8 ScrubbedFlag[1] = {SCRUBBER_VERSION};
|
|
||||||
fseek(f, 0x80, SEEK_SET);
|
|
||||||
bool success = fwrite(ScrubbedFlag, 1, 1, f) == 1;
|
|
||||||
fclose(f);
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper functions for RAW reading the BE discs
|
// Helper functions for RAW reading the BE discs
|
||||||
void ReadFromDisc(u64 _Offset, u64 _Length, u32& _Buffer)
|
void ReadFromDisc(u64 _Offset, u64 _Length, u32& _Buffer)
|
||||||
{
|
{
|
||||||
|
@ -39,7 +39,9 @@ namespace DiscScrubber
|
|||||||
|
|
||||||
u32 IsScrubbed(const char* filename);
|
u32 IsScrubbed(const char* filename);
|
||||||
|
|
||||||
bool Scrub(const char* filename, CompressCB callback = 0, void* arg = 0);
|
bool SetupScrub(const char* filename, int block_size);
|
||||||
|
void GetNextBlock(FILE* in, u8* buffer);
|
||||||
|
void Cleanup();
|
||||||
|
|
||||||
} // namespace DiscScrubber
|
} // namespace DiscScrubber
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user