jReader.ml 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  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 ExtString;;
  22. open ExtList;;
  23. exception Error_message of string
  24. let error msg = raise (Error_message msg)
  25. let get_reference_type i constid =
  26. match i with
  27. | 1 -> RGetField
  28. | 2 -> RGetStatic
  29. | 3 -> RPutField
  30. | 4 -> RPutStatic
  31. | 5 -> RInvokeVirtual
  32. | 6 -> RInvokeStatic
  33. | 7 -> RInvokeSpecial
  34. | 8 -> RNewInvokeSpecial
  35. | 9 -> RInvokeInterface
  36. | _ -> error (string_of_int constid ^ ": Invalid reference type " ^ string_of_int i)
  37. let parse_constant max idx ch =
  38. let cid = IO.read_byte ch in
  39. let error() = error (string_of_int idx ^ ": Invalid constant " ^ string_of_int cid) in
  40. let index() =
  41. let n = read_ui16 ch in
  42. if n = 0 || n >= max then error();
  43. n
  44. in
  45. match cid with
  46. | 7 ->
  47. KClass (index())
  48. | 9 ->
  49. let n1 = index() in
  50. let n2 = index() in
  51. KFieldRef (n1,n2)
  52. | 10 ->
  53. let n1 = index() in
  54. let n2 = index() in
  55. KMethodRef (n1,n2)
  56. | 11 ->
  57. let n1 = index() in
  58. let n2 = index() in
  59. KInterfaceMethodRef (n1,n2)
  60. | 8 ->
  61. KString (index())
  62. | 3 ->
  63. KInt (read_real_i32 ch)
  64. | 4 ->
  65. let f = Int32.float_of_bits (read_real_i32 ch) in
  66. KFloat f
  67. | 5 ->
  68. KLong (read_i64 ch)
  69. | 6 ->
  70. KDouble (read_double ch)
  71. | 12 ->
  72. let n1 = index() in
  73. let n2 = index() in
  74. KNameAndType (n1, n2)
  75. | 1 ->
  76. let len = read_ui16 ch in
  77. let str = IO.nread_string ch len in
  78. (* TODO: correctly decode modified UTF8 *)
  79. KUtf8String str
  80. | 15 ->
  81. let reft = get_reference_type (IO.read_byte ch) idx in
  82. let dynref = index() in
  83. KMethodHandle (reft, dynref)
  84. | 16 ->
  85. KMethodType (index())
  86. | 17 ->
  87. let bootstrapref = read_ui16 ch in (* not index *)
  88. let nametyperef = index() in
  89. KDynamic (bootstrapref, nametyperef)
  90. | 18 ->
  91. let bootstrapref = read_ui16 ch in (* not index *)
  92. let nametyperef = index() in
  93. KInvokeDynamic (bootstrapref, nametyperef)
  94. | 19 ->
  95. KModule (index())
  96. | 20 ->
  97. KPackage (index())
  98. | n ->
  99. error()
  100. let expand_path s =
  101. let rec loop remaining acc =
  102. match remaining with
  103. | name :: [] -> List.rev acc, name
  104. | v :: tl -> loop tl (v :: acc)
  105. | _ -> assert false
  106. in
  107. loop (String.nsplit s "/") []
  108. let rec parse_type_parameter_part s =
  109. match s.[0] with
  110. | '*' -> TAny, 1
  111. | c ->
  112. let wildcard, i = match c with
  113. | '+' -> WExtends, 1
  114. | '-' -> WSuper, 1
  115. | _ -> WNone, 0
  116. in
  117. let jsig, l = parse_signature_part (String.sub s i (String.length s - 1)) in
  118. (TType (wildcard, jsig), l + i)
  119. and parse_signature_part s =
  120. let len = String.length s in
  121. if len = 0 then raise Exit;
  122. match s.[0] with
  123. | 'B' -> TByte, 1
  124. | 'C' -> TChar, 1
  125. | 'D' -> TDouble, 1
  126. | 'F' -> TFloat, 1
  127. | 'I' -> TInt, 1
  128. | 'J' -> TLong, 1
  129. | 'S' -> TShort, 1
  130. | 'Z' -> TBool, 1
  131. | 'L' ->
  132. (try
  133. let orig_s = s in
  134. let rec loop start i acc =
  135. match s.[i] with
  136. | '/' -> loop (i + 1) (i + 1) (String.sub s start (i - start) :: acc)
  137. | ';' | '.' -> List.rev acc, (String.sub s start (i - start)), [], (i)
  138. | '<' ->
  139. let name = String.sub s start (i - start) in
  140. let rec loop_params i acc =
  141. let s = String.sub s i (len - i) in
  142. match s.[0] with
  143. | '>' -> List.rev acc, i + 1
  144. | _ ->
  145. let tp, l = parse_type_parameter_part s in
  146. loop_params (l + i) (tp :: acc)
  147. in
  148. let params, _end = loop_params (i + 1) [] in
  149. List.rev acc, name, params, (_end)
  150. | _ -> loop start (i+1) acc
  151. in
  152. let pack, name, params, _end = loop 1 1 [] in
  153. let rec loop_inner i acc =
  154. match s.[i] with
  155. | '.' ->
  156. let pack, name, params, _end = loop (i+1) (i+1) [] in
  157. if pack <> [] then error ("Inner types must not define packages. For '" ^ orig_s ^ "'.");
  158. loop_inner _end ( (name,params) :: acc )
  159. | ';' -> List.rev acc, i + 1
  160. | c -> error ("End of complex type signature expected after type parameter. Got '" ^ Char.escaped c ^ "' for '" ^ orig_s ^ "'." );
  161. in
  162. let inners, _end = loop_inner _end [] in
  163. match inners with
  164. | [] -> TObject((pack,name), params), _end
  165. | _ -> TObjectInner( pack, (name,params) :: inners ), _end
  166. with
  167. Invalid_string -> raise Exit)
  168. | '[' ->
  169. let p = ref 1 in
  170. while !p < String.length s && s.[!p] >= '0' && s.[!p] <= '9' do
  171. incr p;
  172. done;
  173. let size = (if !p > 1 then Some (int_of_string (String.sub s 1 (!p - 1))) else None) in
  174. let s , l = parse_signature_part (String.sub s !p (String.length s - !p)) in
  175. TArray (s,size) , l + !p
  176. | '(' ->
  177. let p = ref 1 in
  178. let args = ref [] in
  179. while !p < String.length s && s.[!p] <> ')' do
  180. let a , l = parse_signature_part (String.sub s !p (String.length s - !p)) in
  181. args := a :: !args;
  182. p := !p + l;
  183. done;
  184. incr p;
  185. if !p >= String.length s then raise Exit;
  186. let ret , l = (match s.[!p] with 'V' -> None , 1 | _ ->
  187. let s, l = parse_signature_part (String.sub s !p (String.length s - !p)) in
  188. Some s, l
  189. ) in
  190. TMethod (List.rev !args,ret) , !p + l
  191. | 'T' ->
  192. (try
  193. let s1 , _ = String.split s ";" in
  194. let len = String.length s1 in
  195. TTypeParameter (String.sub s1 1 (len - 1)) , len + 1
  196. with
  197. Invalid_string -> raise Exit)
  198. | _ ->
  199. raise Exit
  200. let parse_signature s =
  201. try
  202. let sign , l = parse_signature_part s in
  203. if String.length s <> l then raise Exit;
  204. sign
  205. with
  206. Exit -> error ("Invalid signature '" ^ s ^ "'")
  207. let parse_method_signature s =
  208. match parse_signature s with
  209. | (TMethod m) -> m
  210. | _ -> error ("Unexpected signature '" ^ s ^ "'. Expecting method")
  211. let parse_formal_type_params s =
  212. match s.[0] with
  213. | '<' ->
  214. let rec read_id i =
  215. match s.[i] with
  216. | ':' | '>' -> i
  217. | _ -> read_id (i + 1)
  218. in
  219. let len = String.length s in
  220. let rec parse_params idx acc =
  221. let idi = read_id (idx + 1) in
  222. let id = String.sub s (idx + 1) (idi - idx - 1) in
  223. (* next must be a : *)
  224. (match s.[idi] with | ':' -> () | _ -> error ("Invalid formal type signature character: " ^ Char.escaped s.[idi] ^ " ; from " ^ s));
  225. let ext, l = match s.[idi + 1] with
  226. | ':' | '>' -> None, idi + 1
  227. | _ ->
  228. let sgn, l = parse_signature_part (String.sub s (idi + 1) (len - idi - 1)) in
  229. Some sgn, l + idi + 1
  230. in
  231. let rec loop idx acc =
  232. match s.[idx] with
  233. | ':' ->
  234. let ifacesig, ifacei = parse_signature_part (String.sub s (idx + 1) (len - idx - 1)) in
  235. loop (idx + ifacei + 1) (ifacesig :: acc)
  236. | _ -> acc, idx
  237. in
  238. let ifaces, idx = loop l [] in
  239. let acc = (id, ext, ifaces) :: acc in
  240. if s.[idx] = '>' then List.rev acc, idx + 1 else parse_params (idx - 1) acc
  241. in
  242. parse_params 0 []
  243. | _ -> [], 0
  244. let parse_throws s =
  245. let len = String.length s in
  246. let rec loop idx acc =
  247. if idx > len then raise Exit
  248. else if idx = len then acc, idx
  249. else match s.[idx] with
  250. | '^' ->
  251. let tsig, l = parse_signature_part (String.sub s (idx+1) (len - idx - 1)) in
  252. loop (idx + l + 1) (tsig :: acc)
  253. | _ -> acc, idx
  254. in
  255. loop 0 []
  256. let parse_complete_method_signature s =
  257. try
  258. let len = String.length s in
  259. let tparams, i = parse_formal_type_params s in
  260. let sign, l = parse_signature_part (String.sub s i (len - i)) in
  261. let throws, l2 = parse_throws (String.sub s (i+l) (len - i - l)) in
  262. if (i + l + l2) <> len then raise Exit;
  263. match sign with
  264. | TMethod msig -> tparams, msig, throws
  265. | _ -> raise Exit
  266. with
  267. Exit -> error ("Invalid method extended signature '" ^ s ^ "'")
  268. let rec expand_constant consts i =
  269. let unexpected i = error (string_of_int i ^ ": Unexpected constant type") in
  270. let expand_path n = match Array.get consts n with
  271. | KUtf8String s -> expand_path s
  272. | _ -> unexpected n
  273. in
  274. let expand_cls n = match expand_constant consts n with
  275. | ConstClass p -> p
  276. | _ -> unexpected n
  277. in
  278. let expand_nametype n = match expand_constant consts n with
  279. | ConstNameAndType (s,jsig) -> s, jsig
  280. | _ -> unexpected n
  281. in
  282. let expand_string n = match Array.get consts n with
  283. | KUtf8String s -> s
  284. | _ -> unexpected n
  285. in
  286. let expand_nametype_m n = match expand_nametype n with
  287. | (n, TMethod m) -> n, m
  288. | _ -> unexpected n
  289. in
  290. let expand ncls nt = match expand_cls ncls, expand_nametype nt with
  291. | path, (n, m) -> path, n, m
  292. in
  293. let expand_m ncls nt = match expand_cls ncls, expand_nametype_m nt with
  294. | path, (n, m) -> path, n, m
  295. in
  296. match Array.get consts i with
  297. | KClass utf8ref ->
  298. ConstClass (expand_path utf8ref)
  299. | KFieldRef (classref, nametyperef) ->
  300. ConstField (expand classref nametyperef)
  301. | KMethodRef (classref, nametyperef) ->
  302. ConstMethod (expand_m classref nametyperef)
  303. | KInterfaceMethodRef (classref, nametyperef) ->
  304. ConstInterfaceMethod (expand_m classref nametyperef)
  305. | KString utf8ref ->
  306. ConstString (expand_string utf8ref)
  307. | KInt i32 ->
  308. ConstInt i32
  309. | KFloat f ->
  310. ConstFloat f
  311. | KLong i64 ->
  312. ConstLong i64
  313. | KDouble d ->
  314. ConstDouble d
  315. | KNameAndType (n, t) ->
  316. ConstNameAndType(expand_string n, parse_signature (expand_string t))
  317. | KUtf8String s ->
  318. ConstUtf8 s (* TODO: expand UTF8 characters *)
  319. | KMethodHandle (reference_type, dynref) ->
  320. ConstMethodHandle (reference_type, expand_constant consts dynref)
  321. | KMethodType utf8ref ->
  322. ConstMethodType (parse_method_signature (expand_string utf8ref))
  323. | KDynamic(bootstrapref, nametyperef) ->
  324. let n, t = expand_nametype nametyperef in
  325. ConstDynamic(bootstrapref, n, t)
  326. | KInvokeDynamic (bootstrapref, nametyperef) ->
  327. let n, t = expand_nametype nametyperef in
  328. ConstInvokeDynamic(bootstrapref, n, t)
  329. | KModule n ->
  330. ConstModule (expand_string n)
  331. | KPackage n ->
  332. ConstPackage (expand_string n)
  333. | KUnusable ->
  334. ConstUnusable
  335. let parse_access_flags ch all_flags =
  336. let fl = read_ui16 ch in
  337. let flags = ref [] in
  338. List.iteri (fun fbit f ->
  339. if fl land (1 lsl fbit) <> 0 then begin
  340. flags := f :: !flags;
  341. if f = JUnusable then error ("Unusable flag: " ^ string_of_int fl)
  342. end
  343. ) all_flags;
  344. (*if fl land (0x4000 - (1 lsl !fbit)) <> 0 then error ("Invalid access flags " ^ string_of_int fl);*)
  345. !flags
  346. let get_constant c n =
  347. if n < 1 || n >= Array.length c then error ("Invalid constant index " ^ string_of_int n);
  348. match c.(n) with
  349. | ConstUnusable -> error "Unusable constant index";
  350. | x -> x
  351. let get_class consts ch =
  352. match get_constant consts (read_ui16 ch) with
  353. | ConstClass n -> n
  354. | _ -> error "Invalid class index"
  355. let get_string consts ch =
  356. let i = read_ui16 ch in
  357. match get_constant consts i with
  358. | ConstUtf8 s -> s
  359. | _ -> error ("Invalid string index " ^ string_of_int i)
  360. let rec parse_element_value consts ch =
  361. let tag = IO.read_byte ch in
  362. match Char.chr tag with
  363. | 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' | 's' ->
  364. let jsig = match (Char.chr tag) with
  365. | 's' ->
  366. TObject( (["java";"lang"],"String"), [] )
  367. | tag ->
  368. fst (parse_signature_part (Char.escaped tag))
  369. in
  370. ValConst(jsig, get_constant consts (read_ui16 ch))
  371. | 'e' ->
  372. let path = parse_signature (get_string consts ch) in
  373. let name = get_string consts ch in
  374. ValEnum (path, name)
  375. | 'c' ->
  376. let name = get_string consts ch in
  377. let jsig = if name = "V" then
  378. TObject(([], "Void"), [])
  379. else
  380. parse_signature name
  381. in
  382. ValClass jsig
  383. | '@' ->
  384. ValAnnotation (parse_annotation consts ch)
  385. | '[' ->
  386. let num_vals = read_ui16 ch in
  387. ValArray (List.init (num_vals) (fun _ -> parse_element_value consts ch))
  388. | tag -> error ("Invalid element value: '" ^ Char.escaped tag ^ "'")
  389. and parse_ann_element consts ch =
  390. let name = get_string consts ch in
  391. let element_value = parse_element_value consts ch in
  392. name, element_value
  393. and parse_annotation consts ch =
  394. let anntype = parse_signature (get_string consts ch) in
  395. let count = read_ui16 ch in
  396. {
  397. ann_type = anntype;
  398. ann_elements = List.init count (fun _ -> parse_ann_element consts ch)
  399. }
  400. let parse_attribute on_special consts ch =
  401. let aname = get_string consts ch in
  402. let error() = error ("Malformed attribute " ^ aname) in
  403. let alen = read_i32 ch in
  404. match aname with
  405. | "Deprecated" ->
  406. if alen <> 0 then error();
  407. Some (AttrDeprecated)
  408. | "LocalVariableTable" ->
  409. let len = read_ui16 ch in
  410. let locals = List.init len (fun _ ->
  411. let start_pc = read_ui16 ch in
  412. let length = read_ui16 ch in
  413. let name = get_string consts ch in
  414. let descriptor = get_string consts ch in
  415. let index = read_ui16 ch in
  416. {
  417. ld_start_pc = start_pc;
  418. ld_length = length;
  419. ld_name = name;
  420. ld_descriptor = descriptor;
  421. ld_index = index
  422. }
  423. ) in
  424. Some (AttrLocalVariableTable locals)
  425. | "MethodParameters" ->
  426. let len = IO.read_byte ch in
  427. let parameters = List.init len (fun _ ->
  428. let name = get_string consts ch in
  429. let flags = read_ui16 ch in
  430. (name,flags)
  431. ) in
  432. Some (AttrMethodParameters parameters)
  433. | "RuntimeVisibleAnnotations" ->
  434. let anncount = read_ui16 ch in
  435. Some (AttrVisibleAnnotations (List.init anncount (fun _ -> parse_annotation consts ch)))
  436. | "RuntimeInvisibleAnnotations" ->
  437. let anncount = read_ui16 ch in
  438. Some (AttrInvisibleAnnotations (List.init anncount (fun _ -> parse_annotation consts ch)))
  439. | _ ->
  440. let do_default () =
  441. Some (AttrUnknown (aname,IO.nread_string ch alen))
  442. in
  443. match on_special with
  444. | None -> do_default()
  445. | Some fn -> fn consts ch aname alen do_default
  446. let parse_attributes ?on_special consts ch count =
  447. let rec loop i acc =
  448. if i >= count then List.rev acc
  449. else match parse_attribute on_special consts ch with
  450. | None -> loop (i + 1) acc
  451. | Some attrib -> loop (i + 1) (attrib :: acc)
  452. in
  453. loop 0 []
  454. let parse_field kind consts ch =
  455. let all_flags = match kind with
  456. | JKField ->
  457. [JPublic; JPrivate; JProtected; JStatic; JFinal; JUnusable; JVolatile; JTransient; JSynthetic; JEnum]
  458. | JKMethod ->
  459. [JPublic; JPrivate; JProtected; JStatic; JFinal; JSynchronized; JBridge; JVarArgs; JNative; JUnusable; JAbstract; JStrict; JSynthetic]
  460. in
  461. let acc = ref (parse_access_flags ch all_flags) in
  462. let name = get_string consts ch in
  463. let sign = parse_signature (get_string consts ch) in
  464. let jsig = ref sign in
  465. let throws = ref [] in
  466. let types = ref [] in
  467. let constant = ref None in
  468. let code = ref None in
  469. let attrib_count = read_ui16 ch in
  470. let attribs = parse_attributes ~on_special:(fun _ _ aname alen do_default ->
  471. match kind, aname with
  472. | JKField, "ConstantValue" ->
  473. constant := Some (get_constant consts (read_ui16 ch));
  474. None
  475. | JKField, "Synthetic" ->
  476. if not (List.mem JSynthetic !acc) then acc := !acc @ [JSynthetic];
  477. None
  478. | JKField, "Signature" ->
  479. let s = get_string consts ch in
  480. jsig := parse_signature s;
  481. None
  482. | JKMethod, "Code" ->
  483. ignore(read_ui16 ch); (* max stack *)
  484. ignore(read_ui16 ch); (* max locals *)
  485. let len = read_i32 ch in
  486. ignore(IO.nread_string ch len); (* code *)
  487. let len = read_ui16 ch in
  488. for i = 0 to len - 1 do
  489. ignore(IO.nread_string ch 8);
  490. done; (* exceptions *)
  491. let attrib_count = read_ui16 ch in
  492. let attribs = parse_attributes consts ch attrib_count in
  493. code := Some attribs;
  494. None
  495. | JKMethod, "Exceptions" ->
  496. let num = read_ui16 ch in
  497. throws := List.init num (fun _ -> TObject(get_class consts ch,[]));
  498. None
  499. | JKMethod, "Signature" ->
  500. let s = get_string consts ch in
  501. let tp, sgn, thr = parse_complete_method_signature s in
  502. if thr <> [] then throws := thr;
  503. types := tp;
  504. jsig := TMethod(sgn);
  505. None
  506. | _ -> do_default()
  507. ) consts ch attrib_count in
  508. {
  509. jf_name = name;
  510. jf_kind = kind;
  511. (* signature, as used by the vm *)
  512. jf_vmsignature = sign;
  513. (* actual signature, as used in java code *)
  514. jf_signature = !jsig;
  515. jf_throws = !throws;
  516. jf_types = !types;
  517. jf_flags = !acc;
  518. jf_attributes = attribs;
  519. jf_constant = !constant;
  520. jf_code = !code;
  521. }
  522. let parse_class ch =
  523. if read_real_i32 ch <> 0xCAFEBABEl then error "Invalid header";
  524. let minorv = read_ui16 ch in
  525. let majorv = read_ui16 ch in
  526. let constant_count = read_ui16 ch in
  527. let const_big = ref true in
  528. let consts = Array.init constant_count (fun idx ->
  529. if !const_big then begin
  530. const_big := false;
  531. KUnusable
  532. end else
  533. let c = parse_constant constant_count idx ch in
  534. (match c with KLong _ | KDouble _ -> const_big := true | _ -> ());
  535. c
  536. ) in
  537. let consts = Array.mapi (fun i _ -> expand_constant consts i) consts in
  538. let flags = parse_access_flags ch [JPublic; JUnusable; JUnusable; JUnusable; JFinal; JSuper; JUnusable; JUnusable; JUnusable; JInterface; JAbstract; JUnusable; JSynthetic; JAnnotation; JEnum; JModule] in
  539. let this = get_class consts ch in
  540. let super_idx = read_ui16 ch in
  541. let super = match super_idx with
  542. | 0 -> TObject((["java";"lang"], "Object"), []);
  543. | idx -> match get_constant consts idx with
  544. | ConstClass path -> TObject(path,[])
  545. | _ -> error "Invalid super index"
  546. in
  547. let interfaces = List.init (read_ui16 ch) (fun _ -> TObject (get_class consts ch, [])) in
  548. let fields = List.init (read_ui16 ch) (fun _ -> parse_field JKField consts ch) in
  549. let methods = List.init (read_ui16 ch) (fun _ -> parse_field JKMethod consts ch) in
  550. let inner = ref [] in
  551. let types = ref [] in
  552. let super = ref super in
  553. let interfaces = ref interfaces in
  554. let attribs = read_ui16 ch in
  555. let attribs = parse_attributes ~on_special:(fun _ _ aname alen do_default ->
  556. match aname with
  557. | "InnerClasses" ->
  558. let count = read_ui16 ch in
  559. let classes = List.init count (fun _ ->
  560. let inner_ci = get_class consts ch in
  561. let outeri = read_ui16 ch in
  562. let outer_ci = match outeri with
  563. | 0 -> None
  564. | _ -> match get_constant consts outeri with
  565. | ConstClass n -> Some n
  566. | _ -> error "Invalid class index"
  567. in
  568. let inner_namei = read_ui16 ch in
  569. let inner_name = match inner_namei with
  570. | 0 -> None
  571. | _ -> match get_constant consts inner_namei with
  572. | ConstUtf8 s -> Some s
  573. | _ -> error ("Invalid string index " ^ string_of_int inner_namei)
  574. in
  575. let flags = parse_access_flags ch [JPublic; JPrivate; JProtected; JStatic; JFinal; JUnusable; JUnusable; JUnusable; JUnusable; JInterface; JAbstract; JSynthetic; JAnnotation; JEnum] in
  576. inner_ci, outer_ci, inner_name, flags
  577. ) in
  578. inner := classes;
  579. None
  580. | "Signature" ->
  581. let s = get_string consts ch in
  582. let formal, idx = parse_formal_type_params s in
  583. types := formal;
  584. let s = String.sub s idx (String.length s - idx) in
  585. let len = String.length s in
  586. let sup, idx = parse_signature_part s in
  587. let rec loop idx acc =
  588. if idx = len then
  589. acc
  590. else begin
  591. let s = String.sub s idx (len - idx) in
  592. let iface, i2 = parse_signature_part s in
  593. loop (idx + i2) (iface :: acc)
  594. end
  595. in
  596. interfaces := loop idx [];
  597. super := sup;
  598. None
  599. | _ -> do_default()
  600. ) consts ch attribs in
  601. IO.close_in ch;
  602. {
  603. cversion = majorv, minorv;
  604. cpath = this;
  605. csuper = !super;
  606. cflags = flags;
  607. cinterfaces = !interfaces;
  608. cfields = fields;
  609. cmethods = methods;
  610. cattributes = attribs;
  611. cinner_types = !inner;
  612. ctypes = !types;
  613. }