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/>.
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
#include "addresses.h"
|
|
|
|
#include "rct2.h"
|
|
|
|
#include "sawyercoding.h"
|
|
|
|
|
|
|
|
static int decode_chunk_rle(char *buffer, int length);
|
|
|
|
static int decode_chunk_repeat(char *buffer, int length);
|
|
|
|
static void decode_chunk_rotate(char *buffer, int length);
|
|
|
|
|
2014-05-04 18:34:13 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x00676FD2
|
|
|
|
*/
|
|
|
|
int sawyercoding_validate_checksum(HFILE hFile)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
uint32 checksum, fileChecksum;
|
|
|
|
DWORD dataSize, bufferSize, numBytesRead;
|
|
|
|
uint8 buffer[1024];
|
|
|
|
|
|
|
|
// Get data size
|
|
|
|
if ((dataSize = SetFilePointer(hFile, 0, NULL, FILE_END)) < 8)
|
|
|
|
return;
|
|
|
|
dataSize -= 4;
|
|
|
|
|
|
|
|
// Calculate checksum
|
|
|
|
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
|
|
|
checksum = 0;
|
|
|
|
do {
|
|
|
|
bufferSize = min(dataSize, 1024);
|
|
|
|
ReadFile(hFile, buffer, bufferSize, &numBytesRead, NULL);
|
|
|
|
if (numBytesRead != bufferSize)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < bufferSize; i++)
|
|
|
|
checksum += buffer[i];
|
|
|
|
dataSize -= bufferSize;
|
|
|
|
} while (dataSize != 0);
|
|
|
|
|
|
|
|
// Read file checksum
|
|
|
|
ReadFile(hFile, &fileChecksum, sizeof(fileChecksum), &numBytesRead, NULL);
|
|
|
|
if (numBytesRead != sizeof(fileChecksum))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Reset file position
|
|
|
|
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
|
|
|
|
|
|
|
// Validate
|
|
|
|
return checksum == fileChecksum;
|
|
|
|
}
|
|
|
|
|
2014-04-10 01:22:57 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x0067685F
|
|
|
|
* buffer (esi)
|
|
|
|
*/
|
|
|
|
int sawyercoding_read_chunk(HFILE hFile, uint8 *buffer)
|
|
|
|
{
|
|
|
|
DWORD numBytesRead;
|
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
|
|
|
|
ReadFile(hFile, &chunkHeader, sizeof(sawyercoding_chunk_header), &numBytesRead, NULL);
|
2014-04-10 01:22:57 +02:00
|
|
|
|
|
|
|
// Read chunk data
|
2014-04-10 04:23:12 +02:00
|
|
|
ReadFile(hFile, buffer, chunkHeader.length, &numBytesRead, NULL);
|
2014-04-10 01:22:57 +02:00
|
|
|
|
|
|
|
// Decode chunk data
|
2014-04-10 04:23:12 +02:00
|
|
|
switch (chunkHeader.encoding) {
|
2014-04-10 01:22:57 +02:00
|
|
|
case CHUNK_ENCODING_RLE:
|
2014-04-10 04:23:12 +02:00
|
|
|
chunkHeader.length = decode_chunk_rle(buffer, chunkHeader.length);
|
2014-04-10 01:22:57 +02:00
|
|
|
break;
|
|
|
|
case CHUNK_ENCODING_RLECOMPRESSED:
|
2014-04-10 04:23:12 +02:00
|
|
|
chunkHeader.length = decode_chunk_rle(buffer, chunkHeader.length);
|
|
|
|
chunkHeader.length = decode_chunk_repeat(buffer, chunkHeader.length);
|
2014-04-10 01:22:57 +02:00
|
|
|
break;
|
|
|
|
case CHUNK_ENCODING_ROTATE:
|
2014-04-10 04:23:12 +02:00
|
|
|
decode_chunk_rotate(buffer, chunkHeader.length);
|
2014-04-10 01:22:57 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x0067693A
|
|
|
|
*/
|
|
|
|
static int decode_chunk_rle(char *buffer, int length)
|
|
|
|
{
|
|
|
|
int i, j, count;
|
|
|
|
uint8 *src, *dst, rleCodeByte;
|
|
|
|
|
|
|
|
// Backup buffer
|
|
|
|
src = malloc(length);
|
|
|
|
memcpy(src, buffer, length);
|
|
|
|
dst = buffer;
|
|
|
|
|
|
|
|
for (i = 0; i < length; i++) {
|
|
|
|
rleCodeByte = src[i];
|
|
|
|
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++)
|
|
|
|
*dst++ = src[i];
|
|
|
|
} else {
|
2014-04-10 18:08:41 +02:00
|
|
|
for (j = 0; j <= rleCodeByte; j++)
|
2014-04-10 01:22:57 +02:00
|
|
|
*dst++ = src[++i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free backup buffer
|
|
|
|
free(src);
|
|
|
|
|
|
|
|
// Return final size
|
|
|
|
return dst - buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006769F1
|
|
|
|
*/
|
|
|
|
static int decode_chunk_repeat(char *buffer, int length)
|
|
|
|
{
|
|
|
|
int i, j, count;
|
|
|
|
uint8 *src, *dst, *copyOffset, rleCodeByte;
|
|
|
|
|
|
|
|
// 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
|
|
|
|
return dst - buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* 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
|
|
|
}
|