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