Last active
January 22, 2016 20:57
-
-
Save kakwa/22f176fcd237d1ab59dd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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