45b2a3d2740d6cb6ef321cc4494d6a9470db9354
[swftools.git] / installer / mkarchive.c
1 /* mkarchive.c
2
3    Part of the rfx installer (Main program).
4    
5    Copyright (c) 2004-2008 Matthias Kramm <kramm@quiss.org> 
6  
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <memory.h>
27 #include <zlib.h>
28 #define ZLIB_BUFFER_SIZE 16384
29
30 typedef struct _writer
31 {
32     int (*write)(struct _writer*, void*data, int len);
33     void (*finish)(struct _writer*);
34     void *internal;
35 } writer_t;
36
37 /* ---------------------------- file writer ------------------------------- */
38
39 typedef struct
40 {
41     FILE*fi;
42 } filewrite_t;
43 static int writer_filewrite_write(writer_t*w, void* data, int len) 
44 {
45     filewrite_t * fw= (filewrite_t*)w->internal;
46     return fwrite(data, len, 1, fw->fi);
47 }
48 static void writer_filewrite_finish(writer_t*w)
49 {
50     filewrite_t *mr = (filewrite_t*)w->internal;
51     fclose(mr->fi);
52     free(w->internal);
53     memset(w, 0, sizeof(writer_t));
54 }
55 writer_t*writer_init_filewriter(char*filename)
56 {
57     writer_t*w = malloc(sizeof(writer_t));
58     FILE*fi = fopen(filename, "wb");
59     filewrite_t *mr = (filewrite_t *)malloc(sizeof(filewrite_t));
60     mr->fi = fi;
61     memset(w, 0, sizeof(writer_t));
62     w->write = writer_filewrite_write;
63     w->finish = writer_filewrite_finish;
64     w->internal = mr;
65     return w;
66 }
67
68 /* ---------------------------- include file filter ------------------------------- */
69
70 typedef struct _ifwrite
71 {
72     FILE*fi;
73     int bp;
74     int pos;
75     int last;
76     char buf[1024];
77     char*filename;
78 } ifwrite_t;
79
80 static int writer_ifwrite_write(writer_t*out, void*data, int len)
81 {
82     ifwrite_t*i = (ifwrite_t*)out->internal;
83     FILE*fo = i->fi;
84     int t;
85     for(t=0;t<len;t++) {
86         unsigned char c = ((unsigned char*)data)[t];
87         if(i->bp>=80) {
88             fprintf(fo, "\"%s\"\n", i->buf);
89             i->bp = 0;
90         }
91         if(c<=32 || c>0x7e || c=='"' || c == '\\' || c == '%'
92         || (i->last && c>='0' && c<='9') 
93         || (i->last && c>='a' && c<='f')
94         || (i->last && c>='A' && c<='F')
95         ) {
96             i->bp += sprintf(i->buf+i->bp, "\\x%x",c);
97             i->last = 1;
98         } else {
99             i->buf[i->bp] = c;
100             i->buf[i->bp+1] = 0;
101             i->last = 0;
102             i->bp++;
103         }
104         i->pos++;
105     }
106 }
107 static void writer_ifwrite_finish(writer_t*w)
108 {
109     ifwrite_t *i= (ifwrite_t*)w->internal;
110     fprintf(i->fi, "\"%s\"\n", i->buf);
111     fprintf(i->fi, ";\n");
112     fprintf(i->fi, "int crndata_len = %d;\n", i->pos);
113     fclose(i->fi);
114     printf("wrote file %s\n", i->filename);
115     free(w->internal);w->internal = 0;
116 }
117
118 writer_t*writer_init_includewriter(char*filename)
119 {
120     writer_t*w = malloc(sizeof(writer_t));
121     FILE*fi = fopen(filename, "wb");
122     memset(w, 0, sizeof(writer_t));
123     w->write = writer_ifwrite_write;
124     w->finish = writer_ifwrite_finish;
125     ifwrite_t*i = (ifwrite_t *)malloc(sizeof(ifwrite_t));
126     i->fi = fi;
127     i->pos = 0;
128     i->bp=0;
129     i->last = 0;
130     i->filename = filename;
131     w->internal = i;
132     
133     fprintf(i->fi, "char* crndata =\n");
134     return w;
135
136 }
137
138 /* ---------------------------- zlibdeflate writer -------------------------- */
139
140 struct zlibdeflate_t
141 {
142     z_stream zs;
143     writer_t*output;
144     int written;
145     int zwritten;
146     unsigned char writebuffer[ZLIB_BUFFER_SIZE];
147 };
148
149 static void zlib_error(int ret, char* msg, z_stream*zs)
150 {
151     fprintf(stderr, "%s: zlib error (%d): last zlib error: %s\n",
152           msg,
153           ret,
154           zs->msg?zs->msg:"unknown");
155     perror("errno:");
156     exit(1);
157 }
158
159 static int writer_zlibdeflate_write(writer_t*writer, void* data, int len) 
160 {
161     struct zlibdeflate_t*z = (struct zlibdeflate_t*)writer->internal;
162     int ret;
163
164     if(!z) {
165         fprintf(stderr, "zlib not initialized!\n");
166         return 0;
167     }
168     if(!len)
169         return 0;
170     
171     z->zs.next_in = (Bytef *)data;
172     z->zs.avail_in = len;
173
174     while(1) {
175         ret = deflate(&z->zs, Z_NO_FLUSH);
176         
177         if (ret != Z_OK) zlib_error(ret, "bitio:deflate_deflate", &z->zs);
178
179         if(z->zs.next_out != z->writebuffer) {
180             z->zwritten += z->zs.next_out - (Bytef*)z->writebuffer;
181             z->output->write(z->output, z->writebuffer, z->zs.next_out - (Bytef*)z->writebuffer);
182             z->zs.next_out = z->writebuffer;
183             z->zs.avail_out = ZLIB_BUFFER_SIZE;
184         }
185
186         if(!z->zs.avail_in) {
187             break;
188         }
189     }
190     z->written += len;
191     return len;
192 }
193 static void writer_zlibdeflate_finish(writer_t*writer)
194 {
195     struct zlibdeflate_t*z = (struct zlibdeflate_t*)writer->internal;
196     writer_t*output;
197     int ret;
198     if(!z)
199         return;
200     output= z->output;
201     while(1) {
202         ret = deflate(&z->zs, Z_FINISH);
203         if (ret != Z_OK &&
204             ret != Z_STREAM_END) zlib_error(ret, "bitio:deflate_finish", &z->zs);
205
206         if(z->zs.next_out != z->writebuffer) {
207             z->zwritten += z->zs.next_out - (Bytef*)z->writebuffer;
208             z->output->write(z->output, z->writebuffer, z->zs.next_out - (Bytef*)z->writebuffer);
209             z->zs.next_out = z->writebuffer;
210             z->zs.avail_out = ZLIB_BUFFER_SIZE;
211         }
212
213         if (ret == Z_STREAM_END) {
214             break;
215
216         }
217     }
218     ret = deflateEnd(&z->zs);
219     if (ret != Z_OK) zlib_error(ret, "bitio:deflate_end", &z->zs);
220
221     if(z->written) {
222         printf("Compression ratio: %.2f%% (%d bytes of input data, %d bytes of output data)\n", 
223                 z->zwritten*100.0 / z->written,
224                 z->written, z->zwritten);
225     } else {
226         printf("Compression ratio: 0%% (0 bytes of input data, %d bytes of output data)\n", z->zwritten);
227     }
228
229     free(writer->internal);
230     memset(writer, 0, sizeof(writer_t));
231     output->finish(output); 
232 }
233 writer_t*writer_init_zwriter(writer_t*output)
234 {
235     writer_t*w = malloc(sizeof(writer_t));
236     struct zlibdeflate_t*z;
237     int ret;
238     memset(w, 0, sizeof(writer_t));
239     z = (struct zlibdeflate_t*)malloc(sizeof(struct zlibdeflate_t));
240     memset(z, 0, sizeof(struct zlibdeflate_t));
241     w->internal = z;
242     w->write = writer_zlibdeflate_write;
243     w->finish = writer_zlibdeflate_finish;
244     z->output = output;
245     memset(&z->zs,0,sizeof(z_stream));
246     z->zs.zalloc = Z_NULL;
247     z->zs.zfree  = Z_NULL;
248     z->zs.opaque = Z_NULL;
249     ret = deflateInit(&z->zs, 9);
250     if (ret != Z_OK) zlib_error(ret, "bitio:deflate_init", &z->zs);
251     z->zs.next_out = z->writebuffer;
252     z->zs.avail_out = ZLIB_BUFFER_SIZE;
253     z->written = 0;
254     z->zwritten = 0;
255     return w;
256 }
257
258 /* ------------------------------- main ----------- ------------------------------- */
259
260 static int compare_filenames(const void*_n1, const void*_n2)
261 {
262     const char*s1 = *(const char**)_n1;
263     const char*s2 = *(const char**)_n2;
264
265     char*e1 = strrchr(s1, '.');
266     char*e2 = strrchr(s2, '.');
267     if(!e1 && !e2)
268         return 0;
269     if(e1 && !e2)
270         return 1;
271     if(!e1 && e2)
272         return -1;
273     int c = strcasecmp(e1+1,e2+1);
274     if(c)
275         return c;
276     return strcasecmp(s1,s2);
277 }
278
279 int main (int argn, char*argv[])
280 {
281     int t;
282     char buf[320];
283     int num = 0;
284
285     int fullsize = 0;
286     for(t=1;t<argn;t++)
287     {
288         if(argv[t][0]!='-')
289         {
290             FILE*fi=fopen(argv[t],"rb");
291             if(fi) {
292                 fseek(fi,0,SEEK_END);
293                 long l=ftell(fi);
294                 fclose(fi);
295                 fullsize += l;
296                 num++;
297             }
298         }
299     }
300
301
302 #ifdef ZLIB
303     writer_t*include_writer = writer_init_includewriter("crnfiles.c");
304     writer_t*zwriter = writer_init_zwriter(include_writer);
305 #else //LZMA
306     unlink("crnfiles.dat");
307     unlink("crnfiles.7z");
308     unlink("crnfiles.c");
309     writer_t*zwriter = writer_init_filewriter("crnfiles.dat");
310 #endif
311     unsigned char n1=num;
312     unsigned char n2=num>>8;
313     unsigned char n3=num>>16;
314     unsigned char n4=num>>24;
315     zwriter->write(zwriter,&n1,1);
316     zwriter->write(zwriter,&n2,1);
317     zwriter->write(zwriter,&n3,1);
318     zwriter->write(zwriter,&n4,1);
319
320     qsort(argv+1, argn-1, sizeof(argv[0]), compare_filenames);
321
322     for(t=1;t<argn;t++)
323     {
324             if(argv[t][0]!='-')
325             {
326                     FILE*fi=fopen(argv[t],"rb");
327                     if(fi)
328                     {
329                             fseek(fi,0,SEEK_END);
330                             long l=ftell(fi);
331                             fseek(fi,0,SEEK_SET);
332
333                             char*buf=(char*)malloc(l);
334                             char*id="NUL";
335                             struct stat st;
336                             fstat(fileno(fi),&st);
337                             if(S_ISDIR(st.st_mode)) {id ="DIR";l=0;}
338                             else if(strstr(argv[t],".swf")) id="SWF";
339                             else if(strstr(argv[t],".gif")) id="PIC";
340                             else if(strstr(argv[t],".png")) id="PIC";
341                             else if(strstr(argv[t],".jpeg")) id="PIC";
342                             else if(strstr(argv[t],".jpg")) id="PIC";
343                             else if(strstr(argv[t],".tif")) id="PIC";
344                             else if(strstr(argv[t],".ico")) id="PIC";
345                             else if(strstr(argv[t],".c")) id="SRC";
346                             else if(strstr(argv[t],".cc")) id="SRC";
347                             else if(strstr(argv[t],".cpp")) id="SRC";
348                             else if(strstr(argv[t],".h")) id="SRC";
349                             else if(strstr(argv[t],".class")) id="CLA";
350                             else if(strstr(argv[t],".java")) id="SRC";
351                             else if(strstr(argv[t],".exe")) id="EXE";
352                             else if(strstr(argv[t],".ttf")) id="FON";
353                             else if(strstr(argv[t],".pfa")) id="FON";
354                             else if(strstr(argv[t],".pfb")) id="FON";
355                             else if(strstr(argv[t],".afm")) id="FON";
356                             else if(strstr(argv[t],".1")) id="DOC";
357                             else if(strstr(argv[t],".doc")) id="DOC";
358                             else if(strstr(argv[t],".txt")) id="TXT";
359                             else if(strstr(argv[t],".hlp")) id="DOC";
360                             else if(strstr(argv[t],".dll")) id="DLL";
361
362                             fread(buf,l,1,fi);
363                             zwriter->write(zwriter,id,3);
364                             unsigned char b1=l;
365                             unsigned char b2=l>>8;
366                             unsigned char b3=l>>16;
367                             unsigned char b4=l>>24;
368                             zwriter->write(zwriter,&b1,1);
369                             zwriter->write(zwriter,&b2,1);
370                             zwriter->write(zwriter,&b3,1);
371                             zwriter->write(zwriter,&b4,1);
372                             int sl=strlen(argv[t]);
373                             if(sl>255) {
374                                 fprintf(stderr, "Error: filename %s too long\n", argv[t]);
375                             }
376                             unsigned char b = sl;
377                             zwriter->write(zwriter,&b,1); //write filename len
378                             zwriter->write(zwriter,argv[t],sl); //write filename
379                             zwriter->write(zwriter,buf,l); //write data
380                             fprintf(stderr,"[%s] %s: %d bytes written.\n", id, argv[t], l);
381                             fclose(fi);
382                             free(buf);
383                     }
384                     else
385                     {
386                             fprintf(stderr,"%s not found.\n", argv[t]);
387                     }
388             }
389     }
390     char*id_end = "END";
391     zwriter->write(zwriter,id_end,3);
392     zwriter->finish(zwriter);
393
394 #ifndef ZLIB
395     if(system("do_lzma e crnfiles.dat crnfiles.7z")&0xff00) {
396         perror("do_lzma");
397         exit(1);
398     }
399     FILE*fi = fopen("crnfiles.7z", "rb");
400     if(!fi) {
401         perror("crnfiles.7z");
402         exit(1);
403     }
404     writer_t*w = writer_init_includewriter("crnfiles.c");
405     while(!feof(fi)) {
406         char buf[4096];
407         int len = fread(buf,1,4096,fi);
408         if(!len)
409             break;
410         w->write(w, buf, len);
411     }
412     w->finish(w);
413     fclose(fi);
414     if(unlink("crnfiles.dat")) {
415         perror("crnfiles.dat");
416         exit(1);
417     }
418     if(unlink("crnfiles.7z")) {
419         perror("crnfiles.7z");
420         exit(1);
421     }
422 #endif
423
424     fi = fopen("crnfiles.c", "ab+");
425     fprintf(fi, "\nint crn_decompressed_size=%d;\n", fullsize);
426     fclose(fi);
427
428     return 0;
429 }
430