minor fixes in swfrender
[swftools.git] / src / swfbytes.c
blobb747365d5f33c3c611c393754ad01a0f4e758b98
1 /* swfbytes.c
2 A tool for modifying swfs on the tag level
4 Part of the swftools package.
6 Copyright (c) 2008/2009 Matthias Kramm <kramm@quiss.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
22 #include "../config.h"
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <fcntl.h>
26 #include <stdarg.h>
27 #include "../lib/rfxswf.h"
28 #include "../lib/args.h"
30 static char * filename = 0;
31 static int verbose;
32 static char* output_filename = "output.swf";
34 static struct options_t options[] = {
35 {"h", "help"},
36 {"v", "verbose"},
37 {"V", "version"},
38 {0,0}
41 int args_callback_option(char*name,char*val)
43 if(!strcmp(name, "V")) {
44 printf("swfedit - part of %s %s\n", PACKAGE, VERSION);
45 return 0;
46 } else if(!strcmp(name, "v")) {
47 verbose++;
48 return 0;
49 } else if(!strcmp(name, "o")) {
50 output_filename = val;
51 return 1;
52 } else {
53 printf("Unknown option: -%s\n", name);
54 return 0;
56 return 0;
58 int args_callback_longoption(char*name,char*val)
60 return args_long2shortoption(options, name, val);
62 void args_callback_usage(char *name)
64 printf("\n");
65 printf("Usage: %s [-v] file.swf > file.hexdump\n", name);
66 printf("OR: %s file.hexdump\n", name);
67 printf("\n");
68 printf("-h , --help Print help and exit\n");
69 printf("-v , --verbose Be more verbose\n");
70 printf("-V , --version Print program version and exit\n");
71 printf("\n");
73 int args_callback_command(char*name,char*val)
75 if(filename) {
76 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n", filename, name);
78 filename = name;
79 return 0;
82 void dumpTag(FILE*fo, char*prefix, TAG*tag)
84 int t;
85 for(t=0;t<tag->len;t++) {
86 if(!(t&15))
87 fprintf(fo, "%s| ", prefix);
88 fprintf(fo, "%02x ", tag->data[t]);
89 if((t && ((t&15)==15)) || (t==tag->len-1)) {
90 fprintf(fo, "\n");
95 void dumpFile(SWF*swf, FILE*fo)
97 TAG* tag = swf->firstTag;
98 int indent = 0;
99 int t;
100 char whitespace[33];
101 char*prefix = "";
103 memset(whitespace, 32, 32); whitespace[32] = 0;
105 fprintf(fo, "Version: %d\n", swf->fileVersion);
106 fprintf(fo, "FrameRate: %f\n",swf->frameRate/256.0);
107 fprintf(fo, "FrameCount: %d\n",swf->frameCount);
108 fprintf(fo, "Width: %.2f\n",(swf->movieSize.xmax-swf->movieSize.xmin)/20.0);
109 fprintf(fo, "X-Offset: %.2f\n", swf->movieSize.xmin/20.0);
110 fprintf(fo, "Height: %.2f\n",(swf->movieSize.ymax-swf->movieSize.ymin)/20.0);
111 fprintf(fo, "Y-Offset: %.2f\n", swf->movieSize.ymin/20.0);
112 fprintf(fo, "\n");
114 while(tag)
116 if(swf_isDefiningTag(tag)) {
117 fprintf(fo, "%s%s <%d>\n", prefix, swf_TagGetName(tag), swf_GetDefineID(tag));
118 swf_SetTagPos(tag, 2);
119 dumpTag(fo, prefix, tag);
120 } else if(swf_isPseudoDefiningTag(tag)) {
121 fprintf(fo, "%s%s <%d>\n", prefix, swf_TagGetName(tag), swf_GetDefineID(tag));
122 swf_SetTagPos(tag, 2);
123 dumpTag(fo, prefix, tag);
124 } else if(tag->id == ST_PLACEOBJECT || tag->id == ST_PLACEOBJECT2) {
125 SWFPLACEOBJECT po;
126 swf_GetPlaceObject(tag, &po);
127 fprintf(fo, "%s%s <%d>\n", prefix,swf_TagGetName(tag), po.id);
128 /* for now */
129 swf_SetTagPos(tag, 0);
130 dumpTag(fo, prefix, tag);
131 swf_PlaceObjectFree(&po);
132 } else {
133 fprintf(fo, "%s%s\n", prefix, swf_TagGetName(tag));
134 dumpTag(fo, prefix, tag);
137 if(tag->id == ST_DEFINESPRITE) {
138 indent+=4;
139 if(indent>32)
140 indent = 32;
141 prefix = &whitespace[32-indent];
142 } else if(tag->id == ST_END) {
143 indent-=4;
144 if(indent<0)
145 indent = 0;
146 prefix = &whitespace[32-indent];
149 tag = tag->next;
153 static void readline(FILE*fi, char*line, int maxlen) {
154 int pos = 0;
155 while(!feof(fi)) {
156 if(!fread(&line[pos],1,1,fi))
157 break;
159 /* cut of preceding whitespace */
160 if(pos == 0 && (line[0] == 32 || line[0] == '\t'))
161 continue;
163 if(line[pos] == 13 || line[pos]==10)
164 break;
165 if(pos<maxlen-1)
166 pos++;
168 line[pos]=0;
170 /* cut off comments */
171 char*x=strchr(line,'#');
172 if(x) {
173 *x=0;
174 pos = x-line;
177 /* cut off trailing whitespace */
178 while(pos>=1 && (line[pos-1]==32 || line[pos-1]==9)) {
179 pos--;
180 line[pos]=0;
184 int getFloat(char*s)
186 float x;
187 int n;
188 while(*s==32 || *s=='\t') s++;
189 sscanf(s, "%f%n", &x, &n);
190 if(n==0)
191 fprintf(stderr, "Not a float: %s\n", s);
192 return x;
194 int getInt(char*s)
196 int i;
197 int n;
198 while(*s==32 || *s=='\t') s++;
199 sscanf(s, "%d%n", &i, &n);
200 if(n==0)
201 fprintf(stderr, "Not an integer: %s\n", s);
202 return i;
204 int getTwip(char*x)
206 return (int)(getFloat(x)*20);
210 static char**lookup;
211 int swf_TagNameToID(char*name)
213 int t;
214 TAG tag;
215 memset(&tag, 0, sizeof(tag));
216 if(!lookup) {
217 lookup = (char**)malloc(sizeof(char*)*65536);
218 for(t=0;t<65536;t++) {
219 tag.id = t;
220 lookup[t] = swf_TagGetName(&tag);
223 for(t=0;t<65536;t++) {
224 if(lookup[t] && !strcasecmp(name, lookup[t]))
225 return t;
227 fprintf(stderr, "Not a tag name: \"%s\"\n", name);
228 return -1;
231 void parseFile(FILE*fi, SWF*swf)
233 TAG*tag = 0;
234 char line[1024];
235 memset(swf, 0, sizeof(SWF));
236 while(1) {
237 char*colon = 0;
238 readline(fi, line, 1024);
239 if(!line[0])
240 break;
241 colon = strchr(line, ':');
242 if(colon) {
243 int num = colon - line;
244 int n;
245 if(num == 9 && !strncmp(line, "FrameRate", num)) {
246 swf->frameRate = getFloat(colon+1)*256;
247 } else if(num == 10 && !strncmp(line, "FrameCount", num)) {
248 swf->frameCount = getInt(colon+1);
249 } else if(num == 7 && !strncmp(line, "Version", num)) {
250 swf->fileVersion = getInt(colon+1);
251 } else if(num == 5 && !strncmp(line, "Width", num)) {
252 int width = getTwip(colon+1);
253 swf->movieSize.xmax += width;
254 } else if(num == 6 && !strncmp(line, "Height", num)) {
255 int height = getTwip(colon+1);
256 swf->movieSize.ymax += height;
257 } else if(num == 8 && !strncmp(line, "X-Offset", num)) {
258 int xoffset = getTwip(colon+1);
259 swf->movieSize.xmin += xoffset;
260 swf->movieSize.xmax += xoffset;
261 } else if(num == 8 && !strncmp(line, "Y-Offset", num)) {
262 int yoffset = getTwip(colon+1);
263 swf->movieSize.ymin += yoffset;
264 swf->movieSize.ymax += yoffset;
265 } else {
266 fprintf(stderr, "Ignored line \"%s\"\n", line);
270 while(!feof(fi)) {
271 char*s, *tagname;
272 char*br;
273 readline(fi, line, 1024);
274 if(!line[0])
275 continue;
276 s = strchr(line, ' ');
277 br = strchr(line, '|');
278 if(!br) {
279 int id = 0;
280 /* DEFINESHAPE <id> ... type line */
281 if(!s) {
282 tagname = strdup(line);
283 } else {
284 tagname = strdup(line);
285 tagname[s-line] = 0;
287 id = swf_TagNameToID(tagname);
288 free(tagname);
289 if(id<0) {
290 fprintf(stderr, "Ignored line \"%s\"\n", line);
291 continue;
293 tag = swf_InsertTag(tag, id);
294 if(!swf->firstTag)
295 swf->firstTag = tag;
296 } else {
297 /* | 00 34 fe c7 ... type line */
298 char*p = line;
299 int num = 0;
300 int digits = 0;
302 if(!tag) {
303 fprintf(stderr, "Discarded unassignable data %s\n", line);
304 continue;
307 while(*p) {
308 int n = 0;
309 if((*p>='a' && *p<='f') ||
310 (*p>='A' && *p<='F')) {
311 n = 9 + (*p & 15);
312 num = (num<<4) | n;
313 digits++;
315 else if(*p>='0' && *p<='9') {
316 n = *p & 15;
317 num = (num<<4) | n;
318 digits++;
319 } else if(digits) {
320 swf_SetU8(tag, num);
321 num = 0;
322 digits = 0;
324 p++;
326 if(digits)
327 swf_SetU8(tag, num);
332 char swf_IsSWF(char*filename)
334 int fi = open(filename,O_RDONLY|O_BINARY);
335 U8 buf[3] = {0,0,0};
336 if(fi<0)
337 return 0;
338 read(fi, buf, 3);
339 close(fi);
340 if((buf[0] == 'F' || buf[0] == 'C') && buf[1] == 'W' && buf[2] == 'S')
341 return 1;
342 return 0;
345 int main (int argc,char ** argv)
347 int fi;
348 TAG*tag = 0;
349 SWF swf;
351 processargs(argc, argv);
353 if(!filename) {
354 fprintf(stderr, "You must supply a filename.\n");
355 return -1;
357 if(swf_IsSWF(filename)) {
358 fi = open(filename,O_RDONLY|O_BINARY);
359 if (fi<0) {
360 perror("Couldn't open file: ");
361 exit(1);
363 if FAILED(swf_ReadSWF(fi,&swf)) {
364 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
365 close(fi);
366 exit(1);
368 dumpFile(&swf, stdout);
369 swf_FreeTags(&swf);
370 } else {
371 SWF newswf;
372 FILE*fi = fopen(filename, "rb");
373 parseFile(fi, &newswf);
374 fclose(fi);
375 int f;
376 char*sname = output_filename;
377 f = open(sname,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
378 if FAILED(swf_WriteSWF(f,&newswf)) {
379 fprintf(stderr, "Unable to write output file: %s\n", sname);
381 close(f);
384 return 0;