Como despejar um arquivo binário como um literal de cadeia C / C ++?

34

Eu tenho um arquivo binário que eu gostaria de incluir no meu código-fonte C (temporariamente, para fins de teste), então eu gostaria de obter o conteúdo do arquivo como uma string C, algo assim:

\x01\x02\x03\x04

Isso é possível, talvez usando os utilitários od ou hexdump ? Embora não seja necessário, se a string puder agrupar a próxima linha a cada 16 bytes de entrada e incluir aspas no início e no final de cada linha, seria ainda melhor!

Estou ciente de que a string terá nulos incorporados ( \x00 ), portanto, precisarei especificar o comprimento da string no código, para evitar que esses bytes terminem a string antes.

    
por Malvineous 27.12.2014 / 07:11

6 respostas

8

Você pode quase fazer o que quiser com hexdump , mas não consigo descobrir como obter aspas & únicas barras invertidas na string de formato. Então eu faço um pouco de pós-processamento com sed . Como bônus, também indentei cada linha em 4 espaços. :)

hexdump -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\/g; s/.*/    "&"/'

Editar

Como Cengiz Can apontou, a linha de comando acima não combina bem com linhas curtas de dados. Então aqui está uma nova versão melhorada:

hexdump -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\/g; s/\x  //g; s/.*/    "&"/'

Como Malvineous menciona nos comentários, também precisamos passar a opção -v verbose para hexdump para evitar que ele abrevie execuções longas de bytes idênticos em * .

hexdump -v -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\/g; s/\x  //g; s/.*/    "&"/'
    
por 27.12.2014 / 08:04
62

xxd tem um modo para isso. A opção -i / --include será:

output in C include file style. A complete static array definition is written (named after the input file), unless xxd reads from stdin.

Você pode despejar isso em um arquivo para ser #include d, e então apenas acessar foo como qualquer outro array de caracteres (ou vinculá-lo). Também inclui uma declaração do comprimento do array.

A saída é encapsulada em 80 bytes e parece essencialmente com o que você pode escrever à mão:

$ xxd --include foo
unsigned char foo[] = {
  0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
  0x21, 0x0a, 0x0a, 0x59, 0x6f, 0x75, 0x27, 0x72, 0x65, 0x20, 0x76, 0x65,
  0x72, 0x79, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x21, 0x20,
  0x57, 0x65, 0x6c, 0x6c, 0x20, 0x64, 0x6f, 0x6e, 0x65, 0x2e, 0x0a
};
unsigned int foo_len = 47;

xxd é, um pouco estranhamente, parte da distribuição vim , então você provavelmente já a tem. Se não, é aí que você o obtém - você também pode criar a ferramenta por conta própria da vim source.

    
por 27.12.2014 / 07:38
4

xxd é bom, mas o resultado é altamente detalhado e ocupa muito espaço de armazenamento.

Você pode conseguir praticamente a mesma coisa usando objcopy ; por exemplo,

objcopy --input binary \
    --output elf32-i386 \
    --binary-architecture i386 foo foo.o

Em seguida, vincule foo.o ao seu programa e simplesmente use os seguintes símbolos:

00000550 D _binary_foo_end
00000550 A _binary_foo_size 
00000000 D _binary_foo_start

Esta não é uma string literal, mas é essencialmente a mesma coisa que uma string literal transforma durante a compilação (considere que a string literais não existe de fato em tempo de execução; de fato, nenhuma das outras respostas realmente dão a você uma string literal mesmo em tempo de compilação) e pode ser acessado basicamente da mesma maneira:

unsigned char* ptr = _binary_foo_start;
int i;
for (i = 0; i < _binary_foo_size; i++, ptr++)
   putc(*ptr);

A desvantagem é que você precisa especificar sua arquitetura de destino para tornar o arquivo objeto compatível, e isso pode não ser trivial em seu sistema de compilação.

    
por 28.12.2014 / 14:57
2

Deve ser exatamente o que você pediu:

hexdump -v -e '"\" "x" 1/1 "%02X"' file.bin ; echo
    
por 14.09.2016 / 12:00
0

Este é um utilitário curto que escrevi que essencialmente faz a mesma coisa (originalmente publicado em Stack Overflow ):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LENGTH 80

int main(void)
{
    FILE *fout = fopen("out.txt", "w");

    if(ferror(fout))
    {
        fprintf(stderr, "Error opening output file");
        return 1;
    }
    char init_line[]  = {"char hex_array[] = { "};
    const int offset_length = strlen(init_line);

    char offset_spc[offset_length];

    unsigned char buff[1024];
    char curr_out[64];

    int count, i;
    int line_length = 0;

    memset((void*)offset_spc, (char)32, sizeof(char) * offset_length - 1);
    offset_spc[offset_length - 1] = '
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LENGTH 80

int main(void)
{
    FILE *fout = fopen("out.txt", "w");

    if(ferror(fout))
    {
        fprintf(stderr, "Error opening output file");
        return 1;
    }
    char init_line[]  = {"char hex_array[] = { "};
    const int offset_length = strlen(init_line);

    char offset_spc[offset_length];

    unsigned char buff[1024];
    char curr_out[64];

    int count, i;
    int line_length = 0;

    memset((void*)offset_spc, (char)32, sizeof(char) * offset_length - 1);
    offset_spc[offset_length - 1] = '%pre%';

    fprintf(fout, "%s", init_line);

    while(!feof(stdin))
    {
        count = fread(buff, sizeof(char), sizeof(buff) / sizeof(char), stdin);

        for(i = 0; i < count; i++)
        {
            line_length += sprintf(curr_out, "%#x, ", buff[i]);

            fprintf(fout, "%s", curr_out);
            if(line_length >= MAX_LENGTH - offset_length)
            {
                fprintf(fout, "\n%s", offset_spc);
                line_length = 0;
            }
        }
    }
    fseek(fout, -2, SEEK_CUR);
    fprintf(fout, " };");

    fclose(fout);

    return EXIT_SUCCESS;
}
'; fprintf(fout, "%s", init_line); while(!feof(stdin)) { count = fread(buff, sizeof(char), sizeof(buff) / sizeof(char), stdin); for(i = 0; i < count; i++) { line_length += sprintf(curr_out, "%#x, ", buff[i]); fprintf(fout, "%s", curr_out); if(line_length >= MAX_LENGTH - offset_length) { fprintf(fout, "\n%s", offset_spc); line_length = 0; } } } fseek(fout, -2, SEEK_CUR); fprintf(fout, " };"); fclose(fout); return EXIT_SUCCESS; }
    
por 27.12.2014 / 23:21
0

Se você estiver em python, carregue-o em uma variável "buff" e use algo assim:

buff2 = buff.encode("hex")
print ("0x"+", 0x".join([buff2[i:i+2] for i in range(0,len(buff2),2)]))
    
por 29.09.2016 / 02:14

Tags