aboutsummaryrefslogtreecommitdiff
path: root/Src/bmp/rle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/bmp/rle.cpp')
-rw-r--r--Src/bmp/rle.cpp141
1 files changed, 141 insertions, 0 deletions
diff --git a/Src/bmp/rle.cpp b/Src/bmp/rle.cpp
new file mode 100644
index 00000000..657ff411
--- /dev/null
+++ b/Src/bmp/rle.cpp
@@ -0,0 +1,141 @@
+#include "rle.h"
+static bool CheckOverflow(size_t total_size, int current_position, int read_size)
+{
+ if (read_size > (int)total_size) // check separate to avoid overflow
+ return true;
+ if (((int)total_size - read_size) < current_position)
+ return true;
+ return false;
+}
+
+
+void RLE16(const uint8_t *rle, size_t rle_size_bytes, uint16_t *video_frame, size_t video_frame_size, int stride)
+{
+ int input = 0;
+ int output = 0;
+ video_frame_size >>= 1; // divide by 2 since we're indexing as uint16_t
+ int next_line = output + stride;
+ while (input < (int)rle_size_bytes && output < (int)video_frame_size)
+ {
+ if (CheckOverflow(rle_size_bytes, input, 2)) // we always read at least two bytes
+ break;
+
+ uint8_t b0 = rle[input++];
+ if (b0)
+ {
+ if (CheckOverflow(rle_size_bytes, input, 2))
+ break;
+
+ if (CheckOverflow(video_frame_size, output, b0))
+ {
+ b0 = (uint8_t)(video_frame_size - output);
+ }
+
+ uint16_t pixel = *(uint16_t *)(&rle[input]);
+ input += 2;
+ while (b0--)
+ {
+ memcpy(&video_frame[output], &pixel, 2);
+ output++;
+ }
+ }
+ else
+ {
+ uint8_t b1 = rle[input++];
+ if (b1 == 0)
+ {
+ output = next_line;
+ next_line = output + stride;
+ }
+ else if (b1 == 1)
+ {
+ return;
+ }
+ else if (b1 == 2)
+ {
+ if (CheckOverflow(rle_size_bytes, input, 2))
+ break;
+
+ uint8_t p1 = rle[input++];
+ uint8_t p2 = rle[input++];
+ output += p1;
+ output += p2*stride;
+ next_line += p2*stride;
+ }
+ else
+ {
+ if (CheckOverflow(rle_size_bytes, input, b1*2))
+ break;
+
+ if (CheckOverflow(video_frame_size, output, b1))
+ break;
+ for (uint8_t i=0;i!=b1;i++)
+ {
+ video_frame[output++] = *(uint16_t *)(&rle[input]);
+ input+=2;
+ }
+ }
+ }
+ }
+}
+
+void RLE8(const uint8_t *rle, size_t rle_size_bytes, uint8_t *video_frame, size_t video_frame_size, int stride)
+{
+ int input = 0;
+ int output = 0;
+ int next_line = output + stride;
+ while (input < (int)rle_size_bytes && output < (int)video_frame_size)
+ {
+ if (CheckOverflow(rle_size_bytes, input, 2)) // we always read at least two bytes
+ break;
+ uint8_t b0 = rle[input++];
+ if (b0)
+ {
+ if (CheckOverflow(video_frame_size, output, b0))
+ {
+ b0 = (uint8_t)(video_frame_size - output);
+ }
+
+ uint8_t pixel = rle[input++];
+ memset(&video_frame[output], pixel, b0);
+ output+=b0;
+ }
+ else
+ {
+ uint8_t b1 = rle[input++];
+ if (b1 == 0)
+ {
+ output = next_line;
+ next_line = output + stride;
+ }
+ else if (b1 == 1)
+ {
+ break;
+ }
+ else if (b1 == 2)
+ {
+ if (CheckOverflow(rle_size_bytes, input, 2))
+ break;
+
+ uint8_t p1 = rle[input++];
+ uint8_t p2 = rle[input++];
+ output += p1;
+ output += p2*stride;
+ next_line += p2*stride;
+ }
+ else
+ {
+ if (CheckOverflow(rle_size_bytes, input, b1))
+ break;
+
+ if (CheckOverflow(video_frame_size, output, b1))
+ break;
+ memcpy(&video_frame[output], &rle[input], b1);
+ input += b1;
+ output += b1;
+ if (b1 & 1)
+ input++;
+ }
+ }
+ }
+} \ No newline at end of file