summaryrefslogtreecommitdiff
path: root/bin2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin2c.c')
-rw-r--r--bin2c.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/bin2c.c b/bin2c.c
new file mode 100644
index 0000000..dcc0b7c
--- /dev/null
+++ b/bin2c.c
@@ -0,0 +1,135 @@
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#define MAXLINEWIDTH (79)
+
+void usage(){
+ fprintf(stderr,
+ "Usage: bin2c [inputfile] [outputfile]\n"
+ "\n"
+ "Converts a binary file to a C string that denotes the same binary contents, but\n"
+ "is parseable by a C compiler.\n"
+ "Default values for the arguments are stdin and stdout; also '-' indicates the\n"
+ "standard stream.\n");
+}
+
+// Returns serialised string length
+// Keeps state on the previous few characters to aid compression
+int serialisechar(char *dst,unsigned char c){
+ static bool lastwasoctal=false;
+ static unsigned char prevc; // Only used if lastwasoctal==true
+
+ switch(c){
+ case '\a': lastwasoctal=false; dst[0]='\\'; dst[1]='a'; return 2;
+ case '\b': lastwasoctal=false; dst[0]='\\'; dst[1]='b'; return 2;
+ case '\f': lastwasoctal=false; dst[0]='\\'; dst[1]='f'; return 2;
+ case '\n': lastwasoctal=false; dst[0]='\\'; dst[1]='n'; return 2;
+ case '\r': lastwasoctal=false; dst[0]='\\'; dst[1]='r'; return 2;
+ case '\t': lastwasoctal=false; dst[0]='\\'; dst[1]='t'; return 2;
+ case '\v': lastwasoctal=false; dst[0]='\\'; dst[1]='v'; return 2;
+ case '"': lastwasoctal=false; dst[0]='\\'; dst[1]='"'; return 2;
+ case '\\': lastwasoctal=false; dst[0]='\\'; dst[1]='\\'; return 2;
+ default:
+ if(c<32||c>=127){
+ lastwasoctal=true;
+ prevc=c;
+ return sprintf(dst,"\\%o",(int)c);
+ } else if(isdigit(c)&&lastwasoctal&&prevc<'\100'){
+ prevc=c;
+ return sprintf(dst,"\\%o",(int)c);
+ } else {
+ lastwasoctal=false;
+ dst[0]=c;
+ return 1;
+ }
+ }
+}
+
+// Returns new xposition
+int convertbuffer(FILE *output,const char *buffer,int length,int xposition){
+ char cbuf[8];
+ for(int i=0;i<length;i++){
+ int clen=serialisechar(cbuf,buffer[i]);
+ if(xposition+clen>MAXLINEWIDTH){
+ fputc('"',output);
+ fputc('\n',output);
+ fputc('"',output);
+ xposition=1;
+ }
+ fwrite(cbuf,1,clen,output);
+ xposition+=clen;
+ }
+ return xposition;
+}
+
+void bin2c(FILE *input,FILE *output){
+ fputc('"',output);
+
+ char buffer[1024];
+ int xposition=1;
+
+ while(true){
+ size_t nread=fread(buffer,1,sizeof(buffer),input);
+ if(nread==0){
+ break;
+ }
+ xposition=convertbuffer(output,buffer,nread,xposition);
+ if(feof(input)||ferror(input)){
+ break;
+ }
+ }
+
+ fputc('"',output);
+ fputc('\n',output);
+}
+
+int main(int argc,char **argv){
+ if(argc==1){
+ bin2c(stdin,stdout);
+ } else if(argc==2){
+ if(strcmp(argv[1],"-h")==0||strcmp(argv[1],"--help")==0){
+ usage();
+ } else if(strcmp(argv[1],"-")==0){
+ bin2c(stdin,stdout);
+ } else {
+ FILE *f=fopen(argv[1],"rb");
+ if(!f){
+ fprintf(stderr,"Could not open file '%s'\n",argv[1]);
+ return 1;
+ }
+ bin2c(f,stdout);
+ fclose(f);
+ }
+ } else if(argc==3){
+ FILE *fin,*fout;
+ if(strcmp(argv[1],"-")==0){
+ fin=stdin;
+ } else {
+ fin=fopen(argv[1],"rb");
+ if(!fin){
+ fprintf(stderr,"Could not open file '%s'\n",argv[1]);
+ return 1;
+ }
+ }
+
+ if(strcmp(argv[2],"-")==0){
+ fout=stdout;
+ } else {
+ fout=fopen(argv[2],"rb");
+ if(!fout){
+ fprintf(stderr,"Could not open file '%s'\n",argv[2]);
+ return 1;
+ }
+ }
+
+ bin2c(fin,fout);
+
+ fclose(fin);
+ fclose(fout);
+ } else {
+ usage();
+ return 1;
+ }
+}