On Sun, 26 May 2024 13:09:36 +0200
David Brown <
david.brown@hesbynett.no> wrote:
No, it does /not/. That's the /whole/ point of #embed, and the main
motivation for its existence. People have always managed to embed
binary source files into their binary output files - using linker
tricks, or using xxd or other tools (common or specialised) to turn
binary files into initialisers for constant arrays (or structs).
I've done so myself on many projects, all integrated together in
makefiles.
Let's start another round of private parts' measurements turnament!
'xxd -i' vs DIY
/c/altera/13.0sp1/quartus/bin64/db_wys.dll is 52 MB file
$ time xxd -i < /c/altera/13.0sp1/quartus/bin64/db_wys.dll > xxd.txt
real 0m15.288s
user 0m15.054s
sys 0m0.187s
$ time ../quick_xxd/bin_to_list1
/c/altera/13.0sp1/quartus/bin64/db_wys.dll > bin_to_list1.txt
real 0m8.502s
user 0m0.000s
sys 0m0.000s
$ time ../quick_xxd/bin_to_list
/c/altera/13.0sp1/quartus/bin64/db_wys.dll > bin_to_list.txt
real 0m1.326s
user 0m0.000s
sys 0m0.000s
bin_to_list probably limited by write speed of SSD that in this
particular case is ~9 y.o. and was used rather intensively during these
years.
bin_to_list1 is DYI written in ~5 min.
bin_to_list is DYI written in ~55 min.
In post above David Brown mentioned 'other tools (common or
specialised)'. I'd like to know what they are and how fast they are.
Appendix A.
// bin_to_list1.c
#include <stdio.h>
#include <stdlib.h>
int main(int argz, char** argv)
{
if (argz > 1) {
FILE* fp = fopen(argv[1], "rb");
if (fp) {
int c;
while ((c = fgetc(fp)) >= 0)
printf("%d,\n", c);
fclose(fp);
} else {
perror(argv[1]);
return 1;
}
}
return 0;
}
// end of bin_to_list1.c
Appendix B.
// bin_to_list.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static const char usage[] =
"bin_to_list - convert binary file to comma-delimited list of decimal
numbers\n" "Usage:\n"
" bin_to_list infile [oufile]\n"
"When output file is not specified, the result is written to standard
output.\n" ;
int main(int argz, char** argv)
{
// process command line
if (argz < 2) {
fprintf(stderr, "%s", usage);
return 1;
}
char* infilename = argv[1];
static const char *help_aliases[] = { "-h", "-H", "-?", "--help",
"--?" }; const int n_help_aliases =
sizeof(help_aliases)/sizeof(help_aliases[0]); for (int i = 0; i <
n_help_aliases; ++i) { if (strcmp(infilename, help_aliases[i])==0) {
fprintf(stderr, "%s", usage);
return 0;
}
}
// open files
FILE* fpin = fopen(infilename, "rb");
if (!fpin) {
perror(infilename);
return 1;
}
FILE* fpout = stdout;
char* outfilename = NULL;
if (argz > 2) {
outfilename = argv[2];
fpout = fopen(outfilename, "w");
if (!fpout) {
perror(outfilename);
fclose(fpin);
return 1;
}
}
// Initialize table
char bin2dec[256][4];
for (int i = 0; i < 256;++i)
sprintf(bin2dec[i], "%d", i);
// main loop
int err = 0;
int c;
enum { MAX_CHAR_PER_LINE = 80, MAX_CHAR_PER_NUM = 4,
ALMOST_FULL_THR = MAX_CHAR_PER_LINE-MAX_CHAR_PER_NUM };
char outbuf[MAX_CHAR_PER_LINE+1]; // provide space for EOL
char* outptr = outbuf;
while ((c = fgetc(fpin)) >= 0) {
char* dec = bin2dec[c & 255];
do
*outptr++ = *dec++;
while (*dec);
*outptr++ = ',';
if (outptr > &outbuf[ALMOST_FULL_THR]) { // spill output buffer
*outptr++ = '\n';
ptrdiff_t wrlen = fwrite(outbuf, 1, outptr-outbuf, fpout);
if (wrlen != outptr-outbuf) {
err = 2;
break;
}
outptr = outbuf;
}
}
if (ferror(fpin)) {
perror(infilename);
err = 1;
}
// last line
if (outptr != outbuf && err == 0) {
*outptr++ = '\n';
ptrdiff_t wrlen = fwrite(outbuf, 1, outptr-outbuf, fpout);
if (wrlen != outptr-outbuf)
err = 2;
}
// completion and cleanup
if (err == 2 && outfilename)
perror(outfilename);
fclose(fpin);
if (outfilename) {
fclose(fpout);
if (err)
remove(outfilename);
}
return err;
}
// end of bin_to_list.c