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 | ||
188fa298 FT |
104 | class 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 | ||
113 | class 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 | ||
121 | class 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 |
130 | class 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 | ||
139 | class 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 | ||
148 | class 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 | ||
157 | class 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 | ||
170 | class 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 | ||
178 | class 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 | ||
189 | class 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 | ||
206 | class annotation(object): | |
207 | def __init__(self, tp): | |
208 | self.tp = tp | |
209 | self.vals = {} | |
210 | ||
211 | class 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 | ||
218 | class 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") | |
9d8b6140 | 640 | if not self.checkcp(self.super, classref) and self.cp[self.super] is not None: |
964561d6 FT |
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) |