GFCompression/Cmprss10/cmprss10.cpp
// Help dll for GFCompression
// (c)2001 by Louis.
// Note that this dll cannot be used without the related VB code.
//
// NOTE: as this dll cannot resize VB arrays, all compression
// functions store the compressed/decompressed output string
// in a static array and return the length of the return string
// only. The VB code then must resize an array that has this
// returned length and then call GetCompressionByteString() to
// receive the final compressed/decompressed string.
//
#include "stdafx.h" // done by VC++ (?!?)
#include "cmprss10.h" // done by VC++ (?!?)
#include <malloc.h> // realloc
#include <stdlib.h> // realloc
#include <string.h> // memcpy
#include <assert.h> // assert
#include <afxwin.h> // AfxMessageBox
struct HuffmanTreeCodeStruct
{
long CodeLength;
char CodeArray[256];
};
struct TreeDecompressStruct
{
char Char;
long CharCodeArrayLength;
char CharCodeArray[256];
};
// *** PROTOTYPES***
long _stdcall RLE_CompressString(long, char *);
long _stdcall RLE_DecompressString(long, char *);
long _stdcall GetCompressionByteString(long, char *);
void _stdcall Huffman_CompressString(HuffmanTreeCodeStruct *, long, char *, long, char *);
void _stdcall Huffman_DecompressString(TreeDecompressStruct *, long *, char *, long, long, char *);
long CEILING(double);
long FLOOR(double);
long POW(long, long);
// ***VARS***
static long OutputByteStringLength = 0; // static
static char *OutputByteString = new char; // static
// ***CODE***
long _stdcall RLE_CompressString(long ByteStringLength, char ByteString[])
{
// returns length of compressed string, VB must resize an array and then call GetCompressionByteString()
char ReservedChar = 0;
char Char = 0;
long CharNumber = 0;
long CharFrequencyArray[256]; // initialize whole array to 0 (NOT done automatically)
long CharFrequencyMin = 0;
// char *OutputByteString = new char; // static
// char ReservedChar = 0; // static
long InputByteStringLength = 0;
long Temp1 = 0;
long Temp2 = 0;
double Tempdbl = 0; // '#' cannot be added in C++
// get char with lowest frequency
for (Temp1 = 0; Temp1 < 256; Temp1 ++)
{
CharFrequencyArray[Temp1] = 0;
}
for (Temp1 = 0; Temp1 < ByteStringLength; Temp1 ++)
{
CharFrequencyArray[ByteString[Temp1]] ++;
}
CharFrequencyMin = (256 * 256 * 256); // preset
for (Temp1 = 0; Temp1 < 256; Temp1 ++)
{
if (CharFrequencyArray[Temp1] < CharFrequencyMin)
CharFrequencyMin = CharFrequencyArray[Temp1];
}
for (Temp1 = 0; Temp1 < 256; Temp1 ++)
{
if (CharFrequencyArray[Temp1] == CharFrequencyMin)
{
ReservedChar = (char)Temp1;
break;
}
}
OutputByteStringLength = 5 + ByteStringLength + CharFrequencyMin; // five chars required for header information
OutputByteString = (char *)realloc(OutputByteString, OutputByteStringLength);
// begin
if (ByteStringLength != 0)
{
if (ByteString[0] == 0) Char = (char)255;
else Char = (char)0; // preset
}
OutputByteStringLength = 4; // preset (reserve chars 0‑4 for header information)
for (Temp1 = 0; Temp1 < ByteStringLength; Temp1 ++)
{
if (ByteString[Temp1] == Char)
CharNumber ++;
else
{
switch (CharNumber)
{
case 0:
// no char repetition
break;
case 1:
OutputByteStringLength ++;
OutputByteString[OutputByteStringLength ‑ 1] = ByteString[Temp1 ‑ 1];
CharNumber = 0; // reset
break;
case 2:
OutputByteStringLength += 2;
OutputByteString[OutputByteStringLength ‑ 2] = ByteString[Temp1 ‑ 2];
OutputByteString[OutputByteStringLength ‑ 1] = ByteString[Temp1 ‑ 1];
CharNumber = 0; // reset
break;
default:
OutputByteStringLength ++;
OutputByteString[OutputByteStringLength ‑ 1] = ReservedChar;
Tempdbl = CEILING((double)CharNumber / (double)254);
for (Temp2 = 0; Temp2 < Tempdbl; Temp2 ++)
{
if (Temp2 != Tempdbl)
{
OutputByteStringLength ++;
OutputByteString[OutputByteStringLength ‑ 1] = (char)254;
}
else
{
OutputByteStringLength ++;
OutputByteString[OutputByteStringLength ‑ 1] =
(CharNumber ‑ ((Temp2 ‑ 1) * 254) ‑ 1); // 1 to 0 based
} // if
} // for
CharNumber = 0; // reset
break;
} // switch
if (ByteString[Temp1] == ReservedChar)
{
OutputByteStringLength += 2;
OutputByteString[OutputByteStringLength ‑ 2] = ReservedChar;
OutputByteString[OutputByteStringLength ‑ 1] = (char)255;
CharNumber = 0; // reset
}
else
{
OutputByteStringLength ++;
OutputByteString[OutputByteStringLength ‑ 1] = ByteString[Temp1];
CharNumber = 0;
} // if
} // if
Char = ByteString[Temp1];
if (Temp1 == (ByteStringLength ‑ 2)) // originally ‑1, but Temp1 is 0 based, ByteStringLength is not
{
if (ByteString[Temp1] == 0) Char = (char)255;
else Char = (char)0;
}
if (Char == ReservedChar)
{
if (ByteString[Temp1] == 0) Char = (char)255;
else Char = (char)0;
}
} // for
// create final return string
memcpy((void *)OutputByteString[0], (void *)ByteStringLength, 4); // original string length
memcpy((void *)OutputByteString[4], (void *)ReservedChar, 1);
return OutputByteStringLength; // ok
}
long _stdcall RLE_DecompressString(long ByteStringLength, char ByteString[])
{
// returns length of decompressed string, VB must resize an array and then call GetCompressionByteString()
long OByteStringwritePos = 0;
// long OutputByteStringLength = 0; // static
// char *OutputByteString = new char; // static
char ReservedChar = 0;
long ReservedCharDetectedFlag = 0;
long ReservedCharNumber = 0;
long Temp1 = 0;
long Temp2 = 0;
long Temp3 = 0;
// preset
memcpy((void *)OutputByteStringLength, (void *)ByteString[0], 4);
memcpy((void *)ReservedChar, (void *)ByteString[4], 1);
OutputByteString = (char *)realloc(OutputByteString, OutputByteStringLength);
// begin
for (Temp1 = 5; Temp1 < ByteStringLength; Temp1 ++)
{
if (ByteString[Temp1] == ReservedChar)
{
Temp2 = Temp1 + 1; // read pos in input string
do
{
if (ByteString[Temp2] == (char)254)
{
for (Temp3 = 0; Temp3 < 254; Temp3 ++)
{
OByteStringwritePos ++;
OutputByteString[OByteStringwritePos ‑ 1] = ByteString[Temp1 ‑ 1];
Temp2 ++; // read next char of input string
}
}
else
{
if (ByteString[Temp2] == (char)255)
{
OByteStringwritePos ++;
OutputByteString[OByteStringwritePos ‑ 1] = ReservedChar;
break; // do ... while (1)
}
else
{
for (Temp3 = 0; Temp3 < ((long)ByteString[Temp2] + 1); Temp3 ++) // 0 to 1 based
{
OByteStringwritePos ++;
OutputByteString[OByteStringwritePos ‑ 1] = ByteString[Temp1 ‑ 1];
}
break; // do ... while (1)
}
} // if
}
while (1);
Temp1 = Temp2;
} // if
else
{
OByteStringwritePos ++;
OutputByteString[OByteStringwritePos ‑ 1] = ByteString[Temp1];
}
} // for
// create final, decompressed return string
return OutputByteStringLength; // ok
}
long _stdcall GetCompressionByteString(long ByteStringLength, char ByteString[])
{
// call from VB after ByteString has been resized; this function always returns 1 (return value is reserved for further dll versions)
ByteStringLength = OutputByteStringLength; // was returned by decompression/compression function
memcpy((void *)ByteString, (void *)OutputByteString, OutputByteStringLength);
return 1;
}
void _stdcall Huffman_CompressString(HuffmanTreeCodeStruct HuffmanTreeCodeStructArray[], long ByteStringLength, char ByteString[], long CompressedStringLength, char CompressedString[])
{
double CompressedStringBitWritePos = 0;
long CompressedStringIndex = 0;
long Temp1 = 0;
long Temp2 = 0;
// begin
for (Temp1 = 0; Temp1 < ByteStringLength; Temp1 ++)
{
// NOTE: CompressedStringBitWritePos identifies the bit in
// CompressedString() where the next code string is to be 'added'.
for (Temp2 = 0; Temp2 < HuffmanTreeCodeStructArray[ByteString[Temp1]].CodeLength; Temp2 ++)
{
CompressedStringBitWritePos ++;
assert (ByteString[Temp1] > ‑1);
assert (ByteString[Temp1] < 256);
assert (HuffmanTreeCodeStructArray[ByteString[Temp1]].CodeArray[Temp2] < 20);
if (HuffmanTreeCodeStructArray[ByteString[Temp1]].CodeArray[Temp2])
{
CompressedStringIndex = FLOOR(((CompressedStringBitWritePos ‑ (double)1) / (double)8)); // + (long)1;
AfxMessageBox("1");
CompressedString[CompressedStringIndex] |=
((long)HuffmanTreeCodeStructArray[ByteString[Temp1]].CodeArray[Temp2] *
POW(2, (7 ‑ (((long)CompressedStringBitWritePos + 7) % 8))));
AfxMessageBox("2");
// NOTE: to use the modulo operator the bit write pos
// must be converted to long, what could theoretically
// lead to an overflow,
// but as the GFCompressionCode decompresses large
// files in small blocks this will not happen.
} // if
} // for
} // for
}
void _stdcall Huffman_DecompressString(TreeDecompressStruct TreeDecompressStructArray[], long ByteStringLength, char ByteString[], long BitReadStartPos, long OutputByteStringLength, char OutputByteString[])
{
long CodeBufLength = 0;
char CodeBufArray[256] = {0}; // current code from input string
long ByteStringIndex = 0;
long BitReadPos = 0;
long Temp1 = 0;
long Temp2 = 0;
long Temp3 = 0;
long Temp4 = 0;
// begin
for (Temp1 = 0; Temp1 < OutputByteStringLength; Temp1 ++)
{
// Temp1 = write pos into output string
for (Temp2 = 0; Temp2 < 256; Temp2 ++)
{
// Temp2 = write pos into buffer array
BitReadPos ++;
ByteStringIndex = FLOOR(((double)BitReadPos ‑ (double)1) / (double)8);
if (ByteString[ByteStringIndex ‑ 1] && POW(2, (7 ‑ ((BitReadPos + 7) % 8))))
CodeBufArray[Temp2] = 1;
else
CodeBufArray[Temp2] = 0;
for (Temp3 = 0; Temp3 < 256; Temp3 ++)
{
if (TreeDecompressStructArray[Temp3].CharCodeArrayLength) // important (code length must above 0)
{
// NOTE: another optimization would be to avoid that 0‑length codes are at beginning of the struct array.
if (Temp2 >= TreeDecompressStructArray[Temp3].CharCodeArrayLength)
{
for (Temp4 = 0; Temp4 < TreeDecompressStructArray[Temp3].CharCodeArrayLength; Temp4 ++)
{
if (TreeDecompressStructArray[Temp3].CharCodeArray[Temp4] != CodeBufArray[Temp4])
goto Skip;
} // for
OutputByteString[Temp1] = TreeDecompressStructArray[Temp3].Char;
goto Jump;
Skip:
;
} // if
} // if
} // for Temp3
} // for Temp2
Jump:
;
} // for Temp1
}
// ***HELP FUNCTIONS***
long CEILING(double NumberDouble) // tested; ok
{
// returns 'next larger' number (use for positive values only)
long NumberLong = (long)NumberDouble;
if ((double)NumberLong == NumberDouble)
return NumberLong;
else
return NumberLong + 1;
}
long FLOOR(double NumberDouble) // tested; ok
{
// returns 'next lower' number (use for positive values only)
long NumberLong = (long)NumberDouble;
if ((double)NumberLong == NumberDouble)
return NumberLong;
else
return NumberLong ‑ 1;
}
long POW(long Base, long Exponent)
{
// simple (!) power of‑function, Base must be at least 1, Exponent at least 0
long Temp = 1;
long Result = Base;
if (Exponent)
{
for (Temp; Temp < Exponent; Temp ++) // Temp is 1 based
{
Result *= Result;
}
return Result;
}
else
{
return 1;
}
}
// ***END OF HELP FUNCTIONS***
// ***EOF***
[END OF FILE]