17842e56b97ce677b83bdab09cda48bc2d89ac75aJust"""cffLib.py -- read/write tools for Adobe CFF fonts.""" 27842e56b97ce677b83bdab09cda48bc2d89ac75aJust 31ae29591efbb29492ce05378909ccf4028d7c1eeBehdad Esfahbodfrom __future__ import print_function, division, absolute_import 430e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodfrom fontTools.misc.py23 import * 58413c108d21e8cf0e9059bbfffde8d13f2616340Behdad Esfahbodfrom fontTools.misc import sstruct 6528614e6e254dfe3c501ff440c291c6c55de5e6fJustfrom fontTools.misc import psCharStrings 74e5af60930726d06a58a30bae45bb27ae50aea77jvrfrom fontTools.misc.textTools import safeEval 830e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodimport struct 92a9b86816e7a1b64d755e208a839b01a7a7ce903Behdad Esfahbod 10767102ea85a8af1535c169b2e04da5ba458f3b80jvrDEBUG = 0 11767102ea85a8af1535c169b2e04da5ba458f3b80jvr 12767102ea85a8af1535c169b2e04da5ba458f3b80jvr 137842e56b97ce677b83bdab09cda48bc2d89ac75aJustcffHeaderFormat = """ 147842e56b97ce677b83bdab09cda48bc2d89ac75aJust major: B 157842e56b97ce677b83bdab09cda48bc2d89ac75aJust minor: B 167842e56b97ce677b83bdab09cda48bc2d89ac75aJust hdrSize: B 177842e56b97ce677b83bdab09cda48bc2d89ac75aJust offSize: B 187842e56b97ce677b83bdab09cda48bc2d89ac75aJust""" 197842e56b97ce677b83bdab09cda48bc2d89ac75aJust 20e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass CFFFontSet(object): 217842e56b97ce677b83bdab09cda48bc2d89ac75aJust 227842e56b97ce677b83bdab09cda48bc2d89ac75aJust def __init__(self): 234756b3a04014645ee16a14fb6273e93efa1c7e15jvr pass 247842e56b97ce677b83bdab09cda48bc2d89ac75aJust 254e5af60930726d06a58a30bae45bb27ae50aea77jvr def decompile(self, file, otFont): 26a2a75b348da46073cdd1dea50915384eabfff7c9jvr sstruct.unpack(cffHeaderFormat, file.read(4), self) 277842e56b97ce677b83bdab09cda48bc2d89ac75aJust assert self.major == 1 and self.minor == 0, \ 287842e56b97ce677b83bdab09cda48bc2d89ac75aJust "unknown CFF format: %d.%d" % (self.major, self.minor) 297842e56b97ce677b83bdab09cda48bc2d89ac75aJust 30f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr file.seek(self.hdrSize) 314e5af60930726d06a58a30bae45bb27ae50aea77jvr self.fontNames = list(Index(file)) 324756b3a04014645ee16a14fb6273e93efa1c7e15jvr self.topDictIndex = TopDictIndex(file) 33767102ea85a8af1535c169b2e04da5ba458f3b80jvr self.strings = IndexedStrings(file) 344e5af60930726d06a58a30bae45bb27ae50aea77jvr self.GlobalSubrs = GlobalSubrsIndex(file) 354756b3a04014645ee16a14fb6273e93efa1c7e15jvr self.topDictIndex.strings = self.strings 36016ca76e918ed36888c0fa8e287028ea367ef3d9jvr self.topDictIndex.GlobalSubrs = self.GlobalSubrs 374756b3a04014645ee16a14fb6273e93efa1c7e15jvr 384756b3a04014645ee16a14fb6273e93efa1c7e15jvr def __len__(self): 394756b3a04014645ee16a14fb6273e93efa1c7e15jvr return len(self.fontNames) 404756b3a04014645ee16a14fb6273e93efa1c7e15jvr 414756b3a04014645ee16a14fb6273e93efa1c7e15jvr def keys(self): 42ce522410f26648af01372cc96fe689cf3b3a7c84jvr return list(self.fontNames) 434756b3a04014645ee16a14fb6273e93efa1c7e15jvr 44767102ea85a8af1535c169b2e04da5ba458f3b80jvr def values(self): 45767102ea85a8af1535c169b2e04da5ba458f3b80jvr return self.topDictIndex 46767102ea85a8af1535c169b2e04da5ba458f3b80jvr 474756b3a04014645ee16a14fb6273e93efa1c7e15jvr def __getitem__(self, name): 484756b3a04014645ee16a14fb6273e93efa1c7e15jvr try: 494756b3a04014645ee16a14fb6273e93efa1c7e15jvr index = self.fontNames.index(name) 504756b3a04014645ee16a14fb6273e93efa1c7e15jvr except ValueError: 51cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise KeyError(name) 52016ca76e918ed36888c0fa8e287028ea367ef3d9jvr return self.topDictIndex[index] 537842e56b97ce677b83bdab09cda48bc2d89ac75aJust 544e5af60930726d06a58a30bae45bb27ae50aea77jvr def compile(self, file, otFont): 557842e56b97ce677b83bdab09cda48bc2d89ac75aJust strings = IndexedStrings() 56f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr writer = CFFWriter() 57f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr writer.add(sstruct.pack(cffHeaderFormat, self)) 58f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr fontNames = Index() 59f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for name in self.fontNames: 60f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr fontNames.append(name) 61f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr writer.add(fontNames.getCompiler(strings, None)) 62f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr topCompiler = self.topDictIndex.getCompiler(strings, None) 63f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr writer.add(topCompiler) 64f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr writer.add(strings.getCompiler()) 65f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr writer.add(self.GlobalSubrs.getCompiler(strings, None)) 66f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 674e5af60930726d06a58a30bae45bb27ae50aea77jvr for topDict in self.topDictIndex: 684e5af60930726d06a58a30bae45bb27ae50aea77jvr if not hasattr(topDict, "charset") or topDict.charset is None: 694e5af60930726d06a58a30bae45bb27ae50aea77jvr charset = otFont.getGlyphOrder() 704e5af60930726d06a58a30bae45bb27ae50aea77jvr topDict.charset = charset 714e5af60930726d06a58a30bae45bb27ae50aea77jvr 72f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for child in topCompiler.getChildren(strings): 73f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr writer.add(child) 74f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 75f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr writer.toFile(file) 767842e56b97ce677b83bdab09cda48bc2d89ac75aJust 777842e56b97ce677b83bdab09cda48bc2d89ac75aJust def toXML(self, xmlWriter, progress=None): 787842e56b97ce677b83bdab09cda48bc2d89ac75aJust for fontName in self.fontNames: 79024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod xmlWriter.begintag("CFFFont", name=tostr(fontName)) 807842e56b97ce677b83bdab09cda48bc2d89ac75aJust xmlWriter.newline() 814756b3a04014645ee16a14fb6273e93efa1c7e15jvr font = self[fontName] 827842e56b97ce677b83bdab09cda48bc2d89ac75aJust font.toXML(xmlWriter, progress) 837842e56b97ce677b83bdab09cda48bc2d89ac75aJust xmlWriter.endtag("CFFFont") 847842e56b97ce677b83bdab09cda48bc2d89ac75aJust xmlWriter.newline() 857842e56b97ce677b83bdab09cda48bc2d89ac75aJust xmlWriter.newline() 867842e56b97ce677b83bdab09cda48bc2d89ac75aJust xmlWriter.begintag("GlobalSubrs") 877842e56b97ce677b83bdab09cda48bc2d89ac75aJust xmlWriter.newline() 884756b3a04014645ee16a14fb6273e93efa1c7e15jvr self.GlobalSubrs.toXML(xmlWriter, progress) 897842e56b97ce677b83bdab09cda48bc2d89ac75aJust xmlWriter.endtag("GlobalSubrs") 907842e56b97ce677b83bdab09cda48bc2d89ac75aJust xmlWriter.newline() 917842e56b97ce677b83bdab09cda48bc2d89ac75aJust 923a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def fromXML(self, name, attrs, content): 934e5af60930726d06a58a30bae45bb27ae50aea77jvr if not hasattr(self, "GlobalSubrs"): 944e5af60930726d06a58a30bae45bb27ae50aea77jvr self.GlobalSubrs = GlobalSubrsIndex() 954e5af60930726d06a58a30bae45bb27ae50aea77jvr self.major = 1 964e5af60930726d06a58a30bae45bb27ae50aea77jvr self.minor = 0 974e5af60930726d06a58a30bae45bb27ae50aea77jvr self.hdrSize = 4 984e5af60930726d06a58a30bae45bb27ae50aea77jvr self.offSize = 4 # XXX ?? 994e5af60930726d06a58a30bae45bb27ae50aea77jvr if name == "CFFFont": 1004e5af60930726d06a58a30bae45bb27ae50aea77jvr if not hasattr(self, "fontNames"): 1014e5af60930726d06a58a30bae45bb27ae50aea77jvr self.fontNames = [] 1024e5af60930726d06a58a30bae45bb27ae50aea77jvr self.topDictIndex = TopDictIndex() 1034e5af60930726d06a58a30bae45bb27ae50aea77jvr fontName = attrs["name"] 1044e5af60930726d06a58a30bae45bb27ae50aea77jvr topDict = TopDict(GlobalSubrs=self.GlobalSubrs) 1054e5af60930726d06a58a30bae45bb27ae50aea77jvr topDict.charset = None # gets filled in later 1064e5af60930726d06a58a30bae45bb27ae50aea77jvr self.fontNames.append(fontName) 1074e5af60930726d06a58a30bae45bb27ae50aea77jvr self.topDictIndex.append(topDict) 1084e5af60930726d06a58a30bae45bb27ae50aea77jvr for element in content: 1092a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr if isinstance(element, basestring): 1104e5af60930726d06a58a30bae45bb27ae50aea77jvr continue 1113a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod name, attrs, content = element 1123a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod topDict.fromXML(name, attrs, content) 1134e5af60930726d06a58a30bae45bb27ae50aea77jvr elif name == "GlobalSubrs": 1144e5af60930726d06a58a30bae45bb27ae50aea77jvr for element in content: 1152a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr if isinstance(element, basestring): 1164e5af60930726d06a58a30bae45bb27ae50aea77jvr continue 1174e5af60930726d06a58a30bae45bb27ae50aea77jvr name, attrs, content = element 118489d76a340845361def6af9ab7d9152f8e66f417jvr subr = psCharStrings.T2CharString() 1193a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod subr.fromXML(name, attrs, content) 1204e5af60930726d06a58a30bae45bb27ae50aea77jvr self.GlobalSubrs.append(subr) 1217842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1227842e56b97ce677b83bdab09cda48bc2d89ac75aJust 123e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass CFFWriter(object): 124f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 125f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def __init__(self): 126f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.data = [] 127f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 128f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def add(self, table): 129f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.data.append(table) 130f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 131f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def toFile(self, file): 132f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr lastPosList = None 133f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr count = 1 134ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod while True: 1354e5af60930726d06a58a30bae45bb27ae50aea77jvr if DEBUG: 1363ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print("CFFWriter.toFile() iteration:", count) 1374e5af60930726d06a58a30bae45bb27ae50aea77jvr count = count + 1 138f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr pos = 0 139f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr posList = [pos] 140f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for item in self.data: 141f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if hasattr(item, "getDataLength"): 1424e5af60930726d06a58a30bae45bb27ae50aea77jvr endPos = pos + item.getDataLength() 143f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr else: 1444e5af60930726d06a58a30bae45bb27ae50aea77jvr endPos = pos + len(item) 1454e5af60930726d06a58a30bae45bb27ae50aea77jvr if hasattr(item, "setPos"): 1464e5af60930726d06a58a30bae45bb27ae50aea77jvr item.setPos(pos, endPos) 1474e5af60930726d06a58a30bae45bb27ae50aea77jvr pos = endPos 148f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr posList.append(pos) 149f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if posList == lastPosList: 150f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr break 151f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr lastPosList = posList 1524e5af60930726d06a58a30bae45bb27ae50aea77jvr if DEBUG: 1533ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print("CFFWriter.toFile() writing to file.") 154f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr begin = file.tell() 155f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr posList = [0] 156f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for item in self.data: 157f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if hasattr(item, "toFile"): 158f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr item.toFile(file) 159f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr else: 160f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr file.write(item) 161f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr posList.append(file.tell() - begin) 162f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr assert posList == lastPosList 163f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 164f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 165f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef calcOffSize(largestOffset): 166f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if largestOffset < 0x100: 167f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr offSize = 1 168f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr elif largestOffset < 0x10000: 169f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr offSize = 2 170f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr elif largestOffset < 0x1000000: 171f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr offSize = 3 172f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr else: 173f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr offSize = 4 174f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return offSize 175f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 176f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 177e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass IndexCompiler(object): 178f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 179f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def __init__(self, items, strings, parent): 180f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.items = self.getItems(items, strings) 181f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.parent = parent 182f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 183f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def getItems(self, items, strings): 184f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return items 185f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 186f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def getOffsets(self): 187f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr pos = 1 188f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr offsets = [pos] 189f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for item in self.items: 190f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if hasattr(item, "getDataLength"): 191f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr pos = pos + item.getDataLength() 192f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr else: 193f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr pos = pos + len(item) 194f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr offsets.append(pos) 195f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return offsets 196f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 197f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def getDataLength(self): 198f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr lastOffset = self.getOffsets()[-1] 199f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr offSize = calcOffSize(lastOffset) 200f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr dataLength = ( 201f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 2 + # count 202f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1 + # offSize 203f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr (len(self.items) + 1) * offSize + # the offsets 204f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr lastOffset - 1 # size of object data 205f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr ) 206f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return dataLength 207f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 208f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def toFile(self, file): 209f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr offsets = self.getOffsets() 210f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr writeCard16(file, len(self.items)) 211f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr offSize = calcOffSize(offsets[-1]) 212f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr writeCard8(file, offSize) 213f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr offSize = -offSize 214f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr pack = struct.pack 215f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for offset in offsets: 216f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr binOffset = pack(">l", offset)[offSize:] 217f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr assert len(binOffset) == -offSize 218f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr file.write(binOffset) 219f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for item in self.items: 220f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if hasattr(item, "toFile"): 221f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr item.toFile(file) 222f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr else: 22385a64db5419991b228478b866eb4262df7055cb2Behdad Esfahbod file.write(tobytes(item, encoding="latin1")) 224f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 225f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 226f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass IndexedStringsCompiler(IndexCompiler): 227f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 228f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def getItems(self, items, strings): 229f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return items.strings 230f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 231f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 232f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass TopDictIndexCompiler(IndexCompiler): 233f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 234f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def getItems(self, items, strings): 235f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr out = [] 236f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for item in items: 237f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr out.append(item.getCompiler(strings, self)) 238f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return out 239f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 240f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def getChildren(self, strings): 241f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr children = [] 242f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for topDict in self.items: 243f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr children.extend(topDict.getChildren(strings)) 244f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return children 245f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 246f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 247ed10151701a7d22e5ff4e06766edff59bd713c89jvrclass FDArrayIndexCompiler(IndexCompiler): 248ed10151701a7d22e5ff4e06766edff59bd713c89jvr 249ed10151701a7d22e5ff4e06766edff59bd713c89jvr def getItems(self, items, strings): 250ed10151701a7d22e5ff4e06766edff59bd713c89jvr out = [] 251ed10151701a7d22e5ff4e06766edff59bd713c89jvr for item in items: 252ed10151701a7d22e5ff4e06766edff59bd713c89jvr out.append(item.getCompiler(strings, self)) 253ed10151701a7d22e5ff4e06766edff59bd713c89jvr return out 254ed10151701a7d22e5ff4e06766edff59bd713c89jvr 255ed10151701a7d22e5ff4e06766edff59bd713c89jvr def getChildren(self, strings): 256ed10151701a7d22e5ff4e06766edff59bd713c89jvr children = [] 257ed10151701a7d22e5ff4e06766edff59bd713c89jvr for fontDict in self.items: 258ed10151701a7d22e5ff4e06766edff59bd713c89jvr children.extend(fontDict.getChildren(strings)) 259ed10151701a7d22e5ff4e06766edff59bd713c89jvr return children 260ed10151701a7d22e5ff4e06766edff59bd713c89jvr 261ed10151701a7d22e5ff4e06766edff59bd713c89jvr def toFile(self, file): 262ed10151701a7d22e5ff4e06766edff59bd713c89jvr offsets = self.getOffsets() 263ed10151701a7d22e5ff4e06766edff59bd713c89jvr writeCard16(file, len(self.items)) 264ed10151701a7d22e5ff4e06766edff59bd713c89jvr offSize = calcOffSize(offsets[-1]) 265ed10151701a7d22e5ff4e06766edff59bd713c89jvr writeCard8(file, offSize) 266ed10151701a7d22e5ff4e06766edff59bd713c89jvr offSize = -offSize 267ed10151701a7d22e5ff4e06766edff59bd713c89jvr pack = struct.pack 268ed10151701a7d22e5ff4e06766edff59bd713c89jvr for offset in offsets: 269ed10151701a7d22e5ff4e06766edff59bd713c89jvr binOffset = pack(">l", offset)[offSize:] 270ed10151701a7d22e5ff4e06766edff59bd713c89jvr assert len(binOffset) == -offSize 271ed10151701a7d22e5ff4e06766edff59bd713c89jvr file.write(binOffset) 272ed10151701a7d22e5ff4e06766edff59bd713c89jvr for item in self.items: 273ed10151701a7d22e5ff4e06766edff59bd713c89jvr if hasattr(item, "toFile"): 274ed10151701a7d22e5ff4e06766edff59bd713c89jvr item.toFile(file) 275ed10151701a7d22e5ff4e06766edff59bd713c89jvr else: 276ed10151701a7d22e5ff4e06766edff59bd713c89jvr file.write(item) 277ed10151701a7d22e5ff4e06766edff59bd713c89jvr 278ed10151701a7d22e5ff4e06766edff59bd713c89jvr def setPos(self, pos, endPos): 279ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.parent.rawDict["FDArray"] = pos 280ed10151701a7d22e5ff4e06766edff59bd713c89jvr 281ed10151701a7d22e5ff4e06766edff59bd713c89jvr 282f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass GlobalSubrsCompiler(IndexCompiler): 283f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def getItems(self, items, strings): 284f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr out = [] 285f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for cs in items: 286f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr cs.compile() 287f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr out.append(cs.bytecode) 288f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return out 289f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 290f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass SubrsCompiler(GlobalSubrsCompiler): 2914e5af60930726d06a58a30bae45bb27ae50aea77jvr def setPos(self, pos, endPos): 292f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr offset = pos - self.parent.pos 293f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.parent.rawDict["Subrs"] = offset 294f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 295f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass CharStringsCompiler(GlobalSubrsCompiler): 2964e5af60930726d06a58a30bae45bb27ae50aea77jvr def setPos(self, pos, endPos): 297f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.parent.rawDict["CharStrings"] = pos 298f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 299f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 300e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass Index(object): 3017842e56b97ce677b83bdab09cda48bc2d89ac75aJust 3024756b3a04014645ee16a14fb6273e93efa1c7e15jvr """This class represents what the CFF spec calls an INDEX.""" 3037842e56b97ce677b83bdab09cda48bc2d89ac75aJust 304f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr compilerClass = IndexCompiler 305f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 3064e5af60930726d06a58a30bae45bb27ae50aea77jvr def __init__(self, file=None): 3074e5af60930726d06a58a30bae45bb27ae50aea77jvr name = self.__class__.__name__ 308f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if file is None: 309f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.items = [] 310f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return 311767102ea85a8af1535c169b2e04da5ba458f3b80jvr if DEBUG: 3123ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print("loading %s at %s" % (name, file.tell())) 3131890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr self.file = file 314a2ad5447fb707448d2c442b16956f87e048ef0d1jvr count = readCard16(file) 3151890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr self.count = count 3164756b3a04014645ee16a14fb6273e93efa1c7e15jvr self.items = [None] * count 3171890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr if count == 0: 318f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.items = [] 3191890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr return 320a2ad5447fb707448d2c442b16956f87e048ef0d1jvr offSize = readCard8(file) 321767102ea85a8af1535c169b2e04da5ba458f3b80jvr if DEBUG: 3223ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print(" index count: %s offSize: %s" % (count, offSize)) 323767102ea85a8af1535c169b2e04da5ba458f3b80jvr assert offSize <= 4, "offSize too large: %s" % offSize 3241890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr self.offsets = offsets = [] 32518316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod pad = b'\0' * (4 - offSize) 3261890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr for index in range(count+1): 3271890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr chunk = file.read(offSize) 3281890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr chunk = pad + chunk 3291890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr offset, = struct.unpack(">L", chunk) 3301890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr offsets.append(int(offset)) 3311890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr self.offsetBase = file.tell() - 1 3324756b3a04014645ee16a14fb6273e93efa1c7e15jvr file.seek(self.offsetBase + offsets[-1]) # pretend we've read the whole lot 333f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if DEBUG: 3343ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print(" end of %s at %s" % (name, file.tell())) 3351890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 3361890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr def __len__(self): 337f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return len(self.items) 3381890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 3391890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr def __getitem__(self, index): 3404756b3a04014645ee16a14fb6273e93efa1c7e15jvr item = self.items[index] 3414756b3a04014645ee16a14fb6273e93efa1c7e15jvr if item is not None: 3424756b3a04014645ee16a14fb6273e93efa1c7e15jvr return item 3431890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr offset = self.offsets[index] + self.offsetBase 3441890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr size = self.offsets[index+1] - self.offsets[index] 3454756b3a04014645ee16a14fb6273e93efa1c7e15jvr file = self.file 3464756b3a04014645ee16a14fb6273e93efa1c7e15jvr file.seek(offset) 3474756b3a04014645ee16a14fb6273e93efa1c7e15jvr data = file.read(size) 3484756b3a04014645ee16a14fb6273e93efa1c7e15jvr assert len(data) == size 349a2ad5447fb707448d2c442b16956f87e048ef0d1jvr item = self.produceItem(index, data, file, offset, size) 3504756b3a04014645ee16a14fb6273e93efa1c7e15jvr self.items[index] = item 3514756b3a04014645ee16a14fb6273e93efa1c7e15jvr return item 3521890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 353a2ad5447fb707448d2c442b16956f87e048ef0d1jvr def produceItem(self, index, data, file, offset, size): 3544756b3a04014645ee16a14fb6273e93efa1c7e15jvr return data 355f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 356f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def append(self, item): 357f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.items.append(item) 358f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 359f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def getCompiler(self, strings, parent): 360f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return self.compilerClass(self, strings, parent) 3611890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 3621890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 363f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass GlobalSubrsIndex(Index): 364f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 365f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr compilerClass = GlobalSubrsCompiler 3664756b3a04014645ee16a14fb6273e93efa1c7e15jvr 3674e5af60930726d06a58a30bae45bb27ae50aea77jvr def __init__(self, file=None, globalSubrs=None, private=None, fdSelect=None, fdArray=None): 3684e5af60930726d06a58a30bae45bb27ae50aea77jvr Index.__init__(self, file) 369a2ad5447fb707448d2c442b16956f87e048ef0d1jvr self.globalSubrs = globalSubrs 370a2ad5447fb707448d2c442b16956f87e048ef0d1jvr self.private = private 371ed10151701a7d22e5ff4e06766edff59bd713c89jvr if fdSelect: 372ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.fdSelect = fdSelect 373ed10151701a7d22e5ff4e06766edff59bd713c89jvr if fdArray: 374ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.fdArray = fdArray 375a2ad5447fb707448d2c442b16956f87e048ef0d1jvr 376a2ad5447fb707448d2c442b16956f87e048ef0d1jvr def produceItem(self, index, data, file, offset, size): 377a2ad5447fb707448d2c442b16956f87e048ef0d1jvr if self.private is not None: 378a2ad5447fb707448d2c442b16956f87e048ef0d1jvr private = self.private 379ed10151701a7d22e5ff4e06766edff59bd713c89jvr elif hasattr(self, 'fdArray') and self.fdArray is not None: 380a2ad5447fb707448d2c442b16956f87e048ef0d1jvr private = self.fdArray[self.fdSelect[index]].Private 381a2ad5447fb707448d2c442b16956f87e048ef0d1jvr else: 382a2ad5447fb707448d2c442b16956f87e048ef0d1jvr private = None 383489d76a340845361def6af9ab7d9152f8e66f417jvr return psCharStrings.T2CharString(data, private=private, globalSubrs=self.globalSubrs) 3844756b3a04014645ee16a14fb6273e93efa1c7e15jvr 3854756b3a04014645ee16a14fb6273e93efa1c7e15jvr def toXML(self, xmlWriter, progress): 386ed10151701a7d22e5ff4e06766edff59bd713c89jvr xmlWriter.comment("The 'index' attribute is only for humans; it is ignored when parsed.") 3874e5af60930726d06a58a30bae45bb27ae50aea77jvr xmlWriter.newline() 3884756b3a04014645ee16a14fb6273e93efa1c7e15jvr for i in range(len(self)): 389b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr subr = self[i] 390b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr if subr.needsDecompilation(): 391b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr xmlWriter.begintag("CharString", index=i, raw=1) 392b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr else: 393b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr xmlWriter.begintag("CharString", index=i) 3944756b3a04014645ee16a14fb6273e93efa1c7e15jvr xmlWriter.newline() 395b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr subr.toXML(xmlWriter) 3964756b3a04014645ee16a14fb6273e93efa1c7e15jvr xmlWriter.endtag("CharString") 3974756b3a04014645ee16a14fb6273e93efa1c7e15jvr xmlWriter.newline() 398a2ad5447fb707448d2c442b16956f87e048ef0d1jvr 3993a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def fromXML(self, name, attrs, content): 400180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod if name != "CharString": 4014e5af60930726d06a58a30bae45bb27ae50aea77jvr return 402489d76a340845361def6af9ab7d9152f8e66f417jvr subr = psCharStrings.T2CharString() 4033a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod subr.fromXML(name, attrs, content) 4044e5af60930726d06a58a30bae45bb27ae50aea77jvr self.append(subr) 4054e5af60930726d06a58a30bae45bb27ae50aea77jvr 406a2ad5447fb707448d2c442b16956f87e048ef0d1jvr def getItemAndSelector(self, index): 407ed10151701a7d22e5ff4e06766edff59bd713c89jvr sel = None 408ed10151701a7d22e5ff4e06766edff59bd713c89jvr if hasattr(self, 'fdSelect'): 409ed10151701a7d22e5ff4e06766edff59bd713c89jvr sel = self.fdSelect[index] 410a2ad5447fb707448d2c442b16956f87e048ef0d1jvr return self[index], sel 411f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 412e2ca9b5a4ff537ad827c3f722c8137b4f986d9a5jvr 413f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass SubrsIndex(GlobalSubrsIndex): 414f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr compilerClass = SubrsCompiler 415f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 4164756b3a04014645ee16a14fb6273e93efa1c7e15jvr 417767102ea85a8af1535c169b2e04da5ba458f3b80jvrclass TopDictIndex(Index): 418a2ad5447fb707448d2c442b16956f87e048ef0d1jvr 419f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr compilerClass = TopDictIndexCompiler 420f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 421a2ad5447fb707448d2c442b16956f87e048ef0d1jvr def produceItem(self, index, data, file, offset, size): 422767102ea85a8af1535c169b2e04da5ba458f3b80jvr top = TopDict(self.strings, file, offset, self.GlobalSubrs) 423767102ea85a8af1535c169b2e04da5ba458f3b80jvr top.decompile(data) 424767102ea85a8af1535c169b2e04da5ba458f3b80jvr return top 425a2ad5447fb707448d2c442b16956f87e048ef0d1jvr 426a2ad5447fb707448d2c442b16956f87e048ef0d1jvr def toXML(self, xmlWriter, progress): 427a2ad5447fb707448d2c442b16956f87e048ef0d1jvr for i in range(len(self)): 428a2ad5447fb707448d2c442b16956f87e048ef0d1jvr xmlWriter.begintag("FontDict", index=i) 429a2ad5447fb707448d2c442b16956f87e048ef0d1jvr xmlWriter.newline() 430a2ad5447fb707448d2c442b16956f87e048ef0d1jvr self[i].toXML(xmlWriter, progress) 431a2ad5447fb707448d2c442b16956f87e048ef0d1jvr xmlWriter.endtag("FontDict") 432a2ad5447fb707448d2c442b16956f87e048ef0d1jvr xmlWriter.newline() 433767102ea85a8af1535c169b2e04da5ba458f3b80jvr 434767102ea85a8af1535c169b2e04da5ba458f3b80jvr 435ed10151701a7d22e5ff4e06766edff59bd713c89jvrclass FDArrayIndex(TopDictIndex): 436ed10151701a7d22e5ff4e06766edff59bd713c89jvr 437ed10151701a7d22e5ff4e06766edff59bd713c89jvr compilerClass = FDArrayIndexCompiler 438ed10151701a7d22e5ff4e06766edff59bd713c89jvr 4393a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def fromXML(self, name, attrs, content): 440180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod if name != "FontDict": 441ed10151701a7d22e5ff4e06766edff59bd713c89jvr return 442ed10151701a7d22e5ff4e06766edff59bd713c89jvr fontDict = FontDict() 443ed10151701a7d22e5ff4e06766edff59bd713c89jvr for element in content: 4442a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr if isinstance(element, basestring): 445ed10151701a7d22e5ff4e06766edff59bd713c89jvr continue 4463a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod name, attrs, content = element 4473a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod fontDict.fromXML(name, attrs, content) 448ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.append(fontDict) 449ed10151701a7d22e5ff4e06766edff59bd713c89jvr 450ed10151701a7d22e5ff4e06766edff59bd713c89jvr 451ed10151701a7d22e5ff4e06766edff59bd713c89jvrclass FDSelect: 452ed10151701a7d22e5ff4e06766edff59bd713c89jvr def __init__(self, file = None, numGlyphs = None, format=None): 453ed10151701a7d22e5ff4e06766edff59bd713c89jvr if file: 454ed10151701a7d22e5ff4e06766edff59bd713c89jvr # read data in from file 455ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.format = readCard8(file) 456ed10151701a7d22e5ff4e06766edff59bd713c89jvr if self.format == 0: 457ed10151701a7d22e5ff4e06766edff59bd713c89jvr from array import array 458ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.gidArray = array("B", file.read(numGlyphs)).tolist() 459ed10151701a7d22e5ff4e06766edff59bd713c89jvr elif self.format == 3: 460ed10151701a7d22e5ff4e06766edff59bd713c89jvr gidArray = [None] * numGlyphs 461ed10151701a7d22e5ff4e06766edff59bd713c89jvr nRanges = readCard16(file) 462ed10151701a7d22e5ff4e06766edff59bd713c89jvr prev = None 463ed10151701a7d22e5ff4e06766edff59bd713c89jvr for i in range(nRanges): 464ed10151701a7d22e5ff4e06766edff59bd713c89jvr first = readCard16(file) 465ed10151701a7d22e5ff4e06766edff59bd713c89jvr if prev is not None: 466ed10151701a7d22e5ff4e06766edff59bd713c89jvr for glyphID in range(prev, first): 467ed10151701a7d22e5ff4e06766edff59bd713c89jvr gidArray[glyphID] = fd 468ed10151701a7d22e5ff4e06766edff59bd713c89jvr prev = first 469ed10151701a7d22e5ff4e06766edff59bd713c89jvr fd = readCard8(file) 470ed10151701a7d22e5ff4e06766edff59bd713c89jvr if prev is not None: 471ed10151701a7d22e5ff4e06766edff59bd713c89jvr first = readCard16(file) 472ed10151701a7d22e5ff4e06766edff59bd713c89jvr for glyphID in range(prev, first): 473ed10151701a7d22e5ff4e06766edff59bd713c89jvr gidArray[glyphID] = fd 474ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.gidArray = gidArray 475ed10151701a7d22e5ff4e06766edff59bd713c89jvr else: 476153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod assert False, "unsupported FDSelect format: %s" % format 477ed10151701a7d22e5ff4e06766edff59bd713c89jvr else: 478ed10151701a7d22e5ff4e06766edff59bd713c89jvr # reading from XML. Make empty gidArray,, and leave format as passed in. 4799e6ef94b5554c5b7dda2de9c863c11ed4b996b7aBehdad Esfahbod # format is None will result in the smallest representation being used. 480ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.format = format 481ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.gidArray = [] 482ed10151701a7d22e5ff4e06766edff59bd713c89jvr 483ed10151701a7d22e5ff4e06766edff59bd713c89jvr 484ed10151701a7d22e5ff4e06766edff59bd713c89jvr def __len__(self): 485ed10151701a7d22e5ff4e06766edff59bd713c89jvr return len(self.gidArray) 486ed10151701a7d22e5ff4e06766edff59bd713c89jvr 487ed10151701a7d22e5ff4e06766edff59bd713c89jvr def __getitem__(self, index): 488ed10151701a7d22e5ff4e06766edff59bd713c89jvr return self.gidArray[index] 489ed10151701a7d22e5ff4e06766edff59bd713c89jvr 490ed10151701a7d22e5ff4e06766edff59bd713c89jvr def __setitem__(self, index, fdSelectValue): 491ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.gidArray[index] = fdSelectValue 492ed10151701a7d22e5ff4e06766edff59bd713c89jvr 493ed10151701a7d22e5ff4e06766edff59bd713c89jvr def append(self, fdSelectValue): 494ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.gidArray.append(fdSelectValue) 495ed10151701a7d22e5ff4e06766edff59bd713c89jvr 496ed10151701a7d22e5ff4e06766edff59bd713c89jvr 497e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass CharStrings(object): 4981890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 499a2ad5447fb707448d2c442b16956f87e048ef0d1jvr def __init__(self, file, charset, globalSubrs, private, fdSelect, fdArray): 5004e5af60930726d06a58a30bae45bb27ae50aea77jvr if file is not None: 5014e5af60930726d06a58a30bae45bb27ae50aea77jvr self.charStringsIndex = SubrsIndex(file, globalSubrs, private, fdSelect, fdArray) 5024e5af60930726d06a58a30bae45bb27ae50aea77jvr self.charStrings = charStrings = {} 5034e5af60930726d06a58a30bae45bb27ae50aea77jvr for i in range(len(charset)): 5044e5af60930726d06a58a30bae45bb27ae50aea77jvr charStrings[charset[i]] = i 5054e5af60930726d06a58a30bae45bb27ae50aea77jvr self.charStringsAreIndexed = 1 5064e5af60930726d06a58a30bae45bb27ae50aea77jvr else: 5074e5af60930726d06a58a30bae45bb27ae50aea77jvr self.charStrings = {} 5084e5af60930726d06a58a30bae45bb27ae50aea77jvr self.charStringsAreIndexed = 0 5094e5af60930726d06a58a30bae45bb27ae50aea77jvr self.globalSubrs = globalSubrs 5104e5af60930726d06a58a30bae45bb27ae50aea77jvr self.private = private 5119e6ef94b5554c5b7dda2de9c863c11ed4b996b7aBehdad Esfahbod if fdSelect is not None: 512ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.fdSelect = fdSelect 5139e6ef94b5554c5b7dda2de9c863c11ed4b996b7aBehdad Esfahbod if fdArray is not None: 514ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.fdArray = fdArray 5151890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 5164756b3a04014645ee16a14fb6273e93efa1c7e15jvr def keys(self): 517c2297cd41d6c00b95f857b65bc9fd4b57559ac5eBehdad Esfahbod return list(self.charStrings.keys()) 5184756b3a04014645ee16a14fb6273e93efa1c7e15jvr 519016ca76e918ed36888c0fa8e287028ea367ef3d9jvr def values(self): 5204e5af60930726d06a58a30bae45bb27ae50aea77jvr if self.charStringsAreIndexed: 5214e5af60930726d06a58a30bae45bb27ae50aea77jvr return self.charStringsIndex 5224e5af60930726d06a58a30bae45bb27ae50aea77jvr else: 523c2297cd41d6c00b95f857b65bc9fd4b57559ac5eBehdad Esfahbod return list(self.charStrings.values()) 524016ca76e918ed36888c0fa8e287028ea367ef3d9jvr 5254756b3a04014645ee16a14fb6273e93efa1c7e15jvr def has_key(self, name): 526bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod return name in self.charStrings 5271890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 528767102ea85a8af1535c169b2e04da5ba458f3b80jvr def __len__(self): 5294e5af60930726d06a58a30bae45bb27ae50aea77jvr return len(self.charStrings) 530767102ea85a8af1535c169b2e04da5ba458f3b80jvr 5314756b3a04014645ee16a14fb6273e93efa1c7e15jvr def __getitem__(self, name): 5324e5af60930726d06a58a30bae45bb27ae50aea77jvr charString = self.charStrings[name] 5334e5af60930726d06a58a30bae45bb27ae50aea77jvr if self.charStringsAreIndexed: 5344e5af60930726d06a58a30bae45bb27ae50aea77jvr charString = self.charStringsIndex[charString] 5354e5af60930726d06a58a30bae45bb27ae50aea77jvr return charString 5364e5af60930726d06a58a30bae45bb27ae50aea77jvr 5374e5af60930726d06a58a30bae45bb27ae50aea77jvr def __setitem__(self, name, charString): 5384e5af60930726d06a58a30bae45bb27ae50aea77jvr if self.charStringsAreIndexed: 5394e5af60930726d06a58a30bae45bb27ae50aea77jvr index = self.charStrings[name] 5404e5af60930726d06a58a30bae45bb27ae50aea77jvr self.charStringsIndex[index] = charString 5414e5af60930726d06a58a30bae45bb27ae50aea77jvr else: 5424e5af60930726d06a58a30bae45bb27ae50aea77jvr self.charStrings[name] = charString 5431890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 544a2ad5447fb707448d2c442b16956f87e048ef0d1jvr def getItemAndSelector(self, name): 5454e5af60930726d06a58a30bae45bb27ae50aea77jvr if self.charStringsAreIndexed: 5464e5af60930726d06a58a30bae45bb27ae50aea77jvr index = self.charStrings[name] 5474e5af60930726d06a58a30bae45bb27ae50aea77jvr return self.charStringsIndex.getItemAndSelector(index) 5484e5af60930726d06a58a30bae45bb27ae50aea77jvr else: 549ed10151701a7d22e5ff4e06766edff59bd713c89jvr if hasattr(self, 'fdSelect'): 55091bca4244286fb519c93fe92329da96b0e6f32eejvr sel = self.fdSelect[index] # index is not defined at this point. Read R. ? 551ed10151701a7d22e5ff4e06766edff59bd713c89jvr else: 552ed10151701a7d22e5ff4e06766edff59bd713c89jvr raise KeyError("fdSelect array not yet defined.") 553ed10151701a7d22e5ff4e06766edff59bd713c89jvr return self.charStrings[name], sel 554a2ad5447fb707448d2c442b16956f87e048ef0d1jvr 5554756b3a04014645ee16a14fb6273e93efa1c7e15jvr def toXML(self, xmlWriter, progress): 556ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod names = sorted(self.keys()) 5577ce0a139ab67dd30614e728a1ef897e53ad805aejvr i = 0 5587ce0a139ab67dd30614e728a1ef897e53ad805aejvr step = 10 5597ce0a139ab67dd30614e728a1ef897e53ad805aejvr numGlyphs = len(names) 5604756b3a04014645ee16a14fb6273e93efa1c7e15jvr for name in names: 561ed10151701a7d22e5ff4e06766edff59bd713c89jvr charStr, fdSelectIndex = self.getItemAndSelector(name) 562b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr if charStr.needsDecompilation(): 563b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr raw = [("raw", 1)] 564b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr else: 565b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr raw = [] 566ed10151701a7d22e5ff4e06766edff59bd713c89jvr if fdSelectIndex is None: 567b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr xmlWriter.begintag("CharString", [('name', name)] + raw) 568a2ad5447fb707448d2c442b16956f87e048ef0d1jvr else: 569a2ad5447fb707448d2c442b16956f87e048ef0d1jvr xmlWriter.begintag("CharString", 570ed10151701a7d22e5ff4e06766edff59bd713c89jvr [('name', name), ('fdSelectIndex', fdSelectIndex)] + raw) 5714756b3a04014645ee16a14fb6273e93efa1c7e15jvr xmlWriter.newline() 572b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr charStr.toXML(xmlWriter) 5734756b3a04014645ee16a14fb6273e93efa1c7e15jvr xmlWriter.endtag("CharString") 5744756b3a04014645ee16a14fb6273e93efa1c7e15jvr xmlWriter.newline() 5757ce0a139ab67dd30614e728a1ef897e53ad805aejvr if not i % step and progress is not None: 5767ce0a139ab67dd30614e728a1ef897e53ad805aejvr progress.setLabel("Dumping 'CFF ' table... (%s)" % name) 57732c10eecffb4923e0721c395e4b80fb732543f18Behdad Esfahbod progress.increment(step / numGlyphs) 5787ce0a139ab67dd30614e728a1ef897e53ad805aejvr i = i + 1 5794e5af60930726d06a58a30bae45bb27ae50aea77jvr 5803a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def fromXML(self, name, attrs, content): 5814e5af60930726d06a58a30bae45bb27ae50aea77jvr for element in content: 5822a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr if isinstance(element, basestring): 5834e5af60930726d06a58a30bae45bb27ae50aea77jvr continue 5844e5af60930726d06a58a30bae45bb27ae50aea77jvr name, attrs, content = element 585180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod if name != "CharString": 5864e5af60930726d06a58a30bae45bb27ae50aea77jvr continue 587ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdID = -1 588ed10151701a7d22e5ff4e06766edff59bd713c89jvr if hasattr(self, "fdArray"): 589ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdID = safeEval(attrs["fdSelectIndex"]) 590ed10151701a7d22e5ff4e06766edff59bd713c89jvr private = self.fdArray[fdID].Private 591ed10151701a7d22e5ff4e06766edff59bd713c89jvr else: 592ed10151701a7d22e5ff4e06766edff59bd713c89jvr private = self.private 593ed10151701a7d22e5ff4e06766edff59bd713c89jvr 5944e5af60930726d06a58a30bae45bb27ae50aea77jvr glyphName = attrs["name"] 595489d76a340845361def6af9ab7d9152f8e66f417jvr charString = psCharStrings.T2CharString( 596489d76a340845361def6af9ab7d9152f8e66f417jvr private=private, 597489d76a340845361def6af9ab7d9152f8e66f417jvr globalSubrs=self.globalSubrs) 5983a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod charString.fromXML(name, attrs, content) 599ed10151701a7d22e5ff4e06766edff59bd713c89jvr if fdID >= 0: 600ed10151701a7d22e5ff4e06766edff59bd713c89jvr charString.fdSelectIndex = fdID 6014e5af60930726d06a58a30bae45bb27ae50aea77jvr self[glyphName] = charString 6021890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 6031890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 604a2ad5447fb707448d2c442b16956f87e048ef0d1jvrdef readCard8(file): 605319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod return byteord(file.read(1)) 606a2ad5447fb707448d2c442b16956f87e048ef0d1jvr 607a2ad5447fb707448d2c442b16956f87e048ef0d1jvrdef readCard16(file): 608a2ad5447fb707448d2c442b16956f87e048ef0d1jvr value, = struct.unpack(">H", file.read(2)) 609a2ad5447fb707448d2c442b16956f87e048ef0d1jvr return value 610a2ad5447fb707448d2c442b16956f87e048ef0d1jvr 611f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef writeCard8(file, value): 612b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod file.write(bytechr(value)) 613f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 614f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef writeCard16(file, value): 615f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr file.write(struct.pack(">H", value)) 616f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 617f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef packCard8(value): 618b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod return bytechr(value) 619f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 620f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef packCard16(value): 621f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return struct.pack(">H", value) 622f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 6234756b3a04014645ee16a14fb6273e93efa1c7e15jvrdef buildOperatorDict(table): 6244756b3a04014645ee16a14fb6273e93efa1c7e15jvr d = {} 6254756b3a04014645ee16a14fb6273e93efa1c7e15jvr for op, name, arg, default, conv in table: 6264756b3a04014645ee16a14fb6273e93efa1c7e15jvr d[op] = (name, arg) 6274756b3a04014645ee16a14fb6273e93efa1c7e15jvr return d 6281890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 629f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef buildOpcodeDict(table): 630f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr d = {} 631f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for op, name, arg, default, conv in table: 6322a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr if isinstance(op, tuple): 633b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod op = bytechr(op[0]) + bytechr(op[1]) 634f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr else: 635b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod op = bytechr(op) 636f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr d[name] = (op, arg) 637f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return d 638f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 6394756b3a04014645ee16a14fb6273e93efa1c7e15jvrdef buildOrder(table): 6404756b3a04014645ee16a14fb6273e93efa1c7e15jvr l = [] 6414756b3a04014645ee16a14fb6273e93efa1c7e15jvr for op, name, arg, default, conv in table: 6424756b3a04014645ee16a14fb6273e93efa1c7e15jvr l.append(name) 6434756b3a04014645ee16a14fb6273e93efa1c7e15jvr return l 6441890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 6454756b3a04014645ee16a14fb6273e93efa1c7e15jvrdef buildDefaults(table): 6464756b3a04014645ee16a14fb6273e93efa1c7e15jvr d = {} 6474756b3a04014645ee16a14fb6273e93efa1c7e15jvr for op, name, arg, default, conv in table: 6484756b3a04014645ee16a14fb6273e93efa1c7e15jvr if default is not None: 6494756b3a04014645ee16a14fb6273e93efa1c7e15jvr d[name] = default 6504756b3a04014645ee16a14fb6273e93efa1c7e15jvr return d 6514756b3a04014645ee16a14fb6273e93efa1c7e15jvr 6524756b3a04014645ee16a14fb6273e93efa1c7e15jvrdef buildConverters(table): 6534756b3a04014645ee16a14fb6273e93efa1c7e15jvr d = {} 6544756b3a04014645ee16a14fb6273e93efa1c7e15jvr for op, name, arg, default, conv in table: 6554756b3a04014645ee16a14fb6273e93efa1c7e15jvr d[name] = conv 6564756b3a04014645ee16a14fb6273e93efa1c7e15jvr return d 6574756b3a04014645ee16a14fb6273e93efa1c7e15jvr 6584756b3a04014645ee16a14fb6273e93efa1c7e15jvr 659e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass SimpleConverter(object): 6607ce02ea9dfa1236002aaf61c972a8f31544d070ejvr def read(self, parent, value): 6617ce02ea9dfa1236002aaf61c972a8f31544d070ejvr return value 662f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def write(self, parent, value): 663f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return value 6647ce0a139ab67dd30614e728a1ef897e53ad805aejvr def xmlWrite(self, xmlWriter, name, value, progress): 6654e5af60930726d06a58a30bae45bb27ae50aea77jvr xmlWriter.simpletag(name, value=value) 6664e5af60930726d06a58a30bae45bb27ae50aea77jvr xmlWriter.newline() 6673a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def xmlRead(self, name, attrs, content, parent): 6684e5af60930726d06a58a30bae45bb27ae50aea77jvr return attrs["value"] 6694e5af60930726d06a58a30bae45bb27ae50aea77jvr 670024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbodclass ASCIIConverter(SimpleConverter): 671024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod def read(self, parent, value): 672024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod return tostr(value, encoding='ascii') 673024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod def write(self, parent, value): 674024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod return tobytes(value, encoding='ascii') 675024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod def xmlWrite(self, xmlWriter, name, value, progress): 676024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod xmlWriter.simpletag(name, value=tostr(value, encoding="ascii")) 677024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod xmlWriter.newline() 678024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod def xmlRead(self, name, attrs, content, parent): 679024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod return tobytes(attrs["value"], encoding=("ascii")) 680024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod 681e2ca9b5a4ff537ad827c3f722c8137b4f986d9a5jvrclass Latin1Converter(SimpleConverter): 682024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod def read(self, parent, value): 683024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod return tostr(value, encoding='latin1') 684024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod def write(self, parent, value): 685024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod return tobytes(value, encoding='latin1') 6868c5c96647147a4cfc13d31d17a64f501fa824994Behdad Esfahbod def xmlWrite(self, xmlWriter, name, value, progress): 687024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod xmlWriter.simpletag(name, value=tostr(value, encoding="latin1")) 6888c5c96647147a4cfc13d31d17a64f501fa824994Behdad Esfahbod xmlWriter.newline() 6893a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def xmlRead(self, name, attrs, content, parent): 690024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod return tobytes(attrs["value"], encoding=("latin1")) 691e2ca9b5a4ff537ad827c3f722c8137b4f986d9a5jvr 692e2ca9b5a4ff537ad827c3f722c8137b4f986d9a5jvr 6934e5af60930726d06a58a30bae45bb27ae50aea77jvrdef parseNum(s): 6944e5af60930726d06a58a30bae45bb27ae50aea77jvr try: 6954e5af60930726d06a58a30bae45bb27ae50aea77jvr value = int(s) 6964e5af60930726d06a58a30bae45bb27ae50aea77jvr except: 6974e5af60930726d06a58a30bae45bb27ae50aea77jvr value = float(s) 6984e5af60930726d06a58a30bae45bb27ae50aea77jvr return value 6994e5af60930726d06a58a30bae45bb27ae50aea77jvr 7004e5af60930726d06a58a30bae45bb27ae50aea77jvrclass NumberConverter(SimpleConverter): 7013a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def xmlRead(self, name, attrs, content, parent): 7024e5af60930726d06a58a30bae45bb27ae50aea77jvr return parseNum(attrs["value"]) 7034e5af60930726d06a58a30bae45bb27ae50aea77jvr 7044e5af60930726d06a58a30bae45bb27ae50aea77jvrclass ArrayConverter(SimpleConverter): 7057ce0a139ab67dd30614e728a1ef897e53ad805aejvr def xmlWrite(self, xmlWriter, name, value, progress): 706e5ca79699d00fdf7ac6eaceaed372aea8d6bc1fdBehdad Esfahbod value = " ".join(map(str, value)) 707e5ca79699d00fdf7ac6eaceaed372aea8d6bc1fdBehdad Esfahbod xmlWriter.simpletag(name, value=value) 7084e5af60930726d06a58a30bae45bb27ae50aea77jvr xmlWriter.newline() 7093a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def xmlRead(self, name, attrs, content, parent): 7104e5af60930726d06a58a30bae45bb27ae50aea77jvr values = attrs["value"].split() 711e5ca79699d00fdf7ac6eaceaed372aea8d6bc1fdBehdad Esfahbod return [parseNum(value) for value in values] 7124e5af60930726d06a58a30bae45bb27ae50aea77jvr 7134e5af60930726d06a58a30bae45bb27ae50aea77jvrclass TableConverter(SimpleConverter): 7147ce0a139ab67dd30614e728a1ef897e53ad805aejvr def xmlWrite(self, xmlWriter, name, value, progress): 715a2ad5447fb707448d2c442b16956f87e048ef0d1jvr xmlWriter.begintag(name) 716a2ad5447fb707448d2c442b16956f87e048ef0d1jvr xmlWriter.newline() 7177ce0a139ab67dd30614e728a1ef897e53ad805aejvr value.toXML(xmlWriter, progress) 718a2ad5447fb707448d2c442b16956f87e048ef0d1jvr xmlWriter.endtag(name) 719a2ad5447fb707448d2c442b16956f87e048ef0d1jvr xmlWriter.newline() 7203a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def xmlRead(self, name, attrs, content, parent): 7214e5af60930726d06a58a30bae45bb27ae50aea77jvr ob = self.getClass()() 7224e5af60930726d06a58a30bae45bb27ae50aea77jvr for element in content: 7232a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr if isinstance(element, basestring): 7244e5af60930726d06a58a30bae45bb27ae50aea77jvr continue 7253a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod name, attrs, content = element 7263a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod ob.fromXML(name, attrs, content) 7274e5af60930726d06a58a30bae45bb27ae50aea77jvr return ob 728a2ad5447fb707448d2c442b16956f87e048ef0d1jvr 7294e5af60930726d06a58a30bae45bb27ae50aea77jvrclass PrivateDictConverter(TableConverter): 7304e5af60930726d06a58a30bae45bb27ae50aea77jvr def getClass(self): 7314e5af60930726d06a58a30bae45bb27ae50aea77jvr return PrivateDict 7324756b3a04014645ee16a14fb6273e93efa1c7e15jvr def read(self, parent, value): 7334756b3a04014645ee16a14fb6273e93efa1c7e15jvr size, offset = value 7344756b3a04014645ee16a14fb6273e93efa1c7e15jvr file = parent.file 7354e5af60930726d06a58a30bae45bb27ae50aea77jvr priv = PrivateDict(parent.strings, file, offset) 7364756b3a04014645ee16a14fb6273e93efa1c7e15jvr file.seek(offset) 7374756b3a04014645ee16a14fb6273e93efa1c7e15jvr data = file.read(size) 738153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod assert len(data) == size 7394e5af60930726d06a58a30bae45bb27ae50aea77jvr priv.decompile(data) 7404e5af60930726d06a58a30bae45bb27ae50aea77jvr return priv 741f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def write(self, parent, value): 742f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return (0, 0) # dummy value 7434756b3a04014645ee16a14fb6273e93efa1c7e15jvr 7444e5af60930726d06a58a30bae45bb27ae50aea77jvrclass SubrsConverter(TableConverter): 7454e5af60930726d06a58a30bae45bb27ae50aea77jvr def getClass(self): 7464e5af60930726d06a58a30bae45bb27ae50aea77jvr return SubrsIndex 7474756b3a04014645ee16a14fb6273e93efa1c7e15jvr def read(self, parent, value): 7484756b3a04014645ee16a14fb6273e93efa1c7e15jvr file = parent.file 7494756b3a04014645ee16a14fb6273e93efa1c7e15jvr file.seek(parent.offset + value) # Offset(self) 7504e5af60930726d06a58a30bae45bb27ae50aea77jvr return SubrsIndex(file) 751f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def write(self, parent, value): 752f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return 0 # dummy value 7534756b3a04014645ee16a14fb6273e93efa1c7e15jvr 7544e5af60930726d06a58a30bae45bb27ae50aea77jvrclass CharStringsConverter(TableConverter): 7554756b3a04014645ee16a14fb6273e93efa1c7e15jvr def read(self, parent, value): 7564756b3a04014645ee16a14fb6273e93efa1c7e15jvr file = parent.file 757767102ea85a8af1535c169b2e04da5ba458f3b80jvr charset = parent.charset 758a2ad5447fb707448d2c442b16956f87e048ef0d1jvr globalSubrs = parent.GlobalSubrs 759a2ad5447fb707448d2c442b16956f87e048ef0d1jvr if hasattr(parent, "ROS"): 760a2ad5447fb707448d2c442b16956f87e048ef0d1jvr fdSelect, fdArray = parent.FDSelect, parent.FDArray 761a2ad5447fb707448d2c442b16956f87e048ef0d1jvr private = None 762a2ad5447fb707448d2c442b16956f87e048ef0d1jvr else: 763a2ad5447fb707448d2c442b16956f87e048ef0d1jvr fdSelect, fdArray = None, None 764a2ad5447fb707448d2c442b16956f87e048ef0d1jvr private = parent.Private 7654756b3a04014645ee16a14fb6273e93efa1c7e15jvr file.seek(value) # Offset(0) 766a2ad5447fb707448d2c442b16956f87e048ef0d1jvr return CharStrings(file, charset, globalSubrs, private, fdSelect, fdArray) 767f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def write(self, parent, value): 768f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return 0 # dummy value 7693a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def xmlRead(self, name, attrs, content, parent): 770ed10151701a7d22e5ff4e06766edff59bd713c89jvr if hasattr(parent, "ROS"): 771ed10151701a7d22e5ff4e06766edff59bd713c89jvr # if it is a CID-keyed font, then the private Dict is extracted from the parent.FDArray 772ed10151701a7d22e5ff4e06766edff59bd713c89jvr private, fdSelect, fdArray = None, parent.FDSelect, parent.FDArray 773ed10151701a7d22e5ff4e06766edff59bd713c89jvr else: 774ed10151701a7d22e5ff4e06766edff59bd713c89jvr # if it is a name-keyed font, then the private dict is in the top dict, and there is no fdArray. 775ed10151701a7d22e5ff4e06766edff59bd713c89jvr private, fdSelect, fdArray = parent.Private, None, None 776ed10151701a7d22e5ff4e06766edff59bd713c89jvr charStrings = CharStrings(None, None, parent.GlobalSubrs, private, fdSelect, fdArray) 7773a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod charStrings.fromXML(name, attrs, content) 7784e5af60930726d06a58a30bae45bb27ae50aea77jvr return charStrings 7794756b3a04014645ee16a14fb6273e93efa1c7e15jvr 780e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass CharsetConverter(object): 7814756b3a04014645ee16a14fb6273e93efa1c7e15jvr def read(self, parent, value): 7824756b3a04014645ee16a14fb6273e93efa1c7e15jvr isCID = hasattr(parent, "ROS") 7834756b3a04014645ee16a14fb6273e93efa1c7e15jvr if value > 2: 7844756b3a04014645ee16a14fb6273e93efa1c7e15jvr numGlyphs = parent.numGlyphs 7854756b3a04014645ee16a14fb6273e93efa1c7e15jvr file = parent.file 7864756b3a04014645ee16a14fb6273e93efa1c7e15jvr file.seek(value) 787f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if DEBUG: 7883ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print("loading charset at %s" % value) 789a2ad5447fb707448d2c442b16956f87e048ef0d1jvr format = readCard8(file) 7904756b3a04014645ee16a14fb6273e93efa1c7e15jvr if format == 0: 791c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr charset = parseCharset0(numGlyphs, file, parent.strings, isCID) 7924756b3a04014645ee16a14fb6273e93efa1c7e15jvr elif format == 1 or format == 2: 7934756b3a04014645ee16a14fb6273e93efa1c7e15jvr charset = parseCharset(numGlyphs, file, parent.strings, isCID, format) 7944756b3a04014645ee16a14fb6273e93efa1c7e15jvr else: 7954756b3a04014645ee16a14fb6273e93efa1c7e15jvr raise NotImplementedError 7964756b3a04014645ee16a14fb6273e93efa1c7e15jvr assert len(charset) == numGlyphs 797f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if DEBUG: 7983ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print(" charset end at %s" % file.tell()) 799c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr else: # offset == 0 -> no charset data. 800bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod if isCID or "CharStrings" not in parent.rawDict: 801c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr assert value == 0 # We get here only when processing fontDicts from the FDArray of CFF-CID fonts. Only the real topDict references the chrset. 8024756b3a04014645ee16a14fb6273e93efa1c7e15jvr charset = None 8034756b3a04014645ee16a14fb6273e93efa1c7e15jvr elif value == 0: 804c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr charset = cffISOAdobeStrings 8054756b3a04014645ee16a14fb6273e93efa1c7e15jvr elif value == 1: 806c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr charset = cffIExpertStrings 8074756b3a04014645ee16a14fb6273e93efa1c7e15jvr elif value == 2: 808c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr charset = cffExpertSubsetStrings 8094756b3a04014645ee16a14fb6273e93efa1c7e15jvr return charset 810c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr 811f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def write(self, parent, value): 812f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return 0 # dummy value 8137ce0a139ab67dd30614e728a1ef897e53ad805aejvr def xmlWrite(self, xmlWriter, name, value, progress): 8144e5af60930726d06a58a30bae45bb27ae50aea77jvr # XXX only write charset when not in OT/TTX context, where we 8154e5af60930726d06a58a30bae45bb27ae50aea77jvr # dump charset as a separate "GlyphOrder" table. 8164e5af60930726d06a58a30bae45bb27ae50aea77jvr ##xmlWriter.simpletag("charset") 8174e5af60930726d06a58a30bae45bb27ae50aea77jvr xmlWriter.comment("charset is dumped separately as the 'GlyphOrder' element") 8184756b3a04014645ee16a14fb6273e93efa1c7e15jvr xmlWriter.newline() 8193a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def xmlRead(self, name, attrs, content, parent): 8204e5af60930726d06a58a30bae45bb27ae50aea77jvr if 0: 8214e5af60930726d06a58a30bae45bb27ae50aea77jvr return safeEval(attrs["value"]) 8227842e56b97ce677b83bdab09cda48bc2d89ac75aJust 8237842e56b97ce677b83bdab09cda48bc2d89ac75aJust 824e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass CharsetCompiler(object): 825f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 826f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def __init__(self, strings, charset, parent): 827f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr assert charset[0] == '.notdef' 828ed10151701a7d22e5ff4e06766edff59bd713c89jvr isCID = hasattr(parent.dictObj, "ROS") 829ed10151701a7d22e5ff4e06766edff59bd713c89jvr data0 = packCharset0(charset, isCID, strings) 830ed10151701a7d22e5ff4e06766edff59bd713c89jvr data = packCharset(charset, isCID, strings) 8316004bafc1f6654e45283d01a9c1141f89cdeec3fjvr if len(data) < len(data0): 8326004bafc1f6654e45283d01a9c1141f89cdeec3fjvr self.data = data 8336004bafc1f6654e45283d01a9c1141f89cdeec3fjvr else: 8346004bafc1f6654e45283d01a9c1141f89cdeec3fjvr self.data = data0 835f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.parent = parent 836f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 8374e5af60930726d06a58a30bae45bb27ae50aea77jvr def setPos(self, pos, endPos): 838f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.parent.rawDict["charset"] = pos 839f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 840f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def getDataLength(self): 841f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return len(self.data) 842f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 843f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def toFile(self, file): 844f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr file.write(self.data) 845f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 846f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 847ed10151701a7d22e5ff4e06766edff59bd713c89jvrdef getCIDfromName(name, strings): 848ed10151701a7d22e5ff4e06766edff59bd713c89jvr return int(name[3:]) 849ed10151701a7d22e5ff4e06766edff59bd713c89jvr 850ed10151701a7d22e5ff4e06766edff59bd713c89jvrdef getSIDfromName(name, strings): 851ed10151701a7d22e5ff4e06766edff59bd713c89jvr return strings.getSID(name) 852ed10151701a7d22e5ff4e06766edff59bd713c89jvr 853ed10151701a7d22e5ff4e06766edff59bd713c89jvrdef packCharset0(charset, isCID, strings): 854153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod fmt = 0 855153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod data = [packCard8(fmt)] 856ed10151701a7d22e5ff4e06766edff59bd713c89jvr if isCID: 857ed10151701a7d22e5ff4e06766edff59bd713c89jvr getNameID = getCIDfromName 858ed10151701a7d22e5ff4e06766edff59bd713c89jvr else: 859ed10151701a7d22e5ff4e06766edff59bd713c89jvr getNameID = getSIDfromName 860ed10151701a7d22e5ff4e06766edff59bd713c89jvr 8616004bafc1f6654e45283d01a9c1141f89cdeec3fjvr for name in charset[1:]: 862ed10151701a7d22e5ff4e06766edff59bd713c89jvr data.append(packCard16(getNameID(name,strings))) 86318316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod return bytesjoin(data) 8646004bafc1f6654e45283d01a9c1141f89cdeec3fjvr 865ed10151701a7d22e5ff4e06766edff59bd713c89jvr 866ed10151701a7d22e5ff4e06766edff59bd713c89jvrdef packCharset(charset, isCID, strings): 867153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod fmt = 1 8686004bafc1f6654e45283d01a9c1141f89cdeec3fjvr ranges = [] 8696004bafc1f6654e45283d01a9c1141f89cdeec3fjvr first = None 8706004bafc1f6654e45283d01a9c1141f89cdeec3fjvr end = 0 871ed10151701a7d22e5ff4e06766edff59bd713c89jvr if isCID: 872ed10151701a7d22e5ff4e06766edff59bd713c89jvr getNameID = getCIDfromName 873ed10151701a7d22e5ff4e06766edff59bd713c89jvr else: 874ed10151701a7d22e5ff4e06766edff59bd713c89jvr getNameID = getSIDfromName 875ed10151701a7d22e5ff4e06766edff59bd713c89jvr 8766004bafc1f6654e45283d01a9c1141f89cdeec3fjvr for name in charset[1:]: 877ed10151701a7d22e5ff4e06766edff59bd713c89jvr SID = getNameID(name, strings) 8786004bafc1f6654e45283d01a9c1141f89cdeec3fjvr if first is None: 8796004bafc1f6654e45283d01a9c1141f89cdeec3fjvr first = SID 880180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod elif end + 1 != SID: 8816004bafc1f6654e45283d01a9c1141f89cdeec3fjvr nLeft = end - first 8826004bafc1f6654e45283d01a9c1141f89cdeec3fjvr if nLeft > 255: 883153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod fmt = 2 8846004bafc1f6654e45283d01a9c1141f89cdeec3fjvr ranges.append((first, nLeft)) 8856004bafc1f6654e45283d01a9c1141f89cdeec3fjvr first = SID 8866004bafc1f6654e45283d01a9c1141f89cdeec3fjvr end = SID 8876004bafc1f6654e45283d01a9c1141f89cdeec3fjvr nLeft = end - first 8886004bafc1f6654e45283d01a9c1141f89cdeec3fjvr if nLeft > 255: 889153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod fmt = 2 8906004bafc1f6654e45283d01a9c1141f89cdeec3fjvr ranges.append((first, nLeft)) 8916004bafc1f6654e45283d01a9c1141f89cdeec3fjvr 892153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod data = [packCard8(fmt)] 893153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod if fmt == 1: 8946004bafc1f6654e45283d01a9c1141f89cdeec3fjvr nLeftFunc = packCard8 8956004bafc1f6654e45283d01a9c1141f89cdeec3fjvr else: 8966004bafc1f6654e45283d01a9c1141f89cdeec3fjvr nLeftFunc = packCard16 8976004bafc1f6654e45283d01a9c1141f89cdeec3fjvr for first, nLeft in ranges: 8986004bafc1f6654e45283d01a9c1141f89cdeec3fjvr data.append(packCard16(first) + nLeftFunc(nLeft)) 89918316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod return bytesjoin(data) 9006004bafc1f6654e45283d01a9c1141f89cdeec3fjvr 901c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrdef parseCharset0(numGlyphs, file, strings, isCID): 902f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr charset = [".notdef"] 903c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr if isCID: 904c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr for i in range(numGlyphs - 1): 905c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr CID = readCard16(file) 90614fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod charset.append("cid" + str(CID).zfill(5)) 907c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr else: 908c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr for i in range(numGlyphs - 1): 909c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr SID = readCard16(file) 910c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr charset.append(strings[SID]) 911f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return charset 912f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 913153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahboddef parseCharset(numGlyphs, file, strings, isCID, fmt): 914a2a75b348da46073cdd1dea50915384eabfff7c9jvr charset = ['.notdef'] 9157842e56b97ce677b83bdab09cda48bc2d89ac75aJust count = 1 916153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod if fmt == 1: 917a2ad5447fb707448d2c442b16956f87e048ef0d1jvr nLeftFunc = readCard8 9184756b3a04014645ee16a14fb6273e93efa1c7e15jvr else: 919a2ad5447fb707448d2c442b16956f87e048ef0d1jvr nLeftFunc = readCard16 9204756b3a04014645ee16a14fb6273e93efa1c7e15jvr while count < numGlyphs: 921a2ad5447fb707448d2c442b16956f87e048ef0d1jvr first = readCard16(file) 9224756b3a04014645ee16a14fb6273e93efa1c7e15jvr nLeft = nLeftFunc(file) 923a2a75b348da46073cdd1dea50915384eabfff7c9jvr if isCID: 924a2a75b348da46073cdd1dea50915384eabfff7c9jvr for CID in range(first, first+nLeft+1): 92514fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod charset.append("cid" + str(CID).zfill(5)) 926a2a75b348da46073cdd1dea50915384eabfff7c9jvr else: 927a2a75b348da46073cdd1dea50915384eabfff7c9jvr for SID in range(first, first+nLeft+1): 928a2a75b348da46073cdd1dea50915384eabfff7c9jvr charset.append(strings[SID]) 9297842e56b97ce677b83bdab09cda48bc2d89ac75aJust count = count + nLeft + 1 930a2a75b348da46073cdd1dea50915384eabfff7c9jvr return charset 9317842e56b97ce677b83bdab09cda48bc2d89ac75aJust 9327842e56b97ce677b83bdab09cda48bc2d89ac75aJust 933e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass EncodingCompiler(object): 934b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 935b9702ba0f1d86307752ed7d593d59e923c8d4054jvr def __init__(self, strings, encoding, parent): 9362a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr assert not isinstance(encoding, basestring) 937b9702ba0f1d86307752ed7d593d59e923c8d4054jvr data0 = packEncoding0(parent.dictObj.charset, encoding, parent.strings) 938b9702ba0f1d86307752ed7d593d59e923c8d4054jvr data1 = packEncoding1(parent.dictObj.charset, encoding, parent.strings) 939b9702ba0f1d86307752ed7d593d59e923c8d4054jvr if len(data0) < len(data1): 940b9702ba0f1d86307752ed7d593d59e923c8d4054jvr self.data = data0 941b9702ba0f1d86307752ed7d593d59e923c8d4054jvr else: 942b9702ba0f1d86307752ed7d593d59e923c8d4054jvr self.data = data1 943b9702ba0f1d86307752ed7d593d59e923c8d4054jvr self.parent = parent 944b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 945b9702ba0f1d86307752ed7d593d59e923c8d4054jvr def setPos(self, pos, endPos): 946b9702ba0f1d86307752ed7d593d59e923c8d4054jvr self.parent.rawDict["Encoding"] = pos 947b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 948b9702ba0f1d86307752ed7d593d59e923c8d4054jvr def getDataLength(self): 949b9702ba0f1d86307752ed7d593d59e923c8d4054jvr return len(self.data) 950b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 951b9702ba0f1d86307752ed7d593d59e923c8d4054jvr def toFile(self, file): 952b9702ba0f1d86307752ed7d593d59e923c8d4054jvr file.write(self.data) 953b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 954b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 955b9702ba0f1d86307752ed7d593d59e923c8d4054jvrclass EncodingConverter(SimpleConverter): 956b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 957b9702ba0f1d86307752ed7d593d59e923c8d4054jvr def read(self, parent, value): 958b9702ba0f1d86307752ed7d593d59e923c8d4054jvr if value == 0: 959b9702ba0f1d86307752ed7d593d59e923c8d4054jvr return "StandardEncoding" 960b9702ba0f1d86307752ed7d593d59e923c8d4054jvr elif value == 1: 961b9702ba0f1d86307752ed7d593d59e923c8d4054jvr return "ExpertEncoding" 962b9702ba0f1d86307752ed7d593d59e923c8d4054jvr else: 963b9702ba0f1d86307752ed7d593d59e923c8d4054jvr assert value > 1 964b9702ba0f1d86307752ed7d593d59e923c8d4054jvr file = parent.file 965b9702ba0f1d86307752ed7d593d59e923c8d4054jvr file.seek(value) 966b9702ba0f1d86307752ed7d593d59e923c8d4054jvr if DEBUG: 9673ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print("loading Encoding at %s" % value) 968153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod fmt = readCard8(file) 969153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod haveSupplement = fmt & 0x80 970b9702ba0f1d86307752ed7d593d59e923c8d4054jvr if haveSupplement: 971cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise NotImplementedError("Encoding supplements are not yet supported") 972153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod fmt = fmt & 0x7f 973153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod if fmt == 0: 974b9702ba0f1d86307752ed7d593d59e923c8d4054jvr encoding = parseEncoding0(parent.charset, file, haveSupplement, 975b9702ba0f1d86307752ed7d593d59e923c8d4054jvr parent.strings) 976153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod elif fmt == 1: 977b9702ba0f1d86307752ed7d593d59e923c8d4054jvr encoding = parseEncoding1(parent.charset, file, haveSupplement, 978b9702ba0f1d86307752ed7d593d59e923c8d4054jvr parent.strings) 979b9702ba0f1d86307752ed7d593d59e923c8d4054jvr return encoding 980b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 981b9702ba0f1d86307752ed7d593d59e923c8d4054jvr def write(self, parent, value): 982b9702ba0f1d86307752ed7d593d59e923c8d4054jvr if value == "StandardEncoding": 983b9702ba0f1d86307752ed7d593d59e923c8d4054jvr return 0 984b9702ba0f1d86307752ed7d593d59e923c8d4054jvr elif value == "ExpertEncoding": 985b9702ba0f1d86307752ed7d593d59e923c8d4054jvr return 1 986b9702ba0f1d86307752ed7d593d59e923c8d4054jvr return 0 # dummy value 987b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 988b9702ba0f1d86307752ed7d593d59e923c8d4054jvr def xmlWrite(self, xmlWriter, name, value, progress): 989b9702ba0f1d86307752ed7d593d59e923c8d4054jvr if value in ("StandardEncoding", "ExpertEncoding"): 990b9702ba0f1d86307752ed7d593d59e923c8d4054jvr xmlWriter.simpletag(name, name=value) 991b9702ba0f1d86307752ed7d593d59e923c8d4054jvr xmlWriter.newline() 992b9702ba0f1d86307752ed7d593d59e923c8d4054jvr return 993b9702ba0f1d86307752ed7d593d59e923c8d4054jvr xmlWriter.begintag(name) 994b9702ba0f1d86307752ed7d593d59e923c8d4054jvr xmlWriter.newline() 995b9702ba0f1d86307752ed7d593d59e923c8d4054jvr for code in range(len(value)): 996b9702ba0f1d86307752ed7d593d59e923c8d4054jvr glyphName = value[code] 997b9702ba0f1d86307752ed7d593d59e923c8d4054jvr if glyphName != ".notdef": 998b9702ba0f1d86307752ed7d593d59e923c8d4054jvr xmlWriter.simpletag("map", code=hex(code), name=glyphName) 999b9702ba0f1d86307752ed7d593d59e923c8d4054jvr xmlWriter.newline() 1000b9702ba0f1d86307752ed7d593d59e923c8d4054jvr xmlWriter.endtag(name) 1001b9702ba0f1d86307752ed7d593d59e923c8d4054jvr xmlWriter.newline() 1002b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 10033a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def xmlRead(self, name, attrs, content, parent): 1004bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod if "name" in attrs: 1005b9702ba0f1d86307752ed7d593d59e923c8d4054jvr return attrs["name"] 1006b9702ba0f1d86307752ed7d593d59e923c8d4054jvr encoding = [".notdef"] * 256 1007b9702ba0f1d86307752ed7d593d59e923c8d4054jvr for element in content: 10082a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr if isinstance(element, basestring): 1009b9702ba0f1d86307752ed7d593d59e923c8d4054jvr continue 1010b9702ba0f1d86307752ed7d593d59e923c8d4054jvr name, attrs, content = element 1011b9702ba0f1d86307752ed7d593d59e923c8d4054jvr code = safeEval(attrs["code"]) 1012b9702ba0f1d86307752ed7d593d59e923c8d4054jvr glyphName = attrs["name"] 1013b9702ba0f1d86307752ed7d593d59e923c8d4054jvr encoding[code] = glyphName 1014b9702ba0f1d86307752ed7d593d59e923c8d4054jvr return encoding 1015b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 1016b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 1017b9702ba0f1d86307752ed7d593d59e923c8d4054jvrdef parseEncoding0(charset, file, haveSupplement, strings): 1018b9702ba0f1d86307752ed7d593d59e923c8d4054jvr nCodes = readCard8(file) 1019b9702ba0f1d86307752ed7d593d59e923c8d4054jvr encoding = [".notdef"] * 256 1020b9702ba0f1d86307752ed7d593d59e923c8d4054jvr for glyphID in range(1, nCodes + 1): 1021b9702ba0f1d86307752ed7d593d59e923c8d4054jvr code = readCard8(file) 1022b9702ba0f1d86307752ed7d593d59e923c8d4054jvr if code != 0: 1023b9702ba0f1d86307752ed7d593d59e923c8d4054jvr encoding[code] = charset[glyphID] 1024b9702ba0f1d86307752ed7d593d59e923c8d4054jvr return encoding 1025b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 1026b9702ba0f1d86307752ed7d593d59e923c8d4054jvrdef parseEncoding1(charset, file, haveSupplement, strings): 1027b9702ba0f1d86307752ed7d593d59e923c8d4054jvr nRanges = readCard8(file) 1028b9702ba0f1d86307752ed7d593d59e923c8d4054jvr encoding = [".notdef"] * 256 1029b9702ba0f1d86307752ed7d593d59e923c8d4054jvr glyphID = 1 1030b9702ba0f1d86307752ed7d593d59e923c8d4054jvr for i in range(nRanges): 1031b9702ba0f1d86307752ed7d593d59e923c8d4054jvr code = readCard8(file) 1032b9702ba0f1d86307752ed7d593d59e923c8d4054jvr nLeft = readCard8(file) 1033b9702ba0f1d86307752ed7d593d59e923c8d4054jvr for glyphID in range(glyphID, glyphID + nLeft + 1): 1034b9702ba0f1d86307752ed7d593d59e923c8d4054jvr encoding[code] = charset[glyphID] 1035b9702ba0f1d86307752ed7d593d59e923c8d4054jvr code = code + 1 1036b9702ba0f1d86307752ed7d593d59e923c8d4054jvr glyphID = glyphID + 1 1037b9702ba0f1d86307752ed7d593d59e923c8d4054jvr return encoding 1038b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 1039b9702ba0f1d86307752ed7d593d59e923c8d4054jvrdef packEncoding0(charset, encoding, strings): 1040153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod fmt = 0 1041b9702ba0f1d86307752ed7d593d59e923c8d4054jvr m = {} 1042b9702ba0f1d86307752ed7d593d59e923c8d4054jvr for code in range(len(encoding)): 1043b9702ba0f1d86307752ed7d593d59e923c8d4054jvr name = encoding[code] 1044b9702ba0f1d86307752ed7d593d59e923c8d4054jvr if name != ".notdef": 1045b9702ba0f1d86307752ed7d593d59e923c8d4054jvr m[name] = code 1046b9702ba0f1d86307752ed7d593d59e923c8d4054jvr codes = [] 1047b9702ba0f1d86307752ed7d593d59e923c8d4054jvr for name in charset[1:]: 1048b9702ba0f1d86307752ed7d593d59e923c8d4054jvr code = m.get(name) 1049b9702ba0f1d86307752ed7d593d59e923c8d4054jvr codes.append(code) 1050b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 1051b9702ba0f1d86307752ed7d593d59e923c8d4054jvr while codes and codes[-1] is None: 1052b9702ba0f1d86307752ed7d593d59e923c8d4054jvr codes.pop() 1053b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 1054153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod data = [packCard8(fmt), packCard8(len(codes))] 1055b9702ba0f1d86307752ed7d593d59e923c8d4054jvr for code in codes: 1056b9702ba0f1d86307752ed7d593d59e923c8d4054jvr if code is None: 1057b9702ba0f1d86307752ed7d593d59e923c8d4054jvr code = 0 1058b9702ba0f1d86307752ed7d593d59e923c8d4054jvr data.append(packCard8(code)) 105918316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod return bytesjoin(data) 1060b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 1061b9702ba0f1d86307752ed7d593d59e923c8d4054jvrdef packEncoding1(charset, encoding, strings): 1062153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod fmt = 1 1063b9702ba0f1d86307752ed7d593d59e923c8d4054jvr m = {} 1064b9702ba0f1d86307752ed7d593d59e923c8d4054jvr for code in range(len(encoding)): 1065b9702ba0f1d86307752ed7d593d59e923c8d4054jvr name = encoding[code] 1066b9702ba0f1d86307752ed7d593d59e923c8d4054jvr if name != ".notdef": 1067b9702ba0f1d86307752ed7d593d59e923c8d4054jvr m[name] = code 1068b9702ba0f1d86307752ed7d593d59e923c8d4054jvr ranges = [] 1069b9702ba0f1d86307752ed7d593d59e923c8d4054jvr first = None 1070b9702ba0f1d86307752ed7d593d59e923c8d4054jvr end = 0 1071b9702ba0f1d86307752ed7d593d59e923c8d4054jvr for name in charset[1:]: 1072b9702ba0f1d86307752ed7d593d59e923c8d4054jvr code = m.get(name, -1) 1073b9702ba0f1d86307752ed7d593d59e923c8d4054jvr if first is None: 1074b9702ba0f1d86307752ed7d593d59e923c8d4054jvr first = code 1075180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod elif end + 1 != code: 1076b9702ba0f1d86307752ed7d593d59e923c8d4054jvr nLeft = end - first 1077b9702ba0f1d86307752ed7d593d59e923c8d4054jvr ranges.append((first, nLeft)) 1078b9702ba0f1d86307752ed7d593d59e923c8d4054jvr first = code 1079b9702ba0f1d86307752ed7d593d59e923c8d4054jvr end = code 1080b9702ba0f1d86307752ed7d593d59e923c8d4054jvr nLeft = end - first 1081b9702ba0f1d86307752ed7d593d59e923c8d4054jvr ranges.append((first, nLeft)) 1082b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 1083b9702ba0f1d86307752ed7d593d59e923c8d4054jvr # remove unencoded glyphs at the end. 1084b9702ba0f1d86307752ed7d593d59e923c8d4054jvr while ranges and ranges[-1][0] == -1: 1085b9702ba0f1d86307752ed7d593d59e923c8d4054jvr ranges.pop() 1086b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 1087153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod data = [packCard8(fmt), packCard8(len(ranges))] 1088b9702ba0f1d86307752ed7d593d59e923c8d4054jvr for first, nLeft in ranges: 1089b9702ba0f1d86307752ed7d593d59e923c8d4054jvr if first == -1: # unencoded 1090b9702ba0f1d86307752ed7d593d59e923c8d4054jvr first = 0 1091b9702ba0f1d86307752ed7d593d59e923c8d4054jvr data.append(packCard8(first) + packCard8(nLeft)) 109218316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod return bytesjoin(data) 1093b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 1094b9702ba0f1d86307752ed7d593d59e923c8d4054jvr 10954e5af60930726d06a58a30bae45bb27ae50aea77jvrclass FDArrayConverter(TableConverter): 1096ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1097a2ad5447fb707448d2c442b16956f87e048ef0d1jvr def read(self, parent, value): 1098a2ad5447fb707448d2c442b16956f87e048ef0d1jvr file = parent.file 1099a2ad5447fb707448d2c442b16956f87e048ef0d1jvr file.seek(value) 1100ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdArray = FDArrayIndex(file) 1101a2ad5447fb707448d2c442b16956f87e048ef0d1jvr fdArray.strings = parent.strings 1102a2ad5447fb707448d2c442b16956f87e048ef0d1jvr fdArray.GlobalSubrs = parent.GlobalSubrs 1103a2ad5447fb707448d2c442b16956f87e048ef0d1jvr return fdArray 1104a2ad5447fb707448d2c442b16956f87e048ef0d1jvr 1105ed10151701a7d22e5ff4e06766edff59bd713c89jvr def write(self, parent, value): 1106ed10151701a7d22e5ff4e06766edff59bd713c89jvr return 0 # dummy value 1107ed10151701a7d22e5ff4e06766edff59bd713c89jvr 11083a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def xmlRead(self, name, attrs, content, parent): 1109ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdArray = FDArrayIndex() 1110ed10151701a7d22e5ff4e06766edff59bd713c89jvr for element in content: 11112a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr if isinstance(element, basestring): 1112ed10151701a7d22e5ff4e06766edff59bd713c89jvr continue 11133a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod name, attrs, content = element 11143a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod fdArray.fromXML(name, attrs, content) 1115ed10151701a7d22e5ff4e06766edff59bd713c89jvr return fdArray 1116ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1117a2ad5447fb707448d2c442b16956f87e048ef0d1jvr 1118e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass FDSelectConverter(object): 1119ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1120a2ad5447fb707448d2c442b16956f87e048ef0d1jvr def read(self, parent, value): 1121a2ad5447fb707448d2c442b16956f87e048ef0d1jvr file = parent.file 1122a2ad5447fb707448d2c442b16956f87e048ef0d1jvr file.seek(value) 1123ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdSelect = FDSelect(file, parent.numGlyphs) 1124ed10151701a7d22e5ff4e06766edff59bd713c89jvr return fdSelect 1125ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1126ed10151701a7d22e5ff4e06766edff59bd713c89jvr def write(self, parent, value): 1127ed10151701a7d22e5ff4e06766edff59bd713c89jvr return 0 # dummy value 1128ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1129ed10151701a7d22e5ff4e06766edff59bd713c89jvr # The FDSelect glyph data is written out to XML in the charstring keys, 1130ed10151701a7d22e5ff4e06766edff59bd713c89jvr # so we write out only the format selector 1131ed10151701a7d22e5ff4e06766edff59bd713c89jvr def xmlWrite(self, xmlWriter, name, value, progress): 1132ed10151701a7d22e5ff4e06766edff59bd713c89jvr xmlWriter.simpletag(name, [('format', value.format)]) 1133ed10151701a7d22e5ff4e06766edff59bd713c89jvr xmlWriter.newline() 1134ed10151701a7d22e5ff4e06766edff59bd713c89jvr 11353a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def xmlRead(self, name, attrs, content, parent): 1136153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod fmt = safeEval(attrs["format"]) 1137ed10151701a7d22e5ff4e06766edff59bd713c89jvr file = None 1138ed10151701a7d22e5ff4e06766edff59bd713c89jvr numGlyphs = None 1139153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod fdSelect = FDSelect(file, numGlyphs, fmt) 1140ed10151701a7d22e5ff4e06766edff59bd713c89jvr return fdSelect 1141ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1142ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1143ed10151701a7d22e5ff4e06766edff59bd713c89jvrdef packFDSelect0(fdSelectArray): 1144153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod fmt = 0 1145153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod data = [packCard8(fmt)] 1146ed10151701a7d22e5ff4e06766edff59bd713c89jvr for index in fdSelectArray: 1147ed10151701a7d22e5ff4e06766edff59bd713c89jvr data.append(packCard8(index)) 114818316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod return bytesjoin(data) 1149ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1150ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1151ed10151701a7d22e5ff4e06766edff59bd713c89jvrdef packFDSelect3(fdSelectArray): 1152153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod fmt = 3 1153ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdRanges = [] 1154ed10151701a7d22e5ff4e06766edff59bd713c89jvr first = None 1155ed10151701a7d22e5ff4e06766edff59bd713c89jvr end = 0 1156ed10151701a7d22e5ff4e06766edff59bd713c89jvr lenArray = len(fdSelectArray) 1157ed10151701a7d22e5ff4e06766edff59bd713c89jvr lastFDIndex = -1 1158ed10151701a7d22e5ff4e06766edff59bd713c89jvr for i in range(lenArray): 1159ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdIndex = fdSelectArray[i] 1160ed10151701a7d22e5ff4e06766edff59bd713c89jvr if lastFDIndex != fdIndex: 1161ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdRanges.append([i, fdIndex]) 1162ed10151701a7d22e5ff4e06766edff59bd713c89jvr lastFDIndex = fdIndex 1163ed10151701a7d22e5ff4e06766edff59bd713c89jvr sentinelGID = i + 1 1164ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1165153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod data = [packCard8(fmt)] 1166ed10151701a7d22e5ff4e06766edff59bd713c89jvr data.append(packCard16( len(fdRanges) )) 1167ed10151701a7d22e5ff4e06766edff59bd713c89jvr for fdRange in fdRanges: 1168ed10151701a7d22e5ff4e06766edff59bd713c89jvr data.append(packCard16(fdRange[0])) 1169ed10151701a7d22e5ff4e06766edff59bd713c89jvr data.append(packCard8(fdRange[1])) 1170ed10151701a7d22e5ff4e06766edff59bd713c89jvr data.append(packCard16(sentinelGID)) 117118316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod return bytesjoin(data) 1172ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1173ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1174e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass FDSelectCompiler(object): 1175ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1176ed10151701a7d22e5ff4e06766edff59bd713c89jvr def __init__(self, fdSelect, parent): 1177153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod fmt = fdSelect.format 1178ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdSelectArray = fdSelect.gidArray 1179153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod if fmt == 0: 1180ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.data = packFDSelect0(fdSelectArray) 1181153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod elif fmt == 3: 1182ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.data = packFDSelect3(fdSelectArray) 1183a2ad5447fb707448d2c442b16956f87e048ef0d1jvr else: 1184ed10151701a7d22e5ff4e06766edff59bd713c89jvr # choose smaller of the two formats 1185ed10151701a7d22e5ff4e06766edff59bd713c89jvr data0 = packFDSelect0(fdSelectArray) 1186ed10151701a7d22e5ff4e06766edff59bd713c89jvr data3 = packFDSelect3(fdSelectArray) 1187ed10151701a7d22e5ff4e06766edff59bd713c89jvr if len(data0) < len(data3): 1188ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.data = data0 1189ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdSelect.format = 0 1190ed10151701a7d22e5ff4e06766edff59bd713c89jvr else: 1191ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.data = data3 1192ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdSelect.format = 3 1193ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1194ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.parent = parent 1195ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1196ed10151701a7d22e5ff4e06766edff59bd713c89jvr def setPos(self, pos, endPos): 1197ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.parent.rawDict["FDSelect"] = pos 1198ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1199ed10151701a7d22e5ff4e06766edff59bd713c89jvr def getDataLength(self): 1200ed10151701a7d22e5ff4e06766edff59bd713c89jvr return len(self.data) 1201ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1202ed10151701a7d22e5ff4e06766edff59bd713c89jvr def toFile(self, file): 1203ed10151701a7d22e5ff4e06766edff59bd713c89jvr file.write(self.data) 1204a2ad5447fb707448d2c442b16956f87e048ef0d1jvr 1205a2ad5447fb707448d2c442b16956f87e048ef0d1jvr 12064e5af60930726d06a58a30bae45bb27ae50aea77jvrclass ROSConverter(SimpleConverter): 1207ed10151701a7d22e5ff4e06766edff59bd713c89jvr 12087ce0a139ab67dd30614e728a1ef897e53ad805aejvr def xmlWrite(self, xmlWriter, name, value, progress): 1209155aa7569f9d18fda270434f38642cfffdca4873jvr registry, order, supplement = value 1210024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod xmlWriter.simpletag(name, [('Registry', tostr(registry)), ('Order', tostr(order)), 1211f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr ('Supplement', supplement)]) 12124afb2573876b6ad2ee03fc696cb045e8d1ddb237jvr xmlWriter.newline() 1213155aa7569f9d18fda270434f38642cfffdca4873jvr 12143a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def xmlRead(self, name, attrs, content, parent): 1215ed10151701a7d22e5ff4e06766edff59bd713c89jvr return (attrs['Registry'], attrs['Order'], safeEval(attrs['Supplement'])) 1216ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1217ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1218155aa7569f9d18fda270434f38642cfffdca4873jvr 12194756b3a04014645ee16a14fb6273e93efa1c7e15jvrtopDictOperators = [ 12204756b3a04014645ee16a14fb6273e93efa1c7e15jvr# opcode name argument type default converter 1221155aa7569f9d18fda270434f38642cfffdca4873jvr ((12, 30), 'ROS', ('SID','SID','number'), None, ROSConverter()), 1222f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr ((12, 20), 'SyntheticBase', 'number', None, None), 12234756b3a04014645ee16a14fb6273e93efa1c7e15jvr (0, 'version', 'SID', None, None), 1224e2ca9b5a4ff537ad827c3f722c8137b4f986d9a5jvr (1, 'Notice', 'SID', None, Latin1Converter()), 1225e2ca9b5a4ff537ad827c3f722c8137b4f986d9a5jvr ((12, 0), 'Copyright', 'SID', None, Latin1Converter()), 12264756b3a04014645ee16a14fb6273e93efa1c7e15jvr (2, 'FullName', 'SID', None, None), 1227155aa7569f9d18fda270434f38642cfffdca4873jvr ((12, 38), 'FontName', 'SID', None, None), 12284756b3a04014645ee16a14fb6273e93efa1c7e15jvr (3, 'FamilyName', 'SID', None, None), 12294756b3a04014645ee16a14fb6273e93efa1c7e15jvr (4, 'Weight', 'SID', None, None), 12304756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 1), 'isFixedPitch', 'number', 0, None), 12314756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 2), 'ItalicAngle', 'number', 0, None), 12324756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 3), 'UnderlinePosition', 'number', None, None), 12334756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 4), 'UnderlineThickness', 'number', 50, None), 12344756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 5), 'PaintType', 'number', 0, None), 12354756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 6), 'CharstringType', 'number', 2, None), 12364756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 7), 'FontMatrix', 'array', [0.001,0,0,0.001,0,0], None), 12374756b3a04014645ee16a14fb6273e93efa1c7e15jvr (13, 'UniqueID', 'number', None, None), 12384756b3a04014645ee16a14fb6273e93efa1c7e15jvr (5, 'FontBBox', 'array', [0,0,0,0], None), 12394756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 8), 'StrokeWidth', 'number', 0, None), 12404756b3a04014645ee16a14fb6273e93efa1c7e15jvr (14, 'XUID', 'array', None, None), 12414756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 21), 'PostScript', 'SID', None, None), 12424756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 22), 'BaseFontName', 'SID', None, None), 12434756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 23), 'BaseFontBlend', 'delta', None, None), 12444756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 31), 'CIDFontVersion', 'number', 0, None), 12454756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 32), 'CIDFontRevision', 'number', 0, None), 12464756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 33), 'CIDFontType', 'number', 0, None), 12474756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 34), 'CIDCount', 'number', 8720, None), 1248ed10151701a7d22e5ff4e06766edff59bd713c89jvr (15, 'charset', 'number', 0, CharsetConverter()), 12494756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 35), 'UIDBase', 'number', None, None), 1250b9702ba0f1d86307752ed7d593d59e923c8d4054jvr (16, 'Encoding', 'number', 0, EncodingConverter()), 1251155aa7569f9d18fda270434f38642cfffdca4873jvr (18, 'Private', ('number','number'), None, PrivateDictConverter()), 1252ed10151701a7d22e5ff4e06766edff59bd713c89jvr ((12, 37), 'FDSelect', 'number', None, FDSelectConverter()), 1253ed10151701a7d22e5ff4e06766edff59bd713c89jvr ((12, 36), 'FDArray', 'number', None, FDArrayConverter()), 1254155aa7569f9d18fda270434f38642cfffdca4873jvr (17, 'CharStrings', 'number', None, CharStringsConverter()), 12554756b3a04014645ee16a14fb6273e93efa1c7e15jvr] 12561890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 1257ed10151701a7d22e5ff4e06766edff59bd713c89jvr# Note! FDSelect and FDArray must both preceed CharStrings in the output XML build order, 1258ed10151701a7d22e5ff4e06766edff59bd713c89jvr# in order for the font to compile back from xml. 1259ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1260ed10151701a7d22e5ff4e06766edff59bd713c89jvr 12614756b3a04014645ee16a14fb6273e93efa1c7e15jvrprivateDictOperators = [ 12624756b3a04014645ee16a14fb6273e93efa1c7e15jvr# opcode name argument type default converter 12634756b3a04014645ee16a14fb6273e93efa1c7e15jvr (6, 'BlueValues', 'delta', None, None), 12644756b3a04014645ee16a14fb6273e93efa1c7e15jvr (7, 'OtherBlues', 'delta', None, None), 12654756b3a04014645ee16a14fb6273e93efa1c7e15jvr (8, 'FamilyBlues', 'delta', None, None), 12664756b3a04014645ee16a14fb6273e93efa1c7e15jvr (9, 'FamilyOtherBlues', 'delta', None, None), 12674756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 9), 'BlueScale', 'number', 0.039625, None), 12684756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 10), 'BlueShift', 'number', 7, None), 12694756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 11), 'BlueFuzz', 'number', 1, None), 12704756b3a04014645ee16a14fb6273e93efa1c7e15jvr (10, 'StdHW', 'number', None, None), 12714756b3a04014645ee16a14fb6273e93efa1c7e15jvr (11, 'StdVW', 'number', None, None), 12724756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 12), 'StemSnapH', 'delta', None, None), 12734756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 13), 'StemSnapV', 'delta', None, None), 12744756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 14), 'ForceBold', 'number', 0, None), 1275f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr ((12, 15), 'ForceBoldThreshold', 'number', None, None), # deprecated 1276f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr ((12, 16), 'lenIV', 'number', None, None), # deprecated 12774756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 17), 'LanguageGroup', 'number', 0, None), 12784756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 18), 'ExpansionFactor', 'number', 0.06, None), 12794756b3a04014645ee16a14fb6273e93efa1c7e15jvr ((12, 19), 'initialRandomSeed', 'number', 0, None), 12804756b3a04014645ee16a14fb6273e93efa1c7e15jvr (20, 'defaultWidthX', 'number', 0, None), 12814756b3a04014645ee16a14fb6273e93efa1c7e15jvr (21, 'nominalWidthX', 'number', 0, None), 12824756b3a04014645ee16a14fb6273e93efa1c7e15jvr (19, 'Subrs', 'number', None, SubrsConverter()), 12834756b3a04014645ee16a14fb6273e93efa1c7e15jvr] 12841890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 12854e5af60930726d06a58a30bae45bb27ae50aea77jvrdef addConverters(table): 12864e5af60930726d06a58a30bae45bb27ae50aea77jvr for i in range(len(table)): 12874e5af60930726d06a58a30bae45bb27ae50aea77jvr op, name, arg, default, conv = table[i] 12884e5af60930726d06a58a30bae45bb27ae50aea77jvr if conv is not None: 12894e5af60930726d06a58a30bae45bb27ae50aea77jvr continue 12904e5af60930726d06a58a30bae45bb27ae50aea77jvr if arg in ("delta", "array"): 12914e5af60930726d06a58a30bae45bb27ae50aea77jvr conv = ArrayConverter() 12924e5af60930726d06a58a30bae45bb27ae50aea77jvr elif arg == "number": 12934e5af60930726d06a58a30bae45bb27ae50aea77jvr conv = NumberConverter() 12944e5af60930726d06a58a30bae45bb27ae50aea77jvr elif arg == "SID": 1295024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod conv = ASCIIConverter() 12964e5af60930726d06a58a30bae45bb27ae50aea77jvr else: 1297153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod assert False 12984e5af60930726d06a58a30bae45bb27ae50aea77jvr table[i] = op, name, arg, default, conv 12994e5af60930726d06a58a30bae45bb27ae50aea77jvr 13004e5af60930726d06a58a30bae45bb27ae50aea77jvraddConverters(privateDictOperators) 13014e5af60930726d06a58a30bae45bb27ae50aea77jvraddConverters(topDictOperators) 13024e5af60930726d06a58a30bae45bb27ae50aea77jvr 13031890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 13044756b3a04014645ee16a14fb6273e93efa1c7e15jvrclass TopDictDecompiler(psCharStrings.DictDecompiler): 13054756b3a04014645ee16a14fb6273e93efa1c7e15jvr operators = buildOperatorDict(topDictOperators) 13061890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr 1307e327558aa54f182912a26b8313f3af5a07bc2e77jvr 13084756b3a04014645ee16a14fb6273e93efa1c7e15jvrclass PrivateDictDecompiler(psCharStrings.DictDecompiler): 13094756b3a04014645ee16a14fb6273e93efa1c7e15jvr operators = buildOperatorDict(privateDictOperators) 1310e327558aa54f182912a26b8313f3af5a07bc2e77jvr 13114756b3a04014645ee16a14fb6273e93efa1c7e15jvr 1312e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass DictCompiler(object): 1313f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1314f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def __init__(self, dictObj, strings, parent): 1315f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr assert isinstance(strings, IndexedStrings) 1316f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.dictObj = dictObj 1317f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.strings = strings 1318f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.parent = parent 1319f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr rawDict = {} 1320f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for name in dictObj.order: 1321f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr value = getattr(dictObj, name, None) 1322f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if value is None: 1323f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr continue 1324f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr conv = dictObj.converters[name] 13254e5af60930726d06a58a30bae45bb27ae50aea77jvr value = conv.write(dictObj, value) 1326f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if value == dictObj.defaults.get(name): 1327f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr continue 1328f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr rawDict[name] = value 1329f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.rawDict = rawDict 1330f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 13314e5af60930726d06a58a30bae45bb27ae50aea77jvr def setPos(self, pos, endPos): 1332f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr pass 1333f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1334f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def getDataLength(self): 13354e5af60930726d06a58a30bae45bb27ae50aea77jvr return len(self.compile("getDataLength")) 1336f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 13374e5af60930726d06a58a30bae45bb27ae50aea77jvr def compile(self, reason): 13384e5af60930726d06a58a30bae45bb27ae50aea77jvr if DEBUG: 13393ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print("-- compiling %s for %s" % (self.__class__.__name__, reason)) 13403ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print("in baseDict: ", self) 1341f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr rawDict = self.rawDict 1342f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr data = [] 1343f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for name in self.dictObj.order: 1344f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr value = rawDict.get(name) 1345f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if value is None: 1346f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr continue 1347f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr op, argType = self.opcodes[name] 13482a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr if isinstance(argType, tuple): 1349f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr l = len(argType) 1350f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr assert len(value) == l, "value doesn't match arg type" 1351f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for i in range(l): 1352ed10151701a7d22e5ff4e06766edff59bd713c89jvr arg = argType[i] 1353f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr v = value[i] 1354f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr arghandler = getattr(self, "arg_" + arg) 1355f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr data.append(arghandler(v)) 1356f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr else: 1357f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr arghandler = getattr(self, "arg_" + argType) 1358f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr data.append(arghandler(value)) 1359f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr data.append(op) 136018316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod return bytesjoin(data) 1361f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1362f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def toFile(self, file): 13634e5af60930726d06a58a30bae45bb27ae50aea77jvr file.write(self.compile("toFile")) 1364f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1365f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def arg_number(self, num): 1366f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return encodeNumber(num) 1367f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def arg_SID(self, s): 1368f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return psCharStrings.encodeIntCFF(self.strings.getSID(s)) 1369f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def arg_array(self, value): 1370f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr data = [] 1371f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for num in value: 1372f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr data.append(encodeNumber(num)) 137318316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod return bytesjoin(data) 1374f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def arg_delta(self, value): 1375f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr out = [] 1376f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr last = 0 1377f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for v in value: 1378f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr out.append(v - last) 1379f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr last = v 1380f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr data = [] 1381f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for num in out: 1382f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr data.append(encodeNumber(num)) 138318316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod return bytesjoin(data) 1384f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1385f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1386f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef encodeNumber(num): 1387f6ff48be3c858d7c4f942e1d4f062120c2e376e0jvr if isinstance(num, float): 1388f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return psCharStrings.encodeFloat(num) 1389f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr else: 1390f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return psCharStrings.encodeIntCFF(num) 1391f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1392f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1393f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass TopDictCompiler(DictCompiler): 1394f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1395f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr opcodes = buildOpcodeDict(topDictOperators) 1396f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1397f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def getChildren(self, strings): 1398f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr children = [] 1399ed10151701a7d22e5ff4e06766edff59bd713c89jvr if hasattr(self.dictObj, "charset") and self.dictObj.charset: 1400f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr children.append(CharsetCompiler(strings, self.dictObj.charset, self)) 1401b9702ba0f1d86307752ed7d593d59e923c8d4054jvr if hasattr(self.dictObj, "Encoding"): 1402b9702ba0f1d86307752ed7d593d59e923c8d4054jvr encoding = self.dictObj.Encoding 14032a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr if not isinstance(encoding, basestring): 1404b9702ba0f1d86307752ed7d593d59e923c8d4054jvr children.append(EncodingCompiler(strings, encoding, self)) 1405ce522410f26648af01372cc96fe689cf3b3a7c84jvr if hasattr(self.dictObj, "FDSelect"): 1406ed10151701a7d22e5ff4e06766edff59bd713c89jvr # I have not yet supported merging a ttx CFF-CID font, as there are interesting 1407ed10151701a7d22e5ff4e06766edff59bd713c89jvr # issues about merging the FDArrays. Here I assume that 1408ed10151701a7d22e5ff4e06766edff59bd713c89jvr # either the font was read from XML, and teh FDSelect indices are all 1409ed10151701a7d22e5ff4e06766edff59bd713c89jvr # in the charstring data, or the FDSelect array is already fully defined. 1410ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdSelect = self.dictObj.FDSelect 1411ed10151701a7d22e5ff4e06766edff59bd713c89jvr if len(fdSelect) == 0: # probably read in from XML; assume fdIndex in CharString data 1412ed10151701a7d22e5ff4e06766edff59bd713c89jvr charStrings = self.dictObj.CharStrings 1413ed10151701a7d22e5ff4e06766edff59bd713c89jvr for name in self.dictObj.charset: 1414ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdSelect.append(charStrings[name].fdSelectIndex) 1415ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdSelectComp = FDSelectCompiler(fdSelect, self) 1416ed10151701a7d22e5ff4e06766edff59bd713c89jvr children.append(fdSelectComp) 1417f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if hasattr(self.dictObj, "CharStrings"): 1418f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr items = [] 1419f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr charStrings = self.dictObj.CharStrings 1420f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr for name in self.dictObj.charset: 1421f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr items.append(charStrings[name]) 1422f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr charStringsComp = CharStringsCompiler(items, strings, self) 1423f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr children.append(charStringsComp) 1424ce522410f26648af01372cc96fe689cf3b3a7c84jvr if hasattr(self.dictObj, "FDArray"): 1425ed10151701a7d22e5ff4e06766edff59bd713c89jvr # I have not yet supported merging a ttx CFF-CID font, as there are interesting 1426ed10151701a7d22e5ff4e06766edff59bd713c89jvr # issues about merging the FDArrays. Here I assume that the FDArray info is correct 1427ed10151701a7d22e5ff4e06766edff59bd713c89jvr # and complete. 1428ed10151701a7d22e5ff4e06766edff59bd713c89jvr fdArrayIndexComp = self.dictObj.FDArray.getCompiler(strings, self) 1429ed10151701a7d22e5ff4e06766edff59bd713c89jvr children.append(fdArrayIndexComp) 1430ed10151701a7d22e5ff4e06766edff59bd713c89jvr children.extend(fdArrayIndexComp.getChildren(strings)) 1431ed10151701a7d22e5ff4e06766edff59bd713c89jvr if hasattr(self.dictObj, "Private"): 1432ed10151701a7d22e5ff4e06766edff59bd713c89jvr privComp = self.dictObj.Private.getCompiler(strings, self) 1433ed10151701a7d22e5ff4e06766edff59bd713c89jvr children.append(privComp) 1434ed10151701a7d22e5ff4e06766edff59bd713c89jvr children.extend(privComp.getChildren(strings)) 1435ed10151701a7d22e5ff4e06766edff59bd713c89jvr return children 1436ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1437ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1438ed10151701a7d22e5ff4e06766edff59bd713c89jvrclass FontDictCompiler(DictCompiler): 1439ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1440ed10151701a7d22e5ff4e06766edff59bd713c89jvr opcodes = buildOpcodeDict(topDictOperators) 1441ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1442ed10151701a7d22e5ff4e06766edff59bd713c89jvr def getChildren(self, strings): 1443ed10151701a7d22e5ff4e06766edff59bd713c89jvr children = [] 1444f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if hasattr(self.dictObj, "Private"): 1445f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr privComp = self.dictObj.Private.getCompiler(strings, self) 1446f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr children.append(privComp) 1447f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr children.extend(privComp.getChildren(strings)) 1448f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return children 1449f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1450f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1451f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass PrivateDictCompiler(DictCompiler): 1452f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1453f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr opcodes = buildOpcodeDict(privateDictOperators) 1454f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 14554e5af60930726d06a58a30bae45bb27ae50aea77jvr def setPos(self, pos, endPos): 14564e5af60930726d06a58a30bae45bb27ae50aea77jvr size = endPos - pos 1457f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.parent.rawDict["Private"] = size, pos 1458f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr self.pos = pos 1459f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1460f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def getChildren(self, strings): 1461f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr children = [] 1462f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if hasattr(self.dictObj, "Subrs"): 1463f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr children.append(self.dictObj.Subrs.getCompiler(strings, self)) 1464f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return children 1465f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 14664756b3a04014645ee16a14fb6273e93efa1c7e15jvr 1467e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass BaseDict(object): 1468e327558aa54f182912a26b8313f3af5a07bc2e77jvr 14694e5af60930726d06a58a30bae45bb27ae50aea77jvr def __init__(self, strings=None, file=None, offset=None): 14704756b3a04014645ee16a14fb6273e93efa1c7e15jvr self.rawDict = {} 1471767102ea85a8af1535c169b2e04da5ba458f3b80jvr if DEBUG: 14723ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print("loading %s at %s" % (self.__class__.__name__, offset)) 14734756b3a04014645ee16a14fb6273e93efa1c7e15jvr self.file = file 14744756b3a04014645ee16a14fb6273e93efa1c7e15jvr self.offset = offset 14754756b3a04014645ee16a14fb6273e93efa1c7e15jvr self.strings = strings 1476155aa7569f9d18fda270434f38642cfffdca4873jvr self.skipNames = [] 1477e327558aa54f182912a26b8313f3af5a07bc2e77jvr 14784756b3a04014645ee16a14fb6273e93efa1c7e15jvr def decompile(self, data): 1479f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr if DEBUG: 14803ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print(" length %s is %s" % (self.__class__.__name__, len(data))) 1481f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr dec = self.decompilerClass(self.strings) 14824756b3a04014645ee16a14fb6273e93efa1c7e15jvr dec.decompile(data) 14834756b3a04014645ee16a14fb6273e93efa1c7e15jvr self.rawDict = dec.getDict() 14844756b3a04014645ee16a14fb6273e93efa1c7e15jvr self.postDecompile() 14854756b3a04014645ee16a14fb6273e93efa1c7e15jvr 14864756b3a04014645ee16a14fb6273e93efa1c7e15jvr def postDecompile(self): 14874756b3a04014645ee16a14fb6273e93efa1c7e15jvr pass 14884756b3a04014645ee16a14fb6273e93efa1c7e15jvr 1489f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def getCompiler(self, strings, parent): 1490f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return self.compilerClass(self, strings, parent) 1491f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 14924756b3a04014645ee16a14fb6273e93efa1c7e15jvr def __getattr__(self, name): 14934756b3a04014645ee16a14fb6273e93efa1c7e15jvr value = self.rawDict.get(name) 14944756b3a04014645ee16a14fb6273e93efa1c7e15jvr if value is None: 14954756b3a04014645ee16a14fb6273e93efa1c7e15jvr value = self.defaults.get(name) 14964756b3a04014645ee16a14fb6273e93efa1c7e15jvr if value is None: 1497cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise AttributeError(name) 14984756b3a04014645ee16a14fb6273e93efa1c7e15jvr conv = self.converters[name] 14994e5af60930726d06a58a30bae45bb27ae50aea77jvr value = conv.read(self, value) 15004756b3a04014645ee16a14fb6273e93efa1c7e15jvr setattr(self, name, value) 15014756b3a04014645ee16a14fb6273e93efa1c7e15jvr return value 15024756b3a04014645ee16a14fb6273e93efa1c7e15jvr 15034756b3a04014645ee16a14fb6273e93efa1c7e15jvr def toXML(self, xmlWriter, progress): 15044756b3a04014645ee16a14fb6273e93efa1c7e15jvr for name in self.order: 1505155aa7569f9d18fda270434f38642cfffdca4873jvr if name in self.skipNames: 1506155aa7569f9d18fda270434f38642cfffdca4873jvr continue 15074756b3a04014645ee16a14fb6273e93efa1c7e15jvr value = getattr(self, name, None) 15084756b3a04014645ee16a14fb6273e93efa1c7e15jvr if value is None: 15094756b3a04014645ee16a14fb6273e93efa1c7e15jvr continue 15104e5af60930726d06a58a30bae45bb27ae50aea77jvr conv = self.converters[name] 15117ce0a139ab67dd30614e728a1ef897e53ad805aejvr conv.xmlWrite(xmlWriter, name, value, progress) 15124e5af60930726d06a58a30bae45bb27ae50aea77jvr 15133a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def fromXML(self, name, attrs, content): 15144e5af60930726d06a58a30bae45bb27ae50aea77jvr conv = self.converters[name] 15153a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod value = conv.xmlRead(name, attrs, content, self) 15164e5af60930726d06a58a30bae45bb27ae50aea77jvr setattr(self, name, value) 1517e327558aa54f182912a26b8313f3af5a07bc2e77jvr 1518e327558aa54f182912a26b8313f3af5a07bc2e77jvr 15194756b3a04014645ee16a14fb6273e93efa1c7e15jvrclass TopDict(BaseDict): 1520e327558aa54f182912a26b8313f3af5a07bc2e77jvr 15214756b3a04014645ee16a14fb6273e93efa1c7e15jvr defaults = buildDefaults(topDictOperators) 15224756b3a04014645ee16a14fb6273e93efa1c7e15jvr converters = buildConverters(topDictOperators) 15234756b3a04014645ee16a14fb6273e93efa1c7e15jvr order = buildOrder(topDictOperators) 1524f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr decompilerClass = TopDictDecompiler 1525f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr compilerClass = TopDictCompiler 15264756b3a04014645ee16a14fb6273e93efa1c7e15jvr 15274e5af60930726d06a58a30bae45bb27ae50aea77jvr def __init__(self, strings=None, file=None, offset=None, GlobalSubrs=None): 1528016ca76e918ed36888c0fa8e287028ea367ef3d9jvr BaseDict.__init__(self, strings, file, offset) 1529016ca76e918ed36888c0fa8e287028ea367ef3d9jvr self.GlobalSubrs = GlobalSubrs 1530016ca76e918ed36888c0fa8e287028ea367ef3d9jvr 15314756b3a04014645ee16a14fb6273e93efa1c7e15jvr def getGlyphOrder(self): 15324756b3a04014645ee16a14fb6273e93efa1c7e15jvr return self.charset 15334756b3a04014645ee16a14fb6273e93efa1c7e15jvr 15344756b3a04014645ee16a14fb6273e93efa1c7e15jvr def postDecompile(self): 15354756b3a04014645ee16a14fb6273e93efa1c7e15jvr offset = self.rawDict.get("CharStrings") 15364756b3a04014645ee16a14fb6273e93efa1c7e15jvr if offset is None: 15374756b3a04014645ee16a14fb6273e93efa1c7e15jvr return 15384756b3a04014645ee16a14fb6273e93efa1c7e15jvr # get the number of glyphs beforehand. 15394756b3a04014645ee16a14fb6273e93efa1c7e15jvr self.file.seek(offset) 1540a2ad5447fb707448d2c442b16956f87e048ef0d1jvr self.numGlyphs = readCard16(self.file) 15414756b3a04014645ee16a14fb6273e93efa1c7e15jvr 1542016ca76e918ed36888c0fa8e287028ea367ef3d9jvr def toXML(self, xmlWriter, progress): 1543155aa7569f9d18fda270434f38642cfffdca4873jvr if hasattr(self, "CharStrings"): 15447ce0a139ab67dd30614e728a1ef897e53ad805aejvr self.decompileAllCharStrings(progress) 1545ed10151701a7d22e5ff4e06766edff59bd713c89jvr if hasattr(self, "ROS"): 1546ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.skipNames = ['Encoding'] 1547155aa7569f9d18fda270434f38642cfffdca4873jvr if not hasattr(self, "ROS") or not hasattr(self, "CharStrings"): 1548155aa7569f9d18fda270434f38642cfffdca4873jvr # these values have default values, but I only want them to show up 1549155aa7569f9d18fda270434f38642cfffdca4873jvr # in CID fonts. 1550155aa7569f9d18fda270434f38642cfffdca4873jvr self.skipNames = ['CIDFontVersion', 'CIDFontRevision', 'CIDFontType', 1551155aa7569f9d18fda270434f38642cfffdca4873jvr 'CIDCount'] 1552016ca76e918ed36888c0fa8e287028ea367ef3d9jvr BaseDict.toXML(self, xmlWriter, progress) 1553767102ea85a8af1535c169b2e04da5ba458f3b80jvr 15547ce0a139ab67dd30614e728a1ef897e53ad805aejvr def decompileAllCharStrings(self, progress): 15554e5af60930726d06a58a30bae45bb27ae50aea77jvr # XXX only when doing ttdump -i? 15567ce0a139ab67dd30614e728a1ef897e53ad805aejvr i = 0 1557a2ad5447fb707448d2c442b16956f87e048ef0d1jvr for charString in self.CharStrings.values(): 1558ed10151701a7d22e5ff4e06766edff59bd713c89jvr try: 1559ed10151701a7d22e5ff4e06766edff59bd713c89jvr charString.decompile() 1560ed10151701a7d22e5ff4e06766edff59bd713c89jvr except: 15613ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print("Error in charstring ", i) 1562ed10151701a7d22e5ff4e06766edff59bd713c89jvr import sys 1563153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod typ, value = sys.exc_info()[0:2] 1564153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod raise typ(value) 15657ce0a139ab67dd30614e728a1ef897e53ad805aejvr if not i % 30 and progress: 15667ce0a139ab67dd30614e728a1ef897e53ad805aejvr progress.increment(0) # update 15677ce0a139ab67dd30614e728a1ef897e53ad805aejvr i = i + 1 15684756b3a04014645ee16a14fb6273e93efa1c7e15jvr 15694756b3a04014645ee16a14fb6273e93efa1c7e15jvr 1570ed10151701a7d22e5ff4e06766edff59bd713c89jvrclass FontDict(BaseDict): 1571ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1572ed10151701a7d22e5ff4e06766edff59bd713c89jvr defaults = buildDefaults(topDictOperators) 1573ed10151701a7d22e5ff4e06766edff59bd713c89jvr converters = buildConverters(topDictOperators) 1574ed10151701a7d22e5ff4e06766edff59bd713c89jvr order = buildOrder(topDictOperators) 1575ed10151701a7d22e5ff4e06766edff59bd713c89jvr decompilerClass = None 1576ed10151701a7d22e5ff4e06766edff59bd713c89jvr compilerClass = FontDictCompiler 1577ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1578ed10151701a7d22e5ff4e06766edff59bd713c89jvr def __init__(self, strings=None, file=None, offset=None, GlobalSubrs=None): 1579ed10151701a7d22e5ff4e06766edff59bd713c89jvr BaseDict.__init__(self, strings, file, offset) 1580ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.GlobalSubrs = GlobalSubrs 1581ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1582ed10151701a7d22e5ff4e06766edff59bd713c89jvr def getGlyphOrder(self): 1583ed10151701a7d22e5ff4e06766edff59bd713c89jvr return self.charset 1584ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1585ed10151701a7d22e5ff4e06766edff59bd713c89jvr def toXML(self, xmlWriter, progress): 1586ed10151701a7d22e5ff4e06766edff59bd713c89jvr self.skipNames = ['Encoding'] 1587ed10151701a7d22e5ff4e06766edff59bd713c89jvr BaseDict.toXML(self, xmlWriter, progress) 1588ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1589ed10151701a7d22e5ff4e06766edff59bd713c89jvr 1590ed10151701a7d22e5ff4e06766edff59bd713c89jvr 15914756b3a04014645ee16a14fb6273e93efa1c7e15jvrclass PrivateDict(BaseDict): 15924756b3a04014645ee16a14fb6273e93efa1c7e15jvr defaults = buildDefaults(privateDictOperators) 15934756b3a04014645ee16a14fb6273e93efa1c7e15jvr converters = buildConverters(privateDictOperators) 15944756b3a04014645ee16a14fb6273e93efa1c7e15jvr order = buildOrder(privateDictOperators) 1595f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr decompilerClass = PrivateDictDecompiler 1596f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr compilerClass = PrivateDictCompiler 15974756b3a04014645ee16a14fb6273e93efa1c7e15jvr 15984756b3a04014645ee16a14fb6273e93efa1c7e15jvr 1599e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass IndexedStrings(object): 1600e327558aa54f182912a26b8313f3af5a07bc2e77jvr 1601767102ea85a8af1535c169b2e04da5ba458f3b80jvr """SID -> string mapping.""" 1602767102ea85a8af1535c169b2e04da5ba458f3b80jvr 1603767102ea85a8af1535c169b2e04da5ba458f3b80jvr def __init__(self, file=None): 1604767102ea85a8af1535c169b2e04da5ba458f3b80jvr if file is None: 1605e327558aa54f182912a26b8313f3af5a07bc2e77jvr strings = [] 1606767102ea85a8af1535c169b2e04da5ba458f3b80jvr else: 1607617ec41d4c2db2011e62cadf619e2a8b07aec93eBehdad Esfahbod strings = [tostr(s, encoding="latin1") for s in Index(file)] 1608e327558aa54f182912a26b8313f3af5a07bc2e77jvr self.strings = strings 1609e327558aa54f182912a26b8313f3af5a07bc2e77jvr 1610f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def getCompiler(self): 1611f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return IndexedStringsCompiler(self, None, None) 1612f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1613f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr def __len__(self): 1614f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr return len(self.strings) 1615f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr 1616e327558aa54f182912a26b8313f3af5a07bc2e77jvr def __getitem__(self, SID): 1617e327558aa54f182912a26b8313f3af5a07bc2e77jvr if SID < cffStandardStringCount: 1618e327558aa54f182912a26b8313f3af5a07bc2e77jvr return cffStandardStrings[SID] 1619e327558aa54f182912a26b8313f3af5a07bc2e77jvr else: 1620e327558aa54f182912a26b8313f3af5a07bc2e77jvr return self.strings[SID - cffStandardStringCount] 1621e327558aa54f182912a26b8313f3af5a07bc2e77jvr 1622e327558aa54f182912a26b8313f3af5a07bc2e77jvr def getSID(self, s): 1623e327558aa54f182912a26b8313f3af5a07bc2e77jvr if not hasattr(self, "stringMapping"): 1624e327558aa54f182912a26b8313f3af5a07bc2e77jvr self.buildStringMapping() 1625bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod if s in cffStandardStringMapping: 1626e327558aa54f182912a26b8313f3af5a07bc2e77jvr SID = cffStandardStringMapping[s] 1627bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod elif s in self.stringMapping: 1628e327558aa54f182912a26b8313f3af5a07bc2e77jvr SID = self.stringMapping[s] 1629e327558aa54f182912a26b8313f3af5a07bc2e77jvr else: 1630e327558aa54f182912a26b8313f3af5a07bc2e77jvr SID = len(self.strings) + cffStandardStringCount 1631e327558aa54f182912a26b8313f3af5a07bc2e77jvr self.strings.append(s) 1632e327558aa54f182912a26b8313f3af5a07bc2e77jvr self.stringMapping[s] = SID 1633e327558aa54f182912a26b8313f3af5a07bc2e77jvr return SID 1634e327558aa54f182912a26b8313f3af5a07bc2e77jvr 1635e327558aa54f182912a26b8313f3af5a07bc2e77jvr def getStrings(self): 1636e327558aa54f182912a26b8313f3af5a07bc2e77jvr return self.strings 1637e327558aa54f182912a26b8313f3af5a07bc2e77jvr 1638e327558aa54f182912a26b8313f3af5a07bc2e77jvr def buildStringMapping(self): 1639e327558aa54f182912a26b8313f3af5a07bc2e77jvr self.stringMapping = {} 1640e327558aa54f182912a26b8313f3af5a07bc2e77jvr for index in range(len(self.strings)): 1641e327558aa54f182912a26b8313f3af5a07bc2e77jvr self.stringMapping[self.strings[index]] = index + cffStandardStringCount 1642e327558aa54f182912a26b8313f3af5a07bc2e77jvr 1643e327558aa54f182912a26b8313f3af5a07bc2e77jvr 16447842e56b97ce677b83bdab09cda48bc2d89ac75aJust# The 391 Standard Strings as used in the CFF format. 16457842e56b97ce677b83bdab09cda48bc2d89ac75aJust# from Adobe Technical None #5176, version 1.0, 18 March 1998 16467842e56b97ce677b83bdab09cda48bc2d89ac75aJust 16477842e56b97ce677b83bdab09cda48bc2d89ac75aJustcffStandardStrings = ['.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 16487842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', 16497842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 16507842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 16517842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 16527842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 16537842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 16547842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 16557842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 16567842e56b97ce677b83bdab09cda48bc2d89ac75aJust 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 16577842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'asciitilde', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 16587842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', 16597842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 16607842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'daggerdbl', 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', 16617842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 16627842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 16637842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'dotaccent', 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 16647842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 16657842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', 16667842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 16677842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 16687842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 16697842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 16707842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 16717842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 16727842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 16737842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 16747842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', 16757842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', 16767842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', 16777842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', 16787842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall', 16797842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 16807842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 16817842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 16827842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 16837842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior', 16847842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 16857842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 16867842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', 16877842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 16887842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 16897842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 16907842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 16917842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', 16927842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 16937842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', 16947842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 16957842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 16967842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'onethird', 'twothirds', 'zerosuperior', 'foursuperior', 'fivesuperior', 16977842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 16987842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 16997842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 17007842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', 17017842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 17027842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 17037842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 17047842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 17057842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 17067842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 17077842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', 17087842e56b97ce677b83bdab09cda48bc2d89ac75aJust '001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 17097842e56b97ce677b83bdab09cda48bc2d89ac75aJust 'Semibold' 17107842e56b97ce677b83bdab09cda48bc2d89ac75aJust] 17117842e56b97ce677b83bdab09cda48bc2d89ac75aJust 17127842e56b97ce677b83bdab09cda48bc2d89ac75aJustcffStandardStringCount = 391 17137842e56b97ce677b83bdab09cda48bc2d89ac75aJustassert len(cffStandardStrings) == cffStandardStringCount 17147842e56b97ce677b83bdab09cda48bc2d89ac75aJust# build reverse mapping 17157842e56b97ce677b83bdab09cda48bc2d89ac75aJustcffStandardStringMapping = {} 17167842e56b97ce677b83bdab09cda48bc2d89ac75aJustfor _i in range(cffStandardStringCount): 17177842e56b97ce677b83bdab09cda48bc2d89ac75aJust cffStandardStringMapping[cffStandardStrings[_i]] = _i 1718c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr 1719c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrcffISOAdobeStrings = [".notdef", "space", "exclam", "quotedbl", "numbersign", 1720c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", 1721c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", 1722c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", 1723c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", 1724c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", 1725c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", 1726c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", 1727c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", 1728c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent", 1729c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", 1730c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", 1731c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"endash", "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", 1732c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", 1733c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"perthousand", "questiondown", "grave", "acute", "circumflex", "tilde", 1734c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", 1735c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", "Oslash", "OE", 1736c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", "germandbls", 1737c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"onesuperior", "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", 1738c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn", 1739c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"threequarters", "twosuperior", "registered", "minus", "eth", "multiply", 1740c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"threesuperior", "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", 1741c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", 1742c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", 1743c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", 1744c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute", 1745c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"acircumflex", "adieresis", "agrave", "aring", "atilde", "ccedilla", "eacute", 1746c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"ecircumflex", "edieresis", "egrave", "iacute", "icircumflex", "idieresis", 1747c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"igrave", "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", 1748c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", "ydieresis", 1749c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"zcaron"] 1750c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr 1751c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrcffISOAdobeStringCount = 229 1752c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrassert len(cffISOAdobeStrings) == cffISOAdobeStringCount 1753c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr 1754c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrcffIExpertStrings = [".notdef", "space", "exclamsmall", "Hungarumlautsmall", 1755c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", 1756c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", 1757c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"comma", "hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle", 1758c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", 1759c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", "semicolon", 1760c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", 1761c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", 1762c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", 1763c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"tsuperior", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", 1764c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", 1765c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", 1766c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", 1767c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", 1768c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", 1769c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", 1770c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Dieresissmall", "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", 1771c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"figuredash", "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", 1772c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"onequarter", "onehalf", "threequarters", "questiondownsmall", "oneeighth", 1773c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", 1774c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"zerosuperior", "onesuperior", "twosuperior", "threesuperior", "foursuperior", 1775c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", 1776c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", 1777c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", 1778c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"centinferior", "dollarinferior", "periodinferior", "commainferior", 1779c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", 1780c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", 1781c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", 1782c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", 1783c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", 1784c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", 1785c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", 1786c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Ydieresissmall"] 1787c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr 1788c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrcffExpertStringCount = 166 1789c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrassert len(cffIExpertStrings) == cffExpertStringCount 1790c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr 1791c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrcffExpertSubsetStrings = [".notdef", "space", "dollaroldstyle", 1792c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"dollarsuperior", "parenleftsuperior", "parenrightsuperior", "twodotenleader", 1793c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"onedotenleader", "comma", "hyphen", "period", "fraction", "zerooldstyle", 1794c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", 1795c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", 1796c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"semicolon", "commasuperior", "threequartersemdash", "periodsuperior", 1797c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", 1798c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", 1799c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"tsuperior", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", 1800c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"parenrightinferior", "hyphensuperior", "colonmonetary", "onefitted", "rupiah", 1801c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"centoldstyle", "figuredash", "hypheninferior", "onequarter", "onehalf", 1802c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"threequarters", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", 1803c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"onethird", "twothirds", "zerosuperior", "onesuperior", "twosuperior", 1804c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"threesuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", 1805c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", 1806c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", 1807c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"eightinferior", "nineinferior", "centinferior", "dollarinferior", 1808c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"periodinferior", "commainferior"] 1809c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr 1810c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrcffExpertSubsetStringCount = 87 1811c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrassert len(cffExpertSubsetStrings) == cffExpertSubsetStringCount 1812