/* * JSwiff is an open source Java API for Macromedia Flash file generation * and manipulation * * Copyright (C) 2004-2005 Ralf Terdic (contact@jswiff.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.jswiff.swfrecords.actions; import java.io.IOException; import org.apache.log4j.Logger; import com.jswiff.io.InputBitStream; /* * This class contains methods for reading action records. */ public class ActionReader { private static Logger logger = Logger.getLogger(ActionReader.class); private ActionReader() { // prohibits instantiation } /* * Reads an action record from a bit stream. */ public static Action readRecord(InputBitStream stream) throws IOException { Action action; InputBitStream actionStream = null; // contains action record data int offset = (int) stream.getOffset(); short actionCode = stream.readUI8(); boolean longHeader = (actionCode >= 0x80); int length = longHeader ? stream.readUI16() : 0; // logger.debug("actionCode = "+actionFormat.sprintf(actionCode)+" // ("+ActionConstants.getActionName(actionCode)+"),length="+length); // if (length > 0) { boolean invalidActionLength = false; if (length > 0) { if (stream.available()>=length) { actionStream = new InputBitStream(stream.readBytes(length)); actionStream.setANSI(stream.isANSI()); actionStream.setShiftJIS(stream.isShiftJIS()); } else { logger.debug("Action "+actionCode+". stream.available() = "+stream.available()+", length="+length); invalidActionLength = true; InvalidAction invalidAction = new InvalidAction(); invalidAction.setOffset(offset); return invalidAction; } } switch (actionCode) { case ActionConstants.ADD: action = new Add(); break; case ActionConstants.ADD_2: action = new Add2(); break; case ActionConstants.AND: action = new And(); break; case ActionConstants.ASCII_TO_CHAR: action = new AsciiToChar(); break; case ActionConstants.BIT_AND: action = new BitAnd(); break; case ActionConstants.BIT_L_SHIFT: action = new BitLShift(); break; case ActionConstants.BIT_OR: action = new BitOr(); break; case ActionConstants.BIT_R_SHIFT: action = new BitRShift(); break; case ActionConstants.BIT_U_R_SHIFT: action = new BitURShift(); break; case ActionConstants.BIT_XOR: action = new BitXor(); break; case ActionConstants.CALL: // MM bug here: high bit of code set although length=0 action = new Call(); break; case ActionConstants.CALL_FUNCTION: action = new CallFunction(); break; case ActionConstants.CALL_METHOD: action = new CallMethod(); break; case ActionConstants.CAST_OP: action = new CastOp(); break; case ActionConstants.CHAR_TO_ASCII: action = new CharToAscii(); break; case ActionConstants.CLONE_SPRITE: action = new CloneSprite(); break; case ActionConstants.CONSTANT_POOL: action = new ConstantPool(actionStream); break; case ActionConstants.DECREMENT: action = new Decrement(); break; case ActionConstants.DEFINE_FUNCTION: action = new DefineFunction(actionStream, stream); break; case ActionConstants.DEFINE_FUNCTION_2: action = new DefineFunction2(actionStream, stream); break; case ActionConstants.DEFINE_LOCAL: action = new DefineLocal(); break; case ActionConstants.DEFINE_LOCAL_2: action = new DefineLocal2(); break; case ActionConstants.DELETE: action = new Delete(); break; case ActionConstants.DELETE_2: action = new Delete2(); break; case ActionConstants.DIVIDE: action = new Divide(); break; case ActionConstants.END: action = new End(); break; case ActionConstants.END_DRAG: action = new EndDrag(); break; case ActionConstants.ENUMERATE: action = new Enumerate(); break; case ActionConstants.ENUMERATE_2: action = new Enumerate2(); break; case ActionConstants.EQUALS: action = new Equals(); break; case ActionConstants.EQUALS_2: action = new Equals2(); break; case ActionConstants.EXTENDS: action = new Extends(); break; case ActionConstants.GET_MEMBER: action = new GetMember(); break; case ActionConstants.GET_PROPERTY: action = new GetProperty(); break; case ActionConstants.GET_TIME: action = new GetTime(); break; case ActionConstants.GET_URL: action = new GetURL(actionStream); break; case ActionConstants.GET_URL_2: action = new GetURL2(actionStream); break; case ActionConstants.GET_VARIABLE: action = new GetVariable(); break; case ActionConstants.GO_TO_FRAME: action = new GoToFrame(actionStream); break; case ActionConstants.GO_TO_FRAME_2: action = new GoToFrame2(actionStream); break; case ActionConstants.GO_TO_LABEL: action = new GoToLabel(actionStream); break; case ActionConstants.GREATER: action = new Greater(); break; case ActionConstants.IF: action = new If(actionStream); break; case ActionConstants.IMPLEMENTS_OP: action = new ImplementsOp(); break; case ActionConstants.INCREMENT: action = new Increment(); break; case ActionConstants.INIT_ARRAY: action = new InitArray(); break; case ActionConstants.INIT_OBJECT: action = new InitObject(); break; case ActionConstants.INSTANCE_OF: action = new InstanceOf(); break; case ActionConstants.JUMP: Jump jmpAction = new Jump(actionStream); action = jmpAction; // logger.debug("jmpAction.getBranchOffset() = // "+jmpAction.getBranchOffset()); // if (jmpAction.getBranchOffset()>0) { // logger.debug("Skipping next "+jmpAction.getBranchOffset()+" bytes // as unknown action"); // } // stream.s break; case ActionConstants.LESS: action = new Less(); break; case ActionConstants.LESS_2: action = new Less2(); break; case ActionConstants.M_B_ASCII_TO_CHAR: action = new MBAsciiToChar(); break; case ActionConstants.M_B_CHAR_TO_ASCII: action = new MBCharToAscii(); break; case ActionConstants.M_B_STRING_EXTRACT: action = new MBStringExtract(); break; case ActionConstants.M_B_STRING_LENGTH: action = new MBStringLength(); break; case ActionConstants.MODULO: action = new Modulo(); break; case ActionConstants.MULTIPLY: action = new Multiply(); break; case ActionConstants.NEW_METHOD: action = new NewMethod(); break; case ActionConstants.NEW_OBJECT: action = new NewObject(); break; case ActionConstants.NEXT_FRAME: action = new NextFrame(); break; case ActionConstants.NOT: action = new Not(); break; case ActionConstants.OR: action = new Or(); break; case ActionConstants.PLAY: action = new Play(); break; case ActionConstants.POP: action = new Pop(); break; case ActionConstants.PREVIOUS_FRAME: action = new PreviousFrame(); break; case ActionConstants.PUSH: action = new Push(actionStream); break; case ActionConstants.PUSH_DUPLICATE: action = new PushDuplicate(); break; case ActionConstants.RANDOM_NUMBER: action = new RandomNumber(); break; case ActionConstants.REMOVE_SPRITE: action = new RemoveSprite(); break; case ActionConstants.RETURN: action = new Return(); break; case ActionConstants.SET_MEMBER: action = new SetMember(); break; case ActionConstants.SET_PROPERTY: action = new SetProperty(); break; case ActionConstants.SET_TARGET: action = new SetTarget(actionStream); break; case ActionConstants.SET_TARGET_2: action = new SetTarget2(); break; case ActionConstants.SET_VARIABLE: action = new SetVariable(); break; case ActionConstants.STACK_SWAP: action = new StackSwap(); break; case ActionConstants.START_DRAG: action = new StartDrag(); break; case ActionConstants.STOP: action = new Stop(); break; case ActionConstants.STOP_SOUNDS: action = new StopSounds(); break; case ActionConstants.STORE_REGISTER: action = new StoreRegister(actionStream); break; case ActionConstants.STRICT_EQUALS: action = new StrictEquals(); break; case ActionConstants.STRING_ADD: action = new StringAdd(); break; case ActionConstants.STRING_EQUALS: action = new StringEquals(); break; case ActionConstants.STRING_EXTRACT: action = new StringExtract(); break; case ActionConstants.STRING_GREATER: action = new StringGreater(); break; case ActionConstants.STRING_LENGTH: action = new StringLength(); break; case ActionConstants.STRING_LESS: action = new StringLess(); break; case ActionConstants.SUBTRACT: action = new Subtract(); break; case ActionConstants.TARGET_PATH: action = new TargetPath(); break; case ActionConstants.THROW: action = new Throw(); break; case ActionConstants.TOGGLE_QUALITY: action = new ToggleQuality(); break; case ActionConstants.TO_INTEGER: action = new ToInteger(); break; case ActionConstants.TO_NUMBER: action = new ToNumber(); break; case ActionConstants.TO_STRING: action = new ToString(); break; case ActionConstants.TRACE: action = new Trace(); break; case ActionConstants.TRY: action = new Try(actionStream, stream); break; case ActionConstants.TYPE_OF: action = new TypeOf(); break; case ActionConstants.WAIT_FOR_FRAME: action = new WaitForFrame(actionStream); break; case ActionConstants.WAIT_FOR_FRAME_2: action = new WaitForFrame2(actionStream); break; case ActionConstants.WITH: action = new With(actionStream, stream); break; default: action = new UnknownAction(actionStream, actionCode); } // fool a decompilation protection which pretends an action record to be // longer than it actually is in order to hide subsequent actions int delta = action.getSize() - (length + (longHeader ? 3 : 1)); if (delta < 0) { stream.move(delta); } action.setOffset(offset); return action; } }