t1Lib.py revision 319c5fd10e2ea84304bd299b7483e05b5b0d5480
17842e56b97ce677b83bdab09cda48bc2d89ac75aJust"""fontTools.t1Lib.py -- Tools for PostScript Type 1 fonts 27842e56b97ce677b83bdab09cda48bc2d89ac75aJust 37842e56b97ce677b83bdab09cda48bc2d89ac75aJustFunctions for reading and writing raw Type 1 data: 47842e56b97ce677b83bdab09cda48bc2d89ac75aJust 57842e56b97ce677b83bdab09cda48bc2d89ac75aJustread(path) 67842e56b97ce677b83bdab09cda48bc2d89ac75aJust reads any Type 1 font file, returns the raw data and a type indicator: 77842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'LWFN', 'PFB' or 'OTHER', depending on the format of the file pointed 87842e56b97ce677b83bdab09cda48bc2d89ac75aJust to by 'path'. 97842e56b97ce677b83bdab09cda48bc2d89ac75aJust Raises an error when the file does not contain valid Type 1 data. 107842e56b97ce677b83bdab09cda48bc2d89ac75aJust 115810aa9967488207b039cb2d300fa53c91d4df2fJustwrite(path, data, kind='OTHER', dohex=0) 127842e56b97ce677b83bdab09cda48bc2d89ac75aJust writes raw Type 1 data to the file pointed to by 'path'. 137842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'kind' can be one of 'LWFN', 'PFB' or 'OTHER'; it defaults to 'OTHER'. 147842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'dohex' is a flag which determines whether the eexec encrypted 157842e56b97ce677b83bdab09cda48bc2d89ac75aJust part should be written as hexadecimal or binary, but only if kind 167842e56b97ce677b83bdab09cda48bc2d89ac75aJust is 'LWFN' or 'PFB'. 177842e56b97ce677b83bdab09cda48bc2d89ac75aJust""" 187842e56b97ce677b83bdab09cda48bc2d89ac75aJust 197842e56b97ce677b83bdab09cda48bc2d89ac75aJust__author__ = "jvr" 207842e56b97ce677b83bdab09cda48bc2d89ac75aJust__version__ = "1.0b2" 217842e56b97ce677b83bdab09cda48bc2d89ac75aJustDEBUG = 0 227842e56b97ce677b83bdab09cda48bc2d89ac75aJust 2332c10eecffb4923e0721c395e4b80fb732543f18Behdad Esfahbodfrom __future__ import print_function, division 2430e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodfrom fontTools.misc.py23 import * 25c2be3d982b04c4bbb1c11d9ab8452f78415d6522Justfrom fontTools.misc import eexec 2645d1f3b3b552297484bc2b8e9a2e999630bb5e50jvrfrom fontTools.misc.macCreatorType import getMacCreatorAndType 277842e56b97ce677b83bdab09cda48bc2d89ac75aJustimport os 2830e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodimport re 297842e56b97ce677b83bdab09cda48bc2d89ac75aJust 3022433b1f52c34a04cf13e21103ee978f7f5b501cjvr 3122433b1f52c34a04cf13e21103ee978f7f5b501cjvrtry: 3225ccb9c3460b05522eae9283a4c9ea783da87aa4jvr try: 3325ccb9c3460b05522eae9283a4c9ea783da87aa4jvr from Carbon import Res 3425ccb9c3460b05522eae9283a4c9ea783da87aa4jvr except ImportError: 3525ccb9c3460b05522eae9283a4c9ea783da87aa4jvr import Res # MacPython < 2.2 36e568dc77d3baccc303d5115e2686f126c96c8a26jvrexcept ImportError: 37e568dc77d3baccc303d5115e2686f126c96c8a26jvr haveMacSupport = 0 38e568dc77d3baccc303d5115e2686f126c96c8a26jvrelse: 39e568dc77d3baccc303d5115e2686f126c96c8a26jvr haveMacSupport = 1 40b19141e48930ddd3106a6fe303fa2e6b76d35f47jvr import MacOS 4159afba7684d4c2f7760be5dbc1aeffceb8ced46fjvr 427842e56b97ce677b83bdab09cda48bc2d89ac75aJust 43e568dc77d3baccc303d5115e2686f126c96c8a26jvrclass T1Error(Exception): pass 447842e56b97ce677b83bdab09cda48bc2d89ac75aJust 457842e56b97ce677b83bdab09cda48bc2d89ac75aJust 467842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass T1Font: 477842e56b97ce677b83bdab09cda48bc2d89ac75aJust 483618300613e796ff81abddde967b1092ac1dc915Just """Type 1 font class. 493618300613e796ff81abddde967b1092ac1dc915Just 503618300613e796ff81abddde967b1092ac1dc915Just Uses a minimal interpeter that supports just about enough PS to parse 513618300613e796ff81abddde967b1092ac1dc915Just Type 1 fonts. 527842e56b97ce677b83bdab09cda48bc2d89ac75aJust """ 537842e56b97ce677b83bdab09cda48bc2d89ac75aJust 547842e56b97ce677b83bdab09cda48bc2d89ac75aJust def __init__(self, path=None): 557842e56b97ce677b83bdab09cda48bc2d89ac75aJust if path is not None: 567842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.data, type = read(path) 577842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 587842e56b97ce677b83bdab09cda48bc2d89ac75aJust pass # XXX 597842e56b97ce677b83bdab09cda48bc2d89ac75aJust 607842e56b97ce677b83bdab09cda48bc2d89ac75aJust def saveAs(self, path, type): 618c74f4639a4494d9d84d1220cbe895de4ffb8aacjvr write(path, self.getData(), type) 627842e56b97ce677b83bdab09cda48bc2d89ac75aJust 637842e56b97ce677b83bdab09cda48bc2d89ac75aJust def getData(self): 643618300613e796ff81abddde967b1092ac1dc915Just # XXX Todo: if the data has been converted to Python object, 653618300613e796ff81abddde967b1092ac1dc915Just # recreate the PS stream 667842e56b97ce677b83bdab09cda48bc2d89ac75aJust return self.data 677842e56b97ce677b83bdab09cda48bc2d89ac75aJust 687d4b693627c128bea3ad0c6dd49e923fe5ca4947jvr def getGlyphSet(self): 697d4b693627c128bea3ad0c6dd49e923fe5ca4947jvr """Return a generic GlyphSet, which is a dict-like object 707d4b693627c128bea3ad0c6dd49e923fe5ca4947jvr mapping glyph names to glyph objects. The returned glyph objects 717d4b693627c128bea3ad0c6dd49e923fe5ca4947jvr have a .draw() method that supports the Pen protocol, and will 727d4b693627c128bea3ad0c6dd49e923fe5ca4947jvr have an attribute named 'width', but only *after* the .draw() method 737d4b693627c128bea3ad0c6dd49e923fe5ca4947jvr has been called. 747d4b693627c128bea3ad0c6dd49e923fe5ca4947jvr 757d4b693627c128bea3ad0c6dd49e923fe5ca4947jvr In the case of Type 1, the GlyphSet is simply the CharStrings dict. 767d4b693627c128bea3ad0c6dd49e923fe5ca4947jvr """ 777d4b693627c128bea3ad0c6dd49e923fe5ca4947jvr return self["CharStrings"] 787d4b693627c128bea3ad0c6dd49e923fe5ca4947jvr 797842e56b97ce677b83bdab09cda48bc2d89ac75aJust def __getitem__(self, key): 807842e56b97ce677b83bdab09cda48bc2d89ac75aJust if not hasattr(self, "font"): 817842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.parse() 823618300613e796ff81abddde967b1092ac1dc915Just return self.font[key] 837842e56b97ce677b83bdab09cda48bc2d89ac75aJust 847842e56b97ce677b83bdab09cda48bc2d89ac75aJust def parse(self): 85528614e6e254dfe3c501ff440c291c6c55de5e6fJust from fontTools.misc import psLib 86528614e6e254dfe3c501ff440c291c6c55de5e6fJust from fontTools.misc import psCharStrings 877842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.font = psLib.suckfont(self.data) 887842e56b97ce677b83bdab09cda48bc2d89ac75aJust charStrings = self.font["CharStrings"] 897842e56b97ce677b83bdab09cda48bc2d89ac75aJust lenIV = self.font["Private"].get("lenIV", 4) 907842e56b97ce677b83bdab09cda48bc2d89ac75aJust assert lenIV >= 0 91489d76a340845361def6af9ab7d9152f8e66f417jvr subrs = self.font["Private"]["Subrs"] 927842e56b97ce677b83bdab09cda48bc2d89ac75aJust for glyphName, charString in charStrings.items(): 93c2be3d982b04c4bbb1c11d9ab8452f78415d6522Just charString, R = eexec.decrypt(charString, 4330) 94489d76a340845361def6af9ab7d9152f8e66f417jvr charStrings[glyphName] = psCharStrings.T1CharString(charString[lenIV:], 95489d76a340845361def6af9ab7d9152f8e66f417jvr subrs=subrs) 967842e56b97ce677b83bdab09cda48bc2d89ac75aJust for i in range(len(subrs)): 97c2be3d982b04c4bbb1c11d9ab8452f78415d6522Just charString, R = eexec.decrypt(subrs[i], 4330) 98489d76a340845361def6af9ab7d9152f8e66f417jvr subrs[i] = psCharStrings.T1CharString(charString[lenIV:], subrs=subrs) 997842e56b97ce677b83bdab09cda48bc2d89ac75aJust del self.data 1007842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1017842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1023618300613e796ff81abddde967b1092ac1dc915Just# low level T1 data read and write functions 1037842e56b97ce677b83bdab09cda48bc2d89ac75aJust 10410fd22a9890ce20091a20e70660677db779d4b64jvrdef read(path, onlyHeader=0): 1057842e56b97ce677b83bdab09cda48bc2d89ac75aJust """reads any Type 1 font file, returns raw data""" 10614fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod normpath = path.lower() 10745d1f3b3b552297484bc2b8e9a2e999630bb5e50jvr creator, type = getMacCreatorAndType(path) 10845d1f3b3b552297484bc2b8e9a2e999630bb5e50jvr if type == 'LWFN': 10945d1f3b3b552297484bc2b8e9a2e999630bb5e50jvr return readLWFN(path, onlyHeader), 'LWFN' 1107842e56b97ce677b83bdab09cda48bc2d89ac75aJust if normpath[-4:] == '.pfb': 11110fd22a9890ce20091a20e70660677db779d4b64jvr return readPFB(path, onlyHeader), 'PFB' 1127842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 1135810aa9967488207b039cb2d300fa53c91d4df2fJust return readOther(path), 'OTHER' 1147842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1157842e56b97ce677b83bdab09cda48bc2d89ac75aJustdef write(path, data, kind='OTHER', dohex=0): 1165810aa9967488207b039cb2d300fa53c91d4df2fJust assertType1(data) 11714fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod kind = kind.upper() 1187842e56b97ce677b83bdab09cda48bc2d89ac75aJust try: 1197842e56b97ce677b83bdab09cda48bc2d89ac75aJust os.remove(path) 1207842e56b97ce677b83bdab09cda48bc2d89ac75aJust except os.error: 1217842e56b97ce677b83bdab09cda48bc2d89ac75aJust pass 1227842e56b97ce677b83bdab09cda48bc2d89ac75aJust err = 1 1237842e56b97ce677b83bdab09cda48bc2d89ac75aJust try: 1247842e56b97ce677b83bdab09cda48bc2d89ac75aJust if kind == 'LWFN': 1255810aa9967488207b039cb2d300fa53c91d4df2fJust writeLWFN(path, data) 1267842e56b97ce677b83bdab09cda48bc2d89ac75aJust elif kind == 'PFB': 1275810aa9967488207b039cb2d300fa53c91d4df2fJust writePFB(path, data) 1287842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 1295810aa9967488207b039cb2d300fa53c91d4df2fJust writeOther(path, data, dohex) 1307842e56b97ce677b83bdab09cda48bc2d89ac75aJust err = 0 1317842e56b97ce677b83bdab09cda48bc2d89ac75aJust finally: 1327842e56b97ce677b83bdab09cda48bc2d89ac75aJust if err and not DEBUG: 1337842e56b97ce677b83bdab09cda48bc2d89ac75aJust try: 1347842e56b97ce677b83bdab09cda48bc2d89ac75aJust os.remove(path) 1357842e56b97ce677b83bdab09cda48bc2d89ac75aJust except os.error: 1367842e56b97ce677b83bdab09cda48bc2d89ac75aJust pass 1377842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1387842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1397842e56b97ce677b83bdab09cda48bc2d89ac75aJust# -- internal -- 1407842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1417842e56b97ce677b83bdab09cda48bc2d89ac75aJustLWFNCHUNKSIZE = 2000 1427842e56b97ce677b83bdab09cda48bc2d89ac75aJustHEXLINELENGTH = 80 1437842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1447842e56b97ce677b83bdab09cda48bc2d89ac75aJust 145da0d805d2603dd9b83c695006521f887b68d5505jvrdef readLWFN(path, onlyHeader=0): 1467842e56b97ce677b83bdab09cda48bc2d89ac75aJust """reads an LWFN font file, returns raw data""" 14791bca4244286fb519c93fe92329da96b0e6f32eejvr resRef = Res.FSOpenResFile(path, 1) # read-only 1487842e56b97ce677b83bdab09cda48bc2d89ac75aJust try: 149e9601bf9e1253f77b8a66f27685fae453ce98b14Just Res.UseResFile(resRef) 1507842e56b97ce677b83bdab09cda48bc2d89ac75aJust n = Res.Count1Resources('POST') 1517842e56b97ce677b83bdab09cda48bc2d89ac75aJust data = [] 1527842e56b97ce677b83bdab09cda48bc2d89ac75aJust for i in range(501, 501 + n): 1537842e56b97ce677b83bdab09cda48bc2d89ac75aJust res = Res.Get1Resource('POST', i) 154319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod code = byteord(res.data[0]) 155319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod if byteord(res.data[1]) != 0: 156cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise T1Error('corrupt LWFN file') 1577842e56b97ce677b83bdab09cda48bc2d89ac75aJust if code in [1, 2]: 158da0d805d2603dd9b83c695006521f887b68d5505jvr if onlyHeader and code == 2: 159da0d805d2603dd9b83c695006521f887b68d5505jvr break 16005a16f2310e26193557a3dc223ac0efeb166789fjvr data.append(res.data[2:]) 1617842e56b97ce677b83bdab09cda48bc2d89ac75aJust elif code in [3, 5]: 1627842e56b97ce677b83bdab09cda48bc2d89ac75aJust break 1637842e56b97ce677b83bdab09cda48bc2d89ac75aJust elif code == 4: 1647842e56b97ce677b83bdab09cda48bc2d89ac75aJust f = open(path, "rb") 1657842e56b97ce677b83bdab09cda48bc2d89ac75aJust data.append(f.read()) 1667842e56b97ce677b83bdab09cda48bc2d89ac75aJust f.close() 1677842e56b97ce677b83bdab09cda48bc2d89ac75aJust elif code == 0: 1687842e56b97ce677b83bdab09cda48bc2d89ac75aJust pass # comment, ignore 1697842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 170dc7e6f3e5563a853477ebe26166b002c158dbe8bBehdad Esfahbod raise T1Error('bad chunk code: ' + repr(code)) 1717842e56b97ce677b83bdab09cda48bc2d89ac75aJust finally: 172e9601bf9e1253f77b8a66f27685fae453ce98b14Just Res.CloseResFile(resRef) 17314fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod data = ''.join(data) 1745810aa9967488207b039cb2d300fa53c91d4df2fJust assertType1(data) 1757842e56b97ce677b83bdab09cda48bc2d89ac75aJust return data 1767842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1775810aa9967488207b039cb2d300fa53c91d4df2fJustdef readPFB(path, onlyHeader=0): 1787842e56b97ce677b83bdab09cda48bc2d89ac75aJust """reads a PFB font file, returns raw data""" 1797842e56b97ce677b83bdab09cda48bc2d89ac75aJust f = open(path, "rb") 1807842e56b97ce677b83bdab09cda48bc2d89ac75aJust data = [] 181ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod while True: 182b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod if f.read(1) != bytechr(128): 183cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise T1Error('corrupt PFB file') 184319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod code = byteord(f.read(1)) 1857842e56b97ce677b83bdab09cda48bc2d89ac75aJust if code in [1, 2]: 1865810aa9967488207b039cb2d300fa53c91d4df2fJust chunklen = stringToLong(f.read(4)) 1873618300613e796ff81abddde967b1092ac1dc915Just chunk = f.read(chunklen) 1883618300613e796ff81abddde967b1092ac1dc915Just assert len(chunk) == chunklen 1893618300613e796ff81abddde967b1092ac1dc915Just data.append(chunk) 1907842e56b97ce677b83bdab09cda48bc2d89ac75aJust elif code == 3: 1917842e56b97ce677b83bdab09cda48bc2d89ac75aJust break 1927842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 193dc7e6f3e5563a853477ebe26166b002c158dbe8bBehdad Esfahbod raise T1Error('bad chunk code: ' + repr(code)) 1945810aa9967488207b039cb2d300fa53c91d4df2fJust if onlyHeader: 1955810aa9967488207b039cb2d300fa53c91d4df2fJust break 1967842e56b97ce677b83bdab09cda48bc2d89ac75aJust f.close() 19714fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod data = ''.join(data) 1985810aa9967488207b039cb2d300fa53c91d4df2fJust assertType1(data) 1997842e56b97ce677b83bdab09cda48bc2d89ac75aJust return data 2007842e56b97ce677b83bdab09cda48bc2d89ac75aJust 2015810aa9967488207b039cb2d300fa53c91d4df2fJustdef readOther(path): 2027842e56b97ce677b83bdab09cda48bc2d89ac75aJust """reads any (font) file, returns raw data""" 2037842e56b97ce677b83bdab09cda48bc2d89ac75aJust f = open(path, "rb") 2047842e56b97ce677b83bdab09cda48bc2d89ac75aJust data = f.read() 2057842e56b97ce677b83bdab09cda48bc2d89ac75aJust f.close() 2065810aa9967488207b039cb2d300fa53c91d4df2fJust assertType1(data) 2077842e56b97ce677b83bdab09cda48bc2d89ac75aJust 2085810aa9967488207b039cb2d300fa53c91d4df2fJust chunks = findEncryptedChunks(data) 2097842e56b97ce677b83bdab09cda48bc2d89ac75aJust data = [] 2105810aa9967488207b039cb2d300fa53c91d4df2fJust for isEncrypted, chunk in chunks: 2115810aa9967488207b039cb2d300fa53c91d4df2fJust if isEncrypted and isHex(chunk[:4]): 2125810aa9967488207b039cb2d300fa53c91d4df2fJust data.append(deHexString(chunk)) 2137842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 2147842e56b97ce677b83bdab09cda48bc2d89ac75aJust data.append(chunk) 21514fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod return ''.join(data) 2167842e56b97ce677b83bdab09cda48bc2d89ac75aJust 2177842e56b97ce677b83bdab09cda48bc2d89ac75aJust# file writing tools 2187842e56b97ce677b83bdab09cda48bc2d89ac75aJust 2195810aa9967488207b039cb2d300fa53c91d4df2fJustdef writeLWFN(path, data): 220e9601bf9e1253f77b8a66f27685fae453ce98b14Just Res.FSpCreateResFile(path, "just", "LWFN", 0) 22191bca4244286fb519c93fe92329da96b0e6f32eejvr resRef = Res.FSOpenResFile(path, 2) # write-only 2227842e56b97ce677b83bdab09cda48bc2d89ac75aJust try: 223e9601bf9e1253f77b8a66f27685fae453ce98b14Just Res.UseResFile(resRef) 2247842e56b97ce677b83bdab09cda48bc2d89ac75aJust resID = 501 2255810aa9967488207b039cb2d300fa53c91d4df2fJust chunks = findEncryptedChunks(data) 2265810aa9967488207b039cb2d300fa53c91d4df2fJust for isEncrypted, chunk in chunks: 2275810aa9967488207b039cb2d300fa53c91d4df2fJust if isEncrypted: 2287842e56b97ce677b83bdab09cda48bc2d89ac75aJust code = 2 2297842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 2307842e56b97ce677b83bdab09cda48bc2d89ac75aJust code = 1 2317842e56b97ce677b83bdab09cda48bc2d89ac75aJust while chunk: 232b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod res = Res.Resource(bytechr(code) + '\0' + chunk[:LWFNCHUNKSIZE - 2]) 2337842e56b97ce677b83bdab09cda48bc2d89ac75aJust res.AddResource('POST', resID, '') 2347842e56b97ce677b83bdab09cda48bc2d89ac75aJust chunk = chunk[LWFNCHUNKSIZE - 2:] 2357842e56b97ce677b83bdab09cda48bc2d89ac75aJust resID = resID + 1 236b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod res = Res.Resource(bytechr(5) + '\0') 2377842e56b97ce677b83bdab09cda48bc2d89ac75aJust res.AddResource('POST', resID, '') 2387842e56b97ce677b83bdab09cda48bc2d89ac75aJust finally: 239e9601bf9e1253f77b8a66f27685fae453ce98b14Just Res.CloseResFile(resRef) 2407842e56b97ce677b83bdab09cda48bc2d89ac75aJust 2415810aa9967488207b039cb2d300fa53c91d4df2fJustdef writePFB(path, data): 2425810aa9967488207b039cb2d300fa53c91d4df2fJust chunks = findEncryptedChunks(data) 2433618300613e796ff81abddde967b1092ac1dc915Just f = open(path, "wb") 2447842e56b97ce677b83bdab09cda48bc2d89ac75aJust try: 2455810aa9967488207b039cb2d300fa53c91d4df2fJust for isEncrypted, chunk in chunks: 2465810aa9967488207b039cb2d300fa53c91d4df2fJust if isEncrypted: 2477842e56b97ce677b83bdab09cda48bc2d89ac75aJust code = 2 2487842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 2497842e56b97ce677b83bdab09cda48bc2d89ac75aJust code = 1 250b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod f.write(bytechr(128) + bytechr(code)) 2515810aa9967488207b039cb2d300fa53c91d4df2fJust f.write(longToString(len(chunk))) 2527842e56b97ce677b83bdab09cda48bc2d89ac75aJust f.write(chunk) 253b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod f.write(bytechr(128) + bytechr(3)) 2547842e56b97ce677b83bdab09cda48bc2d89ac75aJust finally: 2557842e56b97ce677b83bdab09cda48bc2d89ac75aJust f.close() 2567842e56b97ce677b83bdab09cda48bc2d89ac75aJust 2575810aa9967488207b039cb2d300fa53c91d4df2fJustdef writeOther(path, data, dohex = 0): 2585810aa9967488207b039cb2d300fa53c91d4df2fJust chunks = findEncryptedChunks(data) 2597842e56b97ce677b83bdab09cda48bc2d89ac75aJust f = open(path, "wb") 2607842e56b97ce677b83bdab09cda48bc2d89ac75aJust try: 26132c10eecffb4923e0721c395e4b80fb732543f18Behdad Esfahbod hexlinelen = HEXLINELENGTH // 2 2625810aa9967488207b039cb2d300fa53c91d4df2fJust for isEncrypted, chunk in chunks: 2635810aa9967488207b039cb2d300fa53c91d4df2fJust if isEncrypted: 2647842e56b97ce677b83bdab09cda48bc2d89ac75aJust code = 2 2657842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 2667842e56b97ce677b83bdab09cda48bc2d89ac75aJust code = 1 2677842e56b97ce677b83bdab09cda48bc2d89ac75aJust if code == 2 and dohex: 2687842e56b97ce677b83bdab09cda48bc2d89ac75aJust while chunk: 269c2be3d982b04c4bbb1c11d9ab8452f78415d6522Just f.write(eexec.hexString(chunk[:hexlinelen])) 2707842e56b97ce677b83bdab09cda48bc2d89ac75aJust f.write('\r') 2717842e56b97ce677b83bdab09cda48bc2d89ac75aJust chunk = chunk[hexlinelen:] 2727842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 2737842e56b97ce677b83bdab09cda48bc2d89ac75aJust f.write(chunk) 2747842e56b97ce677b83bdab09cda48bc2d89ac75aJust finally: 2757842e56b97ce677b83bdab09cda48bc2d89ac75aJust f.close() 2767842e56b97ce677b83bdab09cda48bc2d89ac75aJust 2777842e56b97ce677b83bdab09cda48bc2d89ac75aJust 2787842e56b97ce677b83bdab09cda48bc2d89ac75aJust# decryption tools 2797842e56b97ce677b83bdab09cda48bc2d89ac75aJust 2807842e56b97ce677b83bdab09cda48bc2d89ac75aJustEEXECBEGIN = "currentfile eexec" 2817842e56b97ce677b83bdab09cda48bc2d89ac75aJustEEXECEND = '0' * 64 2827842e56b97ce677b83bdab09cda48bc2d89ac75aJustEEXECINTERNALEND = "currentfile closefile" 2837842e56b97ce677b83bdab09cda48bc2d89ac75aJustEEXECBEGINMARKER = "%-- eexec start\r" 2847842e56b97ce677b83bdab09cda48bc2d89ac75aJustEEXECENDMARKER = "%-- eexec end\r" 2857842e56b97ce677b83bdab09cda48bc2d89ac75aJust 2867842e56b97ce677b83bdab09cda48bc2d89ac75aJust_ishexRE = re.compile('[0-9A-Fa-f]*$') 2877842e56b97ce677b83bdab09cda48bc2d89ac75aJust 2885810aa9967488207b039cb2d300fa53c91d4df2fJustdef isHex(text): 2897842e56b97ce677b83bdab09cda48bc2d89ac75aJust return _ishexRE.match(text) is not None 2907842e56b97ce677b83bdab09cda48bc2d89ac75aJust 2917842e56b97ce677b83bdab09cda48bc2d89ac75aJust 2925810aa9967488207b039cb2d300fa53c91d4df2fJustdef decryptType1(data): 2935810aa9967488207b039cb2d300fa53c91d4df2fJust chunks = findEncryptedChunks(data) 2947842e56b97ce677b83bdab09cda48bc2d89ac75aJust data = [] 2955810aa9967488207b039cb2d300fa53c91d4df2fJust for isEncrypted, chunk in chunks: 2965810aa9967488207b039cb2d300fa53c91d4df2fJust if isEncrypted: 2975810aa9967488207b039cb2d300fa53c91d4df2fJust if isHex(chunk[:4]): 2985810aa9967488207b039cb2d300fa53c91d4df2fJust chunk = deHexString(chunk) 299c2be3d982b04c4bbb1c11d9ab8452f78415d6522Just decrypted, R = eexec.decrypt(chunk, 55665) 3007842e56b97ce677b83bdab09cda48bc2d89ac75aJust decrypted = decrypted[4:] 301180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod if decrypted[-len(EEXECINTERNALEND)-1:-1] != EEXECINTERNALEND \ 302180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod and decrypted[-len(EEXECINTERNALEND)-2:-2] != EEXECINTERNALEND: 303cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise T1Error("invalid end of eexec part") 3047842e56b97ce677b83bdab09cda48bc2d89ac75aJust decrypted = decrypted[:-len(EEXECINTERNALEND)-2] + '\r' 3057842e56b97ce677b83bdab09cda48bc2d89ac75aJust data.append(EEXECBEGINMARKER + decrypted + EEXECENDMARKER) 3067842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 3077842e56b97ce677b83bdab09cda48bc2d89ac75aJust if chunk[-len(EEXECBEGIN)-1:-1] == EEXECBEGIN: 3087842e56b97ce677b83bdab09cda48bc2d89ac75aJust data.append(chunk[:-len(EEXECBEGIN)-1]) 3097842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 3107842e56b97ce677b83bdab09cda48bc2d89ac75aJust data.append(chunk) 31114fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod return ''.join(data) 3127842e56b97ce677b83bdab09cda48bc2d89ac75aJust 3135810aa9967488207b039cb2d300fa53c91d4df2fJustdef findEncryptedChunks(data): 3147842e56b97ce677b83bdab09cda48bc2d89ac75aJust chunks = [] 315ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod while True: 31614fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod eBegin = data.find(EEXECBEGIN) 3175810aa9967488207b039cb2d300fa53c91d4df2fJust if eBegin < 0: 3187842e56b97ce677b83bdab09cda48bc2d89ac75aJust break 31990290b7bd9d8d1e31d98637126aafc7dd8d0dfacjvr eBegin = eBegin + len(EEXECBEGIN) + 1 32014fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod eEnd = data.find(EEXECEND, eBegin) 3215810aa9967488207b039cb2d300fa53c91d4df2fJust if eEnd < 0: 322cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise T1Error("can't find end of eexec part") 323db1f2800e1fe8eedb102c997e9f133ed74b3af13jvr cypherText = data[eBegin:eEnd + 2] 324e56bc902cf6a707349ae6ddfe8a83a1bd7b155b9jvr if isHex(cypherText[:4]): 325e56bc902cf6a707349ae6ddfe8a83a1bd7b155b9jvr cypherText = deHexString(cypherText) 326db1f2800e1fe8eedb102c997e9f133ed74b3af13jvr plainText, R = eexec.decrypt(cypherText, 55665) 32714fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod eEndLocal = plainText.find(EEXECINTERNALEND) 328db1f2800e1fe8eedb102c997e9f133ed74b3af13jvr if eEndLocal < 0: 329cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise T1Error("can't find end of eexec part") 33090290b7bd9d8d1e31d98637126aafc7dd8d0dfacjvr chunks.append((0, data[:eBegin])) 331e56bc902cf6a707349ae6ddfe8a83a1bd7b155b9jvr chunks.append((1, cypherText[:eEndLocal + len(EEXECINTERNALEND) + 1])) 3325810aa9967488207b039cb2d300fa53c91d4df2fJust data = data[eEnd:] 3337842e56b97ce677b83bdab09cda48bc2d89ac75aJust chunks.append((0, data)) 3347842e56b97ce677b83bdab09cda48bc2d89ac75aJust return chunks 3357842e56b97ce677b83bdab09cda48bc2d89ac75aJust 3365810aa9967488207b039cb2d300fa53c91d4df2fJustdef deHexString(hexstring): 33714fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod return eexec.deHexString(''.join(hexstring.split())) 3387842e56b97ce677b83bdab09cda48bc2d89ac75aJust 3397842e56b97ce677b83bdab09cda48bc2d89ac75aJust 3407842e56b97ce677b83bdab09cda48bc2d89ac75aJust# Type 1 assertion 3417842e56b97ce677b83bdab09cda48bc2d89ac75aJust 3427842e56b97ce677b83bdab09cda48bc2d89ac75aJust_fontType1RE = re.compile(r"/FontType\s+1\s+def") 3437842e56b97ce677b83bdab09cda48bc2d89ac75aJust 3445810aa9967488207b039cb2d300fa53c91d4df2fJustdef assertType1(data): 345e56bc902cf6a707349ae6ddfe8a83a1bd7b155b9jvr for head in ['%!PS-AdobeFont', '%!FontType1']: 3467842e56b97ce677b83bdab09cda48bc2d89ac75aJust if data[:len(head)] == head: 3477842e56b97ce677b83bdab09cda48bc2d89ac75aJust break 3487842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 349cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise T1Error("not a PostScript font") 3507842e56b97ce677b83bdab09cda48bc2d89ac75aJust if not _fontType1RE.search(data): 351cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise T1Error("not a Type 1 font") 35214fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod if data.find("currentfile eexec") < 0: 353cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise T1Error("not an encrypted Type 1 font") 3547842e56b97ce677b83bdab09cda48bc2d89ac75aJust # XXX what else? 3557842e56b97ce677b83bdab09cda48bc2d89ac75aJust return data 3567842e56b97ce677b83bdab09cda48bc2d89ac75aJust 3577842e56b97ce677b83bdab09cda48bc2d89ac75aJust 3587842e56b97ce677b83bdab09cda48bc2d89ac75aJust# pfb helpers 3597842e56b97ce677b83bdab09cda48bc2d89ac75aJust 3605810aa9967488207b039cb2d300fa53c91d4df2fJustdef longToString(long): 3617842e56b97ce677b83bdab09cda48bc2d89ac75aJust str = "" 3627842e56b97ce677b83bdab09cda48bc2d89ac75aJust for i in range(4): 363b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod str = str + bytechr((long & (0xff << (i * 8))) >> i * 8) 3647842e56b97ce677b83bdab09cda48bc2d89ac75aJust return str 3657842e56b97ce677b83bdab09cda48bc2d89ac75aJust 3665810aa9967488207b039cb2d300fa53c91d4df2fJustdef stringToLong(str): 367180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod if len(str) != 4: 368cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise ValueError('string must be 4 bytes long') 3697842e56b97ce677b83bdab09cda48bc2d89ac75aJust long = 0 3707842e56b97ce677b83bdab09cda48bc2d89ac75aJust for i in range(4): 371319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod long = long + (byteord(str[i]) << (i * 8)) 3727842e56b97ce677b83bdab09cda48bc2d89ac75aJust return long 3735810aa9967488207b039cb2d300fa53c91d4df2fJust 374