/**************************************************************************** * Function : AssignCanonicalCode * Description: This function accepts a list of symbols sorted by their * code lengths, and assigns a canonical Huffman code to each * symbol. * Parameters : cl - sorted list of symbols to have code values assigned * Effects : cl stores a list of canonical codes sorted by the length * of the code used to encode the symbol. * Returned : TRUE for success, FALSE for failure ****************************************************************************/ static int AssignCanonicalCodes(canonical_list_t *cl) { int i; byte_t length; bit_array_t *code; /* assign the new codes */ code = BitArrayCreate(256); BitArrayClearAll(code); length = cl[(NUM_CHARS - 1)].codeLen; for(i = (NUM_CHARS - 1); i >= 0; i--) { /* bail if we hit a zero len code */ if (cl[i].codeLen == 0) { break; } /* adjust code if this length is shorter than the previous */ if (cl[i].codeLen < length) { BitArrayShiftRight(code, (length - cl[i].codeLen)); length = cl[i].codeLen; } /* assign left justified code */ if ((cl[i].code = BitArrayDuplicate(code)) == NULL) { perror("Duplicating code"); BitArrayDestroy(code); return FALSE; } BitArrayShiftLeft(cl[i].code, 256 - length); BitArrayIncrement(code); } BitArrayDestroy(code); return TRUE; }
/**************************************************************************** * Function : MakeCodeList * Description: This function uses a huffman tree to build a list of codes * and their length for each encoded symbol. This simplifies * the encoding process. Instead of traversing a tree in * search of the code for any symbol, the code maybe found * by accessing codeList[symbol].code. * Parameters : ht - pointer to root of huffman tree * codeList - code list to populate. * Effects : Code values are filled in for symbols in a code list. * Returned : 0 for success, -1 for failure. errno will be set in the * event of a failure. ****************************************************************************/ static int MakeCodeList(huffman_node_t *ht, code_list_t *codeList) { bit_array_t *code; byte_t depth = 0; if((code = BitArrayCreate(EOF_CHAR)) == NULL) { perror("Unable to allocate bit array"); return -1; } BitArrayClearAll(code); for(;;) { /* follow this branch all the way left */ while (ht->left != NULL) { BitArrayShiftLeft(code, 1); ht = ht->left; depth++; } if (ht->value != COMPOSITE_NODE) { /* enter results in list */ codeList[ht->value].codeLen = depth; codeList[ht->value].code = BitArrayDuplicate(code); if (codeList[ht->value].code == NULL) { perror("Unable to allocate bit array"); BitArrayDestroy(code); return -1; } /* now left justify code */ BitArrayShiftLeft(codeList[ht->value].code, EOF_CHAR - depth); } while (ht->parent != NULL) { if (ht != ht->parent->right) { /* try the parent's right */ BitArraySetBit(code, (EOF_CHAR - 1)); ht = ht->parent->right; break; } else { /* parent's right tried, go up one level yet */ depth--; BitArrayShiftRight(code, 1); ht = ht->parent; } } if (ht->parent == NULL) { /* we're at the top with nowhere to go */ break; } } BitArrayDestroy(code); return 0; }
/**************************************************************************** * Function : HuffmanEncodeFile * Description: This routine genrates a huffman tree optimized for a file * and writes out an encoded version of that file. * Parameters : inFile - Open file pointer for file to encode (must be * rewindable). * outFile - Open file pointer for file receiving encoded data * Effects : File is Huffman encoded * Returned : 0 for success, -1 for failure. errno will be set in the * event of a failure. Either way, inFile and outFile will * be left open. ****************************************************************************/ int HuffmanEncodeFile(FILE *inFile, FILE *outFile) { huffman_node_t *huffmanTree; /* root of huffman tree */ code_list_t codeList[NUM_CHARS]; /* table for quick encode */ bit_file_t *bOutFile; int c; /* validate input and output files */ if ((NULL == inFile) || (NULL == outFile)) { errno = ENOENT; return -1; } bOutFile = MakeBitFile(outFile, BF_WRITE); if (NULL == bOutFile) { perror("Making Output File a BitFile"); return -1; } /* build tree */ if ((huffmanTree = GenerateTreeFromFile(inFile)) == NULL) { outFile = BitFileToFILE(bOutFile); return -1; } /* build a list of codes for each symbol */ /* initialize code list */ for (c = 0; c < NUM_CHARS; c++) { codeList[c].code = NULL; codeList[c].codeLen = 0; } if (0 != MakeCodeList(huffmanTree, codeList)) { outFile = BitFileToFILE(bOutFile); return -1; } /* write out encoded file */ /* write header for rebuilding of tree */ WriteHeader(huffmanTree, bOutFile); /* read characters from file and write them to encoded file */ rewind(inFile); /* start another pass on the input file */ while((c = fgetc(inFile)) != EOF) { BitFilePutBits(bOutFile, BitArrayGetBits(codeList[c].code), codeList[c].codeLen); } /* now write EOF */ BitFilePutBits(bOutFile, BitArrayGetBits(codeList[EOF_CHAR].code), codeList[EOF_CHAR].codeLen); /* free the code list */ for (c = 0; c < NUM_CHARS; c++) { if (codeList[c].code != NULL) { BitArrayDestroy(codeList[c].code); } } /* clean up */ outFile = BitFileToFILE(bOutFile); /* make file normal again */ FreeHuffmanTree(huffmanTree); /* free allocated memory */ return 0; }
int CHuffmanInit(struct CHuffman *ch) { int i; /* initialize canonical list */ for (i = 0; i < NUM_CHARS; i++) { ch->canonicalList[i].codeLen = 0; ch->canonicalList[i].code = NULL; } if (!ReadHeader(ch->canonicalList)) { return FALSE; } /* sort the header by code length */ qsort(ch->canonicalList, NUM_CHARS, sizeof(canonical_list_t), CompareByCodeLen); if (AssignCanonicalCodes(ch->canonicalList) == 0) { /* failed to assign codes */ for (i = 0; i < NUM_CHARS; i++) { if(ch->canonicalList[i].code != NULL) { BitArrayDestroy(ch->canonicalList[i].code); } } return FALSE; } if (ch->for_encode) { /* re-sort list in lexical order for use by encode algorithm */ qsort(ch->canonicalList, NUM_CHARS, sizeof(canonical_list_t), CompareBySymbolValue); } else { /* decoding */ /* allocate canonical code list */ ch->code = BitArrayCreate(256); if (ch->code == NULL) { perror("Bit array allocation"); return FALSE; } ch->resume = 0; /* create an index of first code at each possible length */ for (i = 0; i < NUM_CHARS; i++) { ch->lenIndex[i] = NUM_CHARS; } for (i = 0; i < NUM_CHARS; i++) { if (ch->lenIndex[ch->canonicalList[i].codeLen] > i) { /* first occurance of this code length */ ch->lenIndex[ch->canonicalList[i].codeLen] = i; } } } return TRUE; }