2 Ming, an SWF output library
3 Copyright (C) 2002 Opaque Industries - http://www.opaque.net/
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "blocks/error.h"
35 static int nConstants = {0}, maxConstants = {0}, sizeConstants = {0};
36 static char **constants;
38 /* XXX - temp hack until we check at compile time */
54 p = (unsigned char *)&x;
57 byteorder = SWF_BIG_ENDIAN;
59 byteorder = SWF_LITTLE_ENDIAN;
63 char *stringConcat(char *a, char *b)
69 a = (char*)realloc(a, strlen(a)+strlen(b)+1);
80 void bufferPatchLength(Buffer buffer, int back)
82 unsigned char *output = buffer->buffer;
83 int len = bufferLength(buffer);
85 output[len-back-1] = (back>>8) & 0xff;
86 output[len-back-2] = back & 0xff;
90 /* add len more bytes to length of the pushdata opcode pointed to by
93 void bufferPatchPushLength(Buffer buffer, int len)
97 if(buffer->pushloc != NULL)
99 oldsize = (buffer->pushloc[0] & 0xff) | ((buffer->pushloc[1] & 0xff) << 8);
101 buffer->pushloc[0] = oldsize & 0xff;
102 buffer->pushloc[1] = (oldsize >> 8) & 0xff;
105 SWF_error("problem with bufferPatchPushLength\n");
109 static int useConstants = 1;
110 void Ming_useConstants(int flag)
111 { useConstants = flag;
115 int addConstant(const char *s)
119 for(i=0; i<nConstants; ++i)
121 if(strcmp(s, constants[i]) == 0)
125 /* Don't let constant pool biggern then allowed */
126 if ( sizeConstants+strlen(s)+1 > MAXCONSTANTPOOLSIZE ) return -1;
128 if(nConstants == maxConstants)
129 constants = (char **) realloc(constants, (maxConstants += 64) * sizeof(char *));
130 constants[nConstants] = strdup(s);
131 sizeConstants += (strlen(s)+1);
135 int bufferWriteConstants(Buffer out)
142 bufferWriteU8(out, SWFACTION_CONSTANTPOOL);
143 bufferWriteS16(out, 0); /* length */
144 bufferWriteS16(out, nConstants);
146 for(i=0; i<nConstants; ++i)
148 len += bufferWriteHardString(out,(byte*) constants[i], strlen(constants[i])+1);
154 bufferPatchLength(out, len);
161 Buffer out = (Buffer)malloc(BUFFER_SIZE);
162 memset(out, 0, BUFFER_SIZE);
164 out->buffer = (byte*)malloc(BUFFER_INCREMENT);
165 out->pos = out->buffer;
167 out->buffersize = out->free = BUFFER_INCREMENT;
173 void destroyBuffer(Buffer out)
179 int bufferLength(Buffer out)
182 return (out->pos)-(out->buffer);
187 /* make sure there's enough space for bytes bytes */
188 void bufferCheckSize(Buffer out, int bytes)
190 if(bytes > out->free)
192 int New = BUFFER_INCREMENT * ((bytes-out->free-1)/BUFFER_INCREMENT + 1);
194 int num = bufferLength(out); /* in case buffer gets displaced.. */
195 unsigned char *newbuf = (unsigned char*)realloc(out->buffer, out->buffersize+New);
197 if(newbuf != out->buffer)
202 pushd = out->pos - out->pushloc;
204 out->pos = newbuf+num;
207 out->pushloc = out->pos - pushd;
210 out->buffer = newbuf;
211 out->buffersize += New;
216 int bufferWriteData(Buffer b, const byte *data, int length)
220 bufferCheckSize(b, length);
222 for(i=0; i<length; ++i)
223 bufferWriteU8(b, data[i]);
228 int bufferWriteBuffer(Buffer a, Buffer b)
234 return bufferWriteData(a, b->buffer, bufferLength(b));
239 /* if a's last op and b's first op are both PUSHDATA, concat into one op */
241 int bufferWriteDataAndPush(Buffer a, Buffer b)
245 byte *data = b->buffer;
246 int length = b->pos - b->buffer;
248 if(a->pushloc && (b->buffer[0] == SWFACTION_PUSHDATA) && SWF_versionNum > 4)
250 pushd = (b->buffer[1] & 0xff) | ((b->buffer[2] & 0xff) << 8);
251 bufferPatchPushLength(a, pushd);
257 pushd = b->pos - b->pushloc;
259 bufferCheckSize(a, length);
261 for(i=0; i<length; ++i)
262 bufferWriteU8(a, data[i]);
265 (b->buffer[0] == SWFACTION_PUSHDATA) && (b->pushloc == b->buffer+1))
266 ; /* b is just one pushdata, so do nothing.. */
268 a->pushloc = a->pos - pushd;
275 int bufferConcat(Buffer a, Buffer b)
283 { len = bufferWriteDataAndPush(a, b);
290 int bufferWriteOp(Buffer out, int data)
292 bufferWriteU8(out, data);
298 int bufferWritePushOp(Buffer out)
300 bufferWriteU8(out, SWFACTION_PUSHDATA);
301 out->pushloc = out->pos;
306 int bufferWriteU8(Buffer out, int data)
308 bufferCheckSize(out, 1);
316 int bufferWriteS16(Buffer out, int data)
321 bufferWriteU8(out, data%256);
323 bufferWriteU8(out, data%256);
328 int bufferWriteHardString(Buffer out, byte *string, int length)
332 for(i=0; i<length; ++i)
333 bufferWriteU8(out, string[i]);
338 int bufferWriteConstantString(Buffer out, byte *string, int length)
342 if(SWF_versionNum < 5)
346 n = addConstant((char*) string);
352 bufferWriteU8(out, PUSH_STRING);
353 return bufferWriteHardString(out, string, length) + 1;
357 bufferWriteU8(out, PUSH_CONSTANT);
358 return bufferWriteU8(out, n) + 1;
362 bufferWriteU8(out, PUSH_CONSTANT16);
363 return bufferWriteS16(out, n) + 1;
367 int bufferWriteString(Buffer out, byte *string, int length)
369 if(SWF_versionNum < 5)
371 bufferWritePushOp(out);
372 bufferWriteS16(out, length+1);
373 bufferWriteU8(out, PUSH_STRING);
374 bufferWriteHardString(out, string, length);
382 if(out->pushloc == NULL)
384 bufferWritePushOp(out);
385 bufferWriteS16(out, 0);
388 l = bufferWriteConstantString(out, string, length);
390 bufferPatchPushLength(out, l);
395 int bufferWriteInt(Buffer out, int i)
398 unsigned char *p = (unsigned char *)&i;
400 if(out->pushloc == NULL || SWF_versionNum < 5)
403 bufferWritePushOp(out);
404 bufferWriteS16(out, 5);
407 bufferPatchPushLength(out, 5);
409 bufferWriteU8(out, PUSH_INT);
411 if(byteorder == SWF_LITTLE_ENDIAN)
413 bufferWriteU8(out, p[0]);
414 bufferWriteU8(out, p[1]);
415 bufferWriteU8(out, p[2]);
416 bufferWriteU8(out, p[3]);
420 bufferWriteU8(out, p[3]);
421 bufferWriteU8(out, p[2]);
422 bufferWriteU8(out, p[1]);
423 bufferWriteU8(out, p[0]);
429 int bufferWriteDouble(Buffer out, double d)
432 unsigned char *p = (unsigned char *)&d;
434 if(out->pushloc == NULL || SWF_versionNum < 5)
437 bufferWritePushOp(out);
438 bufferWriteS16(out, 9);
441 bufferPatchPushLength(out, 5);
443 bufferWriteU8(out, PUSH_DOUBLE);
445 if(byteorder == SWF_LITTLE_ENDIAN)
447 bufferWriteU8(out, p[4]);
448 bufferWriteU8(out, p[5]);
449 bufferWriteU8(out, p[6]);
450 bufferWriteU8(out, p[7]);
451 bufferWriteU8(out, p[0]);
452 bufferWriteU8(out, p[1]);
453 bufferWriteU8(out, p[2]);
454 bufferWriteU8(out, p[3]);
458 bufferWriteU8(out, p[3]);
459 bufferWriteU8(out, p[2]);
460 bufferWriteU8(out, p[1]);
461 bufferWriteU8(out, p[0]);
462 bufferWriteU8(out, p[7]);
463 bufferWriteU8(out, p[6]);
464 bufferWriteU8(out, p[5]);
465 bufferWriteU8(out, p[4]);
471 int bufferWriteNull(Buffer out)
475 if(out->pushloc == NULL || SWF_versionNum < 5)
478 bufferWritePushOp(out);
479 bufferWriteS16(out, 1);
482 bufferPatchPushLength(out, 1);
484 bufferWriteU8(out, PUSH_NULL);
489 int bufferWriteBoolean(Buffer out, int val)
493 if(out->pushloc == NULL || SWF_versionNum < 5)
496 bufferWritePushOp(out);
497 bufferWriteS16(out, 2);
500 bufferPatchPushLength(out, 2);
502 bufferWriteU8(out, PUSH_BOOLEAN);
503 bufferWriteU8(out, val ? 1 : 0);
508 int bufferWriteRegister(Buffer out, int num)
512 if(out->pushloc == NULL || SWF_versionNum < 5)
515 bufferWritePushOp(out);
516 bufferWriteS16(out, 2);
519 bufferPatchPushLength(out, 2);
521 bufferWriteU8(out, PUSH_REGISTER);
522 bufferWriteU8(out, num);
527 int bufferWriteSetRegister(Buffer out, int num)
529 bufferWriteU8(out, SWFACTION_SETREGISTER);
530 bufferWriteS16(out, 1);
531 bufferWriteU8(out, num);
544 /* this code will eventually help to pop extra values off the
545 stack and make sure that continue and break address the proper
548 static enum ctx *ctx_stack = {0};
549 static int ctx_count = {0}, ctx_len = {0};
550 void addctx(enum ctx val)
551 { if(ctx_count >= ctx_len)
552 ctx_stack = (enum ctx*) realloc(ctx_stack, (ctx_len += 10) * sizeof(enum ctx));
553 ctx_stack[ctx_count++] = val;
555 void delctx(enum ctx val)
556 { if(ctx_count <= 0 || ctx_stack[--ctx_count] != val)
557 SWF_error("consistency check in delctx");
560 int chkctx(enum ctx val)
564 for(n = ctx_count ; --n >= 0 ; )
572 default: ; /* computers are stupid */
576 for(n = ctx_count ; --n >= 0 ; )
585 default: ; /* computers are stupid */
588 for(n = ctx_count ; --n >= 0 ; )
595 default: ; /* computers are stupid */
597 default: ; /* computers are stupid */
602 /* replace MAGIC_CONTINUE_NUMBER and MAGIC_BREAK_NUMBER with jumps to
603 head or tail, respectively */
604 /* jump offset is relative to end of jump instruction */
605 /* I can't believe this actually worked */
607 void bufferResolveJumps(Buffer out)
609 byte *p = out->buffer;
614 if(*p & 0x80) /* then it's a multibyte instruction */
616 if(*p == SWFACTION_BRANCHALWAYS)
618 p += 3; /* plus instruction plus two-byte length */
620 if(*p == MAGIC_CONTINUE_NUMBER_LO &&
621 *(p+1) == MAGIC_CONTINUE_NUMBER_HI)
623 target = out->buffer - (p+2);
625 *(p+1) = (target>>8) & 0xff;
627 else if(*p == MAGIC_BREAK_NUMBER_LO &&
628 *(p+1) == MAGIC_BREAK_NUMBER_HI)
630 target = out->pos - (p+2);
632 *(p+1) = (target>>8) & 0xff;
653 // handle SWITCH statement
655 void bufferResolveSwitch(Buffer buffer, struct switchcases *slp)
656 { struct switchcase *scp;
658 unsigned char *output;
660 len = bufferLength(buffer);
661 for(n = 0, scp = slp->list ; n < slp->count ; n++, scp++)
662 { scp->actlen = bufferLength(scp->action);
663 if((n < slp->count-1))
666 { scp->condlen = bufferLength(scp->cond) + 8;
667 bufferWriteOp(buffer, SWFACTION_DUP);
668 bufferConcat(buffer, scp->cond);
669 bufferWriteOp(buffer, SWFACTION_NEWEQUALS);
670 bufferWriteOp(buffer, SWFACTION_LOGICALNOT);
671 bufferWriteOp(buffer, SWFACTION_BRANCHIFTRUE);
672 bufferWriteS16(buffer, 2);
673 bufferWriteS16(buffer, scp->actlen);
677 bufferConcat(buffer, scp->action);
678 bufferWriteOp(buffer, SWFACTION_BRANCHALWAYS);
679 bufferWriteS16(buffer, 2);
680 bufferWriteS16(buffer, scp->isbreak ? MAGIC_BREAK_NUMBER : 0);
686 for(n = 0, scp = slp->list ; n < slp->count ; n++, scp++)
687 { len += scp->condlen;
688 output = buffer->buffer + len;
689 if((n < slp->count-1) && !scp->isbreak)
690 { output[scp->actlen-2] = (scp+1)->condlen & 0xff;
691 output[scp->actlen-1] = (scp+1)->condlen >> 8;
697 int lookupSetProperty(char *string)
701 if(strcmp(string,"x")==0) return 0x0000;
702 if(strcmp(string,"y")==0) return 0x3f80;
703 if(strcmp(string,"xscale")==0) return 0x4000;
704 if(strcmp(string,"yscale")==0) return 0x4040;
705 if(strcmp(string,"alpha")==0) return 0x40c0;
706 if(strcmp(string,"visible")==0) return 0x40e0;
707 if(strcmp(string,"rotation")==0) return 0x4120;
708 if(strcmp(string,"name")==0) return 0x4140;
709 if(strcmp(string,"quality")==0) return 0x4180;
710 if(strcmp(string,"focusrect")==0) return 0x4188;
711 if(strcmp(string,"soundbuftime")==0) return 0x4190;
713 SWF_error("No such property: %s\n", string);
717 int bufferWriteSetProperty(Buffer out, char *string)
719 int property = lookupSetProperty(string);
721 bufferWriteU8(out, SWFACTION_PUSHDATA);
722 bufferWriteS16(out, 5);
723 bufferWriteU8(out, PUSH_PROPERTY);
724 bufferWriteS16(out, 0);
725 bufferWriteS16(out, property);
730 int bufferWriteWTHITProperty(Buffer out)
732 bufferWriteU8(out, SWFACTION_PUSHDATA);
733 bufferWriteS16(out, 5);
734 bufferWriteU8(out, PUSH_PROPERTY);
735 bufferWriteS16(out, 0);
736 bufferWriteS16(out, 0x4680);
741 const char *lookupGetProperty(char *string)
745 if(strcmp(string,"x")==0) return "0";
746 if(strcmp(string,"y")==0) return "1";
747 if(strcmp(string,"xscale")==0) return "2";
748 if(strcmp(string,"yscale")==0) return "3";
749 if(strcmp(string,"currentframe")==0) return "4";
750 if(strcmp(string,"totalframes")==0) return "5";
751 if(strcmp(string,"alpha")==0) return "6";
752 if(strcmp(string,"visible")==0) return "7";
753 if(strcmp(string,"width")==0) return "8";
754 if(strcmp(string,"height")==0) return "9";
755 if(strcmp(string,"rotation")==0) return "10";
756 if(strcmp(string,"target")==0) return "11";
757 if(strcmp(string,"framesloaded")==0) return "12";
758 if(strcmp(string,"name")==0) return "13";
759 if(strcmp(string,"droptarget")==0) return "14";
760 if(strcmp(string,"url")==0) return "15";
761 if(strcmp(string,"quality")==0) return "16";
762 if(strcmp(string,"focusrect")==0) return "17";
763 if(strcmp(string,"soundbuftime")==0) return "18";
765 SWF_error("No such property: %s\n", string);
769 int bufferWriteGetProperty(Buffer out, char *string)
771 const char *property = lookupGetProperty(string);
773 bufferWriteU8(out, SWFACTION_PUSHDATA);
774 bufferWriteS16(out, strlen(property)+2);
775 bufferWriteU8(out, PUSH_STRING);
777 return 4 + bufferWriteData(out, (byte*) property, strlen(property)+1);