upgrade to xpdf 3.00.
[swftools.git] / lib / action / compile.c
blobb658dd2eef918a62c6dd3febd714ad80e63ea3d8
1 /*
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
20 #ifndef WIN32
21 #include <unistd.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <ctype.h>
27 #include <string.h>
29 #include "libming.h"
30 #include "compile.h"
31 #include "action.h"
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 */
40 enum
42 SWF_BIG_ENDIAN,
43 SWF_LITTLE_ENDIAN
46 static int byteorder;
48 void checkByteOrder()
50 unsigned int x;
51 unsigned char *p;
53 x = 0x01020304;
54 p = (unsigned char *)&x;
56 if(*p == 1)
57 byteorder = SWF_BIG_ENDIAN;
58 else
59 byteorder = SWF_LITTLE_ENDIAN;
63 char *stringConcat(char *a, char *b)
65 if ( a != NULL )
67 if ( b != NULL )
69 a = (char*)realloc(a, strlen(a)+strlen(b)+1);
70 strcat(a, b);
71 free(b);
74 return a;
76 else
77 return b;
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
91 buffer->pushloc */
93 void bufferPatchPushLength(Buffer buffer, int len)
95 int oldsize;
97 if(buffer->pushloc != NULL)
99 oldsize = (buffer->pushloc[0] & 0xff) | ((buffer->pushloc[1] & 0xff) << 8);
100 oldsize += len;
101 buffer->pushloc[0] = oldsize & 0xff;
102 buffer->pushloc[1] = (oldsize >> 8) & 0xff;
104 else
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)
117 int i;
119 for(i=0; i<nConstants; ++i)
121 if(strcmp(s, constants[i]) == 0)
122 return i;
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);
132 return nConstants++;
135 int bufferWriteConstants(Buffer out)
137 int i, len=2;
139 if(nConstants == 0)
140 return 0;
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);
149 free(constants[i]);
152 nConstants = 0;
153 sizeConstants = 0;
154 bufferPatchLength(out, len);
156 return len+3;
159 Buffer newBuffer()
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;
166 *(out->pos) = 0;
167 out->buffersize = out->free = BUFFER_INCREMENT;
168 out->pushloc = NULL;
170 return out;
173 void destroyBuffer(Buffer out)
175 free(out->buffer);
176 free(out);
179 int bufferLength(Buffer out)
181 if(out)
182 return (out->pos)-(out->buffer);
183 else
184 return 0;
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)
199 int pushd;
201 if(out->pushloc)
202 pushd = out->pos - out->pushloc;
204 out->pos = newbuf+num;
206 if(out->pushloc)
207 out->pushloc = out->pos - pushd;
210 out->buffer = newbuf;
211 out->buffersize += New;
212 out->free += New;
216 int bufferWriteData(Buffer b, const byte *data, int length)
218 int i;
220 bufferCheckSize(b, length);
222 for(i=0; i<length; ++i)
223 bufferWriteU8(b, data[i]);
225 return length;
228 int bufferWriteBuffer(Buffer a, Buffer b)
230 if(!a)
231 return 0;
233 if(b)
234 return bufferWriteData(a, b->buffer, bufferLength(b));
236 return 0;
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)
243 int i, pushd;
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);
252 data += 3;
253 length -= 3;
256 if(b->pushloc)
257 pushd = b->pos - b->pushloc;
259 bufferCheckSize(a, length);
261 for(i=0; i<length; ++i)
262 bufferWriteU8(a, data[i]);
264 if(a->pushloc &&
265 (b->buffer[0] == SWFACTION_PUSHDATA) && (b->pushloc == b->buffer+1))
266 ; /* b is just one pushdata, so do nothing.. */
267 else if(b->pushloc)
268 a->pushloc = a->pos - pushd;
269 else
270 a->pushloc = 0;
272 return length;
275 int bufferConcat(Buffer a, Buffer b)
277 int len;
279 if(!a)
280 return 0;
282 if(b)
283 { len = bufferWriteDataAndPush(a, b);
284 destroyBuffer(b);
287 return len;
290 int bufferWriteOp(Buffer out, int data)
292 bufferWriteU8(out, data);
293 out->pushloc = NULL;
295 return 1;
298 int bufferWritePushOp(Buffer out)
300 bufferWriteU8(out, SWFACTION_PUSHDATA);
301 out->pushloc = out->pos;
303 return 1;
306 int bufferWriteU8(Buffer out, int data)
308 bufferCheckSize(out, 1);
309 *(out->pos) = data;
310 out->pos++;
311 out->free--;
313 return 1;
316 int bufferWriteS16(Buffer out, int data)
318 if(data < 0)
319 data = (1<<16)+data;
321 bufferWriteU8(out, data%256);
322 data >>= 8;
323 bufferWriteU8(out, data%256);
325 return 2;
328 int bufferWriteHardString(Buffer out, byte *string, int length)
330 int i;
332 for(i=0; i<length; ++i)
333 bufferWriteU8(out, string[i]);
335 return length;
338 int bufferWriteConstantString(Buffer out, byte *string, int length)
340 int n;
342 if(SWF_versionNum < 5)
343 return -1;
345 if(useConstants)
346 n = addConstant((char*) string);
347 else
348 n = -1;
350 if(n == -1)
352 bufferWriteU8(out, PUSH_STRING);
353 return bufferWriteHardString(out, string, length) + 1;
355 else if(n < 256)
357 bufferWriteU8(out, PUSH_CONSTANT);
358 return bufferWriteU8(out, n) + 1;
360 else
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);
376 return 4 + length;
378 else
380 int l;
382 if(out->pushloc == NULL)
384 bufferWritePushOp(out);
385 bufferWriteS16(out, 0);
388 l = bufferWriteConstantString(out, string, length);
390 bufferPatchPushLength(out, l);
391 return l;
395 int bufferWriteInt(Buffer out, int i)
397 int len = 0;
398 unsigned char *p = (unsigned char *)&i;
400 if(out->pushloc == NULL || SWF_versionNum < 5)
402 len = 3;
403 bufferWritePushOp(out);
404 bufferWriteS16(out, 5);
406 else
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]);
418 else
420 bufferWriteU8(out, p[3]);
421 bufferWriteU8(out, p[2]);
422 bufferWriteU8(out, p[1]);
423 bufferWriteU8(out, p[0]);
426 return len + 5;
429 int bufferWriteDouble(Buffer out, double d)
431 int len = 0;
432 unsigned char *p = (unsigned char *)&d;
434 if(out->pushloc == NULL || SWF_versionNum < 5)
436 len = 3;
437 bufferWritePushOp(out);
438 bufferWriteS16(out, 9);
440 else
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]);
456 else
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]);
468 return len + 9;
471 int bufferWriteNull(Buffer out)
473 int len = 0;
475 if(out->pushloc == NULL || SWF_versionNum < 5)
477 len = 3;
478 bufferWritePushOp(out);
479 bufferWriteS16(out, 1);
481 else
482 bufferPatchPushLength(out, 1);
484 bufferWriteU8(out, PUSH_NULL);
486 return len + 1;
489 int bufferWriteBoolean(Buffer out, int val)
491 int len = 0;
493 if(out->pushloc == NULL || SWF_versionNum < 5)
495 len = 3;
496 bufferWritePushOp(out);
497 bufferWriteS16(out, 2);
499 else
500 bufferPatchPushLength(out, 2);
502 bufferWriteU8(out, PUSH_BOOLEAN);
503 bufferWriteU8(out, val ? 1 : 0);
505 return len + 2;
508 int bufferWriteRegister(Buffer out, int num)
510 int len = 0;
512 if(out->pushloc == NULL || SWF_versionNum < 5)
514 len = 3;
515 bufferWritePushOp(out);
516 bufferWriteS16(out, 2);
518 else
519 bufferPatchPushLength(out, 2);
521 bufferWriteU8(out, PUSH_REGISTER);
522 bufferWriteU8(out, num);
524 return len + 2;
527 int bufferWriteSetRegister(Buffer out, int num)
529 bufferWriteU8(out, SWFACTION_SETREGISTER);
530 bufferWriteS16(out, 1);
531 bufferWriteU8(out, num);
532 return 4;
535 void lower(char *s)
537 while(*s)
539 *s = tolower(*s);
540 ++s;
544 /* this code will eventually help to pop extra values off the
545 stack and make sure that continue and break address the proper
546 context
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)
561 { int n, ret = 0;
562 switch(val)
563 { case CTX_FUNCTION:
564 for(n = ctx_count ; --n >= 0 ; )
565 switch(ctx_stack[n])
566 { case CTX_SWITCH:
567 case CTX_FOR_IN:
568 ret++;
569 break;
570 case CTX_FUNCTION:
571 return ret;
572 default: ; /* computers are stupid */
574 return -1;
575 case CTX_BREAK:
576 for(n = ctx_count ; --n >= 0 ; )
577 switch(ctx_stack[n])
578 { case CTX_SWITCH:
579 case CTX_LOOP:
580 return 0;
581 case CTX_FOR_IN:
582 return 1;
583 case CTX_FUNCTION:
584 return -1;
585 default: ; /* computers are stupid */
587 case CTX_CONTINUE:
588 for(n = ctx_count ; --n >= 0 ; )
589 switch(ctx_stack[n])
590 { case CTX_LOOP:
591 case CTX_FOR_IN:
592 return 0;
593 case CTX_FUNCTION:
594 return -1;
595 default: ; /* computers are stupid */
597 default: ; /* computers are stupid */
599 return 0;
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;
610 int l, target;
612 while(p < out->pos)
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);
624 *p = target & 0xff;
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);
631 *p = target & 0xff;
632 *(p+1) = (target>>8) & 0xff;
635 p += 2;
637 else
639 ++p;
640 l = *p;
641 ++p;
642 l += *p<<8;
643 ++p;
645 p += l;
648 else
649 ++p;
653 // handle SWITCH statement
655 void bufferResolveSwitch(Buffer buffer, struct switchcases *slp)
656 { struct switchcase *scp;
657 int n, len;
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))
664 scp->actlen += 5;
665 if(scp->cond)
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);
675 else
676 scp->condlen = 0;
677 bufferConcat(buffer, scp->action);
678 bufferWriteOp(buffer, SWFACTION_BRANCHALWAYS);
679 bufferWriteS16(buffer, 2);
680 bufferWriteS16(buffer, scp->isbreak ? MAGIC_BREAK_NUMBER : 0);
681 if(!scp->cond)
682 { slp->count = n+1;
683 break;
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;
693 len += scp->actlen;
697 int lookupSetProperty(char *string)
699 lower(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);
714 return -1;
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);
727 return 8;
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);
738 return 8;
741 const char *lookupGetProperty(char *string)
743 lower(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);
766 return "";
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);
782 * Local variables:
783 * tab-width: 2
784 * c-basic-offset: 2
785 * End: