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. } }