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);