home *** CD-ROM | disk | FTP | other *** search
/ Power CD-ROM!! 7 / POWERCD7.ISO / prgmming / clipper / rle.c < prev    next >
C/C++ Source or Header  |  1993-10-14  |  13KB  |  378 lines

  1. /*
  2.  * File......: RLE.C
  3.  * Author....: Dave Pearson
  4.  * BBS.......: The Dark Knight Returns
  5.  * Net/Node..: 050/069
  6.  * User Name.: Dave Pearson
  7.  * Date......: 10/08/93
  8.  * Revision..: 1.1
  9.  *
  10.  * This is an original work by Dave Pearson and is placed in the public
  11.  * domain.
  12.  *
  13.  * Modification history:
  14.  * ---------------------
  15.  *
  16.  * $Log$
  17.  *
  18.  */
  19.  
  20. // NOTE: This code has been written for and compiled with Borland C++
  21. //       Version 3.1
  22. //
  23.  
  24. #include <extend.h>
  25.  
  26. // In the Extend.H for Clipper 5.01 the prototype for the _xunlock()
  27. // function is missing, so, just in case.....
  28.  
  29. void _xunlock(void);
  30.  
  31. // Constants for the replic' ID's.
  32.  
  33. #define REPLIC_FLAG_BYTE        (0x0)
  34. #define REPLIC_FLAG_UINT        (0x1)
  35.  
  36. // Constants for the ``screen optimized'' flag.
  37.  
  38. #define SCREEN_OPT              1
  39. #define SCREEN_NOT_OPT          0
  40.  
  41. #define IS_SCREEN_OPTIMIZED(x)  (x & SCREEN_OPT)
  42.  
  43. // Types used in this source.
  44.  
  45. typedef unsigned char   BYTE;
  46. typedef BYTE *          STRING;
  47. typedef unsigned int    UINT;
  48. typedef UINT *          UINTARR;
  49. typedef UINT            BOOL;
  50.  
  51. // Prototype the functions used in this source.
  52.  
  53. STRING SwapScreen(STRING, UINT);
  54. STRING UnSwapScreen(STRING, UINT);
  55. UINT   Encode(STRING, STRING, UINT);
  56. void   Decode(STRING, UINT, STRING);
  57.  
  58. /*  $DOC$
  59.  *  $FUNCNAME$
  60.  *      GT_RLECOMP()
  61.  *  $CATEGORY$
  62.  *      Compression
  63.  *  $ONELINER$
  64.  *      Compress a string or screen image with RLE.
  65.  *  $SYNTAX$
  66.  *      GT_RleComp(<cString>,[<lIsAScreen>]) --> cCompressed
  67.  *  $ARGUMENTS$
  68.  *      <cString> is the string to be compressed.
  69.  *
  70.  *      <lIsAScreen> is an optional logical paramepet to tell the
  71.  *      function that the string is a screen image. The default value
  72.  *      is TRUE.
  73.  *
  74.  *  $RETURNS$
  75.  *      A Compressed version of the string or screen image.
  76.  *  $DESCRIPTION$
  77.  *      GT_RleComp() uses a form of run length encoding to compress a
  78.  *      string, This form of compression is only any good on strings
  79.  *      that have a lot of repeating characters.
  80.  *
  81.  *      By default GT_RleComp() is optimized to compress screen images
  82.  *      as returned by Clipper's SaveScreen() function. When compressing
  83.  *      ``normal'' strings this optimisation will not work so you must
  84.  *      tell the function to use the ``normal'' compression method.
  85.  *  $EXAMPLES$
  86.  *
  87.  *      // Save the screen and compress it.
  88.  *
  89.  *      cScreen := GT_RleComp(savescreen())
  90.  *      ...
  91.  *      restscreen(0,0,maxrow(),maxcol(),GT_RleUnCo(cScreen))
  92.  *
  93.  *      // Compress a normal string and print it's length.
  94.  *
  95.  *      cString := space(1000)
  96.  *      ? len(GT_RleComp(cString,.F.))
  97.  *  $SEEALSO$
  98.  *      GT_RLEUNCO()
  99.  *  $END$
  100.  */
  101.  
  102. CLIPPER GT_RleComp()
  103. {
  104.         STRING Default = "";
  105.         STRING Source;
  106.         STRING Target;
  107.         STRING Swapped;
  108.         UINT   SourceLen;
  109.         UINT   TargetLen;
  110.         UINT   Header;
  111.         BOOL   ScrnOpt = TRUE;
  112.  
  113.         if (PCOUNT && ISCHAR(1))
  114.         {
  115.                 if (PCOUNT == 2 && ISLOG(2))
  116.                 {
  117.                         ScrnOpt = _parl(2);
  118.                 }
  119.                 Source    = _parc(1);
  120.                 SourceLen = _parclen(1);
  121.                 if (SourceLen <= 0x7FFF)
  122.                 {
  123.                         Swapped   = (ScrnOpt ? SwapScreen(Source,SourceLen) : Source);
  124.                         Target    = _xgrab(SourceLen + sizeof(UINT));
  125.                         TargetLen = Encode(Target + sizeof(UINT),Swapped,SourceLen);
  126.                         if (ScrnOpt)
  127.                         {
  128.                                 _xfree(Swapped);
  129.                         }
  130.                         ((UINTARR) Target)[0] = (UINT) (SourceLen << 1) | (ScrnOpt ? SCREEN_OPT : SCREEN_NOT_OPT);
  131.                         _retclen(Target,TargetLen + sizeof(Header));
  132.                         _xfree(Target);
  133.                 }
  134.                 else
  135.                 {
  136.                         _retc(Default);
  137.                 }
  138.         }
  139.         else
  140.         {
  141.                 _retc(Default);
  142.         }
  143.         _xunlock();
  144. }
  145.  
  146. /*  $DOC$
  147.  *  $FUNCNAME$
  148.  *      GT_RLEUNCO()
  149.  *  $CATEGORY$
  150.  *      Compression
  151.  *  $ONELINER$
  152.  *      Un-Compress a string or screen image.
  153.  *  $SYNTAX$
  154.  *      GT_RleUnCo(<cCompressed>) --> cString
  155.  *  $ARGUMENTS$
  156.  *      <cCompressed> is a string that has been compressed using
  157.  *      GT_RleComp().
  158.  *
  159.  *  $RETURNS$
  160.  *      The un-compressed version of the string.
  161.  *  $DESCRIPTION$
  162.  *      GT_RleUnCo() is used to un-compress a string or screen image that
  163.  *      has been compressed with GT_RleComp().
  164.  *  $EXAMPLES$
  165.  *
  166.  *      // Save the screen and compress it.
  167.  *
  168.  *      cScreen := GT_RleComp(savescreen())
  169.  *      ...
  170.  *      restscreen(0,0,maxrow(),maxcol(),GT_RleUnCo(cScreen))
  171.  *
  172.  *      // Compress a normal string and print it's length.
  173.  *
  174.  *      cString := space(1000)
  175.  *      ? len(GT_RleComp(cString,.F.))
  176.  *  $SEEALSO$
  177.  *      GT_RLECOMP()
  178.  *  $END$
  179.  */
  180.  
  181. CLIPPER GT_RleUnCo()
  182. {
  183.         STRING Source;
  184.         STRING Target;
  185.         STRING Return;
  186.         UINT   SourceLen;
  187.         UINT   TargetLen;
  188.         UINT   Header;
  189.         BOOL   ScrnOpt;
  190.  
  191.         if (PCOUNT && ISCHAR(1))
  192.         {
  193.                 Source    = _parc(1);
  194.                 SourceLen = _parclen(1);
  195.                 Header    = *((UINTARR) Source);
  196.                 ScrnOpt   = IS_SCREEN_OPTIMIZED(Header);
  197.                 TargetLen = (Header >> 1);
  198.                 Source    += sizeof(Header);
  199.                 SourceLen -= sizeof(Header);
  200.                 Target    = _xgrab(TargetLen);
  201.                 Decode(Source,SourceLen,Target);
  202.                 Return = (ScrnOpt ? UnSwapScreen(Target,TargetLen) : Target);
  203.                 _retclen(Return,TargetLen);
  204.                 if (ScrnOpt)
  205.                 {
  206.                         _xfree(Return);
  207.                 }
  208.                 _xfree(Target);
  209.         }
  210.         else
  211.         {
  212.                 _retc("");
  213.         }
  214.         _xunlock();
  215. }
  216.  
  217. /*****************************************************************************
  218. * Function: SwapScreen()                                                     *
  219. * Syntax..: STRING SwapScreen(STRING Screen, UINT ScreenSize)                *
  220. * Usage...: Swap round the screen image so that all the characters and all   *
  221. * ........: the attribute bytes are together.                                *
  222. * By......: David A Pearson                                                  *
  223. *****************************************************************************/
  224.  
  225. static STRING SwapScreen(STRING Screen, UINT ScreenSize)
  226. {
  227.         STRING Temp     = _xgrab(ScreenSize);
  228.         UINT   Offset   = (ScreenSize / 2);
  229.         UINT   CharCnt;
  230.         UINT   OtherCnt = 0;
  231.  
  232.         for (CharCnt = 0; CharCnt < ScreenSize; CharCnt += 2, OtherCnt++)
  233.         {
  234.                 Temp[OtherCnt]          = Screen[CharCnt];
  235.                 Temp[Offset + OtherCnt] = Screen[CharCnt+1];
  236.         }
  237.         return(Temp);
  238. }
  239.  
  240. /*****************************************************************************
  241. * Function: UnSwapScreen()                                                   *
  242. * Syntax..: STRING UnSwapScreen(STRING Screen, UINT ScreenSize)              *
  243. * Usage...: Re-build the screen image so that it is made up of char/attr     *
  244. * ........: pairs.                                                           *
  245. * By......: David A Pearson                                                  *
  246. *****************************************************************************/
  247.  
  248. static STRING UnSwapScreen(STRING Screen, UINT ScreenSize)
  249. {
  250.         STRING Temp     = _xgrab(ScreenSize);
  251.         UINT   Offset   = (ScreenSize / 2);
  252.         UINT   CharCnt;
  253.         UINT   OtherCnt = 0;
  254.  
  255.         for (CharCnt = 0; CharCnt < Offset; CharCnt++)
  256.         {
  257.                 Temp[OtherCnt++] = Screen[CharCnt];
  258.                 Temp[OtherCnt++] = Screen[CharCnt + Offset];
  259.         }
  260.         return(Temp);
  261. }
  262.  
  263. /*****************************************************************************
  264. * Function: Encode()                                                         *
  265. * Syntax..: UINT Encode(STRING Target, STRING Source, UINT SourceLen)        *
  266. * Usage...: Run length encode a string.                                      *
  267. * By......: David A Pearson                                                  *
  268. *****************************************************************************/
  269.  
  270. static UINT Encode(STRING Target, STRING Source, UINT SourceLen)
  271. {
  272.         UINT SrceCnt    = 0;
  273.         UINT TrgtCnt    = 0;
  274.         UINT Replicated = 0;
  275.         BYTE CurrChar;
  276.  
  277.         while (SrceCnt < SourceLen)
  278.         {
  279.                 if (Source[SrceCnt] == (BYTE) REPLIC_FLAG_BYTE)
  280.                 {
  281.                         Target[TrgtCnt++] = (BYTE) REPLIC_FLAG_BYTE;
  282.                         Target[TrgtCnt++] = 0;
  283.                         ++SrceCnt;
  284.                 }
  285.                 else if (Source[SrceCnt] == (BYTE) REPLIC_FLAG_UINT)
  286.                 {
  287.                         Target[TrgtCnt++] = (BYTE) REPLIC_FLAG_UINT;
  288.                         Target[TrgtCnt++] = 0;
  289.                         Target[TrgtCnt++] = 0;
  290.                         ++SrceCnt;
  291.                 }
  292.                 else if ((Source[SrceCnt] == Source[SrceCnt+1]) && (Source[SrceCnt] == Source[SrceCnt+2]) && (SrceCnt + 2 < SourceLen))
  293.                 {
  294.                         Replicated = 1;
  295.                         CurrChar   = Source[SrceCnt++];
  296.                         while (Source[SrceCnt] == CurrChar)
  297.                         {
  298.                                 ++Replicated;
  299.                                 ++SrceCnt;
  300.                         }
  301.                         Target[TrgtCnt++] = (BYTE) (Replicated > 0xFF ? REPLIC_FLAG_UINT : REPLIC_FLAG_BYTE);
  302.                         if (Replicated > 0xFF)
  303.                         {
  304.                                 *((UINTARR) &Target[TrgtCnt]) = (UINT) Replicated;
  305.                                 TrgtCnt += sizeof(UINT);
  306.                         }
  307.                         else
  308.                         {
  309.                                 Target[TrgtCnt++] = (BYTE) Replicated;
  310.                         }
  311.                         Target[TrgtCnt++] = (BYTE) CurrChar;
  312.                 }
  313.                 else
  314.                 {
  315.                         Target[TrgtCnt++] = Source[SrceCnt++];
  316.                 }
  317.         }
  318.         return(TrgtCnt);
  319. }
  320.  
  321. /*****************************************************************************
  322. * Function: Decode()                                                         *
  323. * Syntax..: void Decode(STRING Source, UINT SourceLen, STRING Target)        *
  324. * Usage...: Decode a RLE string.                                             *
  325. * By......: David A Pearson                                                  *
  326. *****************************************************************************/
  327.  
  328. static void Decode(STRING Source, UINT SourceLen, STRING Target)
  329. {
  330.         UINT SrceCnt = 0;
  331.         UINT TrgtCnt = 0;
  332.         UINT RepCount;
  333.         UINT Replicate;
  334.         BYTE RepChar;
  335.  
  336.         while (SrceCnt < SourceLen)
  337.         {
  338.                 if (Source[SrceCnt] == (BYTE) REPLIC_FLAG_BYTE)
  339.                 {
  340.                         Replicate = (UINT) Source[++SrceCnt];
  341.                         if (Replicate)
  342.                         {
  343.                                 RepChar = Source[++SrceCnt];
  344.                                 for (RepCount = 0; RepCount < Replicate; RepCount++)
  345.                                 {
  346.                                         Target[TrgtCnt++] = RepChar;
  347.                                 }
  348.                         }
  349.                         else
  350.                         {
  351.                                 Target[TrgtCnt++] = (BYTE) REPLIC_FLAG_BYTE;
  352.                         }
  353.                 }
  354.                 else if (Source[SrceCnt] == (BYTE) REPLIC_FLAG_UINT)
  355.                 {
  356.                         Replicate = (UINT) *((UINTARR) &Source[++SrceCnt]);
  357.                         ++SrceCnt;
  358.                         if (Replicate)
  359.                         {
  360.                                 RepChar = Source[++SrceCnt];
  361.                                 for (RepCount = 0; RepCount < Replicate; RepCount++)
  362.                                 {
  363.                                         Target[TrgtCnt++] = RepChar;
  364.                                 }
  365.                         }
  366.                         else
  367.                         {
  368.                                 Target[TrgtCnt++] = (BYTE) REPLIC_FLAG_UINT;
  369.                         }
  370.                 }
  371.                 else
  372.                 {
  373.                         Target[TrgtCnt++] = Source[SrceCnt];
  374.                 }
  375.                 ++SrceCnt;
  376.         }
  377. }
  378.