psCharStrings.py revision dbc2c173b35360386c907a3c70cb931ae4c3fac9
1"""psCharStrings.py -- module implementing various kinds of CharStrings: 2CFF dictionary data and Type1/Type2 CharStrings. 3""" 4 5__version__ = "1.0b1" 6__author__ = "jvr" 7 8 9import types 10import struct 11import string 12 13 14t1OperandEncoding = [None] * 256 15t1OperandEncoding[0:32] = (32) * ["do_operator"] 16t1OperandEncoding[32:247] = (247 - 32) * ["read_byte"] 17t1OperandEncoding[247:251] = (251 - 247) * ["read_smallInt1"] 18t1OperandEncoding[251:255] = (255 - 251) * ["read_smallInt2"] 19t1OperandEncoding[255] = "read_longInt" 20assert len(t1OperandEncoding) == 256 21 22t2OperandEncoding = t1OperandEncoding[:] 23t2OperandEncoding[28] = "read_shortInt" 24 25cffDictOperandEncoding = t2OperandEncoding[:] 26cffDictOperandEncoding[29] = "read_longInt" 27cffDictOperandEncoding[30] = "read_realNumber" 28cffDictOperandEncoding[255] = "reserved" 29 30 31realNibbles = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 32 '.', 'E', 'E-', None, '-'] 33 34 35class ByteCodeDecompilerBase: 36 37 def read_byte(self, b0, data, index): 38 return b0 - 139, index 39 40 def read_smallInt1(self, b0, data, index): 41 b1 = ord(data[index]) 42 return (b0-247)*256 + b1 + 108, index+1 43 44 def read_smallInt2(self, b0, data, index): 45 b1 = ord(data[index]) 46 return -(b0-251)*256 - b1 - 108, index+1 47 48 def read_shortInt(self, b0, data, index): 49 bin = data[index] + data[index+1] 50 value, = struct.unpack(">h", bin) 51 return value, index+2 52 53 def read_longInt(self, b0, data, index): 54 bin = data[index] + data[index+1] + data[index+2] + data[index+3] 55 value, = struct.unpack(">l", bin) 56 return value, index+4 57 58 def read_realNumber(self, b0, data, index): 59 number = '' 60 while 1: 61 b = ord(data[index]) 62 index = index + 1 63 nibble0 = (b & 0xf0) >> 4 64 nibble1 = b & 0x0f 65 if nibble0 == 0xf: 66 break 67 number = number + realNibbles[nibble0] 68 if nibble1 == 0xf: 69 break 70 number = number + realNibbles[nibble1] 71 return string.atof(number), index 72 73 74def buildOperatorDict(operatorList): 75 dict = {} 76 for item in operatorList: 77 if len(item) == 2: 78 dict[item[0]] = item[1] 79 else: 80 dict[item[0]] = item[1:] 81 return dict 82 83 84t2Operators = [ 85# opcode name 86 (1, 'hstem'), 87 (3, 'vstem'), 88 (4, 'vmoveto'), 89 (5, 'rlineto'), 90 (6, 'hlineto'), 91 (7, 'vlineto'), 92 (8, 'rrcurveto'), 93 (10, 'callsubr'), 94 (11, 'return'), 95 (14, 'endchar'), 96 (16, 'blend'), 97 (18, 'hstemhm'), 98 (19, 'hintmask'), 99 (20, 'cntrmask'), 100 (21, 'rmoveto'), 101 (22, 'hmoveto'), 102 (23, 'vstemhm'), 103 (24, 'rcurveline'), 104 (25, 'rlinecurve'), 105 (26, 'vvcurveto'), 106 (27, 'hhcurveto'), 107# (28, 'shortint'), # not really an operator 108 (29, 'callgsubr'), 109 (30, 'vhcurveto'), 110 (31, 'hvcurveto'), 111 ((12, 3), 'and'), 112 ((12, 4), 'or'), 113 ((12, 5), 'not'), 114 ((12, 8), 'store'), 115 ((12, 9), 'abs'), 116 ((12, 10), 'add'), 117 ((12, 11), 'sub'), 118 ((12, 12), 'div'), 119 ((12, 13), 'load'), 120 ((12, 14), 'neg'), 121 ((12, 15), 'eq'), 122 ((12, 18), 'drop'), 123 ((12, 20), 'put'), 124 ((12, 21), 'get'), 125 ((12, 22), 'ifelse'), 126 ((12, 23), 'random'), 127 ((12, 24), 'mul'), 128 ((12, 26), 'sqrt'), 129 ((12, 27), 'dup'), 130 ((12, 28), 'exch'), 131 ((12, 29), 'index'), 132 ((12, 30), 'roll'), 133 ((12, 34), 'hflex'), 134 ((12, 35), 'flex'), 135 ((12, 36), 'hflex1'), 136 ((12, 37), 'flex1'), 137] 138 139class T2CharString(ByteCodeDecompilerBase): 140 141 operandEncoding = t2OperandEncoding 142 operators = buildOperatorDict(t2Operators) 143 144 def __init__(self, bytecode=None, program=None): 145 if program is None: 146 program = [] 147 self.bytecode = bytecode 148 self.program = program 149 150 def __repr__(self): 151 if self.bytecode is None: 152 return "<%s (source) at %x>" % (self.__class__.__name__, id(self)) 153 else: 154 return "<%s (bytecode) at %x>" % (self.__class__.__name__, id(self)) 155 156 def needsDecompilation(self): 157 return self.bytecode is not None 158 159 def setProgram(self, program): 160 self.program = program 161 self.bytecode = None 162 163 def getToken(self, index, 164 len=len, ord=ord, getattr=getattr, type=type, StringType=types.StringType): 165 if self.bytecode is not None: 166 if index >= len(self.bytecode): 167 return None, 0, 0 168 b0 = ord(self.bytecode[index]) 169 index = index + 1 170 code = self.operandEncoding[b0] 171 handler = getattr(self, code) 172 token, index = handler(b0, self.bytecode, index) 173 else: 174 if index >= len(self.program): 175 return None, 0, 0 176 token = self.program[index] 177 index = index + 1 178 isOperator = type(token) == StringType 179 return token, isOperator, index 180 181 def getBytes(self, index, nBytes): 182 if self.bytecode is not None: 183 newIndex = index + nBytes 184 bytes = self.bytecode[index:newIndex] 185 index = newIndex 186 else: 187 bytes = self.program[index] 188 index = index + 1 189 assert len(bytes) == nBytes 190 return bytes, index 191 192 def do_operator(self, b0, data, index): 193 if b0 == 12: 194 op = (b0, ord(data[index])) 195 index = index+1 196 else: 197 op = b0 198 operator = self.operators[op] 199 return operator, index 200 201 def toXML(self, xmlWriter): 202 from fontTools.misc.textTools import num2binary 203 if self.bytecode is not None: 204 xmlWriter.dumphex(self.bytecode) 205 else: 206 index = 0 207 args = [] 208 while 1: 209 token, isOperator, index = self.getToken(index) 210 if token is None: 211 break 212 if isOperator: 213 args = map(str, args) 214 if token in ('hintmask', 'cntrmask'): 215 hintMask, isOperator, index = self.getToken(index) 216 bits = [] 217 for byte in hintMask: 218 bits.append(num2binary(ord(byte), 8)) 219 hintMask = repr(string.join(bits, "")) 220 line = string.join(args + [token, hintMask], " ") 221 else: 222 line = string.join(args + [token], " ") 223 xmlWriter.write(line) 224 xmlWriter.newline() 225 args = [] 226 else: 227 args.append(token) 228 229 230t1Operators = [ 231# opcode name 232 (1, 'hstem'), 233 (3, 'vstem'), 234 (4, 'vmoveto'), 235 (5, 'rlineto'), 236 (6, 'hlineto'), 237 (7, 'vlineto'), 238 (8, 'rrcurveto'), 239 (9, 'closepath'), 240 (10, 'callsubr'), 241 (11, 'return'), 242 (13, 'hsbw'), 243 (14, 'endchar'), 244 (21, 'rmoveto'), 245 (22, 'hmoveto'), 246 (30, 'vhcurveto'), 247 (31, 'hvcurveto'), 248 ((12, 0), 'dotsection'), 249 ((12, 1), 'vstem3'), 250 ((12, 2), 'hstem3'), 251 ((12, 6), 'seac'), 252 ((12, 7), 'sbw'), 253 ((12, 12), 'div'), 254 ((12, 16), 'callothersubr'), 255 ((12, 17), 'pop'), 256 ((12, 33), 'setcurrentpoint'), 257] 258 259class T1CharString(T2CharString): 260 261 operandEncoding = t1OperandEncoding 262 operators = buildOperatorDict(t1Operators) 263 264 def decompile(self): 265 if self.program is not None: 266 return 267 program = [] 268 index = 0 269 while 1: 270 token, isOperator, index = self.getToken(index) 271 if token is None: 272 break 273 program.append(token) 274 self.setProgram(program) 275 276 277class SimpleT2Decompiler: 278 279 def __init__(self, localSubrs, globalSubrs): 280 self.localSubrs = localSubrs 281 self.localBias = calcSubrBias(localSubrs) 282 self.globalSubrs = globalSubrs 283 self.globalBias = calcSubrBias(globalSubrs) 284 self.reset() 285 286 def reset(self): 287 self.callingStack = [] 288 self.operandStack = [] 289 self.hintCount = 0 290 self.hintMaskBytes = 0 291 292 def execute(self, charString): 293 self.callingStack.append(charString) 294 needsDecompilation = charString.needsDecompilation() 295 if needsDecompilation: 296 program = [] 297 pushToProgram = program.append 298 else: 299 pushToProgram = lambda x: None 300 pushToStack = self.operandStack.append 301 index = 0 302 while 1: 303 token, isOperator, index = charString.getToken(index) 304 if token is None: 305 break # we're done! 306 pushToProgram(token) 307 if isOperator: 308 handlerName = "op_" + token 309 if hasattr(self, handlerName): 310 handler = getattr(self, handlerName) 311 rv = handler(index) 312 if rv: 313 hintMaskBytes, index = rv 314 pushToProgram(hintMaskBytes) 315 else: 316 self.popall() 317 else: 318 pushToStack(token) 319 if needsDecompilation: 320 charString.setProgram(program) 321 assert program[-1] in ("endchar", "return", "callsubr", "callgsubr", "seac") 322 del self.callingStack[-1] 323 324 def pop(self): 325 value = self.operandStack[-1] 326 del self.operandStack[-1] 327 return value 328 329 def popall(self): 330 stack = self.operandStack[:] 331 self.operandStack[:] = [] 332 return stack 333 334 def push(self, value): 335 self.operandStack.append(value) 336 337 def op_return(self, index): 338 if self.operandStack: 339 pass 340 341 def op_endchar(self, index): 342 pass 343 344 def op_callsubr(self, index): 345 subrIndex = self.pop() 346 subr = self.localSubrs[subrIndex+self.localBias] 347 self.execute(subr) 348 349 def op_callgsubr(self, index): 350 subrIndex = self.pop() 351 subr = self.globalSubrs[subrIndex+self.globalBias] 352 self.execute(subr) 353 354 def op_hstemhm(self, index): 355 self.countHints() 356 357 op_vstemhm = op_hstemhm 358 359 def op_hintmask(self, index): 360 if not self.hintMaskBytes: 361 self.countHints() 362 self.hintMaskBytes = (self.hintCount + 7) / 8 363 hintMaskBytes, index = self.callingStack[-1].getBytes(index, self.hintMaskBytes) 364 return hintMaskBytes, index 365 366 op_cntrmask = op_hintmask 367 368 def countHints(self): 369 assert self.hintMaskBytes == 0 370 args = self.popall() 371 self.hintCount = self.hintCount + len(args) / 2 372 373 374class T2OutlineExtractor(SimpleT2Decompiler): 375 376 def __init__(self, localSubrs, globalSubrs, nominalWidthX, defaultWidthX): 377 SimpleT2Decompiler.__init__(self, localSubrs, globalSubrs) 378 self.nominalWidthX = nominalWidthX 379 self.defaultWidthX = defaultWidthX 380 381 def reset(self): 382 import Numeric 383 SimpleT2Decompiler.reset(self) 384 self.hints = [] 385 self.gotWidth = 0 386 self.width = 0 387 self.currentPoint = Numeric.array((0, 0), Numeric.Int16) 388 self.contours = [] 389 390 def getContours(self): 391 return self.contours 392 393 def newPath(self): 394 self.contours.append([[], [], 0]) 395 396 def closePath(self): 397 if self.contours and self.contours[-1][2] == 0: 398 self.contours[-1][2] = 1 399 400 def appendPoint(self, point, isPrimary): 401 import Numeric 402 point = self.currentPoint + Numeric.array(point, Numeric.Int16) 403 if not self.contours or self.contours[-1][2]: 404 # The subpath doesn't start with a moveto. Not sure whether 405 # this is legal, but apparently it usually works. 406 self.newPath() 407 self.appendPoint((0, 0), 1) 408 self.currentPoint = point 409 points, flags, isClosed = self.contours[-1] 410 points.append(point) 411 flags.append(isPrimary) 412 413 def popallWidth(self, evenOdd=0): 414 args = self.popall() 415 if not self.gotWidth: 416 if evenOdd ^ (len(args) % 2): 417 self.width = self.nominalWidthX + args[0] 418 args = args[1:] 419 else: 420 self.width = self.defaultWidthX 421 self.gotWidth = 1 422 return args 423 424 def countHints(self): 425 assert self.hintMaskBytes == 0 426 args = self.popallWidth() 427 self.hintCount = self.hintCount + len(args) / 2 428 429 # 430 # hint operators 431 # 432 def op_hstem(self, index): 433 self.popallWidth() # XXX 434 def op_vstem(self, index): 435 self.popallWidth() # XXX 436 def op_hstemhm(self, index): 437 self.countHints() 438 #XXX 439 def op_vstemhm(self, index): 440 self.countHints() 441 #XXX 442 #def op_hintmask(self, index): 443 # self.countHints() 444 #def op_cntrmask(self, index): 445 # self.countHints() 446 447 # 448 # path constructors, moveto 449 # 450 def op_rmoveto(self, index): 451 self.closePath() 452 self.newPath() 453 self.appendPoint(self.popallWidth(), 1) 454 def op_hmoveto(self, index): 455 self.closePath() 456 self.newPath() 457 self.appendPoint((self.popallWidth(1)[0], 0), 1) 458 def op_vmoveto(self, index): 459 self.closePath() 460 self.newPath() 461 self.appendPoint((0, self.popallWidth(1)[0]), 1) 462 def op_endchar(self, index): 463 self.closePath() 464 465 # 466 # path constructors, lines 467 # 468 def op_rlineto(self, index): 469 args = self.popall() 470 for i in range(0, len(args), 2): 471 point = args[i:i+2] 472 self.appendPoint(point, 1) 473 474 def op_hlineto(self, index): 475 self.alternatingLineto(1) 476 def op_vlineto(self, index): 477 self.alternatingLineto(0) 478 479 # 480 # path constructors, curves 481 # 482 def op_rrcurveto(self, index): 483 """{dxa dya dxb dyb dxc dyc}+ rrcurveto""" 484 args = self.popall() 485 for i in range(0, len(args), 6): 486 dxa, dya, dxb, dyb, dxc, dyc, = args[i:i+6] 487 self.rrcurveto((dxa, dya), (dxb, dyb), (dxc, dyc)) 488 489 def op_rcurveline(self, index): 490 """{dxa dya dxb dyb dxc dyc}+ dxd dyd rcurveline""" 491 args = self.popall() 492 for i in range(0, len(args)-2, 6): 493 dxb, dyb, dxc, dyc, dxd, dyd = args[i:i+6] 494 self.rrcurveto((dxb, dyb), (dxc, dyc), (dxd, dyd)) 495 self.appendPoint(args[-2:], 1) 496 497 def op_rlinecurve(self, index): 498 """{dxa dya}+ dxb dyb dxc dyc dxd dyd rlinecurve""" 499 args = self.popall() 500 lineArgs = args[:-6] 501 for i in range(0, len(lineArgs), 2): 502 self.appendPoint(lineArgs[i:i+2], 1) 503 dxb, dyb, dxc, dyc, dxd, dyd = args[-6:] 504 self.rrcurveto((dxb, dyb), (dxc, dyc), (dxd, dyd)) 505 506 def op_vvcurveto(self, index): 507 "dx1? {dya dxb dyb dyc}+ vvcurveto" 508 args = self.popall() 509 if len(args) % 2: 510 dx1 = args[0] 511 args = args[1:] 512 else: 513 dx1 = 0 514 for i in range(0, len(args), 4): 515 dya, dxb, dyb, dyc = args[i:i+4] 516 self.rrcurveto((dx1, dya), (dxb, dyb), (0, dyc)) 517 dx1 = 0 518 519 def op_hhcurveto(self, index): 520 """dy1? {dxa dxb dyb dxc}+ hhcurveto""" 521 args = self.popall() 522 if len(args) % 2: 523 dy1 = args[0] 524 args = args[1:] 525 else: 526 dy1 = 0 527 for i in range(0, len(args), 4): 528 dxa, dxb, dyb, dxc = args[i:i+4] 529 self.rrcurveto((dxa, dy1), (dxb, dyb), (dxc, 0)) 530 dy1 = 0 531 532 def op_vhcurveto(self, index): 533 """dy1 dx2 dy2 dx3 {dxa dxb dyb dyc dyd dxe dye dxf}* dyf? vhcurveto (30) 534 {dya dxb dyb dxc dxd dxe dye dyf}+ dxf? vhcurveto 535 """ 536 args = self.popall() 537 while args: 538 args = self.vcurveto(args) 539 if args: 540 args = self.hcurveto(args) 541 542 def op_hvcurveto(self, index): 543 """dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf? 544 {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf? 545 """ 546 args = self.popall() 547 while args: 548 args = self.hcurveto(args) 549 if args: 550 args = self.vcurveto(args) 551 552 # 553 # path constructors, flex 554 # 555 def op_hflex(self, index): 556 XXX 557 def op_flex(self, index): 558 XXX 559 def op_hflex1(self, index): 560 XXX 561 def op_flex1(self, index): 562 XXX 563 564 # 565 # MultipleMaster. Well... 566 # 567 def op_blend(self, index): 568 XXX 569 570 # misc 571 def op_and(self, index): 572 XXX 573 def op_or(self, index): 574 XXX 575 def op_not(self, index): 576 XXX 577 def op_store(self, index): 578 XXX 579 def op_abs(self, index): 580 XXX 581 def op_add(self, index): 582 XXX 583 def op_sub(self, index): 584 XXX 585 def op_div(self, index): 586 num2 = self.pop() 587 num1 = self.pop() 588 d1 = num1/num2 589 d2 = float(num1)/num2 590 if d1 == d2: 591 self.push(d1) 592 else: 593 self.push(d2) 594 def op_load(self, index): 595 XXX 596 def op_neg(self, index): 597 XXX 598 def op_eq(self, index): 599 XXX 600 def op_drop(self, index): 601 XXX 602 def op_put(self, index): 603 XXX 604 def op_get(self, index): 605 XXX 606 def op_ifelse(self, index): 607 XXX 608 def op_random(self, index): 609 XXX 610 def op_mul(self, index): 611 XXX 612 def op_sqrt(self, index): 613 XXX 614 def op_dup(self, index): 615 XXX 616 def op_exch(self, index): 617 XXX 618 def op_index(self, index): 619 XXX 620 def op_roll(self, index): 621 XXX 622 623 # 624 # miscelaneous helpers 625 # 626 def alternatingLineto(self, isHorizontal): 627 args = self.popall() 628 for arg in args: 629 if isHorizontal: 630 point = (arg, 0) 631 else: 632 point = (0, arg) 633 self.appendPoint(point, 1) 634 isHorizontal = not isHorizontal 635 636 def rrcurveto(self, p1, p2, p3): 637 self.appendPoint(p1, 0) 638 self.appendPoint(p2, 0) 639 self.appendPoint(p3, 1) 640 641 def vcurveto(self, args): 642 dya, dxb, dyb, dxc = args[:4] 643 args = args[4:] 644 if len(args) == 1: 645 dyc = args[0] 646 args = [] 647 else: 648 dyc = 0 649 self.rrcurveto((0, dya), (dxb, dyb), (dxc, dyc)) 650 return args 651 652 def hcurveto(self, args): 653 dxa, dxb, dyb, dyc = args[:4] 654 args = args[4:] 655 if len(args) == 1: 656 dxc = args[0] 657 args = [] 658 else: 659 dxc = 0 660 self.rrcurveto((dxa, 0), (dxb, dyb), (dxc, dyc)) 661 return args 662 663 664class T1OutlineExtractor(T2OutlineExtractor): 665 666 def __init__(self, subrs): 667 self.subrs = subrs 668 self.reset() 669 670 def reset(self): 671 self.flexing = 0 672 self.width = 0 673 self.sbx = 0 674 T2OutlineExtractor.reset(self) 675 676 def popallWidth(self, evenOdd=0): 677 return self.popall() 678 679 def exch(self): 680 stack = self.operandStack 681 stack[-1], stack[-2] = stack[-2], stack[-1] 682 683 # 684 # path constructors 685 # 686 def op_rmoveto(self, index): 687 if self.flexing: 688 return 689 self.newPath() 690 self.appendPoint(self.popall(), 1) 691 def op_hmoveto(self, index): 692 if self.flexing: 693 # We must add a parameter to the stack if we are flexing 694 self.push(0) 695 return 696 self.newPath() 697 self.appendPoint((self.popall()[0], 0), 1) 698 def op_vmoveto(self, index): 699 if self.flexing: 700 # We must add a parameter to the stack if we are flexing 701 self.push(0) 702 self.exch() 703 return 704 self.newPath() 705 self.appendPoint((0, self.popall()[0]), 1) 706 def op_closepath(self, index): 707 self.closePath() 708 def op_setcurrentpoint(self, index): 709 args = self.popall() 710 x, y = args 711 self.currentPoint[0] = x 712 self.currentPoint[1] = y 713 714 def op_endchar(self, index): 715 self.closePath() 716 717 def op_hsbw(self, index): 718 sbx, wx = self.popall() 719 self.width = wx 720 self.sbx = sbx 721 self.currentPoint[0] = sbx 722 def op_sbw(self, index): 723 self.popall() # XXX 724 725 # 726 def op_callsubr(self, index): 727 subrIndex = self.pop() 728 subr = self.subrs[subrIndex] 729 self.execute(subr) 730 def op_callothersubr(self, index): 731 subrIndex = self.pop() 732 nArgs = self.pop() 733 #print nArgs, subrIndex, "callothersubr" 734 if subrIndex == 0 and nArgs == 3: 735 self.doFlex() 736 self.flexing = 0 737 elif subrIndex == 1 and nArgs == 0: 738 self.flexing = 1 739 # ignore... 740 def op_pop(self, index): 741 pass # ignore... 742 743 def doFlex(self): 744 finaly = self.pop() 745 finalx = self.pop() 746 self.pop() # flex height is unused 747 748 p3y = self.pop() 749 p3x = self.pop() 750 bcp4y = self.pop() 751 bcp4x = self.pop() 752 bcp3y = self.pop() 753 bcp3x = self.pop() 754 p2y = self.pop() 755 p2x = self.pop() 756 bcp2y = self.pop() 757 bcp2x = self.pop() 758 bcp1y = self.pop() 759 bcp1x = self.pop() 760 rpy = self.pop() 761 rpx = self.pop() 762 763 # call rrcurveto 764 self.push(bcp1x+rpx) 765 self.push(bcp1y+rpy) 766 self.push(bcp2x) 767 self.push(bcp2y) 768 self.push(p2x) 769 self.push(p2y) 770 self.op_rrcurveto(None) 771 772 # call rrcurveto 773 self.push(bcp3x) 774 self.push(bcp3y) 775 self.push(bcp4x) 776 self.push(bcp4y) 777 self.push(p3x) 778 self.push(p3y) 779 self.op_rrcurveto(None) 780 781 # Push back final coords so subr 0 can find them 782 self.push(finalx) 783 self.push(finaly) 784 785 def op_dotsection(self, index): 786 self.popall() # XXX 787 def op_hstem3(self, index): 788 self.popall() # XXX 789 def op_seac(self, index): 790 "asb adx ady bchar achar seac" 791 asb, adx, ady, bchar, achar = self.popall() # XXX 792 self.contours.append([(asb, adx, ady, bchar, achar), None, -1]) 793 def op_vstem3(self, index): 794 self.popall() # XXX 795 796 797class DictDecompiler(ByteCodeDecompilerBase): 798 799 operandEncoding = cffDictOperandEncoding 800 dictDefaults = {} 801 802 def __init__(self, strings): 803 self.stack = [] 804 self.strings = strings 805 self.dict = {} 806 807 def getDict(self): 808 assert len(self.stack) == 0, "non-empty stack" 809 return self.dict 810 811 def decompile(self, data): 812 index = 0 813 lenData = len(data) 814 push = self.stack.append 815 while index < lenData: 816 b0 = ord(data[index]) 817 index = index + 1 818 code = self.operandEncoding[b0] 819 handler = getattr(self, code) 820 value, index = handler(b0, data, index) 821 if value is not None: 822 push(value) 823 824 def pop(self): 825 value = self.stack[-1] 826 del self.stack[-1] 827 return value 828 829 def popall(self): 830 all = self.stack[:] 831 del self.stack[:] 832 return all 833 834 def do_operator(self, b0, data, index): 835 if b0 == 12: 836 op = (b0, ord(data[index])) 837 index = index+1 838 else: 839 op = b0 840 operator, argType = self.operators[op] 841 self.handle_operator(operator, argType) 842 return None, index 843 844 def handle_operator(self, operator, argType): 845 if type(argType) == type(()): 846 value = () 847 for arg in argType: 848 arghandler = getattr(self, "arg_" + arg) 849 value = (arghandler(operator),) + value 850 else: 851 arghandler = getattr(self, "arg_" + argType) 852 value = arghandler(operator) 853 self.dict[operator] = value 854 855 def arg_number(self, name): 856 return self.pop() 857 def arg_SID(self, name): 858 return self.strings[self.pop()] 859 def arg_array(self, name): 860 return self.popall() 861 862 863def calcSubrBias(subrs): 864 nSubrs = len(subrs) 865 if nSubrs < 1240: 866 bias = 107 867 elif nSubrs < 33900: 868 bias = 1131 869 else: 870 bias = 32768 871 return bias 872 873