implement RLECOMPRESSED chunk encoding, closes #598

This commit is contained in:
IntelOrca 2014-11-26 16:27:21 +00:00
parent 4b897ae1a3
commit 85c41488ce
5 changed files with 171 additions and 102 deletions

View File

@ -12,7 +12,6 @@
<LocalDebuggerCommand>$(TargetDir)\openrct2.exe</LocalDebuggerCommand>
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommandArguments>
</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>"C:\Program Files (x86)\Infogrames\RollerCoaster Tycoon 2\Saved Games\savetest.SV6"</LocalDebuggerCommandArguments>
</PropertyGroup>
</Project>

View File

@ -48,7 +48,7 @@ static const char *const usage[] = {
* will then terminate before any initialisation has even been done.
* @returns 1 if the game should run, otherwise 0.
*/
int cmdline_run(char *argv[], int argc)
int cmdline_run(const char **argv, int argc)
{
// For argparse's sake, add virtual first argument process path
argc++;

View File

@ -26,6 +26,6 @@
/** The exit code for OpenRCT2 when it exits. */
extern int gExitCode;
int cmdline_run(char *argv[], int argc);
int cmdline_run(const char **argv, int argc);
#endif

View File

@ -218,6 +218,7 @@ int rct2_open_file(const char *path)
extension++;
if (_stricmp(extension, "sv6") == 0) {
strcpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, path);
game_load_save(path);
return 1;
} else if (_stricmp(extension, "sc6") == 0) {

View File

@ -27,8 +27,9 @@ static int decode_chunk_rle(uint8* src_buffer, uint8* dst_buffer, int length);
static int decode_chunk_repeat(char *buffer, int length);
static void decode_chunk_rotate(char *buffer, int length);
int encode_chunk_rle(char *src_buffer, char *dst_buffer, int length);
void encode_chunk_rotate(char *buffer, int length);
static int encode_chunk_rle(char *src_buffer, char *dst_buffer, int length);
static int encode_chunk_repeat(char *src_buffer, char *dst_buffer, int length);
static void encode_chunk_rotate(char *buffer, int length);
uint32 sawyercoding_calculate_checksum(uint8* buffer, uint32 length)
{
@ -79,7 +80,6 @@ int sawyercoding_validate_checksum(FILE *file)
return checksum == fileChecksum;
}
/**
*
* rct2: 0x0067685F
@ -127,6 +127,104 @@ int sawyercoding_read_chunk(FILE *file, uint8 *buffer)
return chunkHeader.length;
}
/**
*
* rct2: 0x006762E1
*
*/
int sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding_chunk_header chunkHeader){
uint8 *encode_buffer, *encode_buffer2;
switch (chunkHeader.encoding){
case CHUNK_ENCODING_NONE:
memcpy(dst_file, &chunkHeader, sizeof(sawyercoding_chunk_header));
dst_file += sizeof(sawyercoding_chunk_header);
memcpy(dst_file, buffer, chunkHeader.length);
//fwrite(&chunkHeader, sizeof(sawyercoding_chunk_header), 1, file);
//fwrite(buffer, 1, chunkHeader.length, file);
break;
case CHUNK_ENCODING_RLE:
encode_buffer = malloc(0x600000);
chunkHeader.length = encode_chunk_rle(buffer, encode_buffer, chunkHeader.length);
memcpy(dst_file, &chunkHeader, sizeof(sawyercoding_chunk_header));
dst_file += sizeof(sawyercoding_chunk_header);
memcpy(dst_file, encode_buffer, chunkHeader.length);
free(encode_buffer);
break;
case CHUNK_ENCODING_RLECOMPRESSED:
encode_buffer = malloc(chunkHeader.length * 2);
encode_buffer2 = malloc(0x600000);
chunkHeader.length = encode_chunk_repeat(buffer, encode_buffer, chunkHeader.length);
chunkHeader.length = encode_chunk_rle(encode_buffer, encode_buffer2, chunkHeader.length);
memcpy(dst_file, &chunkHeader, sizeof(sawyercoding_chunk_header));
dst_file += sizeof(sawyercoding_chunk_header);
memcpy(dst_file, encode_buffer2, chunkHeader.length);
free(encode_buffer2);
free(encode_buffer);
break;
case CHUNK_ENCODING_ROTATE:
encode_chunk_rotate(buffer, chunkHeader.length);
memcpy(dst_file, &chunkHeader, sizeof(sawyercoding_chunk_header));
dst_file += sizeof(sawyercoding_chunk_header);
memcpy(dst_file, buffer, chunkHeader.length);
break;
}
return chunkHeader.length + sizeof(sawyercoding_chunk_header);
}
int sawyercoding_decode_sv4(char *src, char *dst, int length)
{
// (0 to length - 4): RLE chunk
// (length - 4 to length): checksum
return decode_chunk_rle(src, dst, length - 4);
}
int sawyercoding_decode_sc4(char *src, char *dst, int length)
{
int decodedLength, i;
uint32 *code;
// Uncompress
decodedLength = decode_chunk_rle(src, dst, length - 4);
// Decode
for (i = 0x60018; i <= min(decodedLength - 1, 0x1F8353); i++)
dst[i] = dst[i] ^ 0x9C;
for (i = 0x60018; i <= min(decodedLength - 1, 0x1F8350); i += 4) {
dst[i + 1] = ror8(dst[i + 1], 3);
code = (uint32*)&dst[i];
*code = rol32(*code, 9);
}
return decodedLength;
}
int sawyercoding_encode_sv4(char *src, char *dst, int length)
{
int encodedLength, checksum;
// Encode
encodedLength = encode_chunk_rle(src, dst, length);
// Append checksum
checksum = sawyercoding_calculate_checksum(dst, encodedLength);
*((uint32*)&dst[encodedLength]) = checksum;
return encodedLength + 4;
}
int sawyercoding_decode_td6(char *src, char *dst, int length)
{
return decode_chunk_rle(src, dst, length - 4);
}
#pragma region Decoding
/**
*
* rct2: 0x0067693A
@ -200,52 +298,15 @@ static void decode_chunk_rotate(char *buffer, int length)
}
}
/**
*
* rct2: 0x006762E1
*
*/
int sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding_chunk_header chunkHeader){
uint8* encode_buffer;
#pragma endregion
switch (chunkHeader.encoding){
case CHUNK_ENCODING_NONE:
memcpy(dst_file, &chunkHeader, sizeof(sawyercoding_chunk_header));
dst_file += sizeof(sawyercoding_chunk_header);
memcpy(dst_file, buffer, chunkHeader.length);
//fwrite(&chunkHeader, sizeof(sawyercoding_chunk_header), 1, file);
//fwrite(buffer, 1, chunkHeader.length, file);
break;
case CHUNK_ENCODING_RLE:
encode_buffer = malloc(0x600000);
chunkHeader.length = encode_chunk_rle(buffer, encode_buffer, chunkHeader.length);
memcpy(dst_file, &chunkHeader, sizeof(sawyercoding_chunk_header));
dst_file += sizeof(sawyercoding_chunk_header);
memcpy(dst_file, encode_buffer, chunkHeader.length);
free(encode_buffer);
break;
case CHUNK_ENCODING_RLECOMPRESSED:
log_warning("RLECOMPRESSED encoding has not been implemented, using CHUNK_ENCODING_RLE instead.");
chunkHeader.encoding = CHUNK_ENCODING_RLE;
return sawyercoding_write_chunk_buffer(dst_file, buffer, chunkHeader);
break;
case CHUNK_ENCODING_ROTATE:
encode_chunk_rotate(buffer, chunkHeader.length);
memcpy(dst_file, &chunkHeader, sizeof(sawyercoding_chunk_header));
dst_file += sizeof(sawyercoding_chunk_header);
memcpy(dst_file, buffer, chunkHeader.length);
break;
}
return chunkHeader.length + sizeof(sawyercoding_chunk_header);
}
#pragma region Encoding
/**
* Ensure dst_buffer is bigger than src_buffer then resize afterwards
* returns length of dst_buffer
*/
int encode_chunk_rle(char *src_buffer, char *dst_buffer, int length)
* Ensure dst_buffer is bigger than src_buffer then resize afterwards
* returns length of dst_buffer
*/
static int encode_chunk_rle(char *src_buffer, char *dst_buffer, int length)
{
char* src = src_buffer;
char* dst = dst_buffer;
@ -286,11 +347,65 @@ int encode_chunk_rle(char *src_buffer, char *dst_buffer, int length)
return dst - dst_buffer;
}
/**
*
*
*/
void encode_chunk_rotate(char *buffer, int length)
static int encode_chunk_repeat(char *src_buffer, char *dst_buffer, int length)
{
int i, j, outLength;
int searchIndex, searchEnd, searchCount, maxRepeatCount;
int bestRepeatIndex, bestRepeatCount, repeatIndex, repeatCount;
if (length == 0)
return 0;
outLength = 0;
// Need to emit at least one byte, otherwise there is nothing to repeat
*dst_buffer++ = 255;
*dst_buffer++ = src_buffer[0];
outLength += 2;
// Itereate through remainder of the source buffer
for (i = 1; i < length; ) {
searchIndex = max(0, i - 32);
searchEnd = i - 1;
searchCount = i - searchIndex;
bestRepeatCount = 0;
for (repeatIndex = searchIndex; repeatIndex <= searchEnd; repeatIndex++) {
repeatCount = 0;
maxRepeatCount = min(7, searchEnd - repeatIndex);
for (j = 0; j <= maxRepeatCount; j++) {
if (src_buffer[repeatIndex + j] == src_buffer[i + j]) {
repeatCount++;
} else {
break;
}
}
if (repeatCount > bestRepeatCount) {
bestRepeatIndex = repeatIndex;
bestRepeatCount = repeatCount;
// Maximum repeat count is 8
if (repeatCount == 8)
break;
}
}
if (bestRepeatCount == 0) {
*dst_buffer++ = 255;
*dst_buffer++ = src_buffer[i];
outLength += 2;
i++;
} else {
*dst_buffer++ = (bestRepeatCount - 1) | ((32 - (i - bestRepeatIndex)) << 3);
outLength++;
i += bestRepeatCount;
}
}
return outLength;
}
static void encode_chunk_rotate(char *buffer, int length)
{
int i, code = 1;
for (i = 0; i < length; i++) {
@ -299,50 +414,4 @@ void encode_chunk_rotate(char *buffer, int length)
}
}
int sawyercoding_decode_sv4(char *src, char *dst, int length)
{
// (0 to length - 4): RLE chunk
// (length - 4 to length): checksum
return decode_chunk_rle(src, dst, length - 4);
}
int sawyercoding_decode_sc4(char *src, char *dst, int length)
{
int decodedLength, i;
uint32 *code;
// Uncompress
decodedLength = decode_chunk_rle(src, dst, length - 4);
// Decode
for (i = 0x60018; i <= min(decodedLength - 1, 0x1F8353); i++)
dst[i] = dst[i] ^ 0x9C;
for (i = 0x60018; i <= min(decodedLength - 1, 0x1F8350); i += 4) {
dst[i + 1] = ror8(dst[i + 1], 3);
code = (uint32*)&dst[i];
*code = rol32(*code, 9);
}
return decodedLength;
}
int sawyercoding_encode_sv4(char *src, char *dst, int length)
{
int encodedLength, checksum;
// Encode
encodedLength = encode_chunk_rle(src, dst, length);
// Append checksum
checksum = sawyercoding_calculate_checksum(dst, encodedLength);
*((uint32*)&dst[encodedLength]) = checksum;
return encodedLength + 4;
}
int sawyercoding_decode_td6(char *src, char *dst, int length)
{
return decode_chunk_rle(src, dst, length - 4);
}
#pragma endregion