mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			330 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
			
		
		
	
	
			330 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
IMPLEMENTATION MODULE HuffChan;
 | 
						|
 | 
						|
(*
 | 
						|
 This module shows how to redefine standard IO file functions. It provides
 | 
						|
 functions for reading and writing packed files opened in Raw mode.
 | 
						|
*)
 | 
						|
 | 
						|
IMPORT IOChan, IOLink, ChanConsts, IOConsts, SYSTEM, Strings;
 | 
						|
FROM Storage IMPORT ALLOCATE, DEALLOCATE;
 | 
						|
 | 
						|
CONST
 | 
						|
  rbldFrq = 512;	(* means: every 512 bytes rebuild table *)
 | 
						|
 | 
						|
TYPE
 | 
						|
  charTap  = POINTER TO ARRAY [0..MAX(INTEGER)-1] OF CHAR;
 | 
						|
  smbTp = POINTER TO smbT;
 | 
						|
 | 
						|
  smbT = RECORD			(* Huffman's tree *)
 | 
						|
    ch			: CHAR;
 | 
						|
    n			: CARDINAL; (* frequncy of char ch *)
 | 
						|
    left,right,next	: smbTp;
 | 
						|
  END;
 | 
						|
 | 
						|
  tblT = RECORD		(* bit sequence for code *)
 | 
						|
    vl		: CARDINAL;	(* bit sequence *)
 | 
						|
    cnt		: INTEGER;	(* it length *)
 | 
						|
  END;
 | 
						|
 | 
						|
  lclDataT = RECORD	(* channel's local data *)
 | 
						|
    tRoot 	: smbTp;
 | 
						|
    htbl	: ARRAY [0..255] OF tblT;     (* code -> bit sequence table *)
 | 
						|
    ftbl  	: ARRAY [0..255] OF CARDINAL; (* frequncey table *)
 | 
						|
    wBf,rb1,rb2	: CARDINAL;
 | 
						|
    wbc,rbc,smc	: INTEGER;
 | 
						|
    chid	: IOChan.ChanId;
 | 
						|
  END;
 | 
						|
  lclDataTp = POINTER TO lclDataT;
 | 
						|
  charp     = POINTER TO CHAR;
 | 
						|
 | 
						|
VAR
 | 
						|
  did	: IOLink.DeviceId;
 | 
						|
  ldt	: lclDataTp;
 | 
						|
 | 
						|
 | 
						|
PROCEDURE Shf(a:CARDINAL; b : INTEGER) : CARDINAL; (* shl a,b (or shr) *)
 | 
						|
BEGIN
 | 
						|
  RETURN SYSTEM.CAST(CARDINAL,SYSTEM.SHIFT(SYSTEM.CAST(BITSET,a),b));
 | 
						|
END Shf;
 | 
						|
 | 
						|
PROCEDURE wrDword(a:CARDINAL);	(* write 4 bytes to file *)
 | 
						|
BEGIN
 | 
						|
  IOChan.RawWrite(ldt^.chid,SYSTEM.ADR(a),4);
 | 
						|
END wrDword;
 | 
						|
 | 
						|
PROCEDURE rdDword() : CARDINAL;  (* read 4 bytes from file *)
 | 
						|
VAR
 | 
						|
  a,z : CARDINAL;
 | 
						|
BEGIN
 | 
						|
  a:=0;
 | 
						|
  IOChan.RawRead(ldt^.chid,SYSTEM.ADR(a),4,z);
 | 
						|
  RETURN a;
 | 
						|
END rdDword;
 | 
						|
 | 
						|
PROCEDURE wrSmb(ch : CHAR);	(* write bit sequence for code ch *)
 | 
						|
VAR
 | 
						|
  v,h : CARDINAL;
 | 
						|
  b,c : INTEGER;
 | 
						|
BEGIN
 | 
						|
  WITH ldt^ DO
 | 
						|
    v:=htbl[ORD(ch)].vl;
 | 
						|
    c:=htbl[ORD(ch)].cnt;
 | 
						|
    IF c+wbc<=32 THEN
 | 
						|
      wBf:=Shf(wBf,c);
 | 
						|
      wBf:=wBf+v;
 | 
						|
      wbc:=wbc+c;
 | 
						|
      IF wbc=32 THEN
 | 
						|
	wrDword(wBf);
 | 
						|
	wBf:=0; wbc:=0;
 | 
						|
      END;
 | 
						|
      RETURN;
 | 
						|
    END;
 | 
						|
    b:=c+wbc-32;
 | 
						|
    h:=Shf(v,-b);
 | 
						|
    wBf:=Shf(wBf,32-wbc)+h;
 | 
						|
    wrDword(wBf);
 | 
						|
    wBf:=v-Shf(h,b);
 | 
						|
    wbc:=b;
 | 
						|
  END;
 | 
						|
END wrSmb;
 | 
						|
 | 
						|
PROCEDURE flush();	(* write data in buffer *)
 | 
						|
BEGIN
 | 
						|
  WITH ldt^ DO
 | 
						|
    wBf:=Shf(wBf,32-wbc);
 | 
						|
    wrDword(wBf);
 | 
						|
  END;
 | 
						|
END flush;
 | 
						|
 | 
						|
PROCEDURE getSym() : CHAR; (* find code for first bit sequence in buffer *)
 | 
						|
VAR
 | 
						|
  t,i : CARDINAL;
 | 
						|
  b   : INTEGER;
 | 
						|
BEGIN
 | 
						|
  WITH ldt^ DO
 | 
						|
    IF rbc<=32 THEN
 | 
						|
      rb2:=rdDword();
 | 
						|
      t:=Shf(rb2,-rbc);
 | 
						|
      IF rbc=32 THEN t:=0; END;
 | 
						|
      rb1:=rb1+t;
 | 
						|
      rb2:=Shf(rb2,32-rbc);
 | 
						|
      IF rbc=0 THEN rb2:=0; END;
 | 
						|
      rbc:=rbc+32;
 | 
						|
    END;
 | 
						|
    FOR i:=0 TO 255 DO
 | 
						|
      t:=Shf(rb1,htbl[i].cnt-32);
 | 
						|
      IF t=htbl[i].vl THEN
 | 
						|
	rb1:=Shf(rb1,htbl[i].cnt);
 | 
						|
	b:=32-htbl[i].cnt;
 | 
						|
	t:=Shf(rb2,-b);
 | 
						|
	rb1:=rb1+t;
 | 
						|
	rb2:=Shf(rb2,32-b);
 | 
						|
	rbc:=rbc+b-32;
 | 
						|
	RETURN CHR(i);
 | 
						|
      END;
 | 
						|
    END;
 | 
						|
  END;
 | 
						|
END getSym;
 | 
						|
 | 
						|
PROCEDURE Insert(s : smbTp); (* insert new character in Huffman's tree *)
 | 
						|
VAR
 | 
						|
  cr : smbTp;
 | 
						|
BEGIN
 | 
						|
  WITH ldt^ DO
 | 
						|
    IF tRoot=NIL THEN
 | 
						|
      cr:=tRoot;
 | 
						|
      tRoot:=s;
 | 
						|
      s^.next:=cr;
 | 
						|
      RETURN;
 | 
						|
    ELSIF tRoot^.n<=s^.n THEN
 | 
						|
      cr:=tRoot;
 | 
						|
      tRoot:=s;
 | 
						|
      s^.next:=cr;
 | 
						|
      RETURN;
 | 
						|
    END;
 | 
						|
    cr:=tRoot;
 | 
						|
    WHILE (cr^.next<>NIL) & (cr^.next^.n>s^.n) DO
 | 
						|
      cr:=cr^.next;
 | 
						|
    END;
 | 
						|
    s^.next:=cr^.next;
 | 
						|
    cr^.next:=s;
 | 
						|
  END;
 | 
						|
END Insert;
 | 
						|
 | 
						|
PROCEDURE BuildTree(); (* build Huffman's tree *)
 | 
						|
VAR
 | 
						|
  cr,ocr,ncr : smbTp;
 | 
						|
BEGIN
 | 
						|
  WITH ldt^ DO
 | 
						|
    LOOP
 | 
						|
      ocr:=NIL; cr:=tRoot;
 | 
						|
      WHILE cr^.next^.next<>NIL  DO
 | 
						|
	ocr:=cr; cr:=cr^.next;
 | 
						|
      END;
 | 
						|
      NEW(ncr);
 | 
						|
      ncr^.n:=cr^.n+cr^.next^.n;
 | 
						|
      ncr^.left:=cr;
 | 
						|
      ncr^.right:=cr^.next;
 | 
						|
      IF ocr<>NIL THEN
 | 
						|
	ocr^.next:=NIL;
 | 
						|
	Insert(ncr);
 | 
						|
      ELSE
 | 
						|
	tRoot:=NIL;
 | 
						|
	Insert(ncr);
 | 
						|
	EXIT;
 | 
						|
      END;
 | 
						|
    END;
 | 
						|
  END;
 | 
						|
END BuildTree;
 | 
						|
 | 
						|
PROCEDURE BuildTable(cr: smbTp; vl,n: CARDINAL); (* build table: code -> bit sequence *)
 | 
						|
BEGIN
 | 
						|
  WITH ldt^ DO
 | 
						|
    IF cr^.left=NIL THEN
 | 
						|
      htbl[ORD(cr^.ch)].vl:=vl;
 | 
						|
      htbl[ORD(cr^.ch)].cnt:=n;
 | 
						|
      DISPOSE(cr);
 | 
						|
      RETURN;
 | 
						|
    END;
 | 
						|
    vl:=vl*2;
 | 
						|
    BuildTable(cr^.left,vl,n+1);
 | 
						|
    BuildTable(cr^.right,vl+1,n+1);
 | 
						|
    DISPOSE(cr);
 | 
						|
  END;
 | 
						|
END BuildTable;
 | 
						|
 | 
						|
PROCEDURE clcTab(); (* build code/bitseq. table from frequency table *)
 | 
						|
VAR
 | 
						|
  i : CARDINAL;
 | 
						|
  s : smbTp;
 | 
						|
BEGIN
 | 
						|
  WITH ldt^ DO
 | 
						|
    tRoot:=NIL;
 | 
						|
    FOR i:=0 TO 255 DO
 | 
						|
      NEW(s);
 | 
						|
      s^.ch:=CHR(i);
 | 
						|
      s^.n:=ftbl[i];
 | 
						|
      s^.left:=NIL; s^.right:=NIL; s^.next:=NIL;
 | 
						|
      Insert(s);
 | 
						|
    END;
 | 
						|
    BuildTree();
 | 
						|
    BuildTable(tRoot,0,0);
 | 
						|
  END;
 | 
						|
END clcTab;
 | 
						|
 | 
						|
PROCEDURE iniHuf();
 | 
						|
VAR
 | 
						|
  i : CARDINAL;
 | 
						|
BEGIN
 | 
						|
  WITH ldt^ DO
 | 
						|
    FOR i:=0 TO 255 DO
 | 
						|
      ftbl[i]:=1;
 | 
						|
    END;
 | 
						|
    wBf:=0; wbc:=0; rb1:=0; rb2:=0; rbc:=0;
 | 
						|
    smc:=0;
 | 
						|
    clcTab();
 | 
						|
  END;
 | 
						|
END iniHuf;
 | 
						|
 | 
						|
 | 
						|
PROCEDURE RawWrite(x: IOLink.DeviceTablePtr; buf: SYSTEM.ADDRESS;
 | 
						|
		len: CARDINAL);
 | 
						|
VAR
 | 
						|
  i	: CARDINAL;
 | 
						|
  ch	: CHAR;
 | 
						|
  cht	: charTap;
 | 
						|
BEGIN
 | 
						|
  IF len = 0 THEN RETURN; END;
 | 
						|
  ldt:=SYSTEM.CAST(lclDataTp,x^.cd);
 | 
						|
  cht:=SYSTEM.CAST(charTap,buf);
 | 
						|
  WITH ldt^ DO
 | 
						|
    FOR i:=0 TO len-1 DO
 | 
						|
      ch:=cht^[i];
 | 
						|
      wrSmb(ch);
 | 
						|
      IF ch = 377C THEN wrSmb(ch); END;
 | 
						|
      ftbl[ORD(ch)]:=ftbl[ORD(ch)]+1; smc:=smc+1;
 | 
						|
      IF smc=rbldFrq THEN
 | 
						|
	clcTab();
 | 
						|
	smc:=0;
 | 
						|
      END;
 | 
						|
    END;
 | 
						|
  END;
 | 
						|
  x^.result:=IOChan.ReadResult(ldt^.chid);
 | 
						|
END RawWrite;
 | 
						|
 | 
						|
PROCEDURE RawRead(x: IOLink.DeviceTablePtr; buf: SYSTEM.ADDRESS;
 | 
						|
		blen: CARDINAL; VAR len: CARDINAL);
 | 
						|
VAR
 | 
						|
  i	: CARDINAL;
 | 
						|
  cht	: charTap;
 | 
						|
  ch	: CHAR;
 | 
						|
BEGIN
 | 
						|
  ldt:=SYSTEM.CAST(lclDataTp,x^.cd);
 | 
						|
  cht:=SYSTEM.CAST(charTap,buf);
 | 
						|
  IF (blen=0) OR (x^.result<>IOConsts.allRight) THEN len:=0; RETURN; END;
 | 
						|
  WITH ldt^ DO
 | 
						|
    FOR i:=0 TO blen-1 DO
 | 
						|
      ch:=getSym();
 | 
						|
      IF ch = 377C THEN
 | 
						|
	ch:=getSym();
 | 
						|
	IF ch = 0C THEN
 | 
						|
	  x^.result:=IOConsts.endOfInput;
 | 
						|
	  len:=i; cht^[i]:=0C;
 | 
						|
	  RETURN;
 | 
						|
	END;
 | 
						|
      END;
 | 
						|
      cht^[i]:=ch;
 | 
						|
      ftbl[ORD(ch)]:=ftbl[ORD(ch)]+1; smc:=smc+1;
 | 
						|
      IF smc=rbldFrq THEN
 | 
						|
	clcTab();
 | 
						|
	smc:=0;
 | 
						|
      END;
 | 
						|
    END;
 | 
						|
    len:=blen;
 | 
						|
  END;
 | 
						|
END RawRead;
 | 
						|
 | 
						|
PROCEDURE CreateAlias(VAR cid: ChanId; io: ChanId; VAR res: OpenResults);
 | 
						|
VAR
 | 
						|
  x	: IOLink.DeviceTablePtr;
 | 
						|
BEGIN
 | 
						|
  IOLink.MakeChan(did,cid);
 | 
						|
  IF cid = IOChan.InvalidChan() THEN
 | 
						|
    res:=ChanConsts.outOfChans
 | 
						|
  ELSE
 | 
						|
    NEW(ldt);
 | 
						|
    IF ldt=NIL THEN
 | 
						|
      IOLink.UnMakeChan(did,cid);
 | 
						|
      res:=ChanConsts.outOfChans;
 | 
						|
      RETURN;
 | 
						|
    END;
 | 
						|
    x:=IOLink.DeviceTablePtrValue(cid,did,IOChan.notAvailable,"");
 | 
						|
    ldt^.chid:=io;
 | 
						|
    x^.cd:=ldt;
 | 
						|
    x^.doRawWrite:=RawWrite;
 | 
						|
    x^.doRawRead:=RawRead;
 | 
						|
    res:=ChanConsts.opened;
 | 
						|
    iniHuf();
 | 
						|
    x^.result:=IOConsts.allRight;
 | 
						|
  END;
 | 
						|
END CreateAlias;
 | 
						|
 | 
						|
PROCEDURE DeleteAlias(VAR cid: ChanId);
 | 
						|
VAR
 | 
						|
  x	: IOLink.DeviceTablePtr;
 | 
						|
BEGIN
 | 
						|
  x:=IOLink.DeviceTablePtrValue(cid,did,IOChan.notAvailable,"");
 | 
						|
  ldt:=x^.cd;
 | 
						|
  IF ldt^.rbc=0 THEN
 | 
						|
    wrSmb(377C);
 | 
						|
    wrSmb(0C);
 | 
						|
    flush();
 | 
						|
  END;
 | 
						|
  DISPOSE(ldt);
 | 
						|
  IOLink.UnMakeChan(did,cid);
 | 
						|
END DeleteAlias;
 | 
						|
 | 
						|
BEGIN
 | 
						|
  IOLink.AllocateDeviceId(did);
 | 
						|
END HuffChan.
 |