From 66de066901835271f8f6fe4e9e8282579ab48c44 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Tue, 28 Apr 2015 20:29:03 +0100 Subject: [PATCH] Added save_track_file. Fixed bugs. Encountered bug where incorrect tracks would be displayed if the loading process failed. Added checksum validation to loading code. Increased the max rle length to match rct2. --- src/ride/track.c | 39 ++++++++++++++++++++++++++++++++++----- src/util/sawyercoding.c | 41 +++++++++++++++++++++++++++++++++++++++-- src/util/sawyercoding.h | 2 ++ 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index 83b8110db2..62d3de6608 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -508,7 +508,10 @@ rct_track_td6* load_track_design(const char *path) // Validate the checksum // Not the same checksum algorithm as scenarios and saved games - // sub_6770C1(); + if (!sawyercoding_validate_track_checksum(fpBuffer, fpLength)){ + log_error("Track checksum failed."); + return 0; + } // Decode the track data decoded = malloc(0x10000); @@ -1055,6 +1058,8 @@ rct_track_design *track_get_info(int index, uint8** preview) if (!(loaded_track = load_track_design(track_path))) { if (preview != NULL) *preview = NULL; + // Mark cache as empty. + RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, uint32)[i] = 0; log_error("Failed to load track: %s", trackDesignList + (index * 128)); return NULL; } @@ -1790,6 +1795,33 @@ int ride_to_td6(uint8 rideIndex){ return tracked_ride_to_td6(rideIndex, track_design, track_elements); } +/* rct2: 0x006771DC but not really its branched from that + * quite far. + */ +int save_track_to_file(rct_track_td6* track_design, char* path){ + window_close_construction_windows(); + + uint8* track_file = malloc(0x8000); + + int length = sawyercoding_encode_td6((char*)track_design, track_file, 0x609F); + + FILE *file; + + log_verbose("saving track %s", path); + file = fopen(path, "wb"); + if (file == NULL) { + free(track_file); + log_error("Failed to save %s", path); + return 0; + } + + fwrite(track_file, length, 1, file); + fclose(file); + free(track_file); + + return 1; +} + /* rct2: 0x006D2804 & 0x006D264D */ int save_track_design(uint8 rideIndex){ rct_ride* ride = GET_RIDE(rideIndex); @@ -1859,10 +1891,7 @@ int save_track_design(uint8 rideIndex){ return 1; } - // Until 0x006771DC is finished we required to copy the path name. - strcpy(RCT2_ADDRESS(0x141EF68, char), path); - // This is the function that actually saves the track to a file - RCT2_CALLPROC_EBPSAFE(0x006771DC); + save_track_to_file(RCT2_ADDRESS(0x009D8178, rct_track_td6), path); ride_list_item item = { .type = 0xFC, .entry_index = 0 }; track_load_list(item); diff --git a/src/util/sawyercoding.c b/src/util/sawyercoding.c index 1388085d32..4caa61697d 100644 --- a/src/util/sawyercoding.c +++ b/src/util/sawyercoding.c @@ -225,6 +225,43 @@ int sawyercoding_decode_td6(char *src, char *dst, int length) return decode_chunk_rle(src, dst, length - 4); } +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; +} + #pragma region Decoding /** @@ -318,14 +355,14 @@ static int encode_chunk_rle(char *src_buffer, char *dst_buffer, int length) while (src < end_src - 1){ - if ((count && *src == src[1]) || count > 120){ + if ((count && *src == src[1]) || count > 125){ *dst++ = count - 1; for (; count != 0; --count){ *dst++ = *src_norm_start++; } } if (*src == src[1]){ - for (; (count < 120) && ((src + count) < end_src); count++){ + for (; (count < 125) && ((src + count) < end_src); count++){ if (*src != src[count]) break; } *dst++ = 257 - count; diff --git a/src/util/sawyercoding.h b/src/util/sawyercoding.h index f05727180f..a1c702b334 100644 --- a/src/util/sawyercoding.h +++ b/src/util/sawyercoding.h @@ -55,6 +55,8 @@ int sawyercoding_decode_sv4(char *src, char *dst, int length); int sawyercoding_decode_sc4(char *src, char *dst, int length); int sawyercoding_encode_sv4(char *src, char *dst, int length); int sawyercoding_decode_td6(char *src, char *dst, int length); +int sawyercoding_encode_td6(char* src, char* dst, int length); +int sawyercoding_validate_track_checksum(char* src, int length); int sawyercoding_detect_file_type(char *src, int length);