Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > ger.ct > #555191 > unrolled thread

Beliebige Dateien in ein Executable packen

Started byBonita Montero <Bonita.Montero@gmail.com>
First post2022-05-19 11:04 +0200
Last post2022-05-20 04:41 +0200
Articles 9 — 4 participants

Back to article view | Back to ger.ct


Contents

  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

#555191 — Beliebige Dateien in ein Executable packen

FromBonita Montero <Bonita.Montero@gmail.com>
Date2022-05-19 11:04 +0200
SubjectBeliebige 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]


#555290

From"Wendelin Uez" <wuez@online.de>
Date2022-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]


#555298

FromBonita Montero <Bonita.Montero@gmail.com>
Date2022-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]


#555299

FromStefan Reuther <stefan.news@arcor.de>
Date2022-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]


#555301

FromBonita Montero <Bonita.Montero@gmail.com>
Date2022-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]


#555303

FromBonita Montero <Bonita.Montero@gmail.com>
Date2022-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]


#555418

FromBonita Montero <Bonita.Montero@gmail.com>
Date2022-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]


#555304

FromWolfgang Kynast <wky@gmx.de>
Date2022-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]


#555321

FromBonita Montero <Bonita.Montero@gmail.com>
Date2022-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