added tool "swfextract".
[swftools.git] / src / swfextract.c
1 /* swfextract.c
2    Allows to extract parts of the swf into a new file.
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 <unistd.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include "../lib/rfxswf.h"
14 #include "../lib/args.h"
15 #include "reloc.h"
16
17 char * filename = 0;
18 char * destfilename = "output.swf";
19 int verbose = 2;
20 int extractid = -1;
21 char* extractname = 0;
22
23 struct options_t options[] =
24 {
25  {"o","output"},
26  {"v","verbose"},
27  {"i","id"},
28  {"n","name"},
29  {"V","version"},
30  {0,0}
31 };
32
33 int args_callback_option(char*name,char*val)
34 {
35     if(!strcmp(name, "V")) {
36         printf("swfextract - part of %s %s\n", PACKAGE, VERSION);
37         exit(0);
38     } 
39     if(!strcmp(name, "o")) {
40         destfilename = val;
41         return 1;
42     } 
43     if(!strcmp(name, "i")) {
44         extractid = atoi(val);
45         if(extractname) {
46             fprintf(stderr, "You can only supply either name or id\n");
47             exit(1);
48         }
49         return 1;
50     } 
51     if(!strcmp(name, "n")) {
52         extractname = val;
53         if(extractid>=0) {
54             fprintf(stderr, "You can only supply either name or id\n");
55             exit(1);
56         }
57         return 1;
58     } 
59     if(!strcmp(name, "v")) {
60         verbose ++;
61         return 0;
62     } 
63     else {
64         printf("Unknown option: -%s\n", name);
65         return 0;
66     }
67
68     return 0;
69 }
70 int args_callback_longoption(char*name,char*val)
71 {
72     return args_long2shortoption(options, name, val);
73 }
74 void args_callback_usage(char*name)
75 {    
76     printf("Usage: %s [-v] [-i id] file.swf\n", name);
77     printf("\t-v , --verbose\t\t\t Be more verbose\n");
78     printf("\t-i , --id ID\t\t\t ID of the object to extract\n");
79     printf("\t-n , --name name\t\t\t instance name of the object to extract\n");
80     printf("\t-V , --version\t\t\t Print program version and exit\n");
81 }
82 int args_callback_command(char*name,char*val)
83 {
84     if(filename) {
85         fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
86                  filename, name);
87     }
88     filename = name;
89     return 0;
90 }
91
92 U8 mainr,maing,mainb;
93 char used[65536];
94 TAG*tags[65536];
95 int changed;
96
97 void idcallback(void*data)
98 {
99     if(!used[*(U16*)data]) {
100         changed = 1;
101         used[*(U16*)data] = 1;
102     }
103 }
104
105 void enumerateIDs(TAG*tag, void(*callback)(void*))
106 {
107     U8*data;
108     int len = tag->len;
109     if(tag->len>=64) {
110         len += 6;
111         data = (U8*)malloc(len);
112         *(U16*)data = (tag->id<<6)+63;
113         *(U32*)&data[2] = tag->len;
114         memcpy(&data[6], tag->data, tag->len);
115     } else {
116         len += 2;
117         data = (U8*)malloc(len);
118         *(U16*)data = (tag->id<<6)+tag->len;
119         memcpy(&data[2], tag->data, tag->len);
120     }
121     map_ids_mem(data, len, callback);
122 }
123
124 void extractTag(SWF*swf, TAG*maintag, char*filename)
125 {
126     SWF newswf;
127     TAG*desttag;
128     TAG*srctag;
129     RGBA rgb;
130     char sprite;
131     int f;
132     int t;
133     int copy = 0;
134     int defineid = swf_GetDefineID(maintag);
135     memset(&newswf,0x00,sizeof(SWF));        // set global movie parameters
136     memset(used, 0,65536);
137
138     newswf.fileVersion    = swf->fileVersion;
139     newswf.frameRate      = swf->frameRate;
140     newswf.movieSize      = swf->movieSize;
141                 
142     newswf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
143     desttag = newswf.firstTag;
144     rgb.r = mainr;
145     rgb.g = maing;
146     rgb.b = mainb;
147     swf_SetRGB(desttag,&rgb);
148
149     used[defineid] = 1;
150     do {
151        changed = 0;
152        for(t=0;t<65536;t++) {
153            if(used[t]==1) {
154              if(tags[t]->id==ST_DEFINESPRITE) {
155                  TAG*tag = tags[t];
156                  while(tag->id != ST_END)
157                  {
158                      enumerateIDs(tag, idcallback);
159                      tag = tag->next;
160                  }
161              }
162              else
163                 enumerateIDs(tags[t], idcallback);
164              used[t] = 2;
165            }
166        }
167     }
168     while(changed);
169
170     srctag = swf->firstTag;
171     while(srctag && (srctag->id || sprite)) {
172         if(!sprite) {
173             copy = 0;
174         }
175         if(srctag->id == ST_END) {
176             sprite = 0;
177         }
178         if(srctag->id == ST_DEFINESPRITE)
179             sprite = 1;
180         if(swf_isDefiningTag(srctag)) {
181             int id = swf_GetDefineID(srctag);
182             if(used[id]) 
183                 copy = 1;
184         } else 
185         if(srctag->id == ST_PLACEOBJECT ||
186             srctag->id == ST_PLACEOBJECT2) {
187             if(swf_GetPlaceID(srctag) == defineid)
188                 copy = 1;
189         }
190         if(copy) {
191             TAG*ttag = (TAG*)malloc(sizeof(TAG));
192             desttag = swf_InsertTag(desttag, srctag->id);
193             desttag->len = desttag->memsize = srctag->len;
194             desttag->data = malloc(srctag->len);
195             memcpy(desttag->data, srctag->data, srctag->len);
196         }
197         
198         srctag = srctag->next;
199     }
200     desttag = swf_InsertTag(desttag,ST_SHOWFRAME);
201     
202     f = open(filename, O_TRUNC|O_WRONLY|O_CREAT, 0644);
203     if FAILED(swf_WriteSWF(f,&newswf)) fprintf(stderr,"WriteSWF() failed.\n");
204     close(f);
205
206     swf_FreeTags(&newswf);                       // cleanup
207 }
208
209 int main (int argc,char ** argv)
210
211     TAG*tag;
212     SWF swf;
213     int f;
214     processargs(argc, argv);
215
216     if(!filename)
217     {
218         fprintf(stderr, "You must supply a filename.\n");
219         return 1;
220     }
221     initLog(0,-1,0,0,-1, verbose);
222
223     f = open(filename,O_RDONLY);
224
225     if (f<0)
226     { 
227         perror("Couldn't open file: ");
228         exit(1);
229     }
230     if FAILED(swf_ReadSWF(f,&swf))
231     { 
232         fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
233         close(f);
234         exit(1);
235     }
236
237     tag = swf.firstTag;
238
239     while(tag) {
240         if(swf_isDefiningTag(tag)) {
241             int id = swf_GetDefineID(tag);
242             tags[id] = tag;
243         }
244         else if (tag->id == ST_SETBACKGROUNDCOLOR) {
245             mainr = tag->data[0];
246             maing = tag->data[1];
247             mainb = tag->data[2];
248         }
249         else if(tag->id == ST_PLACEOBJECT2) {
250             char*name = swf_GetName(tag);
251             if(name && !strcmp(name, extractname)) {
252                 int id = swf_GetPlaceID(tag); 
253                 if(extractid>=0 && id != extractid) {
254                     fprintf(stderr, "Error: More than one instance with name \"%s\"", name);
255                     exit(1);
256                 }
257                 extractid = swf_GetPlaceID(tag); 
258             }
259         }
260         tag = tag->next;
261     }
262     if(tags[extractid])
263         extractTag(&swf, tags[extractid], destfilename);
264
265     swf_FreeTags(&swf);
266     return 0;
267 }
268