Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > ger.ct > #555191 > unrolled thread
| Started by | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| First post | 2022-05-19 11:04 +0200 |
| Last post | 2022-05-20 04:41 +0200 |
| Articles | 9 — 4 participants |
Back to article view | Back to ger.ct
Beliebige Dateien in ein Executable packen Bonita Montero <Bonita.Montero@gmail.com> - 2022-05-19 11:04 +0200
Re: Beliebige Dateien in ein Executable packen "Wendelin Uez" <wuez@online.de> - 2022-05-19 18:06 +0200
Re: Beliebige Dateien in ein Executable packen Bonita Montero <Bonita.Montero@gmail.com> - 2022-05-19 19:05 +0200
Re: Beliebige Dateien in ein Executable packen Stefan Reuther <stefan.news@arcor.de> - 2022-05-19 19:12 +0200
Re: Beliebige Dateien in ein Executable packen Bonita Montero <Bonita.Montero@gmail.com> - 2022-05-19 19:18 +0200
Re: Beliebige Dateien in ein Executable packen Bonita Montero <Bonita.Montero@gmail.com> - 2022-05-19 19:26 +0200
Re: Beliebige Dateien in ein Executable packen Bonita Montero <Bonita.Montero@gmail.com> - 2022-05-20 21:20 +0200
Re: Beliebige Dateien in ein Executable packen Wolfgang Kynast <wky@gmx.de> - 2022-05-19 19:27 +0200
Re: Beliebige Dateien in ein Executable packen Bonita Montero <Bonita.Montero@gmail.com> - 2022-05-20 04:41 +0200
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-05-19 11:04 +0200 |
| Subject | Beliebige Dateien in ein Executable packen |
| Message-ID | <t65169$e3m$1@dont-email.me> |
Ich hab mich mal gefragt, ob es eine Möglichkei gibt, beliebige
Dateien als einfaches char-Array in ein C / C++ executable einzubinden.
Das würde das Handling der Software ggf. einfacher machn, da diese dann
als einzelnes Executable existieren könnte. Ich habe diesbezüglich auf
Stack Overflow gefragt und keine gute Antwort erhalten.
Also habe ich mir ein kleines C++20-Programm geschrieben, das aus einer
beliebigen Datei ein konstantes char-Array macht (d.h. die Daten sind
zur Laufzeit damit nach Standard nicht garantiert überschreibbar). Das
Programm ist unten zu sehen.
Auf jeden Fall hab ich es zuerst versucht, die Datei einfach nach und
nach in einen output filestream zu schreiben. Das war je nach Eingabe
-Datei schnachrchlangsam. Also habe ich die Daten selbst formatiert
in einen String geschrieben, was sehr effizient ist. Dabei ist die
Grenze der Effizienz noch nicht erreicht, sondern ich kann ja vorher
die ganze Datei einmal durchgehen ohne den String zu vergrößern und
durchzählen, wieviel Speicher ich brauche, dass der String nicht in-
krementell immer wieder beim Anfügen vergrößert werden muss. Das geht
mit templated Lambdas in C++20 sehr komfortabel bzw ich übergeben die-
sem Lambda ein Funktionsobjekt zum Anfügen, und beim ersten Aufruf
zählt dieses Funktionsobjekt nur die Bytes um nachfolgend das Array
genau in der richtigen Größe vorzuallokieren, und beim zweiten wird
entsprechend in das Array geschrieben. Der Witz daran ist: das Lambda
für das Zählen oder Schreiben hat einen eigen anonymen Datentyp und
der Code für das Zählen oder Schreiben wird doppelt generiert und im
ersteren Fall entsprechend einigees wegoptimiert. Ich denke wenn man
sowas in gleichermaßen effizient C programmieren würde, dann wäre der
Code sicher fünf bis zehnmal so lange.
#include <iostream>
#include <fstream>
#include <vector>
#include <charconv>
#include <type_traits>
#include <string_view>
using namespace std;
int main( int argc, char **argv )
{
try
{
if( argc < 4 )
return EXIT_FAILURE;
size_t bytesPerLine = 16;
char const
*inFile = argv[1],
*outFile = argv[2],
*symbolName = argv[3],
*sBytesPerLine = argc >= 5 ? argv[4] : nullptr;
if( sBytesPerLine )
{
from_chars_result fcr = from_chars( sBytesPerLine, sBytesPerLine +
strlen( argv[3] ), bytesPerLine );
if( fcr.ec != errc() || *fcr.ptr )
throw invalid_argument( "number of bytes per line format error" );
}
ifstream ifs;
ifs.exceptions( ifstream::failbit | ifstream::badbit );
ifs.open( inFile, ifstream::in | ifstream::binary );
ifs.seekg( 0, ifstream::end );
streampos spSize = ifs.tellg();
if( spSize > (size_t)-1 )
throw invalid_argument( "file too large" );
size_t size = (size_t)spSize;
if( !size )
return EXIT_FAILURE;
using vc_t = vector<char>;
using vc_it = typename vc_t::iterator;
vc_t data( size, 0 );
ifs.seekg( 0, ifstream::beg );
ifs.read( data.data(), (streamsize)size );
ofstream ofsHeader, ofsC;
auto writeDelcaration = [&]( ofstream &ofs, bool definition )
{
ofs.exceptions( ofstream::failbit | ofstream::badbit );
ofs.open( string( string( outFile ) + (!definition ? ".h" : ".c")
).c_str(), ofstream::out | ofstream::trunc | ofstream::binary );
ofs << (!definition ? "extern " : "") << "unsigned char const " <<
symbolName << "[" << data.size() << "]" << (!definition ? ";" : " = ")
<< endl;;
};
writeDelcaration( ofsHeader, false );
writeDelcaration( ofsC, true );
ofsC << "{" << endl;
string bulk;
auto writeBulk = [&]<typename AppendFn>( AppendFn appendFn )
requires requires( AppendFn appendFn, string_view const &sv ) { {
appendFn( sv ) }; }
{
size_t remaining = data.size(), bytesInLine;
for( vc_it cIt = data.begin(); remaining; remaining -= bytesInLine )
{
bytesInLine = remaining >= bytesPerLine ? bytesPerLine : remaining;
appendFn( "\t" );
for( size_t b = 0; b != bytesInLine; ++b )
{
char hex[2 + 2 + 2 + 1];
memcpy( hex, "0x", 2 );
unsigned char byte = cIt[b];
auto toHexChar = []( unsigned char c ) -> char { return c < 10 ? c
+ '0' : c - 10 + 'A'; };
for( size_t i = 2; i--; byte >>= 4 )
hex[2 + i] = toHexChar( byte & 0xF );
size_t nChars = 4;
if( b + 1 != bytesInLine )
memcpy( hex + 2 + 2, ", ", 2 ),
nChars += 2;
else
if( b + 1 < remaining )
hex[2 + 2] = ',',
++nChars;
appendFn( string_view( hex, nChars ) );
}
cIt += bytesInLine;
appendFn( "\n" );
}
};
size_t bulkLength = 0;
writeBulk( [&]( string_view const &sv ) { bulkLength += sv.length(); } );
bulk.reserve( bulkLength );
writeBulk( [&]( string_view const &sv ) { bulk += sv; } );
ofsC << bulk;
ofsC << "};" << endl;
}
catch( exception const &exc )
{
cout << exc.what() << endl;
}
}
[toc] | [next] | [standalone]
| From | "Wendelin Uez" <wuez@online.de> |
|---|---|
| Date | 2022-05-19 18:06 +0200 |
| Message-ID | <t65rqj$91k$1@dont-email.me> |
| In reply to | #555191 |
Um beliebige Dateien in ein selbstgebautes Exe einzubinden gibt es unter Windows die Ressourcenverwaltung (ich nehme mal an, unter Linux dürfte es sowas ebenfalls geben). Die macht genau das, Dateien jeglicher Provenienz als Bytestream in einen res-File einzulagern, und zwar die unterschiedlichsten Dateiformate in eine einzige Datei, also ähnlich wie ein zip-File, nur daß man aus dem Programm heraus eleganter darauf zugreifen kann und es nicht nur komplette Dateien, sondern auch Fragemente wie Texte für Menüs, Bilder u.ä. sein dürfen. Die Frage sei erlaubt, was es bezwecken soll, wenn der Empfänger mittels eines eigenen komprimierten Formats zwar die Bytes erhält, nicht aber den dazu notwendigen Viewer. Dann kann man ihm auch gleich die .xyz-Datei schicken.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-05-19 19:05 +0200 |
| Message-ID | <t65tc7$74v$1@dont-email.me> |
| In reply to | #555290 |
> Um beliebige Dateien in ein selbstgebautes Exe einzubinden gibt es unter > Windows die Ressourcenverwaltung (ich nehme mal an, unter Linux dürfte > es sowas ebenfalls geben). ... Ne, gibt's nicht. Und ich meine Unter Windows kannst Du in die Resorucen auch nicht beliebige binäre Daten packen: https://en.wikipedia.org/wiki/Resource_(Windows)
[toc] | [prev] | [next] | [standalone]
| From | Stefan Reuther <stefan.news@arcor.de> |
|---|---|
| Date | 2022-05-19 19:12 +0200 |
| Message-ID | <t664ql.2d0.1@stefan.msgid.phost.de> |
| In reply to | #555191 |
Am 19.05.2022 um 11:04 schrieb Bonita Montero: > Ich hab mich mal gefragt, ob es eine Möglichkei gibt, beliebige > Dateien als einfaches char-Array in ein C / C++ executable einzubinden. 'xxd -i' und fertig. Kann im Gegensatz zu sowas > ifs.open( inFile, ifstream::in | ifstream::binary ); > ifs.seekg( 0, ifstream::end ); > streampos spSize = ifs.tellg(); auch mit Pipes umgehen. Stefan
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-05-19 19:18 +0200 |
| Message-ID | <t65u53$mbg$1@dont-email.me> |
| In reply to | #555299 |
Am 19.05.2022 um 19:12 schrieb Stefan Reuther: > Am 19.05.2022 um 11:04 schrieb Bonita Montero: >> Ich hab mich mal gefragt, ob es eine Möglichkei gibt, beliebige >> Dateien als einfaches char-Array in ein C / C++ executable einzubinden. > > 'xxd -i' und fertig. > > Kann im Gegensatz zu sowas > >> ifs.open( inFile, ifstream::in | ifstream::binary ); >> ifs.seekg( 0, ifstream::end ); >> streampos spSize = ifs.tellg(); > > auch mit Pipes umgehen. ... aber nicht so effizient. Ich generiere auf meinem Rechner 70mb C-file und den kleinen Header in 200ms. Hrhr.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-05-19 19:26 +0200 |
| Message-ID | <t65ujc$2tn$1@dont-email.me> |
| In reply to | #555301 |
Am 19.05.2022 um 19:18 schrieb Bonita Montero: > Am 19.05.2022 um 19:12 schrieb Stefan Reuther: >> Am 19.05.2022 um 11:04 schrieb Bonita Montero: >>> Ich hab mich mal gefragt, ob es eine Möglichkei gibt, beliebige >>> Dateien als einfaches char-Array in ein C / C++ executable einzubinden. >> >> 'xxd -i' und fertig. >> >> Kann im Gegensatz zu sowas >> >>> ifs.open( inFile, ifstream::in | ifstream::binary ); >>> ifs.seekg( 0, ifstream::end ); >>> streampos spSize = ifs.tellg(); >> >> auch mit Pipes umgehen. > > ... aber nicht so effizient. > Ich generiere auf meinem Rechner 70mb C-file > und den kleinen Header in 200ms. > > Hrhr. > Hab's gerade nochmal ausprobiert: 88.276.992 Bytes in .c und .h ausgegeben mit meinem Progrämmchen ergibt ca ein halbes GB an .c-File und dauern tut das dann knapp weniger als 1,5s. Mit xxd ist die Datei ca. genauso groß, aber die Konvertierung dauert etwas mehr als 27s. Können halt nicht programmieren, die Leute die C nutzen.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-05-20 21:20 +0200 |
| Message-ID | <t68plc$1j9$1@dont-email.me> |
| In reply to | #555303 |
Am 20.05.2022 um 18:09 schrieb Stefan Reuther: > Am 19.05.2022 um 19:26 schrieb Bonita Montero: >> Hab's gerade nochmal ausprobiert: >> 88.276.992 Bytes in .c und .h ausgegeben mit meinem Progrämmchen >> ergibt ca ein halbes GB an .c-File und dauern tut das dann knapp >> weniger als 1,5s. Mit xxd ist die Datei ca. genauso groß, aber >> die Konvertierung dauert etwas mehr als 27s. >> Können halt nicht programmieren, die Leute die C nutzen. > > Wenn Geschwindigkeit relevant wäre, könnte man das auch in C. Was du als > Feature verkaufst und mit fancy C++ Features umsetzt, die Vorallokation > von Puffern, ist für den Anwendungsfall völlig überflüssig: großen > Puffer machen (evtl. gleich einfach den stdio-Puffer vergrößern), bis > Anschlag füllen, bei Anschlag flush. Fertig. Die Eingabe komplett in den > RAM zu lesen halte ich bei Filtern dieser Art grundsätzlich für einen > Implementierungsfehler. Kannst es ja mal vormachen bzw. das wäre bestimmt sehr kurz, aber eben auch sehr langsam. Der Witz an meiner C++20-Lösung ist eben: für das Zählen braucht es nur ein winziges Lambda. Versuch das mal in dieser Murks-Sprache C. > objcopy -I binary -O elf32-i386 in.dat out.o Ist halt nicht portabel.
[toc] | [prev] | [next] | [standalone]
| From | Wolfgang Kynast <wky@gmx.de> |
|---|---|
| Date | 2022-05-19 19:27 +0200 |
| Message-ID | <jencveFfc6jU1@mid.individual.net> |
| In reply to | #555301 |
On Thu, 19 May 2022 19:18:30 +0200, "Bonita Montero" posted: >Am 19.05.2022 um 19:12 schrieb Stefan Reuther: >> Am 19.05.2022 um 11:04 schrieb Bonita Montero: >>> Ich hab mich mal gefragt, ob es eine Möglichkei gibt, beliebige >>> Dateien als einfaches char-Array in ein C / C++ executable einzubinden. >> >> 'xxd -i' und fertig. >> >> Kann im Gegensatz zu sowas >> >>> ifs.open( inFile, ifstream::in | ifstream::binary ); >>> ifs.seekg( 0, ifstream::end ); >>> streampos spSize = ifs.tellg(); >> >> auch mit Pipes umgehen. > >... aber nicht so effizient. >Ich generiere auf meinem Rechner 70mb C-file >und den kleinen Header in 200ms. Und die 70mb verkaufst du dann meistbietend?
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-05-20 04:41 +0200 |
| Message-ID | <t66v3s$93r$1@dont-email.me> |
| In reply to | #555304 |
Am 19.05.2022 um 19:27 schrieb Wolfgang Kynast: > On Thu, 19 May 2022 19:18:30 +0200, "Bonita Montero" posted: > >> Am 19.05.2022 um 19:12 schrieb Stefan Reuther: >>> Am 19.05.2022 um 11:04 schrieb Bonita Montero: >>>> Ich hab mich mal gefragt, ob es eine Möglichkei gibt, beliebige >>>> Dateien als einfaches char-Array in ein C / C++ executable einzubinden. >>> >>> 'xxd -i' und fertig. >>> >>> Kann im Gegensatz zu sowas >>> >>>> ifs.open( inFile, ifstream::in | ifstream::binary ); >>>> ifs.seekg( 0, ifstream::end ); >>>> streampos spSize = ifs.tellg(); >>> >>> auch mit Pipes umgehen. >> >> ... aber nicht so effizient. >> Ich generiere auf meinem Rechner 70mb C-file >> und den kleinen Header in 200ms. > > Und die 70mb verkaufst du dann meistbietend? Soll das lustig sein ?
[toc] | [prev] | [standalone]
Back to top | Article view | ger.ct
csiph-web