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