Path: utzoo!attcan!uunet!lll-winken!lll-lcc!lll-tis!helios.ee.lbl.gov!pasteur!agate!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.SHAR13_OF_19 Message-ID: <880624092735.02d@Ins.MRC.AdhocNet.CA> Date: 24 Jun 88 15:27:33 GMT Sender: daemon@ucbvax.BERKELEY.EDU Organization: The Internet Lines: 286 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} $ GoSub Convert_File $ Goto Part15