#include "../rfxswf.h"
+#define MAX_LOOKUP 1024 // make cross references in dumps
+
struct Action
{
int version;
b: branch (word) (number of bytes)
p (push): type(byte), type=0:string, type=1:double
{: define function (name (string), num (word), params (num strings), codesize (word)
-o: object (string)
+o: codesize (word) object (string)
r: register (byte)
*/
{3,"End", 0x00, ""},
{5,"ToString", 0x4b,""}, //?
{5,"TypeOf", 0x44,""},
{5,"Add2", 0x47,""},
-{5,"Less2", 0x48,""}
+{5,"Less2", 0x48,""},
+{5/*6?*/,"Less3?", 0x67,""},
+{5/*6?*/,"GetMembers?", 0x55,""}
};
static int definedactions = sizeof(actions)/sizeof(struct Action);
-ActionTAG* swf_GetActions(TAG*tag)
+ActionTAG* swf_ActionGet(TAG*tag)
{
U8 op = 1;
int length;
length = swf_GetU16(tag);
if(length) {
- int t;
data = malloc(length);
- for(t=0;t<length;t++)
- data[t] = swf_GetU8(tag);
+ swf_GetBlock(tag, data, length);
} else {
data = 0;
}
return tmp.next;
}
-void swf_SetActions(TAG*tag, ActionTAG*action)
+void swf_ActionFree(ActionTAG*action)
+{
+ while(action)
+ {
+ ActionTAG*tmp;
+ if(action->data && action->data != action->tmp)
+ free(action->data);
+ tmp = action;
+ action=action->next;
+ free(tmp);
+ }
+}
+
+void swf_ActionSet(TAG*tag, ActionTAG*action)
{
while(action)
{
}
}
-int OpAdvance(char c, char*data)
+int OpAdvance(char c, U8*data)
{
switch (c)
{
return 1;
case 'b':
return 2;
+ case 'r':
+ return 1;
case 'p': {
U8 type = *data++;
if(type == 0) {
return 1+4; //int
} else if (type == 8) {
return 1+1; //lookup
- }
+ } else return 1;
break;
}
+ case 'o': {
+ return 2;
+ }
+ case '{': {
+ U16 num;
+ U16 codesize;
+ U8* odata = data;
+ int t;
+ while(*data++); //name
+ num = (*data++)*256; //num
+ num += (*data++);
+ for(t=0;t<num;t++)
+ while(*data++); //param
+ codesize = (*data++)*256; //num
+ codesize += (*data++);
+ return data-odata;
+ }
}
return 0;
}
-
-/* TODO: this should be in swfdump.c */
+#define ATAG_FULLLENGTH(atag) ((atag)->len + 1 + ((atag)->op&0x80?2:0))
+#define MAX_LEVELS 16
+/* TODO: * this should be in swfdump.c */
void swf_DumpActions(ActionTAG*atag, char*prefix)
{
int t;
U8*data;
char* cp;
- if(!prefix)
- prefix="";
+ int entry = 0;
+ char spaces[MAX_LEVELS*4+1];
+ struct {
+ char*text;
+ int count;
+ } counter[MAX_LEVELS];
+ int countpos = 0;
+#ifdef MAX_LOOKUP
+ char * lookup[MAX_LOOKUP];
+ memset(lookup,0x00,sizeof(lookup));
+#endif
+ memset(spaces, 32, sizeof(spaces));
+ spaces[sizeof(spaces)-1] = 0;
+
+ if (!prefix)
+ prefix="";
+
while(atag)
{
+ char*indent = &spaces[sizeof(spaces)-1-countpos*4];
U8 poollen = 0;
for(t=0;t<definedactions;t++)
if(actions[t].op == atag->op)
break;
if(t==definedactions) {
- printf("%s (%5d bytes) action: %02x\n", prefix, atag->len, atag->op);
- atag = atag->next;
- continue;
+ printf("%s (%5d bytes) action:%s unknown[%02x]", prefix, atag->len, indent, atag->op);
+ } else {
+ printf("%s (%5d bytes) action:%s %s", prefix, atag->len, indent, actions[t].name);
}
- printf("%s (%5d bytes) action: %s", prefix, atag->len, actions[t].name);
- cp = actions[t].flags;
data = atag->data;
- if(atag->len) //TODO: check for consistency: should we have a length?
- while(*cp)
+ if(atag->len && t!=definedactions) //TODO: check for consistency: should we have a length?
{
- switch(*cp)
- {
- case 'f': {
- printf(" %d", *(U16*)data); //FIXME: le/be
- } break;
- case 'u': {
- printf(" URL:\"%s\"", data);
- } break;
- case 't': {
- printf(" Target:\"%s\"", data);
- } break;
- case 'l': {
- printf(" Label:\"%s\"", data);
- } break;
- case 'c': {
- printf(" String:\"%s\"", data);
- } break;
- case 'C': {
- poollen = *data;
- printf("(%d entries)", poollen);
- } break;
- case 's': {
- printf(" +%d", *data);
- } break;
- case 'm': {
- //m: method (byte) url:(0=none, 1=get, 2=datat)/gf2:(1=play)
- printf(" %d", *data);
- } break;
- case 'b': {
- printf(" %d", *(U16*)data);
- } break;
- case 'p': {
- U8 type = *data;
- char*value = data+1;
- if(type == 0) {
- printf(" String:\"%s\"", value);
- } else if (type == 1) {
- printf(" Float:\"%f\"", *(float*)value);
- } else if (type == 2) {
- printf(" NULL");
- } else if (type == 4) {
- printf(" register:%d", *value);
- } else if (type == 5) {
- printf(" %s", *value?"true":"false");
- } else if (type == 6) {
- printf(" %f", *(double*)value);
- } else if (type == 7) {
- printf(" %d", *(int*)value);
- } else if (type == 8) {
- printf(" Lookup:%d", *value);
- }
- } break;
- }
- data += OpAdvance(*cp, data);
- if(*cp!='c' || !poollen)
- cp++;
- if(poollen)
- poollen--;
+ cp = actions[t].flags;
+ while(*cp)
+ {
+ switch(*cp)
+ {
+ case 'f': { //frame
+ printf(" %d", data[0]+256*data[1]);
+ } break;
+ case 'u': {
+ printf(" URL:\"%s\"", data);
+ } break;
+ case 't': {
+ printf(" Target:\"%s\"", data);
+ } break;
+ case 'l': {
+ printf(" Label:\"%s\"", data);
+ } break;
+ case 'c': {
+ printf(" String:\"%s\"", data);
+#ifdef MAX_LOOKUP
+ if (entry<MAX_LOOKUP)
+ lookup[entry++] = strdup(data);
+#endif
+ } break;
+ case 'C': {
+ poollen = *data;
+ entry = 0;
+ printf("(%d entries)", poollen);
+ } break;
+ case 's': {
+ printf(" +%d", *data);
+ } break;
+ case 'm': {
+ //m: method (byte) url:(0=none, 1=get, 2=datat)/gf2:(1=play)
+ printf(" %d", *data);
+ } break;
+ case '{': {
+ U16 num;
+ U16 codesize;
+ int s = 0;
+ int t;
+ printf(" %s(", data);
+ while(data[s++]); //name
+ num = (data[s++]); //num
+ num += (data[s++])*256;
+ for(t=0;t<num;t++) {
+ printf("%s",data);
+ if(t<num-1)
+ printf(", ");
+ while(data[s++]); //param
+ }
+ printf(")");
+ codesize = (data[s++]); //num
+ codesize += (data[s++])*256;
+ printf(" codesize:%d ",codesize);
+ printf("\n%s %s{", prefix, indent);
+ if(countpos>=15) {
+ printf("Error: nested too deep\n");
+ continue;
+ }
+ counter[countpos].text = "}";
+ counter[countpos].count = codesize + ATAG_FULLLENGTH(atag);
+ countpos++;
+ } break;
+ case 'o': {
+ int t;
+ U16 codesize = data[0]+256*data[1];
+ printf(" codesize:%d ", codesize);
+
+ /* the following tries to find the "string"
+ the flash documentation speaks of- I've
+ never actually seen one yet. -mk */
+ for(t=2;t<atag->len;t++)
+ printf("[%02x]", atag->data[t]);
+
+ printf("\n%s %s{", prefix, indent);
+ if(countpos>=15) {
+ printf("Error: nested too deep\n");
+ continue;
+ }
+ counter[countpos].text = "}";
+ counter[countpos].count = codesize + ATAG_FULLLENGTH(atag);
+ countpos++;
+ } break;
+ case 'b': {
+ printf(" %d", data[0]+256*(signed char)data[1]);
+ } break;
+ case 'r': {
+ printf(" %d", data[0]);
+ } break;
+ case 'p': {
+ U8 type = *data;
+ unsigned char*value = data+1;
+ if(type == 0) {
+ printf(" String:\"%s\"", value);
+ } else if (type == 1) {
+ U32 f = value[0]+(value[1]<<8)+
+ (value[2]<<16)+(value[3]<<24);
+ printf(" Float:%f", *(float*)&f);
+ } else if (type == 2) {
+ printf(" NULL");
+ } else if (type == 4) {
+ printf(" register:%d", *value);
+ } else if (type == 5) {
+ printf(" bool:%s", *value?"true":"false");
+ } else if (type == 6) {
+ U8 a[8];
+ int t;
+ memcpy(&a[4],value,4);
+ memcpy(a,&value[4],4);
+#ifdef WORDS_BIGENDIAN
+ for(t=0;t<4;t++) {
+ U8 tmp = a[t];
+ a[t]=a[7-t];
+ a[7-t] = tmp;
+ }
+#endif
+ printf(" double:%f", *(double*)a);
+ } else if (type == 7) {
+ printf(" int:%d", value[0]+(value[1]<<8)+
+ (value[2]<<16)+(value[3]<<24));
+ } else if (type == 8) {
+ printf(" Lookup:%d", *value);
+#ifdef MAX_LOOKUP
+ if (lookup[*value])
+ printf(" (\"%s\")",lookup[*value]);
+#endif
+ } else {
+ printf(" UNKNOWN[%02x]",type);
+ }
+ } break;
+ }
+ data += OpAdvance(*cp, data);
+ if((*cp!='c' || !poollen) &&
+ (*cp!='p' || !(data<&atag->data[atag->len])))
+ cp++;
+ if(poollen)
+ poollen--;
+ }
}
if(data < atag->data + atag->len)
{
int nl = ((atag->data+atag->len)-data);
int t;
- printf(" remainder of %d bytes:\"", nl);
+ printf(" (remainder of %d bytes:\"", nl);
for(t=0;t<nl;t++) {
if(data[t]<32)
printf("\\%d",data[t]);
else
printf("%c", data[t]);
}
- printf("\"");
+ printf("\")");
}
printf("\n");
+
+ for(t=0;t<countpos;t++) {
+ counter[t].count -= ATAG_FULLLENGTH(atag);
+ if(counter[t].count < 0) {
+ printf("===== Error: Oplength errors =====\n");
+ countpos = 0;
+ break;
+ }
+ }
+
+ while(countpos && !counter[countpos-1].count)
+ {
+ printf("%s %s%s\n",
+ prefix, indent, counter[countpos-1].text);
+ indent += 4;
+ countpos--;
+ }
+
atag = atag->next;
}
+
+#ifdef MAX_LOOKUP
+ for (t=0;t<MAX_LOOKUP;t++) if (lookup[t]) free(lookup[t]);
+#endif
}
static const char TYPE_URL = 1;
currentatag = currentatag->next;
}
+ActionMarker action_setMarker()
+{
+ ActionMarker m;
+ m.atag = currentatag;
+ return m;
+}
+
+int inline ActionTagSize(ActionTAG*atag)
+{
+ return (atag->op&0x80)?3+(atag->len):1+0;
+}
+
+
#define ACTION_END 0x00
#define ACTION_NEXTFRAME 0x04
#define ACTION_PREVIOUSFRAME 0x05
#define ACTION_CALL 0x9e
#define ACTION_GOTOFRAME2 0x9f
+void action_fixjump(ActionMarker m1, ActionMarker m2)
+{
+ ActionTAG* a1 = m1.atag;
+ ActionTAG* a2 = m2.atag;
+ ActionTAG* a;
+ int len = 0;
+ int oplen = 0;
+ a = a1;
+
+ a = a->next; //first one is free
+ while(a && a!=a2)
+ {
+ len += ActionTagSize(a);
+ oplen ++;
+ a = a->next;
+ }
+ if(!a)
+ { len = 0;
+ oplen = 0;
+ a = a2;
+ while(a && a!=a1) {
+ len -= ActionTagSize(a);
+ oplen --;
+ a = a->next;
+ }
+ if(!a) {
+ fprintf(stderr, "action_fixjump: couldn't find second tag\n");
+ return;
+ }
+ len -= ActionTagSize(a);
+ oplen --;
+ }
+
+ if (a1->op == ACTION_IF || a1->op == ACTION_JUMP)
+ {
+ *(U16*)(a1->data) = SWAP16(len);
+ }
+ else if(a1->op == ACTION_WAITFORFRAME)
+ {
+ ((U8*)(a1->data))[2] = oplen;
+ }
+ else if(a1->op == ACTION_WAITFORFRAME2)
+ {
+ ((U8*)(a1->data))[0] = oplen;
+ }
+
+}
+
+
void action_NextFrame() {swf_AddActionTAG(ACTION_NEXTFRAME, 0, 0);}
void action_PreviousFrame() {swf_AddActionTAG(ACTION_PREVIOUSFRAME, 0, 0);}
void action_Play() {swf_AddActionTAG(ACTION_PLAY, 0, 0);}
void action_End() {swf_AddActionTAG(ACTION_END, 0, 0);}
void action_GotoFrame(U16 frame)
{
- *(U16*)currentatag->tmp = frame;
+ *(U16*)currentatag->tmp = SWAP16(frame);
swf_AddActionTAG(ACTION_GOTOFRAME, (U8*)currentatag->tmp, 2);
}
void action_Jump(U16 branch)
{
- *(U16*)currentatag->tmp = branch;
+ *(U16*)currentatag->tmp = SWAP16(branch);
swf_AddActionTAG(ACTION_JUMP, (U8*)currentatag->tmp, 2);
}
void action_If(U16 branch)
{
- *(U16*)currentatag->tmp = branch;
+ *(U16*)currentatag->tmp = SWAP16(branch);
swf_AddActionTAG(ACTION_IF, (U8*)currentatag->tmp, 2);
}
void action_StoreRegister(U8 reg)
}
void action_WaitForFrame(U16 frame, U8 skip)
{
- *(U16*)currentatag->tmp = frame;
+ *(U16*)currentatag->tmp = SWAP16(frame);
*(U8*)¤tatag->tmp[2] = skip;
swf_AddActionTAG(ACTION_WAITFORFRAME, (U8*)currentatag->tmp, 3);
}
void action_PushFloat(float f)
{
char*ptr = (char*)malloc(5);
+ U32 fd = *(U32*)&f;
ptr[0] = 1; //float
- *(float*)&ptr[1] = f;
+ ptr[1] = fd;
+ ptr[2] = fd>>8;
+ ptr[3] = fd>>16;
+ ptr[4] = fd>>24;
swf_AddActionTAG(ACTION_PUSH, (U8*)ptr, 5);
}
void action_PushDouble(double d)
{
char*ptr = (char*)malloc(9);
+ U8*dd = (U8*)&d;
ptr[0] = 6; //double
- *(double*)&ptr[1] = d;
+#ifdef WORDS_BIGENDIAN
+ ptr[1] = dd[7];ptr[2] = dd[6];
+ ptr[3] = dd[5];ptr[4] = dd[4];
+ ptr[5] = dd[3];ptr[6] = dd[2];
+ ptr[7] = dd[1];ptr[8] = dd[0];
+#else
+ ptr[1] = dd[0];ptr[2] = dd[1];
+ ptr[3] = dd[2];ptr[4] = dd[3];
+ ptr[5] = dd[4];ptr[6] = dd[5];
+ ptr[7] = dd[6];ptr[8] = dd[7];
+#endif
swf_AddActionTAG(ACTION_PUSH, (U8*)ptr, 9);
}
void action_PushInt(int i)
{
*(U8*)currentatag->tmp = 7; //int
- *(U8*)¤tatag->tmp[1] = i;
+ currentatag->tmp[1] = i;
+ currentatag->tmp[2] = i>>8;
+ currentatag->tmp[3] = i>>16;
+ currentatag->tmp[4] = i>>24;
swf_AddActionTAG(ACTION_PUSH, (U8*)currentatag->tmp, 5);
}
void action_GotoLabel(char* label)
int l2= strlen(label);
char*ptr = malloc(l1+l2+2);
strcpy(ptr, url);
- strcat(&ptr[l2+1], label);
- swf_AddActionTAG(ACTION_GOTOLABEL, ptr, strlen(ptr));
+ strcpy(&ptr[l1+1], label);
+ swf_AddActionTAG(ACTION_GETURL, ptr, l1+l2+2);
}
//TODO:
void action_DefineFunction(U8*data, int len) {}
void action_Constantpool(char* constantpool) {}
void action_With(char*object) {}
+
+/*
+ Properties:
+
+ _X 0
+ _Y 1
+ _xscale 2
+ _yscale 3
+ _currentframe 4
+ _totalframes 5
+ _alpha 6
+ _visible 7
+ _width 8
+ _height 9
+ _rotation 10
+ _target 11
+ _framesloaded 12
+ _name 13
+ _droptarget 14
+ _url 15
+ _highquality 16
+ _focusrect 17
+ _soundbuftime 18
+ _quality* 19
+ _xmouse* 20
+ _ymouse* 21
+*/