actionScript.ml 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. (*
  2. * This file is part of SwfLib
  3. * Copyright (c)2004 Nicolas Cannasse
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  18. *)
  19. open Swf
  20. open IO
  21. open Printf
  22. let push_item_length = function
  23. | PString s -> String.length s + 1
  24. | PFloat _ -> 4
  25. | PNull -> 0
  26. | PUndefined -> 0
  27. | PReg _ -> 1
  28. | PBool _ -> 1
  29. | PDouble _ -> 8
  30. | PInt _ -> 4
  31. | PStack _ -> 1
  32. | PStack2 _ -> 2
  33. let push_item_id = function
  34. | PString s -> 0
  35. | PFloat _ -> 1
  36. | PNull -> 2
  37. | PUndefined -> 3
  38. | PReg _ -> 4
  39. | PBool _ -> 5
  40. | PDouble _ -> 6
  41. | PInt _ -> 7
  42. | PStack _ -> 8
  43. | PStack2 _ -> 9
  44. let opcodes = Hashtbl.create 0
  45. let opcodes_rev = Hashtbl.create 0
  46. let opcodes_names = Hashtbl.create 0
  47. let ( => ) code (op,name) =
  48. Hashtbl.add opcodes op code;
  49. Hashtbl.add opcodes_rev code op;
  50. Hashtbl.add opcodes_names op name
  51. let short_op_codes = begin
  52. 0x00 => (AEnd,"END");
  53. 0x04 => (ANextFrame,"NEXTFRAME");
  54. 0x05 => (APrevFrame,"PREVFRAME");
  55. 0x06 => (APlay,"PLAY");
  56. 0x07 => (AStop,"STOP");
  57. 0x08 => (AToggleHighQuality,"TGLHIGHQULTY");
  58. 0x09 => (AStopSounds,"STOPSOUNDS");
  59. 0x0A => (AAddNum,"ADDNUM");
  60. 0x0B => (ASubtract,"SUB");
  61. 0x0C => (AMultiply,"MULT");
  62. 0x0D => (ADivide,"DIV");
  63. 0x0E => (ACompareNum,"CMP");
  64. 0x0F => (AEqualNum,"EQNUM");
  65. 0x10 => (ALogicalAnd,"LAND");
  66. 0x11 => (ALogicalOr,"LOR");
  67. 0x12 => (ANot,"NOT");
  68. 0x13 => (AStringEqual,"STREQ");
  69. 0x14 => (AStringLength,"STRLEN");
  70. 0x15 => (ASubString,"SUBSTR");
  71. 0x17 => (APop,"POP");
  72. 0x18 => (AToInt,"TOINT");
  73. 0x1C => (AEval,"EVAL");
  74. 0x1D => (ASet,"SET");
  75. 0x20 => (ATellTarget,"TELLTARGET");
  76. 0x21 => (AStringAdd,"STRADD");
  77. 0x22 => (AGetProperty,"GETPROP");
  78. 0x23 => (ASetProperty,"SETPROP");
  79. 0x24 => (ADuplicateMC,"DUPLICATEMC");
  80. 0x25 => (ARemoveMC,"REMOVEMC");
  81. 0x26 => (ATrace,"TRACE");
  82. 0x27 => (AStartDrag,"STARTDRAG");
  83. 0x28 => (AStopDrag,"STOPDRAG");
  84. 0x2A => (AThrow,"THROW");
  85. 0x2B => (ACast,"CAST");
  86. 0x2C => (AImplements,"IMPLEMENTS");
  87. 0x2D => (AFSCommand2,"FSCOMMAND2");
  88. 0x30 => (ARandom,"RANDOM");
  89. 0x31 => (AMBStringLength,"MBSTRLEN");
  90. 0x32 => (AOrd,"ORD");
  91. 0x33 => (AChr,"CHR");
  92. 0x34 => (AGetTimer,"GETTIMER");
  93. 0x35 => (AMBStringSub,"MBSTRSUB");
  94. 0x36 => (AMBOrd,"MBORD");
  95. 0x37 => (AMBChr,"MBCHR");
  96. 0x3A => (ADeleteObj,"DELETEOBJ");
  97. 0x3B => (ADelete,"DELETE");
  98. 0x3C => (ALocalAssign,"VARSET");
  99. 0x3D => (ACall,"CALL");
  100. 0x3E => (AReturn,"RET");
  101. 0x3F => (AMod,"MOD");
  102. 0x40 => (ANew,"NEW");
  103. 0x41 => (ALocalVar,"VAR");
  104. 0x42 => (AInitArray,"ARRAY");
  105. 0x43 => (AObject,"OBJECT");
  106. 0x44 => (ATypeOf,"TYPEOF");
  107. 0x45 => (ATargetPath,"TARGETPATH");
  108. 0x46 => (AEnum,"ENUM");
  109. 0x47 => (AAdd,"ADD");
  110. 0x48 => (ACompare,"CMP");
  111. 0x49 => (AEqual,"EQ");
  112. 0x4A => (AToNumber,"TONUMBER");
  113. 0x4B => (AToString,"TOSTRING");
  114. 0x4C => (ADup,"DUP");
  115. 0x4D => (ASwap,"SWAP");
  116. 0x4E => (AObjGet,"OBJGET");
  117. 0x4F => (AObjSet,"OBJSET");
  118. 0x50 => (AIncrement,"INCR");
  119. 0x51 => (ADecrement,"DECR");
  120. 0x52 => (AObjCall,"OBJCALL");
  121. 0x53 => (ANewMethod,"NEWMETHOD");
  122. 0x54 => (AInstanceOf,"INSTANCEOF");
  123. 0x55 => (AEnum2,"ENUM2");
  124. 0x60 => (AAnd,"AND");
  125. 0x61 => (AOr,"OR");
  126. 0x62 => (AXor,"XOR");
  127. 0x63 => (AShl,"SHL");
  128. 0x64 => (AShr,"SHR");
  129. 0x65 => (AAsr,"ASR");
  130. 0x66 => (APhysEqual,"PHYSEQ");
  131. 0x67 => (AGreater,"GT");
  132. 0x68 => (AStringGreater,"STRGT");
  133. 0x69 => (AExtends,"EXTENDS");
  134. 0x9E => (ACallFrame,"CALLFRAME"); (* special case *)
  135. end
  136. let action_id = function
  137. | AGotoFrame _ -> 0x81
  138. | AGetURL _ -> 0x83
  139. | ASetReg _ -> 0x87
  140. | AStringPool _ -> 0x88
  141. | AWaitForFrame _ -> 0x8A
  142. | ASetTarget _ -> 0x8B
  143. | AGotoLabel _ -> 0x8C
  144. | AWaitForFrame2 _ -> 0x8D
  145. | AFunction2 _ -> 0x8E
  146. | ATry _ -> 0x8F
  147. | AWith _ -> 0x94
  148. | APush _ -> 0x96
  149. | AJump _ -> 0x99
  150. | AGetURL2 _ -> 0x9A
  151. | AFunction _ -> 0x9B
  152. | ACondJump _ -> 0x9D
  153. | AGotoFrame2 _ -> 0x9F
  154. | AUnknown (id,_) -> id
  155. | op ->
  156. try
  157. Hashtbl.find opcodes op
  158. with
  159. Not_found -> error "Unknown opcode id"
  160. let action_data_length = function
  161. | AGotoFrame _ ->
  162. 2
  163. | AGetURL (url,target) ->
  164. 2 + String.length url + String.length target
  165. | ASetReg _ ->
  166. 1
  167. | AStringPool strs ->
  168. List.fold_left (fun acc item -> acc + 1 + String.length item) 2 strs
  169. | AWaitForFrame _ ->
  170. 3
  171. | AFunction2 f ->
  172. let base = String.length f.f2_name + 1 + 2 + 1 + 2 + 2 in
  173. List.fold_left (fun acc (_,s) -> acc + 2 + String.length s) base f.f2_args
  174. | ASetTarget target ->
  175. String.length target + 1
  176. | AGotoLabel label ->
  177. String.length label + 1
  178. | AWaitForFrame2 _ ->
  179. 1
  180. | ATry t ->
  181. 1 + 6 + (match t.tr_style with TryVariable n -> String.length n + 1 | TryRegister _ -> 1)
  182. | AWith _ ->
  183. 2 (* the string does not count in length *)
  184. | APush items ->
  185. List.fold_left (fun acc item -> acc + 1 + push_item_length item) 0 items
  186. | AJump _ ->
  187. 2
  188. | AGetURL2 _ ->
  189. 1
  190. | AFunction f ->
  191. List.fold_left (fun acc s -> acc + 1 + String.length s) 4 (f.f_name :: f.f_args)
  192. | ACondJump _ ->
  193. 2
  194. | AGotoFrame2 (_,id) ->
  195. 1 + (if id = None then 0 else 2)
  196. | AUnknown (_,data) ->
  197. String.length data
  198. | _ ->
  199. 0
  200. let action_length a =
  201. let len = (if action_id a >= 0x80 then 3 else 1) in
  202. len + action_data_length a
  203. let actions_length acts =
  204. DynArray.fold_left (fun acc a -> acc + action_length a) (action_length AEnd) acts
  205. let read_mm_double ch =
  206. let i1 = Int64.of_int32 (read_real_i32 ch) in
  207. let i2 = Int64.of_int32 (read_real_i32 ch) in
  208. let i2 = (if i2 < Int64.zero then Int64.add i2 (Int64.shift_left Int64.one 32) else i2) in
  209. Int64.float_of_bits (Int64.logor i2 (Int64.shift_left i1 32))
  210. let write_mm_double ch f =
  211. let i64 = Int64.bits_of_float f in
  212. write_real_i32 ch (Int64.to_int32 (Int64.shift_right_logical i64 32));
  213. write_real_i32 ch (Int64.to_int32 i64)
  214. let read_string_max ch len =
  215. let b = Buffer.create 0 in
  216. let rec loop l =
  217. if l = 0 then begin
  218. let s = Buffer.contents b in
  219. String.sub s 0 (String.length s - 1)
  220. end else
  221. let c = read ch in
  222. if c = '\000' then
  223. Buffer.contents b
  224. else begin
  225. Buffer.add_char b c;
  226. loop (l - 1)
  227. end;
  228. in
  229. loop len
  230. let parse_push_item ch len =
  231. let id = read_byte ch in
  232. match id with
  233. | 0 -> PString (read_string_max ch len)
  234. | 1 -> PFloat (read_real_i32 ch)
  235. | 2 -> PNull
  236. | 3 -> PUndefined
  237. | 4 -> PReg (read_byte ch)
  238. | 5 -> PBool (read_byte ch <> 0)
  239. | 6 -> PDouble (read_mm_double ch)
  240. | 7 -> PInt (read_real_i32 ch)
  241. | 8 -> PStack (read_byte ch)
  242. | 9 -> PStack2 (read_ui16 ch)
  243. | _ -> error (sprintf "Unknown PUSH item id : %d" id)
  244. let rec parse_push_items ch len =
  245. if len < 0 then error "PUSH parse overflow";
  246. if len = 0 then
  247. []
  248. else
  249. let item = parse_push_item ch len in
  250. item :: parse_push_items ch (len - 1 - push_item_length item)
  251. let rec read_strings ch n =
  252. if n = 0 then
  253. []
  254. else
  255. let s = read_string ch in
  256. s :: read_strings ch (n-1)
  257. let parse_function_decl ch =
  258. let name = read_string ch in
  259. let nargs = read_ui16 ch in
  260. let args = read_strings ch nargs in
  261. let clen = read_ui16 ch in
  262. {
  263. f_name = name;
  264. f_args = args;
  265. f_codelen = clen;
  266. }
  267. let parse_f2_flags n =
  268. let flags = ref [] in
  269. let v = ref 1 in
  270. let add_flag f =
  271. if n land !v <> 0 then flags := f :: !flags;
  272. v := !v lsl 1
  273. in
  274. List.iter add_flag
  275. [ThisRegister; ThisNoVar; ArgumentsRegister; ArgumentsNoVar; SuperRegister;
  276. SuperNoVar; RootRegister; ParentRegister; GlobalRegister];
  277. !flags
  278. let parse_function_decl2 ch =
  279. let name = read_string ch in
  280. let nargs = read_ui16 ch in
  281. let nregs = read_byte ch in
  282. let flags = parse_f2_flags (read_ui16 ch) in
  283. let rec loop n =
  284. if n = 0 then
  285. []
  286. else
  287. let r = read_byte ch in
  288. let s = read_string ch in
  289. (r,s) :: loop (n-1)
  290. in
  291. let args = loop nargs in
  292. let clen = read_ui16 ch in
  293. {
  294. f2_name = name;
  295. f2_args = args;
  296. f2_flags = flags;
  297. f2_codelen = clen;
  298. f2_nregs = nregs;
  299. }
  300. let parse_action ch =
  301. let id = read_byte ch in
  302. let len = (if id >= 0x80 then read_ui16 ch else 0) in
  303. let len = (if len = 0xFFFF then 0 else len) in
  304. let act =
  305. (match id with
  306. | 0x81 ->
  307. AGotoFrame (read_ui16 ch)
  308. | 0x83 ->
  309. let url = read_string ch in
  310. let target = read_string ch in
  311. AGetURL (url,target)
  312. | 0x87 ->
  313. ASetReg (read_byte ch)
  314. | 0x88 ->
  315. let nstrs = read_ui16 ch in
  316. AStringPool (read_strings ch nstrs)
  317. | 0x8A ->
  318. let frame = read_ui16 ch in
  319. let skip = read_byte ch in
  320. AWaitForFrame (frame,skip)
  321. | 0x8B ->
  322. ASetTarget (read_string ch)
  323. | 0x8C ->
  324. AGotoLabel (read_string ch)
  325. | 0x8D ->
  326. AWaitForFrame2 (read_byte ch)
  327. | 0x8E ->
  328. AFunction2 (parse_function_decl2 ch)
  329. | 0x8F ->
  330. let flags = read_byte ch in
  331. let tsize = read_ui16 ch in
  332. let csize = read_ui16 ch in
  333. let fsize = read_ui16 ch in
  334. let tstyle = (if flags land 4 == 0 then TryVariable (read_string ch) else TryRegister (read_byte ch)) in
  335. ATry {
  336. tr_style = tstyle;
  337. tr_trylen = tsize;
  338. tr_catchlen = (if flags land 1 == 0 then None else Some csize);
  339. tr_finallylen = (if flags land 2 == 0 then None else Some fsize);
  340. }
  341. | 0x94 ->
  342. let size = read_ui16 ch in
  343. AWith size
  344. | 0x96 ->
  345. APush (parse_push_items ch len)
  346. | 0x99 ->
  347. AJump (read_i16 ch)
  348. | 0x9A ->
  349. AGetURL2 (read_byte ch)
  350. | 0x9B ->
  351. AFunction (parse_function_decl ch)
  352. | 0x9D ->
  353. ACondJump (read_i16 ch)
  354. | 0x9E ->
  355. ACallFrame
  356. | 0x9F ->
  357. let flags = read_byte ch in
  358. let play = flags land 1 <> 0 in
  359. let delta = (if flags land 2 == 0 then None else Some (read_ui16 ch)) in
  360. AGotoFrame2 (play,delta)
  361. | _ ->
  362. try
  363. Hashtbl.find opcodes_rev id
  364. with
  365. Not_found ->
  366. printf "Unknown Action 0x%.2X (%d)\n" id len;
  367. AUnknown (id,nread_string ch len)
  368. ) in
  369. (* let len2 = action_data_length act in
  370. if len <> len2 then error (sprintf "Datalen mismatch for action 0x%.2X (%d != %d)" id len len2);
  371. *) act
  372. let size_to_jump_index acts curindex size =
  373. let delta = ref 0 in
  374. let size = ref size in
  375. if !size >= 0 then begin
  376. while !size > 0 do
  377. incr delta;
  378. size := !size - action_length (DynArray.get acts (curindex + !delta));
  379. if !size < 0 then error "Unaligned code";
  380. done;
  381. end else begin
  382. while !size < 0 do
  383. size := !size + action_length (DynArray.get acts (curindex + !delta));
  384. if !size > 0 then error "Unaligned code";
  385. decr delta;
  386. done;
  387. end;
  388. !delta
  389. let parse_actions ch =
  390. let acts = DynArray.create() in
  391. let rec loop() =
  392. match parse_action ch with
  393. | AEnd -> ()
  394. | AUnknown (0xFF,"") ->
  395. DynArray.add acts APlay;
  396. DynArray.add acts APlay;
  397. DynArray.add acts APlay;
  398. loop()
  399. | a ->
  400. DynArray.add acts a;
  401. loop();
  402. in
  403. loop();
  404. (* process jump indexes *)
  405. let process_jump curindex = function
  406. | AJump size ->
  407. let index = size_to_jump_index acts curindex size in
  408. DynArray.set acts curindex (AJump index)
  409. | ACondJump size ->
  410. let index = size_to_jump_index acts curindex size in
  411. DynArray.set acts curindex (ACondJump index)
  412. | AFunction f ->
  413. let index = size_to_jump_index acts curindex f.f_codelen in
  414. DynArray.set acts curindex (AFunction { f with f_codelen = index })
  415. | AFunction2 f ->
  416. let index = size_to_jump_index acts curindex f.f2_codelen in
  417. DynArray.set acts curindex (AFunction2 { f with f2_codelen = index })
  418. | AWith size ->
  419. let index = size_to_jump_index acts curindex size in
  420. DynArray.set acts curindex (AWith index)
  421. | ATry t ->
  422. let tindex = size_to_jump_index acts curindex t.tr_trylen in
  423. let cindex = (match t.tr_catchlen with None -> None | Some size -> Some (size_to_jump_index acts (curindex + tindex) size)) in
  424. let findex = (match t.tr_finallylen with None -> None | Some size -> Some (size_to_jump_index acts (curindex + tindex + (match cindex with None -> 0 | Some i -> i)) size)) in
  425. DynArray.set acts curindex (ATry { t with tr_trylen = tindex; tr_catchlen = cindex; tr_finallylen = findex })
  426. | _ ->
  427. ()
  428. in
  429. DynArray.iteri process_jump acts;
  430. acts
  431. let jump_index_to_size acts curindex target =
  432. let size = ref 0 in
  433. if target >= 0 then begin
  434. for i = 1 to target do
  435. size := !size + action_length (DynArray.get acts (curindex + i));
  436. done;
  437. end else begin
  438. for i = 0 downto target+1 do
  439. size := !size - action_length (DynArray.get acts (curindex + i));
  440. done;
  441. end;
  442. !size
  443. let rec write_strings ch = function
  444. | [] -> ()
  445. | s :: l ->
  446. write_string ch s;
  447. write_strings ch l
  448. let write_push_item_data ch = function
  449. | PString s -> write_string ch s
  450. | PFloat f -> write_real_i32 ch f
  451. | PNull -> ()
  452. | PUndefined -> ()
  453. | PReg r -> write_byte ch r
  454. | PBool b -> write_byte ch (if b then 1 else 0)
  455. | PDouble f -> write_mm_double ch f
  456. | PInt n -> write_real_i32 ch n
  457. | PStack index -> write_byte ch index
  458. | PStack2 index -> write_ui16 ch index
  459. let f2_flags_value flags =
  460. let fval = function
  461. | ThisRegister -> 1
  462. | ThisNoVar -> 2
  463. | ArgumentsRegister -> 4
  464. | ArgumentsNoVar -> 8
  465. | SuperRegister -> 16
  466. | SuperNoVar -> 32
  467. | RootRegister -> 64
  468. | ParentRegister -> 128
  469. | GlobalRegister -> 256
  470. in
  471. List.fold_left (fun n f -> n lor (fval f)) 0 flags
  472. let write_action_data acts curindex ch = function
  473. | AGotoFrame frame ->
  474. write_ui16 ch frame
  475. | AGetURL (url,target) ->
  476. write_string ch url;
  477. write_string ch target
  478. | ASetReg reg ->
  479. write_byte ch reg
  480. | AStringPool strs ->
  481. write_ui16 ch (List.length strs);
  482. write_strings ch strs
  483. | AWaitForFrame (frame,skip) ->
  484. write_ui16 ch frame;
  485. write_byte ch skip
  486. | ASetTarget target ->
  487. write_string ch target
  488. | AGotoLabel label ->
  489. write_string ch label
  490. | AWaitForFrame2 n ->
  491. write_byte ch n
  492. | AFunction2 f ->
  493. write_string ch f.f2_name;
  494. write_ui16 ch (List.length f.f2_args);
  495. write_byte ch f.f2_nregs;
  496. write_ui16 ch (f2_flags_value f.f2_flags);
  497. List.iter (fun (r,s) ->
  498. write_byte ch r;
  499. write_string ch s;
  500. ) f.f2_args;
  501. let size = jump_index_to_size acts curindex f.f2_codelen in
  502. write_ui16 ch size;
  503. | ATry t ->
  504. let tsize = jump_index_to_size acts curindex t.tr_trylen in
  505. let csize = (match t.tr_catchlen with None -> 0 | Some idx -> jump_index_to_size acts (curindex + t.tr_trylen) idx) in
  506. let fsize = (match t.tr_finallylen with None -> 0 | Some idx -> jump_index_to_size acts (curindex + t.tr_trylen + (match t.tr_catchlen with None -> 0 | Some n -> n)) idx) in
  507. let flags = (if t.tr_catchlen <> None then 1 else 0) lor (if t.tr_finallylen <> None then 2 else 0) lor (match t.tr_style with TryRegister _ -> 4 | TryVariable _ -> 0) in
  508. write_byte ch flags;
  509. write_ui16 ch tsize;
  510. write_ui16 ch csize;
  511. write_ui16 ch fsize;
  512. (match t.tr_style with
  513. | TryVariable v -> write_string ch v
  514. | TryRegister r -> write_byte ch r)
  515. | AWith target ->
  516. let size = jump_index_to_size acts curindex target in
  517. write_ui16 ch size
  518. | APush items ->
  519. List.iter (fun item ->
  520. write_byte ch (push_item_id item);
  521. write_push_item_data ch item
  522. ) items
  523. | AJump target ->
  524. let size = jump_index_to_size acts curindex target in
  525. write_i16 ch size
  526. | AGetURL2 n ->
  527. write_byte ch n
  528. | AFunction f ->
  529. write_string ch f.f_name;
  530. write_ui16 ch (List.length f.f_args);
  531. write_strings ch f.f_args;
  532. let size = jump_index_to_size acts curindex f.f_codelen in
  533. write_ui16 ch size;
  534. | ACondJump target ->
  535. let size = jump_index_to_size acts curindex target in
  536. write_i16 ch size;
  537. | AGotoFrame2 (play,None) ->
  538. write_byte ch (if play then 1 else 0)
  539. | AGotoFrame2 (play,Some delta) ->
  540. write_byte ch (if play then 3 else 2);
  541. write_ui16 ch delta;
  542. | ACallFrame ->
  543. ()
  544. | AUnknown (_,data) ->
  545. nwrite_string ch data
  546. | _ ->
  547. assert false
  548. let write_action acts curindex ch a =
  549. let id = action_id a in
  550. let len = action_data_length a in
  551. if id < 0x80 && len > 0 then error "Invalid Action Written";
  552. write_byte ch id;
  553. if len > 0 || id >= 0x80 then begin
  554. write_ui16 ch len;
  555. write_action_data acts curindex ch a;
  556. end
  557. let write_actions ch acts =
  558. DynArray.iteri (fun index act -> write_action acts index ch act) acts;
  559. write_action acts (DynArray.length acts) ch AEnd
  560. let sprintf = Printf.sprintf
  561. let action_string get_ident pos = function
  562. | AGotoFrame n -> sprintf "GOTOFRAME %d" n
  563. | AGetURL (a,b) -> sprintf "GETURL '%s' '%s'" a b
  564. | ASetReg n -> sprintf "SETREG %d" n
  565. | AStringPool strlist ->
  566. let b = Buffer.create 0 in
  567. Buffer.add_string b "STRINGS ";
  568. let p = ref 0 in
  569. List.iter (fun s ->
  570. Buffer.add_string b (string_of_int !p);
  571. incr p;
  572. Buffer.add_char b ':';
  573. Buffer.add_string b s;
  574. Buffer.add_char b ' ';
  575. ) strlist;
  576. Buffer.contents b
  577. | AWaitForFrame (i,j) -> sprintf "WAITFORFRAME %d %d" i j
  578. | ASetTarget s -> sprintf "SETTARGET %s" s
  579. | AGotoLabel s -> sprintf "GOTOLABEL %s" s
  580. | AWaitForFrame2 n -> sprintf "WAITFORFRAME2 %d" n
  581. | AFunction2 f ->
  582. let b = Buffer.create 0 in
  583. Buffer.add_string b "FUNCTION2 ";
  584. Buffer.add_string b f.f2_name;
  585. Buffer.add_char b '(';
  586. Buffer.add_string b (String.concat "," (List.map (fun (n,str) -> sprintf "%d:%s" n str) f.f2_args));
  587. Buffer.add_char b ')';
  588. Buffer.add_string b (sprintf " nregs:%d flags:%d " f.f2_nregs (f2_flags_value f.f2_flags));
  589. Buffer.add_string b (sprintf "0x%.4X" (pos + 1 + f.f2_codelen));
  590. Buffer.contents b
  591. | APush pl ->
  592. let b = Buffer.create 0 in
  593. Buffer.add_string b "PUSH";
  594. List.iter (fun it ->
  595. Buffer.add_char b ' ';
  596. match it with
  597. | PString s ->
  598. Buffer.add_char b '"';
  599. Buffer.add_string b s;
  600. Buffer.add_char b '"'
  601. | PFloat _ ->
  602. Buffer.add_string b "<float>"
  603. | PNull ->
  604. Buffer.add_string b "null"
  605. | PUndefined ->
  606. Buffer.add_string b "undefined"
  607. | PReg n ->
  608. Buffer.add_string b (sprintf "reg:%d" n)
  609. | PBool fl ->
  610. Buffer.add_string b (if fl then "true" else "false")
  611. | PDouble _ ->
  612. Buffer.add_string b "<double>"
  613. | PInt i ->
  614. Buffer.add_string b (Int32.to_string i)
  615. | PStack n
  616. | PStack2 n ->
  617. Buffer.add_char b '[';
  618. Buffer.add_string b (string_of_int n);
  619. Buffer.add_char b ':';
  620. Buffer.add_string b (get_ident n);
  621. Buffer.add_char b ']';
  622. ) pl;
  623. Buffer.contents b
  624. | ATry _ -> sprintf "TRY"
  625. | AWith n -> sprintf "WITH %d" n
  626. | AJump n -> sprintf "JUMP 0x%.4X" (n + pos + 1)
  627. | AGetURL2 n -> sprintf "GETURL2 %d" n
  628. | AFunction f ->
  629. let b = Buffer.create 0 in
  630. Buffer.add_string b "FUNCTION ";
  631. Buffer.add_string b f.f_name;
  632. Buffer.add_char b '(';
  633. Buffer.add_string b (String.concat "," f.f_args);
  634. Buffer.add_char b ')';
  635. Buffer.add_string b (sprintf " 0x%.4X" (pos + 1 + f.f_codelen));
  636. Buffer.contents b
  637. | ACondJump n -> sprintf "CJMP 0x%.4X" (n + pos + 1)
  638. | AGotoFrame2 (b,None) -> sprintf "GOTOFRAME2 %b" b
  639. | AGotoFrame2 (b,Some i) -> sprintf "GOTOFRAME2 %b %d" b i
  640. | AUnknown (tag,_) -> sprintf "??? 0x%.2X" tag
  641. | op ->
  642. try
  643. Hashtbl.find opcodes_names op
  644. with
  645. Not_found -> assert false