giovani-rubim

Huffman

Aug 21st, 2018
187
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.62 KB | None | 0 0
  1. #include <time.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5.  
  6. #define WORD_SIZE          (1 <<  6)
  7. #define INPUT_BUFFER_SIZE  (1 << 10)
  8. #define OUTPUT_BUFFER_SIZE (1 << 10)
  9. #define MAX_WORDS          (1 << 25)
  10. #define MAX_NODES          (1 << 19)
  11. #define HASH_TABLE_HEIGHT  (1 << 20)
  12. #define MAX_TREE_LEVELS    (1 <<  5)
  13. #define BIN_BUFFER_SIZE    (1 << 10)
  14.  
  15. int fileSize;
  16.  
  17. typedef unsigned int UI;
  18. typedef long long unsigned int LLUI;
  19. typedef unsigned char byte;
  20.  
  21. typedef struct Node {
  22.     char word[WORD_SIZE];
  23.     byte word_len;
  24.     UI code;
  25.     byte code_len;
  26.     UI count;
  27.     byte isLeaf;
  28.     struct Node* left;
  29.     struct Node* right;
  30.     struct Node* next;
  31.     struct Node* sibling;
  32. } Node;
  33.  
  34. Node allNodes[MAX_NODES + 1] = {};
  35. Node* lastNode = allNodes - 1;
  36. #define endNodes (allNodes + MAX_NODES)
  37. #define lastUsableNode (allNodes + MAX_NODES - 1)
  38.  
  39. Node* wordSequence[MAX_WORDS];
  40. int wordSequenceLength = 0;
  41.  
  42. int nWords = 0;
  43.  
  44. int current_hash;
  45. int colisions = 0;
  46. Node* hashTable[HASH_TABLE_HEIGHT] = {};
  47. #define NEXTHASH(h, c)((h<<5)-h+c)
  48.  
  49. byte* bufferIt;
  50.  
  51. char inputBuffer[INPUT_BUFFER_SIZE];
  52. #define inputBufferEnd (inputBuffer + INPUT_BUFFER_SIZE)
  53.  
  54. char last_char = 0;
  55. char word_buffer[WORD_SIZE];
  56. char* word_begin;
  57. char* word_end;
  58.  
  59. byte addWordMap[256][256];
  60.  
  61. Node* minHeap[MAX_NODES];
  62. int minHeapLength;
  63.  
  64. typedef struct NodeList {
  65.     Node* head;
  66.     Node* foot;
  67. } NodeList;
  68. NodeList treeLevels[MAX_TREE_LEVELS] = {};
  69. int nLevels = 0;
  70.  
  71. byte binBuffer[BIN_BUFFER_SIZE + 8];
  72. byte current_bin;
  73. byte current_bin_len;
  74.  
  75. static inline void pushToBinBuffer(UI bin, byte len) {
  76.     LLUI temp = current_bin | (((LLUI)bin) << current_bin_len);
  77.     current_bin_len += len;
  78.     while (current_bin_len >= 8) {
  79.         *bufferIt++ = 0xff & temp;
  80.         temp >>= 8;
  81.         current_bin_len -= 8;
  82.     }
  83.     current_bin = (byte) temp;
  84. }
  85.  
  86. static inline Node* newNode() {
  87.     if (lastNode == lastUsableNode) {
  88.         puts("Error: allNodes overflow");
  89.         exit(0);
  90.     }
  91.     return ++lastNode;
  92. }
  93.  
  94. static inline void minHeapPush(Node* node) {
  95.     int pos = minHeapLength++;
  96.     int count = node->count;
  97.     int parent_pos;
  98.     Node* parent;
  99.     while (pos) {
  100.         parent_pos = (pos - 1) >> 1;
  101.         parent = minHeap[parent_pos];
  102.         if (parent->count <= count) {
  103.             break;
  104.         }
  105.         minHeap[pos] = parent;
  106.         pos = parent_pos;
  107.     }
  108.     minHeap[pos] = node;
  109. }
  110.  
  111. byte ptFlag;
  112.  
  113. byte charToStateCode(char chr) {
  114.     if (!chr) return 1;
  115.     if (chr >= 'a' && chr <= 'z' || chr >= 'A' && chr <= 'Z' || chr & ptFlag) return 2;
  116.     if (chr >= '0' && chr <= '9') return 3;
  117.     if (chr == 10 || chr == 13 || chr == '\t' || chr == ' ') return 4;
  118.     return 5;
  119. }
  120.  
  121. void initAddWordMap(byte map[][256]) {
  122.     byte tempMap[6][6] = {};
  123.     int i, j;
  124.     for (i=2; i<=5; ++i) {
  125.         tempMap[i][1] = 1;
  126.         for (j=2; j<=5; ++j) {
  127.             if (i != j || i == 5 || i == 4) {
  128.                 tempMap[i][j] = 1;
  129.             }
  130.         }
  131.     }
  132.     for (i=0; i<256; ++i) {
  133.         for (j=0; j<256; ++j) {
  134.             byte last = charToStateCode(i);
  135.             byte next = charToStateCode(j);
  136.             map[i][j] = tempMap[last][next];
  137.         }
  138.     }
  139. }
  140.  
  141. static inline int compareStr(char const *a, char const *b) {
  142.     while (*a == *b && *a) ++a, ++b;
  143.     return *a - *b;
  144. }
  145.  
  146. static inline void copyStr(char *dst, char const *src) {
  147.     char copied;
  148.     do {
  149.         copied = *dst++ = *src++;
  150.     } while (copied);
  151. }
  152.  
  153. static inline void countWord() {
  154.     *word_end = 0;
  155.     if (word_end - word_begin >= WORD_SIZE) {
  156.         puts("Error: Word Overflow");
  157.         exit(0);       
  158.     }
  159.     int index = ((unsigned int) current_hash) % HASH_TABLE_HEIGHT;
  160.     Node* node = hashTable[index];
  161.     while (node && compareStr(node->word, word_begin)) {
  162.         node = node->next;
  163.     }
  164.     if (node) {
  165.         ++ node->count;
  166.     } else {
  167.         ++ nWords;
  168.         if (hashTable[index]) {
  169.             ++ colisions;
  170.         }
  171.         node = newNode();
  172.         node->count = 1;
  173.         node->next = hashTable[index];
  174.         node->word_len = word_end - word_begin;
  175.         hashTable[index] = node;
  176.     }
  177.     if (wordSequenceLength == MAX_WORDS) {
  178.         puts("Error: countWord: wordSequence overflow");
  179.         exit(0);
  180.     }
  181.     wordSequence[wordSequenceLength++] = node;
  182.     current_hash = 0;
  183.     word_begin = word_end = lastNode[1].word;
  184. }
  185.  
  186. static inline void iterateInputByte(char chr) {
  187.     if (addWordMap[last_char][chr]) {
  188.         countWord();
  189.     }
  190.     current_hash = NEXTHASH(current_hash, chr);
  191.     *word_end++ = last_char = chr;
  192. }
  193.  
  194. static inline Node* removeMinHeapRoot() {
  195.     int pos = 0;
  196.     Node* root = minHeap[0];
  197.     Node* node = minHeap[--minHeapLength];
  198.     int count = node->count;
  199.     for (;;) {
  200.         int pos_a = (pos << 1) | 1;
  201.         int pos_b = (pos + 1) << 1;
  202.         int count_a = 0x7fffffff;
  203.         int count_b = 0x7fffffff;
  204.         if (pos_a < minHeapLength) {
  205.             count_a = minHeap[pos_a]->count;
  206.         }
  207.         if (pos_b < minHeapLength) {
  208.             count_b = minHeap[pos_b]->count;
  209.         }
  210.         int child_pos;
  211.         int child_count;
  212.         if (count_a <= count_b) {
  213.             child_pos = pos_a;
  214.             child_count = count_a;
  215.         } else {
  216.             child_pos = pos_b;
  217.             child_count = count_b;
  218.         }
  219.         if (child_count >= count) {
  220.             break;
  221.         }
  222.         minHeap[pos] = minHeap[child_pos];
  223.         pos = child_pos;
  224.     }
  225.     minHeap[pos] = node;
  226.     return root;
  227. }
  228.  
  229. static inline void fillMinHeap() {
  230.     minHeapLength = 0;
  231.     Node* node = allNodes;
  232.     while (node <= lastNode) {
  233.         minHeapPush(node++);
  234.     }
  235. }
  236.  
  237. void generateHuffmanTree() {
  238.     while (minHeapLength > 1) {
  239.         Node* a = removeMinHeapRoot();
  240.         Node* b = removeMinHeapRoot();
  241.         Node* node = newNode();
  242.         node->left  = a;
  243.         node->right = b;
  244.         node->count = a->count + b->count;
  245.         minHeapPush(node);
  246.     }
  247. }
  248.  
  249. void prepareHuffmanTree(Node* node, int level, UI code, byte code_len) {
  250.     if (level == nLevels) {
  251.         ++nLevels;
  252.     }
  253.     NodeList* list = treeLevels + level;
  254.     Node* foot = list->foot;
  255.     if (!foot) {
  256.         list->head = node;
  257.     } else {
  258.         foot->sibling = node;
  259.     }
  260.     list->foot = node;
  261.     node->code = code;
  262.     node->code_len = code_len;
  263.     Node* left = node->left;
  264.     if (left) {
  265.         node->isLeaf = 0;
  266.         prepareHuffmanTree(left, level + 1, code, code_len + 1);
  267.         prepareHuffmanTree(node->right, level + 1, code | (1 << code_len), code_len + 1);
  268.     } else {
  269.         node->isLeaf = 1;
  270.     }
  271. }
  272.  
  273. void resetBinBuffer() {
  274.     bufferIt = binBuffer;
  275.     current_bin = 0;
  276.     current_bin_len = 0;
  277. }
  278.  
  279. void writeHuffmanTreeStructure(FILE* fout) {
  280.     int i;
  281.     resetBinBuffer();
  282.     for (i=0; i<nLevels; ++i) {
  283.         Node* node = treeLevels[i].head;
  284.         while (node) {
  285.             pushToBinBuffer(node->isLeaf, 1);
  286.             int length = bufferIt - binBuffer;
  287.             if (length >= BIN_BUFFER_SIZE) {
  288.                 fwrite(binBuffer, length, 1, fout);
  289.                 bufferIt = binBuffer;
  290.             }
  291.             node = node->sibling;
  292.         }
  293.     }
  294.     if (current_bin_len) {
  295.         *bufferIt++ = current_bin;
  296.     }
  297.     int length = bufferIt - binBuffer;
  298.     if (length) {
  299.         fwrite(binBuffer, length, 1, fout);
  300.     }
  301. }
  302.  
  303. void writeUniqueWords(FILE* fout) {
  304.     int i;
  305.     for (i=0; i<nLevels; ++i) {
  306.         Node* node = treeLevels[i].head;
  307.         while (node) {
  308.             if (node->isLeaf) {
  309.                 fwrite(node->word, node->word_len + 1, 1, fout);
  310.             }
  311.             node = node->sibling;
  312.         }
  313.     }
  314. }
  315.  
  316. byte current_byte;
  317. byte current_shift;
  318. NodeList nodeQueue = {};
  319.  
  320. static inline void addNodeToQueue() {
  321.     Node* node = newNode();
  322.     Node* foot = nodeQueue.foot;
  323.     if (!foot) {
  324.         nodeQueue.head = node;
  325.     } else {
  326.         foot->next = node;
  327.     }
  328.     nodeQueue.foot = node;
  329. }
  330.  
  331. static inline Node* popNodeFromQueue() {
  332.     Node* node = nodeQueue.head;
  333.     if (node) {
  334.         nodeQueue.head = node->next;
  335.         if (!nodeQueue.head) {
  336.             nodeQueue.foot = NULL;
  337.         }
  338.     }
  339.     return node;
  340. }
  341.  
  342. static inline void iterateBitReadingHuffmanTreeStructure() {
  343.     Node* node = popNodeFromQueue();
  344.     node->isLeaf = (current_byte >> current_shift) & 1;
  345.     if (!node->isLeaf) {
  346.         addNodeToQueue();
  347.         node->left = lastNode;
  348.         addNodeToQueue();
  349.         node->right = lastNode;
  350.     }
  351.     ++ current_shift;
  352. }
  353.  
  354. void readHuffmanTreeStructure(FILE* fin) {
  355.     lastNode = allNodes - 1;
  356.     fseek(fin, 0L, SEEK_END);
  357.     fileSize = ftell(fin);
  358.     int bytesLeft = fileSize;
  359.     int bufferSize;
  360.     if (fileSize < BIN_BUFFER_SIZE) {
  361.         bufferSize = fileSize;
  362.     } else {
  363.         bufferSize = BIN_BUFFER_SIZE;
  364.     }
  365.     byte* bufferEnd = binBuffer + bufferSize;
  366.     fseek(fin, 0L, SEEK_SET);
  367.     fread(binBuffer, bufferSize, 1, fin);
  368.     bytesLeft -= bufferSize;
  369.     current_shift = 0;
  370.     addNodeToQueue();
  371.     Node* node;
  372.     bufferIt = binBuffer;
  373.     current_byte = *bufferIt;
  374.     while (nodeQueue.head) {
  375.         iterateBitReadingHuffmanTreeStructure();
  376.         if (current_shift == 8) {
  377.             if (++bufferIt == bufferEnd) {
  378.                 bufferIt = binBuffer;
  379.                 if (bytesLeft) {
  380.                     if (bytesLeft < BIN_BUFFER_SIZE) {
  381.                         bufferSize = bytesLeft;
  382.                     } else {
  383.                         bufferSize = BIN_BUFFER_SIZE;
  384.                     }
  385.                     bytesLeft -= bufferSize;
  386.                     fread(binBuffer, BIN_BUFFER_SIZE, 1, fin);
  387.                 }
  388.             }
  389.             current_shift = 0;
  390.             current_byte = *bufferIt;
  391.         }
  392.     }
  393.     prepareHuffmanTree(allNodes, 0, 0, 0);
  394. }
  395.  
  396. void readWords(FILE* fin) {
  397.     int nNodes = lastNode - allNodes + 1;
  398.     int startPos = (nNodes + 7)/8;
  399.     fseek(fin, startPos, SEEK_SET);
  400.     int bytesLeft = fileSize - startPos;
  401.     int bufferSize;
  402.     Node* node;
  403.     for (node = allNodes; node <= lastNode; ++node) {
  404.         if (!node->isLeaf) {
  405.             continue;
  406.         }
  407.         char* str = node->word;
  408.         while (*str++ = fgetc(fin));
  409.         node->word_len = str - node->word - 1;
  410.     }
  411. }
  412.  
  413. void readFile(FILE* fin) {
  414.     fseek(fin, 0L, SEEK_END);
  415.     fileSize = ftell(fin);
  416.     fseek(fin, 0L, SEEK_SET);
  417.     int i;
  418.     initAddWordMap(addWordMap);
  419.     word_begin = word_end = lastNode[1].word;
  420.     for (i=fileSize / INPUT_BUFFER_SIZE; i--;) {
  421.         fread(inputBuffer, sizeof(inputBuffer), 1, fin);
  422.         char* ptr = inputBuffer;
  423.         while (ptr < inputBufferEnd) {
  424.             iterateInputByte(*ptr++);
  425.         }
  426.     }
  427.     i = fileSize % INPUT_BUFFER_SIZE;
  428.     if (i) {
  429.         fread(inputBuffer, i, 1, fin);
  430.         char* ptr = inputBuffer;
  431.         for (;i--;) {
  432.             iterateInputByte(*ptr++);
  433.         }
  434.     }
  435.     iterateInputByte(0);
  436.     fillMinHeap();
  437.     generateHuffmanTree();
  438.     prepareHuffmanTree(minHeap[0], 0, 0, 0);
  439. }
  440.  
  441. void writeCompressedWords(FILE* fout) {
  442.     int i;
  443.     resetBinBuffer();
  444.     Node** ptr = wordSequence;
  445.     Node** end = wordSequence + wordSequenceLength;
  446.     Node* node;
  447.     fwrite(&wordSequenceLength, sizeof(int), 1, fout);
  448.     for (;ptr < end; ++ptr) {
  449.         node = *ptr;
  450.         pushToBinBuffer(node->code, node->code_len);
  451.         int length = bufferIt - binBuffer;
  452.         if (length >= BIN_BUFFER_SIZE) {
  453.             fwrite(binBuffer, length, 1, fout);
  454.             bufferIt = binBuffer;
  455.         }
  456.     }
  457.     if (current_bin_len) {
  458.         *bufferIt++ = current_bin;
  459.     }
  460.     int length = bufferIt - binBuffer;
  461.     if (length) {
  462.         fwrite(binBuffer, length, 1, fout);
  463.     }
  464. }
  465.  
  466. int wordsLeft;
  467. Node* compass;
  468. static inline void decompressWordBitIteration(FILE* fout) {
  469.     if (compass->isLeaf) {
  470.         fwrite(compass->word, compass->word_len, 1, fout);
  471.         compass = allNodes;
  472.         -- wordsLeft;
  473.         return;
  474.     }
  475.     if ((current_byte >> current_shift) & 1) {
  476.         compass = compass->right;
  477.     } else {
  478.         compass = compass->left;
  479.     }
  480.     ++ current_shift;
  481. }
  482.  
  483. void decompressWords(FILE* fin, FILE* fout) {
  484.     fread(&wordsLeft, sizeof(int), 1, fin);
  485.     compass = allNodes;
  486.     int bytesLeft = fileSize - ftell(fin);
  487.     int bufferSize;
  488.     if (fileSize < BIN_BUFFER_SIZE) {
  489.         bufferSize = fileSize;
  490.     } else {
  491.         bufferSize = BIN_BUFFER_SIZE;
  492.     }
  493.     byte* bufferEnd = binBuffer + bufferSize;
  494.     fread(binBuffer, bufferSize, 1, fin);
  495.     bytesLeft -= bufferSize;
  496.     current_shift = 0;
  497.     bufferIt = binBuffer;
  498.     current_byte = *bufferIt;
  499.     while (wordsLeft) {
  500.         decompressWordBitIteration(fout);
  501.         if (current_shift == 8) {
  502.             if (++bufferIt == bufferEnd) {
  503.                 bufferIt = binBuffer;
  504.                 if (bytesLeft) {
  505.                     if (bytesLeft < BIN_BUFFER_SIZE) {
  506.                         bufferSize = bytesLeft;
  507.                     } else {
  508.                         bufferSize = BIN_BUFFER_SIZE;
  509.                     }
  510.                     bytesLeft -= bufferSize;
  511.                     fread(binBuffer, BIN_BUFFER_SIZE, 1, fin);
  512.                 }
  513.             }
  514.             current_shift = 0;
  515.             current_byte = *bufferIt;
  516.         }
  517.     }
  518. }
  519.  
  520. void compress(FILE* fin, FILE* fout) {
  521.     clock_t t1 = clock();
  522.     readFile(fin);
  523.     writeHuffmanTreeStructure(fout);
  524.     writeUniqueWords(fout);
  525.     writeCompressedWords(fout);
  526.     clock_t t2 = clock();
  527.     int l1 = ftell(fin);
  528.     int l2 = ftell(fout);
  529.     fclose(fin);
  530.     fclose(fout);
  531.     float t = (t2 - t1) / (float) CLOCKS_PER_SEC;
  532.     printf("Tempo de execucao: %.4fs\n", t);
  533.     printf("Espaco liberado: %.2f%%\n", 100 - l2 * 100.0f / l1);
  534. }
  535.  
  536. void decompress(FILE* fin, FILE* fout) {
  537.     clock_t t1 = clock();
  538.     readHuffmanTreeStructure(fin);
  539.     readWords(fin);
  540.     decompressWords(fin, fout);
  541.     clock_t t2 = clock();
  542.     fclose(fin);
  543.     fclose(fout);
  544.     float t = (t2 - t1) / (float) CLOCKS_PER_SEC;
  545.     printf("Tempo de execucao: %.4fs\n", t);
  546. }
  547.  
  548. void clearBufferStdin() {
  549.     while (getchar()!='\n');
  550. }
  551.  
  552. void pause() {
  553.     puts("Pressione enter para prosseguir");
  554.     clearBufferStdin();
  555. }
  556.  
  557. void readStr(char s[], int max) {
  558.     fgets(s, max, stdin);
  559.     char* p = strchr(s, '\n');
  560.     if (p) {
  561.         *p = '\0';
  562.     } else {
  563.         clearBufferStdin();
  564.     }
  565. }
  566.  
  567. int lerOpcao(char const s[], int min, int max) {
  568.     int op;
  569.     for (;;) {
  570.         puts(s);
  571.         printf("> ");
  572.         scanf("%d", &op);
  573.         clearBufferStdin();
  574.         if (op >= min && op <= max) {
  575.             break;
  576.         }
  577.         puts("Codigo de operacao invalido");
  578.         pause();
  579.     }
  580. }
  581.  
  582. int main(int argc, char const *argv[]) {
  583.     int op = lerOpcao("Operacao [1 = Compressao, 2 = Descompressao]", 1, 2);
  584.     if (op == 1) {
  585.         if (lerOpcao("Considerar caracteres fora da tabela ASCII como letras? [1 = Sim, 2 = Nao])", 1, 2) == 1) {
  586.             ptFlag = 0x80;
  587.         } else {
  588.             ptFlag = 0;
  589.         }
  590.     }
  591.     FILE* fin;
  592.     FILE* fout;
  593.     char fname[1024] = "";
  594.     for (;;) {
  595.         printf("Arquivo de entrada: ");
  596.         readStr(fname, 1024);
  597.         if (*fname) {
  598.             fin = fopen(fname, "rb");
  599.             if (!fin) {
  600.                 printf("Falha ao abrir %s\n", fname);
  601.                 pause();
  602.             } else {
  603.                 break;
  604.             }
  605.         }
  606.     }
  607.     for (;;) {
  608.         printf("Arquivo de saida: ");
  609.         readStr(fname, 1024);
  610.         if (*fname) {
  611.             fout = fopen(fname, "wb");
  612.             if (!fout) {
  613.                 printf("Falha ao abrir %s\n", fname);
  614.                 pause();
  615.             } else {
  616.                 break;
  617.             }
  618.         }
  619.     }
  620.     if (op == 1) {
  621.         compress(fin, fout);
  622.     } else {
  623.         decompress(fin, fout);
  624.     }
  625. }
Add Comment
Please, Sign In to add comment