2 Shows the structure of a swf file
\r
4 Part of the swftools package.
\r
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
\r
8 This file is distributed under the GPL, see file COPYING for details */
\r
12 #ifdef HAVE_SYS_STAT_H
\r
13 #include <sys/stat.h>
\r
18 #ifdef HAVE_SYS_TYPES_H
\r
19 #include <sys/types.h>
\r
27 #include "../lib/rfxswf.h"
\r
28 #include "../lib/args.h"
\r
30 char * filename = 0;
\r
32 /* idtab stores the ids which are defined in the file. This allows us
\r
33 to detect errors in the file. (i.e. ids which are defined more than
\r
38 struct options_t options[] =
\r
47 int args_callback_option(char*name,char*val)
\r
49 if(!strcmp(name, "V")) {
\r
50 printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
\r
53 else if(name[0]=='a') {
\r
58 int args_callback_longoption(char*name,char*val)
\r
60 return args_long2shortoption(options, name, val);
\r
62 void args_callback_usage(char*name)
\r
64 printf("Usage: %s [-a] file.swf\n", name);
\r
65 printf("-h , --help\t\t\t Print help and exit\n");
\r
66 printf("-a , --action\t\t\t Disassemble action tags\n");
\r
67 printf("-V , --version\t\t\t Print program version and exit\n");
\r
69 int args_callback_command(char*name,char*val)
\r
72 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
\r
92 c: constant pool (string)
\r
93 s: skip (byte) (number of actions)
\r
94 m: method (byte) url:(0=none, 1=get, 2=post)/gf2:(1=play)
\r
95 b: branch (word) (number of bytes)
\r
96 p: type(byte), type=0:string, type=1:double
\r
97 {: define function (name (string), num (word), params (num strings), codesize (word)
\r
101 {3,"GotoFrame", 0x81, "f"},
\r
102 {4,"GotoFrame2", 0x9f, "m"}, // -1 (/Movieclip:3)
\r
103 {3,"GetUrl", 0x83, "ul"},
\r
104 {4,"GetUrl2", 0x9a, "m"}, //-2
\r
105 {3,"NextFrame", 0x04, ""},
\r
106 {3,"PreviousFrame", 0x05, ""},
\r
107 {3,"Play", 0x06, ""},
\r
108 {3,"Stop", 0x07, ""},
\r
109 {3,"ToggleQuality", 0x08, ""},
\r
110 {3,"StopSounds", 0x09, ""},
\r
111 {3,"WaitForFrame", 0x8a, "fs"},
\r
112 {4,"WaitForFrame2", 0x8d, "s"}, // -1
\r
113 {3,"SetTarget", 0x8b, "t"},
\r
114 {4,"SetTarget2", 0x20, ""}, //-1
\r
115 {3,"GotoLabel", 0x8c, "l"},
\r
116 {4,"Add", 0x0a, ""}, // -2, +1
\r
117 {4,"Multiply", 0x0c, ""}, // -2, +1
\r
118 {4,"Divide", 0x0d, ""}, // -2, +1
\r
119 {4,"Subtract", 0x0b, ""}, // -2, +1
\r
120 {4,"Less", 0x0f, ""}, // -2, +1
\r
121 {4,"Equals", 0x0e, ""}, // -2, +1
\r
122 {4,"And", 0x10, ""}, // -2, +1
\r
123 {4,"Or", 0x11, ""}, // -2, +1
\r
124 {4,"Not", 0x12, ""}, // -1, +1
\r
125 {4,"StringAdd", 0x21, ""}, // -2,+1
\r
126 {4,"StringLength", 0x14, ""}, // -1, +1
\r
127 {4,"MBStringLength", 0x31}, // -1, +1
\r
128 {4,"StringEquals", 0x13, ""}, // -2, +1
\r
129 {4,"StringLess", 0x29, ""}, //-2, +1
\r
130 {4,"StringExtract", 0x15, ""}, // -3, +1
\r
131 {4,"MBStringExtract", 0x35, ""}, //-3 +1
\r
132 {4,"Push", 0x96, "p"}, // +1
\r
133 {4,"Pop", 0x17, ""}, // -1
\r
134 {4,"ToInteger", 0x18, ""}, // -1, +1
\r
135 {4,"CharToAscii", 0x32, ""}, // -1, +1
\r
136 {4,"AsciiToChar", 0x33, ""}, // -1, +1
\r
137 {4,"MBCharToAscii", 0x36, ""}, // -1, +1
\r
138 {4,"MBAsciiToChar", 0x37, ""}, // -1, +1
\r
139 {4,"Jump", 0x99, "b"},
\r
140 {4,"If", 0x9a, "b"}, // -1
\r
141 {4,"Call", 0x9e, ""}, //-1 (frame label/number)
\r
142 {4,"GetVariable", 0x1c,""}, // -1, +1
\r
143 {4,"SetVariable", 0x1d,""}, // -2
\r
144 {4,"GetProperty", 0x22,""}, //-2, +1
\r
145 {4,"SetProperty", 0x23, ""}, // -3
\r
146 {4,"RemoveSprite", 0x25, ""}, //-1
\r
147 {4,"StartDrag", 0x27, ""}, // -2, -1, (-4)
\r
148 {4,"EndDrag", 0x28, ""},
\r
149 {4,"CloneSprite", 0x24}, // -3
\r
150 {4,"Trace", 0x26, ""}, //-1
\r
151 {4,"GetTime", 0x34, ""}, //+1
\r
152 {4,"RandomNumber", 0x30, ""}, //-1,+1
\r
154 {5,"Modulo", 0x3f,""},
\r
155 {5,"BitAnd", 0x60,""},
\r
156 {5,"BitLShift", 0x63,""},
\r
157 {5,"BitOr", 0x61,""},
\r
158 {5,"BitRShift", 0x64,""},
\r
159 {5,"BitURShift", 0x65,""},
\r
160 {5,"BitXor", 0x62,""},//66?
\r
161 {5,"Decrement", 0x51,""},
\r
162 {5,"Increment", 0x50,""},
\r
163 {5,"PushDuplicate", 0x4c,""},
\r
164 {5,"StackSwap", 0x4d,""},
\r
165 {5,"StoreRegister", 0x87,"r"},
\r
166 {5,"CallFunction", 0x3d,""},
\r
167 {5,"DefineFunction", 0x9b, "{"},
\r
168 {5,"Return", 0x3e,""},
\r
169 {5,"GetMember", 0x4e,""},
\r
170 {5,"SetMember", 0x4f,""},
\r
171 {5,"CallMethod", 0x52,""},
\r
172 {5,"Constantpool", 0x88, "c"},
\r
173 {5,"DefineLocal", 0x3c,""},
\r
174 {5,"DefineLocal2", 0x41,""},
\r
175 {5,"Delete", 0x3a,""},
\r
176 {5,"Delete2", 0x3b,""},
\r
177 {5,"Enumerate", 0x46,""},
\r
178 {5,"Equals2", 0x49,""},
\r
179 {5,"InitArray", 0x42,""}, // InitObject?
\r
180 {5,"NewMethod", 0x53,""},
\r
181 {5,"NewObject", 0x40,""},
\r
182 {5,"TargetPath", 0x45,""},
\r
183 {5,"With", 0x94, "o"},
\r
184 {5,"ToNumber", 0x4a,""},
\r
185 {5,"ToString", 0x4b,""},
\r
186 {5,"TypeOf", 0x44,""},
\r
187 {5,"Add2", 0x47,""},
\r
188 {5,"Less2", 0x48,""},
\r
190 {5,"???", 0x9d, ""}
\r
192 int definedactions = sizeof(actions)/sizeof(struct Action);
\r
194 struct _ActionTAG {
\r
199 struct _ActionTAG * next;
\r
200 struct _ActionTAG * prev;
\r
203 typedef struct _ActionTAG ActionTAG;
\r
205 ActionTAG* showdoaction(TAG*tag, char*prefix)
\r
211 ActionTAG*atag = &tmp;
\r
217 atag->next = (ActionTAG*)malloc(sizeof(ActionTAG));
\r
218 atag->next->prev = atag;
\r
219 atag->next->next = 0;
\r
225 length = GetU16(tag);
\r
228 data = malloc(length);
\r
229 for(t=0;t<length;t++)
\r
230 data[t] = GetU8(tag);
\r
235 atag->len = length;
\r
241 for(t=0;t<definedactions;t++)
\r
242 if(actions[t].op == op)
\r
245 if(t==definedactions) {
\r
246 printf("%s (%5d bytes) action: %02x\n", prefix, length, op);
\r
249 printf("%s (%5d bytes) action: %s", prefix, length, actions[t].name);
\r
250 cp = actions[t].flags;
\r
252 if(length) //TODO: check for consistency: should we have a length?
\r
258 printf(" %d", *(U16*)&data[pos]);pos+=2; //FIXME: le/be
\r
261 printf(" URL:\"%s\"", &data[pos]);pos+=strlen(&data[pos])+1;
\r
264 printf(" Target:\"%s\"", &data[pos]);pos+=strlen(&data[pos])+1;
\r
267 printf(" Label:\"%s\"", &data[pos]);pos+=strlen(&data[pos])+1;
\r
270 printf(" Constant Pool:\"%s\"", &data[pos]);pos+=strlen(&data[pos])+1;
\r
273 printf(" +%d", data[pos]);pos+=1;
\r
276 //m: method (byte) url:(0=none, 1=get, 2=post)/gf2:(1=play)
\r
277 printf(" %d", data[pos]);pos+=1;
\r
280 printf(" %d", *(U16*)&data[pos]);pos+=2;
\r
283 U8 type = data[pos++];
\r
285 printf(" String:\"%s\"", &data[pos]);pos+=strlen(&data[pos])+1;
\r
286 } else if (type == 1) {
\r
287 printf(" Double:\"%f\"", *(float*)&data[pos]);pos+=4;
\r
288 } else if (type == 2) {
\r
290 } else if (type == 4) {
\r
291 printf(" register:%d", data[pos++]);
\r
292 } else if (type == 5) {
\r
293 printf(" %s", data[pos++]?"true":"false");
\r
294 } else if (type == 6) {
\r
295 printf(" %f", *(double*)&data[pos]); pos+=8;
\r
296 } else if (type == 7) {
\r
297 printf(" %d", *(int*)&data[pos]); pos+=4;
\r
298 } else if (type == 8) {
\r
299 printf(" Lookup:%d", data[pos++]);
\r
309 printf("%s (%5d bytes) action: End\n", prefix, 0);
\r
313 int main (int argc,char ** argv)
\r
318 struct stat statbuf;
\r
323 memset(idtab,0,65536);
\r
325 processargs(argc, argv);
\r
327 f = open(filename,O_RDONLY);
\r
331 perror("Couldn't open file: ");
\r
334 if FAILED(ReadSWF(f,&swf))
\r
336 fprintf(stderr,"%s is not a valid SWF file or contains errors.\n",filename);
\r
342 fstat(f, &statbuf);
\r
343 if(statbuf.st_size != swf.FileSize)
\r
344 fprintf(stderr, "Error: Real Filesize (%d) doesn't match header Filesize (%d)",
\r
345 statbuf.st_size, swf.FileSize);
\r
350 printf("[HEADER] File version: %d\n", swf.FileVersion);
\r
351 printf("[HEADER] File size: %d\n", swf.FileSize);
\r
352 printf("[HEADER] Frame rate: %f\n",swf.FrameRate/256.0);
\r
353 printf("[HEADER] Frame count: %d\n",swf.FrameCount);
\r
354 printf("[HEADER] Movie width: %.3f\n",(swf.MovieSize.xmax-swf.MovieSize.xmin)/20.0);
\r
355 printf("[HEADER] Movie height: %.3f\n",(swf.MovieSize.ymax-swf.MovieSize.ymin)/20.0);
\r
357 tag = swf.FirstTag;
\r
360 char*name = getTagName(tag);
\r
362 fprintf(stderr, "Error: Unknown tag:0x%03x\n", tag->id);
\r
366 printf("[%03x] %9d %s%s", tag->id, tag->len, prefix, getTagName(tag));
\r
368 if(isDefiningTag(tag)) {
\r
369 U16 id = GetDefineID(tag);
\r
370 printf(" defines id %04x", id);
\r
372 fprintf(stderr, "Error: Id %04x is defined more than once.\n", id);
\r
375 else if(tag->id == ST_PLACEOBJECT ||
\r
376 tag->id == ST_PLACEOBJECT2) {
\r
377 printf(" places id %04x at depth %04x", GetPlaceID(tag), GetDepth(tag));
\r
379 printf(" name \"%s\"",GetName(tag));
\r
381 else if(tag->id == ST_REMOVEOBJECT) {
\r
382 printf(" removes id %04x from depth %04x", GetPlaceID(tag), GetDepth(tag));
\r
384 else if(tag->id == ST_REMOVEOBJECT2) {
\r
385 printf(" removes object from depth %04x", GetDepth(tag));
\r
390 if(tag->id == ST_DEFINESPRITE) {
\r
391 sprintf(prefix, " ");
\r
393 else if(tag->id == ST_END) {
\r
394 sprintf(prefix, "");
\r
396 else if(tag->id == ST_DOACTION && action) {
\r
397 char myprefix[128];
\r
398 sprintf(myprefix, " %s", prefix);
\r
399 showdoaction(tag, myprefix);
\r