jReader.ml 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  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. let fbit = ref 0 in
  339. List.iter (fun f ->
  340. if fl land (1 lsl !fbit) <> 0 then begin
  341. flags := f :: !flags;
  342. if f = JUnusable then error ("Unusable flag: " ^ string_of_int fl)
  343. end;
  344. incr fbit
  345. ) all_flags;
  346. (*if fl land (0x4000 - (1 lsl !fbit)) <> 0 then error ("Invalid access flags " ^ string_of_int fl);*)
  347. !flags
  348. let get_constant c n =
  349. if n < 1 || n >= Array.length c then error ("Invalid constant index " ^ string_of_int n);
  350. match c.(n) with
  351. | ConstUnusable -> error "Unusable constant index";
  352. | x -> x
  353. let get_class consts ch =
  354. match get_constant consts (read_ui16 ch) with
  355. | ConstClass n -> n
  356. | _ -> error "Invalid class index"
  357. let get_string consts ch =
  358. let i = read_ui16 ch in
  359. match get_constant consts i with
  360. | ConstUtf8 s -> s
  361. | _ -> error ("Invalid string index " ^ string_of_int i)
  362. let rec parse_element_value consts ch =
  363. let tag = IO.read_byte ch in
  364. match Char.chr tag with
  365. | 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' | 's' ->
  366. let jsig = match (Char.chr tag) with
  367. | 's' ->
  368. TObject( (["java";"lang"],"String"), [] )
  369. | tag ->
  370. fst (parse_signature_part (Char.escaped tag))
  371. in
  372. ValConst(jsig, get_constant consts (read_ui16 ch))
  373. | 'e' ->
  374. let path = parse_signature (get_string consts ch) in
  375. let name = get_string consts ch in
  376. ValEnum (path, name)
  377. | 'c' ->
  378. let name = get_string consts ch in
  379. let jsig = if name = "V" then
  380. TObject(([], "Void"), [])
  381. else
  382. parse_signature name
  383. in
  384. ValClass jsig
  385. | '@' ->
  386. ValAnnotation (parse_annotation consts ch)
  387. | '[' ->
  388. let num_vals = read_ui16 ch in
  389. ValArray (List.init (num_vals) (fun _ -> parse_element_value consts ch))
  390. | tag -> error ("Invalid element value: '" ^ Char.escaped tag ^ "'")
  391. and parse_ann_element consts ch =
  392. let name = get_string consts ch in
  393. let element_value = parse_element_value consts ch in
  394. name, element_value
  395. and parse_annotation consts ch =
  396. let anntype = parse_signature (get_string consts ch) in
  397. let count = read_ui16 ch in
  398. {
  399. ann_type = anntype;
  400. ann_elements = List.init count (fun _ -> parse_ann_element consts ch)
  401. }
  402. let parse_attribute on_special consts ch =
  403. let aname = get_string consts ch in
  404. let error() = error ("Malformed attribute " ^ aname) in
  405. let alen = read_i32 ch in
  406. match aname with
  407. | "Deprecated" ->
  408. if alen <> 0 then error();
  409. Some (AttrDeprecated)
  410. | "LocalVariableTable" ->
  411. let len = read_ui16 ch in
  412. let locals = List.init len (fun _ ->
  413. let start_pc = read_ui16 ch in
  414. let length = read_ui16 ch in
  415. let name = get_string consts ch in
  416. let descriptor = get_string consts ch in
  417. let index = read_ui16 ch in
  418. {
  419. ld_start_pc = start_pc;
  420. ld_length = length;
  421. ld_name = name;
  422. ld_descriptor = descriptor;
  423. ld_index = index
  424. }
  425. ) in
  426. Some (AttrLocalVariableTable locals)
  427. | "MethodParameters" ->
  428. let len = IO.read_byte ch in
  429. let parameters = List.init len (fun _ ->
  430. let name = get_string consts ch in
  431. let flags = read_ui16 ch in
  432. (name,flags)
  433. ) in
  434. Some (AttrMethodParameters parameters)
  435. | "RuntimeVisibleAnnotations" ->
  436. let anncount = read_ui16 ch in
  437. Some (AttrVisibleAnnotations (List.init anncount (fun _ -> parse_annotation consts ch)))
  438. | "RuntimeInvisibleAnnotations" ->
  439. let anncount = read_ui16 ch in
  440. Some (AttrInvisibleAnnotations (List.init anncount (fun _ -> parse_annotation consts ch)))
  441. | _ ->
  442. let do_default () =
  443. Some (AttrUnknown (aname,IO.nread_string ch alen))
  444. in
  445. match on_special with
  446. | None -> do_default()
  447. | Some fn -> fn consts ch aname alen do_default
  448. let parse_attributes ?on_special consts ch count =
  449. let rec loop i acc =
  450. if i >= count then List.rev acc
  451. else match parse_attribute on_special consts ch with
  452. | None -> loop (i + 1) acc
  453. | Some attrib -> loop (i + 1) (attrib :: acc)
  454. in
  455. loop 0 []
  456. let parse_field kind consts ch =
  457. let all_flags = match kind with
  458. | JKField ->
  459. [JPublic; JPrivate; JProtected; JStatic; JFinal; JUnusable; JVolatile; JTransient; JSynthetic; JEnum]
  460. | JKMethod ->
  461. [JPublic; JPrivate; JProtected; JStatic; JFinal; JSynchronized; JBridge; JVarArgs; JNative; JUnusable; JAbstract; JStrict; JSynthetic]
  462. in
  463. let acc = ref (parse_access_flags ch all_flags) in
  464. let name = get_string consts ch in
  465. let sign = parse_signature (get_string consts ch) in
  466. let jsig = ref sign in
  467. let throws = ref [] in
  468. let types = ref [] in
  469. let constant = ref None in
  470. let code = ref None in
  471. let attrib_count = read_ui16 ch in
  472. let attribs = parse_attributes ~on_special:(fun _ _ aname alen do_default ->
  473. match kind, aname with
  474. | JKField, "ConstantValue" ->
  475. constant := Some (get_constant consts (read_ui16 ch));
  476. None
  477. | JKField, "Synthetic" ->
  478. if not (List.mem JSynthetic !acc) then acc := !acc @ [JSynthetic];
  479. None
  480. | JKField, "Signature" ->
  481. let s = get_string consts ch in
  482. jsig := parse_signature s;
  483. None
  484. | JKMethod, "Code" ->
  485. ignore(read_ui16 ch); (* max stack *)
  486. ignore(read_ui16 ch); (* max locals *)
  487. let len = read_i32 ch in
  488. ignore(IO.nread_string ch len); (* code *)
  489. let len = read_ui16 ch in
  490. for i = 0 to len - 1 do
  491. ignore(IO.nread_string ch 8);
  492. done; (* exceptions *)
  493. let attrib_count = read_ui16 ch in
  494. let attribs = parse_attributes consts ch attrib_count in
  495. code := Some attribs;
  496. None
  497. | JKMethod, "Exceptions" ->
  498. let num = read_ui16 ch in
  499. throws := List.init num (fun _ -> TObject(get_class consts ch,[]));
  500. None
  501. | JKMethod, "Signature" ->
  502. let s = get_string consts ch in
  503. let tp, sgn, thr = parse_complete_method_signature s in
  504. if thr <> [] then throws := thr;
  505. types := tp;
  506. jsig := TMethod(sgn);
  507. None
  508. | _ -> do_default()
  509. ) consts ch attrib_count in
  510. {
  511. jf_name = name;
  512. jf_kind = kind;
  513. (* signature, as used by the vm *)
  514. jf_vmsignature = sign;
  515. (* actual signature, as used in java code *)
  516. jf_signature = !jsig;
  517. jf_throws = !throws;
  518. jf_types = !types;
  519. jf_flags = !acc;
  520. jf_attributes = attribs;
  521. jf_constant = !constant;
  522. jf_code = !code;
  523. }
  524. let parse_class ch =
  525. if read_real_i32 ch <> 0xCAFEBABEl then error "Invalid header";
  526. let minorv = read_ui16 ch in
  527. let majorv = read_ui16 ch in
  528. let constant_count = read_ui16 ch in
  529. let const_big = ref true in
  530. let consts = Array.init constant_count (fun idx ->
  531. if !const_big then begin
  532. const_big := false;
  533. KUnusable
  534. end else
  535. let c = parse_constant constant_count idx ch in
  536. (match c with KLong _ | KDouble _ -> const_big := true | _ -> ());
  537. c
  538. ) in
  539. let consts = Array.mapi (fun i _ -> expand_constant consts i) consts in
  540. let flags = parse_access_flags ch [JPublic; JUnusable; JUnusable; JUnusable; JFinal; JSuper; JUnusable; JUnusable; JUnusable; JInterface; JAbstract; JUnusable; JSynthetic; JAnnotation; JEnum; JModule] in
  541. let this = get_class consts ch in
  542. let super_idx = read_ui16 ch in
  543. let super = match super_idx with
  544. | 0 -> TObject((["java";"lang"], "Object"), []);
  545. | idx -> match get_constant consts idx with
  546. | ConstClass path -> TObject(path,[])
  547. | _ -> error "Invalid super index"
  548. in
  549. let interfaces = List.init (read_ui16 ch) (fun _ -> TObject (get_class consts ch, [])) in
  550. let fields = List.init (read_ui16 ch) (fun _ -> parse_field JKField consts ch) in
  551. let methods = List.init (read_ui16 ch) (fun _ -> parse_field JKMethod consts ch) in
  552. let inner = ref [] in
  553. let types = ref [] in
  554. let super = ref super in
  555. let interfaces = ref interfaces in
  556. let attribs = read_ui16 ch in
  557. let attribs = parse_attributes ~on_special:(fun _ _ aname alen do_default ->
  558. match aname with
  559. | "InnerClasses" ->
  560. let count = read_ui16 ch in
  561. let classes = List.init count (fun _ ->
  562. let inner_ci = get_class consts ch in
  563. let outeri = read_ui16 ch in
  564. let outer_ci = match outeri with
  565. | 0 -> None
  566. | _ -> match get_constant consts outeri with
  567. | ConstClass n -> Some n
  568. | _ -> error "Invalid class index"
  569. in
  570. let inner_namei = read_ui16 ch in
  571. let inner_name = match inner_namei with
  572. | 0 -> None
  573. | _ -> match get_constant consts inner_namei with
  574. | ConstUtf8 s -> Some s
  575. | _ -> error ("Invalid string index " ^ string_of_int inner_namei)
  576. in
  577. let flags = parse_access_flags ch [JPublic; JPrivate; JProtected; JStatic; JFinal; JUnusable; JUnusable; JUnusable; JUnusable; JInterface; JAbstract; JSynthetic; JAnnotation; JEnum] in
  578. inner_ci, outer_ci, inner_name, flags
  579. ) in
  580. inner := classes;
  581. None
  582. | "Signature" ->
  583. let s = get_string consts ch in
  584. let formal, idx = parse_formal_type_params s in
  585. types := formal;
  586. let s = String.sub s idx (String.length s - idx) in
  587. let len = String.length s in
  588. let sup, idx = parse_signature_part s in
  589. let rec loop idx acc =
  590. if idx = len then
  591. acc
  592. else begin
  593. let s = String.sub s idx (len - idx) in
  594. let iface, i2 = parse_signature_part s in
  595. loop (idx + i2) (iface :: acc)
  596. end
  597. in
  598. interfaces := loop idx [];
  599. super := sup;
  600. None
  601. | _ -> do_default()
  602. ) consts ch attribs in
  603. IO.close_in ch;
  604. {
  605. cversion = majorv, minorv;
  606. cpath = this;
  607. csuper = !super;
  608. cflags = flags;
  609. cinterfaces = !interfaces;
  610. cfields = fields;
  611. cmethods = methods;
  612. cattributes = attribs;
  613. cinner_types = !inner;
  614. ctypes = !types;
  615. }