Generated from configure.in
[swftools.git] / src / swfcombine.c
1 /* swfcombine.c
2    main routine for swfcombine(1), which is a tool for merging .swf-files.
3
4    Part of the swftools package.
5    
6    Copyright (c) 2001 Matthias Kramm <kramm@quiss.org> 
7
8    This file is distributed under the GPL, see file COPYING for details */
9
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include "../lib/args.h"
14 #include "combine.h"
15 #include "settings.h"
16 #include "types.h"
17 #include "flash.h"
18 #include "../config.h"
19
20 char * master_filename = 0;
21 char * master_name = 0;
22 char * slave_filename[128];
23 char * slave_name[128];
24 int slave_movex[128];
25 int slave_movey[128];
26 float slave_scalex[128];
27 float slave_scaley[128];
28 int numslaves = 0;
29
30 char * outputname = "output.swf";
31
32 int args_callback_option(char*name,char*val) {
33     if(!strcmp(name,"c"))
34     {
35         config.clip = 1;
36         return 0;
37     }
38     else if(!strcmp(name,"l"))
39     {
40         config.overlay = 1;
41         return 0;
42     }
43     else if (!strcmp(name, "o"))
44     {
45         outputname = val;
46         return 1;
47     }
48     else if (!strcmp(name, "v"))
49     {
50         config.loglevel ++;
51         return 0;
52     }
53     else if (!strcmp(name, "a"))
54     {
55         config.alloctest = 1;
56         return 0;
57     }
58     else if (!strcmp(name, "x"))
59     {
60         config.movex = atoi(val);
61         return 1;
62     }
63     else if (!strcmp(name, "y"))
64     {
65         config.movey = atoi(val);
66         return 1;
67     }
68     else if (!strcmp(name, "s"))
69     {
70         config.scalex = config.scaley = atoi(val)/100.0;
71         return 1;
72     }
73     else if (!strcmp(name, "t"))
74     {
75         if(master_filename) {
76             fprintf(stderr, "error with arguments. Try --help.\n");
77             exit(1);
78         }
79         config.stack = 1;
80         master_filename = "__none__";
81         return 0;
82     }
83     else if (!strcmp(name, "V"))
84     {   
85         printf("swfcombine - part of %s %s\n", PACKAGE, VERSION);
86         exit(0);
87     }
88     else 
89     {
90         fprintf(stderr, "Unknown option: -%s\n", name);
91         exit(1);
92     }
93 }
94
95 struct options_t options[] =
96 {{"o","output"},
97  {"s","scale"},
98  {"x","xpos"},
99  {"y","ypos"},
100  {"l","overlay"},
101  {"t","stack"},
102  {"v","verbose"},
103  {"V","version"},
104  {"c","clip"},
105  {0,0}
106 };
107
108 int args_callback_longoption(char*name,char*val) {
109     return args_long2shortoption(options, name, val);
110 }
111
112 int args_callback_command(char*name, char*val) {
113     char*myname = strdup(name);
114     char*filename;
115     filename = strchr(myname, '=');
116     if(filename) {
117         *filename = 0;
118         filename++;
119     } else {
120         // argument has no explicit name field. guess one from the file name
121         char*path = strrchr(myname, '/');
122         char*ext = strrchr(myname, '.');
123         if(!path) path = myname;
124         else path ++;
125         if(ext) *ext = 0;
126         myname = path;
127         filename = name;
128     }
129
130     if(!master_filename) {
131
132         master_filename = filename;
133         master_name = myname;
134     } else {             
135         logf("<verbose> slave entity %s (named \"%s\")\n", filename, myname);
136
137         slave_filename[numslaves] = filename;
138         slave_name[numslaves] = myname;
139         slave_movex[numslaves] = config.movex;
140         slave_movey[numslaves] = config.movey;
141         slave_scalex[numslaves] = config.scalex;
142         slave_scaley[numslaves] = config.scaley;
143         config.movex = config.movey = 0;
144         config.scalex = config.scaley = 1.0;
145         numslaves ++;
146     }
147     return 0;
148 }
149
150 void args_callback_usage(char*name)
151 {
152     printf("Usage: %s [-l][-t] [-o outputfile] [[name=]masterfile] [-x xpos] [-y ypos] [-s scale] [name1=]slavefile1 .. [-x xpos] [-y ypos] [-s scale] [nameN=]slavefileN\n", name);
153     printf("\n");
154     printf("-o outputfile       explicitly specify output file. (otherwise, output.swf will be used)\n");
155     printf("-t                  (stack) place each slave into a seperate frame (no master movie)\n");
156     printf("-l                  (overlay) Don't remove any master objects, only overlay new objects\n");
157     printf("-c                  (clip) Clip the slave objects by the corresponding master objects\n");
158     printf("-v                  (verbose) Use more than one -v for greater effect \n");
159     printf("-x xpos             (move x) Adjust position of slave by xpos twips (1/20 pixel)\n");
160     printf("-y ypos             (move y) Adjust position of slave by ypos twips (1/20 pixel)\n");
161     printf("-s scale            (scale) Adjust size of slave by scale%\n");
162 }
163
164 /* read a whole file in memory */
165 char* fi_slurp(FILE*fi, unsigned int * setlength)
166 {
167     char * mem;
168     long long int length; //;)  
169     long long int pos = 0;
170     fseek(fi,0,SEEK_END);
171     length = ftell(fi);
172     fseek(fi,0,SEEK_SET);
173     if(!length)
174         return 0;
175     mem = malloc(length);
176     if(!mem)
177         return 0;
178     while(!feof(fi))
179     {
180         pos += fread(&mem[pos], 1, 65536, fi);
181     }
182     if (setlength) 
183         *setlength = length;
184     return mem;
185 }
186
187 void fi_dump(FILE*fi, void*_mem, int length)
188 {
189     char*mem = (char*)_mem;
190     int pos = 0;
191     while(pos < length)
192     {
193         int size = 65536;
194         if (size > (length - pos))
195                 size = (length - pos);
196         pos += fwrite(&mem[pos], 1, size, fi);
197     }
198 }
199
200 void makestackmaster(u8**masterdata, int*masterlength)
201 {
202     u8 head[] = {'F','W','S'};
203     u8 *pos;
204     u32 * fixpos;
205     int t;
206     struct RECT box;
207     int strlength = 0;
208     int fileversion = 1;
209
210     /* scan all slaves for bounding box */
211     for(t=0;t<numslaves;t++)
212     {
213         FILE*fi=fopen(slave_filename[t],"rb");
214         u8 data[256];
215         int ret;
216         struct flash_header head;
217         strlength += strlen(slave_name[t]) + 9;
218         if(!fi) {
219             logf("<fatal> Couldn't open %s.", slave_filename[t]);
220             exit(1);
221         }
222         ret = fread(data,1,256,fi);
223         if(ret < 13) {
224             logf("<fatal> File %s is to small (%d bytes)", slave_filename[t], ret);
225             exit(1);
226         }
227         swf_init(data,256);
228         head = swf_read_header();
229         logf("<verbose> File %s has bounding box %d:%d:%d:%d\n",
230                 slave_filename[t], 
231                 head.boundingBox.x1, head.boundingBox.y1,
232                 head.boundingBox.x2, head.boundingBox.y2);
233         if(head.version > fileversion)
234             fileversion = head.version;
235         if(!t)
236             box = head.boundingBox;
237         else {
238             if(head.boundingBox.x1 < box.x1)
239                 box.x1 = head.boundingBox.x1;
240             if(head.boundingBox.y1 < box.y1)
241                 box.y1 = head.boundingBox.y1;
242             if(head.boundingBox.x2 > box.x2)
243                 box.x2 = head.boundingBox.x2;
244             if(head.boundingBox.y2 > box.y2)
245                 box.y2 = head.boundingBox.y2;
246         }
247         logf("<verbose> New master bounding box is %d:%d:%d:%d\n",
248                 box.x1, box.y1,
249                 box.x2, box.y2);
250         fclose(fi);
251     }
252
253     /* we don't have a master, so we create one ourselves. */
254     /* (please notice the philosophical content) */
255     *masterlength = (numslaves + 1) * 32 + strlength;
256     *masterdata = (u8*)malloc(*masterlength);
257     pos = *masterdata;
258     memcpy(pos, head, sizeof(head));
259     pos += sizeof(head);
260     *pos++ = fileversion;
261     fixpos = (u32*)pos;
262     *(u32*)pos = 0x12345678; // to be overwritten
263     pos += 4;
264     writeRECT(&pos, &box);
265     *(u16*)pos = 0x2000; // framerate
266     pos += 2;
267     *(u16*)pos = numslaves;
268     pos += 2;
269     for(t=0;t<numslaves;t++)
270     {
271         char buf[128];
272         int namelen;
273
274         if(1) {
275             sprintf(buf, "Frame%02d", t);
276             slave_name[t] = strdup(buf);
277         } 
278         namelen = strlen(slave_name[t]);
279
280         *(u16*)&pos[0] = (u16)(TAGID_DEFINESPRITE<<6) + 6;
281         *(u16*)&pos[2] = t+1; //ID
282         *(u16*)&pos[4] = 0; // Frames
283         *(u16*)&pos[6] = 0; // TAG1
284         *(u16*)&pos[8] = (u16)(TAGID_PLACEOBJECT2<<6) + 6 + namelen;
285         *(u16*)&pos[10]= 34; //flags: id+name
286         *(u16*)&pos[11]= 1; // depth
287         *(u16*)&pos[13]= t+1; // id
288         sprintf(&pos[15],slave_name[t]);
289         pos += 15 + namelen + 1;
290         *(u16*)&pos[0]= (u16)(TAGID_SHOWFRAME<<6) + 0;
291         pos += 2;
292         if(t!=numslaves-1)
293         {
294             *(u16*)&pos[0]= (u16)(TAGID_REMOVEOBJECT2<<6) + 2;
295             *(u16*)&pos[2]= 1; // depth;
296             pos += 4;
297         }
298     }
299     *(u16*)pos = TAGID_END<<6 + 0;
300     *masterlength = pos - *masterdata;
301     *fixpos = *masterlength;
302 }
303
304 struct config_t config;
305 int main(int argn, char *argv[])
306 {
307     FILE*fi;
308     u8*masterdata;
309     unsigned int masterlength;
310     u8*slavedata;
311     unsigned int slavelength;
312     u8*newdata;
313     unsigned int newlength;
314     int t;
315
316     config.overlay = 0; 
317     config.antistream = 0; 
318     config.alloctest = 0;
319     config.clip = 0;
320     config.loglevel = 2; 
321     config.movex = 0;
322     config.movey = 0;
323     config.scalex = 1.0;
324     config.scaley = 1.0;
325     config.stack = 0;
326
327     processargs(argn, argv);
328     initLog(0,-1,0,0,-1,config.loglevel);
329
330     if(config.stack) {
331
332         if(config.overlay) {
333             logf("<error> Can't combine -l and -t");
334             exit(1);
335         }
336         if(config.clip) {
337             logf("<error> Can't combine -c and -t");
338             exit(1);
339         }
340         logf("<verbose> (stacking) %d files found\n", numslaves);
341
342         makestackmaster(&masterdata,&masterlength);
343
344         logf("<verbose> Generated %d bytes of master data", masterlength);
345     }
346     else {
347         logf("<verbose> master entity %s (named \"%s\")\n", master_filename, master_name);
348         fi = fopen(master_filename, "rb");
349         if(!fi) {
350             fprintf(stderr, "Failed to open %s\n", master_filename);
351             return 1;
352         }
353         masterdata = fi_slurp(fi, &masterlength);
354         if(!masterdata) {
355             fprintf(stderr, "Failed to read from %s\n", master_filename);
356             return 1;
357         }
358         logf("<debug> Read %d bytes from masterfile\n", masterlength);
359         fclose(fi);
360     }
361     
362     for(t=0;t<numslaves;t++)
363         logf("<verbose> slave entity(%d) %s (named \"%s\")\n", t+1, slave_filename[t], slave_name[t]);
364
365     if (config.alloctest)
366     {
367         int*bitmap = malloc(sizeof(int)*65536);
368         memset(bitmap, -1, 65536*sizeof(int));
369         memset(bitmap, 1, 101*sizeof(int));
370         swf_relocate(masterdata, masterlength, bitmap);
371         newdata = masterdata;
372         newlength = masterlength;
373         free(bitmap);
374     }
375     else
376     {
377         if (!numslaves)
378         {
379             logf("<error> You must have at least one slave entity.");
380             return 0;
381         }
382         for(t = 0; t < numslaves; t++)
383         {
384             config.movex = slave_movex[t];
385             config.movey = slave_movey[t];
386             config.scalex = slave_scalex[t];
387             config.scaley = slave_scaley[t];
388
389             logf("<notice> Combine [%s]%s and [%s]%s", master_name, master_filename,
390                     slave_name[t], slave_filename[t]);
391             fi = fopen(slave_filename[t], "rb");
392             if(!fi) {
393                 fprintf(stderr, "Failed to open %s\n", slave_filename[t]);
394                 return 1;
395             }
396             slavedata = fi_slurp(fi, &slavelength);
397             if(!slavedata) {
398                 fprintf(stderr, "Failed to read from %s\n", slave_filename[t]);
399                 return 1;
400             }
401             logf("<debug> Read %d bytes from slavefile\n", slavelength);
402             fclose(fi);
403
404             newdata = combine(masterdata, masterlength, slave_name[t], slavedata, slavelength, &newlength);
405             if(!newdata) { 
406                 logf("<fatal> Aborting.");
407                 return 1;
408             }
409
410             free(masterdata);
411             masterdata = newdata;
412             masterlength = newlength;
413         }
414     }
415
416     logf("<debug> New File is %d bytes \n", newlength);
417     if(newdata && newlength) {
418         FILE*fi = fopen(outputname, "wb");
419         fi_dump(fi, newdata, newlength);
420         fclose(fi);
421     }
422     return 0;
423 }
424