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", 0x9d, "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,"Makehash", 0x43, ""}, //??
\r
176 {5,"Delete", 0x3a,""}, //?
\r
177 {5,"Delete2", 0x3b,""},
\r
178 {5,"Enumerate", 0x46,""},
\r
179 {5,"Equals2", 0x49,""},
\r
180 {5,"InitArray", 0x42,""}, // InitObject?
\r
181 {5,"NewMethod", 0x53,""}, //?
\r
182 {5,"NewObject", 0x40,""},
\r
183 {5,"TargetPath", 0x45,""}, //?
\r
184 {5,"With", 0x94, "o"},
\r
185 {5,"ToNumber", 0x4a,""}, //?
\r
186 {5,"ToString", 0x4b,""}, //?
\r
187 {5,"TypeOf", 0x44,""},
\r
188 {5,"Add2", 0x47,""},
\r
189 {5,"Less2", 0x48,""}
\r
192 int definedactions = sizeof(actions)/sizeof(struct Action);
\r
195 struct _ActionTAG {
\r
200 struct _ActionTAG * next;
\r
201 struct _ActionTAG * prev;
\r
204 typedef struct _ActionTAG ActionTAG;
\r
206 ActionTAG* showdoaction(TAG*tag, char*prefix)
\r
212 ActionTAG*atag = &tmp;
\r
218 atag->next = (ActionTAG*)malloc(sizeof(ActionTAG));
\r
219 atag->next->prev = atag;
\r
220 atag->next->next = 0;
\r
226 length = GetU16(tag);
\r
229 data = malloc(length);
\r
230 for(t=0;t<length;t++)
\r
231 data[t] = GetU8(tag);
\r
236 atag->len = length;
\r
242 for(t=0;t<definedactions;t++)
\r
243 if(actions[t].op == op)
\r
246 if(t==definedactions) {
\r
247 printf("%s (%5d bytes) action: %02x\n", prefix, length, op);
\r
250 printf("%s (%5d bytes) action: %s", prefix, length, actions[t].name);
\r
251 cp = actions[t].flags;
\r
253 if(length) //TODO: check for consistency: should we have a length?
\r
259 printf(" %d", *(U16*)&data[pos]);pos+=2; //FIXME: le/be
\r
262 printf(" URL:\"%s\"", &data[pos]);pos+=strlen(&data[pos])+1;
\r
265 printf(" Target:\"%s\"", &data[pos]);pos+=strlen(&data[pos])+1;
\r
268 printf(" Label:\"%s\"", &data[pos]);pos+=strlen(&data[pos])+1;
\r
271 printf(" Constant Pool:\"%s\"", &data[pos]);pos+=strlen(&data[pos])+1;
\r
274 printf(" +%d", data[pos]);pos+=1;
\r
277 //m: method (byte) url:(0=none, 1=get, 2=post)/gf2:(1=play)
\r
278 printf(" %d", data[pos]);pos+=1;
\r
281 printf(" %d", *(U16*)&data[pos]);pos+=2;
\r
284 U8 type = data[pos++];
\r
286 printf(" String:\"%s\"", &data[pos]);pos+=strlen(&data[pos])+1;
\r
287 } else if (type == 1) {
\r
288 printf(" Double:\"%f\"", *(float*)&data[pos]);pos+=4;
\r
289 } else if (type == 2) {
\r
291 } else if (type == 4) {
\r
292 printf(" register:%d", data[pos++]);
\r
293 } else if (type == 5) {
\r
294 printf(" %s", data[pos++]?"true":"false");
\r
295 } else if (type == 6) {
\r
296 printf(" %f", *(double*)&data[pos]); pos+=8;
\r
297 } else if (type == 7) {
\r
298 printf(" %d", *(int*)&data[pos]); pos+=4;
\r
299 } else if (type == 8) {
\r
300 printf(" Lookup:%d", data[pos++]);
\r
310 printf("%s (%5d bytes) action: End\n", prefix, 0);
\r
314 int main (int argc,char ** argv)
\r
319 struct stat statbuf;
\r
324 memset(idtab,0,65536);
\r
326 processargs(argc, argv);
\r
328 f = open(filename,O_RDONLY);
\r
332 perror("Couldn't open file: ");
\r
335 if FAILED(ReadSWF(f,&swf))
\r
337 fprintf(stderr,"%s is not a valid SWF file or contains errors.\n",filename);
\r
343 fstat(f, &statbuf);
\r
344 if(statbuf.st_size != swf.FileSize)
\r
345 fprintf(stderr, "Error: Real Filesize (%d) doesn't match header Filesize (%d)",
\r
346 statbuf.st_size, swf.FileSize);
\r
351 printf("[HEADER] File version: %d\n", swf.FileVersion);
\r
352 printf("[HEADER] File size: %d\n", swf.FileSize);
\r
353 printf("[HEADER] Frame rate: %f\n",swf.FrameRate/256.0);
\r
354 printf("[HEADER] Frame count: %d\n",swf.FrameCount);
\r
355 printf("[HEADER] Movie width: %.3f\n",(swf.MovieSize.xmax-swf.MovieSize.xmin)/20.0);
\r
356 printf("[HEADER] Movie height: %.3f\n",(swf.MovieSize.ymax-swf.MovieSize.ymin)/20.0);
\r
358 tag = swf.FirstTag;
\r
361 char*name = getTagName(tag);
\r
363 fprintf(stderr, "Error: Unknown tag:0x%03x\n", tag->id);
\r
367 printf("[%03x] %9d %s%s", tag->id, tag->len, prefix, getTagName(tag));
\r
369 if(isDefiningTag(tag)) {
\r
370 U16 id = GetDefineID(tag);
\r
371 printf(" defines id %04x", id);
\r
373 fprintf(stderr, "Error: Id %04x is defined more than once.\n", id);
\r
376 else if(tag->id == ST_PLACEOBJECT ||
\r
377 tag->id == ST_PLACEOBJECT2) {
\r
378 printf(" places id %04x at depth %04x", GetPlaceID(tag), GetDepth(tag));
\r
380 printf(" name \"%s\"",GetName(tag));
\r
382 else if(tag->id == ST_REMOVEOBJECT) {
\r
383 printf(" removes id %04x from depth %04x", GetPlaceID(tag), GetDepth(tag));
\r
385 else if(tag->id == ST_REMOVEOBJECT2) {
\r
386 printf(" removes object from depth %04x", GetDepth(tag));
\r
391 if(tag->id == ST_DEFINESPRITE) {
\r
392 sprintf(prefix, " ");
\r
394 else if(tag->id == ST_END) {
\r
395 sprintf(prefix, "");
\r
397 else if(tag->id == ST_DOACTION && action) {
\r
398 char myprefix[128];
\r
399 sprintf(myprefix, " %s", prefix);
\r
400 showdoaction(tag, myprefix);
\r