winamp/Src/bmp/rle.cpp
2024-09-24 14:54:57 +02:00

141 lines
2.9 KiB
C++

#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++;
}
}
}
}