Advertisement
Cees

ineptpdf8.4.51.pyw

Jul 25th, 2011
3,299
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 29.29 KB | None | 0 0
  1. 1.
  2. #! /usr/bin/python
  3.  
  4. 2.
  5.  
  6.  
  7. 3.
  8. # ineptpdf8.4.51.pyw
  9.  
  10. 4.
  11. # ineptpdf, version 8.4.51
  12.  
  13. 5.
  14.  
  15.  
  16. 6.
  17. # To run this program install Python 2.7 from http://www.python.org/download/
  18.  
  19. 7.
  20. #
  21.  
  22. 8.
  23. # PyCrypto from http://www.voidspace.org.uk/python/modules.shtml#pycrypto
  24.  
  25. 9.
  26. #
  27.  
  28. 10.
  29. # and PyWin Extension (Win32API module) from
  30.  
  31. 11.
  32. # http://sourceforge.net/projects/pywin32/files/
  33.  
  34. 12.
  35. #
  36.  
  37. 13.
  38. # Make sure to install the dedicated versions for Python 2.7.
  39.  
  40. 14.
  41. #
  42.  
  43. 15.
  44. # It's recommended to use the 32-Bit Python Windows versions (even with a 64-bit
  45.  
  46. 16.
  47. # Windows system).
  48.  
  49. 17.
  50. #
  51.  
  52. 18.
  53. # Save this script file as
  54.  
  55. 19.
  56. # ineptpdf8.4.51.pyw and double-click on it to run it.
  57.  
  58. 20.
  59.  
  60.  
  61. 21.
  62. # Revision history:
  63.  
  64. 22.
  65. # 1 - Initial release
  66.  
  67. 23.
  68. # 2 - Improved determination of key-generation algorithm
  69.  
  70. 24.
  71. # 3 - Correctly handle PDF >=1.5 cross-reference streams
  72.  
  73. 25.
  74. # 4 - Removal of ciando's personal ID (anon)
  75.  
  76. 26.
  77. # 5 - removing small bug with V3 ebooks (anon)
  78.  
  79. 27.
  80. # 6 - changed to adeptkey4.der format for 1.7.2 support (anon)
  81.  
  82. 28.
  83. # 6.1 - backward compatibility for 1.7.1 and old adeptkey.der (anon)
  84.  
  85. 29.
  86. # 7 - Get cross reference streams and object streams working for input.
  87.  
  88. 30.
  89. # Not yet supported on output but this only effects file size,
  90.  
  91. 31.
  92. # not functionality. (anon2)
  93.  
  94. 32.
  95. # 7.1 - Correct a problem when an old trailer is not followed by startxref (anon2)
  96.  
  97. 33.
  98. # 7.2 - Correct malformed Mac OS resource forks for Stanza
  99.  
  100. 34.
  101. # - Support for cross ref streams on output (decreases file size) (anon2)
  102.  
  103. 35.
  104. # 7.3 - Correct bug in trailer with cross ref stream that caused the error (anon2)
  105.  
  106. 36.
  107. # "The root object is missing or invalid" in Adobe Reader.
  108.  
  109. 37.
  110. # 7.4 - Force all generation numbers in output file to be 0, like in v6.
  111.  
  112. 38.
  113. # Fallback code for wrong xref improved (search till last trailer
  114.  
  115. 39.
  116. # instead of first) (anon2)
  117.  
  118. 40.
  119. # 8 - fileopen user machine identifier support (Tetrachroma)
  120.  
  121. 41.
  122. # 8.1 - fileopen user cookies support (Tetrachroma)
  123.  
  124. 42.
  125. # 8.2 - fileopen user name/password support (Tetrachroma)
  126.  
  127. 43.
  128. # 8.3 - fileopen session cookie support (Tetrachroma)
  129.  
  130. 44.
  131. # 8.3.1 - fix for the "specified key file does not exist" error (Tetrachroma)
  132.  
  133. 45.
  134. # 8.3.2 - improved server result parsing (Tetrachroma)
  135.  
  136. 46.
  137. # 8.4 - Ident4D and encrypted Uuid support (Tetrachroma)
  138.  
  139. 47.
  140. # 8.4.1 - improved MAC address processing (Tetrachroma)
  141.  
  142. 48.
  143. # 8.4.2 - FowP3Uuid fallback file processing (Tetrachroma)
  144.  
  145. 49.
  146. # 8.4.3 - improved user/password pdf file detection (Tetrachroma)
  147.  
  148. 50.
  149. # 8.4.4 - small bugfix (Tetrachroma)
  150.  
  151. 51.
  152. # 8.4.5 - improved cookie host searching (Tetrachroma)
  153.  
  154. 52.
  155. # 8.4.6 - STRICT parsing disabled (non-standard pdf processing) (Tetrachroma)
  156.  
  157. 53.
  158. # 8.4.7 - UTF-8 input file conversion (Tetrachroma)
  159.  
  160. 54.
  161. # 8.4.8 - fix for more rare utf8 problems (Tetrachroma)
  162.  
  163. 55.
  164. # 8.4.9 - solution for utf8 in comination with
  165.  
  166. 56.
  167. # ident4id method (Tetrachroma)
  168.  
  169. 57.
  170. # 8.4.10 - line feed processing, non c system drive patch, nrbook support (Tetrachroma)
  171.  
  172. 58.
  173. # 8.4.11 - alternative ident4id calculation (Tetrachroma)
  174.  
  175. 59.
  176. # 8.4.12 - fix for capital username characters and
  177.  
  178. 60.
  179. # other unusual user login names (Tetrachroma & ZeroPoint)
  180.  
  181. 61.
  182. # 8.4.13 - small bug fixes (Tetrachroma)
  183.  
  184. 62.
  185. # 8.4.14 - fix for non-standard-conform fileopen pdfs (Tetrachroma)
  186.  
  187. 63.
  188. # 8.4.15 - 'bad file descriptor'-fix (Tetrachroma)
  189.  
  190. 64.
  191. # 8.4.16 - improves user/pass detection (Tetrachroma)
  192.  
  193. 65.
  194. # 8.4.17 - fix for several '=' chars in a DPRM entity (Tetrachroma)
  195.  
  196. 66.
  197. # 8.4.18 - follow up bug fix for the DPRM problem,
  198.  
  199. 67.
  200. # more readable error messages (Tetrachroma)
  201.  
  202. 68.
  203. # 8.4.19 - 2nd fix for 'bad file descriptor' problem (Tetrachroma)
  204.  
  205. 69.
  206. # 8.4.20 - follow up patch (Tetrachroma)
  207.  
  208. 70.
  209. # 8.4.21 - 3rd patch for 'bad file descriptor' (Tetrachroma)
  210.  
  211. 71.
  212. # 8.4.22 - disable prints for exception prevention (Tetrachroma)
  213.  
  214. 72.
  215. # 8.4.23 - check for additional security attributes (Tetrachroma)
  216.  
  217. 73.
  218. # 8.4.24 - improved cookie session support (Tetrachroma)
  219.  
  220. 74.
  221. # 8.4.25 - more compatibility with unicode files (Tetrachroma)
  222.  
  223. 75.
  224. # 8.4.26 - automated session/user cookie request function (works
  225.  
  226. 76.
  227. # only with Firefox 3.x+) (Tetrachroma)
  228.  
  229. 77.
  230. # 8.4.27 - user/password fallback
  231.  
  232. 78.
  233. # 8.4.28 - AES decryption, improved misconfigured pdf handling,
  234.  
  235. 79.
  236. # limited experimental APS support (Tetrachroma & Neisklar)
  237.  
  238. 80.
  239. # 8.4.29 - backport for bad formatted rc4 encrypted pdfs (Tetrachroma)
  240.  
  241. 81.
  242. # 8.4.30 - extended authorization attributes support (Tetrachroma)
  243.  
  244. 82.
  245. # 8.4.31 - improved session cookie and better server response error
  246.  
  247. 83.
  248. # handling (Tetrachroma)
  249.  
  250. 84.
  251. # 8.4.33 - small cookie optimizations (Tetrachroma)
  252.  
  253. 85.
  254. # 8.4.33 - debug output option (Tetrachroma)
  255.  
  256. 86.
  257. # 8.4.34 - better user/password management
  258.  
  259. 87.
  260. # handles the 'AskUnp' response) (Tetrachroma)
  261.  
  262. 88.
  263. # 8.4.35 - special handling for non-standard systems (Tetrachroma)
  264.  
  265. 89.
  266. # 8.4.36 - previous machine/disk handling [PrevMach/PrevDisk] (Tetrachroma)
  267.  
  268. 90.
  269. # 8.4.36 - FOPN_flock support (Tetrachroma)
  270.  
  271. 91.
  272. # 8.4.37 - patch for unicode paths/filenames (Tetrachroma)
  273.  
  274. 92.
  275. # 8.4.38 - small fix for user/password dialog (Tetrachroma)
  276.  
  277. 93.
  278. # 8.4.39 - sophisticated request mode differentiation, forced
  279.  
  280. 94.
  281. # uuid calculation (Tetrachroma)
  282.  
  283. 95.
  284. # 8.4.40 - fix for non standard server responses (Tetrachroma)
  285.  
  286. 96.
  287. # 8.4.41 - improved user/password request windows,
  288.  
  289. 97.
  290. # better server response tolerance (Tetrachroma)
  291.  
  292. 98.
  293. # 8.4.42 - improved nl/cr server response parsing (Tetrachroma)
  294.  
  295. 99.
  296. # 8.4.43 - fix for user names longer than 13 characters and special
  297.  
  298. 100.
  299. # uuid encryption (Tetrachroma)
  300.  
  301. 101.
  302. # 8.4.44 - another fix for ident4d problem (Tetrachroma)
  303.  
  304. 102.
  305. # 8.4.45 - 2nd fix for ident4d problem (Tetrachroma)
  306.  
  307. 103.
  308. # 8.4.46 - script cleanup and optimizations (Tetrachroma)
  309.  
  310. 104.
  311. # 8.4.47 - script identification change to Adobe Reader (Tetrachroma)
  312.  
  313. 105.
  314. # 8.4.48 - improved tolerance for false file/registry entries (Tetrachroma)
  315.  
  316. 106.
  317. # 8.4.49 - improved username encryption (Tetrachroma)
  318.  
  319. 107.
  320. # 8.4.50 - improved (experimental) APS support (Tetrachroma & Neisklar)
  321.  
  322. 108.
  323. # 8.4.51 - automatic APS offline key retrieval (works only for
  324.  
  325. 109.
  326. # Onleihe right now) (80ka80 & Tetrachroma)
  327.  
  328. 110.
  329.  
  330.  
  331. 111.
  332. """
  333.  
  334. 112.
  335. Decrypts Adobe ADEPT-encrypted and Fileopen PDF files.
  336.  
  337. 113.
  338. """
  339.  
  340. 114.
  341.  
  342.  
  343. 115.
  344. from __future__ import with_statement
  345.  
  346. 116.
  347.  
  348.  
  349. 117.
  350. __license__ = 'GPL v3'
  351.  
  352. 118.
  353.  
  354.  
  355. 119.
  356. import sys
  357.  
  358. 120.
  359. import os
  360.  
  361. 121.
  362. import re
  363.  
  364. 122.
  365. import zlib
  366.  
  367. 123.
  368. import struct
  369.  
  370. 124.
  371. import hashlib
  372.  
  373. 125.
  374. from itertools import chain, islice
  375.  
  376. 126.
  377. import xml.etree.ElementTree as etree
  378.  
  379. 127.
  380. import Tkinter
  381.  
  382. 128.
  383. import Tkconstants
  384.  
  385. 129.
  386. import tkFileDialog
  387.  
  388. 130.
  389. import tkMessageBox
  390.  
  391. 131.
  392. # added for fileopen support
  393.  
  394. 132.
  395. import urllib
  396.  
  397. 133.
  398. import urlparse
  399.  
  400. 134.
  401. import time
  402.  
  403. 135.
  404. import socket
  405.  
  406. 136.
  407. import string
  408.  
  409. 137.
  410. import uuid
  411.  
  412. 138.
  413. import subprocess
  414.  
  415. 139.
  416. import time
  417.  
  418. 140.
  419. import getpass
  420.  
  421. 141.
  422. from ctypes import *
  423.  
  424. 142.
  425. import traceback
  426.  
  427. 143.
  428. import inspect
  429.  
  430. 144.
  431. import tempfile
  432.  
  433. 145.
  434. import sqlite3
  435.  
  436. 146.
  437. import httplib
  438.  
  439. 147.
  440. try:
  441.  
  442. 148.
  443. from Crypto.Cipher import ARC4
  444.  
  445. 149.
  446. # needed for newer pdfs
  447.  
  448. 150.
  449. from Crypto.Cipher import AES
  450.  
  451. 151.
  452. from Crypto.Hash import SHA256
  453.  
  454. 152.
  455. from Crypto.PublicKey import RSA
  456.  
  457. 153.
  458.  
  459.  
  460. 154.
  461. except ImportError:
  462.  
  463. 155.
  464. ARC4 = None
  465.  
  466. 156.
  467. RSA = None
  468.  
  469. 157.
  470. try:
  471.  
  472. 158.
  473. from cStringIO import StringIO
  474.  
  475. 159.
  476. except ImportError:
  477.  
  478. 160.
  479. from StringIO import StringIO
  480.  
  481. 161.
  482.  
  483.  
  484. 162.
  485. class ADEPTError(Exception):
  486.  
  487. 163.
  488. pass
  489.  
  490. 164.
  491.  
  492.  
  493. 165.
  494. # global variable (needed for fileopen and password decryption)
  495.  
  496. 166.
  497. INPUTFILEPATH = ''
  498.  
  499. 167.
  500. KEYFILEPATH = ''
  501.  
  502. 168.
  503. PASSWORD = ''
  504.  
  505. 169.
  506. DEBUG_MODE = False
  507.  
  508. 170.
  509. IVERSION = '8.4.51'
  510.  
  511. 171.
  512.  
  513.  
  514. 172.
  515. # Do we generate cross reference streams on output?
  516.  
  517. 173.
  518. # 0 = never
  519.  
  520. 174.
  521. # 1 = only if present in input
  522.  
  523. 175.
  524. # 2 = always
  525.  
  526. 176.
  527.  
  528.  
  529. 177.
  530. GEN_XREF_STM = 1
  531.  
  532. 178.
  533.  
  534.  
  535. 179.
  536. # This is the value for the current document
  537.  
  538. 180.
  539. gen_xref_stm = False # will be set in PDFSerializer
  540.  
  541. 181.
  542.  
  543.  
  544. 182.
  545. ###
  546.  
  547. 183.
  548. ### ASN.1 parsing code from tlslite
  549.  
  550. 184.
  551.  
  552.  
  553. 185.
  554. def bytesToNumber(bytes):
  555.  
  556. 186.
  557. total = 0L
  558.  
  559. 187.
  560. for byte in bytes:
  561.  
  562. 188.
  563. total = (total << 8) + byte
  564.  
  565. 189.
  566. return total
  567.  
  568. 190.
  569.  
  570.  
  571. 191.
  572. class ASN1Error(Exception):
  573.  
  574. 192.
  575. pass
  576.  
  577. 193.
  578.  
  579.  
  580. 194.
  581. class ASN1Parser(object):
  582.  
  583. 195.
  584. class Parser(object):
  585.  
  586. 196.
  587. def __init__(self, bytes):
  588.  
  589. 197.
  590. self.bytes = bytes
  591.  
  592. 198.
  593. self.index = 0
  594.  
  595. 199.
  596.  
  597.  
  598. 200.
  599. def get(self, length):
  600.  
  601. 201.
  602. if self.index + length > len(self.bytes):
  603.  
  604. 202.
  605. raise ASN1Error("Error decoding ASN.1")
  606.  
  607. 203.
  608. x = 0
  609.  
  610. 204.
  611. for count in range(length):
  612.  
  613. 205.
  614. x <<= 8
  615.  
  616. 206.
  617. x |= self.bytes[self.index]
  618.  
  619. 207.
  620. self.index += 1
  621.  
  622. 208.
  623. return x
  624.  
  625. 209.
  626.  
  627.  
  628. 210.
  629. def getFixBytes(self, lengthBytes):
  630.  
  631. 211.
  632. bytes = self.bytes[self.index : self.index+lengthBytes]
  633.  
  634. 212.
  635. self.index += lengthBytes
  636.  
  637. 213.
  638. return bytes
  639.  
  640. 214.
  641.  
  642.  
  643. 215.
  644. def getVarBytes(self, lengthLength):
  645.  
  646. 216.
  647. lengthBytes = self.get(lengthLength)
  648.  
  649. 217.
  650. return self.getFixBytes(lengthBytes)
  651.  
  652. 218.
  653.  
  654.  
  655. 219.
  656. def getFixList(self, length, lengthList):
  657.  
  658. 220.
  659. l = [0] * lengthList
  660.  
  661. 221.
  662. for x in range(lengthList):
  663.  
  664. 222.
  665. l[x] = self.get(length)
  666.  
  667. 223.
  668. return l
  669.  
  670. 224.
  671.  
  672.  
  673. 225.
  674. def getVarList(self, length, lengthLength):
  675.  
  676. 226.
  677. lengthList = self.get(lengthLength)
  678.  
  679. 227.
  680. if lengthList % length != 0:
  681.  
  682. 228.
  683. raise ASN1Error("Error decoding ASN.1")
  684.  
  685. 229.
  686. lengthList = int(lengthList/length)
  687.  
  688. 230.
  689. l = [0] * lengthList
  690.  
  691. 231.
  692. for x in range(lengthList):
  693.  
  694. 232.
  695. l[x] = self.get(length)
  696.  
  697. 233.
  698. return l
  699.  
  700. 234.
  701.  
  702.  
  703. 235.
  704. def startLengthCheck(self, lengthLength):
  705.  
  706. 236.
  707. self.lengthCheck = self.get(lengthLength)
  708.  
  709. 237.
  710. self.indexCheck = self.index
  711.  
  712. 238.
  713.  
  714.  
  715. 239.
  716. def setLengthCheck(self, length):
  717.  
  718. 240.
  719. self.lengthCheck = length
  720.  
  721. 241.
  722. self.indexCheck = self.index
  723.  
  724. 242.
  725.  
  726.  
  727. 243.
  728. def stopLengthCheck(self):
  729.  
  730. 244.
  731. if (self.index - self.indexCheck) != self.lengthCheck:
  732.  
  733. 245.
  734. raise ASN1Error("Error decoding ASN.1")
  735.  
  736. 246.
  737.  
  738.  
  739. 247.
  740. def atLengthCheck(self):
  741.  
  742. 248.
  743. if (self.index - self.indexCheck) < self.lengthCheck:
  744.  
  745. 249.
  746. return False
  747.  
  748. 250.
  749. elif (self.index - self.indexCheck) == self.lengthCheck:
  750.  
  751. 251.
  752. return True
  753.  
  754. 252.
  755. else:
  756.  
  757. 253.
  758. raise ASN1Error("Error decoding ASN.1")
  759.  
  760. 254.
  761.  
  762.  
  763. 255.
  764. def __init__(self, bytes):
  765.  
  766. 256.
  767. p = self.Parser(bytes)
  768.  
  769. 257.
  770. p.get(1)
  771.  
  772. 258.
  773. self.length = self._getASN1Length(p)
  774.  
  775. 259.
  776. self.value = p.getFixBytes(self.length)
  777.  
  778. 260.
  779.  
  780.  
  781. 261.
  782. def getChild(self, which):
  783.  
  784. 262.
  785. p = self.Parser(self.value)
  786.  
  787. 263.
  788. for x in range(which+1):
  789.  
  790. 264.
  791. markIndex = p.index
  792.  
  793. 265.
  794. p.get(1)
  795.  
  796. 266.
  797. length = self._getASN1Length(p)
  798.  
  799. 267.
  800. p.getFixBytes(length)
  801.  
  802. 268.
  803. return ASN1Parser(p.bytes[markIndex:p.index])
  804.  
  805. 269.
  806.  
  807.  
  808. 270.
  809. def _getASN1Length(self, p):
  810.  
  811. 271.
  812. firstLength = p.get(1)
  813.  
  814. 272.
  815. if firstLength<=127:
  816.  
  817. 273.
  818. return firstLength
  819.  
  820. 274.
  821. else:
  822.  
  823. 275.
  824. lengthLength = firstLength & 0x7F
  825.  
  826. 276.
  827. return p.get(lengthLength)
  828.  
  829. 277.
  830.  
  831.  
  832. 278.
  833. ###
  834.  
  835. 279.
  836. ### PDF parsing routines from pdfminer, with changes for EBX_HANDLER
  837.  
  838. 280.
  839.  
  840.  
  841. 281.
  842. ## Utilities
  843.  
  844. 282.
  845. ##
  846.  
  847. 283.
  848. def choplist(n, seq):
  849.  
  850. 284.
  851. '''Groups every n elements of the list.'''
  852.  
  853. 285.
  854. r = []
  855.  
  856. 286.
  857. for x in seq:
  858.  
  859. 287.
  860. r.append(x)
  861.  
  862. 288.
  863. if len(r) == n:
  864.  
  865. 289.
  866. yield tuple(r)
  867.  
  868. 290.
  869. r = []
  870.  
  871. 291.
  872. return
  873.  
  874. 292.
  875.  
  876.  
  877. 293.
  878. def nunpack(s, default=0):
  879.  
  880. 294.
  881. '''Unpacks up to 4 bytes big endian.'''
  882.  
  883. 295.
  884. l = len(s)
  885.  
  886. 296.
  887. if not l:
  888.  
  889. 297.
  890. return default
  891.  
  892. 298.
  893. elif l == 1:
  894.  
  895. 299.
  896. return ord(s)
  897.  
  898. 300.
  899. elif l == 2:
  900.  
  901. 301.
  902. return struct.unpack('>H', s)[0]
  903.  
  904. 302.
  905. elif l == 3:
  906.  
  907. 303.
  908. return struct.unpack('>L', '\x00'+s)[0]
  909.  
  910. 304.
  911. elif l == 4:
  912.  
  913. 305.
  914. return struct.unpack('>L', s)[0]
  915.  
  916. 306.
  917. else:
  918.  
  919. 307.
  920. return TypeError('invalid length: %d' % l)
  921.  
  922. 308.
  923.  
  924.  
  925. 309.
  926.  
  927.  
  928. 310.
  929. STRICT = 0
  930.  
  931. 311.
  932.  
  933.  
  934. 312.
  935.  
  936.  
  937. 313.
  938. ## PS Exceptions
  939.  
  940. 314.
  941. ##
  942.  
  943. 315.
  944. class PSException(Exception): pass
  945.  
  946. 316.
  947. class PSEOF(PSException): pass
  948.  
  949. 317.
  950. class PSSyntaxError(PSException): pass
  951.  
  952. 318.
  953. class PSTypeError(PSException): pass
  954.  
  955. 319.
  956. class PSValueError(PSException): pass
  957.  
  958. 320.
  959.  
  960.  
  961. 321.
  962.  
  963.  
  964. 322.
  965. ## Basic PostScript Types
  966.  
  967. 323.
  968. ##
  969.  
  970. 324.
  971.  
  972.  
  973. 325.
  974. # PSLiteral
  975.  
  976. 326.
  977. class PSObject(object): pass
  978.  
  979. 327.
  980.  
  981.  
  982. 328.
  983. class PSLiteral(PSObject):
  984.  
  985. 329.
  986. '''
  987.  
  988. 330.
  989. PS literals (e.g. "/Name").
  990.  
  991. 331.
  992. Caution: Never create these objects directly.
  993.  
  994. 332.
  995. Use PSLiteralTable.intern() instead.
  996.  
  997. 333.
  998. '''
  999.  
  1000. 334.
  1001. def __init__(self, name):
  1002.  
  1003. 335.
  1004. self.name = name
  1005.  
  1006. 336.
  1007. return
  1008.  
  1009. 337.
  1010.  
  1011.  
  1012. 338.
  1013. def __repr__(self):
  1014.  
  1015. 339.
  1016. name = []
  1017.  
  1018. 340.
  1019. for char in self.name:
  1020.  
  1021. 341.
  1022. if not char.isalnum():
  1023.  
  1024. 342.
  1025. char = '#%02x' % ord(char)
  1026.  
  1027. 343.
  1028. name.append(char)
  1029.  
  1030. 344.
  1031. return '/%s' % ''.join(name)
  1032.  
  1033. 345.
  1034.  
  1035.  
  1036. 346.
  1037. # PSKeyword
  1038.  
  1039. 347.
  1040. class PSKeyword(PSObject):
  1041.  
  1042. 348.
  1043. '''
  1044.  
  1045. 349.
  1046. PS keywords (e.g. "showpage").
  1047.  
  1048. 350.
  1049. Caution: Never create these objects directly.
  1050.  
  1051. 351.
  1052. Use PSKeywordTable.intern() instead.
  1053.  
  1054. 352.
  1055. '''
  1056.  
  1057. 353.
  1058. def __init__(self, name):
  1059.  
  1060. 354.
  1061. self.name = name
  1062.  
  1063. 355.
  1064. return
  1065.  
  1066. 356.
  1067.  
  1068.  
  1069. 357.
  1070. def __repr__(self):
  1071.  
  1072. 358.
  1073. return self.name
  1074.  
  1075. 359.
  1076.  
  1077.  
  1078. 360.
  1079. # PSSymbolTable
  1080.  
  1081. 361.
  1082. class PSSymbolTable(object):
  1083.  
  1084. 362.
  1085.  
  1086.  
  1087. 363.
  1088. '''
  1089.  
  1090. 364.
  1091. Symbol table that stores PSLiteral or PSKeyword.
  1092.  
  1093. 365.
  1094. '''
  1095.  
  1096. 366.
  1097.  
  1098.  
  1099. 367.
  1100. def __init__(self, classe):
  1101.  
  1102. 368.
  1103. self.dic = {}
  1104.  
  1105. 369.
  1106. self.classe = classe
  1107.  
  1108. 370.
  1109. return
  1110.  
  1111. 371.
  1112.  
  1113.  
  1114. 372.
  1115. def intern(self, name):
  1116.  
  1117. 373.
  1118. if name in self.dic:
  1119.  
  1120. 374.
  1121. lit = self.dic[name]
  1122.  
  1123. 375.
  1124. else:
  1125.  
  1126. 376.
  1127. lit = self.classe(name)
  1128.  
  1129. 377.
  1130. self.dic[name] = lit
  1131.  
  1132. 378.
  1133. return lit
  1134.  
  1135. 379.
  1136.  
  1137.  
  1138. 380.
  1139. PSLiteralTable = PSSymbolTable(PSLiteral)
  1140.  
  1141. 381.
  1142. PSKeywordTable = PSSymbolTable(PSKeyword)
  1143.  
  1144. 382.
  1145. LIT = PSLiteralTable.intern
  1146.  
  1147. 383.
  1148. KWD = PSKeywordTable.intern
  1149.  
  1150. 384.
  1151. KEYWORD_BRACE_BEGIN = KWD('{')
  1152.  
  1153. 385.
  1154. KEYWORD_BRACE_END = KWD('}')
  1155.  
  1156. 386.
  1157. KEYWORD_ARRAY_BEGIN = KWD('[')
  1158.  
  1159. 387.
  1160. KEYWORD_ARRAY_END = KWD(']')
  1161.  
  1162. 388.
  1163. KEYWORD_DICT_BEGIN = KWD('<<')
  1164.  
  1165. 389.
  1166. KEYWORD_DICT_END = KWD('>>')
  1167.  
  1168. 390.
  1169.  
  1170.  
  1171. 391.
  1172.  
  1173.  
  1174. 392.
  1175. def literal_name(x):
  1176.  
  1177. 393.
  1178. if not isinstance(x, PSLiteral):
  1179.  
  1180. 394.
  1181. if STRICT:
  1182.  
  1183. 395.
  1184. raise PSTypeError('Literal required: %r' % x)
  1185.  
  1186. 396.
  1187. else:
  1188.  
  1189. 397.
  1190. return str(x)
  1191.  
  1192. 398.
  1193. return x.name
  1194.  
  1195. 399.
  1196.  
  1197.  
  1198. 400.
  1199. def keyword_name(x):
  1200.  
  1201. 401.
  1202. if not isinstance(x, PSKeyword):
  1203.  
  1204. 402.
  1205. if STRICT:
  1206.  
  1207. 403.
  1208. raise PSTypeError('Keyword required: %r' % x)
  1209.  
  1210. 404.
  1211. else:
  1212.  
  1213. 405.
  1214. return str(x)
  1215.  
  1216. 406.
  1217. return x.name
  1218.  
  1219. 407.
  1220.  
  1221.  
  1222. 408.
  1223.  
  1224.  
  1225. 409.
  1226. ## PSBaseParser
  1227.  
  1228. 410.
  1229. ##
  1230.  
  1231. 411.
  1232. EOL = re.compile(r'[\r\n]')
  1233.  
  1234. 412.
  1235. SPC = re.compile(r'\s')
  1236.  
  1237. 413.
  1238. NONSPC = re.compile(r'\S')
  1239.  
  1240. 414.
  1241. HEX = re.compile(r'[0-9a-fA-F]')
  1242.  
  1243. 415.
  1244. END_LITERAL = re.compile(r'[#/%\[\]()<>{}\s]')
  1245.  
  1246. 416.
  1247. END_HEX_STRING = re.compile(r'[^\s0-9a-fA-F]')
  1248.  
  1249. 417.
  1250. HEX_PAIR = re.compile(r'[0-9a-fA-F]{2}|.')
  1251.  
  1252. 418.
  1253. END_NUMBER = re.compile(r'[^0-9]')
  1254.  
  1255. 419.
  1256. END_KEYWORD = re.compile(r'[#/%\[\]()<>{}\s]')
  1257.  
  1258. 420.
  1259. END_STRING = re.compile(r'[()\134]')
  1260.  
  1261. 421.
  1262. OCT_STRING = re.compile(r'[0-7]')
  1263.  
  1264. 422.
  1265. ESC_STRING = { 'b':8, 't':9, 'n':10, 'f':12, 'r':13, '(':40, ')':41, '\\':92 }
  1266.  
  1267. 423.
  1268.  
  1269.  
  1270. 424.
  1271. class PSBaseParser(object):
  1272.  
  1273. 425.
  1274.  
  1275.  
  1276. 426.
  1277. '''
  1278.  
  1279. 427.
  1280. Most basic PostScript parser that performs only basic tokenization.
  1281.  
  1282. 428.
  1283. '''
  1284.  
  1285. 429.
  1286. BUFSIZ = 4096
  1287.  
  1288. 430.
  1289.  
  1290.  
  1291. 431.
  1292. def __init__(self, fp):
  1293.  
  1294. 432.
  1295. self.fp = fp
  1296.  
  1297. 433.
  1298. self.seek(0)
  1299.  
  1300. 434.
  1301. return
  1302.  
  1303. 435.
  1304.  
  1305.  
  1306. 436.
  1307. def __repr__(self):
  1308.  
  1309. 437.
  1310. return '<PSBaseParser: %r, bufpos=%d>' % (self.fp, self.bufpos)
  1311.  
  1312. 438.
  1313.  
  1314.  
  1315. 439.
  1316. def flush(self):
  1317.  
  1318. 440.
  1319. return
  1320.  
  1321. 441.
  1322.  
  1323.  
  1324. 442.
  1325. def close(self):
  1326.  
  1327. 443.
  1328. self.flush()
  1329.  
  1330. 444.
  1331. return
  1332.  
  1333. 445.
  1334.  
  1335.  
  1336. 446.
  1337. def tell(self):
  1338.  
  1339. 447.
  1340. return self.bufpos+self.charpos
  1341.  
  1342. 448.
  1343.  
  1344.  
  1345. 449.
  1346. def poll(self, pos=None, n=80):
  1347.  
  1348. 450.
  1349. pos0 = self.fp.tell()
  1350.  
  1351. 451.
  1352. if not pos:
  1353.  
  1354. 452.
  1355. pos = self.bufpos+self.charpos
  1356.  
  1357. 453.
  1358. self.fp.seek(pos)
  1359.  
  1360. 454.
  1361. ##print >>sys.stderr, 'poll(%d): %r' % (pos, self.fp.read(n))
  1362.  
  1363. 455.
  1364. self.fp.seek(pos0)
  1365.  
  1366. 456.
  1367. return
  1368.  
  1369. 457.
  1370.  
  1371.  
  1372. 458.
  1373. def seek(self, pos):
  1374.  
  1375. 459.
  1376. '''
  1377.  
  1378. 460.
  1379. Seeks the parser to the given position.
  1380.  
  1381. 461.
  1382. '''
  1383.  
  1384. 462.
  1385. self.fp.seek(pos)
  1386.  
  1387. 463.
  1388. # reset the status for nextline()
  1389.  
  1390. 464.
  1391. self.bufpos = pos
  1392.  
  1393. 465.
  1394. self.buf = ''
  1395.  
  1396. 466.
  1397. self.charpos = 0
  1398.  
  1399. 467.
  1400. # reset the status for nexttoken()
  1401.  
  1402. 468.
  1403. self.parse1 = self.parse_main
  1404.  
  1405. 469.
  1406. self.tokens = []
  1407.  
  1408. 470.
  1409. return
  1410.  
  1411. 471.
  1412.  
  1413.  
  1414. 472.
  1415. def fillbuf(self):
  1416.  
  1417. 473.
  1418. if self.charpos < len(self.buf): return
  1419.  
  1420. 474.
  1421. # fetch next chunk.
  1422.  
  1423. 475.
  1424. self.bufpos = self.fp.tell()
  1425.  
  1426. 476.
  1427. self.buf = self.fp.read(self.BUFSIZ)
  1428.  
  1429. 477.
  1430. if not self.buf:
  1431.  
  1432. 478.
  1433. raise PSEOF('Unexpected EOF')
  1434.  
  1435. 479.
  1436. self.charpos = 0
  1437.  
  1438. 480.
  1439. return
  1440.  
  1441. 481.
  1442.  
  1443.  
  1444. 482.
  1445. def parse_main(self, s, i):
  1446.  
  1447. 483.
  1448. m = NONSPC.search(s, i)
  1449.  
  1450. 484.
  1451. if not m:
  1452.  
  1453. 485.
  1454. return (self.parse_main, len(s))
  1455.  
  1456. 486.
  1457. j = m.start(0)
  1458.  
  1459. 487.
  1460. c = s[j]
  1461.  
  1462. 488.
  1463. self.tokenstart = self.bufpos+j
  1464.  
  1465. 489.
  1466. if c == '%':
  1467.  
  1468. 490.
  1469. self.token = '%'
  1470.  
  1471. 491.
  1472. return (self.parse_comment, j+1)
  1473.  
  1474. 492.
  1475. if c == '/':
  1476.  
  1477. 493.
  1478. self.token = ''
  1479.  
  1480. 494.
  1481. return (self.parse_literal, j+1)
  1482.  
  1483. 495.
  1484. if c in '-+' or c.isdigit():
  1485.  
  1486. 496.
  1487. self.token = c
  1488.  
  1489. 497.
  1490. return (self.parse_number, j+1)
  1491.  
  1492. 498.
  1493. if c == '.':
  1494.  
  1495. 499.
  1496. self.token = c
  1497.  
  1498. 500.
  1499. return (self.parse_float, j+1)
  1500.  
  1501. 501.
  1502. if c.isalpha():
  1503.  
  1504. 502.
  1505. self.token = c
  1506.  
  1507. 503.
  1508. return (self.parse_keyword, j+1)
  1509.  
  1510. 504.
  1511. if c == '(':
  1512.  
  1513. 505.
  1514. self.token = ''
  1515.  
  1516. 506.
  1517. self.paren = 1
  1518.  
  1519. 507.
  1520. return (self.parse_string, j+1)
  1521.  
  1522. 508.
  1523. if c == '<':
  1524.  
  1525. 509.
  1526. self.token = ''
  1527.  
  1528. 510.
  1529. return (self.parse_wopen, j+1)
  1530.  
  1531. 511.
  1532. if c == '>':
  1533.  
  1534. 512.
  1535. self.token = ''
  1536.  
  1537. 513.
  1538. return (self.parse_wclose, j+1)
  1539.  
  1540. 514.
  1541. self.add_token(KWD(c))
  1542.  
  1543. 515.
  1544. return (self.parse_main, j+1)
  1545.  
  1546. 516.
  1547.  
  1548.  
  1549. 517.
  1550. def add_token(self, obj):
  1551.  
  1552. 518.
  1553. self.tokens.append((self.tokenstart, obj))
  1554.  
  1555. 519.
  1556. return
  1557.  
  1558. 520.
  1559.  
  1560.  
  1561. 521.
  1562. def parse_comment(self, s, i):
  1563.  
  1564. 522.
  1565. m = EOL.search(s, i)
  1566.  
  1567. 523.
  1568. if not m:
  1569.  
  1570. 524.
  1571. self.token += s[i:]
  1572.  
  1573. 525.
  1574. return (self.parse_comment, len(s))
  1575.  
  1576. 526.
  1577. j = m.start(0)
  1578.  
  1579. 527.
  1580. self.token += s[i:j]
  1581.  
  1582. 528.
  1583. # We ignore comments.
  1584.  
  1585. 529.
  1586. #self.tokens.append(self.token)
  1587.  
  1588. 530.
  1589. return (self.parse_main, j)
  1590.  
  1591. 531.
  1592.  
  1593.  
  1594. 532.
  1595. def parse_literal(self, s, i):
  1596.  
  1597. 533.
  1598. m = END_LITERAL.search(s, i)
  1599.  
  1600. 534.
  1601. if not m:
  1602.  
  1603. 535.
  1604. self.token += s[i:]
  1605.  
  1606. 536.
  1607. return (self.parse_literal, len(s))
  1608.  
  1609. 537.
  1610. j = m.start(0)
  1611.  
  1612. 538.
  1613. self.token += s[i:j]
  1614.  
  1615. 539.
  1616. c = s[j]
  1617.  
  1618. 540.
  1619. if c == '#':
  1620.  
  1621. 541.
  1622. self.hex = ''
  1623.  
  1624. 542.
  1625. return (self.parse_literal_hex, j+1)
  1626.  
  1627. 543.
  1628. self.add_token(LIT(self.token))
  1629.  
  1630. 544.
  1631. return (self.parse_main, j)
  1632.  
  1633. 545.
  1634.  
  1635.  
  1636. 546.
  1637. def parse_literal_hex(self, s, i):
  1638.  
  1639. 547.
  1640. c = s[i]
  1641.  
  1642. 548.
  1643. if HEX.match(c) and len(self.hex) < 2:
  1644.  
  1645. 549.
  1646. self.hex += c
  1647.  
  1648. 550.
  1649. return (self.parse_literal_hex, i+1)
  1650.  
  1651. 551.
  1652. if self.hex:
  1653.  
  1654. 552.
  1655. self.token += chr(int(self.hex, 16))
  1656.  
  1657. 553.
  1658. return (self.parse_literal, i)
  1659.  
  1660. 554.
  1661.  
  1662.  
  1663. 555.
  1664. def parse_number(self, s, i):
  1665.  
  1666. 556.
  1667. m = END_NUMBER.search(s, i)
  1668.  
  1669. 557.
  1670. if not m:
  1671.  
  1672. 558.
  1673. self.token += s[i:]
  1674.  
  1675. 559.
  1676. return (self.parse_number, len(s))
  1677.  
  1678. 560.
  1679. j = m.start(0)
  1680.  
  1681. 561.
  1682. self.token += s[i:j]
  1683.  
  1684. 562.
  1685. c = s[j]
  1686.  
  1687. 563.
  1688. if c == '.':
  1689.  
  1690. 564.
  1691. self.token += c
  1692.  
  1693. 565.
  1694. return (self.parse_float, j+1)
  1695.  
  1696. 566.
  1697. try:
  1698.  
  1699. 567.
  1700. self.add_token(int(self.token))
  1701.  
  1702. 568.
  1703. except ValueError:
  1704.  
  1705. 569.
  1706. pass
  1707.  
  1708. 570.
  1709. return (self.parse_main, j)
  1710.  
  1711. 571.
  1712. def parse_float(self, s, i):
  1713.  
  1714. 572.
  1715. m = END_NUMBER.search(s, i)
  1716.  
  1717. 573.
  1718. if not m:
  1719.  
  1720. 574.
  1721. self.token += s[i:]
  1722.  
  1723. 575.
  1724. return (self.parse_float, len(s))
  1725.  
  1726. 576.
  1727. j = m.start(0)
  1728.  
  1729. 577.
  1730. self.token += s[i:j]
  1731.  
  1732. 578.
  1733. self.add_token(float(self.token))
  1734.  
  1735. 579.
  1736. return (self.parse_main, j)
  1737.  
  1738. 580.
  1739.  
  1740.  
  1741. 581.
  1742. def parse_keyword(self, s, i):
  1743.  
  1744. 582.
  1745. m = END_KEYWORD.search(s, i)
  1746.  
  1747. 583.
  1748. if not m:
  1749.  
  1750. 584.
  1751. self.token += s[i:]
  1752.  
  1753. 585.
  1754. return (self.parse_keyword, len(s))
  1755.  
  1756. 586.
  1757. j = m.start(0)
  1758.  
  1759. 587.
  1760. self.token += s[i:j]
  1761.  
  1762. 588.
  1763. if self.token == 'true':
  1764.  
  1765. 589.
  1766. token = True
  1767.  
  1768. 590.
  1769. elif self.token == 'false':
  1770.  
  1771. 591.
  1772. token = False
  1773.  
  1774. 592.
  1775. else:
  1776.  
  1777. 593.
  1778. token = KWD(self.token)
  1779.  
  1780. 594.
  1781. self.add_token(token)
  1782.  
  1783. 595.
  1784. return (self.parse_main, j)
  1785.  
  1786. 596.
  1787.  
  1788.  
  1789. 597.
  1790. def parse_string(self, s, i):
  1791.  
  1792. 598.
  1793. m = END_STRING.search(s, i)
  1794.  
  1795. 599.
  1796. if not m:
  1797.  
  1798. 600.
  1799. self.token += s[i:]
  1800.  
  1801. 601.
  1802. return (self.parse_string, len(s))
  1803.  
  1804. 602.
  1805. j = m.start(0)
  1806.  
  1807. 603.
  1808. self.token += s[i:j]
  1809.  
  1810. 604.
  1811. c = s[j]
  1812.  
  1813. 605.
  1814. if c == '\\':
  1815.  
  1816. 606.
  1817. self.oct = ''
  1818.  
  1819. 607.
  1820. return (self.parse_string_1, j+1)
  1821.  
  1822. 608.
  1823. if c == '(':
  1824.  
  1825. 609.
  1826. self.paren += 1
  1827.  
  1828. 610.
  1829. self.token += c
  1830.  
  1831. 611.
  1832. return (self.parse_string, j+1)
  1833.  
  1834. 612.
  1835. if c == ')':
  1836.  
  1837. 613.
  1838. self.paren -= 1
  1839.  
  1840. 614.
  1841. if self.paren:
  1842.  
  1843. 615.
  1844. self.token += c
  1845.  
  1846. 616.
  1847. return (self.parse_string, j+1)
  1848.  
  1849. 617.
  1850. self.add_token(self.token)
  1851.  
  1852. 618.
  1853. return (self.parse_main, j+1)
  1854.  
  1855. 619.
  1856. def parse_string_1(self, s, i):
  1857.  
  1858. 620.
  1859. c = s[i]
  1860.  
  1861. 621.
  1862. if OCT_STRING.match(c) and len(self.oct) < 3:
  1863.  
  1864. 622.
  1865. self.oct += c
  1866.  
  1867. 623.
  1868. return (self.parse_string_1, i+1)
  1869.  
  1870. 624.
  1871. if self.oct:
  1872.  
  1873. 625.
  1874. self.token += chr(int(self.oct, 8))
  1875.  
  1876. 626.
  1877. return (self.parse_string, i)
  1878.  
  1879. 627.
  1880. if c in ESC_STRING:
  1881.  
  1882. 628.
  1883. self.token += chr(ESC_STRING[c])
  1884.  
  1885. 629.
  1886. return (self.parse_string, i+1)
  1887.  
  1888. 630.
  1889.  
  1890.  
  1891. 631.
  1892. def parse_wopen(self, s, i):
  1893.  
  1894. 632.
  1895. c = s[i]
  1896.  
  1897. 633.
  1898. if c.isspace() or HEX.match(c):
  1899.  
  1900. 634.
  1901. return (self.parse_hexstring, i)
  1902.  
  1903. 635.
  1904. if c == '<':
  1905.  
  1906. 636.
  1907. self.add_token(KEYWORD_DICT_BEGIN)
  1908.  
  1909. 637.
  1910. i += 1
  1911.  
  1912. 638.
  1913. return (self.parse_main, i)
  1914.  
  1915. 639.
  1916.  
  1917.  
  1918. 640.
  1919. def parse_wclose(self, s, i):
  1920.  
  1921. 641.
  1922. c = s[i]
  1923.  
  1924. 642.
  1925. if c == '>':
  1926.  
  1927. 643.
  1928. self.add_token(KEYWORD_DICT_END)
  1929.  
  1930. 644.
  1931. i += 1
  1932.  
  1933. 645.
  1934. return (self.parse_main, i)
  1935.  
  1936. 646.
  1937.  
  1938.  
  1939. 647.
  1940. def parse_hexstring(self, s, i):
  1941.  
  1942. 648.
  1943. m = END_HEX_STRING.search(s, i)
  1944.  
  1945. 649.
  1946. if not m:
  1947.  
  1948. 650.
  1949. self.token += s[i:]
  1950.  
  1951. 651.
  1952. return (self.parse_hexstring, len(s))
  1953.  
  1954. 652.
  1955. j = m.start(0)
  1956.  
  1957. 653.
  1958. self.token += s[i:j]
  1959.  
  1960. 654.
  1961. token = HEX_PAIR.sub(lambda m: chr(int(m.group(0), 16)),
  1962.  
  1963. 655.
  1964. SPC.sub('', self.token))
  1965.  
  1966. 656.
  1967. self.add_token(token)
  1968.  
  1969. 657.
  1970. return (self.parse_main, j)
  1971.  
  1972. 658.
  1973.  
  1974.  
  1975. 659.
  1976. def nexttoken(self):
  1977.  
  1978. 660.
  1979. while not self.tokens:
  1980.  
  1981. 661.
  1982. self.fillbuf()
  1983.  
  1984. 662.
  1985. (self.parse1, self.charpos) = self.parse1(self.buf, self.charpos)
  1986.  
  1987. 663.
  1988. token = self.tokens.pop(0)
  1989.  
  1990. 664.
  1991. return token
  1992.  
  1993. 665.
  1994.  
  1995.  
  1996. 666.
  1997. def nextline(self):
  1998.  
  1999. 667.
  2000. '''
  2001.  
  2002. 668.
  2003. Fetches a next line that ends either with \\r or \\n.
  2004.  
  2005. 669.
  2006. '''
  2007.  
  2008. 670.
  2009. linebuf = ''
  2010.  
  2011. 671.
  2012. linepos = self.bufpos + self.charpos
  2013.  
  2014. 672.
  2015. eol = False
  2016.  
  2017. 673.
  2018. while 1:
  2019.  
  2020. 674.
  2021. self.fillbuf()
  2022.  
  2023. 675.
  2024. if eol:
  2025.  
  2026. 676.
  2027. c = self.buf[self.charpos]
  2028.  
  2029. 677.
  2030. # handle '\r\n'
  2031.  
  2032. 678.
  2033. if c == '\n':
  2034.  
  2035. 679.
  2036. linebuf += c
  2037.  
  2038. 680.
  2039. self.charpos += 1
  2040.  
  2041. 681.
  2042. break
  2043.  
  2044. 682.
  2045. m = EOL.search(self.buf, self.charpos)
  2046.  
  2047. 683.
  2048. if m:
  2049.  
  2050. 684.
  2051. linebuf += self.buf[self.charpos:m.end(0)]
  2052.  
  2053. 685.
  2054. self.charpos = m.end(0)
  2055.  
  2056. 686.
  2057. if linebuf[-1] == '\r':
  2058.  
  2059. 687.
  2060. eol = True
  2061.  
  2062. 688.
  2063. else:
  2064.  
  2065. 689.
  2066. break
  2067.  
  2068. 690.
  2069. else:
  2070.  
  2071. 691.
  2072. linebuf += self.buf[self.charpos:]
  2073.  
  2074. 692.
  2075. self.charpos = len(self.buf)
  2076.  
  2077. 693.
  2078. return (linepos, linebuf)
  2079.  
  2080. 694.
  2081.  
  2082.  
  2083. 695.
  2084. def revreadlines(self):
  2085.  
  2086. 696.
  2087. '''
  2088.  
  2089. 697.
  2090. Fetches a next line backword. This is used to locate
  2091.  
  2092. 698.
  2093. the trailers at the end of a file.
  2094.  
  2095. 699.
  2096. '''
  2097.  
  2098. 700.
  2099. self.fp.seek(0, 2)
  2100.  
  2101. 701.
  2102. pos = self.fp.tell()
  2103.  
  2104. 702.
  2105. buf = ''
  2106.  
  2107. 703.
  2108. while 0 < pos:
  2109.  
  2110. 704.
  2111. prevpos = pos
  2112.  
  2113. 705.
  2114. pos = max(0, pos-self.BUFSIZ)
  2115.  
  2116. 706.
  2117. self.fp.seek(pos)
  2118.  
  2119. 707.
  2120. s = self.fp.read(prevpos-pos)
  2121.  
  2122. 708.
  2123. if not s: break
  2124.  
  2125. 709.
  2126. while 1:
  2127.  
  2128. 710.
  2129. n = max(s.rfind('\r'), s.rfind('\n'))
  2130.  
  2131. 711.
  2132. if n == -1:
  2133.  
  2134. 712.
  2135. buf = s + buf
  2136.  
  2137. 713.
  2138. break
  2139.  
  2140. 714.
  2141. yield s[n:]+buf
  2142.  
  2143. 715.
  2144. s = s[:n]
  2145.  
  2146. 716.
  2147. buf = ''
  2148.  
  2149. 717.
  2150. return
  2151.  
  2152. 718.
  2153.  
  2154.  
  2155. 719.
  2156.  
  2157.  
  2158. 720.
  2159. ## PSStackParser
  2160.  
  2161. 721.
  2162. ##
  2163.  
  2164. 722.
  2165. class PSStackParser(PSBaseParser):
  2166.  
  2167. 723.
  2168.  
  2169.  
  2170. 724.
  2171. def __init__(self, fp):
  2172.  
  2173. 725.
  2174. PSBaseParser.__init__(self, fp)
  2175.  
  2176. 726.
  2177. self.reset()
  2178.  
  2179. 727.
  2180. return
  2181.  
  2182. 728.
  2183.  
  2184.  
  2185. 729.
  2186. def reset(self):
  2187.  
  2188. 730.
  2189. self.context = []
  2190.  
  2191. 731.
  2192. self.curtype = None
  2193.  
  2194. 732.
  2195. self.curstack = []
  2196.  
  2197. 733.
  2198. self.results = []
  2199.  
  2200. 734.
  2201. return
  2202.  
  2203. 735.
  2204.  
  2205.  
  2206. 736.
  2207. def seek(self, pos):
  2208.  
  2209. 737.
  2210. PSBaseParser.seek(self, pos)
  2211.  
  2212. 738.
  2213. self.reset()
  2214.  
  2215. 739.
  2216. return
  2217.  
  2218. 740.
  2219.  
  2220.  
  2221. 741.
  2222. def push(self, *objs):
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement