Wie kann ich eine Binärdatei als C / C ++ - String-Literal sichern?

39

Ich habe eine Binärdatei, die ich (vorübergehend zu Testzwecken) in meinen C-Quellcode aufnehmen möchte, damit ich den Dateiinhalt als C-String erhalten kann.

\x01\x02\x03\x04

Ist das möglich, vielleicht mit den Hilfsprogrammen ododer hexdump? Auch wenn dies nicht erforderlich ist, wäre es noch angenehmer, wenn die Zeichenfolge alle 16 Eingabebytes in die nächste Zeile umgebrochen und am Anfang und Ende jeder Zeile doppelte Anführungszeichen verwendet werden könnte.

Mir ist bekannt, dass die Zeichenfolge eingebettete Nullen ( \x00) enthält. Daher muss die Länge der Zeichenfolge im Code angegeben werden, damit diese Bytes die Zeichenfolge nicht vorzeitig beenden.

Bösartig
quelle
stackoverflow.com/q/13856930/560648
Leichtigkeit Rennen mit Monica
Ich möchte ähnliche, aber behalten Sie ASCII druckbare Glyphe, nur Escaping 1-127, Zitat, Backslash, Null, etc.
- 友情 留 无 盐 盐

Antworten:

10

Sie können fast tun, was Sie wollen hexdump, aber ich kann nicht herausfinden, wie man Anführungszeichen und einzelne Backslashes in die Formatzeichenfolge bekommt. Also mache ich eine kleine Nachbearbeitung mit sed. Als Bonus habe ich auch jede Zeile um 4 Leerzeichen eingerückt. :)

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

Bearbeiten

Wie Cengiz Can hervorhob, kommt die obige Befehlszeile mit kurzen Datenleitungen nicht gut zurecht. Also hier ist eine neue verbesserte Version:

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

Wie Malvineous in den Kommentaren erwähnt, müssen wir auch die -vOption verbose übergeben, um hexdumpzu verhindern, dass lange Reihen identischer Bytes mit abgekürzt werden *.

hexdump -v -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\\/g; s/\\x  //g; s/.*/    "&"/'
PM 2Ring
quelle
Dies erzeugt redundante und ungültige Elemente, wenn die Eingabe kürzer als 16 Byte ist.
Cengiz Can
@CengizCan:: oops :! Ist das besser?
PM 2Ring
1
Müssen Sie die -vOption hinzufügen hexdump, sonst verursachen lange Läufe des gleichen Eingangsbytes Ausgangsleitungen, die sagen "*".
Malvineous
@Malvineous Guter Punkt! Ich habe meine Antwort geändert. Vielen Dank für das Heads-up (und vielen Dank für die Annahme meiner Antwort).
PM 2Ring
66

xxdhat einen Modus dafür. Die -i/ --includeOption wird:

Ausgabe in C inkludieren Dateiformat. Es wird eine vollständige statische Array-Definition geschrieben (benannt nach der Eingabedatei), sofern xxd nicht von stdin liest.

Sie können das in eine Datei speichern, die #included sein soll, und dann foowie jedes andere Zeichenarray darauf zugreifen (oder es einbinden). Es enthält auch eine Deklaration der Länge des Arrays.

Die Ausgabe wird auf 80 Bytes umbrochen und sieht im Wesentlichen so aus, wie Sie es von Hand schreiben könnten:

$ 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;

xxdist seltsamerweise Teil der vimDistribution, also haben Sie sie wahrscheinlich schon. Wenn nicht, erhalten Sie es hier - Sie können das Tool auch selbst aus dem vimQuellcode erstellen .

Michael Homer
quelle
Nett! Ich wusste nicht einmal, dass ich xxd hatte. Jetzt muss ich mich nur noch daran erinnern, dass es das nächste Mal existiert, wenn ich es brauche ... oder ich werde wahrscheinlich nur die erforderliche Funktionalität in Python replizieren. :)
PM 2Ring
objcopywäre besser
Leichtigkeit Rennen mit Monica
Mit @LightnessRacesinOrbit kann objcopyOP die Binärdaten mit der ausführbaren Datei als Objektdatei verknüpfen. Dies ist nützlich, aber nicht genau das, was hier abgefragt wird.
Wander Nauta
1
@WanderNauta: Sie würden fast genauso darauf zugreifen wie auf foo/ foo_lenhier, und Sie würden nicht viel Speicherplatz verschwenden. Ich bin überzeugt, dass es dem OP besser geht objcopyund dass es seinen Anforderungen entspricht.
Leichtigkeit Rennen mit Monica
2
objcopyist in Ordnung, wenn es um ist, aber es ist nicht portabel und die Ausgabe noch weniger. Es kann sicherlich Teil einer guten dauerhaften Lösung sein, aber das ist hier nicht die Frage.
Michael Homer
3

xxd ist gut, aber das Ergebnis ist sehr ausführlich und nimmt viel Speicherplatz in Anspruch.

Mit können Sie praktisch dasselbe erreichen objcopy. z.B

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

Verlinken Sie dann foo.ozu Ihrem Programm und verwenden Sie einfach die folgenden Symbole:

00000550 D _binary_foo_end
00000550 A _binary_foo_size 
00000000 D _binary_foo_start

Dies ist kein String-Literal, aber es ist im Wesentlichen dasselbe wie das, was aus einem String-Literal während der Kompilierung wird (bedenken Sie, dass String- Literale zur Laufzeit tatsächlich nicht vorhanden sind; in der Tat gibt Ihnen keine der anderen Antworten ein String-Literal auch zur Kompilierungszeit) und können auf die gleiche Weise aufgerufen werden:

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

Der Nachteil ist, dass Sie Ihre Zielarchitektur angeben müssen, um die Objektdatei kompatibel zu machen. Dies ist in Ihrem Build-System möglicherweise nicht trivial.

Leichtigkeit Rennen mit Monica
quelle
2

Sollte genau das sein, wonach Sie gefragt haben:

hexdump -v -e '"\\" "x" 1/1 "%02X"' file.bin ; echo
Schtrudel
quelle
0

Dies ist ein kurzes Dienstprogramm, das ich geschrieben habe und das im Wesentlichen dasselbe tut (ursprünglich auf Stack Overflow gepostet ):

#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] = '\0';

    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;
}
Gerber
quelle
1
Ihre Antwort wäre nützlicher, wenn Sie auch die Eingabe- und Ausgabebeispiele mitliefern würden.
not2qubit
0

Wenn Sie sich für Python interessieren, laden Sie es in eine Variable "buff" und verwenden Sie so etwas wie Folgendes:

buff2 = buff.encode("hex")
print ("0x"+", 0x".join([buff2[i:i+2] for i in range(0,len(buff2),2)]))
TimSC
quelle