/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- checkByteOrder
- stringConcat
- bufferPatchLength
- bufferPatchPushLength
- Ming_useConstants
- addConstant
- bufferWriteConstants
- newBuffer
- destroyBuffer
- bufferLength
- bufferCheckSize
- bufferWriteData
- bufferWriteBuffer
- bufferWriteDataAndPush
- bufferConcat
- bufferWriteOp
- bufferWritePushOp
- bufferWriteU8
- bufferWriteS16
- bufferWriteHardString
- bufferWriteConstantString
- bufferWriteString
- bufferWriteInt
- bufferWriteDouble
- bufferWriteNull
- bufferWriteBoolean
- bufferWriteRegister
- bufferWriteSetRegister
- lower
- addctx
- delctx
- chkctx
- bufferResolveJumps
- bufferResolveSwitch
- lookupSetProperty
- bufferWriteSetProperty
- bufferWriteWTHITProperty
- lookupGetProperty
- bufferWriteGetProperty
/*
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 "action.h"
#include "blocks/error.h"
static int nConstants = {0}, maxConstants = {0}, sizeConstants = {0};
static char **constants;
/* XXX - temp hack until we check at compile time */
enum
{
SWF_BIG_ENDIAN,
SWF_LITTLE_ENDIAN
};
static int byteorder;
void checkByteOrder()
{
unsigned int x;
unsigned char *p;
x = 0x01020304;
p = (unsigned char *)&x;
if(*p == 1)
byteorder = SWF_BIG_ENDIAN;
else
byteorder = SWF_LITTLE_ENDIAN;
}
char *stringConcat(char *a, char *b)
{
if ( a != NULL )
{
if ( b != NULL )
{
a = (char*)realloc(a, strlen(a)+strlen(b)+1);
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,(byte*) 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);
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;
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;
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 PUSHDATA, concat into one op */
int bufferWriteDataAndPush(Buffer a, Buffer b)
{
int i, pushd;
byte *data = b->buffer;
int length = b->pos - b->buffer;
if(a->pushloc && (b->buffer[0] == SWFACTION_PUSHDATA) && SWF_versionNum > 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_PUSHDATA) && (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 bufferConcat(Buffer a, Buffer b)
{
int len;
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_PUSHDATA);
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, byte *string, int length)
{
int i;
for(i=0; i<length; ++i)
bufferWriteU8(out, string[i]);
return length;
}
int bufferWriteConstantString(Buffer out, byte *string, int length)
{
int n;
if(SWF_versionNum < 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;
}
}
int bufferWriteString(Buffer out, byte *string, int length)
{
if(SWF_versionNum < 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 || SWF_versionNum < 5)
{
len = 3;
bufferWritePushOp(out);
bufferWriteS16(out, 5);
}
else
bufferPatchPushLength(out, 5);
bufferWriteU8(out, PUSH_INT);
if(byteorder == 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]);
}
return len + 5;
}
int bufferWriteDouble(Buffer out, double d)
{
int len = 0;
unsigned char *p = (unsigned char *)&d;
if(out->pushloc == NULL || SWF_versionNum < 5)
{
len = 3;
bufferWritePushOp(out);
bufferWriteS16(out, 9);
}
else
bufferPatchPushLength(out, 5);
bufferWriteU8(out, PUSH_DOUBLE);
if(byteorder == 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]);
}
return len + 9;
}
int bufferWriteNull(Buffer out)
{
int len = 0;
if(out->pushloc == NULL || SWF_versionNum < 5)
{
len = 3;
bufferWritePushOp(out);
bufferWriteS16(out, 1);
}
else
bufferPatchPushLength(out, 1);
bufferWriteU8(out, PUSH_NULL);
return len + 1;
}
int bufferWriteBoolean(Buffer out, int val)
{
int len = 0;
if(out->pushloc == NULL || SWF_versionNum < 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 || SWF_versionNum < 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_SETREGISTER);
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 || ctx_stack[--ctx_count] != val)
SWF_error("consistency check in delctx");
}
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:
case CTX_LOOP:
return 0;
case CTX_FOR_IN:
return 1;
case CTX_FUNCTION:
return -1;
default: ; /* computers are stupid */
}
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: ; /* computers are stupid */
}
return 0;
}
/* 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 bufferResolveJumps(Buffer out)
{
byte *p = out->buffer;
int l, target;
while(p < out->pos)
{
if(*p & 0x80) /* then it's a multibyte instruction */
{
if(*p == SWFACTION_BRANCHALWAYS)
{
p += 3; /* plus instruction plus two-byte length */
if(*p == MAGIC_CONTINUE_NUMBER_LO &&
*(p+1) == MAGIC_CONTINUE_NUMBER_HI)
{
target = out->buffer - (p+2);
*p = target & 0xff;
*(p+1) = (target>>8) & 0xff;
}
else if(*p == MAGIC_BREAK_NUMBER_LO &&
*(p+1) == MAGIC_BREAK_NUMBER_HI)
{
target = out->pos - (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_DUP);
bufferConcat(buffer, scp->cond);
bufferWriteOp(buffer, SWFACTION_NEWEQUALS);
bufferWriteOp(buffer, SWFACTION_LOGICALNOT);
bufferWriteOp(buffer, SWFACTION_BRANCHIFTRUE);
bufferWriteS16(buffer, 2);
bufferWriteS16(buffer, scp->actlen);
}
else
scp->condlen = 0;
bufferConcat(buffer, scp->action);
bufferWriteOp(buffer, SWFACTION_BRANCHALWAYS);
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 lookupSetProperty(char *string)
{
lower(string);
if(strcmp(string,"x")==0) return 0x0000;
if(strcmp(string,"y")==0) return 0x3f80;
if(strcmp(string,"xscale")==0) return 0x4000;
if(strcmp(string,"yscale")==0) return 0x4040;
if(strcmp(string,"alpha")==0) return 0x40c0;
if(strcmp(string,"visible")==0) return 0x40e0;
if(strcmp(string,"rotation")==0) return 0x4120;
if(strcmp(string,"name")==0) return 0x4140;
if(strcmp(string,"quality")==0) return 0x4180;
if(strcmp(string,"focusrect")==0) return 0x4188;
if(strcmp(string,"soundbuftime")==0) return 0x4190;
SWF_error("No such property: %s\n", string);
return -1;
}
int bufferWriteSetProperty(Buffer out, char *string)
{
int property = lookupSetProperty(string);
bufferWriteU8(out, SWFACTION_PUSHDATA);
bufferWriteS16(out, 5);
bufferWriteU8(out, PUSH_PROPERTY);
bufferWriteS16(out, 0);
bufferWriteS16(out, property);
return 8;
}
int bufferWriteWTHITProperty(Buffer out)
{
bufferWriteU8(out, SWFACTION_PUSHDATA);
bufferWriteS16(out, 5);
bufferWriteU8(out, PUSH_PROPERTY);
bufferWriteS16(out, 0);
bufferWriteS16(out, 0x4680);
return 8;
}
const char *lookupGetProperty(char *string)
{
lower(string);
if(strcmp(string,"x")==0) return "0";
if(strcmp(string,"y")==0) return "1";
if(strcmp(string,"xscale")==0) return "2";
if(strcmp(string,"yscale")==0) return "3";
if(strcmp(string,"currentframe")==0) return "4";
if(strcmp(string,"totalframes")==0) return "5";
if(strcmp(string,"alpha")==0) return "6";
if(strcmp(string,"visible")==0) return "7";
if(strcmp(string,"width")==0) return "8";
if(strcmp(string,"height")==0) return "9";
if(strcmp(string,"rotation")==0) return "10";
if(strcmp(string,"target")==0) return "11";
if(strcmp(string,"framesloaded")==0) return "12";
if(strcmp(string,"name")==0) return "13";
if(strcmp(string,"droptarget")==0) return "14";
if(strcmp(string,"url")==0) return "15";
if(strcmp(string,"quality")==0) return "16";
if(strcmp(string,"focusrect")==0) return "17";
if(strcmp(string,"soundbuftime")==0) return "18";
SWF_error("No such property: %s\n", string);
return "";
}
int bufferWriteGetProperty(Buffer out, char *string)
{
const char *property = lookupGetProperty(string);
bufferWriteU8(out, SWFACTION_PUSHDATA);
bufferWriteS16(out, strlen(property)+2);
bufferWriteU8(out, PUSH_STRING);
return 4 + bufferWriteData(out, (byte*) property, strlen(property)+1);
}
/*
* Local variables:
* tab-width: 2
* c-basic-offset: 2
* End:
*/