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): | |
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) | |
264 | else: | |
265 | raise Exception("unexpected object type in constant pool: " + const) | |
266 | ||
267 | def checkcp(self, idx, tp): | |
268 | return 0 <= idx < len(self.cp) and isinstance(self.cp[idx], tp) | |
269 | ||
270 | def intern(self, const, new=Exception): | |
271 | for i, cur in enumerate(self.cp): | |
272 | if cur == const: | |
273 | return i | |
274 | if new == Exception: | |
275 | raise Exception("constant not present in pool: " + const) | |
276 | if new: | |
277 | self.cp.append(const) | |
278 | return len(self.cp) - 1 | |
279 | else: | |
280 | return None | |
281 | ||
282 | def loadattr(self, buf): | |
283 | nm = buf.uint16() | |
284 | if not self.checkcp(nm, str): | |
285 | raise binfmt.fmterror("invalid attribute name reference") | |
286 | return nm, binfmt.decbuf(buf.splice(buf.uint32())) | |
287 | ||
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) | |
292 | ||
293 | def loadannval(self, buf): | |
294 | t = chr(buf.uint8()) | |
295 | if t in "BCDFIJSZs": | |
296 | return buf.uint16() | |
297 | elif t == "e": | |
298 | return (buf.uint16(), buf.uint16()) | |
299 | elif t == "c": | |
300 | return classref(buf.uint16()) # XXX, but meh | |
301 | elif t == "@": | |
302 | return loadannotation(buf) | |
303 | elif t == "[": | |
304 | return [self.loadannval(buf) for i in range(buf.uint16())] | |
305 | else: | |
306 | raise binfmt.fmterror("unknown annotation-value type tag: " + t) | |
307 | ||
308 | def saveannval(self, buf, val): | |
309 | if isinstance(val, int): | |
310 | const = self.cp[val] | |
311 | if isinstance(const, str): | |
312 | buf.uint8(ord('s')).uint16(val) | |
313 | else: | |
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): | |
320 | buf.uint8(ord('@')) | |
321 | saveannotation(buf, val) | |
322 | elif isinstance(val, list): | |
323 | buf.uint8(ord('[')) | |
324 | for sval in val: self.saveannval(buf, sval) | |
325 | else: | |
326 | raise Exception("unexpected annotation value type: " + val) | |
327 | ||
328 | def loadannotation(self, buf): | |
329 | tp = buf.uint16() | |
330 | if not self.checkcp(tp, str): | |
331 | raise binfmt.fmterror("invalid annotation type reference") | |
332 | ret = annotation(tp) | |
333 | nval = buf.uint16() | |
334 | for i in range(nval): | |
335 | nm = buf.uint16() | |
336 | if not self.checkcp(nm, str): | |
337 | raise binfmt.fmterror("invalid annotation-value name reference") | |
338 | ret.vals[nm] = self.loadannval(buf) | |
339 | return ret | |
340 | ||
341 | def saveannotation(self, buf, ann): | |
342 | buf.uint16(ann.tp) | |
343 | buf.uint16(len(ann.vals)) | |
344 | for key, val in ann.vals.items(): | |
345 | buf.uint16(key) | |
346 | self.saveannval(buf, val) | |
347 | ||
348 | def loadfield(self, buf): | |
349 | acc = buf.uint16() | |
350 | nm = buf.uint16() | |
351 | if not self.checkcp(nm, str): | |
352 | raise binfmt.fmterror("invalid field name reference") | |
353 | descr = buf.uint16() | |
354 | if not self.checkcp(descr, str): | |
355 | raise binfmt.fmterror("invalid field descriptor reference") | |
356 | ret = field(acc, nm, descr) | |
357 | nattr = buf.uint16() | |
358 | for i in range(nattr): | |
359 | nm, data = self.loadattr(buf) | |
360 | pnm = self.cp[nm] | |
361 | if pnm == "ConstantValue": | |
362 | ret.const = data.uint16() | |
363 | elif pnm == "Synthetic": | |
364 | ret.syn = True | |
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)) | |
375 | else: | |
376 | ret.attrs.append((nm, data.splice())) | |
377 | return ret | |
378 | ||
379 | def savefield(self, buf, field): | |
380 | buf.uint16(field.acc) | |
381 | buf.uint16(field.nm).uint16(field.descr) | |
382 | attrs = list(field.attrs) | |
383 | enc = binfmt.encbuf | |
384 | if field.const is not None: | |
385 | attrs.append((self.intern("ConstantValue"), enc().uint16(field.const))) | |
386 | if field.syn: | |
387 | attrs.append((self.intern("Synthetic"), b"")) | |
388 | if field.sig is not None: | |
389 | attrs.append((self.intern("Signature"), enc().uint16(field.sig))) | |
390 | if field.deprecated: | |
391 | attrs.append((self.intern("Deprecated"), b"")) | |
392 | if len(field.rtann) > 0: | |
393 | data = enc() | |
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: | |
398 | data = enc() | |
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) | |
403 | ||
404 | def loadcode(self, buf): | |
405 | ret = code() | |
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() | |
411 | eend = buf.uint16() | |
412 | ehnd = buf.uint16() | |
413 | ctp = 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)) | |
417 | nattr = buf.uint16() | |
418 | for i in range(nattr): | |
419 | nm, data = self.loadattr(buf) | |
420 | pnm = self.cp[nm] | |
421 | if pnm == "LineNumberTable": | |
422 | lintab = [] | |
423 | for o in range(data.uint16()): | |
424 | pc = data.uint16() | |
425 | ln = data.uint16() | |
426 | lintab.append((pc, ln)) | |
427 | ret.lintab = lintab | |
428 | elif pnm in ("LocalVariableTable", "LocalVariableTypeTable"): | |
429 | locals = [] | |
430 | for o in range(data.uint16()): | |
431 | start = data.uint16() | |
432 | ln = data.uint16() | |
433 | nm = data.uint16() | |
434 | descr = data.uint16() | |
435 | reg = 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": | |
442 | ret.tlocals = locals | |
443 | else: | |
444 | ret.locals = locals | |
445 | else: | |
446 | ret.attrs.append((nm, data.splice())) | |
447 | return ret | |
448 | ||
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) | |
456 | enc = binfmt.encbuf | |
457 | if code.lintab is not None: | |
458 | data = enc() | |
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): | |
464 | data = enc() | |
465 | data.uint16(len(ltab)) | |
466 | for local in ltab: | |
467 | data.uint16(local.start).uint16(local.end - local.start).uint16(local.nm).uint16(local.descr).uint16(local.reg) | |
468 | return data | |
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) | |
474 | ||
475 | def loadmethod(self, buf): | |
476 | acc = buf.uint16() | |
477 | nm = buf.uint16() | |
478 | if not self.checkcp(nm, str): | |
479 | raise binfmt.fmterror("invalid field name reference") | |
480 | descr = buf.uint16() | |
481 | if not self.checkcp(descr, str): | |
482 | raise binfmt.fmterror("invalid field descriptor reference") | |
483 | ret = method(acc, nm, descr) | |
484 | nattr = buf.uint16() | |
485 | for i in range(nattr): | |
486 | nm, data = self.loadattr(buf) | |
487 | pnm = self.cp[nm] | |
488 | if pnm == "Code": | |
489 | ret.code = self.loadcode(data) | |
490 | elif pnm == "Exceptions": | |
491 | for o in range(data.uint16()): | |
492 | eref = 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": | |
497 | ret.syn = True | |
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": | |
509 | ret.prtann = [] | |
510 | for o in range(data.uint8()): | |
511 | abuf = [] | |
512 | for u in range(data.uint16()): | |
513 | abuf.append(self.loadannotation(data)) | |
514 | ret.prtann.append(abuf) | |
515 | elif pnm == "RuntimeInvisibleParameterAnnotations": | |
516 | ret.pcpann = [] | |
517 | for o in range(data.uint8()): | |
518 | abuf = [] | |
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) | |
524 | else: | |
525 | ret.attrs.append((nm, data.splice())) | |
526 | return ret | |
527 | ||
528 | def savemethod(self, buf, method): | |
529 | buf.uint16(method.acc) | |
530 | buf.uint16(method.nm).uint16(method.descr) | |
531 | attrs = list(method.attrs) | |
532 | enc = binfmt.encbuf | |
533 | if method.code: | |
534 | data = enc() | |
535 | self.savecode(data, method.code) | |
536 | attrs.append((self.intern("Code"), data)) | |
537 | if len(method.throws) > 0: | |
538 | data = enc() | |
539 | data.uint16(len(method.throws)) | |
540 | for eref in method.throws: data.uint16(eref) | |
541 | attrs.append((self.intern("Exceptions"), data)) | |
542 | if method.syn: | |
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: | |
549 | data = enc() | |
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: | |
554 | data = enc() | |
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: | |
559 | data = enc() | |
560 | data.uint8(len(method.prtann)) | |
561 | for par in method.prtann: | |
562 | buf.uint16(len(par)) | |
563 | for ann in par: self.saveannotation(data, ann) | |
564 | attrs.append((self.intern("RuntimeVisibleParameterAnnotations"), data)) | |
565 | if method.pcpann is not None: | |
566 | data = enc() | |
567 | data.uint8(len(method.pcpann)) | |
568 | for par in method.pcpann: | |
569 | buf.uint16(len(par)) | |
570 | for ann in par: self.saveannotation(data, ann) | |
571 | attrs.append((self.intern("RuntimeInvisibleParameterAnnotations"), data)) | |
572 | if method.anndef is not None: | |
573 | data = enc() | |
574 | self.saveannval(data, method.anndef) | |
575 | attrs.append((self.intern("AnnotationDefault"), data)) | |
576 | self.saveattrs(buf, attrs) | |
577 | ||
578 | @classmethod | |
579 | def load(cls, fp): | |
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)) | |
585 | ||
586 | cplen = buf.uint16() | |
587 | if cplen < 1: | |
588 | raise binfmt.fmterror("invalid constant-pool length") | |
589 | self.cp.append(None) | |
590 | while len(self.cp) < cplen: | |
591 | loaded, dbl = self.loadconstant(buf) | |
592 | self.cp.append(loaded) | |
593 | if dbl: | |
594 | self.cp.append(None) | |
595 | ||
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") | |
603 | iflen = buf.uint16() | |
604 | while len(self.ifaces) < iflen: | |
605 | iref = buf.uint16() | |
606 | if not self.checkcp(iref, classref): | |
607 | raise binfmt.fmterror("invalid interface reference") | |
608 | self.ifaces.append(iref) | |
609 | ||
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)) | |
616 | ||
617 | nattrs = buf.uint16() | |
618 | for i in range(nattrs): | |
619 | nm, data = self.loadattr(buf) | |
620 | pnm = self.cp[nm] | |
621 | if pnm == "SourceFile": | |
622 | self.srcfile = data.uint16() | |
623 | elif pnm == "Signature": | |
624 | self.sig = data.uint16() | |
625 | elif pnm == "Synthetic": | |
626 | self.syn = True | |
627 | elif pnm == "Deprecated": | |
628 | self.deprecated = True | |
629 | elif pnm == "InnerClasses": | |
630 | for o in range(data.uint16()): | |
631 | cref = data.uint16() | |
632 | outer = data.uint16() | |
633 | cnm = data.uint16() | |
634 | acc = 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)) | |
654 | else: | |
655 | self.attrs.append((nm, data.splice())) | |
656 | ||
657 | return self | |
658 | ||
659 | def _save(self, buf): | |
660 | buf.uint32(self.MAGIC) | |
661 | buf.uint16(self.ver.minor).uint16(self.ver.major) | |
662 | ||
663 | buf.uint16(len(self.cp) + 1) | |
664 | for const in self.cp: | |
665 | if const is not None: | |
666 | self.saveconstant(buf, const) | |
667 | ||
668 | buf.uint16(self.acc) | |
669 | buf.uint16(self.this).uint16(self.super) | |
670 | buf.uint16(len(self.ifaces)) | |
671 | for iref in self.ifaces: buf.uint16(iref) | |
672 | ||
673 | buf.uint16(len(self.fields)) | |
674 | for field in self.fields: | |
675 | self.savefield(buf, field) | |
676 | ||
677 | buf.uint16(len(self.methods)) | |
678 | for method in self.methods: | |
679 | self.savemethod(buf, method) | |
680 | ||
681 | enc = binfmt.encbuf | |
682 | attrs = list(self.attrs) | |
683 | if self.srcfile is not None: | |
684 | attrs.append((self.intern("SourceFile"), enc().uint16(self.srcfile))) | |
685 | if self.syn: | |
686 | attrs.append((self.intern("Synthetic"), b"")) | |
687 | if self.deprecated: | |
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: | |
692 | data = enc() | |
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: | |
699 | data = enc() | |
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: | |
704 | data = enc() | |
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) | |
709 | ||
710 | def save(self, fp): | |
711 | return self._save(binfmt.encstream(fp)) | |
712 | ||
713 | @classmethod | |
714 | def fromfile(cls, fn): | |
715 | with open(fn, "rb") as fp: | |
716 | return cls.load(fp) | |
717 | ||
718 | def tofile(self, fn): | |
719 | with open(fn, "wb") as fp: | |
720 | return self.save(fp) |