123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- MODULE BorrowsWheeler; (** AUTHOR GF; PURPOSE "Borrows Wheeler Transformation"; *)
-
- CONST
- BlockSize* = 8*1024;
-
- TYPE
- MTF = OBJECT (* move to front *)
- TYPE
- Node = POINTER TO RECORD
- byte: CHAR; next: Node
- END;
- VAR
- alpha: Node;
-
-
- PROCEDURE Initialize;
- VAR n: Node; i: LONGINT;
- BEGIN
- alpha := NIL;
- FOR i := 0 TO 255 DO
- NEW( n ); n.next :=alpha; n.byte := CHR( 255 - i ); alpha := n
- END
- END Initialize;
- PROCEDURE Encode( VAR buf: ARRAY OF CHAR; len: LONGINT );
- VAR l, m: Node; i, k: LONGINT; ch: CHAR;
- BEGIN
- Initialize;
- FOR i := 0 TO len - 1 DO
- ch := buf[i];
- IF alpha.byte = ch THEN k := 0
- ELSE
- l := alpha; m := alpha.next; k := 1;
- WHILE m.byte # ch DO
- INC( k ); l := m; m := m.next
- END;
- l.next := m.next; m.next := alpha; alpha := m
- END;
- buf[i] := CHR( k )
- END
- END Encode;
-
- PROCEDURE Decode( VAR buf: ARRAY OF CHAR; len: LONGINT );
- VAR l, m: Node; i, c: LONGINT; ch: CHAR;
- BEGIN
- Initialize;
- FOR i := 0 TO len - 1 DO
- ch := buf[i];
- IF ch # 0X THEN
- c := ORD( ch ); l := alpha;
- WHILE c > 1 DO l := l.next; DEC( c ) END;
- m := l.next; l.next := m.next; m.next := alpha;
- alpha := m
- END;
- buf[i] := alpha.byte;
- END
- END Decode;
-
- END MTF;
-
- TYPE
- Encoder* = OBJECT
- TYPE
- Index = LONGINT;
- VAR
- mtf: MTF; length: LONGINT;
- sbuf: ARRAY 2*BlockSize OF CHAR;
- rotation: ARRAY BlockSize OF Index;
-
- PROCEDURE &New*;
- BEGIN
- NEW( mtf );
- END New;
-
-
- PROCEDURE Less( a, b: Index ): BOOLEAN;
- VAR i1, i2: Index; n, diff: LONGINT;
- BEGIN
- n := 0; i1 := rotation[a]; i2 := rotation[b];
- REPEAT
- diff := ORD( sbuf[i1]) - ORD( sbuf[i2] );
- INC( i1 ); INC( i2 ); INC( n );
- UNTIL (diff # 0) OR (n = length);
- RETURN diff < 0
- END Less;
-
- PROCEDURE Swap( a, b: Index );
- VAR tmp: Index;
- BEGIN
- tmp := rotation[a]; rotation[a] := rotation[b]; rotation[b] := tmp
- END Swap;
-
- PROCEDURE InsertSort( lo, hi: Index );
- VAR x, i, l, h, m, ip, tmp: Index;
- BEGIN
- x := lo + 1;
- WHILE x <= hi DO
- IF Less( x, x - 1 ) THEN
- (* find insert position ip *)
- ip := x - 1; l := lo; h := ip - 1;
- WHILE l <= h DO
- m := (l + h) DIV 2;
- IF Less( x, m ) THEN ip := m; h := m - 1 ELSE l := m + 1 END
- END;
- (* insert rotation[x] at position ip*)
- tmp := rotation[x]; i := x;
- REPEAT rotation[i] := rotation[i - 1]; DEC( i ) UNTIL i = ip;
- rotation[ip] := tmp;
- END;
- INC( x )
- END
- END InsertSort;
-
- PROCEDURE SortR( lo, hi: LONGINT );
- VAR i, j, m, n: LONGINT;
- BEGIN
- IF lo < hi THEN
- i := lo; j := hi; m := (lo + hi) DIV 2; n := hi - lo + 1;
- IF n = 2 THEN
- IF Less( hi, lo ) THEN
- Swap( lo, hi ) END;
- ELSIF n = 3 THEN
- IF Less( m, lo ) THEN Swap( lo, m ) END;
- IF Less( hi, m ) THEN
- Swap( m, hi );
- IF Less( m, lo ) THEN Swap( lo, m ) END
- END
- ELSIF n < 16 THEN
- InsertSort( lo, hi )
- ELSE
- (* QuickSort *)
- REPEAT
- WHILE Less( i, m ) DO INC( i ) END;
- WHILE Less( m, j ) DO DEC( j ) END;
- IF i <= j THEN
- IF m = i THEN m := j ELSIF m = j THEN m := i END;
- Swap( i, j ); INC( i ); DEC( j )
- END
- UNTIL i > j;
- SortR( lo, j ); SortR( i, hi )
- END
- END
- END SortR;
-
- PROCEDURE EncodeBlock*( VAR buf: ARRAY OF CHAR; len: LONGINT ): LONGINT;
- VAR i, index: LONGINT;
- BEGIN
- ASSERT( len <= BlockSize ); length := len;
- FOR i := 0 TO length - 1 DO sbuf[i] := buf[i]; sbuf[i+length] := buf[i] END;
- FOR i := 0 TO length - 1 DO rotation[i] := INTEGER( i ) END;
- SortR( 0, length - 1 );
- (* find index of the original row *)
- index := 0; WHILE rotation[index] # 0 DO INC( index ) END;
- (* replace buf by column L *)
- FOR i := 0 TO length -1 DO buf[i] := sbuf[rotation[i] + length - 1] END;
- mtf.Encode( buf, length );
- RETURN index
- END EncodeBlock;
-
- END Encoder;
-
-
- TYPE
- Decoder* = OBJECT
- TYPE
- Index = LONGINT;
- VAR
- length, index: LONGINT;
- mtf: MTF;
- f: ARRAY BlockSize OF CHAR;
-
- PROCEDURE &New*;
- BEGIN
- NEW( mtf );
- END New;
-
-
- PROCEDURE Swap( a, b: Index );
- VAR tmp: CHAR;
- BEGIN
- tmp := f[a]; f[a] := f[b]; f[b] := tmp
- END Swap;
-
- PROCEDURE InsertSort( lo, hi: Index );
- VAR x, i, l, h, m, ip: Index; tmp: CHAR;
- BEGIN
- x := lo + 1;
- WHILE x <= hi DO
- IF f[x] < f[x - 1] THEN
- (* find insert position ip *)
- ip := x - 1; l := lo; h := ip - 1;
- WHILE l <= h DO
- m := (l + h) DIV 2;
- IF f[x] < f[m] THEN ip := m; h := m - 1 ELSE l := m + 1 END
- END;
- (* insert f[x] at position ip*)
- tmp := f[x]; i := x;
- REPEAT f[i] := f[i - 1]; DEC( i ) UNTIL i = ip;
- f[ip] := tmp;
- END;
- INC( x )
- END
- END InsertSort;
-
- PROCEDURE SortF( lo, hi: Index );
- VAR i, j, m: Index; n: LONGINT;
- BEGIN
- IF lo < hi THEN
- i := lo; j := hi; m := (lo + hi) DIV 2; n := hi - lo + 1;
- IF n = 2 THEN
- IF f[hi] < f[lo] THEN Swap( lo, hi ) END;
- ELSIF n = 3 THEN
- IF f[m] < f[lo] THEN Swap( lo, m ) END;
- IF f[hi] < f[m] THEN
- Swap( m, hi );
- IF f[m] < f[lo] THEN Swap( lo, m ) END
- END
- ELSIF n < 16 THEN
- InsertSort( lo, hi )
- ELSE
- (* QuickSort *)
- REPEAT
- WHILE f[i] < f[m] DO INC( i ) END;
- WHILE f[m] < f[j] DO DEC( j ) END;
- IF i <= j THEN
- IF m = i THEN m := j ELSIF m = j THEN m := i END;
- Swap( i, j ); INC( i ); DEC( j )
- END
- UNTIL i > j;
- SortF( lo, j ); SortF( i, hi )
- END
- END
- END SortF;
-
-
- PROCEDURE DecodeBlock*( VAR buf: ARRAY OF CHAR; len, ind: LONGINT );
- VAR
- i, j, n: LONGINT; ch: CHAR;
- l: POINTER TO ARRAY OF CHAR;
- lc, fc: POINTER TO ARRAY OF LONGINT;
- xn: ARRAY 256 OF LONGINT;
- BEGIN
- ASSERT( len <= BlockSize ); length := len; index := ind;
- mtf.Decode( buf, len );
- NEW( l, length ); NEW( lc, length ); NEW( fc, length );
- FOR i := 0 TO 255 DO xn[i] := 0 END;
- FOR i := 0 TO length - 1 DO
- l[i] := buf[i]; f[i] := buf[i];
- j := ORD( l[i] ); lc[i] := xn[j]; INC( xn[j] )
- END;
- SortF( 0, length - 1 );
- FOR i := 0 TO 255 DO xn[i] := 0 END;
- FOR i := 0 TO length - 1 DO
- j := ORD( f[i] ); fc[i] := xn[j]; INC( xn[j] )
- END;
- FOR i := 0 TO length - 1 DO
- ch := f[index]; n := fc[index]; buf[i] := ch; index := 0;
- WHILE (l[index] # ch) OR (lc[index] # n) DO INC( index ) END
- END;
- END DecodeBlock;
-
- END Decoder;
-
-
- END BorrowsWheeler.
|