Handle the invokedynamic-related constant-pool entries.
[pycfml.git] / classfile / file.py
CommitLineData
964561d6
FT
1import collections
2from . import binfmt
3
4ACC_PUBLIC = 0x0001
5ACC_PRIVATE = 0x0002
6ACC_PROTECTED = 0x0004
7ACC_STATIC = 0x0008
8ACC_FINAL = 0x0010
9ACC_SUPER = 0x0020
10ACC_SYNCHRONIZED = 0x0020
11ACC_VOLATILE = 0x0040
12ACC_BRIDGE = 0x0040
13ACC_TRANSIENT = 0x0080
14ACC_VARARGS = 0x0080
15ACC_NATIVE = 0x0100
16ACC_INTERFACE = 0x0200
17ACC_ABSTRACT = 0x0400
18ACC_STRICT = 0x0800
19ACC_SYNTHETIC = 0x1000
20ACC_ANNOTATION = 0x2000
21ACC_ENUM = 0x4000
22
23CONSTANT_Class = 7
24CONSTANT_Fieldref = 9
25CONSTANT_Methodref = 10
26CONSTANT_InterfaceMethodref = 11
27CONSTANT_String = 8
28CONSTANT_Integer = 3
29CONSTANT_Float = 4
30CONSTANT_Long = 5
31CONSTANT_Double = 6
32CONSTANT_NameAndType = 12
33CONSTANT_Utf8 = 1
34CONSTANT_MethodHandle = 15
35CONSTANT_MethodType = 16
36CONSTANT_InvokeDynamic = 18
37
38version = collections.namedtuple("version", ["major", "minor"])
39version.__eq__ = lambda s, o: s.major == o.major and s.minor == o.minor
40version.__ne__ = lambda s, o: s.major != o.major or s.minor != o.minor
41version.__lt__ = lambda s, o: (s.major < o.major) or (s.major == o.major and s.minor < o.minor)
42version.__gt__ = lambda s, o: (s.major > o.major) or (s.major == o.major and s.minor > o.minor)
43version.__le__ = lambda s, o: (s.major < o.major) or (s.major == o.major and s.minor <= o.minor)
44version.__ge__ = lambda s, o: (s.major > o.major) or (s.major == o.major and s.minor >= o.minor)
45version.J5 = version(49, 0)
46version.J6 = version(50, 0)
47version.J7 = version(51, 0)
48version.J8 = version(52, 0)
49
50class constint(object):
51 def __init__(self, val):
52 self.val = val
53 def __hash__(self):
54 return hash(constint) + self.val
55 def __eq__(s, o):
56 return isinstance(o, constint) and o.val == s.val
57class constfloat(object):
58 def __init__(self, val):
59 self.val = val
60 def __hash__(self):
61 return hash(constfloat) + self.val
62 def __eq__(s, o):
63 return isinstance(o, constfloat) and o.val == s.val
64class constlong(object):
65 def __init__(self, val):
66 self.val = val
67 def __hash__(self):
68 return hash(constlong) + self.val
69 def __eq__(s, o):
70 return isinstance(o, constlong) and o.val == s.val
71class constdouble(object):
72 def __init__(self, val):
73 self.val = val
74 def __hash__(self):
75 return hash(constdouble) + self.val
76 def __eq__(s, o):
77 return isinstance(o, constdouble) and o.val == s.val
78
79class conststr(object):
80 def __init__(self, idx):
81 self.idx = idx
82 def __hash__(self):
83 return hash(conststr) + self.idx
84 def __eq__(s, o):
85 return isinstance(o, conststr) and o.idx == s.idx
86
87class classref(object):
88 def __init__(self, nm):
89 self.nm = nm
90 def __hash__(self):
91 return hash(classref) + self.nm
92 def __eq__(s, o):
93 return isinstance(o, classref) and o.nm == s.nm
94
95class sig(object):
96 def __init__(self, nm, tp):
97 self.nm = nm
98 self.tp = tp
99 def __hash__(self):
100 return hash(sig) + self.nm * 31 + self.tp
101 def __eq__(s, o):
102 return isinstance(o, sig) and o.nm == s.nm and o.tp == s.tp
103
188fa298
FT
104class methodhandle(object):
105 def __init__(self, kind, ref):
106 self.kind = kind
107 self.ref = ref
108 def __hash__(self):
109 return hash(methodhandle) + self.kind * 31 + self.ref
110 def __eq__(s, o):
111 return isinstance(o, methodhandle) and o.kind == s.kind and o.ref == s.ref
112
113class methodtype(object):
114 def __init__(self, desc):
115 self.desc = desc
116 def __hash__(self):
117 return hash(methodhandle) + self.desc
118 def __eq__(s, o):
119 return isinstance(o, methodtype) and o.desc == s.desc
120
121class callsite(object):
122 def __init__(self, boot, sig):
123 self.boot = boot
124 self.sig = sig
125 def __hash__(self):
126 return hash(callsite) + self.boot * 31 + self.sig
127 def __eq__(s, o):
128 return isinstance(o, callsite) and o.boot == s.boot and o.sig == s.sig
129
964561d6
FT
130class fieldref(object):
131 def __init__(self, cls, sig):
132 self.cls = cls
133 self.sig = sig
134 def __hash__(self):
135 return hash(fieldref) + self.cls * 31 + self.sig
136 def __eq__(s, o):
137 return isinstance(o, fieldref) and o.cls == s.cls and o.sig == s.sig
138
139class methodref(object):
140 def __init__(self, cls, sig):
141 self.cls = cls
142 self.sig = sig
143 def __hash__(self):
144 return hash(methodref) + self.cls * 31 + self.sig
145 def __eq__(s, o):
146 return isinstance(o, methodref) and o.cls == s.cls and o.sig == s.sig
147
148class imethodref(object):
149 def __init__(self, cls, sig):
150 self.cls = cls
151 self.sig = sig
152 def __hash__(self):
153 return hash(imethodref) + self.cls * 31 + self.sig
154 def __eq__(s, o):
155 return isinstance(o, imethodref) and o.cls == s.cls and o.sig == s.sig
156
157class field(object):
158 def __init__(self, acc, nm, descr):
159 self.acc = acc
160 self.nm = nm
161 self.descr = descr
162 self.const = None
163 self.syn = False
164 self.sig = None
165 self.deprecated = False
166 self.rtann = []
167 self.cpann = []
168 self.attrs = []
169
170class localdef(object):
171 def __init__(self, start, end, nm, descr, reg):
172 self.start = start
173 self.end = end
174 self.nm = nm
175 self.descr = descr
176 self.reg = reg
177
178class code(object):
179 def __init__(self):
180 self.maxstack = 0
181 self.maxlocals = 0
182 self.code = b""
183 self.exctab = []
184 self.lintab = None
185 self.locals = None
186 self.tlocals = None
187 self.attrs = []
188
189class method(object):
190 def __init__(self, acc, nm, descr):
191 self.acc = acc
192 self.nm = nm
193 self.descr = descr
194 self.code = None
195 self.throws = []
196 self.syn = False
197 self.sig = None
198 self.deprecated = False
199 self.rtann = []
200 self.cpann = []
201 self.prtann = None
202 self.pcpann = None
203 self.anndef = None
204 self.attrs = []
205
206class annotation(object):
207 def __init__(self, tp):
208 self.tp = tp
209 self.vals = {}
210
211class innerclass(object):
212 def __init__(self, cls, outer, nm, acc):
213 self.cls = cls
214 self.outer = outer
215 self.nm = nm
216 self.acc = acc
217
218class classfile(object):
219 MAGIC = 0xCAFEBABE
220
221 def __init__(self, ver, access=None):
222 self.ver = ver
223 self.cp = []
224 self.access = access
225 self.this = None
226 self.super = None
227 self.ifaces = []
228 self.fields = []
229 self.methods = []
230 self.srcfile = None
231 self.innerclasses = []
232 self.enclosingmethod = None
233 self.syn = False
234 self.sig = None
235 self.deprecated = False
236 self.rtann = []
237 self.cpann = []
238 self.attrs = []
239
240 def loadconstant(self, buf):
241 t = buf.uint8()
242 if t == CONSTANT_Utf8:
243 return binfmt.mutf8dec(buf.splice(buf.uint16())), False
244 elif t == CONSTANT_Class:
245 return classref(buf.uint16()), False
246 elif t == CONSTANT_String:
247 return conststr(buf.uint16()), False
248 elif t == CONSTANT_Integer:
249 return constint(buf.int32()), False
250 elif t == CONSTANT_Float:
251 return constfloat(buf.float32()), False
252 elif t == CONSTANT_Long:
253 return constlong(buf.int64()), True
254 elif t == CONSTANT_Double:
255 return constdouble(buf.float64()), True
256 elif t == CONSTANT_Fieldref:
257 return fieldref(buf.uint16(), buf.uint16()), False
258 elif t == CONSTANT_Methodref:
259 return methodref(buf.uint16(), buf.uint16()), False
260 elif t == CONSTANT_InterfaceMethodref:
261 return imethodref(buf.uint16(), buf.uint16()), False
262 elif t == CONSTANT_NameAndType:
263 return sig(buf.uint16(), buf.uint16()), False
188fa298
FT
264 elif t == CONSTANT_MethodHandle:
265 return methodhandle(buf.uint8(), buf.uint16()), False
266 elif t == CONSTANT_MethodType:
267 return methodtype(buf.uint16()), False
268 elif t == CONSTANT_InvokeDynamic:
269 return callsite(buf.uint16(), buf.uint16()), False
964561d6
FT
270 else:
271 raise binfmt.fmterror("unknown constant tag: " + str(t))
272
273 def saveconstant(self, buf, const):
274 if isinstance(const, str):
31eb7672
FT
275 enc = binfmt.mutf8enc(const)
276 buf.uint8(CONSTANT_Utf8).uint16(len(enc)).extend(enc)
964561d6
FT
277 elif isinstance(const, classref):
278 buf.uint8(CONSTANT_Class).uint16(const.nm)
279 elif isinstance(const, conststr):
280 buf.uint8(CONSTANT_String).uint16(const.idx)
281 elif isinstance(const, constint):
282 buf.uint8(CONSTANT_Integer).int32(const.val)
283 elif isinstance(const, constfloat):
284 buf.uint8(CONSTANT_Float).float32(const.val)
285 elif isinstance(const, constlong):
286 buf.uint8(CONSTANT_Long).int64(const.val)
287 elif isinstance(const, constdouble):
288 buf.uint8(CONSTANT_Double).float64(const.val)
289 elif isinstance(const, fieldref):
290 buf.uint8(CONSTANT_Fieldref).uint16(const.cls).uint16(const.sig)
291 elif isinstance(const, methodref):
292 buf.uint8(CONSTANT_Methodref).uint16(const.cls).uint16(const.sig)
293 elif isinstance(const, imethodref):
294 buf.uint8(CONSTANT_InterfaceMethodref).uint16(const.cls).uint16(const.sig)
295 elif isinstance(const, sig):
296 buf.uint8(CONSTANT_NameAndType).uint16(const.nm).uint16(const.tp)
188fa298
FT
297 elif isinstance(const, methodhandle):
298 buf.uint8(CONSTANT_MethodHandle).uint8(const.kind).uint16(const.ref)
299 elif isinstance(const, methodtype):
300 buf.uint8(CONSTANT_MethodType).uint16(const.desc)
301 elif isinstance(const, callsite):
302 buf.uint8(CONSTANT_InvokeDynamic).uint16(const.boot).uint16(const.sig)
964561d6
FT
303 else:
304 raise Exception("unexpected object type in constant pool: " + const)
305
306 def checkcp(self, idx, tp):
307 return 0 <= idx < len(self.cp) and isinstance(self.cp[idx], tp)
308
309 def intern(self, const, new=Exception):
310 for i, cur in enumerate(self.cp):
311 if cur == const:
312 return i
313 if new == Exception:
314 raise Exception("constant not present in pool: " + const)
315 if new:
316 self.cp.append(const)
317 return len(self.cp) - 1
318 else:
319 return None
320
321 def loadattr(self, buf):
322 nm = buf.uint16()
323 if not self.checkcp(nm, str):
324 raise binfmt.fmterror("invalid attribute name reference")
325 return nm, binfmt.decbuf(buf.splice(buf.uint32()))
326
327 def saveattrs(self, buf, attrs):
328 buf.uint16(len(attrs))
329 for nm, data in attrs:
330 buf.uint16(nm).uint32(len(data)).extend(data)
331
332 def loadannval(self, buf):
333 t = chr(buf.uint8())
334 if t in "BCDFIJSZs":
335 return buf.uint16()
336 elif t == "e":
337 return (buf.uint16(), buf.uint16())
338 elif t == "c":
339 return classref(buf.uint16()) # XXX, but meh
340 elif t == "@":
341 return loadannotation(buf)
342 elif t == "[":
343 return [self.loadannval(buf) for i in range(buf.uint16())]
344 else:
345 raise binfmt.fmterror("unknown annotation-value type tag: " + t)
346
347 def saveannval(self, buf, val):
348 if isinstance(val, int):
349 const = self.cp[val]
350 if isinstance(const, str):
351 buf.uint8(ord('s')).uint16(val)
352 else:
353 raise Exception("unexpected constant type in annotation value: " + const)
354 elif isinstance(val, tuple) and len(val) == 2:
355 buf.uint8(ord('e')).uint16(val[0]).uint16(val[1])
356 elif isinstance(val, classref):
357 buf.uint8(ord('c')).uint16(val.nm)
358 elif isinstance(val, annotation):
359 buf.uint8(ord('@'))
360 saveannotation(buf, val)
361 elif isinstance(val, list):
362 buf.uint8(ord('['))
363 for sval in val: self.saveannval(buf, sval)
364 else:
365 raise Exception("unexpected annotation value type: " + val)
366
367 def loadannotation(self, buf):
368 tp = buf.uint16()
369 if not self.checkcp(tp, str):
370 raise binfmt.fmterror("invalid annotation type reference")
371 ret = annotation(tp)
372 nval = buf.uint16()
373 for i in range(nval):
374 nm = buf.uint16()
375 if not self.checkcp(nm, str):
376 raise binfmt.fmterror("invalid annotation-value name reference")
377 ret.vals[nm] = self.loadannval(buf)
378 return ret
379
380 def saveannotation(self, buf, ann):
381 buf.uint16(ann.tp)
382 buf.uint16(len(ann.vals))
383 for key, val in ann.vals.items():
384 buf.uint16(key)
385 self.saveannval(buf, val)
386
387 def loadfield(self, buf):
388 acc = buf.uint16()
389 nm = buf.uint16()
390 if not self.checkcp(nm, str):
391 raise binfmt.fmterror("invalid field name reference")
392 descr = buf.uint16()
393 if not self.checkcp(descr, str):
394 raise binfmt.fmterror("invalid field descriptor reference")
395 ret = field(acc, nm, descr)
396 nattr = buf.uint16()
397 for i in range(nattr):
398 nm, data = self.loadattr(buf)
399 pnm = self.cp[nm]
400 if pnm == "ConstantValue":
401 ret.const = data.uint16()
402 elif pnm == "Synthetic":
403 ret.syn = True
404 elif pnm == "Signature":
405 ret.sig = data.uint16()
406 elif pnm == "Deprecated":
407 ret.deprecated = True
408 elif pnm == "RuntimeVisibleAnnotations":
409 for o in range(data.uint16()):
410 ret.rtann.append(self.loadannotation(data))
411 elif pnm == "RuntimeInvisibleAnnotations":
412 for o in range(data.uint16()):
413 ret.cpann.append(self.loadannotation(data))
414 else:
415 ret.attrs.append((nm, data.splice()))
416 return ret
417
418 def savefield(self, buf, field):
419 buf.uint16(field.acc)
420 buf.uint16(field.nm).uint16(field.descr)
421 attrs = list(field.attrs)
422 enc = binfmt.encbuf
423 if field.const is not None:
424 attrs.append((self.intern("ConstantValue"), enc().uint16(field.const)))
425 if field.syn:
426 attrs.append((self.intern("Synthetic"), b""))
427 if field.sig is not None:
428 attrs.append((self.intern("Signature"), enc().uint16(field.sig)))
429 if field.deprecated:
430 attrs.append((self.intern("Deprecated"), b""))
431 if len(field.rtann) > 0:
432 data = enc()
433 data.uint16(len(field.rtann))
434 for ann in field.rtann: self.saveannotation(data, ann)
435 attrs.append((self.intern("RuntimeVisibleAnnotations"), data))
436 if len(field.cpann) > 0:
437 data = enc()
438 data.uint16(len(field.cpann))
439 for ann in field.cpann: self.saveannotation(data, ann)
440 attrs.append((self.intern("RuntimeInvisibleAnnotations"), data))
441 self.saveattrs(buf, attrs)
442
443 def loadcode(self, buf):
444 ret = code()
445 ret.maxstack = buf.uint16()
446 ret.maxlocals = buf.uint16()
447 ret.code = buf.splice(buf.uint32())
448 for i in range(buf.uint16()):
449 estart = buf.uint16()
450 eend = buf.uint16()
451 ehnd = buf.uint16()
452 ctp = buf.uint16()
453 if not (ctp == 0 or self.checkcp(ctp, classref)):
454 raise binfmt.fmterror("invalid exception-catch reference")
455 ret.exctab.append((estart, eend, ehnd, ctp))
456 nattr = buf.uint16()
457 for i in range(nattr):
458 nm, data = self.loadattr(buf)
459 pnm = self.cp[nm]
460 if pnm == "LineNumberTable":
461 lintab = []
462 for o in range(data.uint16()):
463 pc = data.uint16()
464 ln = data.uint16()
465 lintab.append((pc, ln))
466 ret.lintab = lintab
467 elif pnm in ("LocalVariableTable", "LocalVariableTypeTable"):
468 locals = []
469 for o in range(data.uint16()):
470 start = data.uint16()
471 ln = data.uint16()
472 nm = data.uint16()
473 descr = data.uint16()
474 reg = data.uint16()
475 if not self.checkcp(nm, str):
476 raise binfmt.fmterror("invalid local variable name reference")
477 if not self.checkcp(descr, str):
478 raise binfmt.fmterror("invalid local variable descriptor reference")
479 locals.append(localdef(start, start + ln, nm, descr, reg))
480 if nm == "LocalVariableTypeTable":
481 ret.tlocals = locals
482 else:
483 ret.locals = locals
484 else:
485 ret.attrs.append((nm, data.splice()))
486 return ret
487
488 def savecode(self, buf, code):
489 buf.uint16(code.maxstack).uint16(code.maxlocals)
490 buf.uint32(len(code.code)).extend(code.code)
491 buf.uint16(len(code.exctab))
492 for estart, eend, ehnd, ctp in code.exctab:
493 buf.uint16(estart).uint16(eend).uint16(ehnd).uint16(ctp)
494 attrs = list(code.attrs)
495 enc = binfmt.encbuf
496 if code.lintab is not None:
497 data = enc()
498 data.uint16(len(code.lintab))
499 for pc, ln in code.lintab:
500 data.uint16(pc).uint16(ln)
501 attrs.append((self.intern("LineNumberTable"), data))
502 def savelocals(ltab):
503 data = enc()
504 data.uint16(len(ltab))
505 for local in ltab:
506 data.uint16(local.start).uint16(local.end - local.start).uint16(local.nm).uint16(local.descr).uint16(local.reg)
507 return data
508 if code.locals is not None:
509 attrs.append((self.intern("LocalVariableTable"), savelocals(code.locals)))
510 if code.tlocals is not None:
511 attrs.append((self.intern("LocalVariableTypeTable"), savelocals(code.tlocals)))
512 self.saveattrs(buf, attrs)
513
514 def loadmethod(self, buf):
515 acc = buf.uint16()
516 nm = buf.uint16()
517 if not self.checkcp(nm, str):
518 raise binfmt.fmterror("invalid field name reference")
519 descr = buf.uint16()
520 if not self.checkcp(descr, str):
521 raise binfmt.fmterror("invalid field descriptor reference")
522 ret = method(acc, nm, descr)
523 nattr = buf.uint16()
524 for i in range(nattr):
525 nm, data = self.loadattr(buf)
526 pnm = self.cp[nm]
527 if pnm == "Code":
528 ret.code = self.loadcode(data)
529 elif pnm == "Exceptions":
530 for o in range(data.uint16()):
531 eref = data.uint16()
532 if not self.checkcp(eref, classref):
533 raise binfmt.fmterror("invalid exception reference")
534 ret.throws.append(eref)
535 elif pnm == "Synthetic":
536 ret.syn = True
537 elif pnm == "Signature":
538 ret.sig = data.uint16()
539 elif pnm == "Deprecated":
540 ret.deprecated = True
541 elif pnm == "RuntimeVisibleAnnotations":
542 for o in range(data.uint16()):
543 ret.rtann.append(self.loadannotation(data))
544 elif pnm == "RuntimeInvisibleAnnotations":
545 for o in range(data.uint16()):
546 ret.cpann.append(self.loadannotation(data))
547 elif pnm == "RuntimeVisibleParameterAnnotations":
548 ret.prtann = []
549 for o in range(data.uint8()):
550 abuf = []
551 for u in range(data.uint16()):
552 abuf.append(self.loadannotation(data))
553 ret.prtann.append(abuf)
554 elif pnm == "RuntimeInvisibleParameterAnnotations":
555 ret.pcpann = []
556 for o in range(data.uint8()):
557 abuf = []
558 for u in range(data.uint16()):
559 abuf.append(self.loadannotation(data))
560 ret.pcpann.append(abuf)
561 elif pnm == "AnnotationDefault":
562 ret.anndef = self.loadannval(data)
563 else:
564 ret.attrs.append((nm, data.splice()))
565 return ret
566
567 def savemethod(self, buf, method):
568 buf.uint16(method.acc)
569 buf.uint16(method.nm).uint16(method.descr)
570 attrs = list(method.attrs)
571 enc = binfmt.encbuf
572 if method.code:
573 data = enc()
574 self.savecode(data, method.code)
575 attrs.append((self.intern("Code"), data))
576 if len(method.throws) > 0:
577 data = enc()
578 data.uint16(len(method.throws))
579 for eref in method.throws: data.uint16(eref)
580 attrs.append((self.intern("Exceptions"), data))
581 if method.syn:
582 attrs.append((self.intern("Synthetic"), b""))
583 if method.sig is not None:
584 attrs.append((self.intern("Signature"), enc().uint16(method.sig)))
585 if method.deprecated:
586 attrs.append((self.intern("Deprecated"), b""))
587 if len(method.rtann) > 0:
588 data = enc()
589 data.uint16(len(method.rtann))
590 for ann in method.rtann: self.saveannotation(data, ann)
591 attrs.append((self.intern("RuntimeVisibleAnnotations"), data))
592 if len(method.cpann) > 0:
593 data = enc()
594 data.uint16(len(method.cpann))
595 for ann in method.cpann: self.saveannotation(data, ann)
596 attrs.append((self.intern("RuntimeInvisibleAnnotations"), data))
597 if method.prtann is not None:
598 data = enc()
599 data.uint8(len(method.prtann))
600 for par in method.prtann:
601 buf.uint16(len(par))
602 for ann in par: self.saveannotation(data, ann)
603 attrs.append((self.intern("RuntimeVisibleParameterAnnotations"), data))
604 if method.pcpann is not None:
605 data = enc()
606 data.uint8(len(method.pcpann))
607 for par in method.pcpann:
608 buf.uint16(len(par))
609 for ann in par: self.saveannotation(data, ann)
610 attrs.append((self.intern("RuntimeInvisibleParameterAnnotations"), data))
611 if method.anndef is not None:
612 data = enc()
613 self.saveannval(data, method.anndef)
614 attrs.append((self.intern("AnnotationDefault"), data))
615 self.saveattrs(buf, attrs)
616
617 @classmethod
618 def load(cls, fp):
619 buf = binfmt.decstream(fp)
620 if buf.uint32() != cls.MAGIC:
621 raise binfmt.fmterror("invalid magic number")
622 minor, major = buf.uint16(), buf.uint16()
623 self = cls(version(major, minor))
624
625 cplen = buf.uint16()
626 if cplen < 1:
627 raise binfmt.fmterror("invalid constant-pool length")
628 self.cp.append(None)
629 while len(self.cp) < cplen:
630 loaded, dbl = self.loadconstant(buf)
631 self.cp.append(loaded)
632 if dbl:
633 self.cp.append(None)
634
635 self.acc = buf.uint16()
636 self.this = buf.uint16()
637 self.super = buf.uint16()
638 if not self.checkcp(self.this, classref):
639 raise binfmt.fmterror("invalid class name reference")
640 if not self.checkcp(self.super, classref):
641 raise binfmt.fmterror("invalid super-class reference")
642 iflen = buf.uint16()
643 while len(self.ifaces) < iflen:
644 iref = buf.uint16()
645 if not self.checkcp(iref, classref):
646 raise binfmt.fmterror("invalid interface reference")
647 self.ifaces.append(iref)
648
649 nfields = buf.uint16()
650 while len(self.fields) < nfields:
651 self.fields.append(self.loadfield(buf))
652 nmethods = buf.uint16()
653 while len(self.methods) < nmethods:
654 self.methods.append(self.loadmethod(buf))
655
656 nattrs = buf.uint16()
657 for i in range(nattrs):
658 nm, data = self.loadattr(buf)
659 pnm = self.cp[nm]
660 if pnm == "SourceFile":
661 self.srcfile = data.uint16()
662 elif pnm == "Signature":
663 self.sig = data.uint16()
664 elif pnm == "Synthetic":
665 self.syn = True
666 elif pnm == "Deprecated":
667 self.deprecated = True
668 elif pnm == "InnerClasses":
669 for o in range(data.uint16()):
670 cref = data.uint16()
671 outer = data.uint16()
672 cnm = data.uint16()
673 acc = data.uint16()
674 if not self.checkcp(cref, classref):
675 raise binfmt.fmterror("invalid inner-class reference")
676 if not (outer == 0 or self.checkcp(outer, classref)):
677 raise binfmt.fmterror("invalid inner-class outer reference")
678 if not (cnm == 0 or self.checkcp(cnm, str)):
679 raise binfmt.fmterror("invalid inner-class name reference")
680 self.innerclasses.append(innerclass(cref, outer, cnm, acc))
681 elif pnm == "EnclosingMethod":
682 self.enclosingmethod = (data.uint16(), data.uint16())
683 if not self.checkcp(self.enclosingmethod[0], classref):
684 raise binfmt.fmterror("invalid enclosing-method class reference")
685 if not (self.enclosingmethod[1] == 0 or self.checkcp(self.enclosingmethod[1], sig)):
686 raise binfmt.fmterror("invalid enclosing-method method reference")
687 elif pnm == "RuntimeVisibleAnnotations":
688 for o in range(data.uint16()):
689 self.rtann.append(self.loadannotation(data))
690 elif pnm == "RuntimeInvisibleAnnotations":
691 for o in range(data.uint16()):
692 self.cpann.append(self.loadannotation(data))
693 else:
694 self.attrs.append((nm, data.splice()))
695
696 return self
697
698 def _save(self, buf):
699 buf.uint32(self.MAGIC)
700 buf.uint16(self.ver.minor).uint16(self.ver.major)
701
31eb7672 702 buf.uint16(len(self.cp))
964561d6
FT
703 for const in self.cp:
704 if const is not None:
705 self.saveconstant(buf, const)
706
707 buf.uint16(self.acc)
708 buf.uint16(self.this).uint16(self.super)
709 buf.uint16(len(self.ifaces))
710 for iref in self.ifaces: buf.uint16(iref)
711
712 buf.uint16(len(self.fields))
713 for field in self.fields:
714 self.savefield(buf, field)
715
716 buf.uint16(len(self.methods))
717 for method in self.methods:
718 self.savemethod(buf, method)
719
720 enc = binfmt.encbuf
721 attrs = list(self.attrs)
722 if self.srcfile is not None:
723 attrs.append((self.intern("SourceFile"), enc().uint16(self.srcfile)))
724 if self.syn:
725 attrs.append((self.intern("Synthetic"), b""))
726 if self.deprecated:
727 attrs.append((self.intern("Deprecated"), b""))
728 if self.sig is not None:
729 attrs.append((self.intern("Signature"), enc().uint16(self.sig)))
730 if len(self.innerclasses) > 0:
731 data = enc()
732 data.uint16(len(self.innerclasses))
733 for inner in self.innerclasses: data.uint16(inner.cls).uint16(inner.outer).uint16(inner.nm).uint16(inner.acc)
734 attrs.append((self.intern("InnerClasses"), data))
735 if self.enclosingmethod is not None:
31eb7672 736 attrs.append((self.intern("EnclosingMethod"), enc().uint16(self.enclosingmethod[0]).uint16(self.enclosingmethod[1])))
964561d6
FT
737 if len(self.rtann) > 0:
738 data = enc()
739 data.uint16(len(self.rtann))
740 for ann in self.rtann: self.saveannotation(data, ann)
741 attrs.append((self.intern("RuntimeVisibleAnnotations"), data))
742 if len(self.cpann) > 0:
743 data = enc()
744 data.uint16(len(self.cpann))
745 for ann in self.cpann: self.saveannotation(data, ann)
746 attrs.append((self.intern("RuntimeInvisibleAnnotations"), data))
747 self.saveattrs(buf, attrs)
748
749 def save(self, fp):
750 return self._save(binfmt.encstream(fp))
751
752 @classmethod
753 def fromfile(cls, fn):
754 with open(fn, "rb") as fp:
755 return cls.load(fp)
756
757 def tofile(self, fn):
758 with open(fn, "wb") as fp:
759 return self.save(fp)