/***************************** ASC **************************/
?define POSCODES 31200
?define SLCODES	16
?define LLCODES 48
?define LLLEN	16
?define LLBITS	4
?define LLMASK	LLLEN-1
?define LENCODES LLCODES*LLLEN+SLCODES	//784
?define LTCODES SLCODES+LLCODES
?define CTCODES 256
?define PTCODES 16
?define LTSTEP 8
?define MAXLT 750*LTSTEP
?define CTSTEP 1
?define MAXCT 1000*CTSTEP
?define PTSTEP 24
?define MAXPT 250*PTSTEP
?define TTSTEP 40
?define MAXTT 150*TTSTEP
?define TTORD 4
?define TTOMASK TTORD-1
?define LCUTOFF 3*LTSTEP
?define CCUTOFF 3*CTSTEP
?define CPLEN 8
?define LPLEN 4
?define MINLENLIM 16384 //4096
?define HSIZE	16384
?define HSIZE1M	HSIZE-1
?define HSHIFT	3

word numsim,vobpos;
word binb;
word bbf,bbl,inptr;
word ccnt_swd=0;
word ll=0,cr=0,best=0;
word b=0;
word swd_bpos,swd_mlf;
int swd_char;
word ltab[2*LTCODES];	//256
word eltab[2*LTCODES];	//256
word ptab[2*PTCODES];	//64
word ctab[2*CTCODES];	//1024
word ectab[2*CTCODES];	//1024
word ttab[TTORD*2];	//16
word ccnt,pmax,npt;
word ces;
word les;
word ttcon;
word h,l,v;
int s,gpat,ppat;
byte bufsim[3];

ASC_UNPACK()
word p,i;
{
	$PUSH SI
	$PUSH DI
	b=GETMEM(POSCODES/16+1);//место для словаря
	$OR AX,AX
	IF(ZEROFLAG)error(1,ERR_MEM,"swd_dinit",AX);
	bbf=0;
	MODEL_INIT();
	AC_INIT_DECODE();
DW1:
	SI=ttcon;
	$SHL SI,2
	SI=SI+#ttab;	//ttab[ttcon][0]
	AX=DSWORD[SI]+DSWORD[SI+2];
	DI=AX;	//ttab[ttcon][0]+ttab[ttcon][1]
	AX++;
	AC_THRESHOLD_VAL();
	CX=AX;	//tv
	BX=DSWORD[SI];
	if(BX>CX){
		AX=DI;
		AX++;
		ac_in(0,BX,AX);
		DSWORD[SI]+=TTSTEP;
		IF(DI>=MAXTT)TTSCALE(ttcon);
		$SHL ttcon,1
		ttcon&=TTOMASK;
		SI=DSWORD[#ctab+2];
		AX=SI+ces;
		AC_THRESHOLD_VAL();
		CX=AX;
		if(CX>=SI){
			AX=SI+ces;
			ac_in(SI,AX,AX);
			AC_THRESHOLD_VAL(DSWORD[#ectab+2]);
			CX=AX;
			SI=2;
			DX=0;
DW2:
			BX=SI;
			AX=DX;
			AX+=DSWORD[BX+SI+#ectab];
			IF(AX<=CX){
				DX=AX;	//DX+=DSWORD[BX+#ectab];
				SI++;
			}
			IF(SI>=CTCODES){
				SI-=CTCODES;
				$JMP SHORT BR1
			}
			SI+=SI;
			$JMP SHORT DW2
BR1:
			BX=SI+CTCODES;
			BX+=BX;
			AX=DX+DSWORD[BX+#ectab];
			ac_in(DX,AX,DSWORD[#ectab+2]);
			TZERO(#ectab,CTCODES,SI);
			IF(DSWORD[#ectab+2]!=0)ces+=CTSTEP;
			ELSE ces=0;
			IF(SI<CPLEN)AX=0;
			ELSE AX=SI-CPLEN;
			DI=AX;
			AX+=CTCODES;
			AX+=AX;
			i=AX+#ectab;
			do{
				BX=i;
				IF(DSWORD[BX]!=0)tupd(#ectab,CTCODES,MAXCT,1,DI);
				i+=2;
				DI++;
				AX=SI+CPLEN;
				IF(AX>=CTCODES-1)AX=CTCODES-1;
			}while(DI<AX);
		}
		ELSE{
			SI=2;
			DX=0;
DW3:
			BX=SI;
			AX=DX+DSWORD[BX+SI+#ctab];
			IF(AX<=CX){
				DX=AX;	//DX+=DSWORD[BX+#ctab];
				SI++;
			}
			IF(SI>=CTCODES){
				SI-=CTCODES;
				$JMP SHORT BR2
			}
			SI+=SI;
			$JMP SHORT DW3
BR2:
			BX=SI+CTCODES;
			$ADD BX,BX
			AX=DX+DSWORD[BX+#ctab];
			ac_in(DX,AX,DSWORD[#ctab+2]+ces);
		}
		tupd(#ctab,CTCODES,MAXCT,CTSTEP,SI);
		BX=SI+CTCODES;
		$ADD BX,BX
		IF(DSWORD[BX+#ctab]==CCUTOFF){
			IF(CTSTEP<ces)AX=CTSTEP;
			ELSE AX=ces-1;
			ces-=AX;
		}
	//запись в словарь и буфер SWD_DCHAR();
		AX=SI;
		ES=b;
		BX=bbf;
		ESBYTE[BX]=AL;
		bbf++;
		IF(BX==POSCODES-1)bbf=0;
		ES=ob;
		BX=obl;
		ESBYTE[BX]=AL;
		obl++;
		IF(BX==BLOCKLEN-1)BWRITE();

		IF(ccnt<POSCODES)ccnt++;
	}
	else if(DI>CX){
		AX=DI;
		AX++;
		ac_in(BX,DI,AX);
		DSWORD[SI+2]+=TTSTEP;
		IF(DI>=MAXTT)TTSCALE(ttcon);
		AX=ttcon;
		AX+=AX;
		AX|=1;
		AX&=TTOMASK;
		ttcon=AX;
		$JMP SHORT TW
		do{
			BX=npt;
			npt++;
			tupd(#ptab,PTCODES,MAXPT,PTSTEP,BX);
			pmax<<=1;
TW:
		}while (ccnt>pmax);
		AC_THRESHOLD_VAL(DSWORD[#ptab+2]);
		CX=AX;
		SI=2;//p=2;
		DX=0;
DW4:
		BX=SI;//p;
		AX=DX+DSWORD[BX+SI+#ptab];
		IF(AX<=CX){
			DX=AX;
			SI++;//p++;
		}
		IF(SI>=PTCODES){
			SI-=PTCODES;
			$JMP SHORT BW3
		}
		SI+=SI;//$SHL p,1
		$JMP SHORT DW4
BW3:
		BX=SI+PTCODES;
		$ADD BX,BX
		AX=DX+DSWORD[BX+#ptab];
		ac_in(DX,AX,DSWORD[#ptab+2]);
		tupd(#ptab,PTCODES,MAXPT,PTSTEP,SI);
		IF(SI>1){
			DI=1;
			do
			{
				DI+=DI;
				SI--;
			} while (NOTZEROFLAG);
			$SHR DI,1 //	i>>=1;
			AX=pmax;
			$SHR AX,1
			p=SI;
			IF(DI==AX)SI=ccnt-AX;
			ELSE SI=DI;
			p=AC_THRESHOLD_VAL(SI);
			$PUSH AX
			AX++;
			$PUSH AX
			$PUSH SI
			ac_in();
			p+=DI;
		}
		ELSE p=SI;
		AC_THRESHOLD_VAL(DSWORD[#ltab+2]+les);
		CX=AX;
		SI=2;
		AX=DSWORD[#ltab+SI];
		if(CX>=AX) {
			BX=AX+les;
			ac_in(AX,BX,BX);
			AC_THRESHOLD_VAL(DSWORD[#eltab+2]);
			CX=AX;
			DX=0;
DW5:
			BX=SI;
			AX=DX+DSWORD[BX+SI+#eltab];
			IF(AX<=CX){
				DX=AX;	//DX+=DSWORD[BX+SI+#eltab];
				SI++;
			}
			IF(SI>=LTCODES){
				SI-=LTCODES;
				$JMP SHORT BW4
			}
			SI+=SI;
			$JMP SHORT DW5
BW4:
			BX=SI+LTCODES;
			$ADD BX,BX
			AX=DX+DSWORD[BX+#eltab];
			ac_in(DX,AX,DSWORD[#eltab+2]);
			TZERO(#eltab,LTCODES,SI);
			IF(DSWORD[#eltab+2]!=0)les+=LTSTEP;
			ELSE les=0;
			IF(SI<LPLEN)AX=0;
			ELSE AX=SI-LPLEN;
			DI=AX;
			AX+=LTCODES;
			AX+=AX;
			i=AX+#eltab;
			$JMP SHORT TW2
			do{
				BX=i;
				IF(DSWORD[BX]!=0)tupd(#eltab,LTCODES,MAXLT,1,DI);
				i+=2;
				DI++;
TW2:
				AX=SI+LPLEN;
				IF(AX>=LTCODES-1)AX=LTCODES-1;
			}while(DI<AX);
		}
		ELSE{
			DX=0;
DW6:
			BX=SI;
			AX=DX+DSWORD[BX+SI+#ltab];
			IF(AX<=CX){
				DX=AX;	//DX+=DSWORD[BX+#ltab];
				SI++;
			}
			IF(SI>=LTCODES){
				SI-=LTCODES;
				$JMP SHORT BW5
			}
			SI+=SI;
			$JMP SHORT DW6
BW5:
			BX=SI+LTCODES;
			$ADD BX,BX
			AX=DX+DSWORD[BX+#ltab];
			ac_in(DX,AX,DSWORD[#ltab+2]+les);
		}
		tupd(#ltab,LTCODES,MAXLT,LTSTEP,SI);
		BX=SI+LTCODES;
		$ADD BX,BX
		IF(DSWORD[BX+#ltab]==LCUTOFF){
			IF(LTSTEP<les)AX=LTSTEP;
			ELSE{
				AX=les;
				AX--;
			}
			les-=AX;
		}
		IF(SI==SLCODES-1)SI=LENCODES-1;
		ELSE IF(SI>=SLCODES){
			AC_THRESHOLD_VAL(LLLEN);
			DI=AX;
			AX++;
			ac_in(DI,AX,LLLEN);
			SI-=SLCODES;
			$SHL SI,LLBITS
			SI=SI+DI+SLCODES-1;
		}
		SI+=3;
		IF(ccnt<POSCODES){
			ccnt+=SI;
			IF(ccnt>POSCODES)ccnt=POSCODES;
		}
		DI=p;
		IF(bbf>DI)AX=bbf;
	  ELSE AX=POSCODES+bbf;
		AX-=DI;
		AX--;
		DI=AX;
		FS=b;
		ES=ob;
		CX=SI;
		SI=bbf;
		BX=obl;
M2:
		AL=FSBYTE[DI];
		FSBYTE[SI]=AL;
		ESBYTE[BX]=AL;
		BX++;
		IF(BX==BLOCKLEN){
			obl=BX;
			$PUSH CX
			BWRITE();
			$POP CX
			BX=0;
		}
		SI++;
		IF(SI==POSCODES)SI=0;
		DI++;
		IF(DI==POSCODES)DI=0;
		$LOOP M2
		bbf=SI;
		obl=BX;

	}
	ELSE{
		$PUSH DI
		DI++;
		$PUSH DI
		$PUSH DI
		ac_in();
		BWRITE();
		FREEBL(,#b);
		$JMP SHORT EN
	}
	$JMP DW1
EN:
	$POP DI
	$POP SI
}

TZERO()
{
	CX+=BX;
	BX=CX;
	BX+=BX;
	BX+=AX;
	DX=DSWORD[BX];
	do{
		BX=CX;
		BX+=BX;
		BX+=AX;
		DSWORD[BX]-=DX;
		$SAR CX,1;
//	$OR CX,CX
	}while(NOTZEROFLAG);
}

word AC_THRESHOLD_VAL()
{
	DX=l;   //1/2
	CX=h-DX;//2/4
	BX=v-DX;//2/4
	BX++;   //1/2
	$MUL BX //13/16
	$SUB AX,1 //1/2
	$SBB DX,0 //1/2
	CX++;     //1/2
	IF(NOTZEROFLAG)$DIV CX	//24/22 +3+7
	ELSE AX=DX;
}

ac_in(word low,high,tot)
{
	AX=h;
	BX=l;
	AX-=BX;
	AX++;
	CX=AX;
	IF(NOTZEROFLAG)$MUL high
	ELSE DX=high;
	$CMP DX,tot
	IF(NOTZEROFLAG){
		$DIV tot
		AX--;
	}
	ELSE AX=-1;
	AX+=BX;
	h=AX;
	AX=CX;
	$OR AX,AX
	IF(NOTZEROFLAG)$MUL low
	ELSE DX=low;
	$DIV tot
	l+=AX;
	CX=gpat;
	ES=ib;
	$JMP SHORT TW
	do{
		$SHL l,1
		$SHL h,1
		$OR h,1
		$SHL v,1
		CX+=CX;
		$OR CL,CL
		IF(ZEROFLAG){
			IF(ibl==0){
				BREAD();
				IF(ibl==0){
					CX=0X100;
					$JMP SHORT EN1
				}
			}
			ibl--;
			BX=ibf;
			CL=ESBYTE[BX];
			CH=0;
			ibf++;
			CX+=CX;
			CL|=1;
EN1:
		}
		CH&=1;
		$OR DSBYTE[#v],CH
TW:
		AX=h^l&0X8000;
	}while(ZEROFLAG);
	$JMP SHORT TW2
	do{
		$SHL l,1
		l&=0x7fff;
		$SHL h,1
		h|=0x8001;
		$SHL v,1
		v^=0x8000;
		CX+=CX;
		$OR CL,CL
		IF(ZEROFLAG){
			IF(ibl==0){
				BREAD();
				IF(ibl==0){
					CX=0X100;
					$JMP SHORT EN2
				}
			}
			ibl--;
			BX=ibf;
			CL=ESBYTE[BX];
			CH=0;
			ibf++;
			CX+=CX;
			CL|=1;
EN2:
		}
		CH&=1;
		$OR DSBYTE[#v],CH
TW2:
		$TEST l,0X4000
		$JZ EN
		$TEST h,0X4000
	}while(ZEROFLAG);
EN:
	gpat=CX;
}

TTSCALE()
{
	$SHL AX,2
	BX=#ttab+AX;
	$SHR DSWORD[BX],1
	IF(ZEROFLAG)DSWORD[BX]=1;
	BX+=2;
	$SHR DSWORD[BX],1
	IF(ZEROFLAG)DSWORD[BX]=1;
}

MODEL_INIT()
{
	ces=CTSTEP;	//1
	les=LTSTEP;	//8
	ES=SS;
	$CLD
	EAX=0;
	ccnt=AX;
	ttcon=AX;

	DI=#ltab;
	CX=LTCODES;
	$REPE
	$STOSD
	DI=#ctab;
	CX=CTCODES;
	$REPE
	$STOSD
	DI=#ptab;
	CX=PTCODES;
	$REPE
	$STOSD

	AX++;
	npt=AX;
	pmax=AX;
	CX=TTORD*2;
	DI=#ttab;
	AX=TTSTEP;
	$REPE
	$STOSW
	TABINIT(#eltab,LTCODES,1);
	TABINIT(#ectab,CTCODES,1);
	tupd(#ptab,PTCODES,MAXPT,PTSTEP,0);
}

tupd(word t,tl,maxt,step,p)
{
	$PUSH SI
	$PUSH DI
	SI=tl;
	DI=t;
	CX=step;
	DX=p;
	DX+=SI;
	do{
		BX=DX;
		BX+=BX;
		$ADD DSWORD[BX+DI],CX
		$SHR DX,1
	}while(NOTZEROFLAG);
	IF(DSWORD[DI+2]>=maxt)TSCALE(DI,SI);
	$POP DI
	$POP SI
}

TSCALE()
//1-Таблица 2-1/2размера таблицы
{
	$PUSH SI
	$PUSH DI
	CX=SS;
	ES=CX;
	CX=BX+BX;
	CX--;
	SI=CX+CX+AX;
	DI=SI;
	do{
		IF(DSWORD[DI]>1)$SHR DSWORD[DI],1
		DI-=2;
		CX--;
	}while(CX>=BX);
	CX=BX;
	CX--;
	DI=CX+CX+AX;
	$STD
	loop(CX){
		$LODSW
		BX=AX;
		$LODSW
		AX+=BX;
		$STOSW
	}
	$CLD
	$POP DI
	$POP SI
}

TABINIT()
//заполняет таблицу 1-смещение таблицы 2-половина размера таблицы 3-значение
{
	$PUSH SI
	$PUSH DI
	DX=BX;	// 1/2 ТАБЛ
	BX=AX;	// OFFSET
	ES=DS;
	AX=CX;	// VAL
	CX=DX;
	DI=BX+DX+DX;
	SI=DI-2;
	$REPE
	$STOSW
	CX=DX;
	CX--;
	DI=SI;
	SI=SI+DX+DX;
	$STD
	loop(CX){
		$LODSW
		BX=AX;
		$LODSW
		AX+=BX;
		$STOSW
	}
	AX=0;
	$STOSW
	$CLD
	$POP DI
	$POP SI
}

AC_INIT_DECODE()
{
	h=0xffff;
	AX=0;
	l=AX;
	gpat=AX;
	IF(ibl==0){
		BREAD();
		IF(ibl==0){
			AL=-1;
			$JMP SHORT EN1
		}
	}
	ibl--;
	ES=ib;
	BX=ibf;
	AL=ESBYTE[BX];
	ibf++;
EN1:
	DSBYTE[#v+1]=AL;
	IF(ibl==0){
		BREAD();
		IF(ibl==0){
			AL=-1;
			$JMP SHORT EN
		}
	}
	ibl--;
	BX=ibf;
	AL=ESBYTE[BX];
	ibf++;
EN:
	DSBYTE[#v]=AL;
}

/************************ PACK *******************/
?define SIZE_LL   POSCODES+LENCODES+MINLEN-1/8+1
?define SIZE_BEST POSCODES+LENCODES+MINLEN-1/8+1
?define SIZE_CCNT HSIZE/8
?define SIZE_CR   HSIZE/8
?define SIZE_B    POSCODES+LENCODES+MINLEN+LENCODES+MINLEN-3/16+1

ASC_PACK()
word obpos,vswd_mlf;
{
	$PUSH SI
	$PUSH DI
	//создать буфера и заполнить словарь
	AX=SIZE_LL+SIZE_BEST+SIZE_CCNT+SIZE_CR+SIZE_B;
  ll=GETMEM();
	$OR AX,AX
	IF(ZEROFLAG)error(1,ERR_MEM,"swd_init",AX);
	best=AX+SIZE_LL;
  ccnt_swd=AX+SIZE_BEST;
  cr=AX+SIZE_CCNT;
  b=AX+SIZE_CR;
	CX=HSIZE/2;
	DI=0;
	ES=ccnt_swd;
	EAX=0;
	$REPE
	$STOSD
  binb=AX;
	bbf=AX;
//ЗАПОЛНИТЬ СЛОВАРЬ 786 байт
	BREAD();
	SI=0;
	DI=0;
	CX=LENCODES+MINLEN-1;
	IF(CX>=ibl)CX=ibl;
	ibf=CX;
	inptr=CX;
	bbl=CX;
	ibl-=CX;
	ES=b;
	DS=ib;
	$REPE
	$MOVSB
	DS=SS;
	swd_mlf=MINLEN-1;
  MODEL_INIT();	//заполнить таблицы
  AC_INIT_ENCODE();	//инициализировать таблицы и переменные
	SWD_FINDBEST();
	numsim=0;
	$JMP TW
DW:
	$CMP swd_mlf,MINLEN
	$JA L250	//длина совпадений больше 3
	$JNZ LL1
	IF(swd_bpos<MINLENLIM){	//растояние до повтора меньше 4096 и длина совпадения =3
L250:
		SI=swd_mlf;
		obpos=swd_bpos;
		SWD_FINDBEST();	//проверить цепочку для следующ символа
		IF(swd_mlf>SI){
			BX=numsim;
			$OR BX,BX
			IF(ZEROFLAG){
				vswd_mlf=SI;
				vobpos=obpos;
			}
			IF(BX<3)DSBYTE[#bufsim+BX]=DI;
			BX++;
			IF(BX==vswd_mlf){
				codepair(vswd_mlf,vobpos);
				BX=0;
			}
			numsim=BX;
		}
		ELSE{
			IF(numsim!=0)CODE_OST();
			SWD_ACCEPT();	//заполнить хэш кодом повторяющ цепочку
			codepair(SI,obpos);	//закодир повторную посл
			SWD_FINDBEST();
		}
	}
	ELSE{
LL1:
		IF(numsim!=0)CODE_OST();
		DSWORD[#swd_mlf]=MINLEN-1;
		codechar(DI);
		SWD_FINDBEST();
	}
TW:
	DI=swd_char;	//символ в тек полож
	$OR DI,DI
	$JL EN
	$JMP DW
EN:
	IF(numsim!=0)CODE_OST();
	BX=ttcon;
	$SHL BX,2
	CX=DSWORD[BX+#ttab]+DSWORD[BX+#ttab+2];
	AX=CX;
	AX++;
	ac_out(CX,AX,AX);
	AC_END_ENCODE();
	FREEBL(,#ll);
	$POP DI
	$POP SI
}

AC_INIT_ENCODE()
{
	AX=0;
	l=AX;
	s=AX;
	AX--;
	h=AX;
	ppat=1;
}

CODE_OST()
{
	$CMP numsim,MINLEN
	$JA L253	//длина совпадений больше 3
	$JNZ LL5
	IF(vobpos<MINLENLIM){	//растояние до повтора меньше 4096 и длина совпадения =3
L253:
		codepair(numsim,vobpos);
	}
	ELSE{
LL5:
		$PUSH SI
		SI=0;
		do
		{
			codechar(DSBYTE[#bufsim+SI]);
			SI++;
		} while (SI!=numsim );
		$POP SI
	}
	numsim=0;
}

codechar(int c)
//кодирует одиночный символ
word tot,cf,ii;
{
	$PUSH SI
	$PUSH DI
	DI=ttcon;
	$SHL DI,2
	SI=DSWORD[DI+#ttab]+DSWORD[DI+#ttab+2];
	CX=SI;
	CX++;
	ac_out(0,DSWORD[DI+#ttab],CX);
	DSWORD[DI+#ttab]+=TTSTEP;
	IF(SI>=MAXTT)TTSCALE(ttcon);
	ttcon=ttcon<<1&TTOMASK;
	DI=0;
	SI=c+CTCODES;
	BX=SI;
	cf=DSWORD[BX+SI+#ctab];
	$OR AX,AX
	if(ZEROFLAG){
		AX=DSWORD[#ctab+2];
		BX=AX+ces;
		ac_out(AX,BX,BX);
		do
		{
			BX=SI;
			$TEST SI,1
			IF(NOTZEROFLAG)DI+=DSWORD[BX+SI-2+#ectab];
			DSWORD[BX+SI+#ctab]+=CTSTEP;
			$SHR SI,1
		} while ( NOTZEROFLAG );
		IF(DSWORD[#ctab+2]>=MAXCT)TSCALE(#ctab,CTCODES);
		BX=c+CTCODES;
		BX+=BX;
		$PUSH DI
		DI+=DSWORD[#ectab+BX];
		$PUSH DI
		$PUSH DSWORD[#ectab+2];
		ac_out();
		TZERO(#ectab,CTCODES,c);
		IF(DSWORD[#ectab+2]!=0)ces+=CTSTEP;
		ELSE ces=0;
		$CMP c,CPLEN
		$JG L1
		AX=0;
		$JMP SHORT L2
L1:
		AX=c-CPLEN;
L2:
		SI=AX;
		DI=AX+CTCODES;
		DI+=DI;
		DI=DI+#ectab;
		AX=c+CPLEN;
		IF(AX>=CTCODES-1)AX=CTCODES-1;
		ii=AX;
		do{
			IF(DSWORD[DI]!=0)tupd(#ectab,CTCODES,MAXCT,1,SI);
			DI+=2;
			SI++;
		}while(SI<ii);
	}
	ELSE{
		tot=DSWORD[#ctab+2]+ces;
		do
		{
			BX=SI;
			$TEST SI,1
			IF(NOTZEROFLAG)DI+=DSWORD[BX+SI-2+#ctab];
			DSWORD[BX+SI+#ctab]+=CTSTEP;
			$SHR SI,1
		} while (NOTZEROFLAG);
		IF(DSWORD[#ctab+2]>=MAXCT)TSCALE(#ctab,CTCODES);
		$PUSH DI
		DI+=cf;
		$PUSH DI
		$PUSH tot
		ac_out();
  }
	BX=c+CTCODES;
	BX+=BX;
	IF(DSWORD[BX+#ctab]==CCUTOFF){
		IF(CTSTEP<ces)AX=CTSTEP;
		ELSE{
			AX=ces;
			AX--;
		}
		ces-=AX;
	}
	IF(ccnt<POSCODES)ccnt++;
	$POP DI
	$POP SI
}

ac_out(word low,high,tot)
{
	AX=h;
	BX=l;
	AX=AX-BX;	//интервал
	AX++;
	CX=AX;
	IF(NOTZEROFLAG)$MUL high
	ELSE DX=high;
	IF(DX!=tot){
		$DIV tot
		AX--;
	}
	ELSE AX=-1;
	AX+=BX;
	h=AX;	//верхн гр интервала
	AX><CX;
	$OR AX,AX
	IF(NOTZEROFLAG)$MUL low
	ELSE DX=low;
	$DIV tot
	l+=AX;	//НИЖН ГРАН ИНТЕРВАЛА
	$XOR CX,l
	CH&=0X80;
	if(ZEROFLAG){
		s++;
		AX=l;
		CX=ppat;
		ES=ob;
		$JMP SHORT TW2
		do{
			AX=l;
			$NOT AX
TW2:
			CX+=CX;
			AH&=0X80;
			IF(NOTZEROFLAG)CL|=1;
			$TEST CH,1
			IF(NOTZEROFLAG){
				BX=obl;
				ESBYTE[BX]=CL;
				obl++;
				IF(BX==BLOCKLEN-1)BWRITE();
				CX=1;
			}
			s--;
		}while(NOTZEROFLAG);
		$JMP SHORT TW
		do{
			AX=l;
			CX+=CX;
			AH&=0X80;
			IF(NOTZEROFLAG)CL|=1;
			$TEST CH,1
			IF(NOTZEROFLAG){
				BX=obl;
				ESBYTE[BX]=CL;
				obl++;
				IF(BX==BLOCKLEN-1)BWRITE();
				CX=1;
			}
TW:
			l<<=1;
			AX=h;
			AX+=AX;
			AL|=1;
			h=AX;
			AX^=l;
			$TEST AH,0X80
		}while(ZEROFLAG);
		ppat=CX;
	}
NN1:
	$JMP SHORT TW1
	do{
		s++;
		l<<=1;
		l&=0x7fff;
		h<<=1;
		h|=0x8001;
TW1:
		$TEST l,0X4000
		$JZ EN
		$TEST h,0X4000
	}while(ZEROFLAG);
EN:
}

codepair(int omlf,obpos)
word ii,j,lt,cf,tot;
{
	$PUSH SI
	$PUSH DI
	DI=ttcon;
	$SHL DI,2
	SI=DSWORD[DI+#ttab+2]+DSWORD[DI+#ttab];
	ac_out(DSWORD[DI+#ttab],SI,SI+1);
	DSWORD[DI+#ttab+2]+=TTSTEP;
	IF(SI>=MAXTT)TTSCALE(ttcon);
	ttcon=ttcon<<1|1&TTOMASK;
	$JMP SHORT TW
	do{
		BX=npt;
		npt++;
		tupd(#ptab,PTCODES,MAXPT,PTSTEP,BX);
		pmax<<=1;
TW:
	}while(ccnt>pmax);
	DI=obpos;
	CX=DI;
	BX=PTCODES;
	$JCXZ M1
	do{
		BX++;
		$SHR CX,1
	}while(NOTZEROFLAG);
M1:
	SI=BX;
	cf=DSWORD[BX+SI+#ptab];
	tot=DSWORD[#ptab+2];
	lt=0;
	do{
		BX=SI;
		$TEST SI,1
		IF(NOTZEROFLAG)lt+=DSWORD[BX+SI-2+#ptab];
		DSWORD[BX+SI+#ptab]+=PTSTEP;
		$SHR SI,1
	}while(NOTZEROFLAG);
	IF(DSWORD[#ptab+2]>=MAXPT)TSCALE(#ptab,PTCODES);
	AX=lt;
	ac_out(AX,AX+cf,tot);
	$CMP DI,1
	$JLE NW
	SI=0X8000;
	$JMP SHORT TW3
	do{
		$SHR SI,1
TW3:
		$TEST SI,DI
	}while(ZEROFLAG);
	AX=SI;
	$NOT AX
	DX=DI&AX;
	j=DX;
	BX=pmax;
	$SHR BX,1
	IF(SI!=BX){
		$PUSH DX
		DX++;
		$PUSH DX
		$PUSH SI
		ac_out();
	}
	ELSE{
		$PUSH DX
		DX++;
		$PUSH DX
		AX=ccnt-BX;
		$PUSH AX
		ac_out();
	}
NW:
	SI=omlf-MINLEN;
	IF(SI==LENCODES-1){
		SI=SLCODES-1;
		j=0xffff;
	}
	ELSE IF(SI<SLCODES-1)j=0xffff;
	ELSE{
		SI-=SLCODES;
		SI++;
		j=SI&LLMASK;
		SI>>=LLBITS;
		SI+=SLCODES;
	}
	lt=0;
	DI=SI+LTCODES;
	BX=DI;
	cf=DSWORD[#ltab+BX+DI];
	$OR AX,AX
	if(ZEROFLAG){
		AX=DSWORD[#ltab+2];
		BX=AX+les;
		ac_out(AX,BX,BX);
		do{
			BX=DI;
			$TEST DI,1
			IF(NOTZEROFLAG)lt+=DSWORD[BX+DI+#eltab-2];
			DSWORD[BX+DI+#ltab]+=LTSTEP;
			$SHR DI,1
		}while(NOTZEROFLAG);
		IF(DSWORD[#ltab+2]>=MAXLT)TSCALE(#ltab,LTCODES);
		BX=SI+LTCODES;
		BX+=BX;
		CX=lt+DSWORD[BX+#eltab];
		ac_out(lt,CX,DSWORD[#eltab+2]);
		TZERO(#eltab,LTCODES,SI);
		IF(DSWORD[#eltab+2]!=0)les+=LTSTEP;
		ELSE les=0;
		IF(SI<=LPLEN)DI=0;
		ELSE DI=SI-LPLEN;
		AX=SI+LPLEN;
		IF(AX>=LTCODES-1)AX=LTCODES-1;
		ii=AX;
		do{
			BX=DI+LTCODES;
			BX+=BX;
			IF(DSWORD[#eltab+BX]!=0)tupd(#eltab,LTCODES,MAXLT,1,DI);
			DI++;
		}while(DI<ii);
	}
	ELSE{
		tot=DSWORD[#ltab+2]+les;
		do{
			BX=DI;
			$TEST DI,1
			IF(NOTZEROFLAG)lt+=DSWORD[#ltab+BX+DI-2];
			DSWORD[BX+DI+#ltab]+=LTSTEP;
			$SHR DI,1
		}while (NOTZEROFLAG);
		IF(DSWORD[#ltab+2]>=MAXLT)TSCALE(#ltab,LTCODES);
		AX=lt;
		ac_out(AX,AX+cf,tot);
	}
	BX=SI+LTCODES;
	BX+=BX;
	IF(DSWORD[#ltab+BX]==LCUTOFF){
		IF(LTSTEP<les)AX=LTSTEP;
		ELSE{
			AX=les;
			AX--;
		}
		les-=AX;
	}
	IF(j!=0xffff){
		AX=j;
		$PUSH AX
		AX++;
		$PUSH AX
		$PUSH LLLEN
		ac_out();
	}
	IF(ccnt<POSCODES){
		ccnt+=omlf;
		IF(ccnt>POSCODES)ccnt=POSCODES;
  }
	$POP DI
	$POP SI
}

AC_END_ENCODE()
{
	s++;
	AX=l;
	CX=ppat;
	ES=ob;
mmm1:
	CX+=CX;
	AH&=0X40;
	IF(NOTZEROFLAG)CL|=1;
	$TEST CH,1
	IF(NOTZEROFLAG){
		BX=obl;
		ESBYTE[BX]=CL;
		obl++;
		IF(BX==BLOCKLEN-1)BWRITE();
		CX=1;
	}
	$SUB	s,1
	$JC	mmm2
	AX=l;
	$NOT AX
	$JMP SHORT mmm1;
mmm2:
	IF(CX==1)$JMP SHORT EN
	do{
		CX+=CX;
		$TEST CH,1
	}while(ZEROFLAG);
	BX=obl;
	ESBYTE[BX]=CL;
	obl++;
EN:
	BWRITE();
}
