aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/ruby-msg/contrib/rtfdecompr.c
blob: 633d50286ef6abe3b40f675841ad3c5b011a8a74 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void decompress_rtf(FILE *srcf)
{
//	#define prebuf_len (sizeof(prebuf))
//	static unsigned char prebuf[] =

	// the window of decompressed bytes that can be referenced for copies.
	// moved to this rather than indexing directly into output for streaming.
	// circular buffer.
	// because we use single-function call approach, no need for copy.
	// if using libstream-3, i would have a few options. i would be part of
	// the filter interface, which doesn't care if it is reading or writing,
	// all it knows about is its input and output buffers. we can't just
	// flush some data to the output buffer in that scenario, so we would need
	// to keep the window around. we also can't guarantee availability of that
	// buffer. so, we would probably have a instance member which would be
	// this ->
	unsigned char buf[4096] =
		"{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}"
		"{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscript "
		"\\fdecor MS Sans SerifSymbolArialTimes New RomanCourier"
		"{\\colortbl\\red0\\green0\\blue0\n\r\\par "
		"\\pard\\plain\\f0\\fs20\\b\\i\\u\\tab\\tx";

	#define BUF_MASK 4095		

	int wp = strlen((char *)buf);

	unsigned char *dst; // destination for uncompressed bytes
	int in = 0; // current position in src array
	int out = 0; // current position in dst array

	unsigned char hdr[16];
	int got;
	// get header fields (as defined in RTFLIB.H)
	got = fread(hdr, 1, 16, srcf);
	if (got != 16) {
		printf("Invalid compressed-RTF header\n");
		exit(1);
	}

	int compr_size = *(unsigned int *)(hdr);
	int uncompr_size = *(unsigned int *)(hdr + 4);
	int magic = *(unsigned int *)(hdr + 8);
	long crc32 = *(unsigned int *)(hdr + 12);

	unsigned char *x, *y;;
	unsigned char *src = malloc(compr_size - 12); // includes the 3 header fields
	y = src;
	x = src + compr_size - 12;
	got = fread(src, 1, compr_size - 12, srcf);
	if (got != compr_size - 12) {
		printf("compressed-RTF data size mismatch (%d != %d)\n", got, compr_size - 12);
		exit(1);
	}
	// shouldn't be any more than that
	got = fread(dst, 1, 16, srcf);
	if (got > 0) {
		printf("warning: data after the size\n");
	}

	// process the data
	if (magic == 0x414c454d) { // magic number that identifies the stream as a uncompressed stream
		dst = malloc(uncompr_size);
		memcpy(dst, src, uncompr_size);
	}
	else if (magic == 0x75465a4c) { // magic number that identifies the stream as a compressed stream
		out = 0; //strlen(prebuf);
		int dst_len;
		dst = malloc(dst_len = uncompr_size);

		int flagCount = 0;
		int flags = 0;
		while (out < dst_len && src < x) {
			// each flag byte flags 8 literals/references, 1 per bit
			flags = (flagCount++ % 8 == 0) ? *src++ : flags >> 1;
			if (flags & 1) { // each flag bit is 1 for reference, 0 for literal
				int rp = *src++;
				int l = *src++;
				//offset is a 12 byte number. 2^12 is 4096, so thats fine
				rp = (rp << 4) | (l >> 4); // the offset relative to block start
				l = (l & 0xf) + 2; // the number of bytes to copy
				int e = rp + l;
				while (rp < e)
					putchar(buf[wp++ & BUF_MASK] = buf[rp++ & BUF_MASK]);
			}
			else putchar(buf[wp++ & BUF_MASK] = *src++);
		}
	}
	else { // unknown magic number
		printf("Unknown compression type (magic number %04x)", magic);
	}

	free(y);
}

int main(int argc, char *argv[])
{
	FILE *file = fopen(argv[1], "rb");
	decompress_rtf(file);
	fclose(file);
}