Skip to content

Instantly share code, notes, and snippets.

@kakwa
Last active January 22, 2016 00:27
Show Gist options
  • Save kakwa/4e1ef87ab445f975ee84 to your computer and use it in GitHub Desktop.
Save kakwa/4e1ef87ab445f975ee84 to your computer and use it in GitHub Desktop.
uncompress Windows RLE8 to get bitmap
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h> /* for offsetof() macro */
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
typedef struct _dibImg {
char *img;
size_t size;
uint32_t width;
uint32_t height;
} bidImg;
#define RLE_MARK 0x00
#define RLE_EOL 0x00
#define RLE_EOB 0x01
#define RLE_DELTA 0x02
// uncompress RLE8 to get bitmap (section 3.1.6.2 [MS-WMF].pdf)
bidImg rle8ToBitmap(bidImg img) {
FILE *stream;
bool decode = true;
char *out;
size_t size;
bidImg out_img;
out_img.size = 0;
out_img.width = 0;
out_img.height = 0;
out_img.img = NULL;
uint8_t *bm = (uint8_t *)img.img;
uint32_t x = 0;
uint32_t y = img.height - 1;
uint8_t *bm_next;
stream = open_memstream(&out, &size);
if (stream == NULL) {
return out_img;
}
uint8_t *end = bm + img.size;
while (decode && (bm < end)) {
switch (bm[0]) {
// check against potential overflow
if ((bm + 2) > end) {
fclose(stream);
return out_img;
};
case RLE_MARK:
switch (bm[1]) {
case RLE_EOL:
// end of line, pad the rest of the line with zeros
for (int i = 0; i < (img.width - x); i++)
fputc(0x00, stream);
bm += 2;
x = 0;
y--;
break;
case RLE_EOB:
// end of bitmap
decode = false;
break;
case RLE_DELTA:
// offset handling, pad with (off.x + off.y * width) zeros
if ((bm + 3) > end) {
fclose(stream);
return out_img;
};
for (int i = 0; i < (bm[2] + img.width * bm[3]); i++)
fputc(0x00, stream);
x += bm[2];
y -= bm[3];
bm += 4;
break;
default:
// absolute mode handling (no compression)
// data is padded to a word
// calculate next address accordingly
bm_next = bm + 1 + ((bm[1] + 1) / 2) * 2;
if (bm_next > end) {
fclose(stream);
return out_img;
};
for (int i = 2; i < bm[1] + 2; i++)
fputc(bm[i], stream);
x += bm[1];
bm = bm_next + 1;
break;
}
break;
default:
for (int i = 0; i < bm[0]; i++)
fputc(bm[1], stream);
x += bm[0];
bm += 2;
if (x >= img.width) {
x = x % img.width;
y--;
}
break;
}
}
// pad the rest of the bitmap
for (int i = 0; i < ((img.width - x) + img.width * y); i++)
fputc(0x00, stream);
fflush(stream);
fclose(stream);
out_img.img = out;
out_img.size = size;
out_img.width = img.width;
out_img.height = img.height;
return out_img;
}
int main() {
char img[] = {0x03, 0x04, 0x05, 0x06, 0x00, 0x03, 0x45, 0x56,
0x67, 0x00, 0x02, 0x78, 0x00, 0x02, 0x05, 0x01,
0x02, 0x78, 0x00, 0x00, 0x09, 0x1E, 0x00, 0x01};
bidImg in;
in.img = img;
in.width = 32;
in.height = 4;
in.size = 24;
printf("IN:\n");
for (size_t i = 0; i < in.size; i++) {
printf("%02x ", in.img[i]);
}
printf("\n\n");
printf("OUT:\n");
bidImg out = rle8ToBitmap(in);
for (size_t i = 0; i < out.size; i++) {
printf("%02x ", out.img[i]);
if ((i % out.width) == 31)
printf("\n");
}
printf("\n");
}
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment