1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111 |
- (*
- * 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 As3
- let parse_idents = true
- let parse_namespaces = true && parse_idents
- let parse_ns_sets = true && parse_namespaces
- let parse_names = true && parse_ns_sets
- let parse_mtypes = true && parse_names
- let parse_metadata = true && parse_mtypes
- let parse_classes = true && parse_metadata
- let parse_statics = true && parse_classes
- let parse_inits = true && parse_statics
- let parse_functions = true && parse_inits
- let parse_bytecode = true && parse_functions
- let magic_index (i : int) : 'a index =
- Obj.magic i
- let magic_index_nz (i : int) : 'a index_nz =
- Obj.magic i
- let index (t : 'a array) (i : int) : 'a index =
- if i <= 0 || i - 1 >= Array.length t then assert false;
- magic_index i
- let index_opt t i =
- if i = 0 then
- None
- else
- Some (index t i)
- let index_nz (t : 'a array) (i : int) : 'a index_nz =
- if i < 0 || i >= Array.length t then assert false;
- Obj.magic i
- let index_int (i : 'a index) =
- (Obj.magic i : int)
- let index_nz_int (i : 'a index_nz) =
- (Obj.magic i : int)
- let iget (t : 'a array) (i : 'a index) : 'a =
- t.(index_int i - 1)
- let no_nz (i : 'a index_nz) : 'a index =
- Obj.magic ((Obj.magic i) + 1)
- (* ************************************************************************ *)
- (* LENGTH *)
- let as3_empty_index ctx =
- let empty_index = ref 0 in
- try
- Array.iteri (fun i x -> if x = "" then begin empty_index := (i + 1); raise Exit; end) ctx.as3_idents;
- if parse_idents then assert false;
- magic_index 0
- with Exit ->
- index ctx.as3_idents (!empty_index)
- let as3_int_length i =
- if Int32.compare (Int32.shift_right_logical i 28) 0l > 0 then
- 5
- else if Int32.compare (Int32.shift_right i 21) 0l > 0 then
- 4
- else if Int32.compare (Int32.shift_right i 14) 0l > 0 then
- 3
- else if Int32.compare (Int32.shift_right i 7) 0l > 0 then
- 2
- else
- 1
- let as3_uint_length i =
- as3_int_length i
- let sum f l =
- List.fold_left (fun acc n -> acc + f n) 0 l
- let int_length i =
- as3_int_length (Int32.of_int i)
- let idx_length i =
- int_length (index_int i)
- let idx_length_nz i =
- int_length (index_nz_int i)
- let idx_opt_length = function
- | None -> int_length 0
- | Some i -> idx_length i
- let as3_ident_length s =
- let n = String.length s in
- n + int_length n
- let as3_namespace_length ei = function
- | A3NStaticProtected o
- | A3NPrivate o ->
- 1 + (match o with None -> int_length 0 | Some n -> idx_length n)
- | A3NPublic o
- | A3NInternal o ->
- 1 + idx_length (match o with None -> ei | Some n -> n)
- | A3NExplicit n
- | A3NNamespace n
- | A3NProtected n ->
- 1 + idx_length n
- let as3_ns_set_length l =
- int_length (List.length l) + sum idx_length l
- let rec as3_name_length t =
- 1 +
- match t with
- | A3MMultiName (id,r) ->
- idx_opt_length id + idx_length r
- | A3MName (id,r) ->
- idx_length r + idx_length id
- | A3MNSAny (id) ->
- int_length 0 + idx_length id
- | A3MAny ->
- int_length 0 + int_length 0
- | A3MRuntimeName i ->
- idx_length i
- | A3MRuntimeNameLate ->
- 0
- | A3MMultiNameLate idx ->
- idx_length idx
- | A3MAttrib n ->
- as3_name_length n - 1
- | A3MParams (id,pl) ->
- idx_length id + 1 + (sum idx_length pl)
- let as3_value_length extra = function
- | A3VNone -> if extra then 2 else 1
- | A3VNull | A3VBool _ -> 2
- | A3VString s -> 1 + idx_length s
- | A3VInt s -> 1 + idx_length s
- | A3VUInt s -> 1 + idx_length s
- | A3VFloat s -> 1 + idx_length s
- | A3VNamespace (_,s) -> 1 + idx_length s
- let as3_method_type_length m =
- 1 +
- idx_opt_length m.mt3_ret +
- sum idx_opt_length m.mt3_args +
- idx_opt_length m.mt3_debug_name +
- 1 +
- (match m.mt3_dparams with None -> 0 | Some l -> 1 + sum (as3_value_length true) l) +
- (match m.mt3_pnames with None -> 0 | Some l -> sum idx_opt_length l)
- let list_length f l =
- match Array.length l with
- | 0 -> int_length 0
- | n ->
- Array.fold_left (fun acc x -> acc + f x) (int_length (n + 1)) l
- let list2_length f l =
- Array.fold_left (fun acc x -> acc + f x) (int_length (Array.length l)) l
- let as3_field_length f =
- idx_length f.f3_name +
- 1 +
- int_length f.f3_slot +
- (match f.f3_kind with
- | A3FMethod m ->
- idx_length_nz m.m3_type
- | A3FClass c ->
- idx_length_nz c
- | A3FFunction id ->
- idx_length_nz id
- | A3FVar v ->
- idx_opt_length v.v3_type + as3_value_length false v.v3_value) +
- match f.f3_metas with
- | None -> 0
- | Some l -> list2_length idx_length_nz l
- let as3_class_length c =
- idx_length c.cl3_name +
- idx_opt_length c.cl3_super +
- 1 +
- (match c.cl3_namespace with None -> 0 | Some r -> idx_length r) +
- list2_length idx_length c.cl3_implements +
- idx_length_nz c.cl3_construct +
- list2_length as3_field_length c.cl3_fields
- let as3_static_length s =
- idx_length_nz s.st3_method +
- list2_length as3_field_length s.st3_fields
- let as3_metadata_length m =
- idx_length m.meta3_name +
- list2_length (fun (i1,i2) -> idx_opt_length i1 + idx_length i2) m.meta3_data
- let as3_try_catch_length t =
- int_length t.tc3_start +
- int_length t.tc3_end +
- int_length t.tc3_handle +
- idx_opt_length t.tc3_type +
- idx_opt_length t.tc3_name
- let as3_function_length f =
- let clen = MultiArray.fold_left (fun acc op -> acc + As3code.length op) 0 f.fun3_code in
- idx_length_nz f.fun3_id +
- int_length f.fun3_stack_size +
- int_length f.fun3_nregs +
- int_length f.fun3_init_scope +
- int_length f.fun3_max_scope +
- int_length clen +
- clen +
- list2_length as3_try_catch_length f.fun3_trys +
- list2_length as3_field_length f.fun3_locals
- let as3_length ctx =
- let ei = as3_empty_index ctx in
- String.length ctx.as3_unknown +
- 4 +
- list_length as3_int_length ctx.as3_ints +
- list_length as3_uint_length ctx.as3_uints +
- list_length (fun _ -> 8) ctx.as3_floats
- + if parse_idents then list_length as3_ident_length ctx.as3_idents
- + if parse_namespaces then list_length (as3_namespace_length ei) ctx.as3_namespaces
- + if parse_ns_sets then list_length as3_ns_set_length ctx.as3_nsets
- + if parse_names then list_length as3_name_length ctx.as3_names
- + if parse_mtypes then list2_length as3_method_type_length ctx.as3_method_types
- + if parse_metadata then list2_length as3_metadata_length ctx.as3_metadatas
- + if parse_classes then list2_length as3_class_length ctx.as3_classes
- + if parse_statics then Array.fold_left (fun acc x -> acc + as3_static_length x) 0 ctx.as3_statics
- + if parse_inits then list2_length as3_static_length ctx.as3_inits
- + if parse_functions then list2_length as3_function_length ctx.as3_functions
- else 0 else 0 else 0 else 0 else 0 else 0 else 0 else 0 else 0 else 0
- (* ************************************************************************ *)
- (* PARSING *)
- let read_as3_int ch =
- let a = IO.read_byte ch in
- if a < 128 then
- Int32.of_int a
- else
- let a = a land 127 in
- let b = IO.read_byte ch in
- if b < 128 then
- Int32.of_int ((b lsl 7) lor a)
- else
- let b = b land 127 in
- let c = IO.read_byte ch in
- if c < 128 then
- Int32.of_int ((c lsl 14) lor (b lsl 7) lor a)
- else
- let c = c land 127 in
- let d = IO.read_byte ch in
- if d < 128 then
- Int32.of_int ((d lsl 21) lor (c lsl 14) lor (b lsl 7) lor a)
- else
- let d = d land 127 in
- let e = IO.read_byte ch in
- if e > 15 then assert false;
- let small = Int32.of_int ((d lsl 21) lor (c lsl 14) lor (b lsl 7) lor a) in
- let big = Int32.shift_left (Int32.of_int e) 28 in
- Int32.logor big small
- let read_as3_uint ch =
- read_as3_int ch
- let read_int ch =
- Int32.to_int (read_as3_int ch)
- let read_ident ch =
- IO.nread_string ch (read_int ch)
- let read_namespace idents ch =
- let k = IO.read_byte ch in
- let p = index_opt idents (read_int ch) in
- match k with
- | 0x05 ->
- A3NPrivate p
- | 0x08 ->
- (match p with
- | None -> assert false
- | Some idx -> A3NNamespace idx)
- | 0x16 ->
- (match p with
- | None -> assert false
- | Some p when iget idents p = "" -> A3NPublic None
- | _ -> A3NPublic p)
- | 0x17 ->
- (match p with
- | None -> assert false
- | Some p when iget idents p = "" -> A3NInternal None
- | _ -> A3NInternal p)
- | 0x18 ->
- (match p with
- | None -> assert false
- | Some idx -> A3NProtected idx)
- | 0x19 ->
- (match p with
- | None -> assert false
- | Some idx -> A3NExplicit idx)
- | 0x1A ->
- A3NStaticProtected p
- | _ ->
- assert false
- let read_ns_set namespaces ch =
- let rec loop n =
- if n = 0 then
- []
- else
- let r = index namespaces (read_int ch) in
- r :: loop (n - 1)
- in
- loop (IO.read_byte ch)
- let rec read_name ctx ?k ch =
- let k = (match k with None -> IO.read_byte ch | Some k -> k) in
- match k with
- | 0x07 ->
- let i = read_int ch in
- let j = read_int ch in
- if i = 0 && j = 0 then
- A3MAny
- else if i = 0 && j <> 0 then
- let id = index ctx.as3_idents j in
- A3MNSAny(id)
- else
- let ns = index ctx.as3_namespaces i in
- let id = index ctx.as3_idents j in
- (* both ns and id can be 0 <=> '*' *)
- A3MName (id,ns)
- | 0x09 ->
- let id = index_opt ctx.as3_idents (read_int ch) in
- let ns = index ctx.as3_nsets (read_int ch) in
- A3MMultiName (id,ns)
- | 0x0D ->
- A3MAttrib (read_name ctx ~k:0x07 ch)
- | 0x0E ->
- A3MAttrib (read_name ctx ~k:0x09 ch)
- | 0x0F ->
- let id = index ctx.as3_idents (read_int ch) in
- A3MRuntimeName id
- | 0x10 ->
- A3MAttrib (read_name ctx ~k:0x0F ch)
- | 0x11 ->
- A3MRuntimeNameLate
- | 0x12 ->
- A3MAttrib (read_name ctx ~k:0x11 ch)
- | 0x1B ->
- let ns = index ctx.as3_nsets (read_int ch) in
- A3MMultiNameLate ns
- | 0x1C ->
- A3MAttrib (read_name ctx ~k:0x1B ch)
- | 0x1D ->
- let rec loop n =
- if n = 0 then
- []
- else
- let name = magic_index (read_int ch) in
- name :: loop (n - 1)
- in
- let id = magic_index (read_int ch) in
- A3MParams (id,loop (IO.read_byte ch))
- | n ->
- prerr_endline (string_of_int n);
- assert false
- let read_value ctx ch extra =
- let idx = read_int ch in
- if idx = 0 then begin
- if extra && IO.read_byte ch <> 0 then assert false;
- A3VNone
- end else match IO.read_byte ch with
- | 0x01 ->
- A3VString (index ctx.as3_idents idx)
- | 0x03 ->
- A3VInt (index ctx.as3_ints idx)
- | 0x04 ->
- A3VUInt (index ctx.as3_uints idx)
- | 0x06 ->
- A3VFloat (index ctx.as3_floats idx)
- | 0x08 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0x05 as n->
- A3VNamespace (n,index ctx.as3_namespaces idx)
- | 0x0A ->
- if idx <> 0x0A then assert false;
- A3VBool false
- | 0x0B ->
- if idx <> 0x0B then assert false;
- A3VBool true
- | 0x0C ->
- if idx <> 0x0C then assert false;
- A3VNull
- | _ ->
- assert false
- let read_method_type ctx ch =
- let nargs = IO.read_byte ch in
- let tret = index_opt ctx.as3_names (read_int ch) in
- let targs = Array.to_list (Array.init nargs (fun _ -> index_opt ctx.as3_names (read_int ch))) in
- let dname = index_opt ctx.as3_idents (read_int ch) in
- let flags = IO.read_byte ch in
- let dparams = (if flags land 0x08 <> 0 then
- Some (Array.to_list (Array.init (IO.read_byte ch) (fun _ -> read_value ctx ch true)))
- else
- None
- ) in
- let pnames = (if flags land 0x80 <> 0 then
- Some (Array.to_list (Array.init nargs (fun _ -> index_opt ctx.as3_idents (read_int ch))))
- else
- None
- ) in
- {
- mt3_ret = tret;
- mt3_args = targs;
- mt3_var_args = flags land 0x04 <> 0;
- mt3_native = flags land 0x20 <> 0;
- mt3_new_block = flags land 0x02 <> 0;
- mt3_debug_name = dname;
- mt3_dparams = dparams;
- mt3_pnames = pnames;
- mt3_arguments_defined = flags land 0x01 <> 0;
- mt3_uses_dxns = flags land 0x40 <> 0;
- mt3_unused_flag = flags land 0x10 <> 0;
- }
- let read_list ch f =
- match read_int ch with
- | 0 -> [||]
- | n -> Array.init (n - 1) (fun _ -> f ch)
- let read_list2 ch f =
- Array.init (read_int ch) (fun _ -> f ch)
- let read_field ctx ch =
- let name = index ctx.as3_names (read_int ch) in
- let kind = IO.read_byte ch in
- let has_meta = kind land 0x40 <> 0 in
- let slot = read_int ch in
- let kind = (match kind land 0xF with
- | 0x00 | 0x06 as kind ->
- let t = index_opt ctx.as3_names (read_int ch) in
- let value = read_value ctx ch false in
- A3FVar {
- v3_type = t;
- v3_value = value;
- v3_const = kind = 0x06;
- }
- | 0x02
- | 0x03
- | 0x01 ->
- let meth = index_nz ctx.as3_method_types (read_int ch) in
- let final = kind land 0x10 <> 0 in
- let override = kind land 0x20 <> 0 in
- A3FMethod {
- m3_type = meth;
- m3_final = final;
- m3_override = override;
- m3_kind = (match kind land 0xF with 0x01 -> MK3Normal | 0x02 -> MK3Getter | 0x03 -> MK3Setter | _ -> assert false);
- }
- | 0x04 ->
- let c = index_nz ctx.as3_classes (read_int ch) in
- A3FClass c
- | 0x05 ->
- let f = index_nz ctx.as3_method_types (read_int ch) in
- A3FFunction f
- | _ ->
- assert false
- ) in
- let metas = (if has_meta then
- Some (read_list2 ch (fun _ -> index_nz ctx.as3_metadatas (read_int ch)))
- else
- None
- ) in
- {
- f3_name = name;
- f3_slot = slot;
- f3_kind = kind;
- f3_metas = metas;
- }
- let read_class ctx ch =
- let name = index ctx.as3_names (read_int ch) in
- let csuper = index_opt ctx.as3_names (read_int ch) in
- let flags = IO.read_byte ch in
- let namespace =
- if flags land 8 <> 0 then
- let r = index ctx.as3_namespaces (read_int ch) in
- Some r
- else
- None
- in
- let impls = read_list2 ch (fun _ -> index ctx.as3_names (read_int ch)) in
- let construct = index_nz ctx.as3_method_types (read_int ch) in
- let fields = read_list2 ch (read_field ctx) in
- {
- cl3_name = name;
- cl3_super = csuper;
- cl3_sealed = (flags land 1) <> 0;
- cl3_final = (flags land 2) <> 0;
- cl3_interface = (flags land 4) <> 0;
- cl3_namespace = namespace;
- cl3_implements = impls;
- cl3_construct = construct;
- cl3_fields = fields;
- }
- let read_static ctx ch =
- let meth = index_nz ctx.as3_method_types (read_int ch) in
- let fields = read_list2 ch (read_field ctx) in
- {
- st3_method = meth;
- st3_fields = fields;
- }
- let read_metadata ctx ch =
- let name = index ctx.as3_idents (read_int ch) in
- let data = read_list2 ch (fun _ -> index_opt ctx.as3_idents (read_int ch)) in
- let data = Array.map (fun i1 -> i1 , index ctx.as3_idents (read_int ch)) data in
- {
- meta3_name = name;
- meta3_data = data;
- }
- let read_try_catch ctx ch =
- let start = read_int ch in
- let pend = read_int ch in
- let handle = read_int ch in
- let t = index_opt ctx.as3_names (read_int ch) in
- let name = index_opt ctx.as3_names (read_int ch) in
- {
- tc3_start = start;
- tc3_end = pend;
- tc3_handle = handle;
- tc3_type = t;
- tc3_name = name;
- }
- let read_function ctx ch =
- let id = index_nz ctx.as3_method_types (read_int ch) in
- let ss = read_int ch in
- let nregs = read_int ch in
- let init_scope = read_int ch in
- let max_scope = read_int ch in
- let size = read_int ch in
- let code = if parse_bytecode then As3code.parse ch size else MultiArray.init size (fun _ -> A3Unk (IO.read ch)) in
- let trys = read_list2 ch (read_try_catch ctx) in
- let local_funs = read_list2 ch (read_field ctx) in
- {
- fun3_id = id;
- fun3_stack_size = ss;
- fun3_nregs = nregs;
- fun3_init_scope = init_scope;
- fun3_max_scope = max_scope;
- fun3_code = code;
- fun3_trys = trys;
- fun3_locals = local_funs;
- }
- let header_magic = 0x002E0010
- let parse ch len =
- let ch, get_pos = IO.pos_in ch in
- if IO.read_i32 ch <> header_magic then assert false;
- let ints = read_list ch read_as3_int in
- let uints = read_list ch read_as3_uint in
- let floats = read_list ch IO.read_double in
- let idents = (if parse_idents then read_list ch read_ident else [||]) in
- let idents = (if parse_idents then begin if ExtArray.Array.exists (fun i -> i="") idents then idents else Array.append idents [|""|] end else [||]) in
- let namespaces = (if parse_namespaces then read_list ch (read_namespace idents) else [||]) in
- let nsets = (if parse_ns_sets then read_list ch (read_ns_set namespaces) else [||]) in
- let ctx = {
- as3_ints = ints;
- as3_uints = uints;
- as3_floats = floats;
- as3_idents = idents;
- as3_namespaces = namespaces;
- as3_nsets = nsets;
- as3_names = [||];
- as3_method_types = [||];
- as3_metadatas = [||];
- as3_classes = [||];
- as3_statics = [||];
- as3_inits = [||];
- as3_functions = [||];
- as3_unknown = "";
- } in
- if parse_names then ctx.as3_names <- read_list ch (read_name ctx);
- if parse_mtypes then ctx.as3_method_types <- read_list2 ch (read_method_type ctx);
- if parse_metadata then ctx.as3_metadatas <- read_list2 ch (read_metadata ctx);
- if parse_classes then ctx.as3_classes <- read_list2 ch (read_class ctx);
- if parse_statics then ctx.as3_statics <- Array.map (fun _ -> read_static ctx ch) ctx.as3_classes;
- if parse_inits then ctx.as3_inits <- read_list2 ch (read_static ctx);
- if parse_functions then ctx.as3_functions <- read_list2 ch (read_function ctx);
- ctx.as3_unknown <- IO.really_nread_string ch (len - (get_pos()));
- if parse_functions && String.length ctx.as3_unknown <> 0 then assert false;
- (* let len2 = as3_length ctx in
- if len2 <> len then begin Printf.printf "%d != %d" len len2; assert false; end;
- *) ctx
- (* ************************************************************************ *)
- (* WRITING *)
- let write_as3_int ch i =
- let e = Int32.to_int (Int32.shift_right_logical i 28) in
- let d = Int32.to_int (Int32.shift_right i 21) land 0x7F in
- let c = Int32.to_int (Int32.shift_right i 14) land 0x7F in
- let b = Int32.to_int (Int32.shift_right i 7) land 0x7F in
- let a = Int32.to_int (Int32.logand i 0x7Fl) in
- if b <> 0 || c <> 0 || d <> 0 || e <> 0 then begin
- IO.write_byte ch (a lor 0x80);
- if c <> 0 || d <> 0 || e <> 0 then begin
- IO.write_byte ch (b lor 0x80);
- if d <> 0 || e <> 0 then begin
- IO.write_byte ch (c lor 0x80);
- if e <> 0 then begin
- IO.write_byte ch (d lor 0x80);
- IO.write_byte ch e;
- end else
- IO.write_byte ch d;
- end else
- IO.write_byte ch c;
- end else
- IO.write_byte ch b;
- end else
- IO.write_byte ch a
- let write_as3_uint = write_as3_int
- let write_int ch i =
- write_as3_int ch (Int32.of_int i)
- let write_index ch n =
- write_int ch (index_int n)
- let write_index_nz ch n =
- write_int ch (index_nz_int n)
- let write_index_opt ch = function
- | None -> write_int ch 0
- | Some n -> write_index ch n
- let write_as3_ident ch id =
- write_int ch (String.length id);
- IO.nwrite_string ch id
- let write_namespace empty_index ch = function
- | A3NPrivate n ->
- IO.write_byte ch 0x05;
- (match n with
- | None -> write_int ch 0
- | Some n -> write_index ch n);
- | A3NPublic n ->
- IO.write_byte ch 0x16;
- (match n with
- | None -> write_index ch empty_index
- | Some n -> write_index ch n);
- | A3NInternal n ->
- IO.write_byte ch 0x17;
- (match n with
- | None -> write_index ch empty_index
- | Some n -> write_index ch n);
- | A3NProtected n ->
- IO.write_byte ch 0x18;
- write_index ch n
- | A3NNamespace n ->
- IO.write_byte ch 0x08;
- write_index ch n
- | A3NExplicit n ->
- IO.write_byte ch 0x19;
- write_index ch n
- | A3NStaticProtected n ->
- IO.write_byte ch 0x1A;
- (match n with
- | None -> write_int ch 0
- | Some n -> write_index ch n)
- let write_rights ch l =
- IO.write_byte ch (List.length l);
- List.iter (write_index ch) l
- let rec write_name ch ?k x =
- let b n = match k with None -> n | Some v -> v in
- match x with
- | A3MMultiName (id,r) ->
- IO.write_byte ch (b 0x09);
- write_index_opt ch id;
- write_index ch r;
- | A3MName (id,r) ->
- IO.write_byte ch (b 0x07);
- write_index ch r;
- write_index ch id
- | A3MNSAny(id) ->
- IO.write_byte ch (b 0x07);
- write_int ch 0;
- write_index ch id;
- | A3MAny ->
- IO.write_byte ch (b 0x07);
- write_int ch 0;
- write_int ch 0;
- | A3MRuntimeName i ->
- IO.write_byte ch (b 0x0F);
- write_index ch i
- | A3MRuntimeNameLate ->
- IO.write_byte ch (b 0x11);
- | A3MMultiNameLate id ->
- IO.write_byte ch (b 0x1B);
- write_index ch id
- | A3MAttrib n ->
- write_name ch ~k:(match n with
- | A3MName _ | A3MNSAny _ | A3MAny -> 0x0D
- | A3MMultiName _ -> 0x0E
- | A3MRuntimeName _ -> 0x10
- | A3MRuntimeNameLate -> 0x12
- | A3MMultiNameLate _ -> 0x1C
- | A3MAttrib _ | A3MParams _ -> assert false
- ) n
- | A3MParams (id,pl) ->
- IO.write_byte ch (b 0x1D);
- write_index ch id;
- IO.write_byte ch (List.length pl);
- List.iter (write_index ch) pl
- let write_value ch extra v =
- match v with
- | A3VNone ->
- IO.write_byte ch 0x00;
- if extra then IO.write_byte ch 0x00;
- | A3VNull ->
- IO.write_byte ch 0x0C;
- IO.write_byte ch 0x0C;
- | A3VBool b ->
- IO.write_byte ch (if b then 0x0B else 0x0A);
- IO.write_byte ch (if b then 0x0B else 0x0A);
- | A3VString s ->
- write_index ch s;
- IO.write_byte ch 0x01;
- | A3VInt s ->
- write_index ch s;
- IO.write_byte ch 0x03;
- | A3VUInt s ->
- write_index ch s;
- IO.write_byte ch 0x04;
- | A3VFloat s ->
- write_index ch s;
- IO.write_byte ch 0x06
- | A3VNamespace (n,s) ->
- write_index ch s;
- IO.write_byte ch n
- let write_method_type ch m =
- let nargs = List.length m.mt3_args in
- IO.write_byte ch nargs;
- write_index_opt ch m.mt3_ret;
- List.iter (write_index_opt ch) m.mt3_args;
- write_index_opt ch m.mt3_debug_name;
- let flags =
- (if m.mt3_arguments_defined then 0x01 else 0) lor
- (if m.mt3_new_block then 0x02 else 0) lor
- (if m.mt3_var_args then 0x04 else 0) lor
- (if m.mt3_dparams <> None then 0x08 else 0) lor
- (if m.mt3_unused_flag then 0x10 else 0) lor
- (if m.mt3_native then 0x20 else 0) lor
- (if m.mt3_uses_dxns then 0x40 else 0) lor
- (if m.mt3_pnames <> None then 0x80 else 0)
- in
- IO.write_byte ch flags;
- (match m.mt3_dparams with
- | None -> ()
- | Some l ->
- IO.write_byte ch (List.length l);
- List.iter (write_value ch true) l);
- match m.mt3_pnames with
- | None -> ()
- | Some l ->
- if List.length l <> nargs then assert false;
- List.iter (write_index_opt ch) l
- let write_list ch f l =
- match Array.length l with
- | 0 -> IO.write_byte ch 0
- | n ->
- write_int ch (n + 1);
- Array.iter (f ch) l
- let write_list2 ch f l =
- write_int ch (Array.length l);
- Array.iter (f ch) l
- let write_field ch f =
- write_index ch f.f3_name;
- let flags = (if f.f3_metas <> None then 0x40 else 0) in
- (match f.f3_kind with
- | A3FMethod m ->
- let base = (match m.m3_kind with MK3Normal -> 0x01 | MK3Getter -> 0x02 | MK3Setter -> 0x03) in
- let flags = flags lor (if m.m3_final then 0x10 else 0) lor (if m.m3_override then 0x20 else 0) in
- IO.write_byte ch (base lor flags);
- write_int ch f.f3_slot;
- write_index_nz ch m.m3_type;
- | A3FClass c ->
- IO.write_byte ch (0x04 lor flags);
- write_int ch f.f3_slot;
- write_index_nz ch c
- | A3FFunction i ->
- IO.write_byte ch (0x05 lor flags);
- write_int ch f.f3_slot;
- write_index_nz ch i
- | A3FVar v ->
- IO.write_byte ch (flags lor (if v.v3_const then 0x06 else 0x00));
- write_int ch f.f3_slot;
- write_index_opt ch v.v3_type;
- write_value ch false v.v3_value);
- match f.f3_metas with
- | None -> ()
- | Some l ->
- write_list2 ch write_index_nz l
- let write_class ch c =
- write_index ch c.cl3_name;
- write_index_opt ch c.cl3_super;
- let flags =
- (if c.cl3_sealed then 1 else 0) lor
- (if c.cl3_final then 2 else 0) lor
- (if c.cl3_interface then 4 else 0) lor
- (if c.cl3_namespace <> None then 8 else 0)
- in
- IO.write_byte ch flags;
- (match c.cl3_namespace with
- | None -> ()
- | Some r -> write_index ch r);
- write_list2 ch write_index c.cl3_implements;
- write_index_nz ch c.cl3_construct;
- write_list2 ch write_field c.cl3_fields
- let write_static ch s =
- write_index_nz ch s.st3_method;
- write_list2 ch write_field s.st3_fields
- let write_metadata ch m =
- write_index ch m.meta3_name;
- write_list2 ch (fun _ (i1,_) -> write_index_opt ch i1) m.meta3_data;
- Array.iter (fun (_,i2) -> write_index ch i2) m.meta3_data
- let write_try_catch ch t =
- write_int ch t.tc3_start;
- write_int ch t.tc3_end;
- write_int ch t.tc3_handle;
- write_index_opt ch t.tc3_type;
- write_index_opt ch t.tc3_name
- let write_function ch f =
- write_index_nz ch f.fun3_id;
- write_int ch f.fun3_stack_size;
- write_int ch f.fun3_nregs;
- write_int ch f.fun3_init_scope;
- write_int ch f.fun3_max_scope;
- let clen = MultiArray.fold_left (fun acc op -> acc + As3code.length op) 0 f.fun3_code in
- write_int ch clen;
- MultiArray.iter (As3code.write ch) f.fun3_code;
- write_list2 ch write_try_catch f.fun3_trys;
- write_list2 ch write_field f.fun3_locals
- let write ch1 ctx =
- let ch = IO.output_strings() in
- let empty_index = as3_empty_index ctx in
- IO.write_i32 ch header_magic;
- write_list ch write_as3_int ctx.as3_ints;
- write_list ch write_as3_uint ctx.as3_uints;
- write_list ch IO.write_double ctx.as3_floats;
- if parse_idents then write_list ch write_as3_ident ctx.as3_idents;
- if parse_namespaces then write_list ch (write_namespace empty_index) ctx.as3_namespaces;
- if parse_ns_sets then write_list ch write_rights ctx.as3_nsets;
- if parse_names then write_list ch (write_name ?k:None) ctx.as3_names;
- if parse_mtypes then write_list2 ch write_method_type ctx.as3_method_types;
- if parse_metadata then write_list2 ch write_metadata ctx.as3_metadatas;
- if parse_classes then write_list2 ch write_class ctx.as3_classes;
- if parse_statics then Array.iter (write_static ch) ctx.as3_statics;
- if parse_inits then write_list2 ch write_static ctx.as3_inits;
- if parse_functions then write_list2 ch write_function ctx.as3_functions;
- IO.nwrite_string ch ctx.as3_unknown;
- let str = IO.close_out ch in
- List.iter (IO.nwrite_string ch1) str
- (* ************************************************************************ *)
- (* DUMP *)
- let dump_code_size = ref true
- let ident_str ctx i =
- iget ctx.as3_idents i
- let namespace_str ctx i =
- match iget ctx.as3_namespaces i with
- | A3NPrivate None -> "private"
- | A3NPrivate (Some n) -> "private:" ^ ident_str ctx n
- | A3NPublic None -> "public"
- | A3NPublic (Some n) -> "public:" ^ ident_str ctx n
- | A3NInternal None -> "internal"
- | A3NInternal (Some n) -> "internal:" ^ ident_str ctx n
- | A3NProtected n -> "protected:" ^ ident_str ctx n
- | A3NExplicit n -> "explicit:" ^ ident_str ctx n
- | A3NStaticProtected None -> "static_protected"
- | A3NStaticProtected (Some n) -> "static_protectec:" ^ ident_str ctx n
- | A3NNamespace n -> "namespace:" ^ ident_str ctx n
- let ns_set_str ctx i =
- let l = iget ctx.as3_nsets i in
- String.concat " " (List.map (fun r -> namespace_str ctx r) l)
- let rec name_str ctx kind t =
- let rec loop = function
- | A3MName (id,r) -> Printf.sprintf "%s %s%s" (namespace_str ctx r) kind (ident_str ctx id)
- | A3MNSAny (id) -> Printf.sprintf "%s %s%s" "ANY" kind (ident_str ctx id)
- | A3MAny -> "ANY"
- | A3MMultiName (id,r) -> Printf.sprintf "[%s %s%s]" (ns_set_str ctx r) kind (match id with None -> "NO" | Some i -> ident_str ctx i)
- | A3MRuntimeName id -> Printf.sprintf "'%s'" (ident_str ctx id)
- | A3MRuntimeNameLate -> "RTLATE"
- | A3MMultiNameLate id -> Printf.sprintf "late:(%s)" (ns_set_str ctx id)
- | A3MAttrib n -> "attrib " ^ loop n
- | A3MParams (id,pl) -> Printf.sprintf "%s<%s>" (name_str ctx kind id) (String.concat "," (List.map (name_str ctx kind) pl))
- in
- loop (iget ctx.as3_names t)
- let value_str ctx v =
- match v with
- | A3VNone -> "<none>"
- | A3VNull -> "null"
- | A3VString s -> "\"" ^ ident_str ctx s ^ "\""
- | A3VBool b -> if b then "true" else "false"
- | A3VInt s -> Printf.sprintf "%ld" (iget ctx.as3_ints s)
- | A3VUInt s -> Printf.sprintf "%ld" (iget ctx.as3_uints s)
- | A3VFloat s -> Printf.sprintf "%f" (iget ctx.as3_floats s)
- | A3VNamespace (_,s) -> "ns::" ^ namespace_str ctx s
- let metadata_str ctx i =
- let m = iget ctx.as3_metadatas i in
- let data = List.map (fun (i1,i2) -> Printf.sprintf "%s=\"%s\"" (match i1 with None -> "NO" | Some i -> ident_str ctx i) (ident_str ctx i2)) (Array.to_list m.meta3_data) in
- Printf.sprintf "%s(%s)" (ident_str ctx m.meta3_name) (String.concat ", " data)
- let method_str ?(infos=false) ctx m =
- let m = iget ctx.as3_method_types m in
- let pcount = ref 0 in
- Printf.sprintf "%s(%s%s)%s"
- (if m.mt3_native then " native " else "")
- (String.concat ", " (List.map (fun a ->
- let id = (match m.mt3_pnames with
- | None -> "p" ^ string_of_int !pcount
- | Some l ->
- match List.nth l !pcount with
- | None -> "p" ^ string_of_int !pcount
- | Some i -> ident_str ctx i
- ) in
- let p = (match a with None -> id | Some t -> name_str ctx (id ^ " : ") t) in
- let p = (match m.mt3_dparams with
- | None -> p
- | Some l ->
- let vargs = List.length m.mt3_args - List.length l in
- if !pcount >= vargs then
- let v = List.nth l (!pcount - vargs) in
- p ^ " = " ^ value_str ctx v
- else
- p
- ) in
- incr pcount;
- p
- ) m.mt3_args))
- (if m.mt3_var_args then " ..." else "")
- (match m.mt3_ret with None -> "" | Some t -> " : " ^ name_str ctx "" t)
- ^ (if infos then begin
- let name = (match m.mt3_debug_name with None -> "" | Some idx -> Printf.sprintf " '%s'" (ident_str ctx idx)) in
- Printf.sprintf "%s blk:%b args:%b dxns:%b%s" name m.mt3_new_block m.mt3_arguments_defined m.mt3_uses_dxns (if m.mt3_unused_flag then " SPECIAL-FLAG" else "")
- end else "")
- let dump_field ctx ch stat f =
- (* (match f.f3_metas with
- | None -> ()
- | Some l -> Array.iter (fun i -> IO.printf ch " [%s]\n" (metadata_str ctx (no_nz i))) l);
- *) IO.printf ch " ";
- if stat then IO.printf ch "static ";
- (match f.f3_kind with
- | A3FVar v ->
- IO.printf ch "%s" (name_str ctx (if v.v3_const then "const " else "var ") f.f3_name);
- (match v.v3_type with
- | None -> ()
- | Some id -> IO.printf ch " : %s" (name_str ctx "" id));
- if v.v3_value <> A3VNone then IO.printf ch " = %s" (value_str ctx v.v3_value);
- | A3FClass c ->
- let c = iget ctx.as3_classes (no_nz c) in
- IO.printf ch "%s = %s" (name_str ctx "CLASS " c.cl3_name) (name_str ctx "class " f.f3_name);
- | A3FFunction id ->
- IO.printf ch "%s = %s" (method_str ~infos:false ctx (no_nz id)) (name_str ctx "method " f.f3_name);
- | A3FMethod m ->
- if m.m3_final then IO.printf ch "final ";
- if m.m3_override then IO.printf ch "override ";
- let k = "function " ^ (match m.m3_kind with
- | MK3Normal -> ""
- | MK3Getter -> "get "
- | MK3Setter -> "set "
- ) in
- IO.printf ch "%s%s #%d" (name_str ctx k f.f3_name) (method_str ctx (no_nz m.m3_type)) (index_nz_int m.m3_type);
- );
- if f.f3_slot <> 0 then IO.printf ch " = [SLOT:%d]" f.f3_slot;
- IO.printf ch ";\n"
- let dump_class ctx ch idx c =
- let st = if parse_statics then ctx.as3_statics.(idx) else { st3_method = magic_index_nz (-1); st3_fields = [||] } in
- if not c.cl3_sealed then IO.printf ch "dynamic ";
- if c.cl3_final then IO.printf ch "final ";
- (match c.cl3_namespace with
- | None -> ()
- | Some r -> IO.printf ch "%s " (namespace_str ctx r));
- let kind = (if c.cl3_interface then "interface " else "class ") in
- IO.printf ch "%s " (name_str ctx kind c.cl3_name);
- (match c.cl3_super with
- | None -> ()
- | Some s -> IO.printf ch "extends %s " (name_str ctx "" s));
- (match Array.to_list c.cl3_implements with
- | [] -> ()
- | l ->
- IO.printf ch "implements %s " (String.concat ", " (List.map (fun i -> name_str ctx "" i) l)));
- IO.printf ch "{\n";
- Array.iter (dump_field ctx ch false) c.cl3_fields;
- Array.iter (dump_field ctx ch true) st.st3_fields;
- IO.printf ch "} constructor#%d statics#%d\n\n" (index_nz_int c.cl3_construct) (index_nz_int st.st3_method)
- let dump_init ctx ch idx s =
- IO.printf ch "init #%d {\n" (index_nz_int s.st3_method);
- Array.iter (dump_field ctx ch false) s.st3_fields;
- IO.printf ch "}\n\n"
- let dump_try_catch ctx ch t =
- IO.printf ch " try %d %d %d (%s) (%s)\n"
- t.tc3_start t.tc3_end t.tc3_handle
- (match t.tc3_type with None -> "*" | Some idx -> name_str ctx "" idx)
- (match t.tc3_name with None -> "NO" | Some idx -> name_str ctx "" idx)
- let dump_function ctx ch idx f =
- IO.printf ch "function #%d %s\n" (index_nz_int f.fun3_id) (method_str ~infos:true ctx (no_nz f.fun3_id));
- IO.printf ch " stack:%d nregs:%d scope:%d-%d\n" f.fun3_stack_size f.fun3_nregs f.fun3_init_scope f.fun3_max_scope;
- Array.iter (dump_field ctx ch false) f.fun3_locals;
- Array.iter (dump_try_catch ctx ch) f.fun3_trys;
- let pos = ref 0 in
- MultiArray.iter (fun op ->
- IO.printf ch "%4d %s\n" !pos (As3code.dump ctx op);
- if !dump_code_size then pos := !pos + As3code.length op else incr pos;
- ) f.fun3_code;
- IO.printf ch "\n"
- let dump_ident ctx ch idx _ =
- IO.printf ch "I%d = %s\n" (idx + 1) (ident_str ctx (index ctx.as3_idents (idx + 1)))
- let dump_namespace ctx ch idx _ =
- IO.printf ch "N%d = %s\n" (idx + 1) (namespace_str ctx (index ctx.as3_namespaces (idx + 1)))
- let dump_ns_set ctx ch idx _ =
- IO.printf ch "S%d = %s\n" (idx + 1) (ns_set_str ctx (index ctx.as3_nsets (idx + 1)))
- let dump_name ctx ch idx _ =
- IO.printf ch "T%d = %s\n" (idx + 1) (name_str ctx "" (index ctx.as3_names (idx + 1)))
- let dump_method_type ctx ch idx _ =
- IO.printf ch "M%d = %s\n" (idx + 1) (method_str ~infos:true ctx (index ctx.as3_method_types (idx + 1)))
- let dump_metadata ctx ch idx _ =
- IO.printf ch "D%d = %s\n" (idx + 1) (metadata_str ctx (index ctx.as3_metadatas (idx + 1)))
- let dump_int ctx ch idx i =
- IO.printf ch "INT %d = 0x%lX\n" (idx + 1) i
- let dump_float ctx ch idx f =
- IO.printf ch "FLOAT %d = %f\n" (idx + 1) f
- let dump ch ctx id =
- (match id with
- | None -> IO.printf ch "\n---------------- AS3 -------------------------\n\n";
- | Some (id,f) -> IO.printf ch "\n---------------- AS3 %s [%d] -----------------\n\n" f id);
- (* Array.iteri (dump_int ctx ch) ctx.as3_ints;
- Array.iteri (dump_float ctx ch) ctx.as3_floats;
- Array.iteri (dump_ident ctx ch) ctx.as3_idents;
- IO.printf ch "\n";
- Array.iteri (dump_namespace ctx ch) ctx.as3_namespaces;
- IO.printf ch "\n";
- Array.iteri (dump_ns_set ctx ch) ctx.as3_nsets;
- IO.printf ch "\n";
- Array.iteri (dump_name ctx ch) ctx.as3_names;
- IO.printf ch "\n"; *)
- (* Array.iteri (dump_metadata ctx ch) ctx.as3_metadatas; *)
- Array.iteri (dump_class ctx ch) ctx.as3_classes;
- Array.iteri (dump_init ctx ch) ctx.as3_inits;
- Array.iteri (dump_function ctx ch) ctx.as3_functions;
- IO.printf ch "\n"
- ;;
- As3code.f_int_length := int_length;
- As3code.f_int_read := read_int;
- As3code.f_int_write := write_int;
|