1/*
2 * PackBits.cpp
3 * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
4 */
5
6//#define DBG_CON_STREAM
7
8#ifdef DBG_CON_STREAM
9#include <fstream>
10#endif
11
12#include <stdio.h>
13#include <string.h>
14#include "PackBits.h"
15
16
17using namespace std;
18
19
20#define	MAXINBYTES		127
21#define CONTROL1(i)		-i
22#define CONTROL2(i)		i
23
24enum STATUS {
25	INITIAL,
26	UNDECIDED,
27	UNMATCHED,
28	MATCHED
29};
30
31#define WRITE_TO_RUN_BUF(byte) \
32	{ \
33		if (write) \
34			*runbuf ++ = byte; \
35		else \
36			runbuf ++; \
37	}
38
39#define WRITE_CONTROL(byte) \
40	{ \
41		if (write) \
42			*control = byte; \
43	}
44
45template <bool write>
46class PackBits {
47public:
48	static int Run(unsigned char* destination, const unsigned char* source, int n)
49	{
50		int i;
51		unsigned char* control;
52		unsigned char* runbuf;
53		unsigned char thisbyte;
54		unsigned char runbyte;
55		STATUS status;
56
57		i = 0;
58		status  = INITIAL;
59		control = runbuf = destination;
60		runbyte = *source++;
61
62		while (--n) {
63			thisbyte = *source++;
64			switch (status) {
65			case INITIAL:
66				control   = runbuf++;
67				WRITE_TO_RUN_BUF(runbyte);
68				if (thisbyte == runbyte) {
69					status = UNDECIDED;
70				} else {
71					runbyte = thisbyte;
72					status  = UNMATCHED;
73				}
74				i = 1;
75				break;
76
77			case UNDECIDED:
78				if (i == MAXINBYTES) {
79					WRITE_CONTROL(CONTROL2(i));
80					WRITE_TO_RUN_BUF(runbyte);
81					runbyte   = thisbyte;
82					status    = INITIAL;
83				} else if (thisbyte == runbyte) {
84					if (i > 1) {
85						WRITE_CONTROL(CONTROL2(i - 2));
86						control  = runbuf - 1;
87					}
88					i = 2;
89					status = MATCHED;
90				} else {
91					WRITE_TO_RUN_BUF(runbyte);
92					runbyte   = thisbyte;
93					status    = UNMATCHED;
94					i++;
95				}
96				break;
97
98			case UNMATCHED:
99				if (i == MAXINBYTES) {
100					WRITE_CONTROL(CONTROL2(i));
101					status   = INITIAL;
102				} else {
103					if (thisbyte == runbyte) {
104						status = UNDECIDED;
105					}
106					i++;
107				}
108				WRITE_TO_RUN_BUF(runbyte);
109				runbyte   = thisbyte;
110				break;
111
112			case MATCHED:
113				if ((thisbyte != runbyte) || (i == MAXINBYTES)) {
114					runbuf    = control;
115					WRITE_TO_RUN_BUF(CONTROL1(i));
116					WRITE_TO_RUN_BUF(runbyte);
117					runbyte   = thisbyte;
118					status    = INITIAL;
119				} else {
120					i++;
121				}
122				break;
123			}
124		}
125
126		switch (status) {
127		case INITIAL:
128			WRITE_TO_RUN_BUF(CONTROL2(1));
129			break;
130		case UNDECIDED:
131		case UNMATCHED:
132			WRITE_CONTROL(CONTROL2(i));
133			break;
134		case MATCHED:
135			runbuf    = control;
136			WRITE_TO_RUN_BUF(CONTROL1(i));
137			break;
138		}
139		WRITE_TO_RUN_BUF(runbyte);
140
141		return runbuf - destination;
142	}
143};
144
145
146int pack_bits_size(const unsigned char* source, int size)
147{
148	PackBits<false> compressedSizeCalculator;
149	return compressedSizeCalculator.Run(NULL, source, size);
150}
151
152int pack_bits(unsigned char* destination, const unsigned char* source, int size)
153{
154	PackBits<true> compressor;
155	return compressor.Run(destination, source, size);
156}
157
158#ifdef DBG_CON_STREAM
159int main(int argc, char **argv)
160{
161	if (argc < 2) {
162		return -1;
163	}
164
165	FILE *input = fopen(*++argv, "rb");
166	if (input == NULL) {
167		return -1;
168	}
169
170	FILE *output = fopen("rle.out", "wb");
171	if (output == NULL) {
172		fclose(input);
173		return -1;
174	}
175
176	fseek(input, 0, SEEK_END);
177	long size = ftell(input);
178	fseek(input, 0, SEEK_SET);
179
180	unsigned char* source  = new unsigned char[size];
181	fread(source, size, 1, input);
182
183	long outSize = pack_bits_size(source, size);
184	printf("input size: %d\noutput size: %d\n", (int)size, (int)outSize);
185
186	unsigned char* destination = new unsigned char[outSize];
187
188	int cnt = pack_bits(destination, source, size);
189
190	fwrite(destination, cnt, 1, output);
191
192	fclose(input);
193	fclose(output);
194
195	delete [] source;
196	delete [] destination;
197
198}
199#endif
200