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