diff options
Diffstat (limited to 'Src/bmp/rle.cpp')
-rw-r--r-- | Src/bmp/rle.cpp | 141 |
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 |