KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > iv > flash > api > action > Program


1 /*
2  * $Id: Program.java,v 1.6 2002/08/02 03:15:17 skavish Exp $
3  *
4  * ==========================================================================
5  *
6  * The JGenerator Software License, Version 1.0
7  *
8  * Copyright (c) 2000 Dmitry Skavish (skavish@usa.net). All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if
22  * any, must include the following acknowlegement:
23  * "This product includes software developed by Dmitry Skavish
24  * (skavish@usa.net, http://www.flashgap.com/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The name "The JGenerator" must not be used to endorse or promote
29  * products derived from this software without prior written permission.
30  * For written permission, please contact skavish@usa.net.
31  *
32  * 5. Products derived from this software may not be called "The JGenerator"
33  * nor may "The JGenerator" appear in their names without prior written
34  * permission of Dmitry Skavish.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL DMITRY SKAVISH OR THE OTHER
40  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  *
49  */

50
51 package org.openlaszlo.iv.flash.api.action;
52
53 import java.io.PrintStream JavaDoc;
54
55 import org.openlaszlo.iv.flash.util.*;
56 import org.openlaszlo.iv.flash.parser.*;
57 import org.openlaszlo.iv.flash.api.*;
58 import org.openlaszlo.iv.flash.context.Context;
59
60 /**
61  * Wrapper of ActionScript bytecode.
62  * <P>
63  * The bytecodes are not parsed into some objects but rather
64  * kept in their "bytecoded" form. Parsing the stuff is very
65  * simple and straightforward and due to the nature of JGenerator
66  * this is what we need most of the time.
67  *
68  * @author Dmitry Skavish
69  */

70 public final class Program extends FlashObject {
71
72     // properties
73
public static final int PROP_X = 0;
74     public static final int PROP_Y = 1;
75     public static final int PROP_XSCALE = 2;
76     public static final int PROP_YSCALE = 3;
77     public static final int PROP_CURRENTFRAME = 4;
78     public static final int PROP_TOTALFRAMES = 5;
79     public static final int PROP_ALPHA = 6;
80     public static final int PROP_VISIBLE = 7;
81     public static final int PROP_WIDTH = 8;
82     public static final int PROP_HEIGHT = 9;
83     public static final int PROP_ROTATION = 10;
84     public static final int PROP_TARGET = 11;
85     public static final int PROP_FRAMESLOADED = 12;
86     public static final int PROP_NAME = 13;
87     public static final int PROP_DROPTARGET = 14;
88     public static final int PROP_URL = 15;
89     public static final int PROP_HIGHQUALITY = 16;
90     public static final int PROP_FOCUSRECT = 17;
91     public static final int PROP_SOUNDBUFTIME = 18;
92     public static final int PROP_QUALITY = 19;
93     public static final int PROP_XMOUSE = 20;
94     public static final int PROP_YMOUSE = 21;
95
96     private FlashBuffer body;
97
98     /**
99      * Creates empty program of default capacity.
100      */

101     public Program() {
102         body = new FlashBuffer(50);
103     }
104
105     /**
106      * Creates program from specified flashbuffer.
107      * <P>
108      * Specified flashbuffer is not copied but directly used.
109      *
110      * @param body flashbuffer containing actionscript bytecode
111      */

112     public Program( FlashBuffer body ) {
113         this.body = body;
114     }
115
116     /**
117      * Creates program from specified buffer of bytecodes.
118      * <P>
119      * The bytecodes from the buffer copied into internal flashbuffer
120      *
121      * @param buf buffer containing bytecodes
122      * @param start offset in the buffer
123      * @param end end offset in the buffer
124      */

125     public Program( byte[] buf, int start, int end ) {
126         int bufLength = end-start;
127         byte[] myBuf = new byte[bufLength];
128         System.arraycopy(buf, start, myBuf, 0, bufLength);
129         body = new FlashBuffer( myBuf, bufLength );
130     }
131
132     public int getTag() {
133         return -1;
134     }
135
136     /**
137      * Applies specified context to this program
138      * <P>
139      * Searches for all possible generator variables in this program
140      * data and applies specified context to them.<br>
141      * Since changing the data may change the offsets used in the program
142      * to perform gotos and jumps the special care taken to resolve forward
143      * references in the bytecode.
144      *
145      * @param context specified generator context
146      */

147     public void apply( Context context ) {
148         int[] new_offs = new int[getLength()];
149         FlashBuffer fob = new FlashBuffer(getLength()+10);
150
151         ForwardRef[] forward_refs = new ForwardRef[] { null };
152         setPos(0);
153     Loop:
154         for(;;) {
155             int curPos = getPos();
156             boolean isFRef = new_offs[curPos] == -1;
157             new_offs[curPos] = fob.getPos();
158             if( isFRef ) resolveForwardReferences(forward_refs, fob);
159             int code = getUByte();
160             boolean hasLength = (code&0x80) != 0;
161             int length = hasLength? getUWord(): 0;
162             fob.writeByte(code);
163             int nextPos = getPos()+length;
164
165             switch( code ) {
166                 case Actions.None:
167                     setPos(nextPos);
168                     break Loop;
169                 case Actions.GotoFrame:
170                     fob.writeWord(2);
171                     fob.writeWord(getUWord());
172                     break;
173                 case Actions.GetURL: {
174                     String JavaDoc url = getString();
175                     String JavaDoc target = getString();
176                     url = context.apply(url);
177                     target = context.apply(target);
178                     fob.writeWord(url.length()+target.length()+2); // 2 - length of end zeroes
179
fob.writeStringZ(url);
180                     fob.writeStringZ(target);
181                     break;
182                 }
183                 case Actions.WaitForFrame:
184                     fob.writeWord(3);
185                     fob.writeWord(getUWord());
186                     fob.writeByte(getUByte());
187                     break;
188                 case Actions.SetTarget: {
189                     String JavaDoc target = getString();
190                     target = context.apply(target);
191                     fob.writeWord(target.length()+1); // 1 - length of end zero
192
fob.writeStringZ(target);
193                     break;
194                 }
195                 case Actions.GotoLabel: {
196                     String JavaDoc label = getString();
197                     label = context.apply(label);
198                     fob.writeWord(label.length()+1); // 1 - length of end zero
199
fob.writeStringZ(label);
200                     break;
201                 }
202                 case Actions.PushData: {
203                     // quick check whether we have vars or not
204
int start = getPos();
205                     int l = length;
206                     while( --l >= 0 ) {
207                         if( getUByte() == '{' ) break;
208                     }
209                     // reset position
210
setPos( start );
211                     if( l <= 0 ) { // no vars
212
fob.writeWord(length);
213                         body.getTo(fob, length);
214                     } else { // probably some vars, let's parse fair
215
FlashBuffer fb = new FlashBuffer( length+5 );
216                         while( getPos() < nextPos ) {
217                             int type = getUByte();
218                             fb.writeByte( type );
219                             switch( type ) {
220                                 case 0: // string
221
fb.writeStringZ( context.apply( getString() ) );
222                                     break;
223                                 case 1: // float
224
fb.writeDWord( getUDWord() );
225                                     break;
226                                 case 2: // null
227
break;
228                                 case 3: // undefined
229
break;
230                                 case 4: // register
231
fb.writeByte( getUByte() );
232                                     break;
233                                 case 5: // boolean
234
fb.writeByte( getUByte() );
235                                     break;
236                                 case 6: // double
237
fb.writeDWord( getUDWord() );
238                                     fb.writeDWord( getUDWord() );
239                                     break;
240                                 case 7: // int
241
fb.writeDWord( getUDWord() );
242                                     break;
243                                 case 8: // dictionary lookup 1 byte
244
fb.writeByte( getUByte() );
245                                     break;
246                                 case 9: // dictionary lookup 2 bytes
247
fb.writeWord( getUWord() );
248                                     break;
249                                 default:
250                                     // since we don't know what is this it's safer to skip everything
251
// it has to be investigated further
252
// after this while loop will break !
253
body.getTo(fb, nextPos-getPos());
254                                     break;
255                             }
256                         }
257                         fob.writeWord( fb.getSize() );
258                         fob.writeFOB( fb );
259                     }
260                     break;
261                 }
262                 case Actions.JumpIfTrue:
263                 case Actions.Jump: {
264                     fob.writeWord(2);
265                     int offset = getWord();
266                     int target_off = getPos()+offset;
267                     if( offset <= 0 ) {
268                         int new_off = new_offs[target_off] - (fob.getPos()+2); // has to be negative
269
fob.writeWord(new_off);
270                     } else {
271                         new_offs[target_off] = -1; // mark this offset as having forward reference (just for optimization)
272
addForwardRef( forward_refs, new ForwardRef( fob.getPos(), target_off ) );
273                         fob.skip(2);
274                     }
275                     break;
276                 }
277                 case Actions.GotoExpression:
278                 case Actions.GetURL2:
279                 case Actions.WaitForFrameExpression:
280                     fob.writeWord(1);
281                     fob.writeByte(getUByte());
282                     break;
283                 case Actions.CallFrame:
284                     fob.writeWord(0);
285                     break;
286                 case Actions.ConstantPool: {
287                     int num = getUWord();
288                     String JavaDoc[] strings = new String JavaDoc[num];
289                     int len = 2;
290                     for( int i=0; i<num; i++ ) {
291                         String JavaDoc c = getString();
292                         c = context.apply(c);
293                         strings[i] = c;
294                         len += c.length()+1;
295                     }
296                     fob.writeWord(len);
297                     fob.writeWord(num);
298                     for( int i=0; i<num; i++ ) {
299                         fob.writeStringZ(strings[i]);
300                     }
301                     break;
302                 }
303                 case Actions.With: {
304                     String JavaDoc with = getString();
305                     with = context.apply(with);
306                     fob.writeWord(with.length()+1);
307                     fob.writeStringZ(with);
308                     break;
309                 }
310                 // name (STR), parmsNum (WORD), parms (STR*parmsNum), codeSize (WORD)
311
// we need to generate correct codesize value
312
case Actions.DefineFunction: {
313                     fob.writeWord(length); // ??? about this length, it may be dangerous
314
fob.writeStringZ(getString());
315                     int num = getUWord();
316                     fob.writeWord(num);
317                     for( int i=0; i<num; i++ ) fob.writeStringZ(getString());
318                     int codesize = getUWord();
319                     int target_off = getPos()+codesize;
320                     new_offs[target_off] = -1; // mark this offset as having forward reference (just for optimization)
321
addForwardRef( forward_refs, new ForwardRef( fob.getPos(), target_off ) );
322                     fob.skip(2);
323                     break;
324                 }
325                 default:
326                     if( hasLength ) {
327                         fob.writeWord(length);
328                         body.getTo(fob, length);
329                     }
330                     break;
331             }
332             setPos(nextPos);
333         }
334         body = fob;
335     }
336
337     /**
338      * Gets length of the program
339      *
340      * @return length of the program
341      */

342     public int getLength() {
343         return body.getSize()+1;
344     }
345
346     public void write( FlashOutput fob ) {
347         fob.writeFOB( body );
348         fob.writeByte(0); // end
349
}
350
351     public void printContent( PrintStream JavaDoc out, String JavaDoc indent ) {
352         int origPos = getPos();
353         try {
354             out.println( indent+"Actions: " );
355             setPos(0);
356
357             String JavaDoc[] cpool = null;
358
359             for(;;) {
360                 int offset = getPos();
361                 int code = getUByte();
362                 boolean hasLength = (code&0x80) != 0;
363                 int length = hasLength? getUWord(): 0;
364                 int nextPos = getPos()+length;
365
366                 out.print( indent+" "+Util.w2h(offset)+": "+Actions.getActionName(code)+" " );
367                 switch( code ) {
368                   case Actions.None:
369                     out.println();
370                     setPos(nextPos);
371                     return;
372                   case Actions.GotoFrame:
373                     out.println( getUWord() );
374                     break;
375                   case Actions.GetURL:
376                     out.println( "url='"+getString()+"' target='"+getString()+"'" );
377                     break;
378                   case Actions.WaitForFrame:
379                     out.println( "frame="+getUWord()+" skipcount="+getUByte() );
380                     break;
381                   case Actions.SetTarget:
382                     out.println( "target='"+getString()+"'" );
383                     break;
384                   case Actions.GotoLabel:
385                     out.println( "label='"+getString()+"'" );
386                     break;
387                   case Actions.PushData: {
388                       out.println( "values: " );
389                       for( int l=length; l>0; ) {
390                           int type = getUByte();
391                           l--;
392                           switch( type ) {
393                             case 0:
394                               String JavaDoc ss = getString();
395                               out.println( indent+" string='"+ss+"'" );
396                               l-=ss.length()+1;
397                               break;
398                             case 1:
399                               float flt = Float.intBitsToFloat(getUDWord());
400                               out.println( indent+" float="+flt );
401                               l-=4;
402                               break;
403                             case 2:
404                               out.println( indent+" NULL" );
405                               break;
406                             case 3:
407                               out.println( indent+" undefined" );
408                               break;
409                             case 4:
410                               out.println( indent+" register="+getUByte() );
411                               l--;
412                               break;
413                             case 5:
414                               out.println( indent+" boolean="+(getUByte()!=0) );
415                               l--;
416                               break;
417                             case 6:
418                               long dbits = ( ((long)getUDWord())<<32 ) | (((long)getUDWord())&0xffffffffL);
419                               double dbl = Double.longBitsToDouble(dbits);
420                               out.println( indent+" double="+dbl );
421                               l-=8;
422                               break;
423                             case 7:
424                               int ival = getUDWord();
425                               out.println( indent+" int="+ival+" (hex: "+Util.d2h(ival)+")" );
426                               l-=4;
427                               break;
428                             case 8: {
429                                 int idx = getUByte();
430                                 String JavaDoc val = cpool!=null&&idx<cpool.length? cpool[idx]: "<<<error>>>";
431                                 out.println( indent+" pool_index="+idx+" -> "+val );
432                                 l--;
433                                 break;
434                             }
435                             case 9: {
436                                 int idx = getUWord();
437                                 String JavaDoc val = cpool!=null&&idx<cpool.length? cpool[idx]: "<<<error>>>";
438                                 out.println( indent+" pool_index="+idx+" -> "+val );
439                                 l-=2;
440                                 break;
441                             }
442                           }
443                       }
444                       break;
445                   }
446                   case Actions.JumpIfTrue:
447                   case Actions.Jump: {
448                       int off = getWord();
449                       out.println( "offset="+off+" (goto "+Util.w2h(getPos()+off)+")" );
450                       break;
451                   }
452                   case Actions.GotoExpression:
453                   case Actions.GetURL2:
454                   case Actions.WaitForFrameExpression:
455                     out.println( "byte="+getUByte() );
456                     break;
457                   case Actions.ConstantPool: {
458                       int num = getUWord();
459                       cpool = new String JavaDoc[num];
460                       out.println( "constants="+num );
461                       for( int i=0; i<num; i++ ) {
462                           out.println( indent+" constpool["+i+"]='"+(cpool[i]=getString())+"'" );
463                       }
464                       break;
465                   }
466                     // name (STR), parmsNum (WORD), parms (STR*parmsNum), codeSize (WORD) /*, code (UI8*codeSize)*/
467
case Actions.DefineFunction: {
468                       String JavaDoc name = getString();
469                       int num = getUWord();
470                       out.print( "function "+name+"( " );
471                       for( int i=0; i<num; i++ ) {
472                           out.print( getString() );
473                           if( i != num-1 ) out.print( ", " );
474                       }
475                       int codesize = getUWord();
476                       out.println( " ) codesize="+codesize+" (until "+Util.w2h(getPos()+codesize)+")" );
477                       break;
478                   }
479                   case Actions.With:
480                     out.println( "withblock='"+getString()+"'" );
481                     break;
482                   default:
483                     // if( hasLength ) body.getSkip( length ); this will be done after switch
484
out.println();
485                     break;
486                 }
487
488                 // Buffer capacity is not ensured in this function since it
489
// assumes that it will be called only when the buffer is
490
// complete. To prevent array overflow, check that the next
491
// position is not >= current buf length. See bug 4589. -pk
492
if (nextPos >= body.getBuf().length) {
493                     return;
494                 }
495
496                 setPos(nextPos);
497             }
498         } finally {
499             setPos(origPos);
500         }
501     }
502
503     protected boolean _isConstant() {
504         setPos(0);
505
506         for(;;) {
507             int code = getUByte();
508             boolean hasLength = (code&0x80) != 0;
509             int length = hasLength? getUWord(): 0;
510             int pos = getPos();
511
512             switch( code ) {
513                 case Actions.None:
514                     return true;
515                 case Actions.GetURL:
516                     if( Util.hasVar(getString()) || Util.hasVar(getString()) ) return false;
517                     break;
518                 case Actions.SetTarget:
519                 case Actions.GotoLabel:
520                     if( Util.hasVar(getString()) ) return false;
521                     break;
522                 case Actions.PushData: {
523                     // quick check whether we have vars or not
524
int l = length;
525                     while( --l >= 0 ) {
526                         if( getUByte() == '{' ) return false;
527                     }
528 /* if( getUByte() == 0 ) {
529                         if( Util.hasVar(getString()) ) return false;
530                     }*/

531                     break;
532                 }
533                 case Actions.ConstantPool: {
534                     int num = getUWord();
535                     for( int i=0; i<num; i++ ) {
536                         if( Util.hasVar(getString()) ) return false;
537                     }
538                     break;
539                 }
540                 case Actions.With:
541                     if( Util.hasVar(getString()) ) return false;
542                     break;
543             }
544             setPos( pos+length );
545         }
546     }
547
548     public FlashItem getCopy( ScriptCopier copier ) {
549         return new Program( body.getCopy() );
550     }
551
552     public FlashBuffer body() {
553         return body;
554     }
555
556     // ------------------------------------------------------------------------- //
557
// API //
558
// ------------------------------------------------------------------------- //
559

560     /**
561      * End of the program
562      * @since flash 3
563      */

564     public void none() {
565         body.writeByte( Actions.None );
566     }
567
568     /**
569      * Instructs the player to go to the next frame in the current movie.
570      * @since flash 3
571      */

572     public void nextFrame() {
573         body.writeByte( Actions.NextFrame );
574     }
575
576     /**
577      * Instructs the player to go to the previous frame in the current movie.
578      * @since flash 3
579      */

580     public void prevFrame() {
581         body.writeByte( Actions.PrevFrame );
582     }
583
584     /**
585      * Instructs the player to start playing at the current frame.
586      * @since flash 3
587      */

588     public void play() {
589         body.writeByte( Actions.Play );
590     }
591
592     /**
593      * Instructs the player to stop playing the movie at the current frame.
594      * @since flash 3
595      */

596     public void stop() {
597         body.writeByte( Actions.Stop );
598     }
599
600     /**
601      * Gets a variable’s value.
602      * <P>
603      * <OL>
604      * <LI>Pops name off the stack, which is a string naming the variable to get.
605      * <LI>Pushes the value of the variable to the stack.
606      * </OL>
607      * @since flash 4
608      */

609     public void eval() {
610         body.writeByte( Actions.Eval );
611     }
612
613     /**
614      * An equivalent of {@link #eval}.
615      *
616      * @see #eval
617      * @since flash 4
618      */

619     public void getVar() {
620         eval();
621     }
622
623     /**
624      * Sets a variable.
625      * <P>
626      * <OL>
627      * <LI>Pops value off the stack.
628      * <LI>Pops name off the stack, which is a string naming the variable to set.
629      * <LI>Sets the variable name in the current execution context to value.
630      * </OL>
631      * A variable in another execution context may be referenced by prefixing the variable name with
632      * the target path and a colon. For example: /A/B:FOO references variable FOO in movie
633      * clip with target path /A/B.
634      * @since flash 4
635      */

636     public void setVar() {
637         body.writeByte( Actions.SetVariable );
638     }
639
640     /**
641      * Toggle the display between high and low quality.
642      * @since flash 3
643      */

644     public void toggleQuality() {
645         body.writeByte( Actions.ToggleQuality );
646     }
647
648     /**
649      * Instructs the player to stop playing all sounds.
650      * @since flash 3
651      */

652     public void stopSounds() {
653         body.writeByte( Actions.StopSounds );
654     }
655
656     /**
657      * Adds two numbers.
658      * <P>
659      * <OL>
660      * <LI>Pops value A off the stack.
661      * <LI>Pops value B off the stack.
662      * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
663      * <LI>The numbers are added.
664      * <LI>Pushes the result, A+B, to the stack.
665      * </OL>
666      * @since flash 4
667      */

668     public void add() {
669         body.writeByte( Actions.Add );
670     }
671
672     /**
673      * Subtracts two numbers.
674      * <P>
675      * <OL>
676      * <LI>Pops value A off the stack.
677      * <LI>Pops value B off the stack.
678      * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
679      * <LI>A is subtracted from B.
680      * <LI>Pushes the result, A-B, to the stack.
681      * </OL>
682      * @since flash 4
683      */

684     public void subtract() {
685         body.writeByte( Actions.Subtract );
686     }
687
688     /**
689      * Multiplies two numbers.
690      * <P>
691      * <OL>
692      * <LI>Pops value A off the stack.
693      * <LI>Pops value B off the stack.
694      * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
695      * <LI>The numbers are multiplied.
696      * <LI>Pushes the result, A*B, to the stack.
697      * </OL>
698      * @since flash 4
699      */

700     public void multiply() {
701         body.writeByte( Actions.Multiply );
702     }
703
704     /**
705      * Divides two numbers.
706      * <P>
707      * <OL>
708      * <LI>Pops value A off the stack.
709      * <LI>Pops value B off the stack.
710      * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
711      * <LI>B is divided by A.
712      * <LI>Pushes the result, B/A, to the stack.
713      * <LI>If A is zero, the result is the string #ERROR#.
714      * </OL>
715      * Note: When playing a Flash 5 .SWF, NaN, Infinity or –Infinity is pushed to the stack instead of #ERROR#.
716      * @since flash 4
717      */

718     public void divide() {
719         body.writeByte( Actions.Divide );
720     }
721
722     /**
723      * Tests two numbers for equality.
724      * <P>
725      * <OL>
726      * <LI>Pops value A off the stack.
727      * <LI>Pops value B off the stack.
728      * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
729      * <LI>The numbers are compared for equality.
730      * <LI>If the numbers are equal, a 1 (TRUE) is pushed to the stack.
731      * <LI>Otherwise, a 0 is pushed to the stack.
732      * </OL>
733      * Note: When playing a Macromedia Flash 5 .SWF, true is pushed to the stack instead of 1,
734      * and false is pushed to the stack instead of 0.
735      * @since flash 4
736      */

737     public void equal() {
738         body.writeByte( Actions.Equal );
739     }
740
741     /**
742      * Tests if a number is less than another number.
743      * <P>
744      * <OL>
745      * <LI>Pops value A off the stack.
746      * <LI>Pops value B off the stack.
747      * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
748      * <LI>The numbers are compared for equality.
749      * <LI>If B < A, a 1 is pushed to the stack; otherwise, a 0 is pushed to the stack.
750      * </OL>
751      * Note: When playing a Macromedia Flash 5 .SWF, true is pushed to the stack instead of 1,
752      * and false is pushed to the stack instead of 0.
753      * @since flash 4
754      */

755     public void lessThan() {
756         body.writeByte( Actions.LessThan );
757     }
758
759     /**
760      * Performs a logical AND of two numbers.
761      * <P>
762      * <OL>
763      * <LI>Pops value A off the stack.
764      * <LI>Pops value B off the stack.
765      * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
766      * <LI>If both numbers are nonzero, a 1 is pushed to the stack; otherwise, a 0 is pushed to the stack.
767      * </OL>
768      * Note: When playing a Macromedia Flash 5 .SWF, true is pushed to the stack instead of 1,
769      * and false is pushed to the stack instead of 0.
770      * @since flash 4
771      */

772     public void logicalAnd() {
773         body.writeByte( Actions.LogicalAnd );
774     }
775     /**
776      * Performs a logical OR of two numbers.
777      * <P>
778      * <OL>
779      * <LI>Pops value A off the stack.
780      * <LI>Pops value B off the stack.
781      * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
782      * <LI>If either numbers is nonzero, a 1 is pushed to the stack; otherwise, a 0 is pushed to the stack.
783      * </OL>
784      * Note: When playing a Macromedia Flash 5 .SWF, true is pushed to the stack instead of 1,
785      * and false is pushed to the stack instead of 0.
786      * @since flash 4
787      */

788     public void logicalOr() {
789         body.writeByte( Actions.LogicalOr );
790     }
791
792     /**
793      * Performs a logical NOT of a number.
794      * <P>
795      * Note that in Macromedia Flash 5 .SWF files, the ActionNot action
796      * converts its argument to a boolean, and pushes a result of type boolean.
797      * In Macromedia Flash 4 .SWF files, the argument and result are numbers.
798      * <P>
799      * <OL>
800      * <LI>Pops value A off the stack.
801      * <LI>Pops value B off the stack.
802      * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
803      * <LI>The numbers are compared for equality.
804      * <LI>If the numbers are equal, a 1 (TRUE) is pushed to the stack.
805      * <LI>Otherwise, a 0 is pushed to the stack.
806      * </OL>
807      * Note: When playing a Macromedia Flash 5 .SWF, true is pushed to the stack instead of 1,
808      * and false is pushed to the stack instead of 0.
809      * @since flash 4
810      */

811     public void logicalNot() {
812         body.writeByte( Actions.LogicalNot );
813     }
814
815     /**
816      * Tests two strings for equality.
817      * <P>
818      * <OL>
819      * <LI>Pops value A off the stack.
820      * <LI>Pops value B off the stack.
821      * <LI>A and B are compared as strings. The comparison is case-sensitive.
822      * <LI>If the strings are equal, a 1 (TRUE) is pushed to the stack.
823      * <LI>Otherwise, a 0 is pushed to the stack.
824      * </OL>
825      * Note: When playing a Macromedia Flash 5 .SWF, true is pushed to the stack instead of 1,
826      * and false is pushed to the stack instead of 0.
827      * @since flash 4
828      */

829     public void stringEqual() {
830         body.writeByte( Actions.StringEqual );
831     }
832
833     /**
834      * Computes the length of a string.
835      * <P>
836      * <OL>
837      * <LI>Pops a string off the stack.
838      * <LI>The length of the string is calculated and pushed to the stack.
839      * </OL>
840      * @since flash 4
841      */

842     public void stringLength() {
843         body.writeByte( Actions.StringLength );
844     }
845
846     /**
847      * Tests if a string is less than another string.
848      * <P>
849      * <OL>
850      * <LI>Pops value A off the stack.
851      * <LI>Pops value B off the stack.
852      * <LI>If B < A using a byte-by-byte comparison, a 1 is pushed to the stack;
853      * otherwise, a 0 is pushed to the stack.
854      * </OL>
855      * Note: When playing a Macromedia Flash 5 .SWF, true is pushed to the stack instead of 1,
856      * and false is pushed to the stack instead of 0.
857      * @since flash 4
858      */

859     public void stringLessThan() {
860         body.writeByte( Actions.StringLessThan );
861     }
862
863     /**
864      * Extracts a substring from a string.
865      * <P>
866      * <OL>
867      * <LI>Pops number <B>count</B> off the stack.
868      * <LI>Pops number <B>index</B> off the stack.
869      * <LI>Pops string <B>string</B> off the stack.
870      * <LI>The substring of <B>string</B> starting at the <B>index</B>’th character and
871      * <B>count</B> characters in length is pushed to the stack.
872      * <LI>If either <B>index</B> or <B>count</B> do not evaluate to integers, the result
873      * is the empty string.
874      * </OL>
875      * @since flash 4
876      */

877     public void subString() {
878         body.writeByte( Actions.SubString );
879     }
880
881     /**
882      * Concatenates two strings.
883      * <P>
884      * <OL>
885      * <LI>Pops value A off the stack.
886      * <LI>Pops value B off the stack.
887      * <LI>The concatenation BA is pushed to the stack.
888      * </OL>
889      * @since flash 4
890      */

891     public void addString() {
892         body.writeByte( Actions.StringConcat );
893     }
894
895     /**
896      * Computes the length of a string, multi-byte aware.
897      * <P>
898      * <OL>
899      * <LI>Pops a string off the stack.
900      * <LI>The length of the string in characters is calculated and pushed to the stack.
901      * <LI>This is a multi-byte aware version of ActionStringLength.
902      * On systems with double-byte support, a double-byte character is counted as a single character.
903      * </OL>
904      * @since flash 4
905      */

906     public void mbLength() {
907         body.writeByte( Actions.MBLength );
908     }
909
910     /**
911      * Converts ASCII to character code, multi-byte aware.
912      * <P>
913      * <OL>
914      * <LI>Pops value off the stack.
915      * <LI>The value is converted from a number to the corresponding character.
916      * If the character is a 16-bit value (>= 256), a double-byte character
917      * is constructed with the first byte containing the high-order byte,
918      * and the second byte containing the low-order byte.
919      * <LI>The resulting character is pushed to the stack.
920      * </OL>
921      * @since flash 4
922      */

923     public void mbChr() {
924         body.writeByte( Actions.MBChr );
925     }
926
927     /**
928      * Converts character code to ASCII, multi-byte aware.
929      * <P>
930      * <OL>
931      * <LI>Pops value off the stack.
932      * <LI>The first character of value is converted to a numeric character code.
933      * If the first character of value is a double-byte character, a 16-bit value
934      * is constructed with the first byte as the high order byte and the second byte
935      * as the low order byte.
936      * <LI>The resulting character code is pushed to the stack.
937      * </OL>
938      * @since flash 4
939      */

940     public void mbOrd() {
941         body.writeByte( Actions.MBOrd );
942     }
943
944     /**
945      * Extracts a substring from a string, multi-byte aware.
946      * <P>
947      * <OL>
948      * <LI>Pops number <B>count</B> off the stack.
949      * <LI>Pops number <B>index</B> off the stack.
950      * <LI>Pops string <B>string</B> off the stack.
951      * <LI>The substring of <B>string</B> starting at the <B>index</B>’th character and
952      * <B>count</B> characters in length is pushed to the stack.
953      * <LI>If either <B>index</B> or <B>count</B> do not evaluate to integers, the result
954      * is the empty string.
955      * <LI>This is a multi-byte aware version of ActionStringExtract. index and count are
956      * treated as character indices, counting double-byte characters as single characters.
957      * </OL>
958      * @since flash 4
959      */

960     public void mbSubString() {
961         body.writeByte( Actions.MBSubString );
962     }
963
964     /**
965      * Converts to integer.
966      * <P>
967      * <OL>
968      * <LI>Pops a value off the stack.
969      * <LI>The value is converted to a number.
970      * <LI>Next, any digits after the decimal point are discarded, resulting in an integer.
971      * <LI>The resulting integer is pushed to the stack.
972      * </OL>
973      * @since flash 4
974      */

975     public void toInt() {
976         body.writeByte( Actions.Int );
977     }
978
979     /**
980      * Converts character code to ASCII.
981      * <P>
982      * <OL>
983      * <LI>Pops value off the stack.
984      * <LI>The first character of value is converted to a numeric ASCII character code.
985      * <LI>The resulting character code is pushed to the stack.
986      * </OL>
987      * @since flash 4
988      */

989     public void ord() {
990         body.writeByte( Actions.Ord );
991     }
992
993     /**
994      * Converts ASCII to character code.
995      * <P>
996      * <OL>
997      * <LI>Pops value off the stack.
998      * <LI>The value is converted from a number to the corresponding ASCII character..
999      * <LI>The resulting character is pushed to the stack.
1000     * </OL>
1001     * @since flash 4
1002     */

1003    public void chr() {
1004        body.writeByte( Actions.Chr );
1005    }
1006
1007    /**
1008     * Set current context, stack-based
1009     * <P>
1010     * <OL>
1011     * <LI>Pops target off the stack and makes it the current active context.
1012     * <LI>This action behaves exactly like the original ActionSetTarget from
1013     * Macromedia Flash 3, but is stack-based to enable the target path to be the
1014     * result of expression evaluation.
1015     * </OL>
1016     * @since flash 4
1017     */

1018    public void setTarget() {
1019        body.writeByte( Actions.SetTargetExpression );
1020    }
1021
1022    /**
1023     * Gets a movie property
1024     * <P>
1025     * <OL>
1026     * <LI>Pops index off the stack.
1027     * <LI>Pops target off the stack.
1028     * <LI>Retrieves the value of the property enumerated as index from
1029     * the movie clip with target path target and pushes the value to the stack.
1030     * </OL>
1031     * @since flash 4
1032     */

1033    public void getProperty() {
1034        body.writeByte( Actions.GetProperty );
1035    }
1036
1037    /**
1038     * Sets a movie property.
1039     * <P>
1040     * <OL>
1041     * <LI>Pops value off the stack.
1042     * <LI>Pops index off the stack.
1043     * <LI>Pops target off the stack.
1044     * <LI>Sets the property enumerated as index in the movie clip
1045     * with target path target to the value value.
1046     * </OL>
1047     * @since flash 4
1048     */

1049    public void setProperty() {
1050        body.writeByte( Actions.SetProperty );
1051    }
1052
1053    /**
1054     * Clones a sprite.
1055     * <P>
1056     * <OL>
1057     * <LI>Pops depth off the stack.
1058     * <LI>Pops target off the stack.
1059     * <LI>Pops source off the stack.
1060     * <LI>Duplicates movie clip source, giving the new instance
1061     * the name target, at z-order depth depth.
1062     * </OL>
1063     * @since flash 4
1064     */

1065    public void cloneClip() {
1066        body.writeByte( Actions.DuplicateClip );
1067    }
1068
1069    /**
1070     * Removes a clone sprite.
1071     * <P>
1072     * <OL>
1073     * <LI>Pops target off the stack.
1074     * <LI>Removes the clone movie clip identified by target path target.
1075     * </OL>
1076     * @since flash 4
1077     */

1078    public void removeClip() {
1079        body.writeByte( Actions.RemoveClip );
1080    }
1081
1082    /**
1083     * Starts dragging a movie clip.
1084     * <P>
1085     * <OL>
1086     * <LI>Pops target off the stack. target identifies the movie clip to be dragged.
1087     * <LI>Pops lockcenter off the stack. If lockcenter evaluates to a nonzero value,
1088     * the center of the dragged movie clip is locked to the mouse position.
1089     * Otherwise, the movie clip moves relatively to the mouse position when
1090     * the drag started.
1091     * <LI>Pops constrain off the stack.
1092     * <LI>If constrain evaluates to a nonzero value:
1093     * <OL>
1094     * <LI>Pops y2 off the stack.
1095     * <LI>Pops x2 off the stack.
1096     * <LI>Pops y1 off the stack.
1097     * <LI>Pops x1 off the stack.
1098     * </OL>
1099     * </OL>
1100     * @since flash 4
1101     */

1102    public void startDrag() {
1103        body.writeByte( Actions.StartDragMovie );
1104    }
1105
1106    /**
1107     * Ends drag operation.
1108     * <P>
1109     * <OL>
1110     * <LI>Ends the drag operation in progress, if any.
1111     * </OL>
1112     * @since flash 4
1113     */

1114    public void endDrag() {
1115        body.writeByte( Actions.StopDragMovie );
1116    }
1117
1118    /**
1119     * Calculates a random number.
1120     * <P>
1121     * <OL>
1122     * <LI>Pops maximum off the stack.
1123     * <LI>Calculates a random number, an integer in the range 0 ... (maximum-1)
1124     * <LI>This random number is pushed to the stack.
1125     * </OL>
1126     * @since flash 4
1127     */

1128    public void random() {
1129        body.writeByte( Actions.Random );
1130    }
1131
1132    /**
1133     * Reports milliseconds since player started.
1134     * <P>
1135     * <OL>
1136     * <LI>Calculates the number of milliseconds since the Player was started (an integer).
1137     * <LI>This number is pushed to the stack.
1138     * </OL>
1139     * @since flash 4
1140     */

1141    public void getTimer() {
1142        body.writeByte( Actions.GetTimer );
1143    }
1144
1145    /**
1146     * Instructs the player to go to the specified frame in the current movie.
1147     *
1148     * @param frame frame number
1149     * @since flash 3
1150     */

1151    public void gotoFrame( int frame ) {
1152        body.writeByte( Actions.GotoFrame );
1153        body.writeWord(2);
1154        body.writeWord(frame);
1155    }
1156
1157    /**
1158     * Instructs the player to get the URL specified by UrlString.
1159     * The URL can be of any type, including an HTML file, an image
1160     * or another SWF movie. If the movie is playing in a browser,
1161     * the URL will be displayed in the frame specified by TargetString.
1162     * The special target names _level0 and _level1 are used to load another
1163     * SWF movie into levels 0 and 1 respectively.
1164     *
1165     * @param url specified url
1166     * @param target target
1167     * @since flash 3
1168     */

1169    public void getURL( String JavaDoc url, String JavaDoc target ) {
1170        body.writeByte( Actions.GetURL );
1171        body.writeWord((url==null?0:url.length())+(target==null?0:target.length())+2); // 2 - length of end zeroes
1172
body.writeStringZ(url==null?"":url);
1173        body.writeStringZ(target==null?"":target);
1174    }
1175
1176    /**
1177     * Instructs the player to wait until the specified frame,
1178     * otherwise skip the specified number of actions.
1179     *
1180     * @param frame specified frame
1181     * @param skip specified number of actions to skip
1182     * @since flash 3
1183     */

1184    public void waitForFrame( int frame, int skip ) {
1185        body.writeByte( Actions.WaitForFrame );
1186        body.writeWord(3);
1187        body.writeWord(frame);
1188        body.writeByte(skip);
1189    }
1190
1191    /**
1192     * Instructs the player to change the context of subsequent actions,
1193     * so they apply to a named object (TargetName) rather than the current movie.
1194     * <P>
1195     * For example, the SetTarget action can be used to control the timeline of a sprite
1196     * object. The following sequence of actions sends a sprite called "spinner" to the
1197     * first frame in its timeline:<BR>
1198     * <OL>
1199     * <LI>SetTarget "spinner"
1200     * <LI>GotoFrame zero
1201     * <LI>SetTarget "" (empty string)
1202     * <LI>End of actions. (Action code = 0)
1203     * </OL>
1204     * <P>
1205     * All actions following SetTarget "spinner" apply to the spinner
1206     * object until SetTarget "", which sets the action context back to
1207     * the current movie.
1208     * For a complete discussion of target names see DefineSprite.
1209     *
1210     * @param target name of the target
1211     * @since flash 3
1212     */

1213    public void setTarget( String JavaDoc target ) {
1214        body.writeByte( Actions.SetTarget );
1215        body.writeWord(target.length()+1); // 1 - length of end zero
1216
body.writeStringZ(target);
1217    }
1218
1219    /**
1220     * Instructs the player to go to frame associated with the specified label.
1221     * A label can be attached to a frame with the FrameLabel tag.
1222     *
1223     * @param label specified frame label
1224     * @since flash 3
1225     */

1226    public void gotoLabel( String JavaDoc label ) {
1227        body.writeByte( Actions.GotoLabel );
1228        body.writeWord(label.length()+1); // 1 - length of end zero
1229
body.writeStringZ(label);
1230    }
1231
1232    /**
1233     * Pops a value from the stack.
1234     * @since flash 4
1235     */

1236    public void pop() {
1237        body.writeByte( Actions.Pop );
1238    }
1239
1240    /**
1241     * Pushes a string to the stack.
1242     *
1243     * @param data string to push
1244     * @since flash 4
1245     */

1246    public void push( String JavaDoc data ) {
1247        body.writeByte( Actions.PushData );
1248        body.writeWord(data.length()+1+1);
1249        body.writeByte(0);
1250        body.writeStringZ(data);
1251    }
1252
1253    /**
1254     * Pushes a float to the stack.
1255     *
1256     * @param data float to push
1257     * @since flash 4
1258     */

1259    public void push( float data ) {
1260        body.writeByte( Actions.PushData );
1261        body.writeWord(4+1);
1262        body.writeByte(1);
1263        body.writeDWord( Float.floatToIntBits(data) );
1264    }
1265
1266    /**
1267     * Pushes an int to the stack.
1268     *
1269     * @param data int to push
1270     * @since flash 4
1271     */

1272    public void push( int data ) {
1273        body.writeByte( Actions.PushData );
1274        body.writeWord(4+1);
1275        body.writeByte(7);
1276        body.writeDWord( data );
1277    }
1278
1279    /**
1280     * Pushes constant index to the stack
1281     *
1282     * @since flash 5
1283     */

1284    public void push( Short JavaDoc const_idx ) {
1285        body.writeByte(Actions.PushData);
1286        int idx = const_idx.intValue();
1287        if( idx > 255 ) {
1288            body.writeWord(3);
1289            body.writeByte(9);
1290            body.writeWord(idx);
1291        } else {
1292            body.writeWord(2);
1293            body.writeByte(8);
1294            body.writeByte(idx);
1295        }
1296    }
1297
1298    /**
1299     * Pushes array of data to the stack
1300     * <P>
1301     * <ul>
1302     * <li>String - is pushed as string
1303     * <li>Integer - is pushed as int
1304     * <li>Double - is pushed as double
1305     * <li>Float - is pushed as float
1306     * <li>Boolean - is pushed as bool
1307     * <li>Byte - is pushed as index in constant pool
1308     * <li>Short - is pushed as index in constant pool
1309     * <li>null - is pushed as null
1310     *
1311     * @param data array of data
1312     * @since flash 5
1313     */

1314    public void push( Object JavaDoc[] data ) {
1315        FlashBuffer fb = new FlashBuffer(40);
1316        for( int i=0; i<data.length; i++ ) {
1317            Object JavaDoc o = data[i];
1318            if( o instanceof String JavaDoc ) {
1319                fb.writeByte(0);
1320                fb.writeStringZ((String JavaDoc)o);
1321            } else if( o instanceof Float JavaDoc ) {
1322                fb.writeByte(1);
1323                fb.writeDWord( Float.floatToIntBits(((Float JavaDoc)o).floatValue()) );
1324            } else if( o instanceof Boolean JavaDoc ) {
1325                fb.writeByte(5);
1326                fb.writeByte(((Boolean JavaDoc)o).booleanValue()?1:0);
1327            } else if( o instanceof Double JavaDoc ) {
1328                fb.writeByte(6);
1329                long dbits = Double.doubleToLongBits(((Double JavaDoc)o).doubleValue());
1330                fb.writeDWord((int)(dbits>>>32));
1331                fb.writeDWord((int)(dbits&0xffffffffL));
1332            } else if( o instanceof Integer JavaDoc ) {
1333                fb.writeByte(7);
1334                fb.writeDWord(((Integer JavaDoc)o).intValue());
1335            } else if( o instanceof Short JavaDoc || o instanceof Byte JavaDoc ) {
1336                int idx = ((Number JavaDoc)o).intValue();
1337                if( idx > 255 ) {
1338                    fb.writeByte(9);
1339                    fb.writeWord(idx);
1340                } else {
1341                    fb.writeByte(8);
1342                    fb.writeByte(idx);
1343                }
1344            } else if( o == null ) {
1345                fb.writeByte(2);
1346            }
1347        }
1348        body.writeByte(Actions.PushData);
1349        body.writeWord(fb.getSize());
1350        body.writeFOB(fb);
1351    }
1352
1353    /**
1354     * Pushes an object to the stack
1355     * <P>
1356     * <ul>
1357     * <li>String - is pushed as string
1358     * <li>Integer - is pushed as int
1359     * <li>Double - is pushed as double
1360     * <li>Float - is pushed as float
1361     * <li>Boolean - is pushed as bool
1362     * <li>Byte - is pushed as index in constant pool
1363     * <li>Short - is pushed as index in constant pool
1364     * <li>null - is pushed as null
1365     *
1366     * @param o data
1367     * @since flash 5
1368     */

1369    public void push( Object JavaDoc o ) {
1370        body.writeByte(Actions.PushData);
1371        if( o instanceof String JavaDoc ) {
1372            body.writeWord(((String JavaDoc)o).length()+2);
1373            body.writeByte(0);
1374            body.writeStringZ((String JavaDoc)o);
1375        } else if( o instanceof Float JavaDoc ) {
1376            body.writeWord(4+1);
1377            body.writeByte(1);
1378            body.writeDWord( Float.floatToIntBits(((Float JavaDoc)o).floatValue()) );
1379        } else if( o instanceof Boolean JavaDoc ) {
1380            body.writeWord(1+1);
1381            body.writeByte(5);
1382            body.writeByte(((Boolean JavaDoc)o).booleanValue()?1:0);
1383        } else if( o instanceof Double JavaDoc ) {
1384            body.writeWord(8+1);
1385            body.writeByte(6);
1386            long dbits = Double.doubleToLongBits(((Double JavaDoc)o).doubleValue());
1387            body.writeDWord((int)(dbits>>>32));
1388            body.writeDWord((int)(dbits&0xffffffffL));
1389        } else if( o instanceof Integer JavaDoc ) {
1390            body.writeWord(4+1);
1391            body.writeByte(7);
1392            body.writeDWord(((Integer JavaDoc)o).intValue());
1393        } else if( o instanceof Short JavaDoc || o instanceof Byte JavaDoc ) {
1394            int idx = ((Number JavaDoc)o).intValue();
1395            if( idx > 255 ) {
1396                body.writeWord(2+1);
1397                body.writeByte(9);
1398                body.writeWord(idx);
1399            } else {
1400                body.writeWord(1+1);
1401                body.writeByte(8);
1402                body.writeByte(idx);
1403            }
1404        } else if( o == null ) {
1405            body.writeWord(0+1);
1406            body.writeByte(2);
1407        }
1408    }
1409
1410    /**
1411     * Unconditional branch.
1412     * <P>
1413     * <OL>
1414     * <LI>BranchOffset bytes are added to the instruction pointer in the execution stream.
1415     * <LI>The offsets is a signed quantity, enabling branches from –32,768 bytes to 32,767 bytes.
1416     * <LI>An offset of 0 points to the action directly after the ActionJump action.
1417     * </OL>
1418     *
1419     * @param offset specified offset
1420     * @since flash 4
1421     */

1422    public void jump( int offset ) {
1423        body.writeByte( Actions.Jump );
1424        body.writeWord(2);
1425        body.writeWord(offset);
1426    }
1427
1428    /**
1429     * Conditional Test and Branch.
1430     * <P>
1431     * <OL>
1432     * <LI>Pops Condition, a number, off the stack.
1433     * <LI>Tests if Condition is nonzero: If Condition is nonzero,
1434     * BranchOffset bytes are added to the instruction pointer in the execution stream.
1435     * </OL>
1436     * Note: When playing a Macromedia Flash 5 .SWF, Condition is converted to a boolean and compared to true, not 0.
1437     * The offset is a signed quantity, enabling branches from –32768 bytes to 32767 bytes.
1438     * An offset of 0 points to the action directly after the ActionIf action.
1439     *
1440     * @param offset specified offset
1441     * @since flash 4
1442     */

1443    public void jumpIfTrue( int offset ) {
1444        body.writeByte( Actions.JumpIfTrue );
1445        body.writeWord(2);
1446        body.writeWord(offset);
1447    }
1448
1449    /**
1450     * Calls a subroutine.
1451     * <P>
1452     * <OL>
1453     * <LI>Pops a value off the stack.
1454     * <LI>This value should be either a string matching a frame label, or a number
1455     * indicating a frame number.
1456     * <LI>The value may be prefixed by a target string identifying the movie clip that
1457     * contains the frame being called.
1458     * <LI>If the frame is successfully located, the actions in the target frame are executed.
1459     * After the actions in the target frame are executed, execution resumes at the instruction
1460     * after the ActionCall instruction.
1461     * <LI>If the frame cannot be found, nothing happens.
1462     * <LI>NOTE: This action's tag (0x9E) has the high bit set, which will waste a few bytes in SWF file size.
1463     * This is a bug.
1464     * </OL>
1465     * @since flash 4
1466     */

1467    public void callFrame() {
1468        body.writeByte( Actions.CallFrame );
1469        body.writeWord(0);
1470    }
1471
1472    /**
1473     * Get URL, stack-based.
1474     * <P>
1475     * <OL>
1476     * <LI>Pops window off the stack. window specifies the target window,
1477     * which may be an empty string to indicate the current window.
1478     * <LI>Pops url off the stack. url which specifies the URL to be retrieved.
1479     * </OL>
1480     *
1481     * @param method Method specifies the method to use for the HTTP request. If (method and 0x40) != 0 then target is movie clip target,
1482     * NOT browser window target!
1483     * <UL>
1484     * <LI>A value of 0 indicates that this is not a form request,
1485     * so the movie clip’s variables should not be encoded and submitted.
1486     * <LI>A value of 1 specifies a HTTP GET request.
1487     * <LI>A value of 2 specifies a HTTP POST request.
1488     * <LI>If method is 1 (GET) or 2 (POST), the variables in the current
1489     * movie clip are submitted to the URL using the standard
1490     * x-www-urlencoded encoding and the HTTP request method specified by method.
1491     * </UL>
1492     * @since flash 4
1493     */

1494    public void getURL( int method ) {
1495        body.writeByte( Actions.GetURL2 );
1496        body.writeWord(1);
1497        body.writeByte(method);
1498    }
1499
1500    /**
1501     * Get URL using GET method, stack-based.
1502     * <P>
1503     * <OL>
1504     * <LI>Pops window off the stack. window specifies the target window,
1505     * which may be an empty string to indicate the current window.
1506     * <LI>Pops url off the stack. url which specifies the URL to be retrieved.
1507     * </OL>
1508     *
1509     * @see #getURL(int)
1510     * @since flash 4
1511     */

1512    public void getURL_GET() {
1513        getURL(1);
1514    }
1515
1516    /**
1517     * Get URL using POST method, stack-based.
1518     * <P>
1519     * <OL>
1520     * <LI>Pops window off the stack. window specifies the target window,
1521     * which may be an empty string to indicate the current window.
1522     * <LI>Pops url off the stack. url which specifies the URL to be retrieved.
1523     * </OL>
1524     *
1525     * @see #getURL(int)
1526     * @since flash 4
1527     */

1528    public void getURL_POST() {
1529        getURL(2);
1530    }
1531
1532    /**
1533     * Go to frame and stop, stack-based.
1534     * <P>
1535     * <OL>
1536     * <LI>Pops <b>frame</b> off the stack.
1537     * <LI>If <b>frame</b> is a number, the next frame of the movie to be displayed
1538     * will be the <b>frame</b>’th frame in the current movie clip.
1539     * <LI>If <b>frame</b> is a string, <b>frame</b> is treated as a frame label.
1540     * If the specified label exists in the current movie clip,
1541     * the labeled frame will become the current frame. Otherwise, the action is ignored.
1542     * <LI>Either a frame or a number may be prefixed by a target path, e.g. /MovieClip:3 or /MovieClip:FrameLabel
1543     * </OL>
1544     * @since flash 4
1545     */

1546    public void gotoFrameAndStop() {
1547        body.writeByte( Actions.GotoExpression );
1548        body.writeWord(1);
1549        body.writeByte(0x00);
1550    }
1551
1552    /**
1553     * Go to frame and play, stack-based.
1554     * <P>
1555     * <OL>
1556     * <LI>Pops <b>frame</b> off the stack.
1557     * <LI>If <b>frame</b> is a number, the next frame of the movie to be displayed
1558     * will be the <b>frame</b>’th frame in the current movie clip.
1559     * <LI>If <b>frame</b> is a string, <b>frame</b> is treated as a frame label.
1560     * If the specified label exists in the current movie clip,
1561     * the labeled frame will become the current frame. Otherwise, the action is ignored.
1562     * <LI>Either a frame or a number may be prefixed by a target path, e.g. /MovieClip:3 or /MovieClip:FrameLabel
1563     * </OL>
1564     * @since flash 4
1565     */

1566    public void gotoFrameAndPlay() {
1567        body.writeByte( Actions.GotoExpression );
1568        body.writeWord(1);
1569        body.writeByte(0x80);
1570    }
1571
1572    /**
1573     * Wait for a frame to be loaded, stack-based.
1574     * <P>
1575     * <OL>
1576     * <LI>Pops frame off the stack.
1577     * <LI>If the frame identified by frame has been loaded, SkipCount
1578     * actions following the current one are skipped.
1579     * <LI>frame is evaluated in the same way as the {@link #gotoFrameAndPlay} action.
1580     * </OL>
1581     *
1582     * @param skip specified number of actions to skip
1583     * @since flash 4
1584     */

1585    public void waitForFrameAndSkip( int skip ) {
1586        body.writeByte( Actions.WaitForFrameExpression );
1587        body.writeWord(1);
1588        body.writeByte(skip);
1589    }
1590
1591    /* Some flash 5 actions */
1592
1593     /**
1594     * Creates constant pool
1595     *
1596     * @param constants array of constants to be created
1597     * @since flash 5
1598     */

1599    public void addConstantPool( String JavaDoc[] constants ) {
1600        int size = 2;
1601        for( int i=0; i<constants.length; i++ ) {
1602            size += constants[i].length()+1;
1603        }
1604        body.writeByte(Actions.ConstantPool);
1605        body.writeWord(size);
1606        body.writeWord(constants.length);
1607        for( int i=0; i<constants.length; i++ ) {
1608            body.writeStringZ(constants[i]);
1609        }
1610    }
1611
1612    /**
1613     * New Object
1614     * @since flash 5
1615     */

1616    public void newObject() {
1617        body.writeByte(Actions.NewObject);
1618    }
1619
1620   /**
1621     * Calls a function.
1622     * Stack state must be [ arguments, argCount, methodName ]
1623     *
1624     * @since flash 5
1625     */

1626    public void callFunction() {
1627        body.writeByte( Actions.CallFunction );
1628    }
1629
1630    /**
1631     * Calls a method of an object.
1632     * Stack state must be [ arguments, argCount, object, methodName ]
1633     *
1634     * @since flash 5
1635     */

1636    public void callMethod() {
1637        body.writeByte( Actions.CallMethod );
1638    }
1639
1640    /**
1641     * Get member.
1642     * Stack state must be [ object, member name ]
1643     *
1644     * @since flash 5
1645     */

1646    public void getMember() {
1647        body.writeByte( Actions.GetMember );
1648    }
1649
1650    /**
1651     * Set member.
1652     * Stack state must be [ object, member name, value ]
1653     *
1654     * @since flash 5
1655     */

1656    public void setMember() {
1657        body.writeByte( Actions.SetMember );
1658    }
1659
1660    /* --------------------------------------------------------------------------------
1661     * Generating stuff
1662     * -------------------------------------------------------------------------------- */

1663    static class ForwardRef {
1664        ForwardRef next;
1665        int jumpOffset;
1666        int targetOffset;
1667        ForwardRef( int jumpOffset, int targetOffset ) {
1668            this.jumpOffset = jumpOffset;
1669            this.targetOffset = targetOffset;
1670        }
1671    }
1672
1673    private void addForwardRef( ForwardRef[] forward_refs, ForwardRef fref ) {
1674        fref.next = forward_refs[0];
1675        forward_refs[0] = fref;
1676    }
1677
1678    // resolve forward references
1679
private void resolveForwardReferences( ForwardRef[] forward_refs, FlashBuffer fob ) {
1680        ForwardRef pred = null;
1681        ForwardRef cur = forward_refs[0];
1682        int curPos = getPos();
1683        while( cur != null ) {
1684            if( cur.targetOffset == curPos ) {
1685                fob.writeWordAt( fob.getPos()-cur.jumpOffset-2, cur.jumpOffset );
1686                cur = cur.next;
1687                if( pred == null ) {
1688                    forward_refs[0] = cur;
1689                } else {
1690                    pred.next = cur;
1691                }
1692                continue;
1693            }
1694            pred = cur;
1695            cur = cur.next;
1696        }
1697    }
1698
1699    // --------------------------------------------------------------------------------- //
1700
// R E A D E R //
1701
// --------------------------------------------------------------------------------- //
1702

1703    protected final String JavaDoc getString() {
1704        return body.getString();
1705    }
1706    protected final int getByte() {
1707        return body.getByte();
1708    }
1709    protected final int getUByte() {
1710        return body.getUByte();
1711    }
1712    protected final int getWord() {
1713        return body.getWord();
1714    }
1715    protected final int getUWord() {
1716        return body.getUWord();
1717    }
1718    protected final int getDWord() {
1719        return body.getDWord();
1720    }
1721    protected final int getUDWord() {
1722        return body.getUDWord();
1723    }
1724    protected final int getPos() {
1725        return body.getPos();
1726    }
1727    protected final void setPos( int pos ) {
1728        body.setPos(pos);
1729    }
1730
1731}
1732
Popular Tags