10 ACC_SYNCHRONIZED = 0x0020
13 ACC_TRANSIENT = 0x0080
16 ACC_INTERFACE = 0x0200
19 ACC_SYNTHETIC = 0x1000
20 ACC_ANNOTATION = 0x2000
25 CONSTANT_Methodref = 10
26 CONSTANT_InterfaceMethodref = 11
32 CONSTANT_NameAndType = 12
34 CONSTANT_MethodHandle = 15
35 CONSTANT_MethodType = 16
36 CONSTANT_InvokeDynamic = 18
38 version = collections.namedtuple("version", ["major", "minor"])
39 version.__eq__ = lambda s, o: s.major == o.major and s.minor == o.minor
40 version.__ne__ = lambda s, o: s.major != o.major or s.minor != o.minor
41 version.__lt__ = lambda s, o: (s.major < o.major) or (s.major == o.major and s.minor < o.minor)
42 version.__gt__ = lambda s, o: (s.major > o.major) or (s.major == o.major and s.minor > o.minor)
43 version.__le__ = lambda s, o: (s.major < o.major) or (s.major == o.major and s.minor <= o.minor)
44 version.__ge__ = lambda s, o: (s.major > o.major) or (s.major == o.major and s.minor >= o.minor)
45 version.J5 = version(49, 0)
46 version.J6 = version(50, 0)
47 version.J7 = version(51, 0)
48 version.J8 = version(52, 0)
50 class constint(object):
51 def __init__(self, val):
54 return hash(constint) + self.val
56 return isinstance(o, constint) and o.val == s.val
57 class constfloat(object):
58 def __init__(self, val):
61 return hash(constfloat) + self.val
63 return isinstance(o, constfloat) and o.val == s.val
64 class constlong(object):
65 def __init__(self, val):
68 return hash(constlong) + self.val
70 return isinstance(o, constlong) and o.val == s.val
71 class constdouble(object):
72 def __init__(self, val):
75 return hash(constdouble) + self.val
77 return isinstance(o, constdouble) and o.val == s.val
79 class conststr(object):
80 def __init__(self, idx):
83 return hash(conststr) + self.idx
85 return isinstance(o, conststr) and o.idx == s.idx
87 class classref(object):
88 def __init__(self, nm):
91 return hash(classref) + self.nm
93 return isinstance(o, classref) and o.nm == s.nm
96 def __init__(self, nm, tp):
100 return hash(sig) + self.nm * 31 + self.tp
102 return isinstance(o, sig) and o.nm == s.nm and o.tp == s.tp
104 class fieldref(object):
105 def __init__(self, cls, sig):
109 return hash(fieldref) + self.cls * 31 + self.sig
111 return isinstance(o, fieldref) and o.cls == s.cls and o.sig == s.sig
113 class methodref(object):
114 def __init__(self, cls, sig):
118 return hash(methodref) + self.cls * 31 + self.sig
120 return isinstance(o, methodref) and o.cls == s.cls and o.sig == s.sig
122 class imethodref(object):
123 def __init__(self, cls, sig):
127 return hash(imethodref) + self.cls * 31 + self.sig
129 return isinstance(o, imethodref) and o.cls == s.cls and o.sig == s.sig
132 def __init__(self, acc, nm, descr):
139 self.deprecated = False
144 class localdef(object):
145 def __init__(self, start, end, nm, descr, reg):
163 class method(object):
164 def __init__(self, acc, nm, descr):
172 self.deprecated = False
180 class annotation(object):
181 def __init__(self, tp):
185 class innerclass(object):
186 def __init__(self, cls, outer, nm, acc):
192 class classfile(object):
195 def __init__(self, ver, access=None):
205 self.innerclasses = []
206 self.enclosingmethod = None
209 self.deprecated = False
214 def loadconstant(self, buf):
216 if t == CONSTANT_Utf8:
217 return binfmt.mutf8dec(buf.splice(buf.uint16())), False
218 elif t == CONSTANT_Class:
219 return classref(buf.uint16()), False
220 elif t == CONSTANT_String:
221 return conststr(buf.uint16()), False
222 elif t == CONSTANT_Integer:
223 return constint(buf.int32()), False
224 elif t == CONSTANT_Float:
225 return constfloat(buf.float32()), False
226 elif t == CONSTANT_Long:
227 return constlong(buf.int64()), True
228 elif t == CONSTANT_Double:
229 return constdouble(buf.float64()), True
230 elif t == CONSTANT_Fieldref:
231 return fieldref(buf.uint16(), buf.uint16()), False
232 elif t == CONSTANT_Methodref:
233 return methodref(buf.uint16(), buf.uint16()), False
234 elif t == CONSTANT_InterfaceMethodref:
235 return imethodref(buf.uint16(), buf.uint16()), False
236 elif t == CONSTANT_NameAndType:
237 return sig(buf.uint16(), buf.uint16()), False
239 raise binfmt.fmterror("unknown constant tag: " + str(t))
241 def saveconstant(self, buf, const):
242 if isinstance(const, str):
243 buf.uint8(CONSTANT_Utf8).extend(binfmt.mutf8enc(const))
244 elif isinstance(const, classref):
245 buf.uint8(CONSTANT_Class).uint16(const.nm)
246 elif isinstance(const, conststr):
247 buf.uint8(CONSTANT_String).uint16(const.idx)
248 elif isinstance(const, constint):
249 buf.uint8(CONSTANT_Integer).int32(const.val)
250 elif isinstance(const, constfloat):
251 buf.uint8(CONSTANT_Float).float32(const.val)
252 elif isinstance(const, constlong):
253 buf.uint8(CONSTANT_Long).int64(const.val)
254 elif isinstance(const, constdouble):
255 buf.uint8(CONSTANT_Double).float64(const.val)
256 elif isinstance(const, fieldref):
257 buf.uint8(CONSTANT_Fieldref).uint16(const.cls).uint16(const.sig)
258 elif isinstance(const, methodref):
259 buf.uint8(CONSTANT_Methodref).uint16(const.cls).uint16(const.sig)
260 elif isinstance(const, imethodref):
261 buf.uint8(CONSTANT_InterfaceMethodref).uint16(const.cls).uint16(const.sig)
262 elif isinstance(const, sig):
263 buf.uint8(CONSTANT_NameAndType).uint16(const.nm).uint16(const.tp)
265 raise Exception("unexpected object type in constant pool: " + const)
267 def checkcp(self, idx, tp):
268 return 0 <= idx < len(self.cp) and isinstance(self.cp[idx], tp)
270 def intern(self, const, new=Exception):
271 for i, cur in enumerate(self.cp):
275 raise Exception("constant not present in pool: " + const)
277 self.cp.append(const)
278 return len(self.cp) - 1
282 def loadattr(self, buf):
284 if not self.checkcp(nm, str):
285 raise binfmt.fmterror("invalid attribute name reference")
286 return nm, binfmt.decbuf(buf.splice(buf.uint32()))
288 def saveattrs(self, buf, attrs):
289 buf.uint16(len(attrs))
290 for nm, data in attrs:
291 buf.uint16(nm).uint32(len(data)).extend(data)
293 def loadannval(self, buf):
298 return (buf.uint16(), buf.uint16())
300 return classref(buf.uint16()) # XXX, but meh
302 return loadannotation(buf)
304 return [self.loadannval(buf) for i in range(buf.uint16())]
306 raise binfmt.fmterror("unknown annotation-value type tag: " + t)
308 def saveannval(self, buf, val):
309 if isinstance(val, int):
311 if isinstance(const, str):
312 buf.uint8(ord('s')).uint16(val)
314 raise Exception("unexpected constant type in annotation value: " + const)
315 elif isinstance(val, tuple) and len(val) == 2:
316 buf.uint8(ord('e')).uint16(val[0]).uint16(val[1])
317 elif isinstance(val, classref):
318 buf.uint8(ord('c')).uint16(val.nm)
319 elif isinstance(val, annotation):
321 saveannotation(buf, val)
322 elif isinstance(val, list):
324 for sval in val: self.saveannval(buf, sval)
326 raise Exception("unexpected annotation value type: " + val)
328 def loadannotation(self, buf):
330 if not self.checkcp(tp, str):
331 raise binfmt.fmterror("invalid annotation type reference")
334 for i in range(nval):
336 if not self.checkcp(nm, str):
337 raise binfmt.fmterror("invalid annotation-value name reference")
338 ret.vals[nm] = self.loadannval(buf)
341 def saveannotation(self, buf, ann):
343 buf.uint16(len(ann.vals))
344 for key, val in ann.vals.items():
346 self.saveannval(buf, val)
348 def loadfield(self, buf):
351 if not self.checkcp(nm, str):
352 raise binfmt.fmterror("invalid field name reference")
354 if not self.checkcp(descr, str):
355 raise binfmt.fmterror("invalid field descriptor reference")
356 ret = field(acc, nm, descr)
358 for i in range(nattr):
359 nm, data = self.loadattr(buf)
361 if pnm == "ConstantValue":
362 ret.const = data.uint16()
363 elif pnm == "Synthetic":
365 elif pnm == "Signature":
366 ret.sig = data.uint16()
367 elif pnm == "Deprecated":
368 ret.deprecated = True
369 elif pnm == "RuntimeVisibleAnnotations":
370 for o in range(data.uint16()):
371 ret.rtann.append(self.loadannotation(data))
372 elif pnm == "RuntimeInvisibleAnnotations":
373 for o in range(data.uint16()):
374 ret.cpann.append(self.loadannotation(data))
376 ret.attrs.append((nm, data.splice()))
379 def savefield(self, buf, field):
380 buf.uint16(field.acc)
381 buf.uint16(field.nm).uint16(field.descr)
382 attrs = list(field.attrs)
384 if field.const is not None:
385 attrs.append((self.intern("ConstantValue"), enc().uint16(field.const)))
387 attrs.append((self.intern("Synthetic"), b""))
388 if field.sig is not None:
389 attrs.append((self.intern("Signature"), enc().uint16(field.sig)))
391 attrs.append((self.intern("Deprecated"), b""))
392 if len(field.rtann) > 0:
394 data.uint16(len(field.rtann))
395 for ann in field.rtann: self.saveannotation(data, ann)
396 attrs.append((self.intern("RuntimeVisibleAnnotations"), data))
397 if len(field.cpann) > 0:
399 data.uint16(len(field.cpann))
400 for ann in field.cpann: self.saveannotation(data, ann)
401 attrs.append((self.intern("RuntimeInvisibleAnnotations"), data))
402 self.saveattrs(buf, attrs)
404 def loadcode(self, buf):
406 ret.maxstack = buf.uint16()
407 ret.maxlocals = buf.uint16()
408 ret.code = buf.splice(buf.uint32())
409 for i in range(buf.uint16()):
410 estart = buf.uint16()
414 if not (ctp == 0 or self.checkcp(ctp, classref)):
415 raise binfmt.fmterror("invalid exception-catch reference")
416 ret.exctab.append((estart, eend, ehnd, ctp))
418 for i in range(nattr):
419 nm, data = self.loadattr(buf)
421 if pnm == "LineNumberTable":
423 for o in range(data.uint16()):
426 lintab.append((pc, ln))
428 elif pnm in ("LocalVariableTable", "LocalVariableTypeTable"):
430 for o in range(data.uint16()):
431 start = data.uint16()
434 descr = data.uint16()
436 if not self.checkcp(nm, str):
437 raise binfmt.fmterror("invalid local variable name reference")
438 if not self.checkcp(descr, str):
439 raise binfmt.fmterror("invalid local variable descriptor reference")
440 locals.append(localdef(start, start + ln, nm, descr, reg))
441 if nm == "LocalVariableTypeTable":
446 ret.attrs.append((nm, data.splice()))
449 def savecode(self, buf, code):
450 buf.uint16(code.maxstack).uint16(code.maxlocals)
451 buf.uint32(len(code.code)).extend(code.code)
452 buf.uint16(len(code.exctab))
453 for estart, eend, ehnd, ctp in code.exctab:
454 buf.uint16(estart).uint16(eend).uint16(ehnd).uint16(ctp)
455 attrs = list(code.attrs)
457 if code.lintab is not None:
459 data.uint16(len(code.lintab))
460 for pc, ln in code.lintab:
461 data.uint16(pc).uint16(ln)
462 attrs.append((self.intern("LineNumberTable"), data))
463 def savelocals(ltab):
465 data.uint16(len(ltab))
467 data.uint16(local.start).uint16(local.end - local.start).uint16(local.nm).uint16(local.descr).uint16(local.reg)
469 if code.locals is not None:
470 attrs.append((self.intern("LocalVariableTable"), savelocals(code.locals)))
471 if code.tlocals is not None:
472 attrs.append((self.intern("LocalVariableTypeTable"), savelocals(code.tlocals)))
473 self.saveattrs(buf, attrs)
475 def loadmethod(self, buf):
478 if not self.checkcp(nm, str):
479 raise binfmt.fmterror("invalid field name reference")
481 if not self.checkcp(descr, str):
482 raise binfmt.fmterror("invalid field descriptor reference")
483 ret = method(acc, nm, descr)
485 for i in range(nattr):
486 nm, data = self.loadattr(buf)
489 ret.code = self.loadcode(data)
490 elif pnm == "Exceptions":
491 for o in range(data.uint16()):
493 if not self.checkcp(eref, classref):
494 raise binfmt.fmterror("invalid exception reference")
495 ret.throws.append(eref)
496 elif pnm == "Synthetic":
498 elif pnm == "Signature":
499 ret.sig = data.uint16()
500 elif pnm == "Deprecated":
501 ret.deprecated = True
502 elif pnm == "RuntimeVisibleAnnotations":
503 for o in range(data.uint16()):
504 ret.rtann.append(self.loadannotation(data))
505 elif pnm == "RuntimeInvisibleAnnotations":
506 for o in range(data.uint16()):
507 ret.cpann.append(self.loadannotation(data))
508 elif pnm == "RuntimeVisibleParameterAnnotations":
510 for o in range(data.uint8()):
512 for u in range(data.uint16()):
513 abuf.append(self.loadannotation(data))
514 ret.prtann.append(abuf)
515 elif pnm == "RuntimeInvisibleParameterAnnotations":
517 for o in range(data.uint8()):
519 for u in range(data.uint16()):
520 abuf.append(self.loadannotation(data))
521 ret.pcpann.append(abuf)
522 elif pnm == "AnnotationDefault":
523 ret.anndef = self.loadannval(data)
525 ret.attrs.append((nm, data.splice()))
528 def savemethod(self, buf, method):
529 buf.uint16(method.acc)
530 buf.uint16(method.nm).uint16(method.descr)
531 attrs = list(method.attrs)
535 self.savecode(data, method.code)
536 attrs.append((self.intern("Code"), data))
537 if len(method.throws) > 0:
539 data.uint16(len(method.throws))
540 for eref in method.throws: data.uint16(eref)
541 attrs.append((self.intern("Exceptions"), data))
543 attrs.append((self.intern("Synthetic"), b""))
544 if method.sig is not None:
545 attrs.append((self.intern("Signature"), enc().uint16(method.sig)))
546 if method.deprecated:
547 attrs.append((self.intern("Deprecated"), b""))
548 if len(method.rtann) > 0:
550 data.uint16(len(method.rtann))
551 for ann in method.rtann: self.saveannotation(data, ann)
552 attrs.append((self.intern("RuntimeVisibleAnnotations"), data))
553 if len(method.cpann) > 0:
555 data.uint16(len(method.cpann))
556 for ann in method.cpann: self.saveannotation(data, ann)
557 attrs.append((self.intern("RuntimeInvisibleAnnotations"), data))
558 if method.prtann is not None:
560 data.uint8(len(method.prtann))
561 for par in method.prtann:
563 for ann in par: self.saveannotation(data, ann)
564 attrs.append((self.intern("RuntimeVisibleParameterAnnotations"), data))
565 if method.pcpann is not None:
567 data.uint8(len(method.pcpann))
568 for par in method.pcpann:
570 for ann in par: self.saveannotation(data, ann)
571 attrs.append((self.intern("RuntimeInvisibleParameterAnnotations"), data))
572 if method.anndef is not None:
574 self.saveannval(data, method.anndef)
575 attrs.append((self.intern("AnnotationDefault"), data))
576 self.saveattrs(buf, attrs)
580 buf = binfmt.decstream(fp)
581 if buf.uint32() != cls.MAGIC:
582 raise binfmt.fmterror("invalid magic number")
583 minor, major = buf.uint16(), buf.uint16()
584 self = cls(version(major, minor))
588 raise binfmt.fmterror("invalid constant-pool length")
590 while len(self.cp) < cplen:
591 loaded, dbl = self.loadconstant(buf)
592 self.cp.append(loaded)
596 self.acc = buf.uint16()
597 self.this = buf.uint16()
598 self.super = buf.uint16()
599 if not self.checkcp(self.this, classref):
600 raise binfmt.fmterror("invalid class name reference")
601 if not self.checkcp(self.super, classref):
602 raise binfmt.fmterror("invalid super-class reference")
604 while len(self.ifaces) < iflen:
606 if not self.checkcp(iref, classref):
607 raise binfmt.fmterror("invalid interface reference")
608 self.ifaces.append(iref)
610 nfields = buf.uint16()
611 while len(self.fields) < nfields:
612 self.fields.append(self.loadfield(buf))
613 nmethods = buf.uint16()
614 while len(self.methods) < nmethods:
615 self.methods.append(self.loadmethod(buf))
617 nattrs = buf.uint16()
618 for i in range(nattrs):
619 nm, data = self.loadattr(buf)
621 if pnm == "SourceFile":
622 self.srcfile = data.uint16()
623 elif pnm == "Signature":
624 self.sig = data.uint16()
625 elif pnm == "Synthetic":
627 elif pnm == "Deprecated":
628 self.deprecated = True
629 elif pnm == "InnerClasses":
630 for o in range(data.uint16()):
632 outer = data.uint16()
635 if not self.checkcp(cref, classref):
636 raise binfmt.fmterror("invalid inner-class reference")
637 if not (outer == 0 or self.checkcp(outer, classref)):
638 raise binfmt.fmterror("invalid inner-class outer reference")
639 if not (cnm == 0 or self.checkcp(cnm, str)):
640 raise binfmt.fmterror("invalid inner-class name reference")
641 self.innerclasses.append(innerclass(cref, outer, cnm, acc))
642 elif pnm == "EnclosingMethod":
643 self.enclosingmethod = (data.uint16(), data.uint16())
644 if not self.checkcp(self.enclosingmethod[0], classref):
645 raise binfmt.fmterror("invalid enclosing-method class reference")
646 if not (self.enclosingmethod[1] == 0 or self.checkcp(self.enclosingmethod[1], sig)):
647 raise binfmt.fmterror("invalid enclosing-method method reference")
648 elif pnm == "RuntimeVisibleAnnotations":
649 for o in range(data.uint16()):
650 self.rtann.append(self.loadannotation(data))
651 elif pnm == "RuntimeInvisibleAnnotations":
652 for o in range(data.uint16()):
653 self.cpann.append(self.loadannotation(data))
655 self.attrs.append((nm, data.splice()))
659 def _save(self, buf):
660 buf.uint32(self.MAGIC)
661 buf.uint16(self.ver.minor).uint16(self.ver.major)
663 buf.uint16(len(self.cp) + 1)
664 for const in self.cp:
665 if const is not None:
666 self.saveconstant(buf, const)
669 buf.uint16(self.this).uint16(self.super)
670 buf.uint16(len(self.ifaces))
671 for iref in self.ifaces: buf.uint16(iref)
673 buf.uint16(len(self.fields))
674 for field in self.fields:
675 self.savefield(buf, field)
677 buf.uint16(len(self.methods))
678 for method in self.methods:
679 self.savemethod(buf, method)
682 attrs = list(self.attrs)
683 if self.srcfile is not None:
684 attrs.append((self.intern("SourceFile"), enc().uint16(self.srcfile)))
686 attrs.append((self.intern("Synthetic"), b""))
688 attrs.append((self.intern("Deprecated"), b""))
689 if self.sig is not None:
690 attrs.append((self.intern("Signature"), enc().uint16(self.sig)))
691 if len(self.innerclasses) > 0:
693 data.uint16(len(self.innerclasses))
694 for inner in self.innerclasses: data.uint16(inner.cls).uint16(inner.outer).uint16(inner.nm).uint16(inner.acc)
695 attrs.append((self.intern("InnerClasses"), data))
696 if self.enclosingmethod is not None:
697 attrs.append((self.intern("EnclosingMethod", enc().uint16(self.enclosingmethod[0]).uint16(self.enclosingmethod[1]))))
698 if len(self.rtann) > 0:
700 data.uint16(len(self.rtann))
701 for ann in self.rtann: self.saveannotation(data, ann)
702 attrs.append((self.intern("RuntimeVisibleAnnotations"), data))
703 if len(self.cpann) > 0:
705 data.uint16(len(self.cpann))
706 for ann in self.cpann: self.saveannotation(data, ann)
707 attrs.append((self.intern("RuntimeInvisibleAnnotations"), data))
708 self.saveattrs(buf, attrs)
711 return self._save(binfmt.encstream(fp))
714 def fromfile(cls, fn):
715 with open(fn, "rb") as fp:
718 def tofile(self, fn):
719 with open(fn, "wb") as fp: