?define IECLIM	32          /* initial escape counter upper limit */
                        		/*ПЕРВОНАЧАЛЬНЫЙ  Счетчик ВЕРХНЕГО ПРЕДЕЛА*/
?define NECLIM	5	          /* no escape expected counter limit */
?define NECTLIM	4
?define NECMAX	10	       /* no escape expected counter maximum */
?define MAXCLEN	4	       /* assumed to be 4 in several places */
?define NUMCON	10000	       /* number of contexts to remember */
				/*число запомненных ссылок*/
?define NUMCFB	32760	       /* number of frequencies to remember */
				/*число запомненых частот*/
?define ESCTH	3	       /* threshold for escape calculation */
?define MAXTVAL 8000	       /* maximum frequency value */
?define RFMINI  4	       /* initial refresh counter value */
?define HTLEN	16384	       /* length of hash table */
?define HTLEN1M HTLEN-1
?define NIL	0xffff	       /* NIL pointer in lists */
?define ESC	256	       /* escape symbol */
?define SIZE_HT HTLEN/8
?define SIZE_HP NUMCON/8
?define SIZE_ELP NUMCON/8
?define SIZE_ELN NUMCON/8
?define SIZE_CL  NUMCON/16
?define SIZE_CC  NUMCON/16
?define SIZE_FT  NUMCON/8
?define SIZE_FE  NUMCON/16
?define SIZE_RFM NUMCON/16
?define SIZE_CON NUMCON/4
?define SIZE_FC  NUMCFB/16+1
?define SIZE_FA  NUMCFB/8
?define SIZE_NB  NUMCFB/8
?define SIZE_HRT HTLEN/8
/* model data */
byte curcon[4];     /* current context */
byte cmask[256];      /* masked characters */
byte cmstack[256];    /* stack of cmask[] entries to clear */
byte nec;	      /* counter for no escape expected */
byte iec[MAXCLEN+1];  /* initial escape counters */
byte maxclen;	      /* current maximum length for context */
word ht=0;		      // hash table 8000H
word hp=0;		      // hash list pointer array
word con=0;       /* context array */
word cl=0;	      /* context length array */
word cc=0;	      /* character counts */
word ft=0;		      /* total frequency of context */
word fe=0;	      /* frequencys under ESCTH in context */
word elp=0;		      /* expire list previous pointer array */
word eln=0;		      /* expire list next pointer array */
word hrt=0;		      /* semi random data for hashing */
word elf,ell;		      /* first and last of expire list */
word rfm=NULL;	      /* refresh counter array */
word fa=NULL;		      /* frequency array */
word fc=NULL;	      /* character for frequency array */
word nb=NULL;		      /* next pointer for frequency array */
word fcfbl;		      /* pointer to free frequency blocks */
word nrel;		      /* context for frequency block release */
/* frequency mask system */
int cmsp;		      /* pointer to cmstack */
/* escape propability modifying system variables */
/* update stack variables */
word usp;		      /* stack pointer */
word cps[MAXCLEN+1]; 	      /* context pointers */
word as[MAXCLEN+1];	      /* indexes to frequency array */
/* miscalneous */
int dropcnt;		      /* counter for context len drop */
word hs[MAXCLEN+1]; 	      /* hash stack for context search */
int cslen;		      /* length of context to search */

HSC_UNPACK()
byte ncmax,ncmin;
{
	$PUSH SI
	$PUSH DI
	INIT_MODEL();
	AC_INIT_DECODE();
DW1:
	FIND_LONGEST();	//ВОЗВРОТ В SI
	AL=maxclen;
	AX++;
	ncmax=AL;
	IF(SI==NIL){
		ncmin=0;
		$JMP SHORT CO
	}
	ES=cl;
	AL=ESBYTE[SI];
	AX++;
	ncmin=AL;
	do{
		IF(cmsp!=0)decode_rest(SI);	//ВОЗВР DI
		ELSE decode_first(SI);	//ВОЗВР DI
		IF(DI!=ESC){
			EL_MOVEFRONT(SI);
			$JMP SHORT BW4
		}
		FIND_NEXT();	//ВОЗВР В SI
	}while(SI!=NIL);
CO:
	DI=257-cmsp;
	AC_THRESHOLD_VAL(DI);
	DX=0;
	BX=0;
	do{
		IF(DSBYTE[#cmask+BX]==0){
			$CMP DX,AX
			$JAE BW3
			DX++;
		}
		BX++;
	}while(BX<256);
BW3:
	$PUSH DX
	DX++;
	$PUSH DX
	$PUSH DI
	DI=BX;
	ac_in();

BW2:
	$CMP DI,ESC
	$JZ BW1
BW4:
	add_model(DI);
	$JMP SHORT TW
	do
	{
		ncmax--;
		AL=ncmax;
		make_context(AX,DI);
TW:
	} while ( ncmax>ncmin );
	AX=DI;
	ES=ob;
	BX=obl;
	ESBYTE[BX]=AL;
	obl++;
	IF(BX==BLOCKLEN-1)BWRITE();
	DSBYTE[#curcon+3]=DSBYTE[#curcon+2];
	DSBYTE[#curcon+2]=DSBYTE[#curcon+1];
	DSBYTE[#curcon+1]=curcon;
	curcon=DI;
	$JMP DW1
BW1:
	BWRITE();
	FREEBL(,#ht);
	$POP DI
	$POP SI
}

int decode_rest(word cp)	//возврат в DI
int tot,esc,cf;
{
	$PUSH SI
	DI=0;
	esc=DI;
	SI=cp;
	FS=fc;
	GS=fa;
	ES=nb;
	do{
		BL=FSBYTE[SI];
		BH=0;
		AL=DSBYTE[BX+#cmask];
		BX=SI;
		IF(AL==0){
			AX=GSWORD[BX+SI];
			DI+=AX;
			IF(AX<ESCTH)esc++;
		}
		SI=ESWORD[BX+SI];
TW:
	}while(SI!=NIL);
	esc=ADJ_ESCAPE_PROB(esc,cp);
	AX+=DI;
	AC_THRESHOLD_VAL();
	DX><AX;
	tot=DI;
	SI=cp;
	DI=0;
	ES=nb;
	do{
		BL=FSBYTE[SI];
		BH=0;
		AL=DSBYTE[BX+#cmask];
		BX=SI;
		IF(AL==0){
			AX=DI+GSWORD[BX+SI];
			IF(AX<=DX)DI><AX;
			ELSE{
				cf=GSWORD[BX+SI];
				$JMP SHORT BW
			}
		}
		SI=ESWORD[BX+SI];
	}while(SI!=NIL);
BW:
	AX=tot+esc;
	IF(SI!=NIL){
		$PUSH DI
		DI+=cf;
		$PUSH DI
		$PUSH AX
		ac_in();
		BX=cp;
		DI=BX;
		ES=ft;
		IF(ESWORD[BX+DI]==1){
			ES=cl;
			BL=ESBYTE[BX];
			BH=0;
			IF(DSBYTE[BX+#iec]!=0)DSBYTE[BX+#iec]--;
		}
		BX=usp;
		$ADD BX,BX
		DSWORD[BX+#as]=SI;
		DSWORD[BX+#cps]=DI;
		usp++;
		AL=FSBYTE[SI];
		AH=0;
		DI><AX;
		nec++;  /* must add test used in code_first() if NECMAX<5 ! */
  }
  ELSE{
		ac_in(tot,AX,AX);
		BX=cp;
		SI=BX;
		ES=ft;
		IF(ESWORD[BX+SI]==1){
			ES=cl;
			BL=ESBYTE[BX];
			BH=0;
			IF(DSBYTE[BX+#iec]<IECLIM)DSBYTE[BX+#iec]++;
		}
		DI=SI;
		ES=nb;
		do{
			BL=FSBYTE[SI];
			BH=0;
			AL=DSBYTE[BX+#cmask];
			IF(AL==0){
				CX=BX;
				BX=cmsp;
				DSBYTE[BX+#cmstack]=CL;
				cmsp++;
				BX=CX;
				DSBYTE[BX+#cmask]=1;
			}
			BX=SI;
			SI=ESWORD[BX+SI];
		}while(SI!=NIL);
		SI=usp;
		$ADD SI,SI
		DI|=0X8000;
		DSWORD[SI+#cps]=DI;
		DSWORD[SI+#as]=BX;	//sum holds last i !!
		usp++;
		DI=ESC;
	}
	$POP SI
}

int decode_first(word cp)
int tot,esc,cf;
byte sv;
{
	$PUSH SI
	ES=fe;
	SI=cp;
	AL=ESBYTE[SI];
	AH=0;
	esc=ADJ_ESCAPE_PROB(AX,SI);
	BX=SI;
	FS=ft;
	GS=nb;
	ES=fa;
	DI=0;
	tot=FSWORD[BX+SI];
	IF(nec>=NECLIM){
		sv=1;
		IF(tot<=NECTLIM)IF(nec==NECMAX)sv++;
		tot<<=sv;
		AC_THRESHOLD_VAL(tot+esc);
		AX=AX>>sv;
		DX><AX;
		do{
			BX=SI;
			AX=DI+ESWORD[BX+SI];
			IF(AX<=DX)DI><AX;
			ELSE{
				cf=ESWORD[BX+SI]<<sv;
				$JMP SHORT BW
			}
			SI=GSWORD[BX+SI];
		}while(SI!=NIL);
BW:
		DI<<=sv;
	}
  ELSE{
		AC_THRESHOLD_VAL(tot+esc);
		DX><AX;
		do{
			BX=SI;
			CX=ESWORD[BX+SI];
			AX=DI+CX;
			IF(AX<=DX)DI><AX;
			ELSE{
				cf=CX;
				$JMP SHORT BW1
			}
			SI=GSWORD[BX+SI];
		}while(SI!=NIL);
BW1:
	}
	usp=1;
	AX=tot+esc;
	IF(SI!=NIL){
		$PUSH DI
		DI+=cf;
		$PUSH DI
		$PUSH AX
		ac_in();
		DI=cp;
		BX=DI;
		IF(FSWORD[BX+DI]==1){
			ES=cl;
			BL=ESBYTE[BX];
			BH=0;
			IF(DSBYTE[BX+#iec]!=0)DSBYTE[BX+#iec]--;
		}
		as=SI;
		cps=DI;
		ES=fc;
		AL=ESBYTE[SI];
		AH=0;
		DI><AX;
		IF(nec<NECMAX)nec++;
	}
	ELSE{
		ac_in(tot,AX,AX);
		SI=cp;
		BX=SI;
		IF(FSWORD[BX+SI]==1){
			ES=cl;
			BL=ESBYTE[BX];
			BH=0;
			IF(DSBYTE[BX+#iec]<IECLIM)DSBYTE[BX+#iec]++;
		}
		ES=fc;
		DI=SI;
		do{
			AL=ESBYTE[SI];
			BX=cmsp;
			DSBYTE[BX+#cmstack]=AL;
			cmsp++;
			AH=0;
			BX=AX;
			DSBYTE[BX+#cmask]=1;
			BX=SI;
			SI=GSWORD[BX+SI];
TW:
		}while(SI!=NIL);
		DI|=0X8000;
		cps=DI;
		as=BX;
		DI=ESC;
		nec=0;
	}
	$POP SI
}

/********************** общие процедуры для распаковки и упаковки **********/

INIT_MODEL()
{
	IF(hrt==0){
		hrt=GETMEM(SIZE_HRT);
		$OR AX,AX
		$JZ ERR
		ES=AX;
		EAX=10;
		SI=0;
		DI=HTLEN+HTLEN;
		do{
			EBX=0X1F31D;
			$DB 0X66,0X99	//CDQ
			$DB	0X66,0XF7,0XFB	//IDIV EBX
			ECX><EAX;	//$PUSH EAX
			EAX><EDX;
			$DB 0X66,0X69,0XC0,0XA7,0X41,0,0	//IMUL EAX,0X41A7
			$DB 0X66,0X69,0XD1,0X14,0XB,0,0	//IMUL EDX,ECX,0XB14
			EAX-=EDX;
			$OR EAX,EAX
			$JLE M1
			$JMP SHORT M2
M1:
			EAX+=0X7FFFFFFF;
M2:
			BX=AX&HTLEN1M;
			ESWORD[SI]=BX;
			SI+=2;
		}while(SI<DI);
	}
	AX=SIZE_HT+SIZE_HP+SIZE_ELP+SIZE_ELN+SIZE_CL+SIZE_CC+SIZE_FT+SIZE_FE+SIZE_RFM+SIZE_CON+SIZE_FC+SIZE_FA+SIZE_NB;
	ht=GETMEM();
	$OR AX,AX
	IF(ZEROFLAG){
		FREEBL(,#hrt);
ERR:
		error(1,ERR_MEM,"init_model",AX);
	}
	hp=AX+SIZE_HT;
	elp=AX+SIZE_HP;
	eln=AX+SIZE_ELP;
	cl=AX+SIZE_ELN;
	cc=AX+SIZE_CL;
	ft=AX+SIZE_CC;
	fe=AX+SIZE_FT;
	rfm=AX+SIZE_FE;
	con=AX+SIZE_RFM;
	fc=AX+SIZE_CON;
	fa=AX+SIZE_FC;
	nb=AX+SIZE_FA;
	maxclen=MAXCLEN;
	ES=DS;
	AL=IECLIM>>1;
	iec=AL;
	DI=#iec;
	DI++;
	AX--;
	AH=AL;
	$STOSW
	$STOSW
	dropcnt=NUMCON/4;
	AX=0;
	nec=AL;
	nrel=AX;
	hs=AX;
	elf=AX;
	cmsp=AX;
	CX=HTLEN/2;
	DI=0;
	ES=ht;
	EAX=-1;
	$REPE
	$STOSD
	SI=0;
	BX=0;
	ES=eln;
	FS=elp;
	GS=cl;
	DS=nb;
	do{
		AX=SI;
		AX++;
		ESWORD[BX+SI]=AX;
		AX-=2;
		FSWORD[BX+SI]=AX;
		GSBYTE[SI]=0XFF;
		DSWORD[BX+SI]=NIL;
		BX++;
		SI++;
	}while(SI<NUMCON);
	DS=SS;
	ell=NUMCON-1;
	DX=NUMCON;
	BX=DX+DX;
	ES=nb;
	do{
		DX++;
		ESWORD[BX]=DX;
		BX+=2;
	}while(DX<NUMCFB-1);
	ESWORD[BX]=NIL;
	fcfbl=NUMCON;
	CX=64;
	DI=#cmask;
	ES=DS;
	EAX=0;
	$REPE
	$STOSD
	DSDWORD[#curcon]=EAX;
}

FREEBL()
{
	AX=DSWORD[BX];
	$OR AX,AX
	IF(NOTZEROFLAG){
		ES=AX;
		AH=0X49;
		$INT 0X21
		DSWORD[BX]=0;
	}
}

word FIND_LONGEST()
{
	BL=curcon;
	BH=0;
	$ADD BX,BX
	ES=hrt;
	DSWORD[#hs+2]=ESWORD[BX];
	BL=DSBYTE[#curcon+1];
	BH=0;
	BX=BX+AX&HTLEN1M;
	$ADD BX,BX
	DSWORD[#hs+4]=ESWORD[BX];
	BL=DSBYTE[#curcon+2];
	BH=0;
	BX=BX+AX&HTLEN1M;
	$ADD BX,BX
	DSWORD[#hs+6]=ESWORD[BX];
	BL=DSBYTE[#curcon+3];
	BH=0;
	BX=BX+AX&HTLEN1M;
	$ADD BX,BX
	DSWORD[#hs+8]=ESWORD[BX];
	usp=0;
	CX=cmsp;
	$JCXZ NW
	do{
		CX--;
		BX=CX;
		BL=DSBYTE[BX+#cmstack];
		BH=0;
		DSBYTE[BX+#cmask]=0;
		$OR CX,CX
	}while(NOTZEROFLAG);
NW:
	cmsp=CX;
	cslen=MAXCLEN+1;
  FIND_NEXT();
}

word FIND_NEXT()
{
	CX=cslen;
	CX--;
	SI=CX;
	$ADD SI,SI
	SI=SI+#hs;
	FS=cl;
	GS=con;
	$JMP SHORT TW
DW:
	BX=DSWORD[SI];	//взять символ из стека
	$ADD BX,BX
	ES=ht;
	DX=ESWORD[BX];	//получить хеш код для этого символа
	ES=hp;
	$JMP SHORT TW1
	do{
		BX=DX;
		AL=FSBYTE[BX];	//длина конкста для символа
		IF(AL==CL){
			$SHL BX,2
			$CMP CL,4
			$JA BS
			IF(ZEROFLAG){
		 		AL=GSBYTE[BX+3];
			 	IF(AL!=DSBYTE[#curcon+3])$JMP SHORT BS	//если символ не равен симв контекста
			}
			IF(CL>=3){
				AL=GSBYTE[BX+2];
				IF(AL!=DSBYTE[#curcon+2])$JMP SHORT BS
			}
			IF(CL>=2){
			 	AL=GSBYTE[BX+1];
			 	IF(AL!=DSBYTE[#curcon+1])$JMP SHORT BS
			}
			IF(CL>=1){
		 		AL=GSBYTE[BX];
			 	IF(AL!=curcon)$JMP SHORT BS
			}
			cslen=CX;	//максим длина совпадения контекста
			SI=DX;    //возвратить хеш код этого контекста
			$JMP SHORT EN
		}
BS:
		BX=DX;
		$ADD BX,BX
		DX=ESWORD[BX];	//получить новую точку контекста
TW1:
	}while(DX!=NIL);
	SI-=2;
	CX--;            //подготовить получение след символа
TW:
	$OR CX,CX
	$JNL DW
EW:
	SI=NIL;
EN:
}

word ADJ_ESCAPE_PROB()
{
	$PUSH SI
	$PUSH DI
	SI=BX;
	ES=ft;
	IF(ESWORD[BX+SI]==1){
		ES=cl;
		BL=ESBYTE[SI];
		BH=0;
		AX=1;
		IF(DSBYTE[BX+#iec]>=IECLIM>>1)AX++;
		$JMP SHORT EN
	}
	ES=cc;
	IF(ESBYTE[SI]==255){
		AX=1;
		$JMP SHORT EN
	}
	IF(ESBYTE[SI]!=0){
		CL=ESBYTE[SI];
		CH=0;
		CX++;
		DI=CX;
		$ADD CX,CX
		ES=ft;
		BX=ESWORD[BX+SI];
		IF(CX>=BX){
			$MUL CX
			$DIV BX
			IF(DI==BX){
				$SAR DI,1
				AX+=DI;
			}
		}
	}
	$OR AX,AX
	IF(ZEROFLAG)AX=1;
EN:
	$POP DI
	$POP SI
}

EL_MOVEFRONT()
{
	IF(AX!=elf){
		CX=AX;
		BX=CX;
		$ADD BX,BX
		ES=elp;
		FS=eln;
		IF(AX==ell)ell=ESWORD[BX];
		ELSE{
			AX=ESWORD[BX];
			BX=FSWORD[BX];
			$ADD BX,BX
			ESWORD[BX]=AX;
			BX=CX;
			$ADD BX,BX
			AX=FSWORD[BX];
			BX=ESWORD[BX];
			$ADD BX,BX
			FSWORD[BX]=AX;
		}
		BX=elf;
		$ADD BX,BX
		ESWORD[BX]=CX;
		BX=CX;
		$ADD BX,BX
		FSWORD[BX]=elf;
		elf=CX;
	}
}

add_model(int c)
{
	$PUSH SI
	$PUSH DI
	if(usp!=0){
		do{
			usp--;
			BX=usp;
			$ADD BX,BX
			DI=DSWORD[BX+#as];
			SI=DSWORD[BX+#cps];
			$TEST SI,0X8000
			IF(NOTZEROFLAG){
				SI&=0X7FFF;
				IF(fcfbl==NIL)RELEASE_CFBLOCKS();
				BX=DI;
				ES=nb;
				AX=fcfbl;
				ESWORD[BX+DI]=AX;
				DI><AX;
				BX=DI;
				fcfbl=ESWORD[BX+DI];
				ESWORD[BX+DI]=NIL;
				ES=fa;
				ESWORD[BX+DI]=1;
				ES=fc;
				ESBYTE[DI]=c;
				ES=cc;
				FS=fe;
				ESBYTE[SI]++;
				FSBYTE[SI]++;
			}
			ELSE{
				FS=fe;
				BX=DI;
				ES=fa;
				ESWORD[BX+DI]++;
				IF(ESWORD[BX+DI]==ESCTH)FSBYTE[SI]--;
			}
			ES=cc;
			AL=ESBYTE[SI];
			AH=0;
			AX++;
			BX=SI;
			GS=ft;
			DX=AX;
			GSWORD[BX+SI]++;
			AX=GSWORD[BX+SI];
			BX=DX;
			DX=0;
			$DIV BX
			BX=DI;
			ES=fa;
			DX=ESWORD[BX+DI];
			$ADD DX,DX
			ES=rfm;
			IF(DX<AX)ESBYTE[SI]--;
			ELSE IF(ESBYTE[SI]<RFMINI)ESBYTE[SI]++;
			AL=ESBYTE[SI];
			BX=SI;
			$OR AL,AL
			$JZ L301
			$CMP GSWORD[BX+SI],MAXTVAL
			$JB TW
L301:
			ESBYTE[SI]++;
			AX=0;
			GSWORD[BX+SI]=AX;
			FSBYTE[SI]=AL;
			DI=SI;
			$JMP SHORT TW1
			do{
				BX=DI;
				ES=fa;
				IF(ESWORD[BX+DI]>1){
					$SHR ESWORD[BX+DI],1
					AX=ESWORD[BX+DI];
					BX=SI;
					GSWORD[BX+SI]+=AX;
					IF(AX<ESCTH)FSBYTE[SI]++;
				}
				ELSE{
					BX=SI;
					GSWORD[BX+SI]++;
					FSBYTE[SI]++;
				}
				BX=DI;
				ES=nb;
				DI=ESWORD[BX+DI];
TW1:
			}while(DI!=NIL);
TW:
		}while(usp!=0);
	}
	$POP DI
	$POP SI
}

RELEASE_CFBLOCKS()
{
	$PUSH SI
	$PUSH DI
	GS=nb;
	DI=nrel;
	do{
		do{
			DI++;
			IF(DI==NUMCON)DI=0;
			BX=DI;
		}while(GSWORD[BX+DI]==NIL);
		CX=0;
		SI=#cps;
		do{
			AX=DSWORD[SI];
			AH&=0X7F;
			$CMP AX,DI
			$JZ BW
			SI+=2;
			CX++;
		}while(usp>=CX);
BW:
	}while(usp>=CX);
	BX=DI;
	CX=GSWORD[BX+DI];
	FS=fa;
	SI=FSWORD[BX+DI];
	$JMP SHORT TW1
	do{
		BX=CX;
		$ADD BX,BX
		IF(FSWORD[BX]<SI)SI=FSWORD[BX];
		CX=GSWORD[BX];
TW1:
	}while(CX!=NIL);
	SI++;
	BX=DI;
	IF(FSWORD[BX+DI]<SI){
		CX=GSWORD[BX+DI];
		do{
			BX=CX;
			$ADD BX,BX
			CX=GSWORD[BX];
			$CMP FSWORD[BX],SI
			$JNB BW2
		}while(CX!=NIL);
BW2:
		AX=FSWORD[BX];
		CX=BX;
		BX=DI;
		FSWORD[BX+DI]=AX;
		ES=fc;
		BX=CX;
		$SHR BX,1
		AL=ESBYTE[BX];
		ESBYTE[DI]=AL;
		BX=CX;
		DX=GSWORD[BX];
		GSWORD[BX]=fcfbl;
		BX=DI;
		fcfbl=GSWORD[BX+DI];
		GSWORD[BX+DI]=DX;
		IF(DX==NIL){
			AX=FSWORD[BX+DI];
			ES=ft;
			ESWORD[BX+DI]=AX;
			IF(AX<ESCTH)AL=1;
			ELSE AL=0;
			ES=fe;
			ESBYTE[DI]=AL;
			ES=cc;
			ESBYTE[DI]=0;
			$JMP EN
		}
	}
	AX=FSWORD[BX+DI]/SI;
	FSWORD[BX+DI]=AX;
	ES=ft;
	ESWORD[BX+DI]=AX;
	IF(AX<ESCTH)AL=1;
	ELSE AL=0;
	ES=fe;
	ESBYTE[BX]=AL;
	ES=cc;
	ESBYTE[BX]=0;
	DX=DI;
	CX=GSWORD[BX+DI];
	$JMP SHORT TW3
	do{
		BX=CX;
		$ADD BX,BX
		IF(FSWORD[BX]<SI){
			AX=GSWORD[BX];
			BX=DX;
			BX+=BX;
			GSWORD[BX]=AX;
			BX=CX;
			$ADD BX,BX
			GSWORD[BX]=fcfbl;
			fcfbl=CX;
		}
		ELSE{
			ES=cc;
			ESBYTE[DI]++;
			AX=FSWORD[BX]/SI;
			FSWORD[BX]=AX;
			BX=DI;
			ES=ft;
			ESWORD[BX+DI]+=AX;
			IF(AX<ESCTH){
				ES=fe;
				ESBYTE[DI]++;
			}
			DX=CX;
		}
		BX=DX;
		BX+=BX;
		CX=GSWORD[BX];
TW3:
	}while(CX!=NIL);
EN:
	nrel=DI;
	$POP DI
	$POP SI
}

word make_context(byte conlen;int c)
{
	$PUSH SI
	$PUSH DI
	SI=ell;
	BX=SI;
	ES=elp;
	ell=ESWORD[BX+SI];
	BX=elf;
	$ADD BX,BX
	ESWORD[BX]=SI;
	BX=SI;
	ES=eln;
	ESWORD[BX+SI]=elf;
	elf=SI;
	FS=cl;
	GS=hrt;
	if(FSBYTE[SI]!=0XFF){
		IF(FSBYTE[SI]==MAXCLEN){
			dropcnt--;
			IF(ZEROFLAG)maxclen=MAXCLEN-1;
		}
		CX=0;
		ES=con;
		DL=FSBYTE[SI];
		DI=SI;
		$SHL DI,2
		IF(DL!=0){
			BL=ESBYTE[DI];
			BH=0;
			$ADD BX,BX
			CX=GSWORD[BX];
		}
		IF(DL>1){
			BL=ESBYTE[DI+1];
			BH=0;
			BX=BX+CX&HTLEN1M;
			$ADD BX,BX
			CX=GSWORD[BX];
		}
		IF(DL>2){
			BL=ESBYTE[DI+2];
			BH=0;
			BX=BX+CX&HTLEN1M;
			$ADD BX,BX
			CX=GSWORD[BX];
		}
		IF(DL>3){
			BL=ESBYTE[DI+3];
			BH=0;
			BX=BX+CX&HTLEN1M;
			$ADD BX,BX
			CX=GSWORD[BX];
		}
		DI=CX;
		DI+=DI;
		ES=ht;
		IF(ESWORD[DI]==SI){
			BX=SI;
			ES=hp;
			AX=ESWORD[BX+SI];
			ES=ht;
			ESWORD[DI]=AX;
		}
		ELSE{
			CX=ESWORD[DI];
			ES=hp;
			do
			{
				BX=CX;
				BX+=BX;
				CX=ESWORD[BX];
			} while ( CX!=SI );
			CX=BX;	//???
			BX=SI;
			AX=ESWORD[BX+SI];
			BX=CX;
			ESWORD[BX]=AX;
		}
		BX=SI;
		ES=nb;
		IF(ESWORD[BX+SI]!=NIL){
			DX=ESWORD[BX+SI];
			do
			{
				BX=DX;
				BX+=BX;
				DX=ESWORD[BX];
			} while (DX!=NIL );
			ESWORD[BX]=fcfbl;
			BX=SI;
			fcfbl=ESWORD[BX+SI];
		}
	}
	BX=SI;
	ES=nb;
	ESWORD[BX+SI]=NIL;
	ES=fa;
	AX=1;
	ESWORD[BX+SI]=AX;
	ES=ft;
	ESWORD[BX+SI]=AX;
	ES=fe;
	ESBYTE[SI]=AL;
	ES=fc;
	ESBYTE[SI]=c;
	ES=rfm;
	ESBYTE[SI]=RFMINI;
	ES=cc;
	ESBYTE[SI]=0;
	FSBYTE[SI]=conlen;
	$SHL BX,2
	ES=con;
	ESBYTE[BX]=curcon;
	ESBYTE[BX+1]=DSBYTE[#curcon+1];
	ESBYTE[BX+2]=DSBYTE[#curcon+2];
	ESBYTE[BX+3]=DSBYTE[#curcon+3];
	DI=0;
	DL=conlen;
	IF(DL!=0){
		BL=curcon;
		BH=0;
		$ADD BX,BX
		DI=GSWORD[BX];
	}
	IF(DL>1){
		BL=DSBYTE[#curcon+1];
		BH=0;
		BX=BX+DI&HTLEN1M;
		$ADD BX,BX
		DI=GSWORD[BX];
	}
	IF(DL>2){
		BL=DSBYTE[#curcon+2];
		BH=0;
		BX=BX+DI&HTLEN1M;
		$ADD BX,BX
		DI=GSWORD[BX];
	}
	IF(DL>3){
		BL=DSBYTE[#curcon+3];
		BH=0;
		BX=BX+DI&HTLEN1M;
		$ADD BX,BX
		DI=GSWORD[BX];
	}
	$ADD DI,DI
	ES=ht;
	AX=ESWORD[DI];
	BX=SI;
	ES=hp;
	ESWORD[BX+SI]=AX;
	ES=ht;
	ESWORD[DI]=SI;
	AX=SI;
	$POP DI
	$POP SI
}

/************** HSC CODING ***************************/

HSC_PACK()
byte ncmin,ncmax;
{
	$PUSH SI
	$PUSH DI
	INIT_MODEL();
	AC_INIT_ENCODE();
	$JMP SHORT TW
DW:
	FIND_LONGEST();	//найти совпадающую цепочку	//ВОЗВРОТ В SI
	AL=maxclen;
	AX++;
	ncmax=AL;
	IF(SI==NIL){//нет совпадения
		ncmin=0;
		$JMP SHORT CO
	}
	ES=cl;
	AL=ESBYTE[SI];
	AX++;
	ncmin=AL;	//длина совпадающей цепочки
	do{
		IF(cmsp!=0)code_rest(SI,DI);
		ELSE code_first(SI,DI);
		$OR AX,AX
		IF(NOTZEROFLAG){
			EL_MOVEFRONT(SI);
			$JMP SHORT BW
 		}
		FIND_NEXT();	//ВОЗВР В SI
	}while(SI!=NIL);
CO:
	CODE_NEW();	//закодировать новый символ
BW:
	add_model(DI);
	$JMP SHORT TW2
	do{
		ncmax--;
		AL=ncmax;
		make_context(AX,DI);
TW2:
	}while(ncmax>ncmin);
	DSBYTE[#curcon+3]=DSBYTE[#curcon+2];
	DSBYTE[#curcon+2]=DSBYTE[#curcon+1];
	DSBYTE[#curcon+1]=curcon;
	curcon=DI;
TW:
	IF(ibl==0){
		BREAD();
		$CMP ibl,0
		$JZ LL
	}
	ibl--;
	ES=ib;
	BX=ibf;
	AL=ESBYTE[BX];
	AH=0;
	ibf++;
	DI><AX;
	$JMP DW
LL:
	FIND_LONGEST();	//ВОЗВРОТ В SI
	$JMP SHORT TW1
	do{
		IF(cmsp!=0)code_rest(SI,ESC);
		ELSE code_first(SI,ESC);
		FIND_NEXT();	//ВОЗВР В SI
TW1:
	}while(SI!=NIL);
	DI=ESC;
	CODE_NEW();
	AC_END_ENCODE();
	FREEBL(,#ht);
	$POP DI
	$POP SI
}

CODE_NEW()
{
	CX=0;
	DX=257-cmsp;
	BX=0;
	$JMP SHORT TW
DW:
	CL-=DSBYTE[BX+#cmask];
	$SBB CH,0
	CX++;
	BX++;
TW:
	$CMP BX,DI
	$JL DW
	AX=CX;
	AX++;
	ac_out(CX,AX,DX);
}

int code_rest(word cp;int c)
int cf;
word temp;
{
	$PUSH SI
	$PUSH DI
	CX=0;
	cf=CX;
	DI=CX;
	SI=CX;
	DX=cp;
	FS=fc;
	GS=nb;
	ES=fa;
	do{
		BX=DX;
		BL=FSBYTE[BX];
		BH=0;
		temp=BX;
		AL=DSBYTE[#cmask+BX];
		BX=DX;
		BX+=BX;
		$OR AL,AL
		IF(ZEROFLAG){
			IF(ESWORD[BX]<ESCTH)CX++;
			IF(cf==0){
				IF(temp==c){
					DI=SI;
					cf=ESWORD[BX];
					BX=usp;
					BX+=BX;
					DSWORD[BX+#as]=DX;
					BX=DX;
					BX+=BX;
				}
			}
			SI+=ESWORD[BX];
		}
		DX=GSWORD[BX];
	}while(DX!=NIL);
	ADJ_ESCAPE_PROB(CX,cp);
	CX=AX;
	IF(cf==0){
		AX+=SI;
		ac_out(SI,AX,AX);
		DX=cp;
		do{
			BX=DX;
			BL=FSBYTE[BX];
			CL=BL;
			BH=0;
			SI=BX;
			AL=DSBYTE[BX+#cmask];
			$OR AL,AL
			IF(ZEROFLAG){
				BX=cmsp;
				DSBYTE[BX+#cmstack]=CL;
				cmsp++;
				DSBYTE[SI+#cmask]=1;
			}
			DI=DX;
			BX=DX;
			DX=GSWORD[BX+DI];
		}while(DX!=NIL);
		BX=usp;
		BX+=BX;
		DSWORD[BX+#as]=DI;   //sum holds last i !
		BX=cp;
		SI=BX;
		ES=ft;
		IF(ESWORD[BX+SI]==1){
			ES=cl;
			BL=ESBYTE[BX];
			BH=0;
			IF(DSBYTE[BX+#iec]<IECLIM)DSBYTE[BX+#iec]++;
		}
		BX=usp;
		BX+=BX;
		SI|=0X8000;
		AX=0;
		$JMP SHORT EN
	}
	ac_out(DI,DI+cf,SI+CX);
	nec++;    //must add test used in code_first() if NECMAX<5 !
	BX=cp;
	SI=BX;
	ES=ft;
	IF(ESWORD[BX+SI]==1){
		ES=cl;
		BL=ESBYTE[BX];
		BH=0;
		IF(DSBYTE[BX+#iec]!=0)DSBYTE[BX+#iec]--;
	}
	BX=usp;
	BX+=BX;
	AX=1;
EN:
	DSWORD[BX+#cps]=SI;
	usp++;
	$POP DI
	$POP SI
}

int code_first(word cp;int c)
int tot;
{
	$PUSH SI
	$PUSH DI
	DI=0;
	SI=DI;
	CX=c;
	DX=cp;
	FS=fc;
	GS=nb;
	ES=fa;
	do{
		BX=DX;
		AL=FSBYTE[BX];
		AH=0;
		BX+=BX;
		IF(AX==CX){
			DI=ESWORD[BX];
			as=DX;
			$JMP SHORT BW
		}
		SI+=ESWORD[BX];
		DX=GSWORD[BX];
	}while(DX!=NIL);
BW:
	BX=cp;
	BX+=BX;
	ES=ft;
	tot=ESWORD[BX];
	ES=fe;
	BX=cp;
	AL=ESBYTE[BX];
	AH=0;
	ADJ_ESCAPE_PROB(AX,BX);
	DX=AX;
	IF(nec>=NECLIM){
		$CMP tot,NECTLIM
		$JG MEM1
		$CMP nec,NECMAX
		$JNZ MEM1
		$SHL tot,2
		SI<<=2;
		DI<<=2;
		$JMP SHORT MEM2
MEM1:
		tot<<=1;
		SI+=SI;
		DI+=DI;
MEM2:
	}
	usp=1;
	$OR DI,DI
	IF(ZEROFLAG){
		AX=tot;
		BX=AX+DX;
		ac_out(AX,BX,BX);
		DX=cp;
		do{
			SI=DX;
			AL=FSBYTE[SI];
			BX=cmsp;
			DSBYTE[BX+#cmstack]=AL;
			cmsp++;
			AH=0;
			BX=AX;
			DSBYTE[BX+#cmask]=1;
			BX=DX;
			DX=GSWORD[BX+SI];
		}while(DX!=NIL);
		as=SI;  /* sum holds last i ! */
		nec=0;
		BX=cp;
		SI=BX;
		ES=ft;
		IF(ESWORD[BX+SI]==1){
			ES=cl;
			BL=ESBYTE[BX];
			BH=0;
			IF(DSBYTE[BX+#iec]<IECLIM)DSBYTE[BX+#iec]++;
		}
		SI|=0X8000;
		AX=0;
		$JMP SHORT EN
	}
	DI+=SI;
	ac_out(SI,DI,tot+DX);
	IF(nec<NECMAX)nec++;
	BX=cp;
	SI=BX;
	ES=ft;
	IF(ESWORD[BX+SI]==1){
		ES=cl;
		BL=ESBYTE[BX];
		BH=0;
		IF(DSBYTE[BX+#iec]!=0)DSBYTE[BX+#iec]--;
	}
	AX=1;
EN:
	cps=SI;
	$POP DI
	$POP SI
}
