| 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) |