| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679 | (* *  This file is part of SwfLib *  Copyright (c)2004 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 Swfopen IOopen Printflet push_item_length = function	| PString s -> String.length s + 1	| PFloat _ -> 4	| PNull -> 0	| PUndefined -> 0	| PReg _ -> 1	| PBool _ -> 1	| PDouble _ -> 8	| PInt _ -> 4	| PStack _ -> 1	| PStack2 _ -> 2let push_item_id = function	| PString s -> 0	| PFloat _ -> 1	| PNull -> 2	| PUndefined -> 3	| PReg _ -> 4	| PBool _ -> 5	| PDouble _ -> 6	| PInt _ -> 7	| PStack _ -> 8	| PStack2 _ -> 9let opcodes = Hashtbl.create 0let opcodes_rev = Hashtbl.create 0let opcodes_names = Hashtbl.create 0let ( => ) code (op,name) =	Hashtbl.add opcodes op code;	Hashtbl.add opcodes_rev code op;	Hashtbl.add opcodes_names op namelet short_op_codes = begin	0x00 => (AEnd,"END");	0x04 => (ANextFrame,"NEXTFRAME");	0x05 => (APrevFrame,"PREVFRAME");	0x06 => (APlay,"PLAY");	0x07 => (AStop,"STOP");	0x08 => (AToggleHighQuality,"TGLHIGHQULTY");	0x09 => (AStopSounds,"STOPSOUNDS");	0x0A => (AAddNum,"ADDNUM");	0x0B => (ASubtract,"SUB");	0x0C => (AMultiply,"MULT");	0x0D => (ADivide,"DIV");	0x0E => (ACompareNum,"CMP");	0x0F => (AEqualNum,"EQNUM");	0x10 => (ALogicalAnd,"LAND");	0x11 => (ALogicalOr,"LOR");	0x12 => (ANot,"NOT");	0x13 => (AStringEqual,"STREQ");	0x14 => (AStringLength,"STRLEN");	0x15 => (ASubString,"SUBSTR");	0x17 => (APop,"POP");	0x18 => (AToInt,"TOINT");	0x1C => (AEval,"EVAL");	0x1D => (ASet,"SET");	0x20 => (ATellTarget,"TELLTARGET");	0x21 => (AStringAdd,"STRADD");	0x22 => (AGetProperty,"GETPROP");	0x23 => (ASetProperty,"SETPROP");	0x24 => (ADuplicateMC,"DUPLICATEMC");	0x25 => (ARemoveMC,"REMOVEMC");	0x26 => (ATrace,"TRACE");	0x27 => (AStartDrag,"STARTDRAG");	0x28 => (AStopDrag,"STOPDRAG");	0x2A => (AThrow,"THROW");	0x2B => (ACast,"CAST");	0x2C => (AImplements,"IMPLEMENTS");	0x2D => (AFSCommand2,"FSCOMMAND2");	0x30 => (ARandom,"RANDOM");	0x31 => (AMBStringLength,"MBSTRLEN");	0x32 => (AOrd,"ORD");	0x33 => (AChr,"CHR");	0x34 => (AGetTimer,"GETTIMER");	0x35 => (AMBStringSub,"MBSTRSUB");	0x36 => (AMBOrd,"MBORD");	0x37 => (AMBChr,"MBCHR");	0x3A => (ADeleteObj,"DELETEOBJ");	0x3B => (ADelete,"DELETE");	0x3C => (ALocalAssign,"VARSET");	0x3D => (ACall,"CALL");	0x3E => (AReturn,"RET");	0x3F => (AMod,"MOD");	0x40 => (ANew,"NEW");	0x41 => (ALocalVar,"VAR");	0x42 => (AInitArray,"ARRAY");	0x43 => (AObject,"OBJECT");	0x44 => (ATypeOf,"TYPEOF");	0x45 => (ATargetPath,"TARGETPATH");	0x46 => (AEnum,"ENUM");	0x47 => (AAdd,"ADD");	0x48 => (ACompare,"CMP");	0x49 => (AEqual,"EQ");	0x4A => (AToNumber,"TONUMBER");	0x4B => (AToString,"TOSTRING");	0x4C => (ADup,"DUP");	0x4D => (ASwap,"SWAP");	0x4E => (AObjGet,"OBJGET");	0x4F => (AObjSet,"OBJSET");	0x50 => (AIncrement,"INCR");	0x51 => (ADecrement,"DECR");	0x52 => (AObjCall,"OBJCALL");	0x53 => (ANewMethod,"NEWMETHOD");	0x54 => (AInstanceOf,"INSTANCEOF");	0x55 => (AEnum2,"ENUM2");	0x60 => (AAnd,"AND");	0x61 => (AOr,"OR");	0x62 => (AXor,"XOR");	0x63 => (AShl,"SHL");	0x64 => (AShr,"SHR");	0x65 => (AAsr,"ASR");	0x66 => (APhysEqual,"PHYSEQ");	0x67 => (AGreater,"GT");	0x68 => (AStringGreater,"STRGT");	0x69 => (AExtends,"EXTENDS");	0x9E => (ACallFrame,"CALLFRAME"); (* special case *)endlet action_id = function	| AGotoFrame _ -> 0x81	| AGetURL _ -> 0x83	| ASetReg _ -> 0x87	| AStringPool _ -> 0x88	| AWaitForFrame _ -> 0x8A	| ASetTarget _ -> 0x8B	| AGotoLabel _ -> 0x8C	| AWaitForFrame2 _ -> 0x8D	| AFunction2 _ -> 0x8E	| ATry _ -> 0x8F	| AWith _ -> 0x94	| APush _ -> 0x96	| AJump _ -> 0x99	| AGetURL2 _ -> 0x9A	| AFunction _ -> 0x9B	| ACondJump _ -> 0x9D	| AGotoFrame2 _ -> 0x9F	| AUnknown (id,_) -> id	| op ->		try			Hashtbl.find opcodes op		with			Not_found -> error "Unknown opcode id"let action_data_length = function	| AGotoFrame _ ->		2	| AGetURL (url,target) ->		2 + String.length url + String.length target	| ASetReg _ ->		1	| AStringPool strs ->		List.fold_left (fun acc item -> acc + 1 + String.length item) 2 strs	| AWaitForFrame _ ->		3	| AFunction2 f ->		let base = String.length f.f2_name + 1 + 2 + 1 + 2 + 2 in		List.fold_left (fun acc (_,s) -> acc + 2 + String.length s) base f.f2_args	| ASetTarget target ->		String.length target + 1	| AGotoLabel label ->		String.length label + 1	| AWaitForFrame2 _ ->		1	| ATry t ->		1 + 6 + (match t.tr_style with TryVariable n -> String.length n + 1 | TryRegister _ -> 1)	| AWith _ ->		2 (* the string does not count in length *)	| APush items ->		List.fold_left (fun acc item -> acc + 1 + push_item_length item) 0 items	| AJump _ ->		2	| AGetURL2 _ ->		1	| AFunction f ->		List.fold_left (fun acc s -> acc + 1 + String.length s) 4 (f.f_name :: f.f_args)	| ACondJump _ ->		2	| AGotoFrame2 (_,id) ->		1 + (if id = None then 0 else 2)	| AUnknown (_,data) ->		String.length data	| _ ->		0let action_length a =	let len = (if action_id a >= 0x80 then 3 else 1) in	len + action_data_length alet actions_length acts =	DynArray.fold_left (fun acc a -> acc + action_length a) (action_length AEnd) actslet read_mm_double ch =	let i1 = Int64.of_int32 (read_real_i32 ch) in	let i2 = Int64.of_int32 (read_real_i32 ch) in	let i2 = (if i2 < Int64.zero then Int64.add i2 (Int64.shift_left Int64.one 32) else i2) in	Int64.float_of_bits (Int64.logor i2 (Int64.shift_left i1 32))let write_mm_double ch f =	let i64 = Int64.bits_of_float f in	write_real_i32 ch (Int64.to_int32 (Int64.shift_right_logical i64 32));	write_real_i32 ch (Int64.to_int32 i64)let read_string_max ch len =	let b = Buffer.create 0 in	let rec loop l =		if l = 0 then begin			let s = Buffer.contents b in			String.sub s 0 (String.length s - 1)		end else			let c = read ch in			if c = '\000' then				Buffer.contents b			else begin				Buffer.add_char b c;				loop (l - 1)			end;	in	loop lenlet parse_push_item ch len =	let id = read_byte ch in	match id with	| 0 -> PString (read_string_max ch len)	| 1 -> PFloat (read_real_i32 ch)	| 2 -> PNull	| 3 -> PUndefined	| 4 -> PReg (read_byte ch)	| 5 -> PBool (read_byte ch <> 0)	| 6 -> PDouble (read_mm_double ch)	| 7 -> PInt (read_real_i32 ch)	| 8 -> PStack (read_byte ch)	| 9 -> PStack2 (read_ui16 ch)	| _ -> error (sprintf "Unknown PUSH item id : %d" id)let rec parse_push_items ch len =	if len < 0 then error "PUSH parse overflow";	if len = 0 then		 []	else		let item = parse_push_item ch len in		item :: parse_push_items ch (len - 1 - push_item_length item)let rec read_strings ch n =	if n = 0 then		[]	else		let s = read_string ch in		s :: read_strings ch (n-1)let parse_function_decl ch =	let name = read_string ch in	let nargs = read_ui16 ch in	let args = read_strings ch nargs in	let clen = read_ui16 ch in	{		f_name = name;		f_args = args;		f_codelen = clen;	}let parse_f2_flags n =	let flags = ref [] in	let v = ref 1 in	let add_flag f =		if n land !v <> 0 then flags := f :: !flags;		v := !v lsl 1	in	List.iter add_flag		[ThisRegister; ThisNoVar; ArgumentsRegister; ArgumentsNoVar; SuperRegister;		 SuperNoVar; RootRegister; ParentRegister; GlobalRegister];	!flagslet parse_function_decl2 ch =	let name = read_string ch in	let nargs = read_ui16 ch in	let nregs = read_byte ch in	let flags = parse_f2_flags (read_ui16 ch) in	let rec loop n =		if n = 0 then			[]		else			let r = read_byte ch in			let s = read_string ch in			(r,s) :: loop (n-1)	in	let args = loop nargs in	let clen = read_ui16 ch in	{		f2_name = name;		f2_args = args;		f2_flags = flags;		f2_codelen = clen;		f2_nregs = nregs;	}let parse_action ch =	let id = read_byte ch in	let len = (if id >= 0x80 then read_ui16 ch else 0) in	let len = (if len = 0xFFFF then 0 else len) in	let act =		(match id with		| 0x81 ->			AGotoFrame (read_ui16 ch)		| 0x83 ->			let url = read_string ch in			let target = read_string ch in			AGetURL (url,target)		| 0x87 ->			ASetReg (read_byte ch)		| 0x88 ->			let nstrs = read_ui16 ch in			AStringPool (read_strings ch nstrs)		| 0x8A ->			let frame = read_ui16 ch in			let skip = read_byte ch in			AWaitForFrame (frame,skip)		| 0x8B ->			ASetTarget (read_string ch)		| 0x8C ->			AGotoLabel (read_string ch)		| 0x8D ->			AWaitForFrame2 (read_byte ch)		| 0x8E ->			AFunction2 (parse_function_decl2 ch)		| 0x8F ->			let flags = read_byte ch in			let tsize = read_ui16 ch in			let csize = read_ui16 ch in			let fsize = read_ui16 ch in			let tstyle = (if flags land 4 == 0 then TryVariable (read_string ch) else TryRegister (read_byte ch)) in			ATry {				tr_style = tstyle;				tr_trylen = tsize;				tr_catchlen = (if flags land 1 == 0 then None else Some csize);				tr_finallylen = (if flags land 2 == 0 then None else Some fsize);			}		| 0x94 ->			let size = read_ui16 ch in			AWith size		| 0x96 ->			APush (parse_push_items ch len)		| 0x99 ->			AJump (read_i16 ch)		| 0x9A ->			AGetURL2 (read_byte ch)		| 0x9B ->			AFunction (parse_function_decl ch)		| 0x9D ->			ACondJump (read_i16 ch)		| 0x9E ->			ACallFrame		| 0x9F ->			let flags = read_byte ch in			let play = flags land 1 <> 0 in			let delta = (if flags land 2 == 0 then None else Some (read_ui16 ch)) in			AGotoFrame2 (play,delta)		| _ ->			try				Hashtbl.find opcodes_rev id			with				Not_found ->					printf "Unknown Action 0x%.2X (%d)\n" id len;					AUnknown (id,nread_string ch len)	) in(*	let len2 = action_data_length act in	if len <> len2 then error (sprintf "Datalen mismatch for action 0x%.2X (%d != %d)" id len len2);*)	actlet size_to_jump_index acts curindex size =	let delta = ref 0 in	let size = ref size in	if !size >= 0 then begin		while !size > 0 do			incr delta;			size := !size - action_length (DynArray.get acts (curindex + !delta));			if !size < 0 then error "Unaligned code";		done;	end else begin		while !size < 0 do			size := !size + action_length (DynArray.get acts (curindex + !delta));			if !size > 0 then error "Unaligned code";			decr delta;		done;	end;	!deltalet parse_actions ch =	let acts = DynArray.create() in	let rec loop() =		match parse_action ch with		| AEnd -> ()		| AUnknown (0xFF,"") ->			DynArray.add acts APlay;			DynArray.add acts APlay;			DynArray.add acts APlay;			loop()		| a ->			DynArray.add acts a;			loop();	in	loop();	(* process jump indexes *)	let process_jump curindex = function		| AJump size ->			let index = size_to_jump_index acts curindex size in			DynArray.set acts curindex (AJump index)		| ACondJump size ->			let index = size_to_jump_index acts curindex size in			DynArray.set acts curindex (ACondJump index)		| AFunction f ->			let index = size_to_jump_index acts curindex f.f_codelen in			DynArray.set acts curindex (AFunction { f with f_codelen = index })		| AFunction2 f ->			let index = size_to_jump_index acts curindex f.f2_codelen in			DynArray.set acts curindex (AFunction2 { f with f2_codelen = index })		| AWith size ->			let index = size_to_jump_index acts curindex size in			DynArray.set acts curindex (AWith index)		| ATry t ->			let tindex = size_to_jump_index acts curindex t.tr_trylen in			let cindex = (match t.tr_catchlen with None -> None | Some size -> Some (size_to_jump_index acts (curindex + tindex) size)) in			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			DynArray.set acts curindex (ATry { t with tr_trylen = tindex; tr_catchlen = cindex; tr_finallylen = findex })		| _ ->			()	in	DynArray.iteri process_jump acts;	actslet jump_index_to_size acts curindex target =	let size = ref 0 in	if target >= 0 then begin		for i = 1 to target do			size := !size + action_length (DynArray.get acts (curindex + i));		done;	end else begin		for i = 0 downto target+1 do			size := !size - action_length (DynArray.get acts (curindex + i));		done;	end;	!sizelet rec write_strings ch = function	| [] -> ()	| s :: l ->		write_string ch s;		write_strings ch llet write_push_item_data ch = function	| PString s -> write_string ch s	| PFloat f -> write_real_i32 ch f	| PNull -> ()	| PUndefined -> ()	| PReg r -> write_byte ch r	| PBool b -> write_byte ch (if b then 1 else 0)	| PDouble f -> write_mm_double ch f	| PInt n -> write_real_i32 ch n	| PStack index -> write_byte ch index	| PStack2 index -> write_ui16 ch indexlet f2_flags_value flags =	let fval = function		| ThisRegister -> 1		| ThisNoVar -> 2		| ArgumentsRegister -> 4		| ArgumentsNoVar -> 8		| SuperRegister -> 16		| SuperNoVar -> 32		| RootRegister -> 64		| ParentRegister -> 128		| GlobalRegister -> 256	in	List.fold_left (fun n f -> n lor (fval f)) 0 flagslet write_action_data acts curindex ch = function	| AGotoFrame frame ->		write_ui16 ch frame	| AGetURL (url,target) ->		write_string ch url;		write_string ch target	| ASetReg reg ->		write_byte ch reg	| AStringPool strs ->		write_ui16 ch (List.length strs);		write_strings ch strs	| AWaitForFrame (frame,skip) ->		write_ui16 ch frame;		write_byte ch skip	| ASetTarget target ->		write_string ch target	| AGotoLabel label ->		write_string ch label	| AWaitForFrame2 n ->		write_byte ch n	| AFunction2 f ->		write_string ch f.f2_name;		write_ui16 ch (List.length f.f2_args);		write_byte ch f.f2_nregs;		write_ui16 ch (f2_flags_value f.f2_flags);		List.iter (fun (r,s) ->			write_byte ch r;			write_string ch s;		) f.f2_args;		let size = jump_index_to_size acts curindex f.f2_codelen in		write_ui16 ch size;	| ATry t ->		let tsize = jump_index_to_size acts curindex t.tr_trylen in		let csize = (match t.tr_catchlen with None -> 0 | Some idx -> jump_index_to_size acts (curindex + t.tr_trylen) idx) in		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		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		write_byte ch flags;		write_ui16 ch tsize;		write_ui16 ch csize;		write_ui16 ch fsize;		(match t.tr_style with		| TryVariable v -> write_string ch v		| TryRegister r -> write_byte ch r)	| AWith target ->		let size = jump_index_to_size acts curindex target in		write_ui16 ch size	| APush items ->		List.iter (fun item ->			write_byte ch (push_item_id item);			write_push_item_data ch item		) items	| AJump target ->		let size = jump_index_to_size acts curindex target in		write_i16 ch size	| AGetURL2 n ->		write_byte ch n	| AFunction f ->		write_string ch f.f_name;		write_ui16 ch (List.length f.f_args);		write_strings ch f.f_args;		let size = jump_index_to_size acts curindex f.f_codelen in		write_ui16 ch size;	| ACondJump target ->		let size = jump_index_to_size acts curindex target in		write_i16 ch size;	| AGotoFrame2 (play,None) ->		write_byte ch (if play then 1 else 0)	| AGotoFrame2 (play,Some delta) ->		write_byte ch (if play then 3 else 2);		write_ui16 ch delta;	| ACallFrame ->		()	| AUnknown (_,data) ->		nwrite_string ch data	| _ ->		assert falselet write_action acts curindex ch a =	let id = action_id a in	let len = action_data_length a in	if id < 0x80 && len > 0 then error "Invalid Action Written";	write_byte ch id;	if len > 0 || id >= 0x80 then begin		write_ui16 ch len;		write_action_data acts curindex ch a;	endlet write_actions ch acts =	DynArray.iteri (fun index act -> write_action acts index ch act) acts;	write_action acts (DynArray.length acts) ch AEndlet sprintf = Printf.sprintflet action_string get_ident pos = function	| AGotoFrame n -> sprintf "GOTOFRAME %d" n	| AGetURL (a,b) -> sprintf "GETURL '%s' '%s'" a b	| ASetReg n -> sprintf "SETREG %d" n	| AStringPool strlist ->		let b = Buffer.create 0 in		Buffer.add_string b "STRINGS ";		let p = ref 0 in		List.iter (fun s ->			Buffer.add_string b (string_of_int !p);			incr p;			Buffer.add_char b ':';			Buffer.add_string b s;			Buffer.add_char b ' ';		) strlist;		Buffer.contents b	| AWaitForFrame (i,j) -> sprintf "WAITFORFRAME %d %d" i j	| ASetTarget s -> sprintf "SETTARGET %s" s	| AGotoLabel s -> sprintf "GOTOLABEL %s" s	| AWaitForFrame2 n -> sprintf "WAITFORFRAME2 %d" n	| AFunction2 f ->		let b = Buffer.create 0 in		Buffer.add_string b "FUNCTION2 ";		Buffer.add_string b f.f2_name;		Buffer.add_char b '(';		Buffer.add_string b (String.concat "," (List.map (fun (n,str) -> sprintf "%d:%s" n str) f.f2_args));		Buffer.add_char b ')';		Buffer.add_string b (sprintf " nregs:%d flags:%d " f.f2_nregs (f2_flags_value f.f2_flags));		Buffer.add_string b (sprintf "0x%.4X" (pos + 1 + f.f2_codelen));		Buffer.contents b	| APush pl ->		let b = Buffer.create 0 in		Buffer.add_string b "PUSH";		List.iter (fun it ->			Buffer.add_char b ' ';			match it with			| PString s ->				Buffer.add_char b '"';				Buffer.add_string b s;				Buffer.add_char b '"'			| PFloat _ ->				Buffer.add_string b "<float>"			| PNull ->				Buffer.add_string b "null"			| PUndefined ->				Buffer.add_string b "undefined"			| PReg n ->				Buffer.add_string b (sprintf "reg:%d" n)			| PBool fl ->				Buffer.add_string b (if fl then "true" else "false")			| PDouble _ ->				Buffer.add_string b "<double>"			| PInt i ->				Buffer.add_string b (Int32.to_string i)			| PStack n			| PStack2 n ->				Buffer.add_char b '[';				Buffer.add_string b (string_of_int n);				Buffer.add_char b ':';				Buffer.add_string b (get_ident n);				Buffer.add_char b ']';		) pl;		Buffer.contents b	| ATry _ -> sprintf "TRY"	| AWith n -> sprintf "WITH %d" n	| AJump n -> sprintf "JUMP 0x%.4X" (n + pos + 1)	| AGetURL2 n -> sprintf "GETURL2 %d" n	| AFunction f ->		let b = Buffer.create 0 in		Buffer.add_string b "FUNCTION ";		Buffer.add_string b f.f_name;		Buffer.add_char b '(';		Buffer.add_string b (String.concat "," f.f_args);		Buffer.add_char b ')';		Buffer.add_string b (sprintf " 0x%.4X" (pos + 1 + f.f_codelen));		Buffer.contents b	| ACondJump n -> sprintf "CJMP 0x%.4X" (n + pos + 1)	| AGotoFrame2 (b,None) -> sprintf "GOTOFRAME2 %b" b	| AGotoFrame2 (b,Some i) -> sprintf "GOTOFRAME2 %b %d" b i	| AUnknown (tag,_) -> sprintf "??? 0x%.2X" tag	| op ->		try			Hashtbl.find opcodes_names op		with			Not_found -> assert false
 |