Path: utzoo!attcan!uunet!lll-winken!lll-tis!helios.ee.lbl.gov!pasteur!ucbvax!CORNELLC.CCS.CORNELL.EDU.BITNET!ewilts%Ins.MRC.AdhocNet.CA%Stasis.MRC.AdhocNet.CA%UNCAEDU.
From: ewilts%Ins.MRC.AdhocNet.CA%Stasis.MRC.AdhocNet.CA%UNCAEDU.@CORNELLC.CCS.CORNELL.EDU.BITNET (Ed Wilts)
Newsgroups: comp.os.vms
Subject: ARC_C.SHAR15_OF_19
Message-ID: <880624092839.02f@Ins.MRC.AdhocNet.CA>
Date: 24 Jun 88 15:28:37 GMT
Sender: daemon@ucbvax.BERKELEY.EDU
Organization: The Internet
Lines: 287
X /* k indexes "smaller" child (in heap of trees) of top */
X /* now make top index "smaller" of old top and smallest child */
X
X if(cmptrees(temp,list[k]))
X { list[top] = list[k];
X list[k] = temp;
X
X /* Make the changed list a heap */
X
X adjust(list,k,bottom); /* recursive */
X }
X }
X}
X
X/* Compare two trees, if a > b return true, else return false.
X Note comparison rules in previous comments.
X*/
X
Xstatic INT cmptrees(a,b)
XINT a, b; /* root nodes of trees */
X{
X if(node[a].weight > node[b].weight)
X return TRUE;
X if(node[a].weight == node[b].weight)
X if(node[a].tdepth > node[b].tdepth)
X return TRUE;
X return FALSE;
X}
X
X/* HUFFMAN ALGORITHM: develops the single element trees
X into a single binary tree by forming subtrees rooted in
X interior nodes having weights equal to the sum of weights of all
X their descendents and having depth counts indicating the
X depth of their longest paths.
X
X When all trees have been formed into a single tree satisfying
X the heap property (on weight, with depth as a tie breaker)
X then the binary code assigned to a leaf (value to be encoded)
X is then the series of left (0) and right (1)
X paths leading from the root to the leaf.
X Note that trees are removed from the heaped list by
X moving the last element over the top element and
X reheaping the shorter list.
X*/
X
Xstatic INT bld_tree(list,len)
XINT list[];
XINT len;
X{
X register INT freenode; /* next free node in tree */
X register struct nd *frnp; /* free node pointer */
X INT lch, rch; /* temps for left, right children */
X INT i;
X INT maxchar();
X
X /* Initialize index to next available (non-leaf) node.
X Lower numbered nodes correspond to leaves (data values).
X */
X
X freenode = NUMVALS;
X
X while(len>1)
X { /* Take from list two btrees with least weight
X and build an interior node pointing to them.
X This forms a new tree.
X */
X
X lch = list[0]; /* This one will be left child */
X
X /* delete top (least) tree from the list of trees */
X
X list[0] = list[--len];
X adjust(list,0,len-1);
X
X /* Take new top (least) tree. Reuse list slot later */
X
X rch = list[0]; /* This one will be right child */
X
X /* Form new tree from the two least trees using
X a free node as root. Put the new tree in the list.
X */
X
X frnp = &node[freenode]; /* address of next free node */
X list[0] = freenode++; /* put at top for now */
X frnp->lchild = lch;
X frnp->rchild = rch;
X frnp->weight = node[lch].weight + node[rch].weight;
X frnp->tdepth = 1 + maxchar(node[lch].tdepth, node[rch].tdepth);
X
X /* reheap list to get least tree at top */
X
X adjust(list,0,len-1);
X }
X dctreehd = list[0]; /* head of final tree */
X}
X
Xstatic INT maxchar(a,b)
X{
X return a>b ? a : b;
X}
X
Xstatic INT init_enc()
X{
X register INT i;
X
X /* Initialize encoding table */
X
X for(i=0; i> (16-level));
X return (level>16) ? ERROR : NULL;
X }
X
X else
X { if(l!=NOCHILD)
X { /* Clear path bit and continue deeper */
X
X tcode &= ~(1 << level);
X if(buildenc(level+1,l)==ERROR)
X return ERROR; /* pass back bad statuses */
X }
X if(r!=NOCHILD)
X { /* Set path bit and continue deeper */
X
X tcode |= 1 << level;
X if(buildenc(level+1,r)==ERROR)
X return ERROR; /* pass back bad statuses */
X }
X }
X return NULL; /* it worked if we reach here */
X}
X
Xstatic INT put_int(n,f) /* output an integer */
XINT n; /* integer to output */
XFILE *f; /* file to put it to */
X{
X putc_pak(n&0xff,f); /* first the low byte */
X putc_pak(n>>8,f); /* then the high byte */
X}
X
X/* Write out the header of the compressed file */
X
Xstatic long wrt_head(ob)
XFILE *ob;
X{
X register INT l,r;
X INT i, k;
X INT numnodes; /* # of nodes in simplified tree */
X
X /* Write out a simplified decoding tree. Only the interior
X nodes are written. When a child is a leaf index
X (representing a data value) it is recoded as
X -(index + 1) to distinguish it from interior indexes
X which are recoded as positive indexes in the new tree.
X
X Note that this tree will be empty for an empty file.
X */
X
X numnodes = dctreehd=need) /* if current code is big enough */
X { if(need==0)
X return rbyte;
X
X rbyte |= ccode << (8-need); /* take what we need */
X ccode >>= need; /* and leave the rest */
X cbitsrem -= need;
X return rbyte & 0xff;
X }
X
X /* We need more than current code */
X
X if(cbitsrem>0)
X { rbyte |= ccode << (8-need); /* take what there is */
X need -= cbitsrem;
X }
X
X /* No more bits in current code string */
X
X if(curin==SPEOF)
X { /* The end of file token has been encoded. If
X result byte has data return it and do EOF next time.
X */
X
X cbitsrem = 0;
X return (need==8) ? EOF : rbyte + 0;
X }
X
X /* Get an input byte */
X
X if((curin=getc_ncr(ib)) == EOF)
X curin = SPEOF; /* convenient for encoding */
X
X ccode = code[curin]; /* get the new byte's code */
X cbitsrem = codelen[curin];
X
X goto loop;
X}
X
X/* This routine is used to perform the actual squeeze operation. It can
X only be called after the file has been scanned. It returns the true
X length of the squeezed entry.
X*/
X
Xlong file_sq(f,t) /* squeeze a file into an archive */
XFILE *f; /* file to squeeze */
XFILE *t; /* archive to receive file */
X{
X INT c; /* one byte of squeezed data */
X long size; /* size after squeezing */
X
X size = wrt_head(t); /* write out the decode tree */
X
X while((c=gethuff(f))!=EOF)
X { putc_pak(c,t);
X size++;
X }
X
X return size; /* report true size */
X}
X
$ GoSub Convert_File
$ Goto Part16