0001: /*
0002: * $Id: Program.java,v 1.6 2002/08/02 03:15:17 skavish Exp $
0003: *
0004: * ==========================================================================
0005: *
0006: * The JGenerator Software License, Version 1.0
0007: *
0008: * Copyright (c) 2000 Dmitry Skavish (skavish@usa.net). All rights reserved.
0009: *
0010: * Redistribution and use in source and binary forms, with or without
0011: * modification, are permitted provided that the following conditions are met:
0012: *
0013: * 1. Redistributions of source code must retain the above copyright
0014: * notice, this list of conditions and the following disclaimer.
0015: *
0016: * 2. Redistributions in binary form must reproduce the above copyright
0017: * notice, this list of conditions and the following disclaimer in
0018: * the documentation and/or other materials provided with the
0019: * distribution.
0020: *
0021: * 3. The end-user documentation included with the redistribution, if
0022: * any, must include the following acknowlegement:
0023: * "This product includes software developed by Dmitry Skavish
0024: * (skavish@usa.net, http://www.flashgap.com/)."
0025: * Alternately, this acknowlegement may appear in the software itself,
0026: * if and wherever such third-party acknowlegements normally appear.
0027: *
0028: * 4. The name "The JGenerator" must not be used to endorse or promote
0029: * products derived from this software without prior written permission.
0030: * For written permission, please contact skavish@usa.net.
0031: *
0032: * 5. Products derived from this software may not be called "The JGenerator"
0033: * nor may "The JGenerator" appear in their names without prior written
0034: * permission of Dmitry Skavish.
0035: *
0036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0039: * DISCLAIMED. IN NO EVENT SHALL DMITRY SKAVISH OR THE OTHER
0040: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0047: * SUCH DAMAGE.
0048: *
0049: */
0050:
0051: package org.openlaszlo.iv.flash.api.action;
0052:
0053: import java.io.PrintStream;
0054:
0055: import org.openlaszlo.iv.flash.util.*;
0056: import org.openlaszlo.iv.flash.parser.*;
0057: import org.openlaszlo.iv.flash.api.*;
0058: import org.openlaszlo.iv.flash.context.Context;
0059:
0060: /**
0061: * Wrapper of ActionScript bytecode.
0062: * <P>
0063: * The bytecodes are not parsed into some objects but rather
0064: * kept in their "bytecoded" form. Parsing the stuff is very
0065: * simple and straightforward and due to the nature of JGenerator
0066: * this is what we need most of the time.
0067: *
0068: * @author Dmitry Skavish
0069: */
0070: public final class Program extends FlashObject {
0071:
0072: // properties
0073: public static final int PROP_X = 0;
0074: public static final int PROP_Y = 1;
0075: public static final int PROP_XSCALE = 2;
0076: public static final int PROP_YSCALE = 3;
0077: public static final int PROP_CURRENTFRAME = 4;
0078: public static final int PROP_TOTALFRAMES = 5;
0079: public static final int PROP_ALPHA = 6;
0080: public static final int PROP_VISIBLE = 7;
0081: public static final int PROP_WIDTH = 8;
0082: public static final int PROP_HEIGHT = 9;
0083: public static final int PROP_ROTATION = 10;
0084: public static final int PROP_TARGET = 11;
0085: public static final int PROP_FRAMESLOADED = 12;
0086: public static final int PROP_NAME = 13;
0087: public static final int PROP_DROPTARGET = 14;
0088: public static final int PROP_URL = 15;
0089: public static final int PROP_HIGHQUALITY = 16;
0090: public static final int PROP_FOCUSRECT = 17;
0091: public static final int PROP_SOUNDBUFTIME = 18;
0092: public static final int PROP_QUALITY = 19;
0093: public static final int PROP_XMOUSE = 20;
0094: public static final int PROP_YMOUSE = 21;
0095:
0096: private FlashBuffer body;
0097:
0098: /**
0099: * Creates empty program of default capacity.
0100: */
0101: public Program() {
0102: body = new FlashBuffer(50);
0103: }
0104:
0105: /**
0106: * Creates program from specified flashbuffer.
0107: * <P>
0108: * Specified flashbuffer is not copied but directly used.
0109: *
0110: * @param body flashbuffer containing actionscript bytecode
0111: */
0112: public Program(FlashBuffer body) {
0113: this .body = body;
0114: }
0115:
0116: /**
0117: * Creates program from specified buffer of bytecodes.
0118: * <P>
0119: * The bytecodes from the buffer copied into internal flashbuffer
0120: *
0121: * @param buf buffer containing bytecodes
0122: * @param start offset in the buffer
0123: * @param end end offset in the buffer
0124: */
0125: public Program(byte[] buf, int start, int end) {
0126: int bufLength = end - start;
0127: byte[] myBuf = new byte[bufLength];
0128: System.arraycopy(buf, start, myBuf, 0, bufLength);
0129: body = new FlashBuffer(myBuf, bufLength);
0130: }
0131:
0132: public int getTag() {
0133: return -1;
0134: }
0135:
0136: /**
0137: * Applies specified context to this program
0138: * <P>
0139: * Searches for all possible generator variables in this program
0140: * data and applies specified context to them.<br>
0141: * Since changing the data may change the offsets used in the program
0142: * to perform gotos and jumps the special care taken to resolve forward
0143: * references in the bytecode.
0144: *
0145: * @param context specified generator context
0146: */
0147: public void apply(Context context) {
0148: int[] new_offs = new int[getLength()];
0149: FlashBuffer fob = new FlashBuffer(getLength() + 10);
0150:
0151: ForwardRef[] forward_refs = new ForwardRef[] { null };
0152: setPos(0);
0153: Loop: for (;;) {
0154: int curPos = getPos();
0155: boolean isFRef = new_offs[curPos] == -1;
0156: new_offs[curPos] = fob.getPos();
0157: if (isFRef)
0158: resolveForwardReferences(forward_refs, fob);
0159: int code = getUByte();
0160: boolean hasLength = (code & 0x80) != 0;
0161: int length = hasLength ? getUWord() : 0;
0162: fob.writeByte(code);
0163: int nextPos = getPos() + length;
0164:
0165: switch (code) {
0166: case Actions.None:
0167: setPos(nextPos);
0168: break Loop;
0169: case Actions.GotoFrame:
0170: fob.writeWord(2);
0171: fob.writeWord(getUWord());
0172: break;
0173: case Actions.GetURL: {
0174: String url = getString();
0175: String target = getString();
0176: url = context.apply(url);
0177: target = context.apply(target);
0178: fob.writeWord(url.length() + target.length() + 2); // 2 - length of end zeroes
0179: fob.writeStringZ(url);
0180: fob.writeStringZ(target);
0181: break;
0182: }
0183: case Actions.WaitForFrame:
0184: fob.writeWord(3);
0185: fob.writeWord(getUWord());
0186: fob.writeByte(getUByte());
0187: break;
0188: case Actions.SetTarget: {
0189: String target = getString();
0190: target = context.apply(target);
0191: fob.writeWord(target.length() + 1); // 1 - length of end zero
0192: fob.writeStringZ(target);
0193: break;
0194: }
0195: case Actions.GotoLabel: {
0196: String label = getString();
0197: label = context.apply(label);
0198: fob.writeWord(label.length() + 1); // 1 - length of end zero
0199: fob.writeStringZ(label);
0200: break;
0201: }
0202: case Actions.PushData: {
0203: // quick check whether we have vars or not
0204: int start = getPos();
0205: int l = length;
0206: while (--l >= 0) {
0207: if (getUByte() == '{')
0208: break;
0209: }
0210: // reset position
0211: setPos(start);
0212: if (l <= 0) { // no vars
0213: fob.writeWord(length);
0214: body.getTo(fob, length);
0215: } else { // probably some vars, let's parse fair
0216: FlashBuffer fb = new FlashBuffer(length + 5);
0217: while (getPos() < nextPos) {
0218: int type = getUByte();
0219: fb.writeByte(type);
0220: switch (type) {
0221: case 0: // string
0222: fb.writeStringZ(context.apply(getString()));
0223: break;
0224: case 1: // float
0225: fb.writeDWord(getUDWord());
0226: break;
0227: case 2: // null
0228: break;
0229: case 3: // undefined
0230: break;
0231: case 4: // register
0232: fb.writeByte(getUByte());
0233: break;
0234: case 5: // boolean
0235: fb.writeByte(getUByte());
0236: break;
0237: case 6: // double
0238: fb.writeDWord(getUDWord());
0239: fb.writeDWord(getUDWord());
0240: break;
0241: case 7: // int
0242: fb.writeDWord(getUDWord());
0243: break;
0244: case 8: // dictionary lookup 1 byte
0245: fb.writeByte(getUByte());
0246: break;
0247: case 9: // dictionary lookup 2 bytes
0248: fb.writeWord(getUWord());
0249: break;
0250: default:
0251: // since we don't know what is this it's safer to skip everything
0252: // it has to be investigated further
0253: // after this while loop will break !
0254: body.getTo(fb, nextPos - getPos());
0255: break;
0256: }
0257: }
0258: fob.writeWord(fb.getSize());
0259: fob.writeFOB(fb);
0260: }
0261: break;
0262: }
0263: case Actions.JumpIfTrue:
0264: case Actions.Jump: {
0265: fob.writeWord(2);
0266: int offset = getWord();
0267: int target_off = getPos() + offset;
0268: if (offset <= 0) {
0269: int new_off = new_offs[target_off]
0270: - (fob.getPos() + 2); // has to be negative
0271: fob.writeWord(new_off);
0272: } else {
0273: new_offs[target_off] = -1; // mark this offset as having forward reference (just for optimization)
0274: addForwardRef(forward_refs, new ForwardRef(fob
0275: .getPos(), target_off));
0276: fob.skip(2);
0277: }
0278: break;
0279: }
0280: case Actions.GotoExpression:
0281: case Actions.GetURL2:
0282: case Actions.WaitForFrameExpression:
0283: fob.writeWord(1);
0284: fob.writeByte(getUByte());
0285: break;
0286: case Actions.CallFrame:
0287: fob.writeWord(0);
0288: break;
0289: case Actions.ConstantPool: {
0290: int num = getUWord();
0291: String[] strings = new String[num];
0292: int len = 2;
0293: for (int i = 0; i < num; i++) {
0294: String c = getString();
0295: c = context.apply(c);
0296: strings[i] = c;
0297: len += c.length() + 1;
0298: }
0299: fob.writeWord(len);
0300: fob.writeWord(num);
0301: for (int i = 0; i < num; i++) {
0302: fob.writeStringZ(strings[i]);
0303: }
0304: break;
0305: }
0306: case Actions.With: {
0307: String with = getString();
0308: with = context.apply(with);
0309: fob.writeWord(with.length() + 1);
0310: fob.writeStringZ(with);
0311: break;
0312: }
0313: // name (STR), parmsNum (WORD), parms (STR*parmsNum), codeSize (WORD)
0314: // we need to generate correct codesize value
0315: case Actions.DefineFunction: {
0316: fob.writeWord(length); // ??? about this length, it may be dangerous
0317: fob.writeStringZ(getString());
0318: int num = getUWord();
0319: fob.writeWord(num);
0320: for (int i = 0; i < num; i++)
0321: fob.writeStringZ(getString());
0322: int codesize = getUWord();
0323: int target_off = getPos() + codesize;
0324: new_offs[target_off] = -1; // mark this offset as having forward reference (just for optimization)
0325: addForwardRef(forward_refs, new ForwardRef(
0326: fob.getPos(), target_off));
0327: fob.skip(2);
0328: break;
0329: }
0330: default:
0331: if (hasLength) {
0332: fob.writeWord(length);
0333: body.getTo(fob, length);
0334: }
0335: break;
0336: }
0337: setPos(nextPos);
0338: }
0339: body = fob;
0340: }
0341:
0342: /**
0343: * Gets length of the program
0344: *
0345: * @return length of the program
0346: */
0347: public int getLength() {
0348: return body.getSize() + 1;
0349: }
0350:
0351: public void write(FlashOutput fob) {
0352: fob.writeFOB(body);
0353: fob.writeByte(0); // end
0354: }
0355:
0356: public void printContent(PrintStream out, String indent) {
0357: int origPos = getPos();
0358: try {
0359: out.println(indent + "Actions: ");
0360: setPos(0);
0361:
0362: String[] cpool = null;
0363:
0364: for (;;) {
0365: int offset = getPos();
0366: int code = getUByte();
0367: boolean hasLength = (code & 0x80) != 0;
0368: int length = hasLength ? getUWord() : 0;
0369: int nextPos = getPos() + length;
0370:
0371: out.print(indent + " " + Util.w2h(offset) + ": "
0372: + Actions.getActionName(code) + " ");
0373: switch (code) {
0374: case Actions.None:
0375: out.println();
0376: setPos(nextPos);
0377: return;
0378: case Actions.GotoFrame:
0379: out.println(getUWord());
0380: break;
0381: case Actions.GetURL:
0382: out.println("url='" + getString() + "' target='"
0383: + getString() + "'");
0384: break;
0385: case Actions.WaitForFrame:
0386: out.println("frame=" + getUWord() + " skipcount="
0387: + getUByte());
0388: break;
0389: case Actions.SetTarget:
0390: out.println("target='" + getString() + "'");
0391: break;
0392: case Actions.GotoLabel:
0393: out.println("label='" + getString() + "'");
0394: break;
0395: case Actions.PushData: {
0396: out.println("values: ");
0397: for (int l = length; l > 0;) {
0398: int type = getUByte();
0399: l--;
0400: switch (type) {
0401: case 0:
0402: String ss = getString();
0403: out.println(indent + " string='"
0404: + ss + "'");
0405: l -= ss.length() + 1;
0406: break;
0407: case 1:
0408: float flt = Float
0409: .intBitsToFloat(getUDWord());
0410: out.println(indent + " float="
0411: + flt);
0412: l -= 4;
0413: break;
0414: case 2:
0415: out.println(indent + " NULL");
0416: break;
0417: case 3:
0418: out.println(indent + " undefined");
0419: break;
0420: case 4:
0421: out.println(indent + " register="
0422: + getUByte());
0423: l--;
0424: break;
0425: case 5:
0426: out.println(indent + " boolean="
0427: + (getUByte() != 0));
0428: l--;
0429: break;
0430: case 6:
0431: long dbits = (((long) getUDWord()) << 32)
0432: | (((long) getUDWord()) & 0xffffffffL);
0433: double dbl = Double.longBitsToDouble(dbits);
0434: out.println(indent + " double="
0435: + dbl);
0436: l -= 8;
0437: break;
0438: case 7:
0439: int ival = getUDWord();
0440: out.println(indent + " int="
0441: + ival + " (hex: " + Util.d2h(ival)
0442: + ")");
0443: l -= 4;
0444: break;
0445: case 8: {
0446: int idx = getUByte();
0447: String val = cpool != null
0448: && idx < cpool.length ? cpool[idx]
0449: : "<<<error>>>";
0450: out.println(indent
0451: + " pool_index=" + idx
0452: + " -> " + val);
0453: l--;
0454: break;
0455: }
0456: case 9: {
0457: int idx = getUWord();
0458: String val = cpool != null
0459: && idx < cpool.length ? cpool[idx]
0460: : "<<<error>>>";
0461: out.println(indent
0462: + " pool_index=" + idx
0463: + " -> " + val);
0464: l -= 2;
0465: break;
0466: }
0467: }
0468: }
0469: break;
0470: }
0471: case Actions.JumpIfTrue:
0472: case Actions.Jump: {
0473: int off = getWord();
0474: out.println("offset=" + off + " (goto "
0475: + Util.w2h(getPos() + off) + ")");
0476: break;
0477: }
0478: case Actions.GotoExpression:
0479: case Actions.GetURL2:
0480: case Actions.WaitForFrameExpression:
0481: out.println("byte=" + getUByte());
0482: break;
0483: case Actions.ConstantPool: {
0484: int num = getUWord();
0485: cpool = new String[num];
0486: out.println("constants=" + num);
0487: for (int i = 0; i < num; i++) {
0488: out.println(indent + " constpool[" + i
0489: + "]='" + (cpool[i] = getString())
0490: + "'");
0491: }
0492: break;
0493: }
0494: // name (STR), parmsNum (WORD), parms (STR*parmsNum), codeSize (WORD) /*, code (UI8*codeSize)*/
0495: case Actions.DefineFunction: {
0496: String name = getString();
0497: int num = getUWord();
0498: out.print("function " + name + "( ");
0499: for (int i = 0; i < num; i++) {
0500: out.print(getString());
0501: if (i != num - 1)
0502: out.print(", ");
0503: }
0504: int codesize = getUWord();
0505: out.println(" ) codesize=" + codesize + " (until "
0506: + Util.w2h(getPos() + codesize) + ")");
0507: break;
0508: }
0509: case Actions.With:
0510: out.println("withblock='" + getString() + "'");
0511: break;
0512: default:
0513: // if( hasLength ) body.getSkip( length ); this will be done after switch
0514: out.println();
0515: break;
0516: }
0517:
0518: // Buffer capacity is not ensured in this function since it
0519: // assumes that it will be called only when the buffer is
0520: // complete. To prevent array overflow, check that the next
0521: // position is not >= current buf length. See bug 4589. -pk
0522: if (nextPos >= body.getBuf().length) {
0523: return;
0524: }
0525:
0526: setPos(nextPos);
0527: }
0528: } finally {
0529: setPos(origPos);
0530: }
0531: }
0532:
0533: protected boolean _isConstant() {
0534: setPos(0);
0535:
0536: for (;;) {
0537: int code = getUByte();
0538: boolean hasLength = (code & 0x80) != 0;
0539: int length = hasLength ? getUWord() : 0;
0540: int pos = getPos();
0541:
0542: switch (code) {
0543: case Actions.None:
0544: return true;
0545: case Actions.GetURL:
0546: if (Util.hasVar(getString())
0547: || Util.hasVar(getString()))
0548: return false;
0549: break;
0550: case Actions.SetTarget:
0551: case Actions.GotoLabel:
0552: if (Util.hasVar(getString()))
0553: return false;
0554: break;
0555: case Actions.PushData: {
0556: // quick check whether we have vars or not
0557: int l = length;
0558: while (--l >= 0) {
0559: if (getUByte() == '{')
0560: return false;
0561: }
0562: /* if( getUByte() == 0 ) {
0563: if( Util.hasVar(getString()) ) return false;
0564: }*/
0565: break;
0566: }
0567: case Actions.ConstantPool: {
0568: int num = getUWord();
0569: for (int i = 0; i < num; i++) {
0570: if (Util.hasVar(getString()))
0571: return false;
0572: }
0573: break;
0574: }
0575: case Actions.With:
0576: if (Util.hasVar(getString()))
0577: return false;
0578: break;
0579: }
0580: setPos(pos + length);
0581: }
0582: }
0583:
0584: public FlashItem getCopy(ScriptCopier copier) {
0585: return new Program(body.getCopy());
0586: }
0587:
0588: public FlashBuffer body() {
0589: return body;
0590: }
0591:
0592: // ------------------------------------------------------------------------- //
0593: // API //
0594: // ------------------------------------------------------------------------- //
0595:
0596: /**
0597: * End of the program
0598: * @since flash 3
0599: */
0600: public void none() {
0601: body.writeByte(Actions.None);
0602: }
0603:
0604: /**
0605: * Instructs the player to go to the next frame in the current movie.
0606: * @since flash 3
0607: */
0608: public void nextFrame() {
0609: body.writeByte(Actions.NextFrame);
0610: }
0611:
0612: /**
0613: * Instructs the player to go to the previous frame in the current movie.
0614: * @since flash 3
0615: */
0616: public void prevFrame() {
0617: body.writeByte(Actions.PrevFrame);
0618: }
0619:
0620: /**
0621: * Instructs the player to start playing at the current frame.
0622: * @since flash 3
0623: */
0624: public void play() {
0625: body.writeByte(Actions.Play);
0626: }
0627:
0628: /**
0629: * Instructs the player to stop playing the movie at the current frame.
0630: * @since flash 3
0631: */
0632: public void stop() {
0633: body.writeByte(Actions.Stop);
0634: }
0635:
0636: /**
0637: * Gets a variable’s value.
0638: * <P>
0639: * <OL>
0640: * <LI>Pops name off the stack, which is a string naming the variable to get.
0641: * <LI>Pushes the value of the variable to the stack.
0642: * </OL>
0643: * @since flash 4
0644: */
0645: public void eval() {
0646: body.writeByte(Actions.Eval);
0647: }
0648:
0649: /**
0650: * An equivalent of {@link #eval}.
0651: *
0652: * @see #eval
0653: * @since flash 4
0654: */
0655: public void getVar() {
0656: eval();
0657: }
0658:
0659: /**
0660: * Sets a variable.
0661: * <P>
0662: * <OL>
0663: * <LI>Pops value off the stack.
0664: * <LI>Pops name off the stack, which is a string naming the variable to set.
0665: * <LI>Sets the variable name in the current execution context to value.
0666: * </OL>
0667: * A variable in another execution context may be referenced by prefixing the variable name with
0668: * the target path and a colon. For example: /A/B:FOO references variable FOO in movie
0669: * clip with target path /A/B.
0670: * @since flash 4
0671: */
0672: public void setVar() {
0673: body.writeByte(Actions.SetVariable);
0674: }
0675:
0676: /**
0677: * Toggle the display between high and low quality.
0678: * @since flash 3
0679: */
0680: public void toggleQuality() {
0681: body.writeByte(Actions.ToggleQuality);
0682: }
0683:
0684: /**
0685: * Instructs the player to stop playing all sounds.
0686: * @since flash 3
0687: */
0688: public void stopSounds() {
0689: body.writeByte(Actions.StopSounds);
0690: }
0691:
0692: /**
0693: * Adds two numbers.
0694: * <P>
0695: * <OL>
0696: * <LI>Pops value A off the stack.
0697: * <LI>Pops value B off the stack.
0698: * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
0699: * <LI>The numbers are added.
0700: * <LI>Pushes the result, A+B, to the stack.
0701: * </OL>
0702: * @since flash 4
0703: */
0704: public void add() {
0705: body.writeByte(Actions.Add);
0706: }
0707:
0708: /**
0709: * Subtracts two numbers.
0710: * <P>
0711: * <OL>
0712: * <LI>Pops value A off the stack.
0713: * <LI>Pops value B off the stack.
0714: * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
0715: * <LI>A is subtracted from B.
0716: * <LI>Pushes the result, A-B, to the stack.
0717: * </OL>
0718: * @since flash 4
0719: */
0720: public void subtract() {
0721: body.writeByte(Actions.Subtract);
0722: }
0723:
0724: /**
0725: * Multiplies two numbers.
0726: * <P>
0727: * <OL>
0728: * <LI>Pops value A off the stack.
0729: * <LI>Pops value B off the stack.
0730: * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
0731: * <LI>The numbers are multiplied.
0732: * <LI>Pushes the result, A*B, to the stack.
0733: * </OL>
0734: * @since flash 4
0735: */
0736: public void multiply() {
0737: body.writeByte(Actions.Multiply);
0738: }
0739:
0740: /**
0741: * Divides two numbers.
0742: * <P>
0743: * <OL>
0744: * <LI>Pops value A off the stack.
0745: * <LI>Pops value B off the stack.
0746: * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
0747: * <LI>B is divided by A.
0748: * <LI>Pushes the result, B/A, to the stack.
0749: * <LI>If A is zero, the result is the string #ERROR#.
0750: * </OL>
0751: * Note: When playing a Flash 5 .SWF, NaN, Infinity or –Infinity is pushed to the stack instead of #ERROR#.
0752: * @since flash 4
0753: */
0754: public void divide() {
0755: body.writeByte(Actions.Divide);
0756: }
0757:
0758: /**
0759: * Tests two numbers for equality.
0760: * <P>
0761: * <OL>
0762: * <LI>Pops value A off the stack.
0763: * <LI>Pops value B off the stack.
0764: * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
0765: * <LI>The numbers are compared for equality.
0766: * <LI>If the numbers are equal, a 1 (TRUE) is pushed to the stack.
0767: * <LI>Otherwise, a 0 is pushed to the stack.
0768: * </OL>
0769: * Note: When playing a Macromedia Flash 5 .SWF, true is pushed to the stack instead of 1,
0770: * and false is pushed to the stack instead of 0.
0771: * @since flash 4
0772: */
0773: public void equal() {
0774: body.writeByte(Actions.Equal);
0775: }
0776:
0777: /**
0778: * Tests if a number is less than another number.
0779: * <P>
0780: * <OL>
0781: * <LI>Pops value A off the stack.
0782: * <LI>Pops value B off the stack.
0783: * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
0784: * <LI>The numbers are compared for equality.
0785: * <LI>If B < A, a 1 is pushed to the stack; otherwise, a 0 is pushed to the stack.
0786: * </OL>
0787: * Note: When playing a Macromedia Flash 5 .SWF, true is pushed to the stack instead of 1,
0788: * and false is pushed to the stack instead of 0.
0789: * @since flash 4
0790: */
0791: public void lessThan() {
0792: body.writeByte(Actions.LessThan);
0793: }
0794:
0795: /**
0796: * Performs a logical AND of two numbers.
0797: * <P>
0798: * <OL>
0799: * <LI>Pops value A off the stack.
0800: * <LI>Pops value B off the stack.
0801: * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
0802: * <LI>If both numbers are nonzero, a 1 is pushed to the stack; otherwise, a 0 is pushed to the stack.
0803: * </OL>
0804: * Note: When playing a Macromedia Flash 5 .SWF, true is pushed to the stack instead of 1,
0805: * and false is pushed to the stack instead of 0.
0806: * @since flash 4
0807: */
0808: public void logicalAnd() {
0809: body.writeByte(Actions.LogicalAnd);
0810: }
0811:
0812: /**
0813: * Performs a logical OR of two numbers.
0814: * <P>
0815: * <OL>
0816: * <LI>Pops value A off the stack.
0817: * <LI>Pops value B off the stack.
0818: * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
0819: * <LI>If either numbers is nonzero, a 1 is pushed to the stack; otherwise, a 0 is pushed to the stack.
0820: * </OL>
0821: * Note: When playing a Macromedia Flash 5 .SWF, true is pushed to the stack instead of 1,
0822: * and false is pushed to the stack instead of 0.
0823: * @since flash 4
0824: */
0825: public void logicalOr() {
0826: body.writeByte(Actions.LogicalOr);
0827: }
0828:
0829: /**
0830: * Performs a logical NOT of a number.
0831: * <P>
0832: * Note that in Macromedia Flash 5 .SWF files, the ActionNot action
0833: * converts its argument to a boolean, and pushes a result of type boolean.
0834: * In Macromedia Flash 4 .SWF files, the argument and result are numbers.
0835: * <P>
0836: * <OL>
0837: * <LI>Pops value A off the stack.
0838: * <LI>Pops value B off the stack.
0839: * <LI>A and B are converted to floating-point; non-numeric values evaluate to 0.
0840: * <LI>The numbers are compared for equality.
0841: * <LI>If the numbers are equal, a 1 (TRUE) is pushed to the stack.
0842: * <LI>Otherwise, a 0 is pushed to the stack.
0843: * </OL>
0844: * Note: When playing a Macromedia Flash 5 .SWF, true is pushed to the stack instead of 1,
0845: * and false is pushed to the stack instead of 0.
0846: * @since flash 4
0847: */
0848: public void logicalNot() {
0849: body.writeByte(Actions.LogicalNot);
0850: }
0851:
0852: /**
0853: * Tests two strings for equality.
0854: * <P>
0855: * <OL>
0856: * <LI>Pops value A off the stack.
0857: * <LI>Pops value B off the stack.
0858: * <LI>A and B are compared as strings. The comparison is case-sensitive.
0859: * <LI>If the strings are equal, a 1 (TRUE) is pushed to the stack.
0860: * <LI>Otherwise, a 0 is pushed to the stack.
0861: * </OL>
0862: * Note: When playing a Macromedia Flash 5 .SWF, true is pushed to the stack instead of 1,
0863: * and false is pushed to the stack instead of 0.
0864: * @since flash 4
0865: */
0866: public void stringEqual() {
0867: body.writeByte(Actions.StringEqual);
0868: }
0869:
0870: /**
0871: * Computes the length of a string.
0872: * <P>
0873: * <OL>
0874: * <LI>Pops a string off the stack.
0875: * <LI>The length of the string is calculated and pushed to the stack.
0876: * </OL>
0877: * @since flash 4
0878: */
0879: public void stringLength() {
0880: body.writeByte(Actions.StringLength);
0881: }
0882:
0883: /**
0884: * Tests if a string is less than another string.
0885: * <P>
0886: * <OL>
0887: * <LI>Pops value A off the stack.
0888: * <LI>Pops value B off the stack.
0889: * <LI>If B < A using a byte-by-byte comparison, a 1 is pushed to the stack;
0890: * otherwise, a 0 is pushed to the stack.
0891: * </OL>
0892: * Note: When playing a Macromedia Flash 5 .SWF, true is pushed to the stack instead of 1,
0893: * and false is pushed to the stack instead of 0.
0894: * @since flash 4
0895: */
0896: public void stringLessThan() {
0897: body.writeByte(Actions.StringLessThan);
0898: }
0899:
0900: /**
0901: * Extracts a substring from a string.
0902: * <P>
0903: * <OL>
0904: * <LI>Pops number <B>count</B> off the stack.
0905: * <LI>Pops number <B>index</B> off the stack.
0906: * <LI>Pops string <B>string</B> off the stack.
0907: * <LI>The substring of <B>string</B> starting at the <B>index</B>’th character and
0908: * <B>count</B> characters in length is pushed to the stack.
0909: * <LI>If either <B>index</B> or <B>count</B> do not evaluate to integers, the result
0910: * is the empty string.
0911: * </OL>
0912: * @since flash 4
0913: */
0914: public void subString() {
0915: body.writeByte(Actions.SubString);
0916: }
0917:
0918: /**
0919: * Concatenates two strings.
0920: * <P>
0921: * <OL>
0922: * <LI>Pops value A off the stack.
0923: * <LI>Pops value B off the stack.
0924: * <LI>The concatenation BA is pushed to the stack.
0925: * </OL>
0926: * @since flash 4
0927: */
0928: public void addString() {
0929: body.writeByte(Actions.StringConcat);
0930: }
0931:
0932: /**
0933: * Computes the length of a string, multi-byte aware.
0934: * <P>
0935: * <OL>
0936: * <LI>Pops a string off the stack.
0937: * <LI>The length of the string in characters is calculated and pushed to the stack.
0938: * <LI>This is a multi-byte aware version of ActionStringLength.
0939: * On systems with double-byte support, a double-byte character is counted as a single character.
0940: * </OL>
0941: * @since flash 4
0942: */
0943: public void mbLength() {
0944: body.writeByte(Actions.MBLength);
0945: }
0946:
0947: /**
0948: * Converts ASCII to character code, multi-byte aware.
0949: * <P>
0950: * <OL>
0951: * <LI>Pops value off the stack.
0952: * <LI>The value is converted from a number to the corresponding character.
0953: * If the character is a 16-bit value (>= 256), a double-byte character
0954: * is constructed with the first byte containing the high-order byte,
0955: * and the second byte containing the low-order byte.
0956: * <LI>The resulting character is pushed to the stack.
0957: * </OL>
0958: * @since flash 4
0959: */
0960: public void mbChr() {
0961: body.writeByte(Actions.MBChr);
0962: }
0963:
0964: /**
0965: * Converts character code to ASCII, multi-byte aware.
0966: * <P>
0967: * <OL>
0968: * <LI>Pops value off the stack.
0969: * <LI>The first character of value is converted to a numeric character code.
0970: * If the first character of value is a double-byte character, a 16-bit value
0971: * is constructed with the first byte as the high order byte and the second byte
0972: * as the low order byte.
0973: * <LI>The resulting character code is pushed to the stack.
0974: * </OL>
0975: * @since flash 4
0976: */
0977: public void mbOrd() {
0978: body.writeByte(Actions.MBOrd);
0979: }
0980:
0981: /**
0982: * Extracts a substring from a string, multi-byte aware.
0983: * <P>
0984: * <OL>
0985: * <LI>Pops number <B>count</B> off the stack.
0986: * <LI>Pops number <B>index</B> off the stack.
0987: * <LI>Pops string <B>string</B> off the stack.
0988: * <LI>The substring of <B>string</B> starting at the <B>index</B>’th character and
0989: * <B>count</B> characters in length is pushed to the stack.
0990: * <LI>If either <B>index</B> or <B>count</B> do not evaluate to integers, the result
0991: * is the empty string.
0992: * <LI>This is a multi-byte aware version of ActionStringExtract. index and count are
0993: * treated as character indices, counting double-byte characters as single characters.
0994: * </OL>
0995: * @since flash 4
0996: */
0997: public void mbSubString() {
0998: body.writeByte(Actions.MBSubString);
0999: }
1000:
1001: /**
1002: * Converts to integer.
1003: * <P>
1004: * <OL>
1005: * <LI>Pops a value off the stack.
1006: * <LI>The value is converted to a number.
1007: * <LI>Next, any digits after the decimal point are discarded, resulting in an integer.
1008: * <LI>The resulting integer is pushed to the stack.
1009: * </OL>
1010: * @since flash 4
1011: */
1012: public void toInt() {
1013: body.writeByte(Actions.Int);
1014: }
1015:
1016: /**
1017: * Converts character code to ASCII.
1018: * <P>
1019: * <OL>
1020: * <LI>Pops value off the stack.
1021: * <LI>The first character of value is converted to a numeric ASCII character code.
1022: * <LI>The resulting character code is pushed to the stack.
1023: * </OL>
1024: * @since flash 4
1025: */
1026: public void ord() {
1027: body.writeByte(Actions.Ord);
1028: }
1029:
1030: /**
1031: * Converts ASCII to character code.
1032: * <P>
1033: * <OL>
1034: * <LI>Pops value off the stack.
1035: * <LI>The value is converted from a number to the corresponding ASCII character..
1036: * <LI>The resulting character is pushed to the stack.
1037: * </OL>
1038: * @since flash 4
1039: */
1040: public void chr() {
1041: body.writeByte(Actions.Chr);
1042: }
1043:
1044: /**
1045: * Set current context, stack-based
1046: * <P>
1047: * <OL>
1048: * <LI>Pops target off the stack and makes it the current active context.
1049: * <LI>This action behaves exactly like the original ActionSetTarget from
1050: * Macromedia Flash 3, but is stack-based to enable the target path to be the
1051: * result of expression evaluation.
1052: * </OL>
1053: * @since flash 4
1054: */
1055: public void setTarget() {
1056: body.writeByte(Actions.SetTargetExpression);
1057: }
1058:
1059: /**
1060: * Gets a movie property
1061: * <P>
1062: * <OL>
1063: * <LI>Pops index off the stack.
1064: * <LI>Pops target off the stack.
1065: * <LI>Retrieves the value of the property enumerated as index from
1066: * the movie clip with target path target and pushes the value to the stack.
1067: * </OL>
1068: * @since flash 4
1069: */
1070: public void getProperty() {
1071: body.writeByte(Actions.GetProperty);
1072: }
1073:
1074: /**
1075: * Sets a movie property.
1076: * <P>
1077: * <OL>
1078: * <LI>Pops value off the stack.
1079: * <LI>Pops index off the stack.
1080: * <LI>Pops target off the stack.
1081: * <LI>Sets the property enumerated as index in the movie clip
1082: * with target path target to the value value.
1083: * </OL>
1084: * @since flash 4
1085: */
1086: public void setProperty() {
1087: body.writeByte(Actions.SetProperty);
1088: }
1089:
1090: /**
1091: * Clones a sprite.
1092: * <P>
1093: * <OL>
1094: * <LI>Pops depth off the stack.
1095: * <LI>Pops target off the stack.
1096: * <LI>Pops source off the stack.
1097: * <LI>Duplicates movie clip source, giving the new instance
1098: * the name target, at z-order depth depth.
1099: * </OL>
1100: * @since flash 4
1101: */
1102: public void cloneClip() {
1103: body.writeByte(Actions.DuplicateClip);
1104: }
1105:
1106: /**
1107: * Removes a clone sprite.
1108: * <P>
1109: * <OL>
1110: * <LI>Pops target off the stack.
1111: * <LI>Removes the clone movie clip identified by target path target.
1112: * </OL>
1113: * @since flash 4
1114: */
1115: public void removeClip() {
1116: body.writeByte(Actions.RemoveClip);
1117: }
1118:
1119: /**
1120: * Starts dragging a movie clip.
1121: * <P>
1122: * <OL>
1123: * <LI>Pops target off the stack. target identifies the movie clip to be dragged.
1124: * <LI>Pops lockcenter off the stack. If lockcenter evaluates to a nonzero value,
1125: * the center of the dragged movie clip is locked to the mouse position.
1126: * Otherwise, the movie clip moves relatively to the mouse position when
1127: * the drag started.
1128: * <LI>Pops constrain off the stack.
1129: * <LI>If constrain evaluates to a nonzero value:
1130: * <OL>
1131: * <LI>Pops y2 off the stack.
1132: * <LI>Pops x2 off the stack.
1133: * <LI>Pops y1 off the stack.
1134: * <LI>Pops x1 off the stack.
1135: * </OL>
1136: * </OL>
1137: * @since flash 4
1138: */
1139: public void startDrag() {
1140: body.writeByte(Actions.StartDragMovie);
1141: }
1142:
1143: /**
1144: * Ends drag operation.
1145: * <P>
1146: * <OL>
1147: * <LI>Ends the drag operation in progress, if any.
1148: * </OL>
1149: * @since flash 4
1150: */
1151: public void endDrag() {
1152: body.writeByte(Actions.StopDragMovie);
1153: }
1154:
1155: /**
1156: * Calculates a random number.
1157: * <P>
1158: * <OL>
1159: * <LI>Pops maximum off the stack.
1160: * <LI>Calculates a random number, an integer in the range 0 ... (maximum-1)
1161: * <LI>This random number is pushed to the stack.
1162: * </OL>
1163: * @since flash 4
1164: */
1165: public void random() {
1166: body.writeByte(Actions.Random);
1167: }
1168:
1169: /**
1170: * Reports milliseconds since player started.
1171: * <P>
1172: * <OL>
1173: * <LI>Calculates the number of milliseconds since the Player was started (an integer).
1174: * <LI>This number is pushed to the stack.
1175: * </OL>
1176: * @since flash 4
1177: */
1178: public void getTimer() {
1179: body.writeByte(Actions.GetTimer);
1180: }
1181:
1182: /**
1183: * Instructs the player to go to the specified frame in the current movie.
1184: *
1185: * @param frame frame number
1186: * @since flash 3
1187: */
1188: public void gotoFrame(int frame) {
1189: body.writeByte(Actions.GotoFrame);
1190: body.writeWord(2);
1191: body.writeWord(frame);
1192: }
1193:
1194: /**
1195: * Instructs the player to get the URL specified by UrlString.
1196: * The URL can be of any type, including an HTML file, an image
1197: * or another SWF movie. If the movie is playing in a browser,
1198: * the URL will be displayed in the frame specified by TargetString.
1199: * The special target names _level0 and _level1 are used to load another
1200: * SWF movie into levels 0 and 1 respectively.
1201: *
1202: * @param url specified url
1203: * @param target target
1204: * @since flash 3
1205: */
1206: public void getURL(String url, String target) {
1207: body.writeByte(Actions.GetURL);
1208: body.writeWord((url == null ? 0 : url.length())
1209: + (target == null ? 0 : target.length()) + 2); // 2 - length of end zeroes
1210: body.writeStringZ(url == null ? "" : url);
1211: body.writeStringZ(target == null ? "" : target);
1212: }
1213:
1214: /**
1215: * Instructs the player to wait until the specified frame,
1216: * otherwise skip the specified number of actions.
1217: *
1218: * @param frame specified frame
1219: * @param skip specified number of actions to skip
1220: * @since flash 3
1221: */
1222: public void waitForFrame(int frame, int skip) {
1223: body.writeByte(Actions.WaitForFrame);
1224: body.writeWord(3);
1225: body.writeWord(frame);
1226: body.writeByte(skip);
1227: }
1228:
1229: /**
1230: * Instructs the player to change the context of subsequent actions,
1231: * so they apply to a named object (TargetName) rather than the current movie.
1232: * <P>
1233: * For example, the SetTarget action can be used to control the timeline of a sprite
1234: * object. The following sequence of actions sends a sprite called "spinner" to the
1235: * first frame in its timeline:<BR>
1236: * <OL>
1237: * <LI>SetTarget "spinner"
1238: * <LI>GotoFrame zero
1239: * <LI>SetTarget "" (empty string)
1240: * <LI>End of actions. (Action code = 0)
1241: * </OL>
1242: * <P>
1243: * All actions following SetTarget "spinner" apply to the spinner
1244: * object until SetTarget "", which sets the action context back to
1245: * the current movie.
1246: * For a complete discussion of target names see DefineSprite.
1247: *
1248: * @param target name of the target
1249: * @since flash 3
1250: */
1251: public void setTarget(String target) {
1252: body.writeByte(Actions.SetTarget);
1253: body.writeWord(target.length() + 1); // 1 - length of end zero
1254: body.writeStringZ(target);
1255: }
1256:
1257: /**
1258: * Instructs the player to go to frame associated with the specified label.
1259: * A label can be attached to a frame with the FrameLabel tag.
1260: *
1261: * @param label specified frame label
1262: * @since flash 3
1263: */
1264: public void gotoLabel(String label) {
1265: body.writeByte(Actions.GotoLabel);
1266: body.writeWord(label.length() + 1); // 1 - length of end zero
1267: body.writeStringZ(label);
1268: }
1269:
1270: /**
1271: * Pops a value from the stack.
1272: * @since flash 4
1273: */
1274: public void pop() {
1275: body.writeByte(Actions.Pop);
1276: }
1277:
1278: /**
1279: * Pushes a string to the stack.
1280: *
1281: * @param data string to push
1282: * @since flash 4
1283: */
1284: public void push(String data) {
1285: body.writeByte(Actions.PushData);
1286: body.writeWord(data.length() + 1 + 1);
1287: body.writeByte(0);
1288: body.writeStringZ(data);
1289: }
1290:
1291: /**
1292: * Pushes a float to the stack.
1293: *
1294: * @param data float to push
1295: * @since flash 4
1296: */
1297: public void push(float data) {
1298: body.writeByte(Actions.PushData);
1299: body.writeWord(4 + 1);
1300: body.writeByte(1);
1301: body.writeDWord(Float.floatToIntBits(data));
1302: }
1303:
1304: /**
1305: * Pushes an int to the stack.
1306: *
1307: * @param data int to push
1308: * @since flash 4
1309: */
1310: public void push(int data) {
1311: body.writeByte(Actions.PushData);
1312: body.writeWord(4 + 1);
1313: body.writeByte(7);
1314: body.writeDWord(data);
1315: }
1316:
1317: /**
1318: * Pushes constant index to the stack
1319: *
1320: * @since flash 5
1321: */
1322: public void push(Short const_idx) {
1323: body.writeByte(Actions.PushData);
1324: int idx = const_idx.intValue();
1325: if (idx > 255) {
1326: body.writeWord(3);
1327: body.writeByte(9);
1328: body.writeWord(idx);
1329: } else {
1330: body.writeWord(2);
1331: body.writeByte(8);
1332: body.writeByte(idx);
1333: }
1334: }
1335:
1336: /**
1337: * Pushes array of data to the stack
1338: * <P>
1339: * <ul>
1340: * <li>String - is pushed as string
1341: * <li>Integer - is pushed as int
1342: * <li>Double - is pushed as double
1343: * <li>Float - is pushed as float
1344: * <li>Boolean - is pushed as bool
1345: * <li>Byte - is pushed as index in constant pool
1346: * <li>Short - is pushed as index in constant pool
1347: * <li>null - is pushed as null
1348: *
1349: * @param data array of data
1350: * @since flash 5
1351: */
1352: public void push(Object[] data) {
1353: FlashBuffer fb = new FlashBuffer(40);
1354: for (int i = 0; i < data.length; i++) {
1355: Object o = data[i];
1356: if (o instanceof String) {
1357: fb.writeByte(0);
1358: fb.writeStringZ((String) o);
1359: } else if (o instanceof Float) {
1360: fb.writeByte(1);
1361: fb.writeDWord(Float.floatToIntBits(((Float) o)
1362: .floatValue()));
1363: } else if (o instanceof Boolean) {
1364: fb.writeByte(5);
1365: fb.writeByte(((Boolean) o).booleanValue() ? 1 : 0);
1366: } else if (o instanceof Double) {
1367: fb.writeByte(6);
1368: long dbits = Double.doubleToLongBits(((Double) o)
1369: .doubleValue());
1370: fb.writeDWord((int) (dbits >>> 32));
1371: fb.writeDWord((int) (dbits & 0xffffffffL));
1372: } else if (o instanceof Integer) {
1373: fb.writeByte(7);
1374: fb.writeDWord(((Integer) o).intValue());
1375: } else if (o instanceof Short || o instanceof Byte) {
1376: int idx = ((Number) o).intValue();
1377: if (idx > 255) {
1378: fb.writeByte(9);
1379: fb.writeWord(idx);
1380: } else {
1381: fb.writeByte(8);
1382: fb.writeByte(idx);
1383: }
1384: } else if (o == null) {
1385: fb.writeByte(2);
1386: }
1387: }
1388: body.writeByte(Actions.PushData);
1389: body.writeWord(fb.getSize());
1390: body.writeFOB(fb);
1391: }
1392:
1393: /**
1394: * Pushes an object to the stack
1395: * <P>
1396: * <ul>
1397: * <li>String - is pushed as string
1398: * <li>Integer - is pushed as int
1399: * <li>Double - is pushed as double
1400: * <li>Float - is pushed as float
1401: * <li>Boolean - is pushed as bool
1402: * <li>Byte - is pushed as index in constant pool
1403: * <li>Short - is pushed as index in constant pool
1404: * <li>null - is pushed as null
1405: *
1406: * @param o data
1407: * @since flash 5
1408: */
1409: public void push(Object o) {
1410: body.writeByte(Actions.PushData);
1411: if (o instanceof String) {
1412: body.writeWord(((String) o).length() + 2);
1413: body.writeByte(0);
1414: body.writeStringZ((String) o);
1415: } else if (o instanceof Float) {
1416: body.writeWord(4 + 1);
1417: body.writeByte(1);
1418: body.writeDWord(Float.floatToIntBits(((Float) o)
1419: .floatValue()));
1420: } else if (o instanceof Boolean) {
1421: body.writeWord(1 + 1);
1422: body.writeByte(5);
1423: body.writeByte(((Boolean) o).booleanValue() ? 1 : 0);
1424: } else if (o instanceof Double) {
1425: body.writeWord(8 + 1);
1426: body.writeByte(6);
1427: long dbits = Double.doubleToLongBits(((Double) o)
1428: .doubleValue());
1429: body.writeDWord((int) (dbits >>> 32));
1430: body.writeDWord((int) (dbits & 0xffffffffL));
1431: } else if (o instanceof Integer) {
1432: body.writeWord(4 + 1);
1433: body.writeByte(7);
1434: body.writeDWord(((Integer) o).intValue());
1435: } else if (o instanceof Short || o instanceof Byte) {
1436: int idx = ((Number) o).intValue();
1437: if (idx > 255) {
1438: body.writeWord(2 + 1);
1439: body.writeByte(9);
1440: body.writeWord(idx);
1441: } else {
1442: body.writeWord(1 + 1);
1443: body.writeByte(8);
1444: body.writeByte(idx);
1445: }
1446: } else if (o == null) {
1447: body.writeWord(0 + 1);
1448: body.writeByte(2);
1449: }
1450: }
1451:
1452: /**
1453: * Unconditional branch.
1454: * <P>
1455: * <OL>
1456: * <LI>BranchOffset bytes are added to the instruction pointer in the execution stream.
1457: * <LI>The offsets is a signed quantity, enabling branches from –32,768 bytes to 32,767 bytes.
1458: * <LI>An offset of 0 points to the action directly after the ActionJump action.
1459: * </OL>
1460: *
1461: * @param offset specified offset
1462: * @since flash 4
1463: */
1464: public void jump(int offset) {
1465: body.writeByte(Actions.Jump);
1466: body.writeWord(2);
1467: body.writeWord(offset);
1468: }
1469:
1470: /**
1471: * Conditional Test and Branch.
1472: * <P>
1473: * <OL>
1474: * <LI>Pops Condition, a number, off the stack.
1475: * <LI>Tests if Condition is nonzero: If Condition is nonzero,
1476: * BranchOffset bytes are added to the instruction pointer in the execution stream.
1477: * </OL>
1478: * Note: When playing a Macromedia Flash 5 .SWF, Condition is converted to a boolean and compared to true, not 0.
1479: * The offset is a signed quantity, enabling branches from –32768 bytes to 32767 bytes.
1480: * An offset of 0 points to the action directly after the ActionIf action.
1481: *
1482: * @param offset specified offset
1483: * @since flash 4
1484: */
1485: public void jumpIfTrue(int offset) {
1486: body.writeByte(Actions.JumpIfTrue);
1487: body.writeWord(2);
1488: body.writeWord(offset);
1489: }
1490:
1491: /**
1492: * Calls a subroutine.
1493: * <P>
1494: * <OL>
1495: * <LI>Pops a value off the stack.
1496: * <LI>This value should be either a string matching a frame label, or a number
1497: * indicating a frame number.
1498: * <LI>The value may be prefixed by a target string identifying the movie clip that
1499: * contains the frame being called.
1500: * <LI>If the frame is successfully located, the actions in the target frame are executed.
1501: * After the actions in the target frame are executed, execution resumes at the instruction
1502: * after the ActionCall instruction.
1503: * <LI>If the frame cannot be found, nothing happens.
1504: * <LI>NOTE: This action's tag (0x9E) has the high bit set, which will waste a few bytes in SWF file size.
1505: * This is a bug.
1506: * </OL>
1507: * @since flash 4
1508: */
1509: public void callFrame() {
1510: body.writeByte(Actions.CallFrame);
1511: body.writeWord(0);
1512: }
1513:
1514: /**
1515: * Get URL, stack-based.
1516: * <P>
1517: * <OL>
1518: * <LI>Pops window off the stack. window specifies the target window,
1519: * which may be an empty string to indicate the current window.
1520: * <LI>Pops url off the stack. url which specifies the URL to be retrieved.
1521: * </OL>
1522: *
1523: * @param method Method specifies the method to use for the HTTP request. If (method and 0x40) != 0 then target is movie clip target,
1524: * NOT browser window target!
1525: * <UL>
1526: * <LI>A value of 0 indicates that this is not a form request,
1527: * so the movie clip’s variables should not be encoded and submitted.
1528: * <LI>A value of 1 specifies a HTTP GET request.
1529: * <LI>A value of 2 specifies a HTTP POST request.
1530: * <LI>If method is 1 (GET) or 2 (POST), the variables in the current
1531: * movie clip are submitted to the URL using the standard
1532: * x-www-urlencoded encoding and the HTTP request method specified by method.
1533: * </UL>
1534: * @since flash 4
1535: */
1536: public void getURL(int method) {
1537: body.writeByte(Actions.GetURL2);
1538: body.writeWord(1);
1539: body.writeByte(method);
1540: }
1541:
1542: /**
1543: * Get URL using GET method, stack-based.
1544: * <P>
1545: * <OL>
1546: * <LI>Pops window off the stack. window specifies the target window,
1547: * which may be an empty string to indicate the current window.
1548: * <LI>Pops url off the stack. url which specifies the URL to be retrieved.
1549: * </OL>
1550: *
1551: * @see #getURL(int)
1552: * @since flash 4
1553: */
1554: public void getURL_GET() {
1555: getURL(1);
1556: }
1557:
1558: /**
1559: * Get URL using POST method, stack-based.
1560: * <P>
1561: * <OL>
1562: * <LI>Pops window off the stack. window specifies the target window,
1563: * which may be an empty string to indicate the current window.
1564: * <LI>Pops url off the stack. url which specifies the URL to be retrieved.
1565: * </OL>
1566: *
1567: * @see #getURL(int)
1568: * @since flash 4
1569: */
1570: public void getURL_POST() {
1571: getURL(2);
1572: }
1573:
1574: /**
1575: * Go to frame and stop, stack-based.
1576: * <P>
1577: * <OL>
1578: * <LI>Pops <b>frame</b> off the stack.
1579: * <LI>If <b>frame</b> is a number, the next frame of the movie to be displayed
1580: * will be the <b>frame</b>’th frame in the current movie clip.
1581: * <LI>If <b>frame</b> is a string, <b>frame</b> is treated as a frame label.
1582: * If the specified label exists in the current movie clip,
1583: * the labeled frame will become the current frame. Otherwise, the action is ignored.
1584: * <LI>Either a frame or a number may be prefixed by a target path, e.g. /MovieClip:3 or /MovieClip:FrameLabel
1585: * </OL>
1586: * @since flash 4
1587: */
1588: public void gotoFrameAndStop() {
1589: body.writeByte(Actions.GotoExpression);
1590: body.writeWord(1);
1591: body.writeByte(0x00);
1592: }
1593:
1594: /**
1595: * Go to frame and play, stack-based.
1596: * <P>
1597: * <OL>
1598: * <LI>Pops <b>frame</b> off the stack.
1599: * <LI>If <b>frame</b> is a number, the next frame of the movie to be displayed
1600: * will be the <b>frame</b>’th frame in the current movie clip.
1601: * <LI>If <b>frame</b> is a string, <b>frame</b> is treated as a frame label.
1602: * If the specified label exists in the current movie clip,
1603: * the labeled frame will become the current frame. Otherwise, the action is ignored.
1604: * <LI>Either a frame or a number may be prefixed by a target path, e.g. /MovieClip:3 or /MovieClip:FrameLabel
1605: * </OL>
1606: * @since flash 4
1607: */
1608: public void gotoFrameAndPlay() {
1609: body.writeByte(Actions.GotoExpression);
1610: body.writeWord(1);
1611: body.writeByte(0x80);
1612: }
1613:
1614: /**
1615: * Wait for a frame to be loaded, stack-based.
1616: * <P>
1617: * <OL>
1618: * <LI>Pops frame off the stack.
1619: * <LI>If the frame identified by frame has been loaded, SkipCount
1620: * actions following the current one are skipped.
1621: * <LI>frame is evaluated in the same way as the {@link #gotoFrameAndPlay} action.
1622: * </OL>
1623: *
1624: * @param skip specified number of actions to skip
1625: * @since flash 4
1626: */
1627: public void waitForFrameAndSkip(int skip) {
1628: body.writeByte(Actions.WaitForFrameExpression);
1629: body.writeWord(1);
1630: body.writeByte(skip);
1631: }
1632:
1633: /* Some flash 5 actions */
1634:
1635: /**
1636: * Creates constant pool
1637: *
1638: * @param constants array of constants to be created
1639: * @since flash 5
1640: */
1641: public void addConstantPool(String[] constants) {
1642: int size = 2;
1643: for (int i = 0; i < constants.length; i++) {
1644: size += constants[i].length() + 1;
1645: }
1646: body.writeByte(Actions.ConstantPool);
1647: body.writeWord(size);
1648: body.writeWord(constants.length);
1649: for (int i = 0; i < constants.length; i++) {
1650: body.writeStringZ(constants[i]);
1651: }
1652: }
1653:
1654: /**
1655: * New Object
1656: * @since flash 5
1657: */
1658: public void newObject() {
1659: body.writeByte(Actions.NewObject);
1660: }
1661:
1662: /**
1663: * Calls a function.
1664: * Stack state must be [ arguments, argCount, methodName ]
1665: *
1666: * @since flash 5
1667: */
1668: public void callFunction() {
1669: body.writeByte(Actions.CallFunction);
1670: }
1671:
1672: /**
1673: * Calls a method of an object.
1674: * Stack state must be [ arguments, argCount, object, methodName ]
1675: *
1676: * @since flash 5
1677: */
1678: public void callMethod() {
1679: body.writeByte(Actions.CallMethod);
1680: }
1681:
1682: /**
1683: * Get member.
1684: * Stack state must be [ object, member name ]
1685: *
1686: * @since flash 5
1687: */
1688: public void getMember() {
1689: body.writeByte(Actions.GetMember);
1690: }
1691:
1692: /**
1693: * Set member.
1694: * Stack state must be [ object, member name, value ]
1695: *
1696: * @since flash 5
1697: */
1698: public void setMember() {
1699: body.writeByte(Actions.SetMember);
1700: }
1701:
1702: /* --------------------------------------------------------------------------------
1703: * Generating stuff
1704: * -------------------------------------------------------------------------------- */
1705: static class ForwardRef {
1706: ForwardRef next;
1707: int jumpOffset;
1708: int targetOffset;
1709:
1710: ForwardRef(int jumpOffset, int targetOffset) {
1711: this .jumpOffset = jumpOffset;
1712: this .targetOffset = targetOffset;
1713: }
1714: }
1715:
1716: private void addForwardRef(ForwardRef[] forward_refs,
1717: ForwardRef fref) {
1718: fref.next = forward_refs[0];
1719: forward_refs[0] = fref;
1720: }
1721:
1722: // resolve forward references
1723: private void resolveForwardReferences(ForwardRef[] forward_refs,
1724: FlashBuffer fob) {
1725: ForwardRef pred = null;
1726: ForwardRef cur = forward_refs[0];
1727: int curPos = getPos();
1728: while (cur != null) {
1729: if (cur.targetOffset == curPos) {
1730: fob.writeWordAt(fob.getPos() - cur.jumpOffset - 2,
1731: cur.jumpOffset);
1732: cur = cur.next;
1733: if (pred == null) {
1734: forward_refs[0] = cur;
1735: } else {
1736: pred.next = cur;
1737: }
1738: continue;
1739: }
1740: pred = cur;
1741: cur = cur.next;
1742: }
1743: }
1744:
1745: // --------------------------------------------------------------------------------- //
1746: // R E A D E R //
1747: // --------------------------------------------------------------------------------- //
1748:
1749: protected final String getString() {
1750: return body.getString();
1751: }
1752:
1753: protected final int getByte() {
1754: return body.getByte();
1755: }
1756:
1757: protected final int getUByte() {
1758: return body.getUByte();
1759: }
1760:
1761: protected final int getWord() {
1762: return body.getWord();
1763: }
1764:
1765: protected final int getUWord() {
1766: return body.getUWord();
1767: }
1768:
1769: protected final int getDWord() {
1770: return body.getDWord();
1771: }
1772:
1773: protected final int getUDWord() {
1774: return body.getUDWord();
1775: }
1776:
1777: protected final int getPos() {
1778: return body.getPos();
1779: }
1780:
1781: protected final void setPos(int pos) {
1782: body.setPos(pos);
1783: }
1784:
1785: }
|