123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- (*
- * This file is part of JavaLib
- * Copyright (c)2004-2012 Nicolas Cannasse and Caue Waneck
- *
- * 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 JData;;
- open IO.BigEndian;;
- open IO;;
- open ExtString;;
- open ExtList;;
- exception Writer_error_message of string
- type context = {
- cpool : unit IO.output;
- mutable ccount : int;
- ch : string IO.output;
- mutable constants : (jconstant,int) PMap.t;
- }
- let error msg = raise (Writer_error_message msg)
- let get_reference_type i =
- match i with
- | RGetField -> 1
- | RGetStatic -> 2
- | RPutField -> 3
- | RPutStatic -> 4
- | RInvokeVirtual -> 5
- | RInvokeStatic -> 6
- | RInvokeSpecial -> 7
- | RNewInvokeSpecial -> 8
- | RInvokeInterface -> 9
- let encode_path ctx (pack,name) =
- String.concat "/" (pack @ [name])
- let rec encode_param ctx ch param =
- match param with
- | TAny -> write_byte ch (Char.code '*')
- | TType(w, s) ->
- (match w with
- | WExtends -> write_byte ch (Char.code '+')
- | WSuper -> write_byte ch (Char.code '-')
- | WNone -> ());
- encode_sig_part ctx ch s
- and encode_sig_part ctx ch jsig = match jsig with
- | TByte -> write_byte ch (Char.code 'B')
- | TChar -> write_byte ch (Char.code 'C')
- | TDouble -> write_byte ch (Char.code 'D')
- | TFloat -> write_byte ch (Char.code 'F')
- | TInt -> write_byte ch (Char.code 'I')
- | TLong -> write_byte ch (Char.code 'J')
- | TShort -> write_byte ch (Char.code 'S')
- | TBool -> write_byte ch (Char.code 'Z')
- | TObject(path, params) ->
- write_byte ch (Char.code 'L');
- write_string ch (encode_path ctx path);
- if params <> [] then begin
- write_byte ch (Char.code '<');
- List.iter (encode_param ctx ch) params;
- write_byte ch (Char.code '>')
- end;
- write_byte ch (Char.code ';')
- | TObjectInner(pack, inners) ->
- write_byte ch (Char.code 'L');
- List.iter (fun p ->
- write_string ch p;
- write_byte ch (Char.code '/')
- ) pack;
- let first = ref true in
- List.iter (fun (name,params) ->
- (if !first then first := false else write_byte ch (Char.code '.'));
- write_string ch name;
- if params <> [] then begin
- write_byte ch (Char.code '<');
- List.iter (encode_param ctx ch) params;
- write_byte ch (Char.code '>')
- end;
- ) inners;
- write_byte ch (Char.code ';')
- | TArray(s,size) ->
- write_byte ch (Char.code '[');
- (match size with
- | Some size ->
- write_string ch (string_of_int size);
- | None -> ());
- encode_sig_part ctx ch s
- | TMethod(args, ret) ->
- write_byte ch (Char.code '(');
- List.iter (encode_sig_part ctx ch) args;
- (match ret with
- | None -> write_byte ch (Char.code 'V')
- | Some jsig -> encode_sig_part ctx ch jsig)
- | TTypeParameter name ->
- write_byte ch (Char.code 'T');
- write_string ch name;
- write_byte ch (Char.code ';')
- let encode_sig ctx jsig =
- let buf = IO.output_string() in
- encode_sig_part ctx buf jsig;
- close_out buf
- let write_utf8 ch s =
- String.iter (fun c ->
- let c = Char.code c in
- if c = 0 then begin
- write_byte ch 0xC0;
- write_byte ch 0x80
- end else
- write_byte ch c
- ) s
- let rec const ctx c =
- try
- PMap.find c ctx.constants
- with
- | Not_found ->
- let ret = ctx.ccount in
- (match c with
- (** references a class or an interface - jpath must be encoded as StringUtf8 *)
- | ConstClass path -> (* tag = 7 *)
- write_byte ctx.cpool 7;
- write_ui16 ctx.cpool (const ctx (ConstUtf8 (encode_path ctx path)))
- (** field reference *)
- | ConstField (jpath, unqualified_name, jsignature) (* tag = 9 *) ->
- write_byte ctx.cpool 9;
- write_ui16 ctx.cpool (const ctx (ConstClass jpath));
- write_ui16 ctx.cpool (const ctx (ConstNameAndType (unqualified_name, jsignature)))
- (** method reference; string can be special "<init>" and "<clinit>" values *)
- | ConstMethod (jpath, unqualified_name, jmethod_signature) (* tag = 10 *) ->
- write_byte ctx.cpool 10;
- write_ui16 ctx.cpool (const ctx (ConstClass jpath));
- write_ui16 ctx.cpool (const ctx (ConstNameAndType (unqualified_name, TMethod jmethod_signature)))
- (** interface method reference *)
- | ConstInterfaceMethod (jpath, unqualified_name, jmethod_signature) (* tag = 11 *) ->
- write_byte ctx.cpool 11;
- write_ui16 ctx.cpool (const ctx (ConstClass jpath));
- write_ui16 ctx.cpool (const ctx (ConstNameAndType (unqualified_name, TMethod jmethod_signature)))
- (** constant values *)
- | ConstString s (* tag = 8 *) ->
- write_byte ctx.cpool 8;
- write_ui16 ctx.cpool (const ctx (ConstUtf8 s))
- | ConstInt i (* tag = 3 *) ->
- write_byte ctx.cpool 3;
- write_real_i32 ctx.cpool i
- | ConstFloat f (* tag = 4 *) ->
- write_byte ctx.cpool 4;
- (match classify_float f with
- | FP_normal | FP_subnormal | FP_zero ->
- write_real_i32 ctx.cpool (Int32.bits_of_float f)
- | FP_infinite when f > 0.0 ->
- write_real_i32 ctx.cpool 0x7f800000l
- | FP_infinite ->
- write_real_i32 ctx.cpool 0xff800000l
- | FP_nan ->
- write_real_i32 ctx.cpool 0x7f800001l)
- | ConstLong i (* tag = 5 *) ->
- write_byte ctx.cpool 5;
- write_i64 ctx.cpool i;
- | ConstDouble d (* tag = 6 *) ->
- write_byte ctx.cpool 6;
- write_double ctx.cpool d;
- ctx.ccount <- ctx.ccount + 1
- (** name and type: used to represent a field or method, without indicating which class it belongs to *)
- | ConstNameAndType (unqualified_name, jsignature) ->
- write_byte ctx.cpool 12;
- write_ui16 ctx.cpool (const ctx (ConstUtf8 (unqualified_name)));
- write_ui16 ctx.cpool (const ctx (ConstUtf8 (encode_sig ctx jsignature)))
- (** UTF8 encoded strings. Note that when reading/writing, take into account Utf8 modifications of java *)
- (* (http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.7) *)
- | ConstUtf8 s ->
- write_byte ctx.cpool 1;
- write_ui16 ctx.cpool (String.length s);
- write_utf8 ctx.cpool s
- (** invokeDynamic-specific *)
- | ConstMethodHandle (reference_type, jconstant) (* tag = 15 *) ->
- write_byte ctx.cpool 15;
- write_byte ctx.cpool (get_reference_type reference_type);
- write_ui16 ctx.cpool (const ctx jconstant)
- | ConstMethodType jmethod_signature (* tag = 16 *) ->
- write_byte ctx.cpool 16;
- write_ui16 ctx.cpool (const ctx (ConstUtf8 (encode_sig ctx (TMethod jmethod_signature))))
- | ConstDynamic (bootstrap_method, unqualified_name, jsignature) (* tag = 17 *) ->
- write_byte ctx.cpool 17;
- write_ui16 ctx.cpool bootstrap_method;
- write_ui16 ctx.cpool (const ctx (ConstNameAndType(unqualified_name, jsignature)))
- | ConstInvokeDynamic (bootstrap_method, unqualified_name, jsignature) (* tag = 18 *) ->
- write_byte ctx.cpool 18;
- write_ui16 ctx.cpool bootstrap_method;
- write_ui16 ctx.cpool (const ctx (ConstNameAndType(unqualified_name, jsignature)))
- | ConstModule unqualified_name (* tag = 19 *) ->
- write_byte ctx.cpool 19;
- write_ui16 ctx.cpool (const ctx (ConstUtf8 (unqualified_name)));
- | ConstPackage unqualified_name (* tag = 20 *) ->
- write_byte ctx.cpool 20;
- write_ui16 ctx.cpool (const ctx (ConstUtf8 (unqualified_name)));
- | ConstUnusable -> assert false);
- ctx.ccount <- ret + 1;
- ret
- let write_const ctx ch cconst =
- write_ui16 ch (const ctx cconst)
- ;;
- let write_formal_type_params ctx ch tparams =
- write_byte ch (Char.code '<');
- List.iter (fun (name,ext,impl) ->
- write_string ch name;
- (match ext with
- | None -> ()
- | Some jsig ->
- write_byte ch (Char.code ':');
- write_string ch (encode_sig ctx jsig));
- List.iter (fun jsig ->
- write_byte ch (Char.code ':');
- write_string ch (encode_sig ctx jsig)
- ) impl
- ) tparams;
- write_byte ch (Char.code '>');
- ;;
- let write_complete_method_signature ctx ch (tparams : jtypes) msig throws =
- if tparams <> [] then write_formal_type_params ctx ch tparams;
- write_string ch (encode_sig ctx (TMethod(msig)));
- if throws <> [] then List.iter (fun jsig ->
- write_byte ch (Char.code '^');
- write_string ch (encode_sig ctx jsig)
- ) throws
- ;;
- let write_access_flags ctx ch all_flags flags =
- let value = List.fold_left (fun acc flag ->
- try
- acc lor (Hashtbl.find all_flags flag)
- with Not_found ->
- error ("Not found flag: " ^ (string_of_int (Obj.magic flag)))
- ) 0 flags in
- write_ui16 ch value
- ;;
- let rec write_ann_element ctx ch (name,eval) =
- write_const ctx ch (ConstUtf8 name);
- write_element_value ctx ch eval
- and write_annotation ctx ch ann =
- write_const ctx ch (ConstUtf8 (encode_sig ctx ann.ann_type));
- write_ui16 ch (List.length ann.ann_elements);
- List.iter (write_ann_element ctx ch) ann.ann_elements
- and write_element_value ctx ch value = match value with
- | ValConst(jsig, cconst) -> (match jsig with
- | TObject((["java";"lang"],"String"), []) ->
- write_byte ch (Char.code 's')
- | TByte | TChar | TDouble | TFloat | TInt | TLong | TShort | TBool ->
- write_string ch (encode_sig ctx jsig)
- | _ ->
- let s = encode_sig ctx jsig in
- error ("Invalid signature " ^ s ^ " for constant value"));
- write_ui16 ch (const ctx cconst)
- | ValEnum(jsig,name) ->
- write_byte ch (Char.code 'e');
- write_const ctx ch (ConstUtf8 (encode_sig ctx jsig));
- write_const ctx ch (ConstUtf8 name)
- | ValClass(jsig) ->
- write_byte ch (Char.code 'c');
- let esig = match jsig with
- | TObject(([],"Void"),[])
- | TObject((["java";"lang"],"Void"),[]) ->
- "V"
- | _ ->
- encode_sig ctx jsig
- in
- write_const ctx ch (ConstUtf8 (esig))
- | ValAnnotation ann ->
- write_byte ch (Char.code '@');
- write_annotation ctx ch ann
- | ValArray(lvals) ->
- write_byte ch (Char.code '[');
- write_ui16 ch (List.length lvals);
- List.iter (write_element_value ctx ch) lvals
- ;;
|