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