Skip to content

Commit

Permalink
filter-ddave-rle: Prevent RLE codes from running across 65,280 byte b…
Browse files Browse the repository at this point in the history
…oundaries

This fixes the graphical corruption that comes from recompressing the tileset,
even if there are no changes.
  • Loading branch information
Malvineous committed Oct 31, 2015
1 parent ceeb15e commit ab095e6
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 9 deletions.
7 changes: 0 additions & 7 deletions BUGS
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,3 @@ Known bugs
return a filename-too-long error when the filename would actually fit due to
the fake extension being removed. However the likelihood of this seems
remote, so it is unlikely to be fixed.

- Extracting and reinserting vgadave.dav into dave.exe results in very obvious
graphical corruption. This is because the Camoto compressor is slightly more
efficient than the original one, so the recompressed file is a few bytes
smaller. Because the file size cannot be set (or it is not known how), this
means there are some trailing bytes at the end of the data which the game
tries to decompress, which causes it to overwrite parts of memory.
21 changes: 19 additions & 2 deletions src/filter-ddave-rle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
#include "filter-ddave-rle.hpp"
#include "filter-decomp-size.hpp"

/// RLE codes must not cross this boundary (almost one 16-bit memory segment)
const unsigned long SPLIT_BOUNDARY = 0xFF00;

namespace camoto {
namespace gamearchive {

Expand Down Expand Up @@ -92,6 +95,7 @@ void filter_ddave_rle::reset(stream::len lenInput)
this->prev = 0;
this->count = 0;
this->step = 0;
this->total_read = 0;
return;
}

Expand Down Expand Up @@ -123,14 +127,29 @@ void filter_ddave_rle::transform(uint8_t *out, stream::len *lenOut,
case 0:
this->prev = *in++;
r++;
this->total_read++;
this->count = 1;
step = 10;
break;
case 10:
if (
(this->total_read > 0)
&& ((this->total_read % SPLIT_BOUNDARY) == 0)
) {
// Have to break any RLE code at this boundary
if (this->buflen) {
// Write out the buffer as escape data
step = 50;
} else {
// Flush the RLE codes by faking a change in character
step = 11;
}
}
if (*in == this->prev) {
this->count++;
in++;
r++;
this->total_read++;
if (this->count == 130) {
// If we've reached the maximum repeat amount, write out a code
*out++ = '\x7F';
Expand All @@ -139,8 +158,6 @@ void filter_ddave_rle::transform(uint8_t *out, stream::len *lenOut,
} else if ((count == 3) && (this->buflen)) {
// If we've reached the point where it is worth writing out the
// repeat code (eventually), flush the buffer now
//*out++ = (uint8_t)(0x80 + this->buflen - 1);
//w++;
step = 50;
}
break;
Expand Down
1 change: 1 addition & 0 deletions src/filter-ddave-rle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class filter_ddave_rle: virtual public filter
uint8_t prev; ///< Previous byte read
unsigned int count; ///< How many prev has been seen so far
unsigned int step; ///< Which point in the algorithm are we up to?
unsigned int total_read; ///< Total number of cleartext bytes read

public:
virtual void reset(stream::len lenInput);
Expand Down

0 comments on commit ab095e6

Please sign in to comment.