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