javaclass.lua 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. require([[autorun\javaClassEditor]])
  2. --parser for .class files and java bytecode
  3. --http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html
  4. --constant type values
  5. java_CONSTANT_Class=7
  6. java_CONSTANT_Fieldref=9
  7. java_CONSTANT_Methodref=10
  8. java_CONSTANT_InterfaceMethodref=11
  9. java_CONSTANT_String=8
  10. java_CONSTANT_Integer=3
  11. java_CONSTANT_Float=4
  12. java_CONSTANT_Long=5
  13. java_CONSTANT_Double=6
  14. java_CONSTANT_NameAndType=12
  15. java_CONSTANT_Utf8=1
  16. java_CONSTANT_MethodHandle=15
  17. java_CONSTANT_MethodType=16
  18. java_CONSTANT_InvokeDynamic=18
  19. function java_read_u4(stream)
  20. local b={string.byte(stream.data, stream.index,stream.index+4-1)}
  21. stream.index=stream.index+4
  22. return byteTableToDword({b[4],b[3],b[2],b[1]})
  23. end
  24. function java_read_u2(stream)
  25. local b={string.byte(stream.data, stream.index,stream.index+2-1)}
  26. stream.index=stream.index+2
  27. return byteTableToWord({b[2],b[1]})
  28. end
  29. function java_read_u1(stream)
  30. local result=string.byte(stream.data, stream.index)
  31. stream.index=stream.index+1
  32. return result
  33. end
  34. function java_parseConstantPool_Class(stream)
  35. result={}
  36. result.tag=java_CONSTANT_Class
  37. result.name_index=java_read_u2(stream)
  38. return result
  39. end
  40. function java_parseConstantPool_Fieldref(stream)
  41. result={}
  42. result.tag=java_CONSTANT_Fieldref
  43. result.class_index=java_read_u2(stream)
  44. result.name_and_type_index=java_read_u2(stream)
  45. return result
  46. end
  47. function java_parseConstantPool_Methodref(stream)
  48. result={}
  49. result.tag=java_CONSTANT_Methodref
  50. result.class_index=java_read_u2(stream)
  51. result.name_and_type_index=java_read_u2(stream)
  52. return result
  53. end
  54. function java_parseConstantPool_InterfaceMethodref(stream)
  55. result={}
  56. result.tag=java_CONSTANT_InterfaceMethodref
  57. result.class_index=java_read_u2(stream)
  58. result.name_and_type_index=java_read_u2(stream)
  59. return result
  60. end
  61. function java_parseConstantPool_String(stream)
  62. result={}
  63. result.tag=java_CONSTANT_String
  64. result.string_index=java_read_u2(stream)
  65. return result
  66. end
  67. function java_parseConstantPool_Integer(stream)
  68. result={}
  69. result.tag=java_CONSTANT_Integer
  70. result.bytes=java_read_u4(stream)
  71. result.value=result.bytes
  72. return result
  73. end
  74. function java_parseConstantPool_Float(stream)
  75. result={}
  76. result.tag=java_CONSTANT_Float
  77. result.bytes=java_read_u4(stream)
  78. result.value=byteTableToFloat(dwordToByteTable(result.bytes))
  79. return result
  80. end
  81. function java_parseConstantPool_Long(stream)
  82. result={}
  83. result.tag=java_CONSTANT_Long
  84. result.high_bytes=java_read_u4(stream)
  85. result.low_bytes=java_read_u4(stream)
  86. local hb=dwordToByteTable(result.high_bytes)
  87. local lb=dwordToByteTable(result.low_bytes)
  88. local i
  89. for i=1, 4 do
  90. lb[i+4]=hb[i]
  91. end
  92. result.value=byteTableToQword(lb)
  93. return result
  94. end
  95. function java_parseConstantPool_Double(stream)
  96. result={}
  97. result.tag=java_CONSTANT_Double
  98. result.high_bytes=java_read_u4(stream)
  99. result.low_bytes=java_read_u4(stream)
  100. local hb=dwordToByteTable(result.high_bytes)
  101. local lb=dwordToByteTable(result.low_bytes)
  102. local i
  103. for i=1, 4 do
  104. lb[i+4]=hb[i]
  105. end
  106. result.value=byteTableToDouble(lb)
  107. return result
  108. end
  109. function java_parseConstantPool_NameAndType(stream)
  110. result={}
  111. result.tag=java_CONSTANT_NameAndType
  112. result.name_index=java_read_u2(stream)
  113. result.descriptor_index=java_read_u2(stream)
  114. return result
  115. end
  116. function java_parseConstantPool_Utf8(stream)
  117. result={}
  118. result.tag=java_CONSTANT_Utf8
  119. result.length=java_read_u2(stream)
  120. result.bytes={string.byte(stream.data, stream.index, stream.index+result.length-1)}
  121. result.utf8=string.sub(stream.data, stream.index, stream.index+result.length-1)
  122. stream.index=stream.index+result.length
  123. return result
  124. end
  125. function java_parseConstantPool_MethodHandle(stream)
  126. result={}
  127. result.tag=java_CONSTANT_MethodHandle
  128. result.reference_kind=java_read_u1(stream)
  129. result.reference_index=java_read_u2(stream)
  130. return result
  131. end
  132. function java_parseConstantPool_MethodType(stream)
  133. result={}
  134. result.tag=java_CONSTANT_MethodType
  135. result.descriptor_index=java_read_u2(stream)
  136. return result
  137. end
  138. function java_parseConstantPool_InvokeDynamic(stream)
  139. result={}
  140. result.tag=java_CONSTANT_InvokeDynamic
  141. result.bootstrap_method_attr_index=java_read_u2(stream)
  142. result.name_and_type_index=java_read_u2(stream)
  143. return result
  144. end
  145. java_parseConstantPoolTag={}
  146. java_parseConstantPoolTag[java_CONSTANT_Class]=java_parseConstantPool_Class
  147. java_parseConstantPoolTag[java_CONSTANT_Fieldref]=java_parseConstantPool_Fieldref
  148. java_parseConstantPoolTag[java_CONSTANT_Methodref]=java_parseConstantPool_Methodref
  149. java_parseConstantPoolTag[java_CONSTANT_InterfaceMethodref]=java_parseConstantPool_InterfaceMethodref
  150. java_parseConstantPoolTag[java_CONSTANT_String]=java_parseConstantPool_String
  151. java_parseConstantPoolTag[java_CONSTANT_Integer]=java_parseConstantPool_Integer
  152. java_parseConstantPoolTag[java_CONSTANT_Float]=java_parseConstantPool_Float
  153. java_parseConstantPoolTag[java_CONSTANT_Long]=java_parseConstantPool_Long
  154. java_parseConstantPoolTag[java_CONSTANT_Double]=java_parseConstantPool_Double
  155. java_parseConstantPoolTag[java_CONSTANT_NameAndType]=java_parseConstantPool_NameAndType
  156. java_parseConstantPoolTag[java_CONSTANT_Utf8]=java_parseConstantPool_Utf8
  157. java_parseConstantPoolTag[java_CONSTANT_MethodHandle]=java_parseConstantPool_MethodHandle
  158. java_parseConstantPoolTag[java_CONSTANT_MethodType]=java_parseConstantPool_MethodType
  159. java_parseConstantPoolTag[java_CONSTANT_InvokeDynamic]=java_parseConstantPool_InvokeDynamic
  160. function java_parseConstantPool(s, count)
  161. local i
  162. local result={}
  163. for i=1,count-1 do
  164. local tag=java_read_u1(s)
  165. --print(tag.." "..string.format("%x",s.index))
  166. if java_parseConstantPoolTag[tag]~=nil then
  167. result[i]=java_parseConstantPoolTag[tag](s)
  168. else
  169. error("Invalid constant pool tag encountered: "..s.index.." (tag="..tag..") (i="..i..")")
  170. end
  171. end
  172. return result
  173. end
  174. function java_parseAttribute_ConstantValue(cp, a)
  175. --create a local stream for parsing the info bytes of the attribute
  176. local s={}
  177. s.data=a.info
  178. s.index=1
  179. a.constantvalue_index=java_read_u2(s);
  180. if cp[a.constantvalue_index].tag==java_CONSTANT_String then
  181. a.value=cp[cp[a.constantvalue_index].string_index].utf8
  182. else
  183. a.value=cp[a.constantvalue_index].value
  184. end
  185. end
  186. function java_parseBytecode(cp, s, code_length)
  187. local result={}
  188. local bytes={string.byte(s.data, s.index, s.index+code_length-1)}
  189. --parse the bytes into an array of programcounter and interpreted bytecode command
  190. result=bytecodeDisassembler(bytes)
  191. s.index=s.index+code_length
  192. return result
  193. end
  194. function java_parseAttribute_Code(cp, a)
  195. local i;
  196. local s={}
  197. s.data=a.info
  198. s.index=1
  199. a.max_stack=java_read_u2(s)
  200. a.max_locals=java_read_u2(s)
  201. a.code_length=java_read_u4(s)
  202. a.code=java_parseBytecode(cp, s, a.code_length)
  203. a.exception_table_length=java_read_u2(s)
  204. a.exception_table={}
  205. for i=1, a.exception_table_length do
  206. a.exception_table[i]={}
  207. a.exception_table[i].start_pc=java_read_u2(s)
  208. a.exception_table[i].end_pc=java_read_u2(s)
  209. a.exception_table[i].handler_pc=java_read_u2(s)
  210. a.exception_table[i].catch_type=java_read_u2(s)
  211. end
  212. a.attributes_count=java_read_u2(s)
  213. a.attributes=java_parseAttributes(cp, s, a.attributes_count)
  214. end
  215. function java_parseAttribute_Exceptions(cp, a)
  216. local i;
  217. local s={}
  218. s.data=a.info
  219. s.index=1
  220. a.attribute_name_index=java_read_u2(s)
  221. a.attribute_length=java_read_u4(s)
  222. a.number_of_exceptions=java_read_u2(s)
  223. a.exception_index_table={}
  224. for i=1, a.number_of_exceptions do
  225. a.exception_index_table[i]=java_read_u2(s)
  226. end
  227. end
  228. java_parseAttribute={}
  229. java_parseAttribute["ConstantValue"]=java_parseAttribute_ConstantValue
  230. java_parseAttribute["Code"]=java_parseAttribute_Code
  231. java_parseAttribute["Exceptions"]=java_parseAttribute_Exceptions
  232. --add more yourself...
  233. function java_parseAttributes(cp, s, count)
  234. local i
  235. local result={}
  236. for i=1,count do
  237. result[i]={}
  238. result[i].attribute_name_index=java_read_u2(s)
  239. result[i].attribute_length=java_read_u4(s)
  240. result[i].info=string.sub(s.data, s.index, s.index+result[i].attribute_length-1)
  241. s.index=s.index+result[i].attribute_length
  242. --fill in some extra data (not required for rebuilding)
  243. result[i].attribute_name=cp[result[i].attribute_name_index].utf8
  244. if java_parseAttribute[result[i].attribute_name]~=nil then --extra data for this attribute is available
  245. java_parseAttribute[result[i].attribute_name](cp, result[i])
  246. end
  247. end
  248. return result
  249. end
  250. function java_parseFields(cp, s, count)
  251. local i
  252. local result={}
  253. for i=1,count do
  254. result[i]={}
  255. result[i].access_flags=java_read_u2(s)
  256. result[i].name_index=java_read_u2(s)
  257. result[i].descriptor_index=java_read_u2(s)
  258. result[i].attributes_count=java_read_u2(s)
  259. result[i].attributes=java_parseAttributes(cp, s, result[i].attributes_count)
  260. end
  261. return result
  262. end
  263. function java_parseMethods(cp, s, count)
  264. local i
  265. local result={}
  266. for i=1,count do
  267. result[i]={}
  268. result[i].access_flags=java_read_u2(s)
  269. result[i].name_index=java_read_u2(s)
  270. result[i].descriptor_index=java_read_u2(s)
  271. result[i].attributes_count=java_read_u2(s)
  272. result[i].attributes=java_parseAttributes(cp, s, result[i].attributes_count)
  273. end
  274. return result
  275. end
  276. function java_parseClass(data)
  277. local result={}
  278. local s={}
  279. local i,j
  280. s.data=data
  281. s.index=1
  282. result.magic=java_read_u4(s)
  283. if (result.magic~=0xcafebabe) then
  284. error("Not a valid classfile")
  285. end
  286. result.minor_version=java_read_u2(s)
  287. result.major_version=java_read_u2(s)
  288. result.constant_pool_count=java_read_u2(s)
  289. result.constant_pool_start=s.index
  290. result.constant_pool=java_parseConstantPool(s, result.constant_pool_count)
  291. result.constant_pool_stop=s.index
  292. result.access_flags=java_read_u2(s)
  293. result.this_class=java_read_u2(s)
  294. result.super_class=java_read_u2(s)
  295. result.interfaces_count=java_read_u2(s)
  296. result.interfaces={}
  297. for i=1,result.interfaces_count do
  298. result.interfaces[i]=java_read_u2(s)
  299. end
  300. result.fields_count=java_read_u2(s)
  301. result.fields=java_parseFields(result.constant_pool, s, result.fields_count)
  302. result.methods_count=java_read_u2(s)
  303. result.methods=java_parseMethods(result.constant_pool, s, result.methods_count)
  304. result.attributes_count=java_read_u2(s)
  305. result.attributes=java_parseAttributes(result.constant_pool, s, result.attributes_count)
  306. return result
  307. end
  308. ----------------------------------------Write class---------------------------------------
  309. function java_write_u4(stream, value)
  310. assert(value)
  311. local b=dwordToByteTable(value)
  312. stream.data=stream.data..string.char(b[4], b[3], b[2],b[1])
  313. stream.index=stream.index+4
  314. end
  315. function java_write_u2(stream, value)
  316. assert(value)
  317. local b=wordToByteTable(value)
  318. stream.data=stream.data..string.char(b[2],b[1])
  319. stream.index=stream.index+2
  320. end
  321. function java_write_u1(stream, value)
  322. assert(value)
  323. stream.data=stream.data..string.char(value)
  324. stream.index=stream.index+1
  325. end
  326. function java_writeConstantPool_Class(s, cpitem)
  327. java_write_u2(s, cpitem.name_index)
  328. end
  329. function java_writeConstantPool_Fieldref(s, cpitem)
  330. java_write_u2(s, cpitem.class_index)
  331. java_write_u2(s, cpitem.name_and_type_index)
  332. end
  333. function java_writeConstantPool_Methodref(s, cpitem)
  334. java_write_u2(s, cpitem.class_index)
  335. java_write_u2(s, cpitem.name_and_type_index)
  336. end
  337. function java_writeConstantPool_InterfaceMethodref(s, cpitem)
  338. java_write_u2(s, cpitem.class_index)
  339. java_write_u2(s, cpitem.name_and_type_index)
  340. end
  341. function java_writeConstantPool_String(s, cpitem)
  342. java_write_u2(s, cpitem.string_index)
  343. end
  344. function java_writeConstantPool_Integer(s, cpitem)
  345. java_write_u4(s, cpitem.bytes)
  346. end
  347. function java_writeConstantPool_Float(s, cpitem)
  348. java_write_u4(s, cpitem.bytes)
  349. end
  350. function java_writeConstantPool_Long(s, cpitem)
  351. java_write_u4(s, cpitem.high_bytes)
  352. java_write_u4(s, cpitem.low_bytes)
  353. end
  354. function java_writeConstantPool_Double(s, cpitem)
  355. java_write_u4(s, cpitem.high_bytes)
  356. java_write_u4(s, cpitem.low_bytes)
  357. end
  358. function java_writeConstantPool_NameAndType(s, cpitem)
  359. java_write_u2(s, cpitem.name_index)
  360. java_write_u2(s, cpitem.descriptor_index)
  361. end
  362. function java_writeConstantPool_Utf8(s, cpitem)
  363. java_write_u2(s, cpitem.length)
  364. local i
  365. for i=1, cpitem.length do
  366. s.data=s.data..string.char(cpitem.bytes[i])
  367. end
  368. s.index=s.index+cpitem.length
  369. end
  370. function java_writeConstantPool_MethodHandle(s, cpitem)
  371. java_write_u1(s, cpitem.reference_kind)
  372. java_write_u2(s, cpitem.reference_index)
  373. end
  374. function java_writeConstantPool_MethodType(s, cpitem)
  375. java_write_u2(s, cpitem.descriptor_index)
  376. end
  377. function java_writeConstantPool_InvokeDynamic(s, cpitem)
  378. java_write_u2(s, cpitem.bootstrap_method_attr_index)
  379. java_write_u2(s, cpitem.name_and_type_index)
  380. end
  381. java_writeConstantPoolTag={}
  382. java_writeConstantPoolTag[java_CONSTANT_Class]=java_writeConstantPool_Class
  383. java_writeConstantPoolTag[java_CONSTANT_Fieldref]=java_writeConstantPool_Fieldref
  384. java_writeConstantPoolTag[java_CONSTANT_Methodref]=java_writeConstantPool_Methodref
  385. java_writeConstantPoolTag[java_CONSTANT_InterfaceMethodref]=java_writeConstantPool_InterfaceMethodref
  386. java_writeConstantPoolTag[java_CONSTANT_String]=java_writeConstantPool_String
  387. java_writeConstantPoolTag[java_CONSTANT_Integer]=java_writeConstantPool_Integer
  388. java_writeConstantPoolTag[java_CONSTANT_Float]=java_writeConstantPool_Float
  389. java_writeConstantPoolTag[java_CONSTANT_Long]=java_writeConstantPool_Long
  390. java_writeConstantPoolTag[java_CONSTANT_Double]=java_writeConstantPool_Double
  391. java_writeConstantPoolTag[java_CONSTANT_NameAndType]=java_writeConstantPool_NameAndType
  392. java_writeConstantPoolTag[java_CONSTANT_Utf8]=java_writeConstantPool_Utf8
  393. java_writeConstantPoolTag[java_CONSTANT_MethodHandle]=java_writeConstantPool_MethodHandle
  394. java_writeConstantPoolTag[java_CONSTANT_MethodType]=java_writeConstantPool_MethodType
  395. java_writeConstantPoolTag[java_CONSTANT_InvokeDynamic]=java_writeConstantPool_InvokeDynamic
  396. function java_writeConstantPool(s, constant_pool, constant_pool_count)
  397. local i
  398. for i=1,constant_pool_count-1 do
  399. java_write_u1(s, constant_pool[i].tag)
  400. java_writeConstantPoolTag[constant_pool[i].tag](s, constant_pool[i])
  401. end
  402. end
  403. function java_writeAttributes(s, attributes, attributes_count)
  404. local i
  405. assert(#attributes==attributes_count)
  406. for i=1, attributes_count do
  407. java_write_u2(s, attributes[i].attribute_name_index)
  408. java_write_u4(s, attributes[i].attribute_length)
  409. s.data=s.data..attributes[i].info
  410. s.index=s.index+attributes[i].attribute_length
  411. end
  412. end
  413. function java_writeFields(s, fields, field_count)
  414. local i
  415. for i=1, field_count do
  416. java_write_u2(s, fields[i].access_flags)
  417. java_write_u2(s, fields[i].name_index)
  418. java_write_u2(s, fields[i].descriptor_index)
  419. java_write_u2(s, fields[i].attributes_count)
  420. java_writeAttributes(s, fields[i].attributes, fields[i].attributes_count)
  421. end
  422. end
  423. function java_writeMethods(s, methods, method_count)
  424. local i
  425. for i=1, method_count do
  426. java_write_u2(s, methods[i].access_flags)
  427. java_write_u2(s, methods[i].name_index)
  428. java_write_u2(s, methods[i].descriptor_index)
  429. java_write_u2(s, methods[i].attributes_count)
  430. java_writeAttributes(s, methods[i].attributes, methods[i].attributes_count)
  431. end
  432. end
  433. function java_writeClass(class)
  434. local s={}
  435. local i
  436. s.data=''
  437. s.index=1
  438. java_write_u4(s, 0xcafebabe)
  439. java_write_u2(s, class.minor_version)
  440. java_write_u2(s, class.major_version)
  441. java_write_u2(s, class.constant_pool_count)
  442. java_writeConstantPool(s, class.constant_pool, class.constant_pool_count)
  443. java_write_u2(s, class.access_flags)
  444. java_write_u2(s, class.this_class)
  445. java_write_u2(s, class.super_class)
  446. java_write_u2(s, class.interfaces_count)
  447. for i=1, class.interfaces_count do
  448. java_write_u2(s, class..interfaces[i])
  449. end
  450. java_write_u2(s, class.fields_count)
  451. java_writeFields(s, class.fields, class.fields_count)
  452. java_write_u2(s, class.methods_count)
  453. java_writeMethods(s, class.methods, class.methods_count)
  454. java_write_u2(s, class.attributes_count)
  455. java_writeAttributes(s, class.attributes, class.attributes_count)
  456. return s.data
  457. end
  458. ----------------------------------------runtime helpers----------------------------------------
  459. function javaclass_getMethodName(class, method)
  460. return class.constant_pool[method.name_index].utf8
  461. end
  462. function javaclass_getExceptionTable(class, method)
  463. end
  464. function javaclass_findMethod(class, methodname)
  465. --returns the method table for the requested method
  466. local i
  467. for i=1, class.methods_count do
  468. if javaclass_getMethodName(class, class.methods[i])==methodname then
  469. return class.methods[i]
  470. end
  471. end
  472. return nil
  473. end
  474. function javaclass_method_findCodeAttribute(method)
  475. local i
  476. if method.CodeAttribute==nil then
  477. for i=1, #method.attributes do
  478. if method.attributes[i].attribute_name=="Code" then
  479. method.CodeAttribute=method.attributes[i]
  480. return method.attributes[i]
  481. end
  482. end
  483. else
  484. return method.CodeAttribute
  485. end
  486. return nil
  487. end
  488. --teststuff
  489. --function trace(event, line)
  490. -- print(line)
  491. --end
  492. --f=io.open([[c:\Users\DB\workspace\guitest\bin\Test.class]],"rb")
  493. --data=f:read("*all")
  494. --f:close()
  495. --x=java_parseClass(data)
  496. --debug.sethook(trace, "l")
  497. --newdata=java_writeClass(x)
  498. --f2=io.open([[c:\Users\DB\workspace\guitest\bin\bla\Test.class]],"wb")
  499. --f2:write(newdata)
  500. --f2:close()
  501. --x2=java_parseClass(newdata)