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