Some my thoughts about compress algorithm in NAV

Yaroslav_GaponovYaroslav_Gaponov Member Posts: 158
edited 2008-10-21 in NAV Tips & Tricks
Hi All

This my simple single-pass compress algorithm. Of course it not very effective, but it working... :D
OBJECT Codeunit 40000 Compress/Expand Mgt.
{
  OBJECT-PROPERTIES
  {
    Date=21-10-08;
    Time=[11:41:34 ];
    Modified=Yes;
    Version List=;
  }
  PROPERTIES
  {
    OnRun=BEGIN
            MESSAGE('Compress ration %1',compress('c:\\test.txt',STRSUBSTNO('c:\\test.arc'),TRUE));
            expand('c:\\test.arc','c:\\test2.txt',TRUE);
          END;

  }
  CODE
  {
    VAR
      abc@1000 : ARRAY [256] OF Text[1024];
      _max_len@1001 : Integer;
      _range_bits@1002 : Integer;
      _power2@1003 : BigInteger;
      _max_limits@1004 : Integer;
      _max_bits@1005 : Integer;

    LOCAL PROCEDURE bit2str@1(value@1000 : BigInteger;size@1001 : Integer) result : Text[64];
    VAR
      i@1002 : Integer;
    BEGIN
      FOR i := 1 TO size DO BEGIN
        result := FORMAT(value MOD 2) + result;
        value  := value DIV 2;
      END;
    END;

    LOCAL PROCEDURE str2bit@2(value@1000 : Text[64];size@1002 : Integer) result : BigInteger;
    VAR
      i@1001 : Integer;
    BEGIN
      FOR i := 1 TO size DO
        result := result * 2 + str2int(FORMAT(value[i]));
    END;

    LOCAL PROCEDURE str2int@3(value@1000 : Text[250]) result : BigInteger;
    BEGIN
      EVALUATE(result,value);
    END;

    LOCAL PROCEDURE initialize@4();
    VAR
      i@1000 : Integer;
    BEGIN

      // some parameters which depended from file...
      _max_len    := 11;
      _range_bits := 5;
      _max_limits := 1;
      _max_bits   := 6;


      FOR i := 0 TO 255 DO
        abc[i + 1] := bit2str(i,8);

      // spead up some calcs
      _power2 := POWER(2,_range_bits-1);
    END;

    PROCEDURE compress@5(input@1000 : Text[250];output@1001 : Text[250];progress@1010 : Boolean) Result : Decimal;
    VAR
      fin@1002 : File;
      fout@1003 : File;
      ch@1004 : Char;
      i@1005 : Integer;
      strbuf@1006 : Text[1024];
      chrbuf@1007 : Char;
      _result_len@1008 : BigInteger;
      chop@1009 : Boolean;
      w@1011 : Dialog;
      _limits@1012 : Integer;
    BEGIN

      fin.TEXTMODE(FALSE);
      fin.OPEN(input);

      fout.TEXTMODE(FALSE);
      fout.CREATE(output);

      initialize();

      IF progress THEN
        w.OPEN('Compress@1@@@@@@@@@@@@@@@@@@@@@@@@@@@\' +
               'Ratio   #2#########%');

      WHILE fin.POS < fin.LEN DO BEGIN

        IF fin.POS > 0 THEN
          Result := ROUND(_result_len * 100 / fin.POS,0.01);

        IF progress THEN BEGIN
          w.UPDATE(1,ROUND(10000 * fin.POS / fin.LEN,1));
          w.UPDATE(2,Result);
        END;

        fin.READ(ch);

        strbuf := strbuf + abc[ch + 1];

        WHILE STRLEN(strbuf) >= 8 DO BEGIN
          chrbuf := str2bit(COPYSTR(strbuf,1,8),8);
          strbuf := DELSTR(strbuf,1,8);
          fout.WRITE(chrbuf); _result_len := _result_len + 1;
        END;

        IF STRLEN(abc[ch + 1]) > _max_bits THEN
          _limits := _limits + 1;


          chop := FALSE;
          FOR i := 0 TO 255 DO
           IF STRLEN(abc[i + 1]) > _max_len THEN
             chop := TRUE;
          IF chop THEN initialize()
            ELSE

        IF _limits > _max_limits THEN BEGIN
          _limits := 0;

              FOR i := 0 TO 255 DO
               IF (i >= (ch - _power2 + 1)) AND (i <= (ch + _power2)) THEN
                  abc[i + 1] := '0' + bit2str(i - ch + _power2 - 1,_range_bits)
               ELSE
                  abc[i + 1] := '1' + abc[i + 1];

        END;

      END;

      IF STRLEN(strbuf) > 0 THEN BEGIN
        WHILE STRLEN(strbuf) < 8 DO
          strbuf := strbuf + '0';
        chrbuf := str2bit(strbuf,8);
        fout.WRITE(chrbuf); _result_len := _result_len + 1;
      END;

      fin.CLOSE;
      fout.CLOSE;

      IF progress THEN
        w.CLOSE;
    END;

    PROCEDURE expand@6(input@1001 : Text[250];output@1000 : Text[250];progress@1012 : Boolean);
    VAR
      fin@1007 : File;
      fout@1006 : File;
      ch@1005 : Char;
      i@1004 : Integer;
      strbuf@1003 : Text[1024];
      chrbuf@1002 : Char;
      j@1009 : Integer;
      found@1008 : Boolean;
      k@1010 : Integer;
      chop@1011 : Boolean;
      w@1013 : Dialog;
      _limits@1014 : Integer;
    BEGIN
      fin.TEXTMODE(FALSE);
      fin.OPEN(input);

      fout.TEXTMODE(FALSE);
      fout.CREATE(output);

      initialize();

      IF progress THEN
        w.OPEN('Extend@1@@@@@@@@@@@@@@@@@@@@@@@@@@@');


      WHILE fin.POS < fin.LEN DO BEGIN

        IF progress THEN
          w.UPDATE(1,ROUND(10000 * fin.POS / fin.LEN,1));

        fin.READ(ch);

        strbuf := strbuf + bit2str(ch,8);

        REPEAT
          found := FALSE;
          FOR j := 1 TO STRLEN(strbuf) DO
            FOR i := 0 TO 255 DO
              IF abc[i + 1] = COPYSTR(strbuf,1,j) THEN
                BEGIN
                  chrbuf := i;
                  fout.WRITE(chrbuf);
                  strbuf := DELSTR(strbuf,1,j);

                  IF STRLEN(abc[chrbuf + 1]) > _max_bits THEN
                    _limits := _limits + 1;


                    chop := FALSE;
                    FOR k := 0 TO 255 DO
                     IF STRLEN(abc[k + 1]) > _max_len THEN
                       chop := TRUE;
                    IF chop THEN initialize()
                     ELSE

                  IF _limits > _max_limits THEN BEGIN
                    _limits := 0;


                       FOR k := 0 TO 255 DO
                         IF (k >= (chrbuf - _power2 + 1)) AND (k <= (chrbuf + _power2)) THEN
                           abc[k + 1] := '0' + bit2str(k - chrbuf + _power2 - 1,_range_bits)
                         ELSE
                           abc[k + 1] := '1' + abc[k + 1];
                  END;

                  found := TRUE;
                END;
        UNTIL NOT found;

      END;

      fin.CLOSE;
      fout.CLOSE;

      IF progress THEN
        w.CLOSE;
    END;

    BEGIN
    {
      Compress/Extend Mgt. Codeunit  - Yaroslav Gaponov (yagaponov@yahoo.com)
      Single-pass compress algorithm.
    }
    END.
  }
}
Sign In or Register to comment.