Advertisement
Guest User

Untitled

a guest
Jan 29th, 2020
120
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.75 KB | None | 0 0
  1. #include "/home/alunoic/Documentos/Huffman-with-priority-queue/huffman/header/header.h"
  2. #include "compress.h"
  3.  
  4. // FUNCOES FILA DE PRIORIDADE
  5.  
  6. PRIORITY_QUEUE* create_priority_queue() {
  7.     PRIORITY_QUEUE* queue = (PRIORITY_QUEUE*) malloc(sizeof(PRIORITY_QUEUE));
  8.    
  9.     queue -> head = NULL;
  10.     queue -> size = 0;
  11.  
  12.     return queue;
  13. };
  14.  
  15. void fill_priority_queue(lli frequence[], PRIORITY_QUEUE* queue) {
  16.     for (int i = 0; i < 256; i++) {
  17.        
  18.         if (frequence[i] != 0) {
  19.             NODE* new_node = create_node(frequence[i], i, NULL, NULL);
  20.             enqueue(new_node, queue);
  21.         }
  22.     }
  23. }
  24.  
  25. void enqueue(NODE* new_node, PRIORITY_QUEUE* queue) {
  26.     if (queue -> head == NULL || new_node -> priority <= queue -> head -> priority) {
  27.        
  28.         new_node -> next = queue -> head;
  29.         queue -> head = new_node;
  30.     }
  31.     else {
  32.         NODE* current = queue -> head;
  33.  
  34.         while (current -> next != NULL && current-> next-> priority < new_node -> priority) {
  35.             current = current->next;
  36.         }
  37.         new_node -> next = current -> next;
  38.         current -> next = new_node;
  39.     }
  40.     queue -> size += 1;
  41. }
  42.  
  43. NODE* dequeue(PRIORITY_QUEUE* queue) {
  44.     if (queue -> head == NULL) {
  45.         printf("QUEUE UNDERFLOW\n");
  46.         return NULL;
  47.     }
  48.     queue -> size -= 1;
  49.     NODE* first_node = queue -> head;
  50.     queue -> head = queue -> head -> next;
  51.     first_node -> next = NULL;
  52.    
  53.     return first_node;
  54. }
  55.  
  56. void print_queue(NODE* current) {
  57.     while (current != NULL) {
  58.  
  59.         printf("%c %lld\n", *(uchar*)current -> caracter, current -> priority);
  60.         current = current->next;
  61.     }
  62.     printf("\n");
  63. }
  64.  
  65. // FUNCOES NODE
  66.  
  67. NODE* create_node(lli priority, uchar caracter, NODE* left, NODE* right) {
  68.     NODE* new_node = (NODE*) malloc(sizeof(NODE));
  69.  
  70.     new_node -> priority = priority;
  71.     *(uchar*)new_node -> caracter = caracter; // representacao do caracter na ASCII.
  72.     new_node -> left = left;
  73.     new_node -> right = right;
  74.     new_node -> next = NULL;
  75.  
  76.     return new_node;
  77. }
  78.  
  79. // FUNCOES ARRAY DE FREQUENCIA
  80.  
  81. void create_freq_array(lli* frequence) {
  82.     for (int i = 0; i < 256; i++) {
  83.         frequence[i] = 0;
  84.     }
  85. }
  86.  
  87. void fill_freq_array(lli* frequence) {
  88.     FILE* file = fopen("/home/ester/Documentos/p2/Huffman-with-priority-queue/huffman/file_tests/meg.mp4", "rb");
  89.     uchar caracter;
  90.  
  91.     while (fscanf(file, "%c", &caracter) != EOF) {
  92.         frequence[caracter] += 1;
  93.     }
  94.     fclose(file);
  95. }
  96.  
  97. // FUNCOES ARVORE DE HUFFMAN
  98.  
  99. NODE* create_huff_tree(PRIORITY_QUEUE* queue) {
  100.     while (queue -> size > 1) {
  101.  
  102.         NODE* left_node = dequeue(queue);
  103.         NODE* right_node = dequeue(queue);
  104.        
  105.         lli sum = left_node -> priority + right_node -> priority;
  106.         NODE* tree_node = create_node(sum, '*', left_node, right_node);
  107.  
  108.         enqueue(tree_node, queue);
  109.     }
  110.     return queue -> head;
  111. }
  112.  
  113. void print_tree(NODE* current) {
  114.     if (current == NULL) return;
  115.  
  116.     printf("caracter: %c freq: %lld\n", *(uchar*)current -> caracter, current -> priority);
  117.     print_tree(current -> left);
  118.     print_tree(current -> right);
  119. }
  120.  
  121. void get_pre_order_tree(NODE* tree, FILE* file) {
  122.     if (tree != NULL) {
  123.         if (is_leaf(tree)) { // se cheguei numa folha
  124.             if (*(uchar*)tree -> caracter == '*' || *(uchar*)tree -> caracter == '\\') {
  125.                 fputc('\\', file);
  126.             }
  127.         }
  128.         fputc(*(uchar*)tree -> caracter, file);
  129.         get_pre_order_tree(tree -> left, file);
  130.         get_pre_order_tree(tree -> right, file);
  131.     }
  132. }
  133.  
  134. bool is_leaf(NODE* current) {
  135.     if (current -> left == NULL && current -> right == NULL) return true;
  136.     else return false;
  137. }
  138.  
  139. // CALCULAR O TAMANHO DA ÁRVORE
  140.  
  141. ushort get_size_tree(NODE* tree) {
  142.     if (is_leaf(tree)) { // se cheguei numa folha
  143.         if (*(uchar*)tree -> caracter == '*' || *(uchar*)tree -> caracter == '\\') {
  144.             return 2;
  145.         } else {
  146.             return 1;
  147.         }
  148.     }
  149.     return 1 + get_size_tree(tree -> left) + get_size_tree(tree -> right);
  150. }
  151.  
  152. // FUNCOES DE HASH
  153.  
  154. HASH* create_hash() {
  155.     HASH* new_hash = (HASH*) malloc(sizeof(HASH));
  156.  
  157.     for (int i = 0; i < 256; i++) {
  158.         new_hash -> array[i] = NULL;
  159.     }
  160.     return new_hash;
  161. }
  162.  
  163. void print_hash(HASH* hash) {
  164.     ushort byte;
  165.     int size;
  166.  
  167.     for (int i = 0; i < 256; i++) {
  168.         if (hash->array[i] != NULL) {
  169.             byte = hash->array[i]->code;
  170.             size = hash->array[i]->size;
  171.  
  172.             printf("new_code: %u size: %d\n", byte, size);
  173.         }
  174.     }
  175. }
  176.  
  177. // NOVA CODIFICACAO
  178.  
  179. bool is_bit_i_set(ushort byte, int i) {
  180.     ushort temp = 1 << i;
  181.     return temp & byte;
  182. }
  183.  
  184. void new_codification(HASH* hash, NODE* tree, int size, ushort byte) {
  185.     if (is_leaf(tree)) { // se cheguei numa folha (achei uma caracter).
  186.  
  187.         ELEMENT* element = (ELEMENT*) malloc(sizeof(ELEMENT)); // crio um no vazio.
  188.         int index = *(uchar*)tree -> caracter; // pego a representação inteira do caracter (indice na hash).
  189.        
  190.         element -> size = size;
  191.         *(ushort*)element -> code = byte;
  192.         hash -> array[index] = element;
  193.        
  194.         return;
  195.     }
  196.     byte <<= 1;
  197.     new_codification(hash, tree -> left, size + 1, byte);
  198.  
  199.     byte++; // poe 1 no primeiro bit do byte.
  200.     new_codification(hash, tree -> right, size + 1, byte);
  201. }
  202.  
  203. // CALCULAR LIXO
  204.  
  205. uchar get_trash(HASH* hash, lli* frequence) {
  206.     lli sum = 0;
  207.  
  208.     for (int i = 0; i < 256; i++) {
  209.         if (hash -> array[i] != NULL) {
  210.             sum += *(ELEMENT*)hash -> array[i] -> size * frequence[i];
  211.         }
  212.     }
  213.     uchar trash = 0; // tamanho do lixo
  214.     lli bits = 0; // quantia de bits usados
  215.     lli bytes = sum / 8; // quantia de bytes alocados
  216.  
  217.     if (sum % 8 != 0) {
  218.         bytes++;
  219.         bits = bytes * 8; // quantidade de bits alocados(NAO É O TOTAL DE BITS USADOS TA!)
  220.         trash = bits - sum;
  221.     }
  222. }
  223.  
  224. // COMPACTAR ARQUIVO TESTE
  225.  
  226. // executar um caso pequeno para entender a funcao, ela eh facil, so entender com calma :D
  227.  
  228. void compact_file(FILE* arq_compact, HASH* hash, uchar trash_size) {
  229.     FILE* read_file = fopen("/home/ester/Documentos/p2/Huffman-with-priority-queue/huffman/file_tests/meg.mp4", "rb"); // abro e leio o arquivo.
  230.     int size;
  231.     int quant_bits;      // verifica se o byte ja esta completo com 8 bits.
  232.     ushort code;         // salva a codificaçao do caracter lido (salvo na hash).
  233.     uchar caracter;      // pega a leitura do caracter.
  234.     uchar compress_byte; // byte com a compressao.
  235.    
  236.     quant_bits = 0, compress_byte = 0, size = 0;  // inicializo tudo com zero.
  237.  
  238.     while (fscanf(read_file, "%c", &caracter) != EOF) { // lemos o arquivo ate o EOF.
  239.  
  240.         code = *(ELEMENT*)hash->array[caracter]->code;     // pega a nova codificaçao (na hash) do caracter lido.
  241.         size = *(ELEMENT*)hash->array[caracter]->size - 1; // pega o tamanho dessa codificaçao.
  242.  
  243.         for (size; size >= 0; size--) {
  244.            
  245.             if (is_bit_i_set(code, size)) {
  246.                 compress_byte += 1; // poe 1 no bit mais a direita.
  247.             }
  248.            
  249.             quant_bits += 1; // soma 1 a quantia de bits.
  250.            
  251.             if (quant_bits == 8) { // renovar o byte (atingiu o limite da quantidade de bits).
  252.  
  253.                 fprintf(arq_compact, "%c", compress_byte); // printa o byte no arquivo.
  254.                 quant_bits = 0;    // zera a quantia de bits.
  255.                 compress_byte = 0; // zera o byte (0000 0000).
  256.  
  257.             }
  258.             compress_byte <<= 1; // shifta para frente o bit mais a dieita para nao perde-lo.
  259.         }
  260.     }
  261.     compress_byte >>= 1;          // ajusta o ultimo bit dp ultimo byte, pois ele contem o ultimo bit errado.
  262.     compress_byte <<= trash_size; //  shiftei o tamanho do lixo no ultimo byte do arquivo codificado.
  263.  
  264.     fprintf(arq_compact, "%c", compress_byte); // printa o ultimo byte no arquivo.
  265.     fclose(read_file);
  266. }
  267.  
  268. int main() {
  269.     lli frequence[256]; // ignoramos o indice zero.
  270.  
  271.     create_freq_array(frequence);
  272.     fill_freq_array(frequence);
  273.    
  274.     PRIORITY_QUEUE* queue = create_priority_queue();
  275.     fill_priority_queue(frequence, queue);
  276.  
  277.     NODE* tree = create_huff_tree(queue);
  278.  
  279.     HASH* hash = create_hash();
  280.     new_codification(hash, tree, 0, 0);
  281.    
  282.     //print_hash(hash);
  283.     //print_tree(tree);
  284.  
  285.     uchar trash = get_trash(hash, frequence); // trash so ocupa 3 bits, por isso so alocamos 1 byte para guardar o lixo.
  286.     ushort size_tree = get_size_tree(tree);
  287.    
  288.     //printf("%d\n", trash);
  289.  
  290.     // COMENTARIOS USANDO O EXEMPLO DO MARCIO: PARA LIXO = 5 OU 0000 0101 (em binario)
  291.  
  292.     ushort header = 0; // zera os 16 bits (2 bytes): 00000000 00000000
  293.     header |= trash;  // agora ficou assim: 000000 00000101 (ultimo byte eh o lixo em binario)
  294.     header <<= 13;   //  para trazer o lixo pras 3 primeiras posicoes do primeiro byte: 10100000 00000000
  295.     header = header | size_tree;  // inserir o restante da arvore (11 exemplo) nos 2 bits: 1010 0000 0000 1011 (header pronta!)
  296.    
  297.     // printf("trash %u\n", trash);
  298.     // printf("header %u\n", header);
  299.    
  300.     FILE* file = fopen("/home/ester/Documentos/p2/Huffman-with-priority-queue/huffman/compressed_files/ester.mp4.huff", "wb"); // arquivo de escrita compactada
  301.     uchar byte_1 = header >> 8; // pega so o primeiro byte da header(que tem 2 bytes)
  302.     uchar byte_2 = header; // nao precisa shiftar, como o byte 2 so tem 1 byte, ele pega o segundo byte da header.
  303.  
  304.     // printf("byte 1: %d\n", byte_1);
  305.     // printf("byte 2: %d\n", byte_2);
  306.  
  307.     fputc(byte_1, file);
  308.     fputc(byte_2, file);
  309.  
  310.     get_pre_order_tree(tree, file);
  311.  
  312.     compact_file(file, hash, trash);
  313.     fclose(file);
  314.  
  315.     return 0;
  316. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement