1_accessstrings = {0: "", 1: "readonly", 2: "executeonly", 3: "noaccess"} 2 3 4class ps_object(object): 5 literal = 1 6 access = 0 7 value = None 8 9 def __init__(self, value): 10 self.value = value 11 self.type = self.__class__.__name__[3:] + "type" 12 13 def __repr__(self): 14 return "<%s %s>" % (self.__class__.__name__[3:], repr(self.value)) 15 16 17class ps_operator(ps_object): 18 literal = 0 19 20 def __init__(self, name, function): 21 self.name = name 22 self.function = function 23 self.type = self.__class__.__name__[3:] + "type" 24 25 def __repr__(self): 26 return "<operator %s>" % self.name 27 28 29class ps_procedure(ps_object): 30 literal = 0 31 32 def __repr__(self): 33 return "<procedure>" 34 35 def __str__(self): 36 psstring = "{" 37 for i in range(len(self.value)): 38 if i: 39 psstring = psstring + " " + str(self.value[i]) 40 else: 41 psstring = psstring + str(self.value[i]) 42 return psstring + "}" 43 44 45class ps_name(ps_object): 46 literal = 0 47 48 def __str__(self): 49 if self.literal: 50 return "/" + self.value 51 else: 52 return self.value 53 54 55class ps_literal(ps_object): 56 def __str__(self): 57 return "/" + self.value 58 59 60class ps_array(ps_object): 61 def __str__(self): 62 psstring = "[" 63 for i in range(len(self.value)): 64 item = self.value[i] 65 access = _accessstrings[item.access] 66 if access: 67 access = " " + access 68 if i: 69 psstring = psstring + " " + str(item) + access 70 else: 71 psstring = psstring + str(item) + access 72 return psstring + "]" 73 74 def __repr__(self): 75 return "<array>" 76 77 78_type1_pre_eexec_order = [ 79 "FontInfo", 80 "FontName", 81 "Encoding", 82 "PaintType", 83 "FontType", 84 "FontMatrix", 85 "FontBBox", 86 "UniqueID", 87 "Metrics", 88 "StrokeWidth", 89] 90 91_type1_fontinfo_order = [ 92 "version", 93 "Notice", 94 "FullName", 95 "FamilyName", 96 "Weight", 97 "ItalicAngle", 98 "isFixedPitch", 99 "UnderlinePosition", 100 "UnderlineThickness", 101] 102 103_type1_post_eexec_order = ["Private", "CharStrings", "FID"] 104 105 106def _type1_item_repr(key, value): 107 psstring = "" 108 access = _accessstrings[value.access] 109 if access: 110 access = access + " " 111 if key == "CharStrings": 112 psstring = psstring + "/%s %s def\n" % ( 113 key, 114 _type1_CharString_repr(value.value), 115 ) 116 elif key == "Encoding": 117 psstring = psstring + _type1_Encoding_repr(value, access) 118 else: 119 psstring = psstring + "/%s %s %sdef\n" % (str(key), str(value), access) 120 return psstring 121 122 123def _type1_Encoding_repr(encoding, access): 124 encoding = encoding.value 125 psstring = "/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n" 126 for i in range(256): 127 name = encoding[i].value 128 if name != ".notdef": 129 psstring = psstring + "dup %d /%s put\n" % (i, name) 130 return psstring + access + "def\n" 131 132 133def _type1_CharString_repr(charstrings): 134 items = sorted(charstrings.items()) 135 return "xxx" 136 137 138class ps_font(ps_object): 139 def __str__(self): 140 psstring = "%d dict dup begin\n" % len(self.value) 141 for key in _type1_pre_eexec_order: 142 try: 143 value = self.value[key] 144 except KeyError: 145 pass 146 else: 147 psstring = psstring + _type1_item_repr(key, value) 148 items = sorted(self.value.items()) 149 for key, value in items: 150 if key not in _type1_pre_eexec_order + _type1_post_eexec_order: 151 psstring = psstring + _type1_item_repr(key, value) 152 psstring = psstring + "currentdict end\ncurrentfile eexec\ndup " 153 for key in _type1_post_eexec_order: 154 try: 155 value = self.value[key] 156 except KeyError: 157 pass 158 else: 159 psstring = psstring + _type1_item_repr(key, value) 160 return ( 161 psstring 162 + "dup/FontName get exch definefont pop\nmark currentfile closefile\n" 163 + 8 * (64 * "0" + "\n") 164 + "cleartomark" 165 + "\n" 166 ) 167 168 def __repr__(self): 169 return "<font>" 170 171 172class ps_file(ps_object): 173 pass 174 175 176class ps_dict(ps_object): 177 def __str__(self): 178 psstring = "%d dict dup begin\n" % len(self.value) 179 items = sorted(self.value.items()) 180 for key, value in items: 181 access = _accessstrings[value.access] 182 if access: 183 access = access + " " 184 psstring = psstring + "/%s %s %sdef\n" % (str(key), str(value), access) 185 return psstring + "end " 186 187 def __repr__(self): 188 return "<dict>" 189 190 191class ps_mark(ps_object): 192 def __init__(self): 193 self.value = "mark" 194 self.type = self.__class__.__name__[3:] + "type" 195 196 197class ps_procmark(ps_object): 198 def __init__(self): 199 self.value = "procmark" 200 self.type = self.__class__.__name__[3:] + "type" 201 202 203class ps_null(ps_object): 204 def __init__(self): 205 self.type = self.__class__.__name__[3:] + "type" 206 207 208class ps_boolean(ps_object): 209 def __str__(self): 210 if self.value: 211 return "true" 212 else: 213 return "false" 214 215 216class ps_string(ps_object): 217 def __str__(self): 218 return "(%s)" % repr(self.value)[1:-1] 219 220 221class ps_integer(ps_object): 222 def __str__(self): 223 return repr(self.value) 224 225 226class ps_real(ps_object): 227 def __str__(self): 228 return repr(self.value) 229 230 231class PSOperators(object): 232 def ps_def(self): 233 obj = self.pop() 234 name = self.pop() 235 self.dictstack[-1][name.value] = obj 236 237 def ps_bind(self): 238 proc = self.pop("proceduretype") 239 self.proc_bind(proc) 240 self.push(proc) 241 242 def proc_bind(self, proc): 243 for i in range(len(proc.value)): 244 item = proc.value[i] 245 if item.type == "proceduretype": 246 self.proc_bind(item) 247 else: 248 if not item.literal: 249 try: 250 obj = self.resolve_name(item.value) 251 except: 252 pass 253 else: 254 if obj.type == "operatortype": 255 proc.value[i] = obj 256 257 def ps_exch(self): 258 if len(self.stack) < 2: 259 raise RuntimeError("stack underflow") 260 obj1 = self.pop() 261 obj2 = self.pop() 262 self.push(obj1) 263 self.push(obj2) 264 265 def ps_dup(self): 266 if not self.stack: 267 raise RuntimeError("stack underflow") 268 self.push(self.stack[-1]) 269 270 def ps_exec(self): 271 obj = self.pop() 272 if obj.type == "proceduretype": 273 self.call_procedure(obj) 274 else: 275 self.handle_object(obj) 276 277 def ps_count(self): 278 self.push(ps_integer(len(self.stack))) 279 280 def ps_eq(self): 281 any1 = self.pop() 282 any2 = self.pop() 283 self.push(ps_boolean(any1.value == any2.value)) 284 285 def ps_ne(self): 286 any1 = self.pop() 287 any2 = self.pop() 288 self.push(ps_boolean(any1.value != any2.value)) 289 290 def ps_cvx(self): 291 obj = self.pop() 292 obj.literal = 0 293 self.push(obj) 294 295 def ps_matrix(self): 296 matrix = [ 297 ps_real(1.0), 298 ps_integer(0), 299 ps_integer(0), 300 ps_real(1.0), 301 ps_integer(0), 302 ps_integer(0), 303 ] 304 self.push(ps_array(matrix)) 305 306 def ps_string(self): 307 num = self.pop("integertype").value 308 self.push(ps_string("\0" * num)) 309 310 def ps_type(self): 311 obj = self.pop() 312 self.push(ps_string(obj.type)) 313 314 def ps_store(self): 315 value = self.pop() 316 key = self.pop() 317 name = key.value 318 for i in range(len(self.dictstack) - 1, -1, -1): 319 if name in self.dictstack[i]: 320 self.dictstack[i][name] = value 321 break 322 self.dictstack[-1][name] = value 323 324 def ps_where(self): 325 name = self.pop() 326 # XXX 327 self.push(ps_boolean(0)) 328 329 def ps_systemdict(self): 330 self.push(ps_dict(self.dictstack[0])) 331 332 def ps_userdict(self): 333 self.push(ps_dict(self.dictstack[1])) 334 335 def ps_currentdict(self): 336 self.push(ps_dict(self.dictstack[-1])) 337 338 def ps_currentfile(self): 339 self.push(ps_file(self.tokenizer)) 340 341 def ps_eexec(self): 342 f = self.pop("filetype").value 343 f.starteexec() 344 345 def ps_closefile(self): 346 f = self.pop("filetype").value 347 f.skipwhite() 348 f.stopeexec() 349 350 def ps_cleartomark(self): 351 obj = self.pop() 352 while obj != self.mark: 353 obj = self.pop() 354 355 def ps_readstring(self, ps_boolean=ps_boolean, len=len): 356 s = self.pop("stringtype") 357 oldstr = s.value 358 f = self.pop("filetype") 359 # pad = file.value.read(1) 360 # for StringIO, this is faster 361 f.value.pos = f.value.pos + 1 362 newstr = f.value.read(len(oldstr)) 363 s.value = newstr 364 self.push(s) 365 self.push(ps_boolean(len(oldstr) == len(newstr))) 366 367 def ps_known(self): 368 key = self.pop() 369 d = self.pop("dicttype", "fonttype") 370 self.push(ps_boolean(key.value in d.value)) 371 372 def ps_if(self): 373 proc = self.pop("proceduretype") 374 if self.pop("booleantype").value: 375 self.call_procedure(proc) 376 377 def ps_ifelse(self): 378 proc2 = self.pop("proceduretype") 379 proc1 = self.pop("proceduretype") 380 if self.pop("booleantype").value: 381 self.call_procedure(proc1) 382 else: 383 self.call_procedure(proc2) 384 385 def ps_readonly(self): 386 obj = self.pop() 387 if obj.access < 1: 388 obj.access = 1 389 self.push(obj) 390 391 def ps_executeonly(self): 392 obj = self.pop() 393 if obj.access < 2: 394 obj.access = 2 395 self.push(obj) 396 397 def ps_noaccess(self): 398 obj = self.pop() 399 if obj.access < 3: 400 obj.access = 3 401 self.push(obj) 402 403 def ps_not(self): 404 obj = self.pop("booleantype", "integertype") 405 if obj.type == "booleantype": 406 self.push(ps_boolean(not obj.value)) 407 else: 408 self.push(ps_integer(~obj.value)) 409 410 def ps_print(self): 411 str = self.pop("stringtype") 412 print("PS output --->", str.value) 413 414 def ps_anchorsearch(self): 415 seek = self.pop("stringtype") 416 s = self.pop("stringtype") 417 seeklen = len(seek.value) 418 if s.value[:seeklen] == seek.value: 419 self.push(ps_string(s.value[seeklen:])) 420 self.push(seek) 421 self.push(ps_boolean(1)) 422 else: 423 self.push(s) 424 self.push(ps_boolean(0)) 425 426 def ps_array(self): 427 num = self.pop("integertype") 428 array = ps_array([None] * num.value) 429 self.push(array) 430 431 def ps_astore(self): 432 array = self.pop("arraytype") 433 for i in range(len(array.value) - 1, -1, -1): 434 array.value[i] = self.pop() 435 self.push(array) 436 437 def ps_load(self): 438 name = self.pop() 439 self.push(self.resolve_name(name.value)) 440 441 def ps_put(self): 442 obj1 = self.pop() 443 obj2 = self.pop() 444 obj3 = self.pop("arraytype", "dicttype", "stringtype", "proceduretype") 445 tp = obj3.type 446 if tp == "arraytype" or tp == "proceduretype": 447 obj3.value[obj2.value] = obj1 448 elif tp == "dicttype": 449 obj3.value[obj2.value] = obj1 450 elif tp == "stringtype": 451 index = obj2.value 452 obj3.value = obj3.value[:index] + chr(obj1.value) + obj3.value[index + 1 :] 453 454 def ps_get(self): 455 obj1 = self.pop() 456 if obj1.value == "Encoding": 457 pass 458 obj2 = self.pop( 459 "arraytype", "dicttype", "stringtype", "proceduretype", "fonttype" 460 ) 461 tp = obj2.type 462 if tp in ("arraytype", "proceduretype"): 463 self.push(obj2.value[obj1.value]) 464 elif tp in ("dicttype", "fonttype"): 465 self.push(obj2.value[obj1.value]) 466 elif tp == "stringtype": 467 self.push(ps_integer(ord(obj2.value[obj1.value]))) 468 else: 469 assert False, "shouldn't get here" 470 471 def ps_getinterval(self): 472 obj1 = self.pop("integertype") 473 obj2 = self.pop("integertype") 474 obj3 = self.pop("arraytype", "stringtype") 475 tp = obj3.type 476 if tp == "arraytype": 477 self.push(ps_array(obj3.value[obj2.value : obj2.value + obj1.value])) 478 elif tp == "stringtype": 479 self.push(ps_string(obj3.value[obj2.value : obj2.value + obj1.value])) 480 481 def ps_putinterval(self): 482 obj1 = self.pop("arraytype", "stringtype") 483 obj2 = self.pop("integertype") 484 obj3 = self.pop("arraytype", "stringtype") 485 tp = obj3.type 486 if tp == "arraytype": 487 obj3.value[obj2.value : obj2.value + len(obj1.value)] = obj1.value 488 elif tp == "stringtype": 489 newstr = obj3.value[: obj2.value] 490 newstr = newstr + obj1.value 491 newstr = newstr + obj3.value[obj2.value + len(obj1.value) :] 492 obj3.value = newstr 493 494 def ps_cvn(self): 495 self.push(ps_name(self.pop("stringtype").value)) 496 497 def ps_index(self): 498 n = self.pop("integertype").value 499 if n < 0: 500 raise RuntimeError("index may not be negative") 501 self.push(self.stack[-1 - n]) 502 503 def ps_for(self): 504 proc = self.pop("proceduretype") 505 limit = self.pop("integertype", "realtype").value 506 increment = self.pop("integertype", "realtype").value 507 i = self.pop("integertype", "realtype").value 508 while 1: 509 if increment > 0: 510 if i > limit: 511 break 512 else: 513 if i < limit: 514 break 515 if type(i) == type(0.0): 516 self.push(ps_real(i)) 517 else: 518 self.push(ps_integer(i)) 519 self.call_procedure(proc) 520 i = i + increment 521 522 def ps_forall(self): 523 proc = self.pop("proceduretype") 524 obj = self.pop("arraytype", "stringtype", "dicttype") 525 tp = obj.type 526 if tp == "arraytype": 527 for item in obj.value: 528 self.push(item) 529 self.call_procedure(proc) 530 elif tp == "stringtype": 531 for item in obj.value: 532 self.push(ps_integer(ord(item))) 533 self.call_procedure(proc) 534 elif tp == "dicttype": 535 for key, value in obj.value.items(): 536 self.push(ps_name(key)) 537 self.push(value) 538 self.call_procedure(proc) 539 540 def ps_definefont(self): 541 font = self.pop("dicttype") 542 name = self.pop() 543 font = ps_font(font.value) 544 self.dictstack[0]["FontDirectory"].value[name.value] = font 545 self.push(font) 546 547 def ps_findfont(self): 548 name = self.pop() 549 font = self.dictstack[0]["FontDirectory"].value[name.value] 550 self.push(font) 551 552 def ps_pop(self): 553 self.pop() 554 555 def ps_dict(self): 556 self.pop("integertype") 557 self.push(ps_dict({})) 558 559 def ps_begin(self): 560 self.dictstack.append(self.pop("dicttype").value) 561 562 def ps_end(self): 563 if len(self.dictstack) > 2: 564 del self.dictstack[-1] 565 else: 566 raise RuntimeError("dictstack underflow") 567 568 569notdef = ".notdef" 570from fontTools.encodings.StandardEncoding import StandardEncoding 571 572ps_StandardEncoding = list(map(ps_name, StandardEncoding)) 573