1 /*
2 Copyright (C) 2009  Justin Karneges
3 
4 This file is free software; unlimited permission is given to copy and/or
5 distribute it, with or without modifications, as long as this notice is
6 preserved.
7 */
8 
9 #include "embed.h"
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 
15 #if defined(WIN32) || defined(_WIN32)
16 # define QC_OS_WIN
17 # include <windows.h>
18 #endif
19 
20 // this hash stuff is total overkill but i was bored
21 
22 static const char *BLOCKSIG_ID = "QCONF_CONFIGWIN_BLOCKSIG";
23 
calc_hash(const char * in,int len)24 static unsigned int calc_hash(const char *in, int len)
25 {
26 	unsigned int x;
27 	int n;
28 
29 	x = 0;
30 	for(n = 0; n < len; ++n)
31 	{
32 		x <<= 4;
33 		x ^= (unsigned int)in[n];
34 	}
35 	return x;
36 }
37 
38 // result should be "QCONF_CONFIGWIN_BLOCKSIG_68b7e7d7"
39 //
40 // the basic idea here is that we use this string as a marker for our
41 //   appended data section, but we don't want to include this actual
42 //   string in our code otherwise it could be misinterpretted as the
43 //   marker
blocksig()44 static char *blocksig()
45 {
46 	char *blocksig_data;
47 	int idlen;
48 	unsigned int hash;
49 	char hashstr[9];
50 	int n;
51 
52 	idlen = strlen(BLOCKSIG_ID);
53 	hash = calc_hash(BLOCKSIG_ID, idlen);
54 	blocksig_data = (char *)malloc(idlen + 1 + 8 + 1);
55 	memcpy(blocksig_data, BLOCKSIG_ID, idlen);
56 	blocksig_data[idlen] = '_';
57 	sprintf(hashstr, "%08x", hash);
58 	for(n = 0; n < 8; ++n)
59 		blocksig_data[idlen + 1 + n] = hashstr[n];
60 	blocksig_data[idlen + 1 + 8] = 0;
61 
62 	return blocksig_data;
63 }
64 
app_file_path(const char * argv0)65 static char *app_file_path(const char *argv0)
66 {
67 #ifdef QC_OS_WIN
68 	char module_name[MAX_PATH+1];
69 	(void)argv0;
70 	GetModuleFileNameA(0, module_name, MAX_PATH);
71 	module_name[MAX_PATH] = 0;
72 	return strdup(module_name);
73 #else
74 	return strdup(argv0);
75 #endif
76 }
77 
find_partial(const char * in,int in_size,const char * sub,int sub_size)78 static int find_partial(const char *in, int in_size, const char *sub, int sub_size)
79 {
80 	int n;
81 	int size;
82 
83 	for(n = 0; n < in_size; ++n)
84 	{
85 		if(sub_size < in_size - n)
86 			size = sub_size;
87 		else
88 			size = in_size - n;
89 		if(memcmp(in + n, sub, size) == 0)
90 			return n;
91 	}
92 
93 	return -1;
94 }
95 
seek_string(FILE * fp,const char * str)96 static int seek_string(FILE *fp, const char *str)
97 {
98 	char block[8192];
99 	int str_at;
100 	int str_len;
101 	int size;
102 	int ret;
103 	int pos;
104 
105 	str_len = strlen(str);
106 	str_at = 0;
107 	pos = ftell(fp);
108 	while(!feof(fp))
109 	{
110 		size = fread(block, 1, 8192, fp);
111 		if(size < 1)
112 			break;
113 
114 		ret = find_partial(block, size, str + str_at, str_len - str_at);
115 		if(ret != -1)
116 		{
117 			if(str_at + (size - ret) >= str_len)
118 			{
119 				if(fseek(fp, pos + ret - str_at + str_len, SEEK_SET) != 0)
120 					return 0;
121 
122 				return 1;
123 			}
124 			else
125 				str_at += (size - ret);
126 		}
127 
128 		pos += size;
129 	}
130 
131 	return 0;
132 }
133 
read32(const unsigned char * in)134 unsigned int read32(const unsigned char *in)
135 {
136 	unsigned int out = in[0];
137 	out <<= 8;
138 	out += in[1];
139 	out <<= 8;
140 	out += in[2];
141 	out <<= 8;
142 	out += in[3];
143 	return out;
144 }
145 
146 // format is:
147 //    <blocksig> <uint32 size> <data....>
148 
import_data(const char * argv0,const char * sig,unsigned char ** ret_data,unsigned int * ret_size)149 static int import_data(const char *argv0, const char *sig, unsigned char **ret_data, unsigned int *ret_size)
150 {
151 	char *fname;
152 	FILE *fp;
153 	int ret;
154 	unsigned char buf[4];
155 	unsigned int size;
156 	unsigned char *data;
157 
158 	fname = app_file_path(argv0);
159 	if(!fname)
160 		return 0;
161 	fp = fopen(fname, "rb");
162 	if(!fp)
163 		return 0;
164 	if(!seek_string(fp, sig))
165 		return 0;
166 	ret = fread(buf, 4, 1, fp);
167 	if(ret < 1)
168 		return 0;
169 	size = read32(buf);
170 	data = (unsigned char *)malloc(size);
171 	if(!data)
172 		return 0;
173 	ret = fread(data, size, 1, fp);
174 	if(ret < 1)
175 	{
176 		free(data);
177 		return 0;
178 	}
179 	fclose(fp);
180 
181 	*ret_data = data;
182 	*ret_size = size;
183 	return 1;
184 }
185 
embed_get_data(const char * argv0,unsigned char ** ret_data,unsigned int * ret_size)186 int embed_get_data(const char *argv0, unsigned char **ret_data, unsigned int *ret_size)
187 {
188 	char *sig;
189 	int ret;
190 
191 	sig = blocksig();
192 	//printf("%s\n", sig);
193 	ret = import_data(argv0, sig, ret_data, ret_size);
194 	free(sig);
195 
196 	return ret;
197 }
198