xref: /haiku/src/libs/print/libprint/PackBits.cpp (revision 26db1794f9199838b3d4c8e6199f72dcf9cfec08)
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 
17 using namespace std;
18 
19 
20 #define	MAXINBYTES		127
21 #define CONTROL1(i)		-i
22 #define CONTROL2(i)		i
23 
24 enum 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 
45 template <bool write>
46 class PackBits {
47 public:
Run(unsigned char * destination,const unsigned char * source,int n)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 
pack_bits_size(const unsigned char * source,int size)146 int pack_bits_size(const unsigned char* source, int size)
147 {
148 	PackBits<false> compressedSizeCalculator;
149 	return compressedSizeCalculator.Run(NULL, source, size);
150 }
151 
pack_bits(unsigned char * destination,const unsigned char * source,int size)152 int 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
main(int argc,char ** argv)159 int 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