KSquare Utilities
SimpleCompressor.cpp
Go to the documentation of this file.
1 /* SimpleCompressor.cpp -- A simple Run Length compression algorithm.
2  * Copyright (C) 1994-2011 Kurt Kramer
3  * For conditions of distribution and use, see copyright notice in KKB.h
4  */
5 #include "FirstIncludes.h"
6 
7 #include <iostream>
8 #include <fstream>
9 #include <vector>
10 #include <string.h>
11 
12 #include "MemoryDebug.h"
13 
14 #include "KKBaseTypes.h"
15 
16 using namespace std;
17 using namespace KKB;
18 
19 #include "OSservices.h"
20 #include "SimpleCompressor.h"
21 
22 
23 
25 {
26  buffBytes = new uchar[estimatedMaxBuffSize];
27  buffLens = new uchar[estimatedMaxBuffSize];
28 
29  buffSize = estimatedMaxBuffSize;
30  buffSpaceUsed = 0;
31  lastBuffByteUsed = 0;
32  growthRate = estimatedMaxBuffSize;
33 }
34 
35 
36 
38 {
39  delete[] buffBytes;
40  delete[] buffLens;
41 }
42 
43 
44 
46 {
47  AddByte ((uchar)(i / 256));
48  AddByte ((uchar)(i % 256));
49 }
50 
51 
52 
54 {
55  if (buffSpaceUsed >= buffSize)
56  {
57  kkuint32 newBuffSize = buffSize + growthRate;
58  uchar* newBuffBytes = new uchar[newBuffSize];
59  uchar* newBuffLens = new uchar[newBuffSize];
60 
61  memcpy (newBuffBytes, buffBytes, buffSize);
62  memcpy (newBuffLens, buffLens, buffSize);
63  delete buffBytes;
64  delete buffLens;
65  buffBytes = newBuffBytes;
66  buffLens = newBuffLens;
67  newBuffBytes = NULL;
68  newBuffLens = NULL;
69  buffSize = newBuffSize;
70  }
71 
72  if (buffSpaceUsed == 0)
73  {
74  buffBytes[0] = b;
75  buffLens [0] = 1;
76  lastBuffByteUsed = 0;
77  buffSpaceUsed = 1;
78 
79  return;
80  }
81 
82  if (b == buffBytes[lastBuffByteUsed])
83  {
84  if (buffLens[lastBuffByteUsed] > 126)
85  {
86  buffBytes[buffSpaceUsed] = b;
87  buffLens [buffSpaceUsed] = 1;
88  lastBuffByteUsed = buffSpaceUsed;
89  buffSpaceUsed++;
90  }
91  else
92  {
93  buffLens[lastBuffByteUsed]++;
94  }
95  }
96  else
97  {
98  buffBytes[buffSpaceUsed] = b;
99  buffLens [buffSpaceUsed] = 1;
100  lastBuffByteUsed = buffSpaceUsed;
101  buffSpaceUsed++;
102  }
103 } /* AddByte */
104 
105 
106 
107 
108 kkuint32 SimpleCompressor::CalcCompressedBytesNeeded ()
109 {
110  kkuint32 compressedBuffUsed = 0;
111 
112  compressedBuffUsed++; // AddByteToCmpressedBuffer (compressedBuff, compressedBuffUsed, compressedBytesNeeded / 255);
113  compressedBuffUsed++; // AddByteToCmpressedBuffer (compressedBuff, compressedBuffUsed, compressedBytesNeeded % 255);
114 
115  kkuint32 idx = 0;
116 
117  while (idx < buffSpaceUsed)
118  {
119  while ((idx < buffSpaceUsed) && (buffLens[idx] > 1))
120  {
121  compressedBuffUsed++; //AddByteToCmpressedBuffer (compressedBuff, compressedBuffUsed, 128 + bufLens[idx]);
122  compressedBuffUsed++; //AddByteToCmpressedBuffer (compressedBuff, compressedBuffUsed, 128 + bufBytes[idx]);
123 
124  idx++;
125  }
126 
127  while ((idx < buffSpaceUsed) && (buffLens[idx] <= 1))
128  {
129  // We have some raw bytes to add.
130  // Lets look forward to see how many
131 
132 
133  kkuint32 endIdx = idx;
134  kkuint32 rawBytesInARow = 0;
135  while ((endIdx < buffSpaceUsed) && (buffLens[endIdx] <= 1) && (rawBytesInARow < 127))
136  {
137  endIdx++;
138  rawBytesInARow++;
139  }
140 
141  endIdx--;
142 
143 
144  compressedBuffUsed++; //AddByteToCmpressedBuffer (compressedBuff, compressedBuffUsed, 0 + rawBytesInARow);
145  for (kkuint32 x = 0; x < rawBytesInARow; x++)
146  {
147  compressedBuffUsed++; // AddByteToCmpressedBuffer (compressedBuff, compressedBuffUsed, buffBytes[idx]);
148  idx++;
149  }
150  }
151  }
152 
153  return compressedBuffUsed;
154 } /* CalcCompressedBytesNeeded*/
155 
156 
157 
158 
159 
160 
161 void SimpleCompressor::AddByteToCmpressedBuffer (uchar* compressedBuff,
162  kkuint32& compressedBuffUsed,
163  uchar b
164  )
165 {
166  compressedBuff[compressedBuffUsed] = b;
167  compressedBuffUsed++;
168 }
169 
170 
171 
173 {
174  kkuint32 compressedBytesNeeded = CalcCompressedBytesNeeded ();
175 
176  if (compressedBytesNeeded > (256 * 256))
177  {
178  ofstream f ("c:\\Temp\\SimpleCompressor.txt", ios_base::app);
179  f << std::endl
180  << osGetLocalDateTime () << "\t"
181  << "SimpleCompressor::CreateCompressedBuffer ***ERROR*** compressedBytesNeeded[" << compressedBytesNeeded << "] to large." << std::endl
182  << std::endl;
183  f.flush ();
184  f.close ();
185  compressedBuffserSize = compressedBytesNeeded;
186  return NULL;
187  }
188 
189 
190  uchar* compressedBuff = new uchar[compressedBytesNeeded];
191  kkuint32 compressedBuffUsed = 0;
192 
193  AddByteToCmpressedBuffer (compressedBuff, compressedBuffUsed, compressedBytesNeeded / 256);
194  AddByteToCmpressedBuffer (compressedBuff, compressedBuffUsed, compressedBytesNeeded % 256);
195 
196  kkuint32 idx = 0;
197 
198  while (idx < buffSpaceUsed)
199  {
200  while ((idx < buffSpaceUsed) && (buffLens[idx] > 1))
201  {
202  AddByteToCmpressedBuffer (compressedBuff, compressedBuffUsed, 128 + buffLens[idx]);
203  AddByteToCmpressedBuffer (compressedBuff, compressedBuffUsed, buffBytes[idx]);
204  idx++;
205  }
206 
207  while ((idx < buffSpaceUsed) && (buffLens[idx] <= 1))
208  {
209  // We have some raw bytes to add.
210  // Lets look forward to see how many
211 
212  kkuint32 endIdx = idx;
213  kkuint32 rawBytesInARow = 0;
214  while ((endIdx < buffSpaceUsed) && (buffLens[endIdx] <= 1) && (rawBytesInARow < 127))
215  {
216  endIdx++;
217  rawBytesInARow++;
218  }
219 
220  endIdx--;
221 
222 
223  AddByteToCmpressedBuffer (compressedBuff, compressedBuffUsed, 0 + rawBytesInARow);
224  for (kkuint32 x = 0; x < rawBytesInARow; x++)
225  {
226  AddByteToCmpressedBuffer (compressedBuff, compressedBuffUsed, buffBytes[idx]);
227  idx++;
228  }
229  }
230  }
231 
232  if (compressedBuffUsed != compressedBytesNeeded)
233  {
234  // This is not a good thing; something has damaged the compressed string.
235  ofstream f ("c:\\Temp\\SimpleCompressor.txt", ios_base::app);
236  f << std::endl
237  << osGetLocalDateTime () << "\t" << "SimpleCompressor::CreateCompressedBuffer ***ERROR***"
238  << std::endl
239  << " " << "\t" << "Something has gone terribly wrong with the simpleCompression algorithm." << std::endl
240  << std::endl;
241  f.flush ();
242  f.close ();
243  }
244 
245 
246  compressedBuffserSize = compressedBuffUsed;
247 
248  return compressedBuff;
249 } /* CreateCompressedBuffer*/
250 
251 
252 
253 
254 
255 uchar* SimpleCompressor::Decompress (const uchar* compressedBuff,
256  kkuint32 compressedBuffLen,
257  kkuint32& unCompressedSize
258  )
259 {
260  if ((compressedBuff == NULL) || ((compressedBuffLen < 2)))
261  return NULL;
262 
263  // First two bytes specifies the total number of compressed bytes including the first two bytes.
264  kkuint32 compressedBuffSize = compressedBuff[0] * 256 + compressedBuff[1];
265 
266  if (compressedBuffSize > compressedBuffLen)
267  {
268  ofstream f ("c:\\Temp\\SimpleCompressor.txt", ios_base::app);
269  f << std::endl
270  << osGetLocalDateTime () << "\t"
271  << "compressedBuffSize[" << compressedBuffSize << "] > compressedBuffLen[" << compressedBuffLen << "]" << "\t"
272  << std::endl;
273  f.flush ();
274  f.close ();
275 
276  compressedBuffSize = compressedBuffLen;
277  }
278 
279  kkuint32 nextByte = 2;
280 
281  // Calculate the number of uncompressed bytes needed. Which is done by decompressing the data.
282  unCompressedSize = 0;
283  while (nextByte < (compressedBuffSize - 1)) // There has to be at least 2 bytes in each group
284  {
285  uchar controlByte = compressedBuff[nextByte];
286  nextByte += 1;
287 
288  if (controlByte < 128)
289  {
290  // Raw data that consists of 'controlByte' bytes.
291  unCompressedSize = unCompressedSize + controlByte;
292  nextByte = nextByte + controlByte;
293  }
294  else
295  {
296  // Run Length data; next byte represents the byte that is to be repeated 'controByte' times.
297  unCompressedSize = unCompressedSize + (controlByte % 128);
298  nextByte = nextByte + 1;
299  }
300  }
301 
302  if (nextByte > compressedBuffSize)
303  {
304  // This is not a good thing; something has damaged the compressed string.
305  ofstream f ("c:\\Temp\\SimpleCompressor.txt", ios_base::app);
306  f << std::endl
307  << osGetLocalDateTime () << "\t"
308  << "nextByte[" << nextByte << "] > compressedBuffSize[" << compressedBuffSize << "]"
309  << std::endl;
310  f.flush ();
311  f.close ();
312  }
313 
314  uchar* unCompressedBuff = new uchar[unCompressedSize];
315  memset (unCompressedBuff, 0, unCompressedSize);
316 
317  nextByte = 2;
318 
319  kkuint32 unCompressedBuffIDX = 0;
320 
321  while (nextByte < (compressedBuffSize - 1))
322  {
323  uchar controlByte = compressedBuff[nextByte];
324  if (controlByte < 128)
325  {
326  // We have raw data that consists of 'controlByte' bytes.
327  nextByte++; // Step past control byte.
328 
329  for (kkint32 x = 0; (x < controlByte) && (nextByte < compressedBuffSize); x++)
330  {
331  unCompressedBuff[unCompressedBuffIDX] = compressedBuff[nextByte];
332  unCompressedBuffIDX++;
333  nextByte++;
334  }
335  }
336  else
337  {
338  // Since the control byte is 128 or greater; then we are dealing with a repeating value.
339  controlByte = controlByte % 128; // Get the lower 7 bits
340  nextByte++; // Step past control byte so now we are pointing at byte that is to be repeated.
341  for (kkint32 x = 0; x < controlByte; x++)
342  {
343  unCompressedBuff[unCompressedBuffIDX] = compressedBuff[nextByte];
344  unCompressedBuffIDX++;
345  }
346  nextByte++; // Move us to next control Byte.
347  }
348  }
349 
350  if (unCompressedBuffIDX != unCompressedSize)
351  {
352  cerr << std::endl
353  << std::endl
354  << "SimpleCompressor::Decompress ***ERROR***" << std::endl
355  << std::endl
356  << " Did not decompress correctly." << std::endl
357  << std::endl;
358  }
359  return unCompressedBuff;
360 } /* Decompress */
void Add16BitInt(kkuint32 i)
__int32 kkint32
Definition: KKBaseTypes.h:88
static uchar * Decompress(const uchar *compressedBuff, kkuint32 compressedBuffLen, kkuint32 &unCompressedSize)
unsigned __int32 kkuint32
Definition: KKBaseTypes.h:89
KKTHread * KKTHreadPtr
SimpleCompressor(kkuint32 estimatedMaxBuffSize)
unsigned char uchar
Unsigned character.
Definition: KKBaseTypes.h:77
uchar * CreateCompressedBuffer(kkuint32 &compressedBuffserSize)