jWriter.ml 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. (*
  2. * This file is part of JavaLib
  3. * Copyright (c)2004-2012 Nicolas Cannasse and Caue Waneck
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  18. *)
  19. open JData;;
  20. open IO.BigEndian;;
  21. open IO;;
  22. open ExtString;;
  23. open ExtList;;
  24. exception Writer_error_message of string
  25. type context = {
  26. cpool : unit IO.output;
  27. mutable ccount : int;
  28. ch : string IO.output;
  29. mutable constants : (jconstant,int) PMap.t;
  30. }
  31. let error msg = raise (Writer_error_message msg)
  32. let get_reference_type i =
  33. match i with
  34. | RGetField -> 1
  35. | RGetStatic -> 2
  36. | RPutField -> 3
  37. | RPutStatic -> 4
  38. | RInvokeVirtual -> 5
  39. | RInvokeStatic -> 6
  40. | RInvokeSpecial -> 7
  41. | RNewInvokeSpecial -> 8
  42. | RInvokeInterface -> 9
  43. let encode_path ctx (pack,name) =
  44. String.concat "/" (pack @ [name])
  45. let rec encode_param ctx ch param =
  46. match param with
  47. | TAny -> write_byte ch (Char.code '*')
  48. | TType(w, s) ->
  49. (match w with
  50. | WExtends -> write_byte ch (Char.code '+')
  51. | WSuper -> write_byte ch (Char.code '-')
  52. | WNone -> ());
  53. encode_sig_part ctx ch s
  54. and encode_sig_part ctx ch jsig = match jsig with
  55. | TByte -> write_byte ch (Char.code 'B')
  56. | TChar -> write_byte ch (Char.code 'C')
  57. | TDouble -> write_byte ch (Char.code 'D')
  58. | TFloat -> write_byte ch (Char.code 'F')
  59. | TInt -> write_byte ch (Char.code 'I')
  60. | TLong -> write_byte ch (Char.code 'J')
  61. | TShort -> write_byte ch (Char.code 'S')
  62. | TBool -> write_byte ch (Char.code 'Z')
  63. | TObject(path, params) ->
  64. write_byte ch (Char.code 'L');
  65. write_string ch (encode_path ctx path);
  66. if params <> [] then begin
  67. write_byte ch (Char.code '<');
  68. List.iter (encode_param ctx ch) params;
  69. write_byte ch (Char.code '>')
  70. end;
  71. write_byte ch (Char.code ';')
  72. | TObjectInner(pack, inners) ->
  73. write_byte ch (Char.code 'L');
  74. List.iter (fun p ->
  75. write_string ch p;
  76. write_byte ch (Char.code '/')
  77. ) pack;
  78. let first = ref true in
  79. List.iter (fun (name,params) ->
  80. (if !first then first := false else write_byte ch (Char.code '.'));
  81. write_string ch name;
  82. if params <> [] then begin
  83. write_byte ch (Char.code '<');
  84. List.iter (encode_param ctx ch) params;
  85. write_byte ch (Char.code '>')
  86. end;
  87. ) inners;
  88. write_byte ch (Char.code ';')
  89. | TArray(s,size) ->
  90. write_byte ch (Char.code '[');
  91. (match size with
  92. | Some size ->
  93. write_string ch (string_of_int size);
  94. | None -> ());
  95. encode_sig_part ctx ch s
  96. | TMethod(args, ret) ->
  97. write_byte ch (Char.code '(');
  98. List.iter (encode_sig_part ctx ch) args;
  99. (match ret with
  100. | None -> write_byte ch (Char.code 'V')
  101. | Some jsig -> encode_sig_part ctx ch jsig)
  102. | TTypeParameter name ->
  103. write_byte ch (Char.code 'T');
  104. write_string ch name;
  105. write_byte ch (Char.code ';')
  106. let encode_sig ctx jsig =
  107. let buf = IO.output_string() in
  108. encode_sig_part ctx buf jsig;
  109. close_out buf
  110. let write_utf8 ch s =
  111. String.iter (fun c ->
  112. let c = Char.code c in
  113. if c = 0 then begin
  114. write_byte ch 0xC0;
  115. write_byte ch 0x80
  116. end else
  117. write_byte ch c
  118. ) s
  119. let rec const ctx c =
  120. try
  121. PMap.find c ctx.constants
  122. with
  123. | Not_found ->
  124. let ret = ctx.ccount in
  125. (match c with
  126. (** references a class or an interface - jpath must be encoded as StringUtf8 *)
  127. | ConstClass path -> (* tag = 7 *)
  128. write_byte ctx.cpool 7;
  129. write_ui16 ctx.cpool (const ctx (ConstUtf8 (encode_path ctx path)))
  130. (** field reference *)
  131. | ConstField (jpath, unqualified_name, jsignature) (* tag = 9 *) ->
  132. write_byte ctx.cpool 9;
  133. write_ui16 ctx.cpool (const ctx (ConstClass jpath));
  134. write_ui16 ctx.cpool (const ctx (ConstNameAndType (unqualified_name, jsignature)))
  135. (** method reference; string can be special "<init>" and "<clinit>" values *)
  136. | ConstMethod (jpath, unqualified_name, jmethod_signature) (* tag = 10 *) ->
  137. write_byte ctx.cpool 10;
  138. write_ui16 ctx.cpool (const ctx (ConstClass jpath));
  139. write_ui16 ctx.cpool (const ctx (ConstNameAndType (unqualified_name, TMethod jmethod_signature)))
  140. (** interface method reference *)
  141. | ConstInterfaceMethod (jpath, unqualified_name, jmethod_signature) (* tag = 11 *) ->
  142. write_byte ctx.cpool 11;
  143. write_ui16 ctx.cpool (const ctx (ConstClass jpath));
  144. write_ui16 ctx.cpool (const ctx (ConstNameAndType (unqualified_name, TMethod jmethod_signature)))
  145. (** constant values *)
  146. | ConstString s (* tag = 8 *) ->
  147. write_byte ctx.cpool 8;
  148. write_ui16 ctx.cpool (const ctx (ConstUtf8 s))
  149. | ConstInt i (* tag = 3 *) ->
  150. write_byte ctx.cpool 3;
  151. write_real_i32 ctx.cpool i
  152. | ConstFloat f (* tag = 4 *) ->
  153. write_byte ctx.cpool 4;
  154. (match classify_float f with
  155. | FP_normal | FP_subnormal | FP_zero ->
  156. write_real_i32 ctx.cpool (Int32.bits_of_float f)
  157. | FP_infinite when f > 0.0 ->
  158. write_real_i32 ctx.cpool 0x7f800000l
  159. | FP_infinite ->
  160. write_real_i32 ctx.cpool 0xff800000l
  161. | FP_nan ->
  162. write_real_i32 ctx.cpool 0x7f800001l)
  163. | ConstLong i (* tag = 5 *) ->
  164. write_byte ctx.cpool 5;
  165. write_i64 ctx.cpool i;
  166. | ConstDouble d (* tag = 6 *) ->
  167. write_byte ctx.cpool 6;
  168. write_double ctx.cpool d;
  169. ctx.ccount <- ctx.ccount + 1
  170. (** name and type: used to represent a field or method, without indicating which class it belongs to *)
  171. | ConstNameAndType (unqualified_name, jsignature) ->
  172. write_byte ctx.cpool 12;
  173. write_ui16 ctx.cpool (const ctx (ConstUtf8 (unqualified_name)));
  174. write_ui16 ctx.cpool (const ctx (ConstUtf8 (encode_sig ctx jsignature)))
  175. (** UTF8 encoded strings. Note that when reading/writing, take into account Utf8 modifications of java *)
  176. (* (http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.7) *)
  177. | ConstUtf8 s ->
  178. write_byte ctx.cpool 1;
  179. write_ui16 ctx.cpool (String.length s);
  180. write_utf8 ctx.cpool s
  181. (** invokeDynamic-specific *)
  182. | ConstMethodHandle (reference_type, jconstant) (* tag = 15 *) ->
  183. write_byte ctx.cpool 15;
  184. write_byte ctx.cpool (get_reference_type reference_type);
  185. write_ui16 ctx.cpool (const ctx jconstant)
  186. | ConstMethodType jmethod_signature (* tag = 16 *) ->
  187. write_byte ctx.cpool 16;
  188. write_ui16 ctx.cpool (const ctx (ConstUtf8 (encode_sig ctx (TMethod jmethod_signature))))
  189. | ConstDynamic (bootstrap_method, unqualified_name, jsignature) (* tag = 17 *) ->
  190. write_byte ctx.cpool 17;
  191. write_ui16 ctx.cpool bootstrap_method;
  192. write_ui16 ctx.cpool (const ctx (ConstNameAndType(unqualified_name, jsignature)))
  193. | ConstInvokeDynamic (bootstrap_method, unqualified_name, jsignature) (* tag = 18 *) ->
  194. write_byte ctx.cpool 18;
  195. write_ui16 ctx.cpool bootstrap_method;
  196. write_ui16 ctx.cpool (const ctx (ConstNameAndType(unqualified_name, jsignature)))
  197. | ConstModule unqualified_name (* tag = 19 *) ->
  198. write_byte ctx.cpool 19;
  199. write_ui16 ctx.cpool (const ctx (ConstUtf8 (unqualified_name)));
  200. | ConstPackage unqualified_name (* tag = 20 *) ->
  201. write_byte ctx.cpool 20;
  202. write_ui16 ctx.cpool (const ctx (ConstUtf8 (unqualified_name)));
  203. | ConstUnusable -> assert false);
  204. ctx.ccount <- ret + 1;
  205. ret
  206. let write_const ctx ch cconst =
  207. write_ui16 ch (const ctx cconst)
  208. ;;
  209. let write_formal_type_params ctx ch tparams =
  210. write_byte ch (Char.code '<');
  211. List.iter (fun (name,ext,impl) ->
  212. write_string ch name;
  213. (match ext with
  214. | None -> ()
  215. | Some jsig ->
  216. write_byte ch (Char.code ':');
  217. write_string ch (encode_sig ctx jsig));
  218. List.iter (fun jsig ->
  219. write_byte ch (Char.code ':');
  220. write_string ch (encode_sig ctx jsig)
  221. ) impl
  222. ) tparams;
  223. write_byte ch (Char.code '>');
  224. ;;
  225. let write_complete_method_signature ctx ch (tparams : jtypes) msig throws =
  226. if tparams <> [] then write_formal_type_params ctx ch tparams;
  227. write_string ch (encode_sig ctx (TMethod(msig)));
  228. if throws <> [] then List.iter (fun jsig ->
  229. write_byte ch (Char.code '^');
  230. write_string ch (encode_sig ctx jsig)
  231. ) throws
  232. ;;
  233. let write_access_flags ctx ch all_flags flags =
  234. let value = List.fold_left (fun acc flag ->
  235. try
  236. acc lor (Hashtbl.find all_flags flag)
  237. with Not_found ->
  238. error ("Not found flag: " ^ (string_of_int (Obj.magic flag)))
  239. ) 0 flags in
  240. write_ui16 ch value
  241. ;;
  242. let rec write_ann_element ctx ch (name,eval) =
  243. write_const ctx ch (ConstUtf8 name);
  244. write_element_value ctx ch eval
  245. and write_annotation ctx ch ann =
  246. write_const ctx ch (ConstUtf8 (encode_sig ctx ann.ann_type));
  247. write_ui16 ch (List.length ann.ann_elements);
  248. List.iter (write_ann_element ctx ch) ann.ann_elements
  249. and write_element_value ctx ch value = match value with
  250. | ValConst(jsig, cconst) -> (match jsig with
  251. | TObject((["java";"lang"],"String"), []) ->
  252. write_byte ch (Char.code 's')
  253. | TByte | TChar | TDouble | TFloat | TInt | TLong | TShort | TBool ->
  254. write_string ch (encode_sig ctx jsig)
  255. | _ ->
  256. let s = encode_sig ctx jsig in
  257. error ("Invalid signature " ^ s ^ " for constant value"));
  258. write_ui16 ch (const ctx cconst)
  259. | ValEnum(jsig,name) ->
  260. write_byte ch (Char.code 'e');
  261. write_const ctx ch (ConstUtf8 (encode_sig ctx jsig));
  262. write_const ctx ch (ConstUtf8 name)
  263. | ValClass(jsig) ->
  264. write_byte ch (Char.code 'c');
  265. let esig = match jsig with
  266. | TObject(([],"Void"),[])
  267. | TObject((["java";"lang"],"Void"),[]) ->
  268. "V"
  269. | _ ->
  270. encode_sig ctx jsig
  271. in
  272. write_const ctx ch (ConstUtf8 (esig))
  273. | ValAnnotation ann ->
  274. write_byte ch (Char.code '@');
  275. write_annotation ctx ch ann
  276. | ValArray(lvals) ->
  277. write_byte ch (Char.code '[');
  278. write_ui16 ch (List.length lvals);
  279. List.iter (write_element_value ctx ch) lvals
  280. ;;