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]