/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- stringConcat
- bufferPatchLength
- bufferPatchPushLength
- Ming_useConstants
- addConstant
- bufferWriteConstants
- newBuffer
- destroyBuffer
- bufferLength
- bufferCheckSize
- bufferWriteData
- bufferWriteBuffer
- bufferWriteDataAndPush
- bufferConcatSimple
- bufferConcat
- bufferWriteOp
- bufferWritePushOp
- bufferWriteU8
- bufferWriteS16
- bufferWriteHardString
- bufferWriteConstantString
- bufferWritePushString
- bufferWriteString
- bufferWriteInt
- bufferWriteFloat
- bufferWriteDouble
- bufferWriteNull
- bufferWriteUndef
- bufferWriteBoolean
- bufferWriteRegister
- bufferWriteSetRegister
- lower
- addctx
- delctx
- chkctx
- bufferResolveJumpsFull
- bufferResolveSwitch
- lookupProperty
- bufferWriteProperty
- bufferWriteWTHITProperty
- bufferWriteDefineFunction2
- destroyASFunction
- bufferWriteFunction
- newASFunction
- destroyASClass
- ASClass_getConstructor
- bufferWriteClassConstructor
- bufferWriteClassMethods
- bufferWriteClassVariable
- bufferWriteClassMembers
- bufferWriteClass
- ASClassMember_append
- newASClass
- newASClassMember_function
- newASClassMember_variable
- newASClassMember_buffer
- newASVariable
/*
Ming, an SWF output library
Copyright (C) 2002 Opaque Industries - http://www.opaque.net/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef WIN32
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "libming.h"
#include "compile.h"
#include "actiontypes.h"
#include "blocks/error.h"
/* Define this to have some debugging output when outputting DEFINEFUNCTION2 */
#undef MING_DEBUG_FUNCTION2
// XXX: set by swf[4|5]Init()
int swfVersion = 0;
static int nConstants = {0}, maxConstants = {0}, sizeConstants = {0};
static char **constants = NULL;
char *stringConcat(char *a, char *b)
{
if ( a != NULL )
{
if ( b != NULL )
{
a = (char*)realloc(a, strlen(a)+strlen(b)+1);
if(a == NULL)
return NULL;
strcat(a, b);
free(b);
}
return a;
}
else
return b;
}
void bufferPatchLength(Buffer buffer, int back)
{
unsigned char *output = buffer->buffer;
int len = bufferLength(buffer);
output[len-back-1] = (back>>8) & 0xff;
output[len-back-2] = back & 0xff;
}
/* add len more bytes to length of the pushdata opcode pointed to by
buffer->pushloc */
void bufferPatchPushLength(Buffer buffer, int len)
{
int oldsize;
if(buffer->pushloc != NULL)
{
oldsize = (buffer->pushloc[0] & 0xff) | ((buffer->pushloc[1] & 0xff) << 8);
oldsize += len;
buffer->pushloc[0] = oldsize & 0xff;
buffer->pushloc[1] = (oldsize >> 8) & 0xff;
}
else
SWF_error("problem with bufferPatchPushLength\n");
}
static int useConstants = 1;
void Ming_useConstants(int flag)
{ useConstants = flag;
}
int addConstant(const char *s)
{
int i;
for(i=0; i<nConstants; ++i)
{
if(strcmp(s, constants[i]) == 0)
return i;
}
/* Don't let constant pool biggern then allowed */
if ( sizeConstants+strlen(s)+1 > MAXCONSTANTPOOLSIZE ) return -1;
if(nConstants == maxConstants)
constants = (char **) realloc(constants, (maxConstants += 64) * sizeof(char *));
constants[nConstants] = strdup(s);
sizeConstants += (strlen(s)+1);
return nConstants++;
}
int bufferWriteConstants(Buffer out)
{
int i, len=2;
if(nConstants == 0)
return 0;
bufferWriteU8(out, SWFACTION_CONSTANTPOOL);
bufferWriteS16(out, 0); /* length */
bufferWriteS16(out, nConstants);
for(i=0; i<nConstants; ++i)
{
len += bufferWriteHardString(out, constants[i], strlen(constants[i])+1);
free(constants[i]);
}
nConstants = 0;
sizeConstants = 0;
bufferPatchLength(out, len);
return len+3;
}
Buffer newBuffer()
{
Buffer out = (Buffer)malloc(BUFFER_SIZE);
if(out == NULL)
return NULL;
memset(out, 0, BUFFER_SIZE);
out->buffer = (byte*)malloc(BUFFER_INCREMENT);
out->pos = out->buffer;
*(out->pos) = 0;
out->buffersize = out->free = BUFFER_INCREMENT;
out->pushloc = NULL;
out->hasObject = 0;
return out;
}
void destroyBuffer(Buffer out)
{
free(out->buffer);
free(out);
}
int bufferLength(Buffer out)
{
if(out)
return (out->pos)-(out->buffer);
else
return 0;
}
/* make sure there's enough space for bytes bytes */
void bufferCheckSize(Buffer out, int bytes)
{
if(bytes > out->free)
{
int New = BUFFER_INCREMENT * ((bytes-out->free-1)/BUFFER_INCREMENT + 1);
int num = bufferLength(out); /* in case buffer gets displaced.. */
unsigned char *newbuf = (unsigned char*)realloc(out->buffer, out->buffersize+New);
if(newbuf != out->buffer)
{
int pushd = 0;
if(out->pushloc)
pushd = out->pos - out->pushloc;
out->pos = newbuf+num;
if(out->pushloc)
out->pushloc = out->pos - pushd;
}
out->buffer = newbuf;
out->buffersize += New;
out->free += New;
}
}
int bufferWriteData(Buffer b, const byte *data, int length)
{
int i;
bufferCheckSize(b, length);
for(i=0; i<length; ++i)
bufferWriteU8(b, data[i]);
return length;
}
int bufferWriteBuffer(Buffer a, Buffer b)
{
if(!a)
return 0;
if(b)
return bufferWriteData(a, b->buffer, bufferLength(b));
return 0;
}
/* if a's last op and b's first op are both PUSH, concat into one op */
int bufferWriteDataAndPush(Buffer a, Buffer b)
{
int i, pushd = 0;
byte *data = b->buffer;
int length = b->pos - b->buffer;
if(a->pushloc && (b->buffer[0] == SWFACTION_PUSH) && swfVersion > 4)
{
pushd = (b->buffer[1] & 0xff) | ((b->buffer[2] & 0xff) << 8);
bufferPatchPushLength(a, pushd);
data += 3;
length -= 3;
}
if(b->pushloc)
pushd = b->pos - b->pushloc;
bufferCheckSize(a, length);
for(i=0; i<length; ++i)
bufferWriteU8(a, data[i]);
if(a->pushloc &&
(b->buffer[0] == SWFACTION_PUSH) && (b->pushloc == b->buffer+1))
; /* b is just one pushdata, so do nothing.. */
else if(b->pushloc)
a->pushloc = a->pos - pushd;
else
a->pushloc = 0;
return length;
}
int bufferConcatSimple(Buffer a, Buffer b)
{
int len = 0;
if(!a)
return 0;
if(b)
{ len = bufferWriteBuffer(a, b);
destroyBuffer(b);
}
return len;
}
int bufferConcat(Buffer a, Buffer b)
{
int len = 0;
if(!a)
return 0;
if(b)
{ len = bufferWriteDataAndPush(a, b);
destroyBuffer(b);
}
return len;
}
int bufferWriteOp(Buffer out, int data)
{
bufferWriteU8(out, data);
out->pushloc = NULL;
return 1;
}
int bufferWritePushOp(Buffer out)
{
bufferWriteU8(out, SWFACTION_PUSH);
out->pushloc = out->pos;
return 1;
}
int bufferWriteU8(Buffer out, int data)
{
bufferCheckSize(out, 1);
*(out->pos) = data;
out->pos++;
out->free--;
return 1;
}
int bufferWriteS16(Buffer out, int data)
{
if(data < 0)
data = (1<<16)+data;
bufferWriteU8(out, data%256);
data >>= 8;
bufferWriteU8(out, data%256);
return 2;
}
int bufferWriteHardString(Buffer out, const char *string, int length)
{
int i;
for(i=0; i<length; ++i)
bufferWriteU8(out, (byte)string[i]);
return length;
}
int bufferWriteConstantString(Buffer out, const char *string, int length)
{
int n;
if(swfVersion < 5)
return -1;
if(useConstants)
n = addConstant((char*) string);
else
n = -1;
if(n == -1)
{
bufferWriteU8(out, PUSH_STRING);
return bufferWriteHardString(out, string, length) + 1;
}
else if(n < 256)
{
bufferWriteU8(out, PUSH_CONSTANT);
return bufferWriteU8(out, n) + 1;
}
else
{
bufferWriteU8(out, PUSH_CONSTANT16);
return bufferWriteS16(out, n) + 1;
}
}
/* allow pushing STRINGs for SWF>=5 */
int bufferWritePushString(Buffer out, char *string, int length)
{
int l, len = 0;
if(out->pushloc == NULL || swfVersion < 5)
{
len = 3;
bufferWritePushOp(out);
bufferWriteS16(out, length+1);
}
bufferWriteU8(out, PUSH_STRING);
l = bufferWriteHardString(out, string, length);
bufferPatchPushLength(out, l + 1);
return len + l + 1;
}
int bufferWriteString(Buffer out, const char *string, int length)
{
if(swfVersion < 5)
{
bufferWritePushOp(out);
bufferWriteS16(out, length+1);
bufferWriteU8(out, PUSH_STRING);
bufferWriteHardString(out, string, length);
return 4 + length;
}
else
{
int l;
if(out->pushloc == NULL)
{
bufferWritePushOp(out);
bufferWriteS16(out, 0);
}
l = bufferWriteConstantString(out, string, length);
bufferPatchPushLength(out, l);
return l;
}
}
int bufferWriteInt(Buffer out, int i)
{
int len = 0;
unsigned char *p = (unsigned char *)&i;
if(out->pushloc == NULL || swfVersion < 5)
{
len = 3;
bufferWritePushOp(out);
bufferWriteS16(out, 5);
}
else
bufferPatchPushLength(out, 5);
bufferWriteU8(out, PUSH_INT);
#if SWF_LITTLE_ENDIAN
bufferWriteU8(out, p[0]);
bufferWriteU8(out, p[1]);
bufferWriteU8(out, p[2]);
bufferWriteU8(out, p[3]);
#else
bufferWriteU8(out, p[3]);
bufferWriteU8(out, p[2]);
bufferWriteU8(out, p[1]);
bufferWriteU8(out, p[0]);
#endif
return len + 5;
}
int bufferWriteFloat(Buffer out, float f)
{
int len = 0;
unsigned char *p = (unsigned char *)&f;
if(out->pushloc == NULL || swfVersion < 5)
{
len = 3;
bufferWritePushOp(out);
bufferWriteS16(out, 5);
}
else
bufferPatchPushLength(out, 5);
bufferWriteU8(out, PUSH_FLOAT);
#if SWF_LITTLE_ENDIAN
bufferWriteU8(out, p[0]);
bufferWriteU8(out, p[1]);
bufferWriteU8(out, p[2]);
bufferWriteU8(out, p[3]);
#else
bufferWriteU8(out, p[3]);
bufferWriteU8(out, p[2]);
bufferWriteU8(out, p[1]);
bufferWriteU8(out, p[0]);
#endif
return len + 5;
}
int bufferWriteDouble(Buffer out, double d)
{
int len = 0;
unsigned char *p = (unsigned char *)&d;
if(out->pushloc == NULL || swfVersion < 5)
{
len = 3;
bufferWritePushOp(out);
bufferWriteS16(out, 9);
}
else
bufferPatchPushLength(out, 5);
bufferWriteU8(out, PUSH_DOUBLE);
#if SWF_LITTLE_ENDIAN
bufferWriteU8(out, p[4]);
bufferWriteU8(out, p[5]);
bufferWriteU8(out, p[6]);
bufferWriteU8(out, p[7]);
bufferWriteU8(out, p[0]);
bufferWriteU8(out, p[1]);
bufferWriteU8(out, p[2]);
bufferWriteU8(out, p[3]);
#else
bufferWriteU8(out, p[3]);
bufferWriteU8(out, p[2]);
bufferWriteU8(out, p[1]);
bufferWriteU8(out, p[0]);
bufferWriteU8(out, p[7]);
bufferWriteU8(out, p[6]);
bufferWriteU8(out, p[5]);
bufferWriteU8(out, p[4]);
#endif
return len + 9;
}
int bufferWriteNull(Buffer out)
{
int len = 0;
if(out->pushloc == NULL || swfVersion < 5)
{
len = 3;
bufferWritePushOp(out);
bufferWriteS16(out, 1);
}
else
bufferPatchPushLength(out, 1);
bufferWriteU8(out, PUSH_NULL);
return len + 1;
}
int bufferWriteUndef(Buffer out)
{
int len = 0;
if(out->pushloc == NULL || swfVersion < 5)
{
len = 3;
bufferWritePushOp(out);
bufferWriteS16(out, 1);
}
else
bufferPatchPushLength(out, 1);
bufferWriteU8(out, PUSH_UNDEF);
return len + 1;
}
int bufferWriteBoolean(Buffer out, int val)
{
int len = 0;
if(out->pushloc == NULL || swfVersion < 5)
{
len = 3;
bufferWritePushOp(out);
bufferWriteS16(out, 2);
}
else
bufferPatchPushLength(out, 2);
bufferWriteU8(out, PUSH_BOOLEAN);
bufferWriteU8(out, val ? 1 : 0);
return len + 2;
}
int bufferWriteRegister(Buffer out, int num)
{
int len = 0;
if(out->pushloc == NULL || swfVersion < 5)
{
len = 3;
bufferWritePushOp(out);
bufferWriteS16(out, 2);
}
else
bufferPatchPushLength(out, 2);
bufferWriteU8(out, PUSH_REGISTER);
bufferWriteU8(out, num);
return len + 2;
}
int bufferWriteSetRegister(Buffer out, int num)
{
bufferWriteU8(out, SWFACTION_STOREREGISTER);
bufferWriteS16(out, 1);
bufferWriteU8(out, num);
return 4;
}
void lower(char *s)
{
while(*s)
{
*s = tolower(*s);
++s;
}
}
/* this code will eventually help to pop extra values off the
stack and make sure that continue and break address the proper
context
*/
static enum ctx *ctx_stack = {0};
static int ctx_count = {0}, ctx_len = {0};
void addctx(enum ctx val)
{
if(ctx_count >= ctx_len)
ctx_stack = (enum ctx*) realloc(ctx_stack, (ctx_len += 10) * sizeof(enum ctx));
ctx_stack[ctx_count++] = val;
}
void delctx(enum ctx val)
{
if(ctx_count <= 0)
SWF_error("consistency check in delctx: stack empty!\n");
else if (ctx_stack[--ctx_count] != val)
SWF_error("consistency check in delctx: val %i != %i\n", ctx_stack[ctx_count], val);
}
int chkctx(enum ctx val)
{ int n, ret = 0;
switch(val)
{ case CTX_FUNCTION:
for(n = ctx_count ; --n >= 0 ; )
switch(ctx_stack[n])
{ case CTX_SWITCH:
case CTX_FOR_IN:
ret++;
break;
case CTX_FUNCTION:
return ret;
default: ; /* computers are stupid */
}
return -1;
case CTX_BREAK:
for(n = ctx_count ; --n >= 0 ; )
switch(ctx_stack[n])
{ case CTX_SWITCH:
return CTX_SWITCH;
case CTX_LOOP:
return CTX_LOOP;
case CTX_FOR_IN:
return CTX_FOR_IN;
case CTX_FUNCTION:
return -1;
case CTX_BREAK:
return CTX_BREAK;
default: ; /* computers are stupid */
}
return -1;
case CTX_CONTINUE:
for(n = ctx_count ; --n >= 0 ; )
switch(ctx_stack[n])
{ case CTX_LOOP:
case CTX_FOR_IN:
return 0;
case CTX_FUNCTION:
return -1;
default: ; /* computers are stupid */
}
default: return -1;; /* computers are stupid */
}
}
/* replace MAGIC_CONTINUE_NUMBER and MAGIC_BREAK_NUMBER with jumps to
head or tail, respectively */
/* jump offset is relative to end of jump instruction */
/* I can't believe this actually worked */
void bufferResolveJumpsFull(Buffer out, byte *break_ptr, byte *continue_ptr)
{
byte *p = out->buffer;
int l, target;
while(p < out->pos)
{
if(*p & 0x80) /* then it's a multibyte instruction */
{
if(*p == SWFACTION_JUMP)
{
p += 3; /* plus instruction plus two-byte length */
if(*p == MAGIC_CONTINUE_NUMBER_LO &&
*(p+1) == MAGIC_CONTINUE_NUMBER_HI)
{
target = continue_ptr - (p+2);
*p = target & 0xff;
*(p+1) = (target>>8) & 0xff;
}
else if(*p == MAGIC_BREAK_NUMBER_LO &&
*(p+1) == MAGIC_BREAK_NUMBER_HI)
{
target = break_ptr - (p+2);
*p = target & 0xff;
*(p+1) = (target>>8) & 0xff;
}
p += 2;
}
else
{
++p;
l = *p;
++p;
l += *p<<8;
++p;
p += l;
}
}
else
++p;
}
}
// handle SWITCH statement
void bufferResolveSwitch(Buffer buffer, struct switchcases *slp)
{ struct switchcase *scp;
int n, len;
unsigned char *output;
len = bufferLength(buffer);
for(n = 0, scp = slp->list ; n < slp->count ; n++, scp++)
{ scp->actlen = bufferLength(scp->action);
if((n < slp->count-1))
scp->actlen += 5;
if(scp->cond)
{ scp->condlen = bufferLength(scp->cond) + 8;
bufferWriteOp(buffer, SWFACTION_PUSHDUP);
bufferConcat(buffer, scp->cond);
bufferWriteOp(buffer, SWFACTION_EQUALS2);
bufferWriteOp(buffer, SWFACTION_LOGICALNOT);
bufferWriteOp(buffer, SWFACTION_IF);
bufferWriteS16(buffer, 2);
bufferWriteS16(buffer, scp->actlen);
}
else
scp->condlen = 0;
bufferConcat(buffer, scp->action);
bufferWriteOp(buffer, SWFACTION_JUMP);
bufferWriteS16(buffer, 2);
bufferWriteS16(buffer, scp->isbreak ? MAGIC_BREAK_NUMBER : 0);
if(!scp->cond)
{ slp->count = n+1;
break;
}
}
for(n = 0, scp = slp->list ; n < slp->count ; n++, scp++)
{ len += scp->condlen;
output = buffer->buffer + len;
if((n < slp->count-1) && !scp->isbreak)
{ output[scp->actlen-2] = (scp+1)->condlen & 0xff;
output[scp->actlen-1] = (scp+1)->condlen >> 8;
}
len += scp->actlen;
}
}
int lookupProperty(char *string)
{
lower(string);
if(strcmp(string, "_x") == 0) return PROPERTY_X;
if(strcmp(string, "_y") == 0) return PROPERTY_Y;
if(strcmp(string, "_xscale") == 0) return PROPERTY_XSCALE;
if(strcmp(string, "_yscale") == 0) return PROPERTY_YSCALE;
if(strcmp(string, "_currentframe") == 0) return PROPERTY_CURRENTFRAME;
if(strcmp(string, "_totalframes") == 0) return PROPERTY_TOTALFRAMES;
if(strcmp(string, "_alpha") == 0) return PROPERTY_ALPHA;
if(strcmp(string, "_visible") == 0) return PROPERTY_VISIBLE;
if(strcmp(string, "_width") == 0) return PROPERTY_WIDTH;
if(strcmp(string, "_height") == 0) return PROPERTY_HEIGHT;
if(strcmp(string, "_rotation") == 0) return PROPERTY_ROTATION;
if(strcmp(string, "_target") == 0) return PROPERTY_TARGET;
if(strcmp(string, "_framesloaded") == 0) return PROPERTY_FRAMESLOADED;
if(strcmp(string, "_name") == 0) return PROPERTY_NAME;
if(strcmp(string, "_droptarget") == 0) return PROPERTY_DROPTARGET;
if(strcmp(string, "_url") == 0) return PROPERTY_URL;
if(strcmp(string, "_highquality") == 0) return PROPERTY_HIGHQUALITY;
if(strcmp(string, "_focusrect") == 0) return PROPERTY_FOCUSRECT;
if(strcmp(string, "_soundbuftime") == 0) return PROPERTY_SOUNDBUFTIME;
if(strcmp(string, "_quality")==0) return PROPERTY_QUALITY;
if(strcmp(string, "_xmouse") == 0) return PROPERTY_XMOUSE;
if(strcmp(string, "_ymouse") == 0) return PROPERTY_YMOUSE;
SWF_error("No such property: %s\n", string);
return -1;
}
int bufferWriteProperty(Buffer out, char *string)
{
int property = lookupProperty(string);
return bufferWriteFloat(out, property);
}
// XXX: ???
int bufferWriteWTHITProperty(Buffer out)
{
bufferWriteU8(out, SWFACTION_PUSH);
bufferWriteS16(out, 5);
bufferWriteU8(out, PUSH_FLOAT);
bufferWriteS16(out, 0);
bufferWriteS16(out, 0x4680);
return 8;
}
/**
* @param func_name
* Function name, NULL for anonymous functions.
*
* @param num_regs
* Number of registers.
*
* @param flags
* See SWFDefineFunction2Flags enum.
*/
static int bufferWriteDefineFunction2(Buffer out, char *func_name,
Buffer args, Buffer code, int flags, int num_regs)
{
Buffer c;
char buf[1024];
int num_args = 0, i;
char *p = (char *) args->buffer;
size_t taglen;
strcpy(buf, "");
// REGISTERPARAM records
c = newBuffer();
// TODO: rewrite this function, all these calls to strncat
// seem overkill to me
for(i = 0; i < bufferLength(args); i++)
{
if(p[i] == '\0')
{
bufferWriteU8(c, 0);
bufferWriteHardString(c, buf, strlen(buf)+1);
strcpy(buf, "");
num_args++;
}
else
{
strncat(buf, &p[i], 1);
}
}
bufferWriteOp(out, SWFACTION_DEFINEFUNCTION2);
if(func_name == NULL)
{
taglen =
+ 1 /* function name (empty) */
+ 2 /* arg count (short) */
+ 1 /* reg count (byte) */
+ 2 /* flags */
+ bufferLength(c) /* swf_params */
+ 2 /* body size */
;
#ifdef MING_DEBUG_FUNCTION2
printf("adding anonymouse SWF_DEFINEFUNCTION2 nargs=%d flags=%d"
" arglen=%d codelen=%d taglen=%d\n",
num_args, flags, bufferLength(args),
bufferLength(code), taglen);
#endif
bufferWriteS16(out, taglen);
bufferWriteU8(out, 0); /* empty function name */
}
else
{
taglen = 0
+ strlen(func_name)+1 /* function name */
+ 2 /* arg count (short) */
+ 1 /* reg count (byte) */
+ 2 /* flags */
+ bufferLength(c) /* swf_params */
+ 2 /* body size */
;
#ifdef MING_DEBUG_FUNCTION2
printf("adding named SWF_DEFINEFUNCTION2 name=%s nargs=%d flags=%d"
" regparamlen=%d arglen=%d codelen=%d taglen=%d\n",
func_name, num_args, flags,
bufferLength(c),
bufferLength(args),
bufferLength(code), taglen);
#endif
bufferWriteS16(out, taglen);
bufferWriteHardString(out, func_name, strlen(func_name)+1);
}
bufferWriteS16(out, num_args); /* number of params */
bufferWriteU8(out, num_regs); /* register count */
bufferWriteS16(out, flags); /* flags */
//bufferWriteS16(out, 0); /* flags */
bufferConcat(out, c);
bufferWriteS16(out, bufferLength(code)); /* code size */
bufferConcat(out, code);
return taglen;
}
void destroyASFunction(ASFunction func)
{
free(func->name);
free(func);
}
int bufferWriteFunction(Buffer out, ASFunction function, int version)
{
int tagLen;
if(version == 2)
{
tagLen = bufferWriteDefineFunction2(out, function->name,
function->params.buffer, function->code, function->flags, 0);
}
else
{
tagLen = 5;
tagLen += bufferLength(function->params.buffer);
if(function->name != NULL)
tagLen += strlen(function->name);
bufferWriteOp(out, SWFACTION_DEFINEFUNCTION);
bufferWriteS16(out, tagLen);
if(function->name == NULL)
bufferWriteU8(out, 0); /* empty function name */
else
bufferWriteHardString(out, function->name, strlen(function->name) +1 );
bufferWriteS16(out, function->params.count);
bufferConcat(out, function->params.buffer);
bufferWriteS16(out, bufferLength(function->code));
bufferConcat(out, function->code);
}
destroyASFunction(function);
return tagLen;
}
ASFunction newASFunction()
{
ASFunction func;
func = (ASFunction) malloc(sizeof(struct function_s));
func->flags = 0;
func->code = NULL;
func->params.count = 0;
func->params.buffer = NULL;
func->name = NULL;
return func;
}
void destroyASClass(ASClass clazz)
{
ASClassMember member;
if(clazz->name)
free(clazz->name);
member = clazz->members;
while(member)
{
ASClassMember _this = member;
member = member->next;
free(_this);
}
free(clazz);
}
ASFunction ASClass_getConstructor(ASClass clazz)
{
ASClassMember member;
member = clazz->members;
while(member)
{
ASFunction func;
ASClassMember _this = member;
member = member->next;
if(_this->type != METHOD)
continue;
func = _this->element.function;
if(!func || !func->name)
continue;
if(strcmp(func->name, clazz->name) != 0)
continue;
_this->element.function = NULL;
return func;
}
return newASFunction(); // default empty constructor
}
static int bufferWriteClassConstructor(Buffer out, ASClass clazz)
{
int len = 0;
ASFunction func;
/* class constructor */
len += bufferWriteString(out, "_global", strlen("_global") + 1);
len += bufferWriteOp(out, SWFACTION_GETVARIABLE);
len += bufferWriteString(out, clazz->name, strlen(clazz->name) + 1);
func = ASClass_getConstructor(clazz);
if(func->name)
{
free(func->name);
func->name = NULL;
}
len += bufferWriteFunction(out, func, 1);
len += bufferWriteSetRegister(out, 1);
len += bufferWriteOp(out, SWFACTION_SETMEMBER);
len += bufferWriteRegister(out, 1);
len += bufferWriteString(out, "prototype", strlen("prototype") + 1);
len += bufferWriteOp(out, SWFACTION_GETMEMBER);
len += bufferWriteSetRegister(out, 2);
len += bufferWriteOp(out, SWFACTION_POP);
return len;
}
static int bufferWriteClassMethods(Buffer out, ASClass clazz)
{
ASClassMember member = clazz->members;
int len = 0;
while(member)
{
ASFunction func;
ASClassMember _this = member;
member = member->next;
if(_this->type != METHOD)
continue;
func = _this->element.function;
if(!func || !func->name)
continue;
if(strcmp(func->name, clazz->name) != 0)
{
SWF_error("only one class constructor allowed\n");
}
len += bufferWriteRegister(out, 2);
len += bufferWriteString(out, func->name, strlen(func->name) + 1);
free(func->name);
func->name = NULL;
len += bufferWriteFunction(out, func, 1);
len += bufferWriteOp(out, SWFACTION_SETMEMBER);
_this->element.function = NULL;
}
return len;
}
static int bufferWriteClassVariable(Buffer out, ASVariable var)
{
int len = 0;
if(var->initCode != NULL)
{
len += bufferWriteRegister(out, 2);
len += bufferWriteString(out, var->name, strlen(var->name)+1);
len += bufferConcat(out, var->initCode);
len += bufferWriteOp(out, SWFACTION_SETMEMBER);
}
free(var->name);
free(var); // aka destroyASVariable
return len;
}
static int bufferWriteClassMembers(Buffer out, ASClass clazz)
{
ASClassMember member = clazz->members;
int len = 0;
while(member)
{
ASVariable var;
ASClassMember _this = member;
member = member->next;
if(_this->type != VARIABLE)
continue;
var = _this->element.var;
if(!var)
continue;
bufferWriteClassVariable(out, var);
_this->element.var = NULL;
}
return len;
}
int bufferWriteClass(Buffer out, ASClass clazz)
{
int len = 0;
len += bufferWriteClassConstructor(out, clazz);
len += bufferWriteClassMembers(out, clazz);
len += bufferWriteClassMethods(out, clazz);
/* set class properties */
len += bufferWriteInt(out, 1);
len += bufferWriteNull(out);
len += bufferWriteString(out, "_global", strlen("_global") + 1);
len += bufferWriteOp(out, SWFACTION_GETVARIABLE);
len += bufferWriteString(out, clazz->name, strlen(clazz->name) + 1);
len += bufferWriteOp(out, SWFACTION_GETMEMBER);
len += bufferWriteString(out, "prototype", strlen("prototype") + 1);
len += bufferWriteOp(out, SWFACTION_GETMEMBER);
len += bufferWriteInt(out, 3);
len += bufferWriteString(out, "ASSetPropFlags", strlen("ASSetPropFlags") + 1);
len += bufferWriteOp(out, SWFACTION_CALLFUNCTION);
len += bufferWriteOp(out, SWFACTION_POP);
destroyASClass(clazz);
return len;
}
void ASClassMember_append(ASClassMember m0, ASClassMember end)
{
ASClassMember mb = m0;
while(mb->next)
mb = mb->next;
mb->next = end;
}
ASClass newASClass(char *name, ASClassMember members)
{
ASClass clazz;
clazz = (ASClass) malloc(sizeof(struct class_s));
clazz->name = name;
clazz->members = members;
return clazz;
}
ASClassMember newASClassMember_function(ASFunction func)
{
ASClassMember member = (ASClassMember) malloc(sizeof(struct class_member_s));
member->element.function = func;
member->type = METHOD;
member->next = NULL;
return member;
}
ASClassMember newASClassMember_variable(ASVariable var)
{
ASClassMember member = (ASClassMember) malloc(sizeof(struct class_member_s));
member->element.var = var;
member->type = VARIABLE;
member->next = NULL;
return member;
}
ASClassMember newASClassMember_buffer(Buffer buf)
{
ASClassMember member = (ASClassMember) malloc(sizeof(struct class_member_s));
member->element.buffer = buf;
member->type = BUFF;
member->next = NULL;
return member;
}
ASVariable newASVariable(char *name, Buffer buf)
{
ASVariable var = (ASVariable) malloc(sizeof(struct variable_s));
var->name = name;
var->initCode = buf;
return var;
}
/*
* Local variables:
* tab-width: 2
* c-basic-offset: 2
* End:
*/