Index: core/fxcodec/codec/fx_codec.cpp |
diff --git a/core/fxcodec/codec/fx_codec.cpp b/core/fxcodec/codec/fx_codec.cpp |
index 6b6c7233880af64cac103bdd12f0597bb501d8e6..23171cf3eac31f98604bdb5ef6f4ccdb13ac911a 100644 |
--- a/core/fxcodec/codec/fx_codec.cpp |
+++ b/core/fxcodec/codec/fx_codec.cpp |
@@ -6,6 +6,7 @@ |
#include "core/fxcodec/fx_codec.h" |
+#include <algorithm> |
#include <cmath> |
#include <memory> |
#include <utility> |
@@ -101,14 +102,151 @@ bool CCodec_BasicModule::RunLengthEncode(const uint8_t* src_buf, |
uint32_t src_size, |
uint8_t** dest_buf, |
uint32_t* dest_size) { |
- return false; |
+ // Check inputs |
+ if (!src_buf || !dest_buf || !dest_size || src_size == 0) |
+ return false; |
+ |
+ // Edge case |
+ if (src_size == 1) { |
+ *dest_buf = FX_Alloc(uint8_t, 3); |
+ (*dest_buf)[0] = 0; |
+ (*dest_buf)[1] = src_buf[0]; |
+ (*dest_buf)[2] = 128; |
+ *dest_size = 3; |
+ return true; |
+ } |
+ |
+ // Worst case: 1 nonmatch, 2 match, 1 nonmatch, 2 match, etc. This becomes |
+ // 4 output chars for every 3 input, plus up to 4 more for the 1-2 chars |
+ // rounded off plus the terminating character. |
+ uint32_t est_size = 4 * ((src_size + 2) / 3) + 1; |
+ *dest_buf = FX_Alloc(uint8_t, est_size); |
+ |
+ // Set up pointers. |
+ uint8_t* out = *dest_buf; |
+ uint32_t run_start = 0; |
+ uint32_t run_end = 1; |
+ uint8_t x = src_buf[run_start]; |
+ uint8_t y = src_buf[run_end]; |
+ while (run_end < src_size) { |
+ uint32_t max_len = std::min((uint32_t)128, src_size - run_start); |
+ while (x == y && (run_end - run_start < max_len - 1)) |
+ y = src_buf[++run_end]; |
+ |
+ // Reached end with matched run. Update variables to expected values. |
+ if (x == y) { |
+ run_end++; |
+ if (run_end < src_size) |
+ y = src_buf[run_end]; |
+ } |
+ if (run_end - run_start > 1) { // Matched run but not at end of input. |
+ out[0] = 257 - (run_end - run_start); |
+ out[1] = x; |
+ x = y; |
+ run_start = run_end; |
+ run_end++; |
+ if (run_end < src_size) |
+ y = src_buf[run_end]; |
+ out += 2; |
+ continue; |
+ } |
+ // Mismatched run |
+ while (x != y && run_end <= run_start + max_len) { |
+ out[run_end - run_start] = x; |
+ x = y; |
+ run_end++; |
+ if (run_end == src_size) { |
+ if (run_end <= run_start + max_len) { |
+ out[run_end - run_start] = x; |
+ run_end++; |
+ } |
+ break; |
+ } |
+ y = src_buf[run_end]; |
+ } |
+ out[0] = run_end - run_start - 2; |
+ out += run_end - run_start; |
+ run_start = run_end - 1; |
+ } |
+ if (run_start < src_size) { // 1 leftover character |
+ out[0] = 0; |
+ out[1] = x; |
+ out += 2; |
+ } |
+ *out = 128; |
+ *dest_size = out + 1 - *dest_buf; |
+ return true; |
} |
bool CCodec_BasicModule::A85Encode(const uint8_t* src_buf, |
uint32_t src_size, |
uint8_t** dest_buf, |
uint32_t* dest_size) { |
- return false; |
+ // Check inputs. |
+ if (!src_buf || !dest_buf || !dest_size) |
+ return false; |
+ |
+ if (src_size == 0) { |
+ *dest_size = 0; |
+ return false; |
+ } |
+ |
+ // Worst case: 5 output for each 4 input (plus up to 4 from leftover), plus |
+ // 2 character new lines each 75 output chars plus 2 termination chars. May |
+ // have fewer if there are special "z" chars. |
+ uint32_t est_size = 5 * (src_size / 4) + 4 + src_size / 30 + 2; |
+ *dest_buf = FX_Alloc(uint8_t, est_size); |
+ |
+ // Set up pointers. |
+ uint8_t* out = *dest_buf; |
+ uint32_t pos = 0; |
+ uint32_t line_length = 0; |
+ while (src_size >= 4 && pos < src_size - 3) { |
+ uint32_t val = ((uint32_t)(src_buf[pos]) << 24) + |
+ ((uint32_t)(src_buf[pos + 1]) << 16) + |
+ ((uint32_t)(src_buf[pos + 2]) << 8) + |
+ (uint32_t)(src_buf[pos + 3]); |
+ pos += 4; |
+ if (val == 0) { // All zero special case |
+ *out = 'z'; |
+ out++; |
+ line_length++; |
+ } else { // Compute base 85 characters and add 33. |
+ for (int i = 4; i >= 0; i--) { |
+ out[i] = (uint8_t)(val % 85) + 33; |
+ val = val / 85; |
+ } |
+ out += 5; |
+ line_length += 5; |
+ } |
+ if (line_length >= 75) { // Add a return. |
+ *out++ = '\r'; |
+ *out++ = '\n'; |
+ line_length = 0; |
+ } |
+ } |
+ if (pos < src_size) { // Leftover bytes |
+ uint32_t val = 0; |
+ int count = 0; |
+ while (pos < src_size) { |
+ val += (uint32_t)(src_buf[pos] << (8 * (3 - pos))); |
+ count++; |
+ pos++; |
+ } |
+ for (int i = 4; i >= 0; i--) { |
+ if (i <= count) |
+ out[i] = (uint8_t)(val % 85) + 33; |
+ val = val / 85; |
+ } |
+ out += count + 1; |
+ } |
+ |
+ // Terminating characters. |
+ out[0] = '~'; |
+ out[1] = '>'; |
+ out += 2; |
+ *dest_size = out - *dest_buf; |
+ return true; |
} |
#ifdef PDF_ENABLE_XFA |