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