| 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_leftoversopen As3let parse_idents = truelet parse_namespaces = true && parse_identslet parse_ns_sets = true && parse_namespaceslet parse_names = true && parse_ns_setslet parse_mtypes = true && parse_nameslet parse_metadata = true && parse_mtypeslet parse_classes = true && parse_metadatalet parse_statics = true && parse_classeslet parse_inits = true && parse_staticslet parse_functions = true && parse_initslet parse_bytecode = true && parse_functionslet magic_index (i : int) : 'a index =	Obj.magic ilet magic_index_nz (i : int) : 'a index_nz =	Obj.magic ilet index (t : 'a array) (i : int) : 'a index =	if i <= 0 || i - 1 >= Array.length t then assert false;	magic_index ilet 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 ilet 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		1let as3_uint_length i =	as3_int_length ilet sum f l =	List.fold_left (fun acc n -> acc + f n) 0 llet 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 ilet as3_ident_length s =	let n = String.length s in	n + int_length nlet 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 nlet as3_ns_set_length l =	int_length (List.length l) + sum idx_length llet 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 slet 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)) llet list2_length f l =	Array.fold_left (fun acc x -> acc + f x) (int_length (Array.length l)) llet 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 llet 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_fieldslet as3_static_length s =	idx_length_nz s.st3_method +	list2_length as3_field_length s.st3_fieldslet as3_metadata_length m =	idx_length m.meta3_name +	list2_length (fun (i1,i2) -> idx_opt_length i1 + idx_length i2) m.meta3_datalet 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_namelet 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_localslet 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 smalllet read_as3_uint ch =	read_as3_int chlet 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 falselet 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 falselet 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 falselet 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 = 0x002E0010let 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 alet write_as3_uint = write_as3_intlet 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 nlet write_as3_ident ch id =	write_int ch (String.length id);	IO.nwrite_string ch idlet 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) llet 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) pllet 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 nlet 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) llet 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) llet write_list2 ch f l =	write_int ch (Array.length l);	Array.iter (f ch) llet 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 llet 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_fieldslet write_static ch s =	write_index_nz ch s.st3_method;	write_list2 ch write_field s.st3_fieldslet 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_datalet 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_namelet 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_localslet 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 truelet ident_str ctx i =	iget ctx.as3_idents ilet 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 nlet 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 slet 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) ilet dump_float ctx ch idx f =	IO.printf ch "FLOAT %d = %f\n" (idx + 1) flet 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;
 |