2014-04-10 01:22:57 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* Copyright (c) 2014 Ted John
|
|
|
|
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
|
|
|
*
|
|
|
|
* This file is part of OpenRCT2.
|
|
|
|
*
|
|
|
|
* OpenRCT2 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2014-10-06 18:36:58 +02:00
|
|
|
#include "../addresses.h"
|
2014-04-10 01:22:57 +02:00
|
|
|
#include "sawyercoding.h"
|
|
|
|
|
2014-09-29 13:43:12 +02:00
|
|
|
static int decode_chunk_rle(uint8* src_buffer, uint8* dst_buffer, int length);
|
2014-04-10 01:22:57 +02:00
|
|
|
static int decode_chunk_repeat(char *buffer, int length);
|
|
|
|
static void decode_chunk_rotate(char *buffer, int length);
|
|
|
|
|
2014-11-26 17:27:21 +01:00
|
|
|
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);
|
2014-10-04 12:41:16 +02:00
|
|
|
|
2014-11-26 01:51:26 +01:00
|
|
|
uint32 sawyercoding_calculate_checksum(uint8* buffer, uint32 length)
|
|
|
|
{
|
|
|
|
uint32 i, checksum = 0;
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
checksum += buffer[i];
|
2014-10-04 12:41:16 +02:00
|
|
|
|
|
|
|
return checksum;
|
|
|
|
}
|
|
|
|
|
2014-05-04 18:34:13 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x00676FD2
|
|
|
|
*/
|
2014-05-24 23:14:42 +02:00
|
|
|
int sawyercoding_validate_checksum(FILE *file)
|
2014-05-04 18:34:13 +02:00
|
|
|
{
|
2014-05-24 23:14:42 +02:00
|
|
|
uint32 i, checksum, fileChecksum, dataSize, bufferSize;
|
2014-05-04 18:34:13 +02:00
|
|
|
uint8 buffer[1024];
|
|
|
|
|
|
|
|
// Get data size
|
2014-05-24 23:14:42 +02:00
|
|
|
fseek(file, 0, SEEK_END);
|
|
|
|
dataSize = ftell(file);
|
|
|
|
if (dataSize < 8)
|
2014-05-12 02:45:45 +02:00
|
|
|
return 0;
|
2014-05-04 18:34:13 +02:00
|
|
|
dataSize -= 4;
|
|
|
|
|
|
|
|
// Calculate checksum
|
2014-05-24 23:14:42 +02:00
|
|
|
fseek(file, 0, SEEK_SET);
|
2014-05-04 18:34:13 +02:00
|
|
|
checksum = 0;
|
|
|
|
do {
|
|
|
|
bufferSize = min(dataSize, 1024);
|
2014-05-24 23:14:42 +02:00
|
|
|
if (fread(buffer, bufferSize, 1, file) != 1)
|
2014-05-04 18:34:13 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < bufferSize; i++)
|
|
|
|
checksum += buffer[i];
|
|
|
|
dataSize -= bufferSize;
|
|
|
|
} while (dataSize != 0);
|
|
|
|
|
|
|
|
// Read file checksum
|
2014-05-24 23:14:42 +02:00
|
|
|
if (fread(&fileChecksum, sizeof(fileChecksum), 1, file) != 1)
|
2014-05-04 18:34:13 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Reset file position
|
2014-05-24 23:14:42 +02:00
|
|
|
fseek(file, 0, SEEK_SET);
|
2014-05-04 18:34:13 +02:00
|
|
|
|
|
|
|
// Validate
|
|
|
|
return checksum == fileChecksum;
|
|
|
|
}
|
|
|
|
|
2014-04-10 01:22:57 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x0067685F
|
|
|
|
* buffer (esi)
|
|
|
|
*/
|
2014-05-24 23:14:42 +02:00
|
|
|
int sawyercoding_read_chunk(FILE *file, uint8 *buffer)
|
2014-04-10 01:22:57 +02:00
|
|
|
{
|
2014-04-10 04:23:12 +02:00
|
|
|
sawyercoding_chunk_header chunkHeader;
|
2014-04-10 01:22:57 +02:00
|
|
|
|
2014-04-10 04:23:12 +02:00
|
|
|
// Read chunk header
|
2014-05-24 23:14:42 +02:00
|
|
|
if (fread(&chunkHeader, sizeof(sawyercoding_chunk_header), 1, file) != 1) {
|
2015-06-14 13:03:32 +02:00
|
|
|
log_error("Unable to read chunk header!");
|
2014-05-24 23:14:42 +02:00
|
|
|
return -1;
|
2014-05-21 00:07:57 +02:00
|
|
|
}
|
2014-04-10 01:22:57 +02:00
|
|
|
|
2014-09-29 13:43:12 +02:00
|
|
|
uint8* src_buffer = malloc(chunkHeader.length);
|
|
|
|
|
2014-04-10 01:22:57 +02:00
|
|
|
// Read chunk data
|
2014-09-29 13:43:12 +02:00
|
|
|
if (fread(src_buffer, chunkHeader.length, 1, file) != 1) {
|
|
|
|
free(src_buffer);
|
2015-06-14 13:03:32 +02:00
|
|
|
log_error("Unable to read chunk data!");
|
2014-05-24 23:14:42 +02:00
|
|
|
return -1;
|
2014-05-21 00:07:57 +02:00
|
|
|
}
|
2014-04-10 01:22:57 +02:00
|
|
|
|
|
|
|
// Decode chunk data
|
2014-04-10 04:23:12 +02:00
|
|
|
switch (chunkHeader.encoding) {
|
2014-09-29 13:43:12 +02:00
|
|
|
case CHUNK_ENCODING_NONE:
|
|
|
|
memcpy(buffer, src_buffer, chunkHeader.length);
|
|
|
|
break;
|
2014-04-10 01:22:57 +02:00
|
|
|
case CHUNK_ENCODING_RLE:
|
2014-09-29 13:43:12 +02:00
|
|
|
chunkHeader.length = decode_chunk_rle(src_buffer, buffer, chunkHeader.length);
|
2014-04-10 01:22:57 +02:00
|
|
|
break;
|
|
|
|
case CHUNK_ENCODING_RLECOMPRESSED:
|
2014-09-29 13:43:12 +02:00
|
|
|
chunkHeader.length = decode_chunk_rle(src_buffer, buffer, chunkHeader.length);
|
2014-04-10 04:23:12 +02:00
|
|
|
chunkHeader.length = decode_chunk_repeat(buffer, chunkHeader.length);
|
2014-04-10 01:22:57 +02:00
|
|
|
break;
|
|
|
|
case CHUNK_ENCODING_ROTATE:
|
2014-09-29 13:43:12 +02:00
|
|
|
memcpy(buffer, src_buffer, chunkHeader.length);
|
2014-04-10 04:23:12 +02:00
|
|
|
decode_chunk_rotate(buffer, chunkHeader.length);
|
2014-04-10 01:22:57 +02:00
|
|
|
break;
|
|
|
|
}
|
2014-09-29 13:43:12 +02:00
|
|
|
free(src_buffer);
|
2014-04-10 01:22:57 +02:00
|
|
|
// Set length
|
2014-04-10 04:23:12 +02:00
|
|
|
RCT2_GLOBAL(0x009E3828, uint32) = chunkHeader.length;
|
|
|
|
return chunkHeader.length;
|
2014-04-10 01:22:57 +02:00
|
|
|
}
|
|
|
|
|
2014-11-26 17:27:21 +01:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* 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:
|
2015-02-28 00:42:51 +01:00
|
|
|
encode_buffer = malloc(chunkHeader.length);
|
|
|
|
memcpy(encode_buffer, buffer, chunkHeader.length);
|
|
|
|
encode_chunk_rotate(encode_buffer, chunkHeader.length);
|
2014-11-26 17:27:21 +01:00
|
|
|
memcpy(dst_file, &chunkHeader, sizeof(sawyercoding_chunk_header));
|
|
|
|
dst_file += sizeof(sawyercoding_chunk_header);
|
2015-02-28 00:42:51 +01:00
|
|
|
memcpy(dst_file, encode_buffer, chunkHeader.length);
|
|
|
|
|
|
|
|
free(encode_buffer);
|
2014-11-26 17:27:21 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-04-28 21:29:03 +02:00
|
|
|
int sawyercoding_encode_td6(char* src, char* dst, int length){
|
|
|
|
int output_length = encode_chunk_rle(src, dst, length);
|
|
|
|
|
|
|
|
uint32 checksum = 0;
|
|
|
|
for (int i = 0; i < output_length; i++){
|
|
|
|
uint8 new_byte = ((checksum & 0xFF) + dst[i]) & 0xFF;
|
|
|
|
checksum = (checksum & 0xFFFFFF00) + new_byte;
|
|
|
|
checksum = rol32(checksum, 3);
|
|
|
|
}
|
|
|
|
checksum -= 0x1D4C1;
|
|
|
|
|
|
|
|
*((uint32*)&dst[output_length]) = checksum;
|
|
|
|
output_length += 4;
|
|
|
|
return output_length;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Based off of rct2: 0x006770C1 */
|
|
|
|
int sawyercoding_validate_track_checksum(char* src, int length){
|
|
|
|
uint32 file_checksum = *((uint32*)&src[length - 4]);
|
|
|
|
|
|
|
|
uint32 checksum = 0;
|
|
|
|
for (int i = 0; i < length - 4; i++){
|
|
|
|
uint8 new_byte = ((checksum & 0xFF) + src[i]) & 0xFF;
|
|
|
|
checksum = (checksum & 0xFFFFFF00) + new_byte;
|
|
|
|
checksum = rol32(checksum, 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (checksum - 0x1D4C1 == file_checksum)
|
|
|
|
return 1; // .TD6
|
|
|
|
else if (checksum - 0x1A67C == file_checksum)
|
|
|
|
return 1; // .TD4
|
|
|
|
else if (checksum - 0x1A650 == file_checksum)
|
|
|
|
return 1; // .TD4
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-26 17:27:21 +01:00
|
|
|
#pragma region Decoding
|
|
|
|
|
2014-04-10 01:22:57 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x0067693A
|
|
|
|
*/
|
2014-09-29 13:43:12 +02:00
|
|
|
static int decode_chunk_rle(uint8* src_buffer, uint8* dst_buffer, int length)
|
2014-04-10 01:22:57 +02:00
|
|
|
{
|
|
|
|
int i, j, count;
|
2014-09-29 13:43:12 +02:00
|
|
|
uint8 *dst, rleCodeByte;
|
2014-04-10 01:22:57 +02:00
|
|
|
|
2014-09-29 13:43:12 +02:00
|
|
|
dst = dst_buffer;
|
2014-04-10 01:22:57 +02:00
|
|
|
|
|
|
|
for (i = 0; i < length; i++) {
|
2014-09-29 13:43:12 +02:00
|
|
|
rleCodeByte = src_buffer[i];
|
2014-04-10 01:22:57 +02:00
|
|
|
if (rleCodeByte & 128) {
|
|
|
|
i++;
|
2014-04-10 18:08:41 +02:00
|
|
|
count = 257 - rleCodeByte;
|
2014-04-10 01:22:57 +02:00
|
|
|
for (j = 0; j < count; j++)
|
2014-09-29 13:43:12 +02:00
|
|
|
*dst++ = src_buffer[i];
|
2014-04-10 01:22:57 +02:00
|
|
|
} else {
|
2014-04-10 18:08:41 +02:00
|
|
|
for (j = 0; j <= rleCodeByte; j++)
|
2014-09-29 13:43:12 +02:00
|
|
|
*dst++ = src_buffer[++i];
|
2014-04-10 01:22:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return final size
|
2014-09-29 20:07:25 +02:00
|
|
|
return dst - dst_buffer;
|
2014-04-10 01:22:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006769F1
|
|
|
|
*/
|
|
|
|
static int decode_chunk_repeat(char *buffer, int length)
|
|
|
|
{
|
|
|
|
int i, j, count;
|
2014-05-21 00:07:57 +02:00
|
|
|
unsigned char *src, *dst, *copyOffset;
|
2014-04-10 01:22:57 +02:00
|
|
|
|
|
|
|
// Backup buffer
|
|
|
|
src = malloc(length);
|
|
|
|
memcpy(src, buffer, length);
|
|
|
|
dst = buffer;
|
|
|
|
|
|
|
|
for (i = 0; i < length; i++) {
|
|
|
|
if (src[i] == 0xFF) {
|
|
|
|
*dst++ = src[++i];
|
|
|
|
} else {
|
2014-04-10 18:08:41 +02:00
|
|
|
count = (src[i] & 7) + 1;
|
2014-04-10 01:22:57 +02:00
|
|
|
copyOffset = dst + (int)(src[i] >> 3) - 32;
|
|
|
|
for (j = 0; j < count; j++)
|
|
|
|
*dst++ = *copyOffset++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free backup buffer
|
|
|
|
free(src);
|
|
|
|
|
|
|
|
// Return final size
|
2014-05-21 00:07:57 +02:00
|
|
|
return (char*)dst - buffer;
|
2014-04-10 01:22:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006768F4
|
|
|
|
*/
|
|
|
|
static void decode_chunk_rotate(char *buffer, int length)
|
|
|
|
{
|
|
|
|
int i, code = 1;
|
|
|
|
for (i = 0; i < length; i++) {
|
|
|
|
buffer[i] = ror8(buffer[i], code);
|
|
|
|
code = (code + 2) % 8;
|
|
|
|
}
|
2014-04-21 11:27:48 +02:00
|
|
|
}
|
2014-10-01 22:49:37 +02:00
|
|
|
|
2014-11-26 17:27:21 +01:00
|
|
|
#pragma endregion
|
2014-10-04 12:41:16 +02:00
|
|
|
|
2014-11-26 17:27:21 +01:00
|
|
|
#pragma region Encoding
|
2014-10-03 21:07:21 +02:00
|
|
|
|
|
|
|
/**
|
2014-11-26 17:27:21 +01:00
|
|
|
* 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)
|
2014-10-03 21:07:21 +02:00
|
|
|
{
|
|
|
|
char* src = src_buffer;
|
|
|
|
char* dst = dst_buffer;
|
|
|
|
char* end_src = src + length;
|
|
|
|
uint8 count = 0;
|
|
|
|
char* src_norm_start = src;
|
|
|
|
|
|
|
|
while (src < end_src - 1){
|
|
|
|
|
2015-04-28 21:29:03 +02:00
|
|
|
if ((count && *src == src[1]) || count > 125){
|
2014-10-04 12:41:16 +02:00
|
|
|
*dst++ = count - 1;
|
2014-10-03 21:07:21 +02:00
|
|
|
for (; count != 0; --count){
|
|
|
|
*dst++ = *src_norm_start++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (*src == src[1]){
|
2015-04-28 21:29:03 +02:00
|
|
|
for (; (count < 125) && ((src + count) < end_src); count++){
|
2014-10-03 21:07:21 +02:00
|
|
|
if (*src != src[count]) break;
|
|
|
|
}
|
|
|
|
*dst++ = 257 - count;
|
|
|
|
*dst++ = *src;
|
|
|
|
src += count;
|
|
|
|
src_norm_start = src;
|
|
|
|
count = 0;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
count++;
|
|
|
|
src++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (src == end_src - 1)count++;
|
|
|
|
if (count){
|
2014-10-04 12:41:16 +02:00
|
|
|
*dst++ = count - 1;
|
2014-10-03 21:07:21 +02:00
|
|
|
for (; count != 0; --count){
|
|
|
|
*dst++ = *src_norm_start++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dst - dst_buffer;
|
|
|
|
}
|
|
|
|
|
2014-11-26 17:27:21 +01:00
|
|
|
static int encode_chunk_repeat(char *src_buffer, char *dst_buffer, int length)
|
2014-10-03 21:07:21 +02:00
|
|
|
{
|
2014-11-26 17:27:21 +01:00
|
|
|
int i, j, outLength;
|
2014-11-26 17:30:41 +01:00
|
|
|
int searchIndex, searchEnd, maxRepeatCount;
|
2014-11-26 17:27:21 +01:00
|
|
|
int bestRepeatIndex, bestRepeatCount, repeatIndex, repeatCount;
|
2014-10-10 23:50:22 +02:00
|
|
|
|
2014-11-26 17:27:21 +01:00
|
|
|
if (length == 0)
|
|
|
|
return 0;
|
2014-10-10 23:50:22 +02:00
|
|
|
|
2014-11-26 17:27:21 +01:00
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
2014-10-10 23:50:22 +02:00
|
|
|
|
2014-11-26 17:27:21 +01:00
|
|
|
// Maximum repeat count is 8
|
|
|
|
if (repeatCount == 8)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-10-10 23:50:22 +02:00
|
|
|
|
2014-11-26 17:27:21 +01:00
|
|
|
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;
|
|
|
|
}
|
2014-10-10 23:50:22 +02:00
|
|
|
}
|
|
|
|
|
2014-11-26 17:27:21 +01:00
|
|
|
return outLength;
|
2014-10-10 23:50:22 +02:00
|
|
|
}
|
|
|
|
|
2014-11-26 17:27:21 +01:00
|
|
|
static void encode_chunk_rotate(char *buffer, int length)
|
2014-10-10 23:50:22 +02:00
|
|
|
{
|
2014-11-26 17:27:21 +01:00
|
|
|
int i, code = 1;
|
|
|
|
for (i = 0; i < length; i++) {
|
|
|
|
buffer[i] = rol8(buffer[i], code);
|
|
|
|
code = (code + 2) % 8;
|
|
|
|
}
|
2014-10-11 02:18:08 +02:00
|
|
|
}
|
|
|
|
|
2014-11-26 17:27:21 +01:00
|
|
|
#pragma endregion
|
2015-01-20 02:04:28 +01:00
|
|
|
|
|
|
|
int sawyercoding_detect_file_type(char *src, int length)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// Currently can't detect TD4, as the checksum is the same as SC4 (need alternative method)
|
|
|
|
|
|
|
|
uint32 checksum = *((uint32*)&src[length - 4]);
|
|
|
|
uint32 actualChecksum = 0;
|
|
|
|
for (i = 0; i < length - 4; i++) {
|
|
|
|
actualChecksum = (actualChecksum & 0xFFFFFF00) | (((actualChecksum & 0xFF) + (uint8)src[i]) & 0xFF);
|
|
|
|
actualChecksum = rol32(actualChecksum, 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (checksum - actualChecksum) {
|
|
|
|
case +108156: return FILE_VERSION_RCT1 | FILE_TYPE_SV4;
|
|
|
|
case -108156: return FILE_VERSION_RCT1 | FILE_TYPE_SC4;
|
|
|
|
case +110001: return FILE_VERSION_RCT1_AA | FILE_TYPE_SV4;
|
|
|
|
case -110001: return FILE_VERSION_RCT1_AA | FILE_TYPE_SC4;
|
|
|
|
case +120001: return FILE_VERSION_RCT1_LL | FILE_TYPE_SV4;
|
|
|
|
case -120001: return FILE_VERSION_RCT1_LL | FILE_TYPE_SC4;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|