1 /* ======================================================================== */
2 /* LZO_EMBED */
3 /* */
4 /* Use Mini-LZO to compress and obscure files that can then be embedded */
5 /* in another program. */
6 /* */
7 /* Usage: */
8 /* lzo_embed outfile_base file1 [file2 [file3 [...]]] */
9 /* */
10 /* The name "outfile_base" is the name of the desired output file, sans */
11 /* file suffixes. lzo_embed will write two files with that prefix: A */
12 /* .c file and a corresponding .h file. */
13 /* */
14 /* Within the file outfile_base, lzo_embed will output an array of */
15 /* exported structures named "lzoe_[outfile_base]". Each element of */
16 /* that array is a structure containing the following information: */
17 /* */
18 /* -- A pointer to the embedded file's name */
19 /* -- A pointer to the compressed, obscured data */
20 /* -- The length of the compressed and decompressed output */
21 /* -- An 8 byte "obscuring key" */
22 /* */
23 /* The obscuring key is not meant as any sort of hardened encryption. */
24 /* It's only meant to lightly obscure the compressed contents. Anyone */
25 /* with sufficient motivation could extract the embedded file. */
26 /* */
27 /* ======================================================================== */
28 #ifdef NO_LZO
main()29 int main() { return 1; }
30 #else
31
32 #include "config.h"
33 #include "lzoe/lzoe.h"
34 #include "file/file.h"
35 #include "minilzo/minilzo.h"
36
37 #define DEFAULT_ENC_BUF_SZ (1l << 16)
38
39 LOCAL uint8_t *lzo_wrk = NULL, *lzo_inp = NULL, *lzo_out = NULL;
40 LOCAL long lzo_enc_buf_sz = DEFAULT_ENC_BUF_SZ;
41 LOCAL lzoe_info *info = NULL;
42 LOCAL int lzoe_cnt;
43 LOCAL char *cheader, *csource;
44 LOCAL char *uc_name, *lc_name;
45
46
lzo_buf_alloc(long at_least)47 LOCAL void lzo_buf_alloc( long at_least )
48 {
49 static int needed = 1;
50
51 if (!lzo_wrk)
52 {
53 if (! (lzo_wrk = CALLOC(uint8_t, LZO1X_MEM_COMPRESS)) ) goto oom;
54 }
55
56 while (at_least > lzo_enc_buf_sz)
57 {
58 lzo_enc_buf_sz <<= 1;
59 needed = 1;
60 }
61
62 if (needed)
63 {
64
65 lzo_inp = REALLOC(lzo_inp, uint8_t, lzo_enc_buf_sz);
66 lzo_out = REALLOC(lzo_out, uint8_t, lzo_enc_buf_sz * 1088 / 1024);
67 needed = 0;
68
69 if (!lzo_inp || !lzo_out)
70 goto oom;
71 }
72
73 return;
74
75 oom:
76 fprintf(stderr, "Out of memory\n");
77 exit(1);
78 }
79
next_lzoe(void)80 LOCAL lzoe_info *next_lzoe( void )
81 {
82 info = REALLOC(info, lzoe_info, ++lzoe_cnt);
83 return info + lzoe_cnt - 1;
84 }
85
push_lzoe_info(const char * fname,long orig_len,long comp_len,const uint8_t * cdata)86 LOCAL void push_lzoe_info( const char *fname, long orig_len, long comp_len,
87 const uint8_t *cdata )
88 {
89 uint8_t *buf = CALLOC( uint8_t, comp_len );
90
91 lzoe_info *new_info = next_lzoe();
92
93 new_info->fname = fname;
94 new_info->orig_len = orig_len;
95 new_info->comp_len = comp_len;
96 new_info->cdata = buf;
97
98 if (!new_info->cdata)
99 {
100 fprintf(stderr, "Out of memory\n");
101 exit(1);
102 }
103
104 memcpy(buf, cdata, comp_len);
105 }
106
read_and_compress(int cnt,char * fnames[])107 LOCAL void read_and_compress( int cnt, char *fnames[] )
108 {
109 int i;
110
111 /* Read and compress all the input files */
112 for (i = 0; i < cnt; i++)
113 {
114 const char *fname = fnames[i];
115 FILE *f;
116 long fl;
117 int r;
118 lzo_uint lzo_len = 0;
119
120 if (! (f = fopen( fname, "rb" ) ) )
121 {
122 perror("fopen()");
123 fprintf(stderr, "Error opening %s for reading\n", fname);
124 exit(1);
125 }
126
127 fseek(f, 0, SEEK_END);
128 fl = ftell(f);
129 rewind(f);
130 lzo_buf_alloc( fl );
131
132 if ( (long)fread( lzo_inp, 1, fl, f ) != fl )
133 {
134 perror("fread()");
135 fprintf(stderr, "Error reading input file %s\n", fname);
136 exit(1);
137 }
138 fclose( f );
139
140 r = lzo1x_1_compress( lzo_inp, (lzo_uint)fl, lzo_out, &lzo_len,
141 (lzo_voidp)lzo_wrk );
142
143 if (r == LZO_E_OK)
144 push_lzoe_info( fname, fl, lzo_len, lzo_out );
145
146 printf("Compressed %s from %ld bytes to %ld bytes.\n", fname,
147 fl, (long)lzo_len );
148 }
149 }
150
make_names_from_base(const char * const base_name)151 LOCAL void make_names_from_base( const char *const base_name )
152 {
153 int i, blen;
154
155 blen = strlen(base_name);
156 cheader = CALLOC(char, blen + 2);
157 csource = CALLOC(char, blen + 2);
158 uc_name = CALLOC(char, blen);
159 lc_name = CALLOC(char, blen);
160
161 if (!cheader || !csource || !uc_name || !lc_name)
162 {
163 fprintf( stderr, "Out of memory\n" );
164 exit(1);
165 }
166
167 memcpy(cheader, base_name, blen); memcpy(cheader + blen, ".h", 3);
168 memcpy(csource, base_name, blen); memcpy(csource + blen, ".c", 3);
169
170 for (i = 0; i < blen; i++)
171 {
172 int uc = base_name[i], lc;
173
174 if (!isalpha( uc ) && !isdigit( uc )) uc = lc = '_';
175 else { lc = tolower(uc); uc = toupper(uc); }
176
177 uc_name[i] = uc;
178 lc_name[i] = lc;
179 }
180
181 uc_name[ blen ] = lc_name[ blen ] = 0;
182 }
183
write_cheader(void)184 LOCAL void write_cheader( void )
185 {
186 FILE *fh = fopen( cheader, "w" );
187
188 if (!fh)
189 {
190 perror( "fopen()" );
191 fprintf(stderr, "Error opening %s for writing\n", cheader);
192 exit(1);
193 }
194
195 fprintf( fh,
196 "#ifndef LZOE_%s\n"
197 "#define LZOE_%s 1\n"
198 "\n"
199 "#include \"lzoe/lzoe.h\"\n"
200 "\n"
201 "extern const lzoe_info lzoe_%s[%d];\n"
202 "#endif\n",
203 uc_name, uc_name, lc_name, lzoe_cnt + 1 );
204
205 fclose( fh );
206 }
207
208
write_csource(void)209 LOCAL void write_csource( void )
210 {
211 FILE *fc = fopen( csource, "w" );
212 int i, j;
213
214 if (!fc)
215 {
216 perror( "fopen()" );
217 fprintf(stderr, "Error opening %s for writing\n", cheader);
218 exit(1);
219 }
220
221 fprintf( fc, "#include \"config.h\"\n"
222 "#include \"lzoe/lzoe.h\"\n\n" );
223
224 for (i = 0; i < lzoe_cnt; i++)
225 {
226 fprintf( fc, "static const uint8_t cdata_%04d[] =\n{\n", i );
227
228 for (j = 0; j < info[i].comp_len; j++)
229 {
230 if ((j & 7) == 0) fprintf(fc, " ");
231
232 fprintf( fc, "0x%02X", info[i].cdata[j] );
233
234 if (j == info[i].comp_len - 1) fprintf( fc, "\n};\n\n" );
235 else if ((j & 7) == 7) fprintf( fc, ",\n" );
236 else fprintf( fc, ", " );
237 }
238 }
239
240 fprintf( fc, "const lzoe_info lzoe_%s[%d] =\n{\n", lc_name, lzoe_cnt + 1);
241
242 for (i = 0; i < lzoe_cnt; i++)
243 {
244 fprintf( fc, " { \"%s\", %ld, %ld, cdata_%04d },\n",
245 info[i].fname, info[i].orig_len, info[i].comp_len, i
246 );
247 }
248
249 fprintf(fc, " { NULL, 0, 0, NULL }\n};\n");
250 fclose( fc );
251 }
252
253
main(int argc,char * argv[])254 int main( int argc, char *argv[] )
255 {
256 if (argc < 3)
257 {
258 fprintf(stderr,
259 "Usage: lzo_embed outfile_base file1 [file2 [file3 [...]]]\n");
260 exit(1);
261 }
262
263 make_names_from_base( argv[1] );
264 read_and_compress( argc - 2, argv + 2 );
265 write_cheader( );
266 write_csource( );
267
268 return 0;
269 }
270
271
272 #endif
273