+ Responder ao Tópico



  1. #1

    Padrão Dúvida: Codificador/decodificador

    Alô galera.

    Achei um exercício interessante na rede para praticar a Linguagem C. Infelizmente não estou conseguindo desenvolvê-lo.
    O Exercício pede para fazer dois programas que permitam respectivamente a codificação e a decodificação de arquivos para a representação em base64. Ou seja, um dos programas deve ser responsável pela codificação e o outro deve ser responsável pela respectiva decodificação.

    A codificação de um arquivo qualquer (origem) para uma representação base64 (destino) deve ser feita da seguinte forma:
    1 - Ler 3 bytes do arquivo origem.
    Ex: 3 bytes => (11110000) (10101010) (00001111)

    2 - Separar esses 3 bytes em 4 blocos contendo 6 bits cada.
    Ex: (11110000) (10101010) (00001111) =>
    => (111100 | 00 ) ( 1010 | 1010 ) ( 00 | 001111) =>
    => (111100) (001010) (101000) (001111).

    OBS. Os bits em negrito pertenciam ao 1o Byte, os em itálico pertenciam ao 2o Byte e os sublinhados pertenciam ao 3o Byte.

    3 - Representar esses 4 blocos usando bytes. Para isso, concatenar esses 4 blocos com dois zeros (0) nos bits mais significantes (bits da esquerda).
    Ex: (111100) (001010) (101000) (001111) =>
    => (00111100) (00001010) (00101000) (00001111)

    OBS. Os bits em negrito foram os zeros (0) inseridos.
    Converter os 4 Bytes resultantes para caracteres (letras) de acordo com a lista decimal-caractere abaixo:
    0 = 'A',
    1 = 'B',
    2 = 'C',
    3 = 'D',
    4 = 'E',
    5 = 'F',
    6 = 'G',
    7 = 'H',
    8 = 'I',
    9 = 'J',
    10 = 'K',
    11 = 'L',
    12 = 'M',
    13 = 'N',
    14 = 'O',
    15 = 'P',
    16 = 'Q',
    17 = 'R',
    18 = 'S',
    19 = 'T',
    20 = 'U','
    21 = V',
    22 = 'W',
    23 = 'X',
    24 = 'Y',
    25 = 'Z',
    26 = 'a',
    27 = 'b',
    28 = 'c',
    29 = 'd',
    30 = 'e',
    31 = 'f',
    32 = 'g',
    33 = 'h',
    34 = 'i',
    35 = 'j',
    36 = 'k',
    37 = 'l',
    38 = 'm',
    39 = 'n',
    40 = 'o',
    'p',
    'q',
    'r',
    's',
    't',
    'u',
    'v',
    'w',
    'x',
    'y',
    'z',
    '0',
    '1',
    '2',
    '3',
    '4',
    '5',
    '6',
    '7',
    '8',
    '9',
    '+',
    '/'

    Ex:
    Binário: (00111100) (00001010) (00101000) (00001111) =
    = Decimal: (60) (10) (40) (15) =
    = Caractere: ('8') ('K') ('o') ('P')

    Sei que talvez seja pedir demais, mas gostaria de analisar algumas ideias do pessoal aqui do forum para tentar entender a lógica.

    Valeu.

  2. #2
    Não Registrado
    Visitante

    Padrão Tarefinha

    Curioso que esse exercício é igual ao exercício de um curso online q estou escrito...

  3. #3

    Padrão

    Exercício interessante esse.

    Começa pelo básico. Você sabe abrir e ler um arquivo em C?? Para isso utilize a função fopen: Curso de C

    Ok, aprendido a abrir arquivos e seus vários modos, vc tem que aprender a ler um byte de cada arquivo. Em C um char é um byte, logo vc pode usar a função getc: Curso de C

    Para separar 6 bits em um byte você vai usar quatro funções de operações binárias: << (shift letter right), >> (shift letter left), | (or) e & (and). Aqui tem uma explicação sobre eles: Operadores e Expressões

    Basicamente o desafio do exercício é essa separação. (alterei um pouco o exemplo)
    Ex: (11110010) (10101010) (00001111) =>
    => (111100 | 10) ( 1010 | 1010 ) ( 00 | 001111) =>
    => (111100) (101010) (101000) (001111).
    resultado final:
    (00111100) (00101010) (00101000) (00001111)

    No primeiro byte, você precisa fazer um and com uma máscara para pegar os 2 bits da direita:
    Código :
      [FONT=Courier New]11110010
    & 00000011
      --------
      00000010[/FONT]
    Podemos dizer que o AND "insere" zeros. Dessa forma "apagamos" todos os outros bits. Para pegar somente os 6 bits da direita podemos fazer um shift letter right, que desloca os bits para a direita. Dessa forma se fizermos um deslocamento de 2 bits para a direita iremos obter o seguinte resultado:
    Código :
    [FONT=Courier New]11110010 >> 1 = 0[/FONT][FONT=Courier New]1111001[/FONT]
    [FONT=Courier New]0[/FONT][FONT=Courier New]1111001 >> 1 = 0[/FONT][FONT=Courier New]0[/FONT][FONT=Courier New]111100[/FONT]
    Assim ja temos parte do resultado, primeiro base64: 00111100.


    Agora vamos trabalhar com o segundo byte: 10101010. Primeiro vamos separa os 4 primeiros bits fazendo um deslocamento de 4 bits para a direita :
    Código :
    [FONT=Courier New]  10101010 >> 4 = 00001010
    [/FONT]
    Agora vamos concatenar a parte do primeiro byte (00000010) com essa parte do segundo byte (00001010). Primeiro temos que deslocar a parte do primeiro byte:
    Código :
    [FONT=Courier New]  00000010 << 4 = 00100000
    [/FONT]
    Agora vou "inserir" esses os dois:
    Código :
     [FONT=Courier New] 00100000
    | 00001010
      --------
      00101010
    [/FONT]
    Pronto, temos o segundo base64, 00101010.

    E assim por diante. So tome cuidado de verificar se o arquivo é múltiplo de 3, uma vez que você vai ler de 3 em 3 bytes. Para isso depois de ler verifique se você não recebeu um EOF, se você recebeu um EOF faça um "padding", isto é, preencha os outros bytes com zero.

    Quanto a conversão para chars nos vamos usar a tabela ASCII: ASCII - Wikipédia, a enciclopédia livre

    Basicamente a ideia é o seguinte, se seu byte estiver entre 0 e 25 você some ele ao valor 64, dessa forma:
    0+65=64 (A na tabela ASCII);
    1+65=65 (B na tabela ASCII);
    2+65=66 (C na tabela ASCII);
    ...

    Se o seu byte estiver entre 26 e 51, subtraia 26 dele e some o resultado a 97 para obter o caractere a:
    26-26+97=97 (a na tabela ASCII);
    27-26+97=98 (b na tabela ASCII);
    28-26+97=99 (b na tabela ASCII);
    ...


    Se o seu byte for maior que 51, subtraia ele por 52 e some o resultado a 48 para obter o caractere 0:
    52-52+48=48 (0 na tabela ASCII)
    53-52+48=49 (1 na tabela ASCII)
    54-52+48=50 (2 na tabela ASCII)
    ...

    Acho que é isso ai cara! Qualquer dúvida posta ai!
    Até mais...
    Última edição por Magnun; 09-09-2009 às 08:25.

  4. #4

    Padrão

    Cara. Consegui chegar até aqui:

    Código :
    #include <stdio.h>
     
    int main()
    {
    FILE *fp;/* Declaração da estrutura */
    char c;
     
    fp=fopen ("origem.txt","r");  /* o arquivo se chama origem.txt e está localizado no diretório corrente */
     
    if(!fp)
    {
        printf( "Erro na abertura do arquivo");
        exit(0);
    }
    while((c = getc(fp) ) != EOF)  /* Enquanto não chegar ao final do arquivo */
        printf("%c", c);                 /* imprime o caracter lido */
    fclose(fp);
    return 0;
    }

    Não consigo entender como tratar o que foi lido no arquivo de origem, como vou saber até onde vai o arquivo para poder pegar o primeiro byte e como fazer a separação, sou seja, como vou até o primeiro byte para separar?

    Valeu

  5. #5

    Padrão

    Mais ou menos assim:
    Código :
    char byte1;
    char byte2;
    char byte3;
     
    int end_flag = 1;
     
    while(end_flag){
        /* Lendo Byte 1*/
        byte1 = getc(fp) 
        if (byte1 == EOF)
            end_flag = 0; 
     
        /* Lendo Byte 2*/
        if (end_flag){
            byte2 = getc(fp) 
            if (byte2 == EOF)
                printf("Arquivo nao multiplo de 3.");
                end_flag = 0; 
        }
     
        /* Lendo Byte 3*/
        if (end_flag){
            byte3 = getc(fp) 
            if (byte3 == EOF)
                printf("Arquivo nao multiplo de 3.");
                end_flag = 0; 
        }
    }
    fclose(fp);

  6. #6

    Padrão Tá difícil

    Cara ainda tô meio viajando. Esse eu tô quase abandonando já, hehehe.
    Olha só até onde fiz (acredito que está completamente equivocado esse código):
    Código :
    #include <stdio.h>
    #include <stdlib.h>
     
    int main()
    {
        FILE *fp;       /* Declaração da estrutura */
        //char c;
        char byte1;
        char byte2;
        char byte3;
        char parte_byte1;
        char parte_byte2;
        char parte_byte3;
        char primeiro_base64;
        char segundo_base64;
        char terceiro_base64;
        int end_flag = 1;
        //int vetor[];
     
        fp=fopen ("origem.txt","r+");    /* o arquivo se chama origem.txt e está localizado no diretório corrente */
     
        if(!fp)
        {
            printf( "Erro na abertura do arquivo");
            exit(0);
        }
        //while((c = fgetc(fp) ) != feof)   /* Enquanto não chegar ao final do arquivo */
        //   printf("%c", c);                    /* imprime o caracter lido */
        //fclose(fp);
        //return 0;
     
        while(end_flag)
        { 
            /* Lendo Byte 1*/
            byte1 = getc(fp);
            if (byte1 == EOF)
                    end_flag = 0; 
     
            /* Lendo Byte 2*/
            if (end_flag)
            {
                byte2 = getc(fp);
                    if (byte2 == EOF)
                {
                    printf("Arquivo nao multiplo de 3.");
                    end_flag = 0; 
                }
            }
     
            /* Lendo Byte 3*/
            if (end_flag)
            {
                    byte3 = getc(fp); 
                    if (byte3 == EOF)
                {
                            printf("Arquivo nao multiplo de 3.");
                        end_flag = 0; 
                }
            }
        }
        fclose(fp);
     
        //tratamento do byte1
        parte_byte1 = byte1 & 00000011;
        primeiro_base64 = byte1 >> 2; //01111001
     
        //tratamento do byte2
        parte_byte2 = byte2 >> 4; // 00001010
        //juntando byte 1 e byte 2
        parte_byte1 = parte_byte1 << 4;
        segundo_base64 = parte_byte1 | parte_byte2;
     
         //tratamento do byte3
        parte_byte3 = byte3 >> 8; // 00000000
        //juntando byte 1 e byte 2
        parte_byte1 = parte_byte1 << 8;
        terceiro_base64 = parte_byte1 | parte_byte3;
     
        //Conversão chars -> ASCII
        if (primeiro_base64 >= 0) & (primeiro_base64 <=25)
        {
     
        }
    }

  7. #7

    Padrão

    Putz cara... É a primeira vez que você programa??

    Cara, ta mastigado agora...
    Código :
    #include <stdio.h>
    #include <stdlib.h>
     
    FILE *fp;
    int loop_flag = 1;
     
    char read_char(void){
        char byte;
        if (loop_flag){
            byte = getc(fp);
            if (byte == EOF){
                byte = 0;
                loop_flag = 0;
            }
        }else{
            byte = 0;
        }
     
         return byte;
    }
     
    char ascii_decode(unsigned char base64){
         if (base64 < 26){
             base64 = base64 + 65;
         }else if (base64 < 51){
             base64 = base64 - 26 + 97;
         }else if (base64 < 62){
             base64 = base64 - 52 + 48; 
         }else if (base64 == 62){
             base64 = 43;
         }else if (base64 == 63){
             base64 = 47;
         }
         return base64;
    }
     
    int main()
    {
        unsigned char byte1;
        unsigned char byte2;
        unsigned char byte3;
        unsigned char tmp1;
        unsigned char tmp2;
        unsigned char base64_1;
        unsigned char base64_2;
        unsigned char base64_3;
        unsigned char base64_4;
     
        fp=fopen ("base64.txt","r+");    /* o arquivo se chama origem.txt e está localizado no diretório corrente */
     
        if(!fp)
        {
            printf( "Erro na abertura do arquivo");
            exit(0);
        }
     
        while(loop_flag)
        { 
            /* Lendo Byte 1*/
            byte1 = read_char();
            byte2 = read_char();
            byte3 = read_char();
     
            /* Processando primeiro base64 */
            printf("Processando: %c (%i)| ", byte1, byte1); //0110 0010 (98)
            base64_1 = byte1 >> 2; // 0001 1000 (24)
     
            /* Processando segundo base64 */
            printf("%c (%i)| ", byte2, byte2); //0110 0011 (99)
            tmp1 = byte1 & 3; // 0000 0010
            tmp1 = tmp1 << 4; // 0010 0000
            tmp2 = byte2 >> 4; // 0000 0110
            base64_2 = tmp1 | tmp2; // 0010 0110 (38)
     
            /* Processando terceiro base64 */
            printf("%c (%i).\n", byte3, byte3); //0110 0100 (100)
            tmp1 = byte3 >> 6; // 0000 0001
            tmp2 = byte2 & 15; // 0110 0011 & 0000 1111
            tmp2 = tmp2 << 2; // 0000 1100
            base64_3 = tmp1 | tmp2; // 0000 1101 (13)
     
            /* Processando quarto base64 */
            base64_4 = byte3 >> 2; // 0001 1001 (25)
     
            /* Saída */
            base64_1 = ascii_decode(base64_1);
            base64_2 = ascii_decode(base64_2);
            base64_3 = ascii_decode(base64_3);
            base64_4 = ascii_decode(base64_4);
            printf("\tOutput base 64: %c | %c | %c | %c\n", base64_1, base64_2, base64_3, base64_4);
        }
    }
    Jogar essa saída pra um arquivo você consegue??

    Até mais...

  8. #8

    Padrão

    Tente quebrar o problema em pedaços. Depois, tente quebrar os pedaços em pedaços menores. Anote tudo na devida ordem, e tente resolver cada uma dessas partes. Tudo parecerá/será muito mais simples.

    Caso tenha dúvidas, utilize google, wikipedia, e principalmente o fórum de programação C.

    Segue minha contribuição:

    Código :
    #include <stdio.h>
    #include <string.h>
     
    #define DEBUG
    #define FILE_OUT	stdout
     
    #define SIZE_IN		3
    #define SIZE_OUT	4
     
    void fprintbits(FILE *fp, char c) {
    	int i, mask;
    	for(i=7; i>=0; i--)
    		fputc((c & (1 << i)) == 0 ? '0' : '1', fp);
    }
     
    int main(int argc, char **argv) {
    	FILE *fp;
    	int filesize, i;
    	char buffer_in[SIZE_IN];
    	char buffer_out[SIZE_OUT];
     
    	// Abre o arquivo
    	fp = fopen("origem.txt", "r");
    	if (ferror(fp)) {
    		perror("erro ao abrir arquivo\n");
    		return 2;
    	}
     
    	// Verifica o tamanho do arquivo
    	fseek(fp, 0, SEEK_END);
    	filesize = ftell(fp) - 1;
    	if (filesize % SIZE_IN) {
    		fprintf(stderr, "tamanho de arquivo invalido\n");
    		return 2;
    	}
    	rewind(fp);
     
    	// Loop de leitura do arquivo
    	while (1) {
    		// Le N bytes
    		if (fread(buffer_in, 1, SIZE_IN, fp) != SIZE_IN)
    			break;
     
    		// Processa os dados
    		// (111100|00) (1010|1010) (00|001111)
    		buffer_out[0] = buffer_in[0] >> 2;
    		buffer_out[1] = (buffer_in[0] & 0x3) << 4 | buffer_in[1] >> 4;
    		buffer_out[2] = (buffer_in[1] & 0xF) << 2 | (buffer_in[2] & 0xC0) >> 6;
    		buffer_out[3] = buffer_in[2] & 0x3F;
    #if DEBUG
    		// Mostra os dados na tela
    		fprintf(FILE_OUT, "IN:\n"); 
    		for (i=0; i<SIZE_IN; i++) {
    			fprintbits(FILE_OUT, buffer_in[i]);
    			fprintf(FILE_OUT, "\n");
    		}
    		fprintf(FILE_OUT, "OUT:\n"); 
    		for (i=0; i<SIZE_OUT; i++) {
    			fprintbits(FILE_OUT, buffer_out[i]);
    			fprintf(FILE_OUT, "\n");
    		}
    #endif
     
    		// E aqui voce processa os bytes de buffer_out…
    	}
     
    	// Fecha o arquivo
    	fclose(fp);
     
    	return 0;
    }
    Última edição por jweyrich; 10-09-2009 às 00:21.

  9. #9

    Padrão Foi mal

    Galera, foi mal.

    Pensei que seria fácil para mim, iniciante em C, desenvolver esse programa já que a lógica é relativamente simples (o fluxo foi fácil de fazer). Mas esbarrei na minha falta de conhecimento de vários comandos e funções da linguagem.
    Por isso, vou me atentar agora a programa mais de início de linguagem mesmo, como fatoriais e médias pra me adaptar, depois tento fazer exercícios mais complexos.
    Grato a todos que ajudaram e desculpem o transtorno.
    Valeu.

  10. #10

    Padrão

    Não desanima não cara!! Aos poucos vc pega o jeito! Tenta começar com uma linguagem mais light. C é uma ótima linguagem, mas exige muito do programador.

    Eu começei programando em C, inclusive fazia muito tempo que não a utilizava, mas certas coisas eu fariam em outra linguagem.

    Até mais...