--- /dev/null
+#include "ted5.h"
+#pragma hdrstop
+
+long inlength,outlength;
+
+long counts[256];
+
+unsigned huffbits[256];
+unsigned long huffstring[256];
+
+huffnode nodearray[256]; // 256 nodes is worst case
+
+void CountBytes (unsigned char huge *start, long length);
+void Huffmanize (void);
+void OptimizeNodes (huffnode *table);
+long HuffCompress (unsigned char huge *source, long length,
+ unsigned char huge *dest);
+void HuffExpand (unsigned char huge *source, unsigned char huge *dest,
+ long length,huffnode *hufftable);
+void RLEWExpand (unsigned huge *source, unsigned huge *dest,long length,
+ unsigned rlewtag);
+long RLEWCompress (unsigned huge *source, long length, unsigned huge *dest,
+ unsigned rlewtag);
+
+/*
+=============================================================================
+
+ COMPRESSION SUBS
+
+=============================================================================
+*/
+
+
+/*
+======================
+=
+= CountBytes
+=
+= Adds the bytes in the pointed to area to the counts array
+= If this is the first segment, make sure counts is zerod
+=
+======================
+*/
+
+void CountBytes (unsigned char huge *start, long length)
+{
+ long i;
+
+ while (length--)
+ counts[*start++]++;
+}
+
+/*
+=======================
+=
+= FindLeast
+=
+= Returns the byte with the lowest counts value
+=
+=======================
+*/
+
+int FindLeast (void)
+{
+ int i,least;
+ long low = 0x7fffffff;
+
+ for (i=0;i<256;i++)
+ if (counts[i]<low)
+ {
+ low = counts[i];
+ least = i;
+ }
+
+ return least;
+}
+
+/*========================================================================*/
+
+/*
+==================
+=
+= TraceNode
+=
+= A recursive function that follows all leaves of nodearray and fills in
+= coding tables huffbits and huffstring.
+=
+==================
+*/
+
+void TraceNode (int nodenum,int numbits,unsigned long bitstring)
+{
+ unsigned bit0,bit1;
+
+ bit0 = nodearray[nodenum].bit0;
+ bit1 = nodearray[nodenum].bit1;
+
+ numbits++;
+
+ if (bit0 <256)
+ {
+ huffbits[bit0]=numbits;
+ huffstring[bit0]=bitstring; // just added a zero in front
+ if (huffbits[bit0]>24 && counts[bit0])
+ {
+ puts("Error: Huffman bit string went over 32 bits!");
+ exit(1);
+ }
+ }
+ else
+ TraceNode (bit0-256,numbits,bitstring);
+
+ if (bit1 <256)
+ {
+ huffbits[bit1]=numbits;
+ huffstring[bit1]=bitstring+ (1ul<<(numbits-1)); // add a one in front
+ if (huffbits[bit1]>24 && counts[bit1])
+ {
+ puts("Error: Huffman bit string went over 32 bits!");
+ exit(1);
+ }
+ }
+ else
+ TraceNode (bit1-256,numbits,bitstring+(1ul<<(numbits-1)));
+}
+
+/*
+=======================
+=
+= Huffmanize
+=
+= Takes the counts array and builds a huffman tree at
+= nodearray, then builds a codeing table.
+=
+=======================
+*/
+
+void Huffmanize (void)
+{
+
+//
+// codes are either bytes if <256 or nodearray numbers+256 if >=256
+//
+ unsigned value[256],code0,code1;
+//
+// probablilities are the number of times the code is hit or $ffffffff if
+// it is allready part of a higher node
+//
+ unsigned long prob[256],low,workprob;
+
+ int i,worknode,bitlength;
+ unsigned long bitstring;
+
+
+//
+// all possible leaves start out as bytes
+//
+ for (i=0;i<256;i++)
+ {
+ value[i]=i;
+ prob[i]=counts[i];
+ }
+
+//
+// start selecting the lowest probable leaves for the ends of the tree
+//
+
+ worknode = 0;
+ while (1) // break out of when all codes have been used
+ {
+ //
+ // find the two lowest probability codes
+ //
+
+ code0=0xffff;
+ low = 0x7ffffffff;
+ for (i=0;i<256;i++)
+ if (prob[i]<low)
+ {
+ code0 = i;
+ low = prob[i];
+ }
+
+ code1=0xffff;
+ low = 0x7fffffff;
+ for (i=0;i<256;i++)
+ if (prob[i]<low && i != code0)
+ {
+ code1 = i;
+ low = prob[i];
+ }
+
+ if (code1 == 0xffff)
+ {
+ if (value[code0]<256)
+ Quit("Wierdo huffman error: last code wasn't a node!");
+ if (value[code0]-256 != 254)
+ Quit("Wierdo huffman error: headnode wasn't 254!");
+ break;
+ }
+
+ //
+ // make code0 into a pointer to work
+ // remove code1 (make 0xffffffff prob)
+ //
+ nodearray[worknode].bit0 = value[code0];
+ nodearray[worknode].bit1 = value[code1];
+
+ value[code0] = 256 + worknode;
+ prob[code0] += prob[code1];
+ prob[code1] = 0xffffffff;
+ worknode++;
+ }
+
+//
+// done with tree, now build table recursively
+//
+
+ TraceNode (254,0,0);
+
+}
+
+/*========================================================================*/
+
+
+/*
+===============
+=
+= OptimizeNodes
+=
+= Goes through a huffman table and changes the 256-511 node numbers to the
+= actular address of the node. Must be called before HuffExpand
+=
+===============
+*/
+
+void OptimizeNodes (huffnode *table)
+{
+ huffnode *node;
+ int i;
+
+ node = table;
+
+ for (i=0;i<255;i++)
+ {
+ if (node->bit0 >= 256)
+ node->bit0 = (unsigned)(table+(node->bit0-256));
+ if (node->bit1 >= 256)
+ node->bit1 = (unsigned)(table+(node->bit1-256));
+ node++;
+ }
+}
+
+/*========================================================================*/
+
+#if 0
+/*
+======================
+=
+= HuffCompress
+=
+= The file must be counted with CountBytes and then Huffmanized first
+=
+======================
+*/
+
+long HuffCompress (unsigned char huge *source, long length,
+ unsigned char huge *dest)
+{
+ long outlength;
+ unsigned long string;
+ unsigned biton,bits;
+ unsigned char byte;
+
+ outlength = biton = 0;
+
+ *(long huge *)dest=0; // so bits can be or'd on
+
+ while (length--)
+ {
+ byte = *source++;
+ bits = huffbits[byte];
+ string = huffstring[byte] << biton;
+ *(long huge *)(dest+1)=0; // so bits can be or'd on
+ *(long huge *)dest |= string;
+ biton += bits; // advance this many bits
+ dest+= biton/8;
+ biton&=7; // stay under 8 shifts
+ outlength+=bits;
+ }
+
+ return (outlength+7)/8;
+}
+#endif
+
+
+/*========================================================================*/
+
+/*
+======================
+=
+= HuffExpand
+=
+======================
+*/
+
+void HuffExpand (unsigned char huge *source, unsigned char huge *dest,
+ long length,huffnode *hufftable)
+
+{
+ unsigned bit,byte,node,code;
+ unsigned sourceseg,sourceoff,destseg,destoff,endoff;
+ huffnode *nodeon,*headptr;
+
+ headptr = hufftable+254; // head node is allways node 254
+
+ source++; // normalize
+ source--;
+ dest++;
+ dest--;
+
+ sourceseg = FP_SEG(source);
+ sourceoff = FP_OFF(source);
+ destseg = FP_SEG(dest);
+ destoff = FP_OFF(dest);
+ endoff = destoff+length;
+
+//
+// ds:si source
+// es:di dest
+// ss:bx node pointer
+//
+
+ if (length <0xfff0)
+ {
+
+//--------------------------
+// expand less than 64k of data
+//--------------------------
+
+asm mov bx,[headptr]
+
+asm mov si,[sourceoff]
+asm mov di,[destoff]
+asm mov es,[destseg]
+asm mov ds,[sourceseg]
+asm mov ax,[endoff]
+
+asm mov ch,[si] // load first byte
+asm inc si
+asm mov cl,1
+
+expandshort:
+asm test ch,cl // bit set?
+asm jnz bit1short
+asm mov dx,[ss:bx] // take bit0 path from node
+asm shl cl,1 // advance to next bit position
+asm jc newbyteshort
+asm jnc sourceupshort
+
+bit1short:
+asm mov dx,[ss:bx+2] // take bit1 path
+asm shl cl,1 // advance to next bit position
+asm jnc sourceupshort
+
+newbyteshort:
+asm mov ch,[si] // load next byte
+asm inc si
+asm mov cl,1 // back to first bit
+
+sourceupshort:
+asm or dh,dh // if dx<256 its a byte, else move node
+asm jz storebyteshort
+asm mov bx,dx // next node = (huffnode *)code
+asm jmp expandshort
+
+storebyteshort:
+asm mov [es:di],dl
+asm inc di // write a decopmpressed byte out
+asm mov bx,[headptr] // back to the head node for next bit
+
+asm cmp di,ax // done?
+asm jne expandshort
+ }
+ else
+ {
+
+//--------------------------
+// expand more than 64k of data
+//--------------------------
+
+ length--;
+
+asm mov bx,[headptr]
+asm mov cl,1
+
+asm mov si,[sourceoff]
+asm mov di,[destoff]
+asm mov es,[destseg]
+asm mov ds,[sourceseg]
+
+asm lodsb // load first byte
+
+expand:
+asm test al,cl // bit set?
+asm jnz bit1
+asm mov dx,[ss:bx] // take bit0 path from node
+asm jmp gotcode
+bit1:
+asm mov dx,[ss:bx+2] // take bit1 path
+
+gotcode:
+asm shl cl,1 // advance to next bit position
+asm jnc sourceup
+asm lodsb
+asm cmp si,0x10 // normalize ds:si
+asm jb sinorm
+asm mov cx,ds
+asm inc cx
+asm mov ds,cx
+asm xor si,si
+sinorm:
+asm mov cl,1 // back to first bit
+
+sourceup:
+asm or dh,dh // if dx<256 its a byte, else move node
+asm jz storebyte
+asm mov bx,dx // next node = (huffnode *)code
+asm jmp expand
+
+storebyte:
+asm mov [es:di],dl
+asm inc di // write a decopmpressed byte out
+asm mov bx,[headptr] // back to the head node for next bit
+
+asm cmp di,0x10 // normalize es:di
+asm jb dinorm
+asm mov dx,es
+asm inc dx
+asm mov es,dx
+asm xor di,di
+dinorm:
+
+asm sub [WORD PTR ss:length],1
+asm jnc expand
+asm dec [WORD PTR ss:length+2]
+asm jns expand // when length = ffff ffff, done
+
+ }
+
+asm mov ax,ss
+asm mov ds,ax
+
+}
+
+
+//----------------- replaced by John C. ------------------------------------
+#if 0
+{
+ unsigned bit,byte,node,code;
+ unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff;
+ huffnode *nodeon,*headptr;
+
+ nodeon = headptr = hufftable+254; // head node is allways node 254
+
+ bit = 1;
+ byte = *source++;
+
+ while (length)
+ {
+ if (byte&bit)
+ code = nodeon->bit1;
+ else
+ code = nodeon->bit0;
+
+ bit<<=1;
+ if (bit==256)
+ {
+ bit=1;
+ byte = *source++;
+ }
+
+ if (code<256)
+ {
+ *dest++=code;
+ nodeon=headptr;
+ length--;
+ }
+ else
+ nodeon = (huffnode *)code;
+ }
+
+
+#if 0
+
+ source++; // normalize
+ source--;
+ dest++;
+ dest--;
+
+ sourceseg = FP_SEG(source);
+ sourceoff = FP_OFF(source);
+ destseg = FP_SEG(dest);
+ destoff = FP_OFF(dest);
+
+ length--;
+//
+// al = source byte
+// cl = bit in source (1,2,4,8,...)
+// dx = code
+//
+// ds:si source
+// es:di dest
+// ss:bx node pointer
+//
+
+asm mov bx,headptr
+asm mov cl,1
+
+asm mov si,sourceoff
+asm mov di,destoff
+asm mov es,destseg
+asm mov ds,sourceseg
+
+asm lodsb // load first byte
+
+expand:
+asm test al,cl // bit set?
+asm jnz bit1
+asm mov dx,ss:bx // take bit0 path from node
+asm jmp gotcode
+bit1:
+asm mov dx,ss:bx+2 // take bit1 path
+
+gotcode:
+asm shl cl,1 // advance to next bit position
+asm jnc sourceup
+asm lodsb
+asm cmp si,0x10 // normalize ds:si
+asm jb sinorm
+asm mov cx,ds
+asm inc cx
+asm mov ds,cx
+asm xor si,si
+sinorm:
+asm mov cl,1 // back to first bit
+
+sourceup:
+asm or dh,dh // if dx<256 its a byte, else move node
+asm jz storebyte
+asm mov bx,dx // next node = (huffnode *)code
+asm jmp expand
+
+storebyte:
+asm mov [es:di],dl
+asm inc di // write a decopmpressed byte out
+asm mov bx,headptr // back to the head node for next bit
+
+asm cmp di,0x10 // normalize es:di
+asm jb dinorm
+asm mov dx,es
+asm inc dx
+asm mov es,dx
+asm xor di,di
+dinorm:
+
+asm sub WORD PTR ss:length,1
+asm jnc expand
+asm dec WORD PTR ss:length+2
+asm jns expand // when length = ffff ffff, done
+
+asm mov ax,ss
+asm mov ds,ax
+
+#endif
+
+}
+#endif
+//---------------------------------------------------------------------------
+
+/*========================================================================*/
+
+/*
+======================
+=
+= RLEWcompress
+=
+======================
+*/
+
+long RLEWCompress (unsigned huge *source, long length, unsigned huge *dest,
+ unsigned rlewtag)
+{
+ long complength;
+ unsigned value,count,i;
+ unsigned huge *start,huge *end;
+
+ start = dest;
+
+ end = source + (length+1)/2;
+
+//
+// compress it
+//
+ do
+ {
+ count = 1;
+ value = *source++;
+ while (*source == value && source<end)
+ {
+ count++;
+ source++;
+ }
+ if (count>3 || value == rlewtag)
+ {
+ //
+ // send a tag / count / value string
+ //
+ *dest++ = rlewtag;
+ *dest++ = count;
+ *dest++ = value;
+ }
+ else
+ {
+ //
+ // send word without compressing
+ //
+ for (i=1;i<=count;i++)
+ *dest++ = value;
+ }
+
+ } while (source<end);
+
+ complength = 2*(dest-start);
+ return complength;
+}
+
+
+
+/*
+======================
+=
+= RLEWexpand
+=
+======================
+*/
+
+void RLEWExpand (unsigned huge *source, unsigned huge *dest,long length,
+ unsigned rlewtag)
+{
+ unsigned value,count,i;
+ unsigned huge *end;
+ unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff;
+
+
+//
+// expand it
+//
+#if 0
+ do
+ {
+ value = *source++;
+ if (value != rlewtag)
+ //
+ // uncompressed
+ //
+ *dest++=value;
+ else
+ {
+ //
+ // compressed string
+ //
+ count = *source++;
+ value = *source++;
+ for (i=1;i<=count;i++)
+ *dest++ = value;
+ }
+ } while (dest<end);
+#endif
+
+ end = dest + (length)/2;
+ sourceseg = FP_SEG(source);
+ sourceoff = FP_OFF(source);
+ destseg = FP_SEG(dest);
+ destoff = FP_OFF(dest);
+ endseg = FP_SEG(end);
+ endoff = FP_OFF(end);
+
+
+//
+// ax = source value
+// bx = tag value
+// cx = repeat counts
+// dx = scratch
+//
+// NOTE: A repeat count that produces 0xfff0 bytes can blow this!
+//
+
+asm mov bx,rlewtag
+asm mov si,sourceoff
+asm mov di,destoff
+asm mov es,destseg
+asm mov ds,sourceseg
+
+expand:
+asm lodsw
+asm cmp ax,bx
+asm je repeat
+asm stosw
+asm jmp next
+
+repeat:
+asm lodsw
+asm mov cx,ax // repeat count
+asm lodsw // repeat value
+asm rep stosw
+
+next:
+
+asm cmp si,0x10 // normalize ds:si
+asm jb sinorm
+asm mov ax,si
+asm shr ax,1
+asm shr ax,1
+asm shr ax,1
+asm shr ax,1
+asm mov dx,ds
+asm add dx,ax
+asm mov ds,dx
+asm and si,0xf
+sinorm:
+asm cmp di,0x10 // normalize es:di
+asm jb dinorm
+asm mov ax,di
+asm shr ax,1
+asm shr ax,1
+asm shr ax,1
+asm shr ax,1
+asm mov dx,es
+asm add dx,ax
+asm mov es,dx
+asm and di,0xf
+dinorm:
+
+asm cmp di,ss:endoff
+asm jne expand
+asm mov ax,es
+asm cmp ax,ss:endseg
+asm jb expand
+
+asm mov ax,ss
+asm mov ds,ax
+
+}
+
+
+/*
+======================
+=
+= RLEBcompress
+=
+======================
+*/
+
+long RLEBCompress (unsigned char huge *source, long length,
+ unsigned char huge *dest, unsigned char rlebtag)
+{
+ long complength;
+ unsigned char value,count;
+ unsigned i;
+ unsigned char huge *start,huge *end;
+
+ start = dest;
+
+ end = source+length;
+
+//
+// compress it
+//
+ do
+ {
+ count = 1;
+ value = *source++;
+ while (*source == value && source<end && count<255)
+ {
+ count++;
+ source++;
+ }
+ if (count>3 || value == rlebtag)
+ {
+ //
+ // send a tag / count / value string
+ //
+ *dest++ = rlebtag;
+ *dest++ = count;
+ *dest++ = value;
+ }
+ else
+ {
+ //
+ // send byte without compressing
+ //
+ for (i=1;i<=count;i++)
+ *dest++ = value;
+ }
+
+ } while (source<end);
+
+ complength = dest-start;
+ return complength;
+}
+
+
+
+/*
+======================
+=
+= RLEBExpand
+=
+======================
+*/
+
+void RLEBExpand (unsigned char huge *source, unsigned char huge *dest,
+ long length, unsigned char rlebtag)
+{
+ unsigned char value,count;
+ unsigned i;
+ unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff;
+ unsigned char huge *end;
+
+
+//
+// expand it
+//
+#if 0
+ do
+ {
+ value = *source++;
+ if (value != rlebtag)
+ //
+ // uncompressed
+ //
+ *dest++=value;
+ else
+ {
+ //
+ // compressed string
+ //
+ count = *source++;
+ value = *source++;
+ for (i=1;i<=count;i++)
+ *dest++ = value;
+ }
+ } while (dest<end);
+#endif
+
+
+ end = dest + (length);
+ sourceseg = FP_SEG(source);
+ sourceoff = FP_OFF(source);
+ destseg = FP_SEG(dest);
+ destoff = FP_OFF(dest);
+ endseg = FP_SEG(end);
+ endoff = FP_OFF(end);
+
+
+//
+// al = source value
+// bl = tag value
+// cl = repeat counts
+// dx = scratch
+//
+// NOTE: A repeat count that produces 0xfff0 bytes can blow this!
+//
+
+asm mov bx,WORD PTR rlebtag
+asm mov si,sourceoff
+asm mov di,destoff
+asm mov es,destseg
+asm mov ds,sourceseg
+asm xor ch,ch
+
+expand:
+asm lodsb
+asm cmp al,bl
+asm je repeat
+asm stosb
+asm jmp next
+
+repeat:
+asm lodsb
+asm mov cl,al // repeat count
+asm lodsb // repeat value
+asm rep stosb
+
+next:
+
+asm cmp si,0x10 // normalize ds:si
+asm jb sinorm
+asm mov ax,si
+asm shr ax,1
+asm shr ax,1
+asm shr ax,1
+asm shr ax,1
+asm mov dx,ds
+asm add dx,ax
+asm mov ds,dx
+asm and si,0xf
+sinorm:
+asm cmp di,0x10 // normalize es:di
+asm jb dinorm
+asm mov ax,di
+asm shr ax,1
+asm shr ax,1
+asm shr ax,1
+asm shr ax,1
+asm mov dx,es
+asm add dx,ax
+asm mov es,dx
+asm and di,0xf
+dinorm:
+
+asm cmp di,ss:endoff
+asm jne expand
+asm mov ax,es
+asm cmp ax,ss:endseg
+asm jb expand
+
+asm mov ax,ss
+asm mov ds,ax
+
+
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+
+#if 1
+/*
+==================
+=
+= CarmackCompress
+=
+= Compress a string of words
+=
+==================
+*/
+
+#define NEARTAG 0xa7
+#define FARTAG 0xa8
+
+long CarmackCompress (unsigned far *source,long length,
+ unsigned far *dest)
+{
+ unsigned ch,chhigh;
+ unsigned far *instart, far *inptr, far *inscan,
+ far *stopscan, far *outptr;
+ unsigned far *bestscan, beststring;
+ unsigned dist,maxstring,string,outlength;
+ unsigned nearrepeats,farrepeats;
+ unsigned dups,count;
+ unsigned newwords;
+
+//
+// this compression method produces a stream of words
+// If the words high byte is NEARTAG or FARTAG, the low byte is a word
+// copy count from the a position specified by either the next byte
+// or the next word, respectively. A copy count of 0 means to insert the
+// next byte as the low byte of the tag into the output
+//
+
+
+//
+// set up
+//
+ instart = inptr = source;
+ outptr = dest;
+
+ outlength = 0;
+ length = (length+1)/2;
+
+ nearrepeats = farrepeats = dups = 0;
+ count = 10;
+ newwords = 0;
+//
+// compress
+//
+ do
+ {
+ ch = *inptr;
+
+//
+// scan from start for patterns that match current data
+//
+ beststring = 0;
+ for (inscan = instart; inscan<inptr; inscan++)
+ {
+ if (*inscan != ch)
+ continue;
+
+ maxstring = inptr-inscan;
+ if (maxstring > length)
+ maxstring = length;
+ if (maxstring > 255)
+ maxstring = 255;
+
+ string = 1;
+ while (*(inscan+string) == *(inptr+string) && string<maxstring)
+ string++;
+
+ if (string >= beststring)
+ {
+ beststring = string;
+ bestscan = inscan;
+ }
+ }
+
+ if (beststring > 1 && inptr-bestscan <= 255)
+ {
+ // near string
+ *outptr++ = beststring + (NEARTAG*256);
+ *((unsigned char far *)outptr)++ = inptr-bestscan;
+ outlength += 3;
+ nearrepeats++;
+ inptr += beststring;
+ length -= beststring;
+ }
+ else if (beststring > 2)
+ {
+ // far string
+ *outptr++ = beststring + (FARTAG*256);
+ *outptr++ = bestscan-instart;
+ outlength += 4;
+ farrepeats++;
+ inptr += beststring;
+ length -= beststring;
+ }
+ else // no compression
+ {
+ chhigh = ch>>8;
+ if (chhigh == NEARTAG || chhigh == FARTAG)
+ {
+ // special case of encountering a
+ // tag word in the data stream
+ // send a length of 0, and follow it with the real low byte
+ *outptr++ = ch & 0xff00;
+ *((unsigned char far *)outptr)++ = ch&0xff;
+ outlength += 3;
+ dups++;
+ }
+ else
+ {
+ *outptr++ = ch;
+ outlength += 2;
+ }
+ inptr++;
+ length--;
+ newwords++;
+ }
+
+ if (!--count)
+ {
+ static char cc[2]="-";
+ cc[0]^='+'^'-';
+ print(cc);
+ sx--;
+
+ count = 10;
+
+ if (keydown[1])
+ {
+ while(keydown[1]);
+ return 0;
+ }
+ }
+ if (length<0)
+ Quit ("Length < 0!");
+ } while (length);
+ #if 0
+ printf ("%u near patterns\n",nearrepeats);
+ printf ("%u far patterns\n",farrepeats);
+ printf ("%u new words\n",newwords);
+ printf ("%u dups\n\n",dups);
+ #endif
+ return outlength;
+}
+#else
+
+
+
+/*
+==================
+=
+= CarmackCompress
+=
+= Compress a string of words
+=
+==================
+*/
+
+#define NEARTAG 0xa7
+#define FARTAG 0xa8
+
+long CarmackCompress (unsigned far *source,long length,
+ unsigned far *dest)
+{
+ unsigned wch,chhigh;
+ unsigned inptrx;
+ unsigned far *instart, far *inptr, far *inscan,
+ far *stopscan, far *outptr;
+ unsigned far *bestscan, beststring;
+ unsigned dist,maxstring,string,outlength;
+ unsigned nearrepeats,farrepeats;
+ unsigned dups,count;
+ unsigned newwords;
+
+//
+// this compression method produces a stream of words
+// If the words high byte is NEARTAG or FARTAG, the low byte is a word
+// copy count from the a position specified by either the next byte
+// or the next word, respectively. A copy count of 0 means to insert the
+// next byte as the low byte of the tag into the output
+//
+
+
+//
+// set up
+//
+ instart = inptr = bestscan = source;
+ outptr = dest;
+
+ outlength = 0;
+ length = (length+1)/2;
+
+ nearrepeats = farrepeats = dups = 0;
+ count = 10;
+ newwords = 0;
+//
+// compress
+//
+ do
+ {
+ wch = *inptr;
+ inptrx = FP_OFF(inptr)+2; // convienient for cmpsw
+
+//
+// scan from start for patterns that match current data
+//
+//================
+
+//
+// ax:
+// bx: beststring
+// cx: repeat counts
+// dx: holding spot for inscan repeat count
+// si: inptr
+// di: inscan
+//
+asm xor bx,bx // beststring = 0
+
+asm les di,[instart] // start looking for an identical string
+ // at the start of uncompressed text
+asm mov ax,es
+asm mov ds,ax // both DS and ES point to uncompressed data
+
+asm mov cx,WORD PTR [inptr]
+asm sub cx,di
+asm shr cx,1 // cx = words between inscan and inptr
+
+search:
+asm mov ax,[wch] // current uncompressed word
+asm repne scasw // search from DI for up to CX words for a
+ // first char match
+asm jcxz done // no more to search
+
+asm mov dx,cx // save off remaining repeat count
+ // the number in CX is the remaining words
+ // to search for a long pattern
+asm mov si,[inptrx] // SI is the current source data
+ // DI is the match in previously compressed
+ // data
+asm mov ax,di // save off DI so we can back up after scan
+asm repe cmpsw // decrement CX for each additional match
+asm jne ended
+asm dec cx // the search ended because of CX, not bad match
+ended:
+asm mov di,ax // back to original spot
+asm mov ax,dx
+asm sub ax,cx // AX is the total number of matching words
+asm cmp ax,bx // more chars than beststring?
+asm jb next
+asm mov bx,ax
+asm mov WORD PTR [bestscan],di // bestscan is start of the best match+2
+
+next:
+asm mov cx,dx // restore the remaining count
+asm jmp search
+
+done:
+asm mov ax,ss
+asm mov ds,ax
+asm mov [beststring],bx // save out the register variable
+asm dec bx
+asm sub WORD PTR [bestscan],2 // scasw incremented past start
+//================
+
+ if (beststring>length)
+ beststring = length;
+
+ if (beststring > 1 && inptr-bestscan <= 255)
+ {
+ // near string
+ *outptr++ = beststring + (NEARTAG*256);
+ *((unsigned char far *)outptr)++ = inptr-bestscan;
+ outlength += 3;
+ nearrepeats++;
+ inptr += beststring;
+ length -= beststring;
+ }
+ else if (beststring > 2)
+ {
+ // far string
+ *outptr++ = beststring + (FARTAG*256);
+ *outptr++ = bestscan-instart;
+ outlength += 4;
+ farrepeats++;
+ inptr += beststring;
+ length -= beststring;
+ }
+ else // no compression
+ {
+ chhigh = wch>>8;
+ if (chhigh == NEARTAG || chhigh == FARTAG)
+ {
+ // special case of encountering a
+ // tag word in the data stream
+ // send a length of 0, and follow it with the real low byte
+ *outptr++ = wch & 0xff00;
+ *((unsigned char far *)outptr)++ = wch&0xff;
+ outlength += 3;
+ dups++;
+ }
+ else
+ {
+ *outptr++ = wch;
+ outlength += 2;
+ }
+ inptr++;
+ length--;
+ newwords++;
+ }
+
+ if (!--count)
+ {
+ static char cc[2]="-";
+ cc[0]^='+'^'-';
+ print(cc);
+ sx--;
+
+ count = 10;
+
+ if (keydown[1])
+ {
+ while(keydown[1]);
+ return 0;
+ }
+ }
+ } while (length);
+#if 0
+ printf ("\r%u near patterns\n",nearrepeats);
+ printf ("%u far patterns\n",farrepeats);
+ printf ("%u new words\n",newwords);
+ printf ("%u dups\n\n",dups);
+#endif
+ return outlength;
+}
+#endif
+
+