/* 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 #endif #include #include #include #include #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 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; ibuffer = (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; ibuffer, 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; ipushloc && (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; ipushloc == 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: */