1 /*
2     Ming, an SWF output library
3     Copyright (C) 2002  Opaque Industries - http://www.opaque.net/
4 
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.
9 
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.
14 
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
18 */
19 
20 #ifndef WIN32
21 	#include <unistd.h>
22 #endif
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <ctype.h>
27 #include <string.h>
28 
29 #include "libming.h"
30 #include "compile.h"
31 #include "actiontypes.h"
32 #include "blocks/error.h"
33 
34 /* Define this to have some debugging output when outputting DEFINEFUNCTION2 */
35 #undef MING_DEBUG_FUNCTION2
36 
37 // XXX: set by swf[4|5]Init()
38 int swfVersion = 0;
39 
40 static int nConstants = {0}, maxConstants = {0}, sizeConstants = {0};
41 static char **constants = NULL;
42 
stringConcat(char * a,char * b)43 char *stringConcat(char *a, char *b)
44 {
45 	if ( a != NULL )
46 	{
47 		if ( b != NULL )
48 		{
49 			a = (char*)realloc(a, strlen(a)+strlen(b)+1);
50 			if(a == NULL)
51 				return NULL;
52 			strcat(a, b);
53 			free(b);
54 		}
55 
56 		return a;
57 	}
58 	else
59 		return b;
60 }
61 
bufferPatchLength(Buffer buffer,int back)62 void bufferPatchLength(Buffer buffer, int back)
63 {
64 	unsigned char *output = buffer->buffer;
65 	int len = bufferLength(buffer);
66 
67 	output[len-back-1] = (back>>8) & 0xff;
68 	output[len-back-2] = back & 0xff;
69 }
70 
71 
72 /* add len more bytes to length of the pushdata opcode pointed to by
73 	 buffer->pushloc */
74 
bufferPatchPushLength(Buffer buffer,int len)75 void bufferPatchPushLength(Buffer buffer, int len)
76 {
77 	int oldsize;
78 
79 	if(buffer->pushloc != NULL)
80 	{
81 		oldsize = (buffer->pushloc[0] & 0xff) | ((buffer->pushloc[1] & 0xff) << 8);
82 		oldsize += len;
83 		buffer->pushloc[0] = oldsize & 0xff;
84 		buffer->pushloc[1] = (oldsize >> 8) & 0xff;
85 	}
86 	else
87 		SWF_error("problem with bufferPatchPushLength\n");
88 }
89 
90 
91 static int useConstants = 1;
Ming_useConstants(int flag)92 void Ming_useConstants(int flag)
93 {	useConstants = flag;
94 }
95 
96 
addConstant(const char * s)97 int addConstant(const char *s)
98 {
99 	int i;
100 
101 	for(i=0; i<nConstants; ++i)
102 	{
103 		if(strcmp(s, constants[i]) == 0)
104 			return i;
105 	}
106 
107 	/* Don't let constant pool biggern then allowed */
108 	if ( sizeConstants+strlen(s)+1 > MAXCONSTANTPOOLSIZE ) return -1;
109 
110 	if(nConstants == maxConstants)
111 		constants = (char **) realloc(constants, (maxConstants += 64) * sizeof(char *));
112 	constants[nConstants] = strdup(s);
113 	sizeConstants += (strlen(s)+1);
114 	return nConstants++;
115 }
116 
bufferWriteConstants(Buffer out)117 int bufferWriteConstants(Buffer out)
118 {
119 	int i, len=2;
120 
121 	if(nConstants == 0)
122 		return 0;
123 
124 	bufferWriteU8(out, SWFACTION_CONSTANTPOOL);
125 	bufferWriteS16(out, 0); /* length */
126 	bufferWriteS16(out, nConstants);
127 
128 	for(i=0; i<nConstants; ++i)
129 	{
130 		len += bufferWriteHardString(out, constants[i], strlen(constants[i])+1);
131 		free(constants[i]);
132 	}
133 
134 	nConstants = 0;
135 	sizeConstants = 0;
136 	bufferPatchLength(out, len);
137 
138 	return len+3;
139 }
140 
newBuffer()141 Buffer newBuffer()
142 {
143 	Buffer out = (Buffer)malloc(BUFFER_SIZE);
144 	if(out == NULL)
145 		return NULL;
146 	memset(out, 0, BUFFER_SIZE);
147 
148 	out->buffer = (byte*)malloc(BUFFER_INCREMENT);
149 	out->pos = out->buffer;
150 	*(out->pos) = 0;
151 	out->buffersize = out->free = BUFFER_INCREMENT;
152 	out->pushloc = NULL;
153 	out->hasObject = 0;
154 
155 	return out;
156 }
157 
destroyBuffer(Buffer out)158 void destroyBuffer(Buffer out)
159 {
160 	free(out->buffer);
161 	free(out);
162 }
163 
bufferLength(Buffer out)164 int bufferLength(Buffer out)
165 {
166 	if(out)
167 		return (out->pos)-(out->buffer);
168 	else
169 		return 0;
170 }
171 
172 /* make sure there's enough space for bytes bytes */
bufferCheckSize(Buffer out,int bytes)173 void bufferCheckSize(Buffer out, int bytes)
174 {
175 	if(bytes > out->free)
176 	{
177 		int New = BUFFER_INCREMENT * ((bytes-out->free-1)/BUFFER_INCREMENT + 1);
178 
179 		int num = bufferLength(out); /* in case buffer gets displaced.. */
180 		unsigned char *newbuf = (unsigned char*)realloc(out->buffer, out->buffersize+New);
181 
182 		if(newbuf != out->buffer)
183 		{
184 			int pushd = 0;
185 
186 			if(out->pushloc)
187 	pushd = out->pos - out->pushloc;
188 
189 			out->pos = newbuf+num;
190 
191 			if(out->pushloc)
192 	out->pushloc = out->pos - pushd;
193 		}
194 
195 		out->buffer = newbuf;
196 		out->buffersize += New;
197 		out->free += New;
198 	}
199 }
200 
bufferWriteData(Buffer b,const byte * data,int length)201 int bufferWriteData(Buffer b, const byte *data, int length)
202 {
203 	int i;
204 
205 	bufferCheckSize(b, length);
206 
207 	for(i=0; i<length; ++i)
208 		bufferWriteU8(b, data[i]);
209 
210 	return length;
211 }
212 
bufferWriteBuffer(Buffer a,Buffer b)213 int bufferWriteBuffer(Buffer a, Buffer b)
214 {
215 	if(!a)
216 		return 0;
217 
218 	if(b)
219 		return bufferWriteData(a, b->buffer, bufferLength(b));
220 
221 	return 0;
222 }
223 
224 /* if a's last op and b's first op are both PUSH, concat into one op */
225 
bufferWriteDataAndPush(Buffer a,Buffer b)226 int bufferWriteDataAndPush(Buffer a, Buffer b)
227 {
228 	int i, pushd = 0;
229 
230 	byte *data = b->buffer;
231 	int length = b->pos - b->buffer;
232 
233 	if(a->pushloc && (b->buffer[0] == SWFACTION_PUSH) && swfVersion > 4)
234 	{
235 		pushd = (b->buffer[1] & 0xff) | ((b->buffer[2] & 0xff) << 8);
236 		bufferPatchPushLength(a, pushd);
237 		data += 3;
238 		length -= 3;
239 	}
240 
241 	if(b->pushloc)
242 		pushd = b->pos - b->pushloc;
243 
244 	bufferCheckSize(a, length);
245 
246 	for(i=0; i<length; ++i)
247 		bufferWriteU8(a, data[i]);
248 
249 	if(a->pushloc &&
250 		 (b->buffer[0] == SWFACTION_PUSH) && (b->pushloc == b->buffer+1))
251 		; /* b is just one pushdata, so do nothing.. */
252 	else if(b->pushloc)
253 		a->pushloc = a->pos - pushd;
254 	else
255 		a->pushloc = 0;
256 
257 	return length;
258 }
259 
bufferConcatSimple(Buffer a,Buffer b)260 int bufferConcatSimple(Buffer a, Buffer b)
261 {
262 	int len = 0;
263 
264 	if(!a)
265 		return 0;
266 
267 	if(b)
268 	{	len = bufferWriteBuffer(a, b);
269 		destroyBuffer(b);
270 	}
271 
272 	return len;
273 }
274 
bufferConcat(Buffer a,Buffer b)275 int bufferConcat(Buffer a, Buffer b)
276 {
277 	int len = 0;
278 
279 	if(!a)
280 		return 0;
281 
282 	if(b)
283 	{	len = bufferWriteDataAndPush(a, b);
284 		destroyBuffer(b);
285 	}
286 
287 	return len;
288 }
289 
bufferWriteOp(Buffer out,int data)290 int bufferWriteOp(Buffer out, int data)
291 {
292 	bufferWriteU8(out, data);
293 	out->pushloc = NULL;
294 
295 	return 1;
296 }
297 
bufferWritePushOp(Buffer out)298 int bufferWritePushOp(Buffer out)
299 {
300 	bufferWriteU8(out, SWFACTION_PUSH);
301 	out->pushloc = out->pos;
302 
303 	return 1;
304 }
305 
bufferWriteU8(Buffer out,int data)306 int bufferWriteU8(Buffer out, int data)
307 {
308 	bufferCheckSize(out, 1);
309 	*(out->pos) = data;
310 	out->pos++;
311 	out->free--;
312 
313 	return 1;
314 }
315 
bufferWriteS16(Buffer out,int data)316 int bufferWriteS16(Buffer out, int data)
317 {
318 	if(data < 0)
319 		data = (1<<16)+data;
320 
321 	bufferWriteU8(out, data%256);
322 	data >>= 8;
323 	bufferWriteU8(out, data%256);
324 
325 	return 2;
326 }
327 
bufferWriteHardString(Buffer out,const char * string,int length)328 int bufferWriteHardString(Buffer out, const char *string, int length)
329 {
330 	int i;
331 
332 	for(i=0; i<length; ++i)
333 		bufferWriteU8(out, (byte)string[i]);
334 
335 	return length;
336 }
337 
bufferWriteConstantString(Buffer out,const char * string,int length)338 int bufferWriteConstantString(Buffer out, const char *string, int length)
339 {
340 	int n;
341 
342 	if(swfVersion < 5)
343 		return -1;
344 
345 	if(useConstants)
346 		n = addConstant((char*) string);
347 	else
348 		n = -1;
349 
350 	if(n == -1)
351 	{
352 		bufferWriteU8(out, PUSH_STRING);
353 		return bufferWriteHardString(out, string, length) + 1;
354 	}
355 	else if(n < 256)
356 	{
357 		bufferWriteU8(out, PUSH_CONSTANT);
358 		return bufferWriteU8(out, n) + 1;
359 	}
360 	else
361 	{
362 		bufferWriteU8(out, PUSH_CONSTANT16);
363 		return bufferWriteS16(out, n) + 1;
364 	}
365 }
366 
367 /* allow pushing STRINGs for SWF>=5 */
bufferWritePushString(Buffer out,char * string,int length)368 int bufferWritePushString(Buffer out, char *string, int length)
369 {
370 	int l, len = 0;
371 	if(out->pushloc == NULL || swfVersion < 5)
372 	{
373 		len = 3;
374 		bufferWritePushOp(out);
375 		bufferWriteS16(out, length+1);
376 	}
377 
378 	bufferWriteU8(out, PUSH_STRING);
379 	l = bufferWriteHardString(out, string, length);
380 	bufferPatchPushLength(out, l + 1);
381 	return len + l + 1;
382 }
383 
bufferWriteString(Buffer out,const char * string,int length)384 int bufferWriteString(Buffer out, const char *string, int length)
385 {
386 	if(swfVersion < 5)
387 	{
388 		bufferWritePushOp(out);
389 		bufferWriteS16(out, length+1);
390 		bufferWriteU8(out, PUSH_STRING);
391 		bufferWriteHardString(out, string, length);
392 
393 		return 4 + length;
394 	}
395 	else
396 	{
397 		int l;
398 
399 		if(out->pushloc == NULL)
400 		{
401 			bufferWritePushOp(out);
402 			bufferWriteS16(out, 0);
403 		}
404 
405 		l = bufferWriteConstantString(out, string, length);
406 
407 		bufferPatchPushLength(out, l);
408 		return l;
409 	}
410 }
411 
bufferWriteInt(Buffer out,int i)412 int bufferWriteInt(Buffer out, int i)
413 {
414 	int len = 0;
415 	unsigned char *p = (unsigned char *)&i;
416 
417 	if(out->pushloc == NULL || swfVersion < 5)
418 	{
419 		len = 3;
420 		bufferWritePushOp(out);
421 		bufferWriteS16(out, 5);
422 	}
423 	else
424 		bufferPatchPushLength(out, 5);
425 
426 	bufferWriteU8(out, PUSH_INT);
427 
428 #if SWF_LITTLE_ENDIAN
429 	bufferWriteU8(out, p[0]);
430 	bufferWriteU8(out, p[1]);
431 	bufferWriteU8(out, p[2]);
432 	bufferWriteU8(out, p[3]);
433 #else
434 	bufferWriteU8(out, p[3]);
435 	bufferWriteU8(out, p[2]);
436 	bufferWriteU8(out, p[1]);
437 	bufferWriteU8(out, p[0]);
438 #endif
439 
440 	return len + 5;
441 }
442 
bufferWriteFloat(Buffer out,float f)443 int bufferWriteFloat(Buffer out, float f)
444 {
445 	int len = 0;
446 	unsigned char *p = (unsigned char *)&f;
447 
448 	if(out->pushloc == NULL || swfVersion < 5)
449 	{
450 		len = 3;
451 		bufferWritePushOp(out);
452 		bufferWriteS16(out, 5);
453 	}
454 	else
455 		bufferPatchPushLength(out, 5);
456 
457 	bufferWriteU8(out, PUSH_FLOAT);
458 
459 #if SWF_LITTLE_ENDIAN
460 	bufferWriteU8(out, p[0]);
461 	bufferWriteU8(out, p[1]);
462 	bufferWriteU8(out, p[2]);
463 	bufferWriteU8(out, p[3]);
464 #else
465 	bufferWriteU8(out, p[3]);
466 	bufferWriteU8(out, p[2]);
467 	bufferWriteU8(out, p[1]);
468 	bufferWriteU8(out, p[0]);
469 #endif
470 	return len + 5;
471 }
472 
bufferWriteDouble(Buffer out,double d)473 int bufferWriteDouble(Buffer out, double d)
474 {
475 	int len = 0;
476 	unsigned char *p = (unsigned char *)&d;
477 
478 	if(out->pushloc == NULL || swfVersion < 5)
479 	{
480 		len = 3;
481 		bufferWritePushOp(out);
482 		bufferWriteS16(out, 9);
483 	}
484 	else
485 		bufferPatchPushLength(out, 5);
486 
487 	bufferWriteU8(out, PUSH_DOUBLE);
488 
489 #if SWF_LITTLE_ENDIAN
490 	bufferWriteU8(out, p[4]);
491 	bufferWriteU8(out, p[5]);
492 	bufferWriteU8(out, p[6]);
493 	bufferWriteU8(out, p[7]);
494 	bufferWriteU8(out, p[0]);
495 	bufferWriteU8(out, p[1]);
496 	bufferWriteU8(out, p[2]);
497 	bufferWriteU8(out, p[3]);
498 #else
499 	bufferWriteU8(out, p[3]);
500 	bufferWriteU8(out, p[2]);
501 	bufferWriteU8(out, p[1]);
502 	bufferWriteU8(out, p[0]);
503 	bufferWriteU8(out, p[7]);
504 	bufferWriteU8(out, p[6]);
505 	bufferWriteU8(out, p[5]);
506 	bufferWriteU8(out, p[4]);
507 #endif
508 
509 	return len + 9;
510 }
511 
bufferWriteNull(Buffer out)512 int bufferWriteNull(Buffer out)
513 {
514 	int len = 0;
515 
516 	if(out->pushloc == NULL || swfVersion < 5)
517 	{
518 		len = 3;
519 		bufferWritePushOp(out);
520 		bufferWriteS16(out, 1);
521 	}
522 	else
523 		bufferPatchPushLength(out, 1);
524 
525 	bufferWriteU8(out, PUSH_NULL);
526 
527 	return len + 1;
528 }
529 
bufferWriteUndef(Buffer out)530 int bufferWriteUndef(Buffer out)
531 {
532 	int len = 0;
533 
534 	if(out->pushloc == NULL || swfVersion < 5)
535 	{
536 		len = 3;
537 		bufferWritePushOp(out);
538 		bufferWriteS16(out, 1);
539 	}
540 	else
541 		bufferPatchPushLength(out, 1);
542 
543 	bufferWriteU8(out, PUSH_UNDEF);
544 
545 	return len + 1;
546 }
547 
bufferWriteBoolean(Buffer out,int val)548 int bufferWriteBoolean(Buffer out, int val)
549 {
550 	int len = 0;
551 
552 	if(out->pushloc == NULL || swfVersion < 5)
553 	{
554 		len = 3;
555 		bufferWritePushOp(out);
556 		bufferWriteS16(out, 2);
557 	}
558 	else
559 		bufferPatchPushLength(out, 2);
560 
561 	bufferWriteU8(out, PUSH_BOOLEAN);
562 	bufferWriteU8(out, val ? 1 : 0);
563 
564 	return len + 2;
565 }
566 
bufferWriteRegister(Buffer out,int num)567 int bufferWriteRegister(Buffer out, int num)
568 {
569 	int len = 0;
570 
571 	if(out->pushloc == NULL || swfVersion < 5)
572 	{
573 		len = 3;
574 		bufferWritePushOp(out);
575 		bufferWriteS16(out, 2);
576 	}
577 	else
578 		bufferPatchPushLength(out, 2);
579 
580 	bufferWriteU8(out, PUSH_REGISTER);
581 	bufferWriteU8(out, num);
582 
583 	return len + 2;
584 }
585 
bufferWriteSetRegister(Buffer out,int num)586 int bufferWriteSetRegister(Buffer out, int num)
587 {
588 	bufferWriteU8(out, SWFACTION_STOREREGISTER);
589 	bufferWriteS16(out, 1);
590 	bufferWriteU8(out, num);
591 	return 4;
592 }
593 
lower(char * s)594 void lower(char *s)
595 {
596 	while(*s)
597 	{
598 		*s = tolower(*s);
599 		++s;
600 	}
601 }
602 
603 /* this code will eventually help to pop extra values off the
604  stack and make sure that continue and break address the proper
605  context
606  */
607 static enum ctx *ctx_stack = {0};
608 static int ctx_count = {0}, ctx_len = {0};
addctx(enum ctx val)609 void addctx(enum ctx val)
610 {
611 	if(ctx_count >= ctx_len)
612 		ctx_stack = (enum ctx*) realloc(ctx_stack, (ctx_len += 10) * sizeof(enum ctx));
613 	ctx_stack[ctx_count++] = val;
614 }
delctx(enum ctx val)615 void delctx(enum ctx val)
616 {
617 	if(ctx_count <= 0)
618 		SWF_error("consistency check in delctx: stack empty!\n");
619 	else if (ctx_stack[--ctx_count] != val)
620 		SWF_error("consistency check in delctx: val %i != %i\n", ctx_stack[ctx_count], val);
621 
622 }
623 
chkctx(enum ctx val)624 int chkctx(enum ctx val)
625 {	int n, ret = 0;
626 	switch(val)
627 	{	case CTX_FUNCTION:
628 			for(n = ctx_count ; --n >= 0 ; )
629 				switch(ctx_stack[n])
630 				{	case CTX_SWITCH:
631 					case CTX_FOR_IN:
632 						ret++;
633 						break;
634 					case CTX_FUNCTION:
635 						return ret;
636 					default: ; /* computers are stupid */
637 				}
638 			return -1;
639 		case CTX_BREAK:
640 			for(n = ctx_count ; --n >= 0 ; )
641 				switch(ctx_stack[n])
642 				{	case CTX_SWITCH:
643 						return CTX_SWITCH;
644 					case CTX_LOOP:
645 						return CTX_LOOP;
646 					case CTX_FOR_IN:
647 						return CTX_FOR_IN;
648 					case CTX_FUNCTION:
649 						return -1;
650 					case CTX_BREAK:
651 						return CTX_BREAK;
652 					default: ; /* computers are stupid */
653 				}
654 			return -1;
655 		case CTX_CONTINUE:
656 			for(n = ctx_count ; --n >= 0 ; )
657 				switch(ctx_stack[n])
658 				{	case CTX_LOOP:
659 					case CTX_FOR_IN:
660 						return 0;
661 					case CTX_FUNCTION:
662 						return -1;
663 					default: ; /* computers are stupid */
664 				}
665 		default: return -1;; /* computers are stupid */
666 	}
667 }
668 
669 /* replace MAGIC_CONTINUE_NUMBER and MAGIC_BREAK_NUMBER with jumps to
670 	 head or tail, respectively */
671 /* jump offset is relative to end of jump instruction */
672 /* I can't believe this actually worked */
673 
bufferResolveJumpsFull(Buffer out,byte * break_ptr,byte * continue_ptr)674 void bufferResolveJumpsFull(Buffer out, byte *break_ptr, byte *continue_ptr)
675 {
676 	byte *p = out->buffer;
677 	int l, target;
678 
679 	while(p < out->pos)
680 	{
681 		if(*p & 0x80) /* then it's a multibyte instruction */
682 		{
683 			if(*p == SWFACTION_JUMP)
684 			{
685 	p += 3; /* plus instruction plus two-byte length */
686 
687 	if(*p == MAGIC_CONTINUE_NUMBER_LO &&
688 		 *(p+1) == MAGIC_CONTINUE_NUMBER_HI)
689 	{
690 		target = continue_ptr - (p+2);
691 		*p = target & 0xff;
692 		*(p+1) = (target>>8) & 0xff;
693 	}
694 	else if(*p == MAGIC_BREAK_NUMBER_LO &&
695 		*(p+1) == MAGIC_BREAK_NUMBER_HI)
696 	{
697 		target = break_ptr - (p+2);
698 		*p = target & 0xff;
699 		*(p+1) = (target>>8) & 0xff;
700 	}
701 
702 	p += 2;
703 			}
704 			else
705 			{
706 	++p;
707 	l = *p;
708 	++p;
709 	l += *p<<8;
710 	++p;
711 
712 	p += l;
713 			}
714 		}
715 		else
716 			++p;
717 	}
718 }
719 
720 // handle SWITCH statement
721 
bufferResolveSwitch(Buffer buffer,struct switchcases * slp)722 void bufferResolveSwitch(Buffer buffer, struct switchcases *slp)
723 {	struct switchcase *scp;
724 	int n, len;
725 	unsigned char *output;
726 
727 	len = bufferLength(buffer);
728 	for(n = 0, scp = slp->list ; n < slp->count ; n++, scp++)
729 	{	scp->actlen = bufferLength(scp->action);
730 		if((n < slp->count-1))
731 			scp->actlen += 5;
732 		if(scp->cond)
733 		{	scp->condlen = bufferLength(scp->cond) + 8;
734 			bufferWriteOp(buffer, SWFACTION_PUSHDUP);
735 			bufferConcat(buffer, scp->cond);
736 			bufferWriteOp(buffer, SWFACTION_EQUALS2);
737 			bufferWriteOp(buffer, SWFACTION_LOGICALNOT);
738 			bufferWriteOp(buffer, SWFACTION_IF);
739 			bufferWriteS16(buffer, 2);
740 			bufferWriteS16(buffer, scp->actlen);
741 		}
742 		else
743 			scp->condlen = 0;
744 		bufferConcat(buffer, scp->action);
745 		bufferWriteOp(buffer, SWFACTION_JUMP);
746 		bufferWriteS16(buffer, 2);
747 		bufferWriteS16(buffer, scp->isbreak ? MAGIC_BREAK_NUMBER : 0);
748 		if(!scp->cond)
749 		{	slp->count = n+1;
750 			break;
751 		}
752 	}
753 	for(n = 0, scp = slp->list ; n < slp->count ; n++, scp++)
754 	{	len += scp->condlen;
755 		output = buffer->buffer + len;
756 		if((n < slp->count-1) && !scp->isbreak)
757 		{	output[scp->actlen-2] = (scp+1)->condlen & 0xff;
758 			output[scp->actlen-1] = (scp+1)->condlen >> 8;
759 		}
760 		len += scp->actlen;
761 	}
762 }
763 
lookupProperty(char * string)764 int lookupProperty(char *string)
765 {
766 	lower(string);
767 
768 	if(strcmp(string, "_x") == 0)		return PROPERTY_X;
769 	if(strcmp(string, "_y") == 0)		return PROPERTY_Y;
770 	if(strcmp(string, "_xscale") == 0)	return PROPERTY_XSCALE;
771 	if(strcmp(string, "_yscale") == 0)	return PROPERTY_YSCALE;
772 	if(strcmp(string, "_currentframe") == 0) return PROPERTY_CURRENTFRAME;
773 	if(strcmp(string, "_totalframes") == 0)	return PROPERTY_TOTALFRAMES;
774 	if(strcmp(string, "_alpha") == 0)	return PROPERTY_ALPHA;
775 	if(strcmp(string, "_visible") == 0)	return PROPERTY_VISIBLE;
776 	if(strcmp(string, "_width") == 0)	return PROPERTY_WIDTH;
777 	if(strcmp(string, "_height") == 0)	return PROPERTY_HEIGHT;
778 	if(strcmp(string, "_rotation") == 0)	return PROPERTY_ROTATION;
779 	if(strcmp(string, "_target") == 0)	return PROPERTY_TARGET;
780 	if(strcmp(string, "_framesloaded") == 0)	return PROPERTY_FRAMESLOADED;
781 	if(strcmp(string, "_name") == 0)		return PROPERTY_NAME;
782 	if(strcmp(string, "_droptarget") == 0)	return PROPERTY_DROPTARGET;
783 	if(strcmp(string, "_url") == 0)		return PROPERTY_URL;
784 	if(strcmp(string, "_highquality") == 0)	return PROPERTY_HIGHQUALITY;
785 	if(strcmp(string, "_focusrect") == 0)	return PROPERTY_FOCUSRECT;
786 	if(strcmp(string, "_soundbuftime") == 0)	return PROPERTY_SOUNDBUFTIME;
787 	if(strcmp(string, "_quality")==0)	return PROPERTY_QUALITY;
788 	if(strcmp(string, "_xmouse") == 0)	return PROPERTY_XMOUSE;
789 	if(strcmp(string, "_ymouse") == 0)	return PROPERTY_YMOUSE;
790 
791 	SWF_error("No such property: %s\n", string);
792 	return -1;
793 }
794 
bufferWriteProperty(Buffer out,char * string)795 int bufferWriteProperty(Buffer out, char *string)
796 {
797 	int property = lookupProperty(string);
798 	return bufferWriteFloat(out, property);
799 }
800 
801 // XXX: ???
bufferWriteWTHITProperty(Buffer out)802 int bufferWriteWTHITProperty(Buffer out)
803 {
804 	bufferWriteU8(out, SWFACTION_PUSH);
805 	bufferWriteS16(out, 5);
806 	bufferWriteU8(out, PUSH_FLOAT);
807 	bufferWriteS16(out, 0);
808 	bufferWriteS16(out, 0x4680);
809 
810 	return 8;
811 }
812 
813 /**
814  * @param func_name
815  * 	Function name, NULL for anonymous functions.
816  *
817  * @param num_regs
818  * 	Number of registers.
819  *
820  * @param flags
821  * 	See SWFDefineFunction2Flags enum.
822  */
bufferWriteDefineFunction2(Buffer out,char * func_name,Buffer args,Buffer code,int flags,int num_regs)823 static int bufferWriteDefineFunction2(Buffer out, char *func_name,
824 		Buffer args, Buffer code, int flags, int num_regs)
825 {
826 	Buffer c;
827 	char buf[1024];
828 	int num_args = 0, i;
829 	char *p = (char *) args->buffer;
830 	size_t taglen;
831 	strcpy(buf, "");
832 
833 	// REGISTERPARAM records
834 	c = newBuffer();
835 	// TODO: rewrite this function, all these calls to strncat
836 	//       seem overkill to me
837 	for(i = 0; i < bufferLength(args); i++)
838 	{
839 		if(p[i] == '\0')
840 		{
841 			bufferWriteU8(c, 0);
842 			bufferWriteHardString(c, buf, strlen(buf)+1);
843 			strcpy(buf, "");
844 			num_args++;
845 		}
846 		else
847 		{
848 			strncat(buf, &p[i], 1);
849 		}
850 	}
851 
852 	bufferWriteOp(out, SWFACTION_DEFINEFUNCTION2);
853 
854 	if(func_name == NULL)
855 	{
856 		taglen =
857 			+ 1			/* function name (empty) */
858 			+ 2			/* arg count (short) */
859 			+ 1			/* reg count (byte) */
860 			+ 2			/* flags */
861 			+ bufferLength(c)	/* swf_params */
862 			+ 2 			/* body size */
863 			;
864 
865 #ifdef MING_DEBUG_FUNCTION2
866 		printf("adding anonymouse SWF_DEFINEFUNCTION2 nargs=%d flags=%d"
867 				" arglen=%d codelen=%d taglen=%d\n",
868 				num_args, flags, bufferLength(args),
869 				bufferLength(code), taglen);
870 #endif
871 		bufferWriteS16(out, taglen);
872 
873 		bufferWriteU8(out, 0); /* empty function name */
874 	}
875 	else
876 	{
877 		taglen = 0
878 			+ strlen(func_name)+1	/* function name */
879 			+ 2			/* arg count (short) */
880 			+ 1			/* reg count (byte) */
881 			+ 2			/* flags */
882 			+ bufferLength(c)	/* swf_params */
883 			+ 2 			/* body size */
884 			;
885 
886 #ifdef MING_DEBUG_FUNCTION2
887 		printf("adding named SWF_DEFINEFUNCTION2 name=%s nargs=%d flags=%d"
888 				" regparamlen=%d arglen=%d codelen=%d taglen=%d\n",
889 				func_name, num_args, flags,
890 				bufferLength(c),
891 				bufferLength(args),
892 				bufferLength(code), taglen);
893 #endif
894 		bufferWriteS16(out, taglen);
895 		bufferWriteHardString(out, func_name, strlen(func_name)+1);
896 	}
897 	bufferWriteS16(out, num_args); /* number of params */
898  	bufferWriteU8(out, num_regs); /* register count */
899  	bufferWriteS16(out, flags);    /* flags */
900  	//bufferWriteS16(out, 0);    /* flags */
901  	bufferConcat(out, c);
902 	bufferWriteS16(out, bufferLength(code)); /* code size */
903 	bufferConcat(out, code);
904 	return taglen;
905 }
906 
destroyASFunction(ASFunction func)907 void destroyASFunction(ASFunction func)
908 {
909 	free(func->name);
910 	free(func);
911 }
912 
bufferWriteFunction(Buffer out,ASFunction function,int version)913 int bufferWriteFunction(Buffer out, ASFunction function, int version)
914 {
915 	int tagLen;
916 
917 	if(version == 2)
918 	{
919 		tagLen = bufferWriteDefineFunction2(out, function->name,
920 			function->params.buffer, function->code, function->flags, 0);
921 	}
922 	else
923 	{
924 		tagLen = 5;
925 		tagLen += bufferLength(function->params.buffer);
926 		if(function->name != NULL)
927 			tagLen += strlen(function->name);
928 
929 		bufferWriteOp(out, SWFACTION_DEFINEFUNCTION);
930 		bufferWriteS16(out, tagLen);
931 		if(function->name == NULL)
932 			bufferWriteU8(out, 0); /* empty function name */
933 		else
934 			bufferWriteHardString(out, function->name, strlen(function->name) +1 );
935 		bufferWriteS16(out, function->params.count);
936 		bufferConcat(out, function->params.buffer);
937 		bufferWriteS16(out, bufferLength(function->code));
938 		bufferConcat(out, function->code);
939 	}
940 	destroyASFunction(function);
941 	return tagLen;
942 }
943 
newASFunction()944 ASFunction newASFunction()
945 {
946 	ASFunction func;
947 	func = (ASFunction) malloc(sizeof(struct function_s));
948 	func->flags = 0;
949 	func->code = NULL;
950 	func->params.count = 0;
951 	func->params.buffer = NULL;
952 	func->name = NULL;
953 	return func;
954 }
955 
destroyASClass(ASClass clazz)956 void destroyASClass(ASClass clazz)
957 {
958 	ASClassMember member;
959 	if(clazz->name)
960 		free(clazz->name);
961 	if(clazz->extends)
962 		free(clazz->extends);
963 
964 	member = clazz->members;
965 	while(member)
966 	{
967 		ASClassMember _this = member;
968 		member = member->next;
969 		free(_this);
970 	}
971 	free(clazz);
972 }
973 
ASClass_getConstructor(ASClass clazz)974 ASFunction ASClass_getConstructor(ASClass clazz)
975 {
976 	ASClassMember member;
977 	member = clazz->members;
978 	while(member)
979 	{
980 		ASFunction func;
981 		ASClassMember _this = member;
982 		member = member->next;
983 
984 		if(_this->type != METHOD)
985 			continue;
986 		func = _this->element.function;
987 		if(!func || !func->name)
988 			continue;
989 		if(strcmp(func->name, clazz->name) != 0)
990 			continue;
991 
992 		_this->element.function = NULL;
993 		return func;
994 	}
995 	return newASFunction(); // default empty constructor
996 }
997 
bufferWriteClassConstructor(Buffer out,ASClass clazz)998 static int bufferWriteClassConstructor(Buffer out, ASClass clazz)
999 {
1000 	int len = 0;
1001 	ASFunction func;
1002 
1003 	/* class constructor */
1004 	len += bufferWriteString(out, "_global", strlen("_global") + 1);
1005 	len += bufferWriteOp(out, SWFACTION_GETVARIABLE);
1006 	len += bufferWriteString(out, clazz->name, strlen(clazz->name) + 1);
1007 	func = ASClass_getConstructor(clazz);
1008 	if(func->name)
1009 	{
1010 		free(func->name);
1011 		func->name = NULL;
1012 	}
1013 	len += bufferWriteFunction(out, func, 1);
1014 	len += bufferWriteSetRegister(out, 1);
1015 	len += bufferWriteOp(out, SWFACTION_SETMEMBER);
1016 
1017 	if(clazz->extends)
1018 	{
1019 		len += bufferWriteRegister(out, 1);
1020 		len += bufferWriteString(out, clazz->extends,
1021 		                         strlen(clazz->extends) + 1);
1022 		len += bufferWriteOp(out, SWFACTION_GETVARIABLE);
1023 		len += bufferWriteOp(out, SWFACTION_EXTENDS);
1024 	}
1025 
1026 	len += bufferWriteRegister(out, 1);
1027 	len += bufferWriteString(out, "prototype", strlen("prototype") + 1);
1028 	len += bufferWriteOp(out, SWFACTION_GETMEMBER);
1029 	len += bufferWriteSetRegister(out, 2);
1030 
1031 	len += bufferWriteOp(out, SWFACTION_POP);
1032 
1033 	return len;
1034 }
1035 
bufferWriteClassMethods(Buffer out,ASClass clazz)1036 static int bufferWriteClassMethods(Buffer out, ASClass clazz)
1037 {
1038 	ASClassMember member = clazz->members;
1039 	int len = 0;
1040 	while(member)
1041 	{
1042 		ASFunction func;
1043 		ASClassMember _this = member;
1044 		member = member->next;
1045 		if(_this->type != METHOD)
1046 			continue;
1047 		func = _this->element.function;
1048 		if(!func || !func->name)
1049 			continue;
1050 
1051 		if(strcmp(func->name, clazz->name) == 0)
1052 		{
1053 			SWF_error("only one class constructor allowed\n");
1054 		}
1055 
1056 		len += bufferWriteRegister(out, 2);
1057 		len += bufferWriteString(out, func->name, strlen(func->name) + 1);
1058 		free(func->name);
1059 		func->name = NULL;
1060 		len += bufferWriteFunction(out, func, 1);
1061 		len += bufferWriteOp(out, SWFACTION_SETMEMBER);
1062 		_this->element.function = NULL;
1063 	}
1064 	return len;
1065 }
1066 
bufferWriteClassVariable(Buffer out,ASVariable var)1067 static int bufferWriteClassVariable(Buffer out, ASVariable var)
1068 {
1069 	int len = 0;
1070 	if(var->initCode != NULL)
1071 	{
1072 		len += bufferWriteRegister(out, 2);
1073 		len += bufferWriteString(out, var->name, strlen(var->name)+1);
1074 		len += bufferConcat(out, var->initCode);
1075 		len += bufferWriteOp(out, SWFACTION_SETMEMBER);
1076 	}
1077 	free(var->name);
1078 	free(var); // aka destroyASVariable
1079 	return len;
1080 }
1081 
bufferWriteClassMembers(Buffer out,ASClass clazz)1082 static int bufferWriteClassMembers(Buffer out, ASClass clazz)
1083 {
1084 	ASClassMember member = clazz->members;
1085 	int len = 0;
1086 	while(member)
1087 	{
1088 		ASVariable var;
1089 		ASClassMember _this = member;
1090 		member = member->next;
1091 		if(_this->type != VARIABLE)
1092 			continue;
1093 		var = _this->element.var;
1094 		if(!var)
1095 			continue;
1096 		bufferWriteClassVariable(out, var);
1097 		_this->element.var = NULL;
1098 	}
1099 	return len;
1100 }
1101 
1102 
bufferWriteClass(Buffer out,ASClass clazz)1103 int bufferWriteClass(Buffer out, ASClass clazz)
1104 {
1105 	int len = 0;
1106 	len += bufferWriteClassConstructor(out, clazz);
1107 	len += bufferWriteClassMembers(out, clazz);
1108 	len += bufferWriteClassMethods(out, clazz);
1109 	/* set class properties */
1110 	len += bufferWriteInt(out, 1);
1111 	len += bufferWriteNull(out);
1112 	len += bufferWriteString(out, "_global", strlen("_global") + 1);
1113 	len += bufferWriteOp(out, SWFACTION_GETVARIABLE);
1114 
1115 	len += bufferWriteString(out, clazz->name, strlen(clazz->name) + 1);
1116 	len += bufferWriteOp(out, SWFACTION_GETMEMBER);
1117 
1118 	len += bufferWriteString(out, "prototype", strlen("prototype") + 1);
1119 	len += bufferWriteOp(out, SWFACTION_GETMEMBER);
1120 
1121 	len += bufferWriteInt(out, 3);
1122 	len += bufferWriteString(out, "ASSetPropFlags", strlen("ASSetPropFlags") + 1);
1123 	len += bufferWriteOp(out, SWFACTION_CALLFUNCTION);
1124 	len += bufferWriteOp(out, SWFACTION_POP);
1125 
1126 	destroyASClass(clazz);
1127 	return len;
1128 }
1129 
ASClassMember_append(ASClassMember m0,ASClassMember end)1130 void ASClassMember_append(ASClassMember m0, ASClassMember end)
1131 {
1132 	ASClassMember mb = m0;
1133 	while(mb->next)
1134 		mb = mb->next;
1135 	mb->next = end;
1136 }
1137 
newASClass(char * name,char * extends,ASClassMember members)1138 ASClass newASClass(char *name, char *extends, ASClassMember members)
1139 {
1140 	ASClass clazz;
1141 	clazz = (ASClass) malloc(sizeof(struct class_s));
1142 	clazz->name = name;
1143 	clazz->extends = extends;
1144 	clazz->members = members;
1145 	return clazz;
1146 }
1147 
newASClassMember_function(ASFunction func)1148 ASClassMember newASClassMember_function(ASFunction func)
1149 {
1150 	ASClassMember member = (ASClassMember) malloc(sizeof(struct class_member_s));
1151 	member->element.function = func;
1152 	member->type = METHOD;
1153 	member->next = NULL;
1154 	return member;
1155 }
1156 
newASClassMember_variable(ASVariable var)1157 ASClassMember newASClassMember_variable(ASVariable var)
1158 {
1159 	ASClassMember member = (ASClassMember) malloc(sizeof(struct class_member_s));
1160 	member->element.var = var;
1161 	member->type = VARIABLE;
1162 	member->next = NULL;
1163 	return member;
1164 }
1165 
1166 
newASClassMember_buffer(Buffer buf)1167 ASClassMember newASClassMember_buffer(Buffer buf)
1168 {
1169 	ASClassMember member = (ASClassMember) malloc(sizeof(struct class_member_s));
1170 	member->element.buffer = buf;
1171 	member->type = BUFF;
1172 	member->next = NULL;
1173 	return member;
1174 }
newASVariable(char * name,Buffer buf)1175 ASVariable newASVariable(char *name, Buffer buf)
1176 {
1177 	ASVariable var = (ASVariable) malloc(sizeof(struct variable_s));
1178 	var->name = name;
1179 	var->initCode = buf;
1180 	return var;
1181 }
1182 /*
1183  * Local variables:
1184  * tab-width: 2
1185  * c-basic-offset: 2
1186  * End:
1187  */
1188