(* * This file is part of SwfLib * Copyright (c)2004-2006 Nicolas Cannasse * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *) open Extlib_leftovers open IO open As3 let s = Printf.sprintf let f_int_length : (int -> int) ref = ref (fun _ -> assert false) let f_int_read : (IO.input -> int) ref = ref (fun _ -> assert false) let f_int_write : (unit IO.output -> int -> unit) ref = ref (fun _ _ -> assert false) let int_length i = (!f_int_length) i let read_int ch = (!f_int_read) ch let write_int (ch : 'a IO.output) i = (!f_int_write) (Obj.magic ch) i let int_index (x : 'a index) : int = Obj.magic x let index_int (x : int) : 'a index = Obj.magic x let int_index_nz (x : 'a index_nz) : int = Obj.magic x let index_nz_int (x : int) : 'a index_nz = Obj.magic x let read_index ch = index_int (read_int ch) let write_index ch i = write_int ch (int_index i) let read_index_nz ch = index_nz_int (read_int ch) let write_index_nz ch i = write_int ch (int_index_nz i) let iget (t : 'a array) (i : 'a index) : 'a = t.(Obj.magic i - 1) let write_signed_byte = write_byte let max_i24 = 1 lsl 23 - 1 let read_i24 ch = let a = read_byte ch in let b = read_byte ch in let c = read_byte ch in let n = a lor (b lsl 8) lor (c lsl 16) in if c land 128 <> 0 then n - (1 lsl 24) else n let rec write_i24 ch n = if n < -max_i24 || n > max_i24 then assert false; let n = (if n land (1 lsl 23) <> 0 then n + (1 lsl 24) else n) in write_byte ch n; write_byte ch (n lsr 8); write_byte ch (n lsr 16) let ops , ops_ids = let h = Hashtbl.create 0 in let h2 = Hashtbl.create 0 in List.iter (fun (o,b) -> Hashtbl.add h b o; Hashtbl.add h2 o b) [ A3OAs, 0x87; A3ONeg, 0x90; A3OIncr, 0x91; (* 0x92 : REGINCR *) A3ODecr, 0x93; (* 0x94 : REGDECR *) (* 0x95 : TYPEOF *) A3ONot, 0x96; A3OBitNot, 0x97; A3OAdd, 0xA0; A3OSub, 0xA1; A3OMul, 0xA2; A3ODiv, 0xA3; A3OMod, 0xA4; A3OShl, 0xA5; A3OShr, 0xA6; A3OUShr, 0xA7; A3OAnd, 0xA8; A3OOr, 0xA9; A3OXor, 0xAA; A3OEq, 0xAB; A3OPhysEq, 0xAC; A3OLt, 0xAD; A3OLte, 0xAE; A3OGt, 0xAF; A3OGte, 0xB0; A3OIs, 0xB3; A3OIn, 0xB4; A3OIIncr, 0xC0; A3OIDecr, 0xC1; A3OINeg, 0xC4; A3OIAdd, 0xC5; A3OISub, 0xC6; A3OIMul, 0xC7; A3OMemGet8, 0x35; A3OMemGet16, 0x36; A3OMemGet32, 0x37; A3OMemGetFloat, 0x38; A3OMemGetDouble, 0x39; A3OMemSet8, 0x3A; A3OMemSet16, 0x3B; A3OMemSet32, 0x3C; A3OMemSetFloat, 0x3D; A3OMemSetDouble, 0x3E; A3OSign1, 0x50; A3OSign8, 0x51; A3OSign16, 0x52; ]; h , h2 let length = function | A3SmallInt _ -> 2 | A3Construct n | A3Object n | A3RegKill n | A3Catch n | A3IncrReg n | A3DecrReg n | A3IncrIReg n | A3DecrIReg n | A3Array n | A3Int n | A3CallStack n | A3ConstructSuper n | A3BreakPointLine n | A3ApplyType n | A3DebugLine n -> 1 + int_length n | A3GetSlot s | A3SetSlot s -> 1 + int_length s | A3ClassDef n -> 1 + int_length (int_index_nz n) | A3DxNs f | A3String f | A3DebugFile f -> 1 + int_length (int_index f) | A3IntRef f -> 1 + int_length (int_index f) | A3UIntRef f -> 1 + int_length (int_index f) | A3Float f -> 1 + int_length (int_index f) | A3Function f -> 1 + int_length (int_index_nz f) | A3Namespace f -> 1 + int_length (int_index f) | A3GetProp f | A3InitProp f | A3DeleteProp f | A3FindPropStrict f | A3FindProp f | A3FindDefinition f | A3GetLex f | A3SetProp f | A3Cast f | A3GetSuper f | A3GetDescendants f | A3SetSuper f -> 1 + int_length (int_index f) | A3Op _ | A3Undefined | A3Null | A3True | A3False | A3NaN | A3RetVoid | A3Ret | A3Pop | A3Dup | A3Swap | A3AsAny | A3ToString | A3ToXml | A3ToXmlAttr | A3ToInt | A3ToUInt | A3ToNumber | A3ToBool | A3ToObject | A3AsString | A3AsObject | A3This | A3Throw | A3Nop | A3Typeof | A3InstanceOf | A3Scope | A3ForIn | A3NewBlock | A3ForEach | A3PopScope | A3CheckIsXml | A3Label | A3BreakPoint | A3PushWith | A3HasNext | A3SetThis | A3Timestamp | A3DxNsLate | A3Unk _ -> 1 | A3AsType n | A3IsType n -> 1 + int_length (int_index n) | A3DebugReg (name,reg,line) -> 1 + 1 + int_length (int_index name) + 1 + int_length line | A3GetGlobalScope -> 1 | A3GetScope n -> 1 + int_length n | A3Reg n | A3SetReg n -> if n >= 1 && n <= 3 then 1 else (1 + int_length n) | A3CallSuper (f,n) | A3CallProperty (f,n) | A3ConstructProperty (f,n) | A3CallPropLex (f,n) | A3CallPropVoid (f,n) | A3CallSuperVoid (f,n) -> 1 + int_length n + int_length (int_index f) | A3CallMethod (f,n) -> 1 + int_length n + int_length f | A3CallStatic (f,n) -> 1 + int_length n + int_length (int_index f) | A3Jump _ -> 4 | A3Next (a,b) -> 1 + int_length a + int_length b | A3Switch (_,cases) -> let ncases = List.length cases in 1 + 3 + int_length (ncases - 1) + 3 * ncases let jump ch kind = A3Jump (kind,read_i24 ch) let opcode ch = let op = (try read_byte ch with IO.No_more_input -> raise Exit) in match op with | 0x01 -> A3BreakPoint | 0x02 -> A3Nop | 0x03 -> A3Throw | 0x04 -> A3GetSuper (read_index ch) | 0x05 -> A3SetSuper (read_index ch) | 0x06 -> A3DxNs (read_index ch) | 0x07 -> A3DxNsLate | 0x08 -> A3RegKill (read_int ch) | 0x09 -> A3Label (* 0x0A -> NONE *) (* 0x0B -> NONE *) | 0x0C -> jump ch J3NotLt | 0x0D -> jump ch J3NotLte | 0x0E -> jump ch J3NotGt | 0x0F -> jump ch J3NotGte | 0x10 -> jump ch J3Always | 0x11 -> jump ch J3True | 0x12 -> jump ch J3False | 0x13 -> jump ch J3Eq | 0x14 -> jump ch J3Neq | 0x15 -> jump ch J3Lt | 0x16 -> jump ch J3Lte | 0x17 -> jump ch J3Gt | 0x18 -> jump ch J3Gte | 0x19 -> jump ch J3PhysEq | 0x1A -> jump ch J3PhysNeq | 0x1B -> let def = read_i24 ch in let rec loop n = if n = 0 then [] else let j = read_i24 ch in j :: loop (n - 1) in let cases = loop (read_int ch + 1) in A3Switch (def,cases) | 0x1C -> A3PushWith | 0x1D -> A3PopScope | 0x1E -> A3ForIn | 0x1F -> A3HasNext | 0x20 -> A3Null | 0x21 -> A3Undefined (* 0x22 -> NONE *) | 0x23 -> A3ForEach | 0x24 -> A3SmallInt (read_signed_byte ch) | 0x25 -> A3Int (read_int ch) | 0x26 -> A3True | 0x27 -> A3False | 0x28 -> A3NaN | 0x29 -> A3Pop | 0x2A -> A3Dup | 0x2B -> A3Swap | 0x2C -> A3String (read_index ch) | 0x2D -> A3IntRef (read_index ch) | 0x2E -> A3UIntRef (read_index ch) | 0x2F -> A3Float (read_index ch) | 0x30 -> A3Scope | 0x31 -> A3Namespace (read_index ch) | 0x32 -> let r1 = read_int ch in let r2 = read_int ch in A3Next (r1,r2) (* 0x33 - 0x3F -> NONE *) | 0x40 -> A3Function (read_index_nz ch) | 0x41 -> A3CallStack (read_int ch) | 0x42 -> A3Construct (read_int ch) | 0x43 -> let id = read_int ch in let nargs = read_int ch in A3CallMethod (id,nargs) | 0x44 -> let id = read_index ch in let nargs = read_int ch in A3CallStatic (id,nargs) | 0x45 -> let id = read_index ch in let nargs = read_int ch in A3CallSuper (id,nargs) | 0x46 -> let id = read_index ch in let nargs = read_int ch in A3CallProperty (id,nargs) | 0x47 -> A3RetVoid | 0x48 -> A3Ret | 0x49 -> A3ConstructSuper (read_int ch) | 0x4A -> let id = read_index ch in let nargs = read_int ch in A3ConstructProperty (id,nargs) (* 0x4B -> NONE *) | 0x4C -> let id = read_index ch in let nargs = read_int ch in A3CallPropLex (id,nargs) (* 0x4D -> NONE *) | 0x4E -> let id = read_index ch in let nargs = read_int ch in A3CallSuperVoid (id,nargs) | 0x4F -> let id = read_index ch in let nargs = read_int ch in A3CallPropVoid (id,nargs) (* 0x50 - 0x52 -> NONE *) | 0x53 -> A3ApplyType (read_int ch) (* 0x54 -> NONE *) | 0x55 -> A3Object (read_int ch) | 0x56 -> A3Array (read_int ch) | 0x57 -> A3NewBlock | 0x58 -> A3ClassDef (read_index_nz ch) | 0x59 -> A3GetDescendants (read_index ch) | 0x5A -> A3Catch (read_int ch) (* 0x5B -> NONE *) (* 0x5C -> NONE *) | 0x5D -> A3FindPropStrict (read_index ch) | 0x5E -> A3FindProp (read_index ch) | 0x5F -> A3FindDefinition (read_index ch) | 0x60 -> A3GetLex (read_index ch) | 0x61 -> A3SetProp (read_index ch) | 0x62 -> A3Reg (read_int ch) | 0x63 -> A3SetReg (read_int ch) | 0x64 -> A3GetGlobalScope | 0x65 -> A3GetScope (IO.read_byte ch) | 0x66 -> A3GetProp (read_index ch) (* 0x67 -> NONE *) | 0x68 -> A3InitProp (read_index ch) (* 0x69 -> NONE *) | 0x6A -> A3DeleteProp (read_index ch) (* 0x6B -> NONE *) | 0x6C -> A3GetSlot (read_int ch) | 0x6D -> A3SetSlot (read_int ch) (* 0x6E -> DEPRECATED getglobalslot *) (* 0x6F -> DEPRECATED setglobalslot *) | 0x70 -> A3ToString | 0x71 -> A3ToXml | 0x72 -> A3ToXmlAttr | 0x73 -> A3ToInt | 0x74 -> A3ToUInt | 0x75 -> A3ToNumber | 0x76 -> A3ToBool | 0x77 -> A3ToObject | 0x78 -> A3CheckIsXml (* 0x79 -> NONE *) | 0x80 -> A3Cast (read_index ch) (* 0x81 -> DEPRECATED asbool *) | 0x82 -> A3AsAny (* 0x83 -> DEPRECATED asint *) (* 0x84 -> DEPRECATED asnumber *) | 0x85 -> A3AsString | 0x86 -> A3AsType (read_index ch) (* 0x87 -> OP *) (* 0x88 -> DEPRECATED asuint *) | 0x89 -> A3AsObject (* 0x8A - 0x8F -> NONE *) (* 0x90 - 0x91 -> OP *) | 0x92 -> A3IncrReg (read_int ch) (* 0x93 -> OP *) | 0x94 -> A3DecrReg (read_int ch) | 0x95 -> A3Typeof (* 0x96 -> OP *) (* 0x97 -> OP *) (* 0x98 - 0x9F -> NONE *) (* 0xA0 - 0xB0 -> OP *) | 0xB1 -> A3InstanceOf | 0xB2 -> A3IsType (read_index ch) (* 0xB3 -> OP *) (* 0xB4 -> OP *) (* 0xB5 - 0xBF -> NONE *) (* 0xC0 -> OP *) (* 0xC1 -> OP *) | 0xC2 -> A3IncrIReg (read_int ch) | 0xC3 -> A3DecrIReg (read_int ch) (* 0xC4 - 0xC7 -> OP *) (* 0xC8 - 0xCF -> NONE *) | 0xD0 -> A3This | 0xD1 -> A3Reg 1 | 0xD2 -> A3Reg 2 | 0xD3 -> A3Reg 3 | 0xD4 -> A3SetThis | 0xD5 -> A3SetReg 1 | 0xD6 -> A3SetReg 2 | 0xD7 -> A3SetReg 3 (* 0xD8 - 0xEE -> NONE *) | 0xEF -> if IO.read_byte ch <> 1 then assert false; let name = read_index ch in let reg = read_byte ch + 1 in let line = read_int ch in A3DebugReg (name,reg,line) | 0xF0 -> A3DebugLine (read_int ch) | 0xF1 -> A3DebugFile (read_index ch) | 0xF2 -> A3BreakPointLine (read_int ch) | 0xF3 -> A3Timestamp (* 0xF4 - 0xFF -> NONE *) | _ -> try A3Op (Hashtbl.find ops op) with Not_found -> Printf.printf "Unknown opcode 0x%.2X\n" op; A3Unk (char_of_int op) let parse ch len = let data = nread_string ch len in let ch = input_string data in let a = MultiArray.create() in let rec loop() = MultiArray.add a (opcode ch); loop(); in (try loop() with Exit -> ()); a let write ch = function | A3BreakPoint -> write_byte ch 0x01 | A3Nop -> write_byte ch 0x02 | A3Throw -> write_byte ch 0x03 | A3GetSuper f -> write_byte ch 0x04; write_index ch f | A3SetSuper f -> write_byte ch 0x05; write_index ch f | A3DxNs i -> write_byte ch 0x06; write_index ch i | A3DxNsLate -> write_byte ch 0x07 | A3RegKill n -> write_byte ch 0x08; write_int ch n | A3Label -> write_byte ch 0x09 | A3Jump (k,n) -> write_byte ch (match k with | J3NotLt -> 0x0C | J3NotLte -> 0x0D | J3NotGt -> 0x0E | J3NotGte -> 0x0F | J3Always -> 0x10 | J3True -> 0x11 | J3False -> 0x12 | J3Eq -> 0x13 | J3Neq -> 0x14 | J3Lt -> 0x15 | J3Lte -> 0x16 | J3Gt -> 0x17 | J3Gte -> 0x18 | J3PhysEq -> 0x19 | J3PhysNeq -> 0x1A ); write_i24 ch n | A3Switch (def,cases) -> write_byte ch 0x1B; write_i24 ch def; write_int ch (List.length cases - 1); List.iter (write_i24 ch) cases | A3PushWith -> write_byte ch 0x1C | A3PopScope -> write_byte ch 0x1D | A3ForIn -> write_byte ch 0x1E | A3HasNext -> write_byte ch 0x1F | A3Null -> write_byte ch 0x20 | A3Undefined -> write_byte ch 0x21 | A3ForEach -> write_byte ch 0x23 | A3SmallInt b -> write_byte ch 0x24; write_signed_byte ch b | A3Int i -> write_byte ch 0x25; write_int ch i | A3True -> write_byte ch 0x26 | A3False -> write_byte ch 0x27 | A3NaN -> write_byte ch 0x28 | A3Pop -> write_byte ch 0x29 | A3Dup -> write_byte ch 0x2A | A3Swap -> write_byte ch 0x2B | A3String s -> write_byte ch 0x2C; write_index ch s | A3IntRef i -> write_byte ch 0x2D; write_index ch i | A3UIntRef i -> write_byte ch 0x2E; write_index ch i | A3Float f -> write_byte ch 0x2F; write_index ch f | A3Scope -> write_byte ch 0x30 | A3Namespace f -> write_byte ch 0x31; write_index ch f | A3Next (r1,r2) -> write_byte ch 0x32; write_int ch r1; write_int ch r2 | A3Function f -> write_byte ch 0x40; write_index_nz ch f | A3CallStack n -> write_byte ch 0x41; write_int ch n | A3Construct n -> write_byte ch 0x42; write_int ch n | A3CallMethod (f,n) -> write_byte ch 0x43; write_int ch f; write_int ch n | A3CallStatic (f,n) -> write_byte ch 0x44; write_index ch f; write_int ch n | A3CallSuper (f,n) -> write_byte ch 0x45; write_index ch f; write_int ch n | A3CallProperty (f,n) -> write_byte ch 0x46; write_index ch f; write_int ch n | A3RetVoid -> write_byte ch 0x47 | A3Ret -> write_byte ch 0x48 | A3ConstructSuper n -> write_byte ch 0x49; write_int ch n | A3ConstructProperty (f,n) -> write_byte ch 0x4A; write_index ch f; write_int ch n | A3CallPropLex (f,n) -> write_byte ch 0x4C; write_index ch f; write_int ch n | A3CallSuperVoid (f,n) -> write_byte ch 0x4E; write_index ch f; write_int ch n | A3CallPropVoid (f,n) -> write_byte ch 0x4F; write_index ch f; write_int ch n | A3ApplyType n -> write_byte ch 0x53; write_int ch n | A3Object n -> write_byte ch 0x55; write_int ch n | A3Array n -> write_byte ch 0x56; write_int ch n | A3NewBlock -> write_byte ch 0x57 | A3ClassDef f -> write_byte ch 0x58; write_index_nz ch f | A3GetDescendants f -> write_byte ch 0x59; write_index ch f | A3Catch n -> write_byte ch 0x5A; write_int ch n | A3FindPropStrict f -> write_byte ch 0x5D; write_index ch f | A3FindProp f -> write_byte ch 0x5E; write_index ch f | A3FindDefinition f -> write_byte ch 0x5F; write_index ch f | A3GetLex f -> write_byte ch 0x60; write_index ch f | A3SetProp f -> write_byte ch 0x61; write_index ch f | A3Reg n -> if n >= 0 && n < 4 then write_byte ch (0xD0 + n) else begin write_byte ch 0x62; write_int ch n end | A3SetReg n -> if n >= 0 && n < 4 then write_byte ch (0xD4 + n) else begin write_byte ch 0x63; write_int ch n end | A3GetGlobalScope -> write_byte ch 0x64 | A3GetScope n -> write_byte ch 0x65; write_byte ch n | A3GetProp f -> write_byte ch 0x66; write_index ch f | A3InitProp f -> write_byte ch 0x68; write_index ch f | A3DeleteProp f -> write_byte ch 0x6A; write_index ch f | A3GetSlot n -> write_byte ch 0x6C; write_int ch n | A3SetSlot n -> write_byte ch 0x6D; write_int ch n | A3ToString -> write_byte ch 0x70 | A3ToXml -> write_byte ch 0x71 | A3ToXmlAttr -> write_byte ch 0x72 | A3ToInt -> write_byte ch 0x73 | A3ToUInt -> write_byte ch 0x74 | A3ToNumber -> write_byte ch 0x75 | A3ToBool -> write_byte ch 0x76 | A3ToObject -> write_byte ch 0x77 | A3CheckIsXml -> write_byte ch 0x78 | A3Cast f -> write_byte ch 0x80; write_index ch f | A3AsAny -> write_byte ch 0x82 | A3AsString -> write_byte ch 0x85 | A3AsType n -> write_byte ch 0x86; write_index ch n | A3AsObject -> write_byte ch 0x89 | A3IncrReg r -> write_byte ch 0x92; write_int ch r | A3DecrReg r -> write_byte ch 0x94; write_int ch r | A3Typeof -> write_byte ch 0x95 | A3InstanceOf -> write_byte ch 0xB1 | A3IsType n -> write_byte ch 0xB2; write_index ch n | A3IncrIReg r -> write_byte ch 0xC2; write_int ch r | A3DecrIReg r -> write_byte ch 0xC3; write_int ch r | A3This -> write_byte ch 0xD0 | A3SetThis -> write_byte ch 0xD4 | A3DebugReg (name,reg,line) -> write_byte ch 0xEF; write_byte ch 0x01; write_index ch name; write_byte ch (reg - 1); write_int ch line; | A3DebugLine f -> write_byte ch 0xF0; write_int ch f; | A3DebugFile f -> write_byte ch 0xF1; write_index ch f; | A3BreakPointLine l -> write_byte ch 0xF2; write_int ch l | A3Timestamp -> write_byte ch 0xF3 | A3Op op -> write_byte ch (try Hashtbl.find ops_ids op with Not_found -> assert false) | A3Unk x -> write ch x let dump_op = function | A3OAs -> "as" | A3ONeg -> "neg" | A3OIncr -> "incr" | A3ODecr -> "decr" | A3ONot -> "not" | A3OBitNot -> "bitnot" | A3OAdd -> "add" | A3OSub -> "sub" | A3OMul -> "mul" | A3ODiv -> "div" | A3OMod -> "mod" | A3OShl -> "shl" | A3OShr -> "shr" | A3OUShr -> "ushr" | A3OAnd -> "and" | A3OOr -> "or" | A3OXor -> "xor" | A3OEq -> "eq" | A3OPhysEq -> "physeq" | A3OLt -> "lt" | A3OLte -> "lte" | A3OGt -> "gt" | A3OGte -> "gte" | A3OIs -> "is" | A3OIn -> "in" | A3OIIncr -> "iincr" | A3OIDecr -> "idecr" | A3OINeg -> "ineg" | A3OIAdd -> "iadd" | A3OISub -> "isub" | A3OIMul -> "imul" | A3OMemSet8 -> "mset8" | A3OMemSet16 -> "set16" | A3OMemSet32 -> "mset32" | A3OMemSetFloat -> "msetfloat" | A3OMemSetDouble -> "msetdouble" | A3OMemGet8 -> "mget8" | A3OMemGet16 -> "mget16" | A3OMemGet32 -> "mget32" | A3OMemGetFloat -> "mgetfloat" | A3OMemGetDouble -> "mgetdouble" | A3OSign1 -> "sign1" | A3OSign8 -> "sign8" | A3OSign16 -> "sign16" let dump_jump = function | J3NotLt -> "-nlt" | J3NotLte -> "-nlte" | J3NotGt -> "-ngt" | J3NotGte -> "-ngte" | J3Always -> "" | J3True -> "-if" | J3False -> "-ifnot" | J3Eq -> "-eq" | J3Neq -> "-neq" | J3Lt -> "-lt" | J3Lte -> "-lte" | J3Gt -> "-gt" | J3Gte -> "-gte" | J3PhysEq -> "-peq" | J3PhysNeq -> "-pneq" let dump ctx op = let ident n = ctx.as3_idents.(int_index n - 1) in let rec field n = let t = ctx.as3_names.(int_index n - 1) in match t with | A3MMultiName (Some ident,_) -> "[" ^ iget ctx.as3_idents ident ^ "]" | A3MName (ident,_) -> iget ctx.as3_idents ident | A3MMultiNameLate idx -> "~array" | A3MParams (t,params) -> field t ^ "<" ^ String.concat "." (List.map field params) ^ ">" | _ -> "???" in match op with | A3BreakPoint -> "bkpt" | A3Nop -> "nop" | A3Throw -> "throw" | A3GetSuper f -> s "getsuper %s" (field f) | A3SetSuper f -> s "setsuper %s" (field f) | A3DxNs i -> s "dxns %s" (ident i) | A3DxNsLate -> "dxnslate" | A3RegKill n -> s "kill %d" n | A3Label -> "label" | A3Jump (k,n) -> s "jump%s %d" (dump_jump k) n | A3Switch (def,cases) -> s "switch %d [%s]" def (String.concat "," (List.map (s "%d") cases)) | A3PushWith -> "pushwith" | A3PopScope -> "popscope" | A3ForIn -> "forin" | A3HasNext -> "hasnext" | A3Null -> "null" | A3Undefined -> "undefined" | A3ForEach -> "foreach" | A3SmallInt b -> s "int %d" b | A3Int n -> s "int %d" n | A3True -> "true" | A3False -> "false" | A3NaN -> "nan" | A3Pop -> "pop" | A3Dup -> "dup" | A3Swap -> "swap" | A3String n -> s "string [%s]" (ident n) | A3IntRef n -> s "int [%ld]" ctx.as3_ints.(int_index n - 1) | A3UIntRef n -> s "uint [%ld]" ctx.as3_uints.(int_index n - 1) | A3Float n -> s "float [%f]" ctx.as3_floats.(int_index n - 1) | A3Scope -> "scope" | A3Namespace f -> s "namespace [%d]" (int_index f) | A3Next (r1,r2) -> s "next %d %d" r1 r2 | A3Function f -> s "function #%d" (int_index_nz f) | A3CallStack n -> s "callstack (%d)" n | A3Construct n -> s "construct (%d)" n | A3CallMethod (f,n) -> s "callmethod %d (%d)" f n | A3CallStatic (f,n) -> s "callstatic %d (%d)" (int_index f) n | A3CallSuper (f,n) -> s "callsuper %s (%d)" (field f) n | A3CallProperty (f,n) -> s "callprop %s (%d)" (field f) n | A3RetVoid -> "retvoid" | A3Ret -> "ret" | A3ConstructSuper n -> s "constructsuper %d" n | A3ConstructProperty (f,n) -> s "constructprop %s (%d)" (field f) n | A3CallPropLex (f,n) -> s "callproplex %s (%d)" (field f) n | A3CallSuperVoid (f,n) -> s "callsupervoid %s (%d)" (field f) n | A3CallPropVoid (f,n) -> s "callpropvoid %s (%d)" (field f) n | A3ApplyType n -> s "applytype %d" n | A3Object n -> s "object %d" n | A3Array n -> s "array %d" n | A3NewBlock -> "newblock" | A3ClassDef n -> s "classdef %d" (int_index_nz n) | A3GetDescendants f -> s "getdescendants %s" (field f) | A3Catch n -> s "catch %d" n | A3FindPropStrict f -> s "findpropstrict %s" (field f) | A3FindProp f -> s "findprop %s" (field f) | A3FindDefinition f -> s "finddefinition %s" (field f) | A3GetLex f -> s "getlex %s" (field f) | A3SetProp f -> s "setprop %s" (field f) | A3Reg n -> s "reg %d" n | A3SetReg n -> s "setreg %d" n | A3GetGlobalScope -> "getglobalscope" | A3GetScope n -> s "getscope %d" n | A3GetProp f -> s "getprop %s" (field f) | A3InitProp f -> s "initprop %s" (field f) | A3DeleteProp f -> s "deleteprop %s" (field f) | A3GetSlot n -> s "getslot %d" n | A3SetSlot n -> s "setslot %d" n | A3ToString -> "tostring" | A3ToXml -> "toxml" | A3ToXmlAttr -> "toxmlattr" | A3ToInt -> "toint" | A3ToUInt -> "touint" | A3ToNumber -> "tonumber" | A3ToBool -> "tobool" | A3ToObject -> "toobject" | A3CheckIsXml -> "checkisxml" | A3Cast f -> s "cast %s" (field f) | A3AsAny -> "asany" | A3AsString -> "asstring" | A3AsType f -> s "astype %s" (field f) | A3AsObject -> "asobject" | A3IncrReg r -> s "incrreg %d" r | A3DecrReg r -> s "decrreg %d" r | A3Typeof -> "typeof" | A3InstanceOf -> "instanceof" | A3IsType f -> s "istype %s" (field f) | A3IncrIReg r -> s "incrireg %d" r | A3DecrIReg r -> s "decrireg %d" r | A3This -> "this" | A3SetThis -> "setthis" | A3DebugReg (name,reg,line) -> s ".reg %d:%s line:%d" reg (ident name) line | A3DebugLine l -> s ".line %d" l | A3DebugFile f -> s ".file %s" (ident f) | A3BreakPointLine l -> s ".bkptline %d" l | A3Timestamp -> ".time" | A3Op o -> dump_op o | A3Unk x -> s "??? 0x%X" (int_of_char x)