Skip to content

Instantly share code, notes, and snippets.

@kakwa
Last active January 22, 2016 20:57
Show Gist options
  • Save kakwa/22f176fcd237d1ab59dd to your computer and use it in GitHub Desktop.
Save kakwa/22f176fcd237d1ab59dd to your computer and use it in GitHub Desktop.
#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 {
uint8_t *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 RLE4 to get bitmap (section 3.1.6.2 [MS-WMF].pdf)
bidImg rle4ToBitmap(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 upper = 0x00;
uint8_t lower = 0x00;
bool odd = false;
uint8_t tmp_u;
uint8_t tmp_l;
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:
if (odd) {
fputc(upper | 0x00, stream);
upper = 0x00;
lower = 0x00;
}
// end of line, pad the rest of the line with zeros
for (int i = 0; i < (((img.width - x) / 2) - 1); i++)
fputc(0x00, stream);
odd = img.width % 2;
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;
};
tmp_u = 0x00;
tmp_l = 0x00;
if (odd) {
fputc(upper | tmp_l, stream);
}
upper = tmp_u;
lower = tmp_l;
for (int i = 0; i < ((bm[2] + img.width * bm[3]) / 2); i++)
fputc(0x00, stream);
odd = ((bm[2] + img.width * bm[3]) + odd) % 2;
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 + (bm[1] / 2) + 2;
if (bm_next > end) {
fclose(stream);
return out_img;
};
for (int i = 2; i < (bm[1] / 2) + 2; i++) {
if (!odd) {
tmp_u = bm[i] & 0xF0;
tmp_l = bm[i] & 0x0F;
fputc(tmp_u | tmp_l, stream);
} else {
tmp_u = (bm[i] & 0x0F) << 4;
tmp_l = (bm[i] & 0xF0) >> 4;
fputc(upper | tmp_l, stream);
}
upper = tmp_u;
lower = tmp_l;
}
x += bm[1];
bm = bm_next + 1;
odd = (bm[1] + odd) % 2;
if (odd) {
upper = (bm[0] & 0x0F) << 4;
lower = (bm[0] & 0xF0) >> 4;
bm += 1;
}
break;
}
break;
default:
if (!odd) {
tmp_u = bm[1] & 0xF0;
tmp_l = bm[1] & 0x0F;
} else {
tmp_u = (bm[1] & 0x0F) << 4;
tmp_l = (bm[1] & 0xF0) >> 4;
fputc(upper | tmp_l, stream);
}
upper = tmp_u;
lower = tmp_l;
for (int i = 0; i < (bm[0] / 2); i++) {
fputc(upper | lower, stream);
}
odd = (bm[0] + odd) % 2;
x += bm[0];
bm += 2;
if (x >= img.width) {
x = x % img.width;
y--;
}
break;
}
}
// pad the rest of the bitmap
if (odd) {
fputc(upper | 0x00, stream);
upper = 0x00;
lower = 0x00;
}
// end of line, pad the rest of the line with zeros
for (int i = 0; i < ((img.width - x + img.width * y) / 2); 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() {
uint8_t img[] = {0x03, 0x04, 0x05, 0x06, 0x00, 0x06, 0x45, 0x56,
0x67, 0x00, 0x04, 0x78, 0x00, 0x02, 0x05, 0x01,
0x04, 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 = rle4ToBitmap(in);
for (size_t i = 0; i < out.size; i++) {
printf("%02x ", out.img[i]);
if (((i * 2) % out.width) == 30)
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