home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power CD-ROM!! 7
/
POWERCD7.ISO
/
prgmming
/
clipper
/
rle.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-14
|
13KB
|
378 lines
/*
* File......: RLE.C
* Author....: Dave Pearson
* BBS.......: The Dark Knight Returns
* Net/Node..: 050/069
* User Name.: Dave Pearson
* Date......: 10/08/93
* Revision..: 1.1
*
* This is an original work by Dave Pearson and is placed in the public
* domain.
*
* Modification history:
* ---------------------
*
* $Log$
*
*/
// NOTE: This code has been written for and compiled with Borland C++
// Version 3.1
//
#include <extend.h>
// In the Extend.H for Clipper 5.01 the prototype for the _xunlock()
// function is missing, so, just in case.....
void _xunlock(void);
// Constants for the replic' ID's.
#define REPLIC_FLAG_BYTE (0x0)
#define REPLIC_FLAG_UINT (0x1)
// Constants for the ``screen optimized'' flag.
#define SCREEN_OPT 1
#define SCREEN_NOT_OPT 0
#define IS_SCREEN_OPTIMIZED(x) (x & SCREEN_OPT)
// Types used in this source.
typedef unsigned char BYTE;
typedef BYTE * STRING;
typedef unsigned int UINT;
typedef UINT * UINTARR;
typedef UINT BOOL;
// Prototype the functions used in this source.
STRING SwapScreen(STRING, UINT);
STRING UnSwapScreen(STRING, UINT);
UINT Encode(STRING, STRING, UINT);
void Decode(STRING, UINT, STRING);
/* $DOC$
* $FUNCNAME$
* GT_RLECOMP()
* $CATEGORY$
* Compression
* $ONELINER$
* Compress a string or screen image with RLE.
* $SYNTAX$
* GT_RleComp(<cString>,[<lIsAScreen>]) --> cCompressed
* $ARGUMENTS$
* <cString> is the string to be compressed.
*
* <lIsAScreen> is an optional logical paramepet to tell the
* function that the string is a screen image. The default value
* is TRUE.
*
* $RETURNS$
* A Compressed version of the string or screen image.
* $DESCRIPTION$
* GT_RleComp() uses a form of run length encoding to compress a
* string, This form of compression is only any good on strings
* that have a lot of repeating characters.
*
* By default GT_RleComp() is optimized to compress screen images
* as returned by Clipper's SaveScreen() function. When compressing
* ``normal'' strings this optimisation will not work so you must
* tell the function to use the ``normal'' compression method.
* $EXAMPLES$
*
* // Save the screen and compress it.
*
* cScreen := GT_RleComp(savescreen())
* ...
* restscreen(0,0,maxrow(),maxcol(),GT_RleUnCo(cScreen))
*
* // Compress a normal string and print it's length.
*
* cString := space(1000)
* ? len(GT_RleComp(cString,.F.))
* $SEEALSO$
* GT_RLEUNCO()
* $END$
*/
CLIPPER GT_RleComp()
{
STRING Default = "";
STRING Source;
STRING Target;
STRING Swapped;
UINT SourceLen;
UINT TargetLen;
UINT Header;
BOOL ScrnOpt = TRUE;
if (PCOUNT && ISCHAR(1))
{
if (PCOUNT == 2 && ISLOG(2))
{
ScrnOpt = _parl(2);
}
Source = _parc(1);
SourceLen = _parclen(1);
if (SourceLen <= 0x7FFF)
{
Swapped = (ScrnOpt ? SwapScreen(Source,SourceLen) : Source);
Target = _xgrab(SourceLen + sizeof(UINT));
TargetLen = Encode(Target + sizeof(UINT),Swapped,SourceLen);
if (ScrnOpt)
{
_xfree(Swapped);
}
((UINTARR) Target)[0] = (UINT) (SourceLen << 1) | (ScrnOpt ? SCREEN_OPT : SCREEN_NOT_OPT);
_retclen(Target,TargetLen + sizeof(Header));
_xfree(Target);
}
else
{
_retc(Default);
}
}
else
{
_retc(Default);
}
_xunlock();
}
/* $DOC$
* $FUNCNAME$
* GT_RLEUNCO()
* $CATEGORY$
* Compression
* $ONELINER$
* Un-Compress a string or screen image.
* $SYNTAX$
* GT_RleUnCo(<cCompressed>) --> cString
* $ARGUMENTS$
* <cCompressed> is a string that has been compressed using
* GT_RleComp().
*
* $RETURNS$
* The un-compressed version of the string.
* $DESCRIPTION$
* GT_RleUnCo() is used to un-compress a string or screen image that
* has been compressed with GT_RleComp().
* $EXAMPLES$
*
* // Save the screen and compress it.
*
* cScreen := GT_RleComp(savescreen())
* ...
* restscreen(0,0,maxrow(),maxcol(),GT_RleUnCo(cScreen))
*
* // Compress a normal string and print it's length.
*
* cString := space(1000)
* ? len(GT_RleComp(cString,.F.))
* $SEEALSO$
* GT_RLECOMP()
* $END$
*/
CLIPPER GT_RleUnCo()
{
STRING Source;
STRING Target;
STRING Return;
UINT SourceLen;
UINT TargetLen;
UINT Header;
BOOL ScrnOpt;
if (PCOUNT && ISCHAR(1))
{
Source = _parc(1);
SourceLen = _parclen(1);
Header = *((UINTARR) Source);
ScrnOpt = IS_SCREEN_OPTIMIZED(Header);
TargetLen = (Header >> 1);
Source += sizeof(Header);
SourceLen -= sizeof(Header);
Target = _xgrab(TargetLen);
Decode(Source,SourceLen,Target);
Return = (ScrnOpt ? UnSwapScreen(Target,TargetLen) : Target);
_retclen(Return,TargetLen);
if (ScrnOpt)
{
_xfree(Return);
}
_xfree(Target);
}
else
{
_retc("");
}
_xunlock();
}
/*****************************************************************************
* Function: SwapScreen() *
* Syntax..: STRING SwapScreen(STRING Screen, UINT ScreenSize) *
* Usage...: Swap round the screen image so that all the characters and all *
* ........: the attribute bytes are together. *
* By......: David A Pearson *
*****************************************************************************/
static STRING SwapScreen(STRING Screen, UINT ScreenSize)
{
STRING Temp = _xgrab(ScreenSize);
UINT Offset = (ScreenSize / 2);
UINT CharCnt;
UINT OtherCnt = 0;
for (CharCnt = 0; CharCnt < ScreenSize; CharCnt += 2, OtherCnt++)
{
Temp[OtherCnt] = Screen[CharCnt];
Temp[Offset + OtherCnt] = Screen[CharCnt+1];
}
return(Temp);
}
/*****************************************************************************
* Function: UnSwapScreen() *
* Syntax..: STRING UnSwapScreen(STRING Screen, UINT ScreenSize) *
* Usage...: Re-build the screen image so that it is made up of char/attr *
* ........: pairs. *
* By......: David A Pearson *
*****************************************************************************/
static STRING UnSwapScreen(STRING Screen, UINT ScreenSize)
{
STRING Temp = _xgrab(ScreenSize);
UINT Offset = (ScreenSize / 2);
UINT CharCnt;
UINT OtherCnt = 0;
for (CharCnt = 0; CharCnt < Offset; CharCnt++)
{
Temp[OtherCnt++] = Screen[CharCnt];
Temp[OtherCnt++] = Screen[CharCnt + Offset];
}
return(Temp);
}
/*****************************************************************************
* Function: Encode() *
* Syntax..: UINT Encode(STRING Target, STRING Source, UINT SourceLen) *
* Usage...: Run length encode a string. *
* By......: David A Pearson *
*****************************************************************************/
static UINT Encode(STRING Target, STRING Source, UINT SourceLen)
{
UINT SrceCnt = 0;
UINT TrgtCnt = 0;
UINT Replicated = 0;
BYTE CurrChar;
while (SrceCnt < SourceLen)
{
if (Source[SrceCnt] == (BYTE) REPLIC_FLAG_BYTE)
{
Target[TrgtCnt++] = (BYTE) REPLIC_FLAG_BYTE;
Target[TrgtCnt++] = 0;
++SrceCnt;
}
else if (Source[SrceCnt] == (BYTE) REPLIC_FLAG_UINT)
{
Target[TrgtCnt++] = (BYTE) REPLIC_FLAG_UINT;
Target[TrgtCnt++] = 0;
Target[TrgtCnt++] = 0;
++SrceCnt;
}
else if ((Source[SrceCnt] == Source[SrceCnt+1]) && (Source[SrceCnt] == Source[SrceCnt+2]) && (SrceCnt + 2 < SourceLen))
{
Replicated = 1;
CurrChar = Source[SrceCnt++];
while (Source[SrceCnt] == CurrChar)
{
++Replicated;
++SrceCnt;
}
Target[TrgtCnt++] = (BYTE) (Replicated > 0xFF ? REPLIC_FLAG_UINT : REPLIC_FLAG_BYTE);
if (Replicated > 0xFF)
{
*((UINTARR) &Target[TrgtCnt]) = (UINT) Replicated;
TrgtCnt += sizeof(UINT);
}
else
{
Target[TrgtCnt++] = (BYTE) Replicated;
}
Target[TrgtCnt++] = (BYTE) CurrChar;
}
else
{
Target[TrgtCnt++] = Source[SrceCnt++];
}
}
return(TrgtCnt);
}
/*****************************************************************************
* Function: Decode() *
* Syntax..: void Decode(STRING Source, UINT SourceLen, STRING Target) *
* Usage...: Decode a RLE string. *
* By......: David A Pearson *
*****************************************************************************/
static void Decode(STRING Source, UINT SourceLen, STRING Target)
{
UINT SrceCnt = 0;
UINT TrgtCnt = 0;
UINT RepCount;
UINT Replicate;
BYTE RepChar;
while (SrceCnt < SourceLen)
{
if (Source[SrceCnt] == (BYTE) REPLIC_FLAG_BYTE)
{
Replicate = (UINT) Source[++SrceCnt];
if (Replicate)
{
RepChar = Source[++SrceCnt];
for (RepCount = 0; RepCount < Replicate; RepCount++)
{
Target[TrgtCnt++] = RepChar;
}
}
else
{
Target[TrgtCnt++] = (BYTE) REPLIC_FLAG_BYTE;
}
}
else if (Source[SrceCnt] == (BYTE) REPLIC_FLAG_UINT)
{
Replicate = (UINT) *((UINTARR) &Source[++SrceCnt]);
++SrceCnt;
if (Replicate)
{
RepChar = Source[++SrceCnt];
for (RepCount = 0; RepCount < Replicate; RepCount++)
{
Target[TrgtCnt++] = RepChar;
}
}
else
{
Target[TrgtCnt++] = (BYTE) REPLIC_FLAG_UINT;
}
}
else
{
Target[TrgtCnt++] = Source[SrceCnt];
}
++SrceCnt;
}
}