cffLib.py revision cd5aad92f23737ff93a110d5c73d624658a28da8
19f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project"""cffLib.py -- read/write tools for Adobe CFF fonts.""" 29f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 39f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project# 49f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project# $Id: cffLib.py,v 1.34 2008-03-07 19:56:17 jvr Exp $ 59f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project# 69f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 79f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectimport struct 89f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectfrom fontTools.misc import sstruct 99f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectimport string 109f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectfrom fontTools.misc import psCharStrings 119f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectfrom fontTools.misc.textTools import safeEval 129f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 139f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source ProjectDEBUG = 0 149f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 159f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 169f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source ProjectcffHeaderFormat = """ 179f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project major: B 189f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project minor: B 199f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project hdrSize: B 209f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project offSize: B 219f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project""" 229f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 239f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass CFFFontSet: 249f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 259f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def __init__(self): 269f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project pass 279f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 289f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def decompile(self, file, otFont): 299f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project sstruct.unpack(cffHeaderFormat, file.read(4), self) 309f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project assert self.major == 1 and self.minor == 0, \ 319f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project "unknown CFF format: %d.%d" % (self.major, self.minor) 329f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 339f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file.seek(self.hdrSize) 349f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.fontNames = list(Index(file)) 359f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.topDictIndex = TopDictIndex(file) 369f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.strings = IndexedStrings(file) 379f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.GlobalSubrs = GlobalSubrsIndex(file) 389f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.topDictIndex.strings = self.strings 399f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.topDictIndex.GlobalSubrs = self.GlobalSubrs 409f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 419f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def __len__(self): 429f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return len(self.fontNames) 439f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 449f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def keys(self): 459f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return list(self.fontNames) 469f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 479f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def values(self): 489f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return self.topDictIndex 499f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 509f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def __getitem__(self, name): 519f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project try: 529f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project index = self.fontNames.index(name) 539f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project except ValueError: 549f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project raise KeyError(name) 559f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return self.topDictIndex[index] 569f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 579f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def compile(self, file, otFont): 589f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project strings = IndexedStrings() 599f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project writer = CFFWriter() 609f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project writer.add(sstruct.pack(cffHeaderFormat, self)) 619f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project fontNames = Index() 629f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for name in self.fontNames: 639f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project fontNames.append(name) 649f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project writer.add(fontNames.getCompiler(strings, None)) 659f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project topCompiler = self.topDictIndex.getCompiler(strings, None) 669f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project writer.add(topCompiler) 679f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project writer.add(strings.getCompiler()) 689f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project writer.add(self.GlobalSubrs.getCompiler(strings, None)) 699f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 709f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for topDict in self.topDictIndex: 719f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if not hasattr(topDict, "charset") or topDict.charset is None: 729f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charset = otFont.getGlyphOrder() 739f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project topDict.charset = charset 749f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 759f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for child in topCompiler.getChildren(strings): 769f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project writer.add(child) 779f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 789f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project writer.toFile(file) 799f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 809f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def toXML(self, xmlWriter, progress=None): 819f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 829f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for fontName in self.fontNames: 839f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.begintag("CFFFont", name=fontName) 849f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 859f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project font = self[fontName] 869f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project font.toXML(xmlWriter, progress) 879f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.endtag("CFFFont") 889f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 899f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 909f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.begintag("GlobalSubrs") 919f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 929f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.GlobalSubrs.toXML(xmlWriter, progress) 939f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.endtag("GlobalSubrs") 949f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 959f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 969f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 979f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def fromXML(self, (name, attrs, content)): 989f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if not hasattr(self, "GlobalSubrs"): 999f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.GlobalSubrs = GlobalSubrsIndex() 1009f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.major = 1 1019f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.minor = 0 1029f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.hdrSize = 4 1039f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.offSize = 4 # XXX ?? 1049f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if name == "CFFFont": 1059f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if not hasattr(self, "fontNames"): 1069f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.fontNames = [] 1079f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.topDictIndex = TopDictIndex() 1089f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project fontName = attrs["name"] 1099f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project topDict = TopDict(GlobalSubrs=self.GlobalSubrs) 1109f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project topDict.charset = None # gets filled in later 1119f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.fontNames.append(fontName) 1129f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.topDictIndex.append(topDict) 1139f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for element in content: 1149f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if isinstance(element, basestring): 1159f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project continue 1169f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project topDict.fromXML(element) 1179f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project elif name == "GlobalSubrs": 1189f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for element in content: 1199f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if isinstance(element, basestring): 1209f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project continue 1219f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project name, attrs, content = element 1229f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project subr = psCharStrings.T2CharString() 1239f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project subr.fromXML((name, attrs, content)) 1249f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.GlobalSubrs.append(subr) 1259f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 1269f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 1279f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass CFFWriter: 1289f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 1299f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def __init__(self): 1309f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.data = [] 1319f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 1329f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def add(self, table): 1339f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.data.append(table) 1349f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 1359f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def toFile(self, file): 1369f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project lastPosList = None 1379f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project count = 1 1389f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project while 1: 1399f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if DEBUG: 1409f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project print "CFFWriter.toFile() iteration:", count 1419f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project count = count + 1 1429f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project pos = 0 1439f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project posList = [pos] 1449f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for item in self.data: 1459f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if hasattr(item, "getDataLength"): 1469f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project endPos = pos + item.getDataLength() 1479f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 1489f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project endPos = pos + len(item) 1499f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if hasattr(item, "setPos"): 1509f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project item.setPos(pos, endPos) 1519f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project pos = endPos 1529f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project posList.append(pos) 1539f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if posList == lastPosList: 1549f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project break 1559f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project lastPosList = posList 1569f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if DEBUG: 1579f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project print "CFFWriter.toFile() writing to file." 1589f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project begin = file.tell() 159f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen posList = [0] 160f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen for item in self.data: 161f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if hasattr(item, "toFile"): 162f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen item.toFile(file) 163f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen else: 164f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen file.write(item) 165f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen posList.append(file.tell() - begin) 166f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen assert posList == lastPosList 1679f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 1689f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 1699f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef calcOffSize(largestOffset): 1709f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if largestOffset < 0x100: 1719f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project offSize = 1 1729f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project elif largestOffset < 0x10000: 173e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen offSize = 2 174e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen elif largestOffset < 0x1000000: 175e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen offSize = 3 176e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen else: 177e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen offSize = 4 1789f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return offSize 179e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen 180e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen 181e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wenclass IndexCompiler: 182e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen 183e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen def __init__(self, items, strings, parent): 184e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen self.items = self.getItems(items, strings) 1859f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.parent = parent 1869f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 1879f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def getItems(self, items, strings): 1889f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return items 1899f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 1909f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def getOffsets(self): 1919f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project pos = 1 1929f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project offsets = [pos] 1939f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for item in self.items: 1949f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if hasattr(item, "getDataLength"): 1959f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project pos = pos + item.getDataLength() 1969f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 1979f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project pos = pos + len(item) 1989f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project offsets.append(pos) 1999f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return offsets 2009f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 2019f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def getDataLength(self): 2029f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project lastOffset = self.getOffsets()[-1] 2039f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project offSize = calcOffSize(lastOffset) 2049f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project dataLength = ( 2059f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 2 + # count 2069f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 1 + # offSize 2079f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project (len(self.items) + 1) * offSize + # the offsets 2089f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project lastOffset - 1 # size of object data 2099f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project ) 2109f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return dataLength 211e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen 212e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen def toFile(self, file): 2139f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project offsets = self.getOffsets() 2149f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project writeCard16(file, len(self.items)) 2159f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project offSize = calcOffSize(offsets[-1]) 2169f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project writeCard8(file, offSize) 2179f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project offSize = -offSize 2189f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project pack = struct.pack 2199f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for offset in offsets: 2209f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project binOffset = pack(">l", offset)[offSize:] 2219f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project assert len(binOffset) == -offSize 2229f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file.write(binOffset) 2239f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for item in self.items: 2249f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if hasattr(item, "toFile"): 2259f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project item.toFile(file) 2269f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 2279f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file.write(item) 2289f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 2299f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 2309f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass IndexedStringsCompiler(IndexCompiler): 2319f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 2329f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def getItems(self, items, strings): 2339f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return items.strings 2349f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 2359f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 2369f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass TopDictIndexCompiler(IndexCompiler): 2379f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 2389f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def getItems(self, items, strings): 2399f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project out = [] 2409f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for item in items: 2419f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project out.append(item.getCompiler(strings, self)) 2429f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return out 2439f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 2449f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def getChildren(self, strings): 2459f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project children = [] 2469f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for topDict in self.items: 2479f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project children.extend(topDict.getChildren(strings)) 2489f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return children 2499f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 2509f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 2519f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass FDArrayIndexCompiler(IndexCompiler): 2529f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 2539f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def getItems(self, items, strings): 2549f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project out = [] 2559f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for item in items: 2569f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project out.append(item.getCompiler(strings, self)) 2579f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return out 2589f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 2599f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def getChildren(self, strings): 2609f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project children = [] 2619f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for fontDict in self.items: 2629f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project children.extend(fontDict.getChildren(strings)) 2639f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return children 2649f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 2659f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def toFile(self, file): 2669f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project offsets = self.getOffsets() 2679f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project writeCard16(file, len(self.items)) 2689f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project offSize = calcOffSize(offsets[-1]) 2699f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project writeCard8(file, offSize) 270f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen offSize = -offSize 2719f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project pack = struct.pack 2729f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for offset in offsets: 2739f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project binOffset = pack(">l", offset)[offSize:] 2749f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project assert len(binOffset) == -offSize 2759f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file.write(binOffset) 2769f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for item in self.items: 277f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if hasattr(item, "toFile"): 278f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen item.toFile(file) 279f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen else: 2802fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen file.write(item) 2812fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen 2822fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen def setPos(self, pos, endPos): 2832fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen self.parent.rawDict["FDArray"] = pos 2842fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen 2852fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen 2862fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chenclass GlobalSubrsCompiler(IndexCompiler): 2872fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen def getItems(self, items, strings): 288cc66ecf44d1407039b05ffd7b3342389f95c17b7Joseph Wen out = [] 289f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen for cs in items: 2902fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen cs.compile() 291f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen out.append(cs.bytecode) 292f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return out 293f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 2949f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass SubrsCompiler(GlobalSubrsCompiler): 2959f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def setPos(self, pos, endPos): 2969f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project offset = pos - self.parent.pos 2972fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen self.parent.rawDict["Subrs"] = offset 298f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 299f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wenclass CharStringsCompiler(GlobalSubrsCompiler): 300f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def setPos(self, pos, endPos): 301f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.parent.rawDict["CharStrings"] = pos 302f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 303f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 304f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wenclass Index: 305f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 306f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen """This class represents what the CFF spec calls an INDEX.""" 307f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 3082fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen compilerClass = IndexCompiler 3092fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen 310f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def __init__(self, file=None): 3112fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen name = self.__class__.__name__ 3129f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if file is None: 3139f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.items = [] 3149f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return 3153147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen if DEBUG: 3163147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen print "loading %s at %s" % (name, file.tell()) 3173147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen self.file = file 3183147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen count = readCard16(file) 3193147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen self.count = count 3203147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen self.items = [None] * count 321f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if count == 0: 322f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.items = [] 3232fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen return 324f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen offSize = readCard8(file) 325f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if DEBUG: 326f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen print " index count: %s offSize: %s" % (count, offSize) 327f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen assert offSize <= 4, "offSize too large: %s" % offSize 3283147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen self.offsets = offsets = [] 3293147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen pad = '\0' * (4 - offSize) 3309f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for index in range(count+1): 3312fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen chunk = file.read(offSize) 3322fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen chunk = pad + chunk 3339f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project offset, = struct.unpack(">L", chunk) 3349f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project offsets.append(int(offset)) 3352fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen self.offsetBase = file.tell() - 1 3362fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen file.seek(self.offsetBase + offsets[-1]) # pretend we've read the whole lot 3372fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen if DEBUG: 3382fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen print " end of %s at %s" % (name, file.tell()) 3399f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 3409f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def __len__(self): 3419f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return len(self.items) 3429f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 3439f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def __getitem__(self, index): 3449f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project item = self.items[index] 3459f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if item is not None: 3469f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return item 3479f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project offset = self.offsets[index] + self.offsetBase 3489f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project size = self.offsets[index+1] - self.offsets[index] 3499f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file = self.file 3509f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file.seek(offset) 3519f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project data = file.read(size) 3529f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project assert len(data) == size 3539f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project item = self.produceItem(index, data, file, offset, size) 354f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.items[index] = item 355f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return item 356f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 357f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def produceItem(self, index, data, file, offset, size): 358f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return data 359f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 360f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def append(self, item): 361f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.items.append(item) 362f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 363f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def getCompiler(self, strings, parent): 364f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return self.compilerClass(self, strings, parent) 365f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 366f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 367f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wenclass GlobalSubrsIndex(Index): 368f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 369f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen compilerClass = GlobalSubrsCompiler 370f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 371f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def __init__(self, file=None, globalSubrs=None, private=None, fdSelect=None, fdArray=None): 372f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen Index.__init__(self, file) 373f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.globalSubrs = globalSubrs 374f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.private = private 375f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if fdSelect: 376f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.fdSelect = fdSelect 377f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if fdArray: 378f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.fdArray = fdArray 379f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 380f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def produceItem(self, index, data, file, offset, size): 381f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if self.private is not None: 382f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen private = self.private 383f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen elif hasattr(self, 'fdArray') and self.fdArray is not None: 384f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen private = self.fdArray[self.fdSelect[index]].Private 3853147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen else: 3863147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen private = None 3873147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen return psCharStrings.T2CharString(data, private=private, globalSubrs=self.globalSubrs) 3883147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen 3893147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen def toXML(self, xmlWriter, progress): 3903147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen xmlWriter.comment("The 'index' attribute is only for humans; it is ignored when parsed.") 391f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen xmlWriter.newline() 392f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen for i in range(len(self)): 3933147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen subr = self[i] 3943147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen if subr.needsDecompilation(): 3953147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen xmlWriter.begintag("CharString", index=i, raw=1) 3963147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen else: 3973147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen xmlWriter.begintag("CharString", index=i) 3983147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen xmlWriter.newline() 3993147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen subr.toXML(xmlWriter) 400f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen xmlWriter.endtag("CharString") 401f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen xmlWriter.newline() 4023147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen 4033147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen def fromXML(self, (name, attrs, content)): 404f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if name != "CharString": 4053147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen return 406f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen subr = psCharStrings.T2CharString() 407f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen subr.fromXML((name, attrs, content)) 4083147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen self.append(subr) 4093147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen 410f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def getItemAndSelector(self, index): 4113147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen sel = None 4123147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen if hasattr(self, 'fdSelect'): 4133147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen sel = self.fdSelect[index] 4143147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen return self[index], sel 4153147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen 4163147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen 4173147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wenclass SubrsIndex(GlobalSubrsIndex): 4183147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen compilerClass = SubrsCompiler 419f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 420f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 4213147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wenclass TopDictIndex(Index): 4223147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen 4233147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen compilerClass = TopDictIndexCompiler 4243147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen 4253147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen def produceItem(self, index, data, file, offset, size): 4263147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen top = TopDict(self.strings, file, offset, self.GlobalSubrs) 4273147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen top.decompile(data) 4283147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen return top 4293147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen 4303147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen def toXML(self, xmlWriter, progress): 4313147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen for i in range(len(self)): 4323147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen xmlWriter.begintag("FontDict", index=i) 4333147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen xmlWriter.newline() 4343147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen self[i].toXML(xmlWriter, progress) 4353147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen xmlWriter.endtag("FontDict") 4363147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen xmlWriter.newline() 4373147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen 4383147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen 4393147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wenclass FDArrayIndex(TopDictIndex): 4403147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen 4413147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen compilerClass = FDArrayIndexCompiler 4423147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen 4433147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen def fromXML(self, (name, attrs, content)): 4443147fbe7688fc353e6ae03825a37cf101a4ee01dJoseph Wen if name != "FontDict": 445f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return 446f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen fontDict = FontDict() 447f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen for element in content: 448f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if isinstance(element, basestring): 449f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen continue 450f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen fontDict.fromXML(element) 451f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.append(fontDict) 452f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 453f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 454f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wenclass FDSelect: 455f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def __init__(self, file = None, numGlyphs = None, format=None): 456f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if file: 457f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen # read data in from file 458f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.format = readCard8(file) 459f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if self.format == 0: 460f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen from array import array 461f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.gidArray = array("B", file.read(numGlyphs)).tolist() 462f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen elif self.format == 3: 463f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen gidArray = [None] * numGlyphs 464f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen nRanges = readCard16(file) 465f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen prev = None 466f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen for i in range(nRanges): 467f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen first = readCard16(file) 468f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if prev is not None: 469f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen for glyphID in range(prev, first): 470f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen gidArray[glyphID] = fd 471f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen prev = first 472f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen fd = readCard8(file) 473f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if prev is not None: 474f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen first = readCard16(file) 475f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen for glyphID in range(prev, first): 476f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen gidArray[glyphID] = fd 477f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.gidArray = gidArray 478f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen else: 479f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen assert 0, "unsupported FDSelect format: %s" % format 480f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen else: 481f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen # reading from XML. Make empty gidArray,, and leave format as passed in. 482f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen # format == None will result in the smallest representation being used. 483f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.format = format 484f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.gidArray = [] 485f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 486f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 487f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def __len__(self): 488f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return len(self.gidArray) 489f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 490f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def __getitem__(self, index): 491f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return self.gidArray[index] 492f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 493f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def __setitem__(self, index, fdSelectValue): 494f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.gidArray[index] = fdSelectValue 495f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 496f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def append(self, fdSelectValue): 497f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.gidArray.append(fdSelectValue) 498f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 499f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 500f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wenclass CharStrings: 501f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 502f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def __init__(self, file, charset, globalSubrs, private, fdSelect, fdArray): 503f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if file is not None: 504f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.charStringsIndex = SubrsIndex(file, globalSubrs, private, fdSelect, fdArray) 505f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.charStrings = charStrings = {} 506f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen for i in range(len(charset)): 507f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen charStrings[charset[i]] = i 508f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.charStringsAreIndexed = 1 509f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen else: 510f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.charStrings = {} 511f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.charStringsAreIndexed = 0 512f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.globalSubrs = globalSubrs 513f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.private = private 514f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if fdSelect != None: 515f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.fdSelect = fdSelect 516f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if fdArray!= None: 517f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.fdArray = fdArray 518f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 519f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def keys(self): 520f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return self.charStrings.keys() 521f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 522f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def values(self): 523f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if self.charStringsAreIndexed: 524f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return self.charStringsIndex 525f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen else: 526f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return self.charStrings.values() 527f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 528f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def has_key(self, name): 529f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return name in self.charStrings 530f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 531f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def __len__(self): 532f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return len(self.charStrings) 533f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 534f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def __getitem__(self, name): 535f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen charString = self.charStrings[name] 536f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if self.charStringsAreIndexed: 537f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen charString = self.charStringsIndex[charString] 538f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return charString 539f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 540f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def __setitem__(self, name, charString): 541f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if self.charStringsAreIndexed: 542f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen index = self.charStrings[name] 543f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen self.charStringsIndex[index] = charString 5449f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 5459f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.charStrings[name] = charString 5469f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 5479f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def getItemAndSelector(self, name): 5489f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if self.charStringsAreIndexed: 5499f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project index = self.charStrings[name] 5509f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return self.charStringsIndex.getItemAndSelector(index) 5519f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 5529f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if hasattr(self, 'fdSelect'): 5539f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project sel = self.fdSelect[index] # index is not defined at this point. Read R. ? 5549f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 5559f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project raise KeyError("fdSelect array not yet defined.") 5569f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return self.charStrings[name], sel 5579f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 5589f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def toXML(self, xmlWriter, progress): 5599f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project names = self.keys() 5609f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project names.sort() 5619f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project i = 0 5629f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project step = 10 5639f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project numGlyphs = len(names) 5649f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for name in names: 5659f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charStr, fdSelectIndex = self.getItemAndSelector(name) 5669f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if charStr.needsDecompilation(): 5679f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project raw = [("raw", 1)] 5689f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 5699f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project raw = [] 5709f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if fdSelectIndex is None: 5719f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.begintag("CharString", [('name', name)] + raw) 5729f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 5739f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.begintag("CharString", 5749f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project [('name', name), ('fdSelectIndex', fdSelectIndex)] + raw) 5759f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 5769f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charStr.toXML(xmlWriter) 5779f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.endtag("CharString") 5789f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 5799f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if not i % step and progress is not None: 5809f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project progress.setLabel("Dumping 'CFF ' table... (%s)" % name) 5819f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project progress.increment(step / float(numGlyphs)) 5829f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project i = i + 1 5839f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 584f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def fromXML(self, (name, attrs, content)): 5859f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for element in content: 5869f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if isinstance(element, basestring): 5879f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project continue 5889f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project name, attrs, content = element 5899f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if name != "CharString": 5909f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project continue 5919f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project fdID = -1 5929f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if hasattr(self, "fdArray"): 5939f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project fdID = safeEval(attrs["fdSelectIndex"]) 5949f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project private = self.fdArray[fdID].Private 5959f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 596e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen private = self.private 597e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen 598e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen glyphName = attrs["name"] 599e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen charString = psCharStrings.T2CharString( 6002fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen private=private, 601e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen globalSubrs=self.globalSubrs) 602e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen charString.fromXML((name, attrs, content)) 603e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen if fdID >= 0: 604e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen charString.fdSelectIndex = fdID 605e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen self[glyphName] = charString 6062fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen 6072fa18d458a5545e7f6cc431954f19e136dfedc9eWei-Ta Chen 608e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wendef readCard8(file): 6099f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return ord(file.read(1)) 6109f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6119f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef readCard16(file): 612e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen value, = struct.unpack(">H", file.read(2)) 613e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen return value 614e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen 6159f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef writeCard8(file, value): 6169f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file.write(chr(value)) 6179f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6189f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef writeCard16(file, value): 6199f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file.write(struct.pack(">H", value)) 6209f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6219f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef packCard8(value): 6229f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return chr(value) 6239f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6249f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef packCard16(value): 6259f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return struct.pack(">H", value) 6269f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6279f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef buildOperatorDict(table): 6289f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project d = {} 6299f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for op, name, arg, default, conv in table: 6309f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project d[op] = (name, arg) 6319f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return d 6329f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6339f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef buildOpcodeDict(table): 6349f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project d = {} 6359f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for op, name, arg, default, conv in table: 6369f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if isinstance(op, tuple): 6379f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project op = chr(op[0]) + chr(op[1]) 6389f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 6399f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project op = chr(op) 6409f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project d[name] = (op, arg) 6419f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return d 6429f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6439f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef buildOrder(table): 6449f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project l = [] 6459f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for op, name, arg, default, conv in table: 6469f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project l.append(name) 6479f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return l 6489f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6499f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef buildDefaults(table): 6509f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project d = {} 6519f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for op, name, arg, default, conv in table: 6529f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if default is not None: 6539f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project d[name] = default 6549f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return d 6559f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6569f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef buildConverters(table): 6579f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project d = {} 6589f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for op, name, arg, default, conv in table: 6599f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project d[name] = conv 6609f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return d 6619f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6629f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6639f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass SimpleConverter: 6649f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def read(self, parent, value): 6659f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return value 6669f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def write(self, parent, value): 6679f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return value 6689f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def xmlWrite(self, xmlWriter, name, value, progress): 6699f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.simpletag(name, value=value) 6709f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 6719f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def xmlRead(self, (name, attrs, content), parent): 6729f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return attrs["value"] 6739f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6749f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass Latin1Converter(SimpleConverter): 6759f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def xmlWrite(self, xmlWriter, name, value, progress): 6769f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project # Store as UTF-8 6779f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project value = unicode(value, "latin-1").encode("utf-8") 6789f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.simpletag(name, value=value) 6799f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 6809f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def xmlRead(self, (name, attrs, content), parent): 6819f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project s = unicode(attrs["value"], "utf-8") 6829f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return s.encode("latin-1") 6839f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6849f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6859f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef parseNum(s): 6869f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project try: 6879f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project value = int(s) 6889f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project except: 6899f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project value = float(s) 6909f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return value 6919f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6929f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass NumberConverter(SimpleConverter): 6939f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def xmlRead(self, (name, attrs, content), parent): 6949f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return parseNum(attrs["value"]) 6959f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 6969f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass ArrayConverter(SimpleConverter): 6979f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def xmlWrite(self, xmlWriter, name, value, progress): 6989f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project value = map(str, value) 6999f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.simpletag(name, value=" ".join(value)) 7009f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 7019f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def xmlRead(self, (name, attrs, content), parent): 7029f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project values = attrs["value"].split() 7039f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return map(parseNum, values) 7049f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 7059f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass TableConverter(SimpleConverter): 7069f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def xmlWrite(self, xmlWriter, name, value, progress): 7079f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.begintag(name) 7089f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 7099f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project value.toXML(xmlWriter, progress) 7109f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.endtag(name) 7119f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 7129f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def xmlRead(self, (name, attrs, content), parent): 7139f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project ob = self.getClass()() 7149f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for element in content: 7159f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if isinstance(element, basestring): 7169f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project continue 7179f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project ob.fromXML(element) 7189f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return ob 7199f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 7209f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass PrivateDictConverter(TableConverter): 7219f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def getClass(self): 7229f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return PrivateDict 7239f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def read(self, parent, value): 7249f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project size, offset = value 7259f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file = parent.file 7269f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project priv = PrivateDict(parent.strings, file, offset) 7279f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file.seek(offset) 7289f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project data = file.read(size) 7299f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project len(data) == size 7309f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project priv.decompile(data) 7319f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return priv 7329f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def write(self, parent, value): 7339f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return (0, 0) # dummy value 7349f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 7359f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass SubrsConverter(TableConverter): 7369f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def getClass(self): 7379f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return SubrsIndex 7389f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def read(self, parent, value): 7399f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file = parent.file 7409f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file.seek(parent.offset + value) # Offset(self) 7419f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return SubrsIndex(file) 7429f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def write(self, parent, value): 7439f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return 0 # dummy value 7449f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 7459f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass CharStringsConverter(TableConverter): 7469f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def read(self, parent, value): 7479f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file = parent.file 7489f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charset = parent.charset 7499f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project globalSubrs = parent.GlobalSubrs 7509f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if hasattr(parent, "ROS"): 7519f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project fdSelect, fdArray = parent.FDSelect, parent.FDArray 7529f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project private = None 7539f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 7549f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project fdSelect, fdArray = None, None 7559f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project private = parent.Private 7569f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file.seek(value) # Offset(0) 7579f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return CharStrings(file, charset, globalSubrs, private, fdSelect, fdArray) 7589f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def write(self, parent, value): 7599f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return 0 # dummy value 7609f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def xmlRead(self, (name, attrs, content), parent): 7619f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if hasattr(parent, "ROS"): 7629f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project # if it is a CID-keyed font, then the private Dict is extracted from the parent.FDArray 7639f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project private, fdSelect, fdArray = None, parent.FDSelect, parent.FDArray 7649f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 7659f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project # if it is a name-keyed font, then the private dict is in the top dict, and there is no fdArray. 7669f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project private, fdSelect, fdArray = parent.Private, None, None 7679f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charStrings = CharStrings(None, None, parent.GlobalSubrs, private, fdSelect, fdArray) 7689f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charStrings.fromXML((name, attrs, content)) 7699f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return charStrings 7709f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 7719f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass CharsetConverter: 7729f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def read(self, parent, value): 7739f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project isCID = hasattr(parent, "ROS") 7749f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if value > 2: 7759f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project numGlyphs = parent.numGlyphs 7769f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file = parent.file 7779f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file.seek(value) 7789f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if DEBUG: 7799f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project print "loading charset at %s" % value 7809f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project format = readCard8(file) 7819f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if format == 0: 7829f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charset = parseCharset0(numGlyphs, file, parent.strings, isCID) 7839f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project elif format == 1 or format == 2: 7849f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charset = parseCharset(numGlyphs, file, parent.strings, isCID, format) 7859f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 7869f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project raise NotImplementedError 7879f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project assert len(charset) == numGlyphs 7889f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if DEBUG: 7899f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project print " charset end at %s" % file.tell() 7909f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: # offset == 0 -> no charset data. 7919f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if isCID or "CharStrings" not in parent.rawDict: 7929f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project assert value == 0 # We get here only when processing fontDicts from the FDArray of CFF-CID fonts. Only the real topDict references the chrset. 7939f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charset = None 7949f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project elif value == 0: 7959f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charset = cffISOAdobeStrings 7969f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project elif value == 1: 7979f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charset = cffIExpertStrings 7989f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project elif value == 2: 7999f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charset = cffExpertSubsetStrings 8009f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return charset 8019f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8029f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def write(self, parent, value): 8039f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return 0 # dummy value 8049f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def xmlWrite(self, xmlWriter, name, value, progress): 8059f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project # XXX only write charset when not in OT/TTX context, where we 8069f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project # dump charset as a separate "GlyphOrder" table. 8079f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project ##xmlWriter.simpletag("charset") 8089f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.comment("charset is dumped separately as the 'GlyphOrder' element") 8099f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 8109f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def xmlRead(self, (name, attrs, content), parent): 8119f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if 0: 8129f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return safeEval(attrs["value"]) 8139f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8149f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8159f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass CharsetCompiler: 8169f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8179f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def __init__(self, strings, charset, parent): 8189f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project assert charset[0] == '.notdef' 8199f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project isCID = hasattr(parent.dictObj, "ROS") 8209f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project data0 = packCharset0(charset, isCID, strings) 8219f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project data = packCharset(charset, isCID, strings) 8229f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if len(data) < len(data0): 8239f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.data = data 8249f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 8259f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.data = data0 8269f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.parent = parent 8279f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8289f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def setPos(self, pos, endPos): 8299f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.parent.rawDict["charset"] = pos 8309f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8319f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def getDataLength(self): 8329f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return len(self.data) 8339f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8349f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def toFile(self, file): 8359f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file.write(self.data) 8369f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8379f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8389f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef getCIDfromName(name, strings): 8399f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return int(name[3:]) 8409f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8419f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef getSIDfromName(name, strings): 8429f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return strings.getSID(name) 8439f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8449f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef packCharset0(charset, isCID, strings): 8459f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project format = 0 8469f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project data = [packCard8(format)] 8479f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if isCID: 8489f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project getNameID = getCIDfromName 8499f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 8509f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project getNameID = getSIDfromName 8519f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8529f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for name in charset[1:]: 8539f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project data.append(packCard16(getNameID(name,strings))) 8549f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return "".join(data) 8559f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8569f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8579f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef packCharset(charset, isCID, strings): 8589f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project format = 1 8599f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project ranges = [] 8609f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project first = None 8619f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project end = 0 8629f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if isCID: 8639f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project getNameID = getCIDfromName 8649f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 8659f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project getNameID = getSIDfromName 8669f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8679f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for name in charset[1:]: 8689f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project SID = getNameID(name, strings) 8699f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if first is None: 8709f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project first = SID 8719f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project elif end + 1 != SID: 8729f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project nLeft = end - first 8739f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if nLeft > 255: 8749f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project format = 2 8759f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project ranges.append((first, nLeft)) 8769f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project first = SID 8779f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project end = SID 8789f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project nLeft = end - first 8799f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if nLeft > 255: 8809f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project format = 2 8819f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project ranges.append((first, nLeft)) 8829f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8839f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project data = [packCard8(format)] 8849f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if format == 1: 8859f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project nLeftFunc = packCard8 8869f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 8879f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project nLeftFunc = packCard16 8889f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for first, nLeft in ranges: 8899f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project data.append(packCard16(first) + nLeftFunc(nLeft)) 8909f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return "".join(data) 8919f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 8929f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef parseCharset0(numGlyphs, file, strings, isCID): 8939f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charset = [".notdef"] 8949f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if isCID: 8959f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for i in range(numGlyphs - 1): 8969f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project CID = readCard16(file) 8979f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charset.append("cid" + string.zfill(str(CID), 5) ) 8989f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 8999f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for i in range(numGlyphs - 1): 9009f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project SID = readCard16(file) 9019f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charset.append(strings[SID]) 9029f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return charset 9039f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 9049f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef parseCharset(numGlyphs, file, strings, isCID, format): 9059f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charset = ['.notdef'] 9069f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project count = 1 9079f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if format == 1: 9089f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project nLeftFunc = readCard8 9099f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 9109f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project nLeftFunc = readCard16 9119f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project while count < numGlyphs: 9129f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project first = readCard16(file) 9139f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project nLeft = nLeftFunc(file) 9149f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if isCID: 9159f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for CID in range(first, first+nLeft+1): 9169f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charset.append("cid" + string.zfill(str(CID), 5) ) 9179f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 9189f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for SID in range(first, first+nLeft+1): 9199f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project charset.append(strings[SID]) 9209f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project count = count + nLeft + 1 9219f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return charset 9229f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 9239f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 9249f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectclass EncodingCompiler: 9259f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 9269f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def __init__(self, strings, encoding, parent): 9279f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project assert not isinstance(encoding, basestring) 9289f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project data0 = packEncoding0(parent.dictObj.charset, encoding, parent.strings) 9299f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project data1 = packEncoding1(parent.dictObj.charset, encoding, parent.strings) 9309f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if len(data0) < len(data1): 9319f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.data = data0 9329f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project else: 9339f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.data = data1 9349f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.parent = parent 9359f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 9369f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def setPos(self, pos, endPos): 9379f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project self.parent.rawDict["Encoding"] = pos 9389f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 939f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def getDataLength(self): 940f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return len(self.data) 941e0eadaa39b72e33f032220246c771d7302ebeaf8Joseph Wen 9429f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def toFile(self, file): 9439f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project file.write(self.data) 9449f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 9459f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 946f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wenclass EncodingConverter(SimpleConverter): 947f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 948f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def read(self, parent, value): 949f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if value == 0: 950f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return "StandardEncoding" 951f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen elif value == 1: 952f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return "ExpertEncoding" 953f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen else: 954f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen assert value > 1 955f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen file = parent.file 956f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen file.seek(value) 957f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if DEBUG: 958f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen print "loading Encoding at %s" % value 959f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen format = readCard8(file) 960f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen haveSupplement = format & 0x80 961f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if haveSupplement: 962f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen raise NotImplementedError("Encoding supplements are not yet supported") 963f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen format = format & 0x7f 964f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if format == 0: 965f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen encoding = parseEncoding0(parent.charset, file, haveSupplement, 966f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen parent.strings) 967f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen elif format == 1: 968f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen encoding = parseEncoding1(parent.charset, file, haveSupplement, 969f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen parent.strings) 970f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return encoding 971f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 972f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def write(self, parent, value): 973f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if value == "StandardEncoding": 974f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return 0 975f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen elif value == "ExpertEncoding": 976f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return 1 977f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return 0 # dummy value 978f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen 979f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen def xmlWrite(self, xmlWriter, name, value, progress): 980f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if value in ("StandardEncoding", "ExpertEncoding"): 981f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen xmlWriter.simpletag(name, name=value) 982f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen xmlWriter.newline() 983f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen return 984f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen xmlWriter.begintag(name) 985f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen xmlWriter.newline() 986f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen for code in range(len(value)): 987f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen glyphName = value[code] 988f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen if glyphName != ".notdef": 989f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen xmlWriter.simpletag("map", code=hex(code), name=glyphName) 990f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen xmlWriter.newline() 991f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wen xmlWriter.endtag(name) 9929f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project xmlWriter.newline() 9939f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 9949f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project def xmlRead(self, (name, attrs, content), parent): 9959f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if "name" in attrs: 9969f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return attrs["name"] 9979f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project encoding = [".notdef"] * 256 9989f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for element in content: 9999f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if isinstance(element, basestring): 10009f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project continue 10019f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project name, attrs, content = element 10029f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project code = safeEval(attrs["code"]) 10039f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project glyphName = attrs["name"] 10049f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project encoding[code] = glyphName 10059f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return encoding 10069f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 10079f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 10089f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef parseEncoding0(charset, file, haveSupplement, strings): 10099f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project nCodes = readCard8(file) 10109f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project encoding = [".notdef"] * 256 10119f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for glyphID in range(1, nCodes + 1): 10129f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project code = readCard8(file) 10139f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if code != 0: 10149f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project encoding[code] = charset[glyphID] 10159f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return encoding 10169f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 10179f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Projectdef parseEncoding1(charset, file, haveSupplement, strings): 10189f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project nRanges = readCard8(file) 10199f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project encoding = [".notdef"] * 256 10209f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project glyphID = 1 10219f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for i in range(nRanges): 10229f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project code = readCard8(file) 10239f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project nLeft = readCard8(file) 10249f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for glyphID in range(glyphID, glyphID + nLeft + 1): 10259f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project encoding[code] = charset[glyphID] 10269f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project code = code + 1 10279f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project glyphID = glyphID + 1 10289f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project return encoding 10299f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project 1030f5b94eebe742df1a9bb3941fc0a0ec0137e936efJoseph Wendef packEncoding0(charset, encoding, strings): 10319f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project format = 0 10329f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project m = {} 10339f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for code in range(len(encoding)): 10349f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project name = encoding[code] 10359f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project if name != ".notdef": 10369f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project m[name] = code 10379f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project codes = [] 10389f5d49a1588e438ae7ceabd0c94172117e3303aaThe Android Open Source Project for name in charset[1:]: 1039 code = m.get(name) 1040 codes.append(code) 1041 1042 while codes and codes[-1] is None: 1043 codes.pop() 1044 1045 data = [packCard8(format), packCard8(len(codes))] 1046 for code in codes: 1047 if code is None: 1048 code = 0 1049 data.append(packCard8(code)) 1050 return "".join(data) 1051 1052def packEncoding1(charset, encoding, strings): 1053 format = 1 1054 m = {} 1055 for code in range(len(encoding)): 1056 name = encoding[code] 1057 if name != ".notdef": 1058 m[name] = code 1059 ranges = [] 1060 first = None 1061 end = 0 1062 for name in charset[1:]: 1063 code = m.get(name, -1) 1064 if first is None: 1065 first = code 1066 elif end + 1 != code: 1067 nLeft = end - first 1068 ranges.append((first, nLeft)) 1069 first = code 1070 end = code 1071 nLeft = end - first 1072 ranges.append((first, nLeft)) 1073 1074 # remove unencoded glyphs at the end. 1075 while ranges and ranges[-1][0] == -1: 1076 ranges.pop() 1077 1078 data = [packCard8(format), packCard8(len(ranges))] 1079 for first, nLeft in ranges: 1080 if first == -1: # unencoded 1081 first = 0 1082 data.append(packCard8(first) + packCard8(nLeft)) 1083 return "".join(data) 1084 1085 1086class FDArrayConverter(TableConverter): 1087 1088 def read(self, parent, value): 1089 file = parent.file 1090 file.seek(value) 1091 fdArray = FDArrayIndex(file) 1092 fdArray.strings = parent.strings 1093 fdArray.GlobalSubrs = parent.GlobalSubrs 1094 return fdArray 1095 1096 def write(self, parent, value): 1097 return 0 # dummy value 1098 1099 def xmlRead(self, (name, attrs, content), parent): 1100 fdArray = FDArrayIndex() 1101 for element in content: 1102 if isinstance(element, basestring): 1103 continue 1104 fdArray.fromXML(element) 1105 return fdArray 1106 1107 1108class FDSelectConverter: 1109 1110 def read(self, parent, value): 1111 file = parent.file 1112 file.seek(value) 1113 fdSelect = FDSelect(file, parent.numGlyphs) 1114 return fdSelect 1115 1116 def write(self, parent, value): 1117 return 0 # dummy value 1118 1119 # The FDSelect glyph data is written out to XML in the charstring keys, 1120 # so we write out only the format selector 1121 def xmlWrite(self, xmlWriter, name, value, progress): 1122 xmlWriter.simpletag(name, [('format', value.format)]) 1123 xmlWriter.newline() 1124 1125 def xmlRead(self, (name, attrs, content), parent): 1126 format = safeEval(attrs["format"]) 1127 file = None 1128 numGlyphs = None 1129 fdSelect = FDSelect(file, numGlyphs, format) 1130 return fdSelect 1131 1132 1133def packFDSelect0(fdSelectArray): 1134 format = 0 1135 data = [packCard8(format)] 1136 for index in fdSelectArray: 1137 data.append(packCard8(index)) 1138 return "".join(data) 1139 1140 1141def packFDSelect3(fdSelectArray): 1142 format = 3 1143 fdRanges = [] 1144 first = None 1145 end = 0 1146 lenArray = len(fdSelectArray) 1147 lastFDIndex = -1 1148 for i in range(lenArray): 1149 fdIndex = fdSelectArray[i] 1150 if lastFDIndex != fdIndex: 1151 fdRanges.append([i, fdIndex]) 1152 lastFDIndex = fdIndex 1153 sentinelGID = i + 1 1154 1155 data = [packCard8(format)] 1156 data.append(packCard16( len(fdRanges) )) 1157 for fdRange in fdRanges: 1158 data.append(packCard16(fdRange[0])) 1159 data.append(packCard8(fdRange[1])) 1160 data.append(packCard16(sentinelGID)) 1161 return "".join(data) 1162 1163 1164class FDSelectCompiler: 1165 1166 def __init__(self, fdSelect, parent): 1167 format = fdSelect.format 1168 fdSelectArray = fdSelect.gidArray 1169 if format == 0: 1170 self.data = packFDSelect0(fdSelectArray) 1171 elif format == 3: 1172 self.data = packFDSelect3(fdSelectArray) 1173 else: 1174 # choose smaller of the two formats 1175 data0 = packFDSelect0(fdSelectArray) 1176 data3 = packFDSelect3(fdSelectArray) 1177 if len(data0) < len(data3): 1178 self.data = data0 1179 fdSelect.format = 0 1180 else: 1181 self.data = data3 1182 fdSelect.format = 3 1183 1184 self.parent = parent 1185 1186 def setPos(self, pos, endPos): 1187 self.parent.rawDict["FDSelect"] = pos 1188 1189 def getDataLength(self): 1190 return len(self.data) 1191 1192 def toFile(self, file): 1193 file.write(self.data) 1194 1195 1196class ROSConverter(SimpleConverter): 1197 1198 def xmlWrite(self, xmlWriter, name, value, progress): 1199 registry, order, supplement = value 1200 xmlWriter.simpletag(name, [('Registry', registry), ('Order', order), 1201 ('Supplement', supplement)]) 1202 xmlWriter.newline() 1203 1204 def xmlRead(self, (name, attrs, content), parent): 1205 return (attrs['Registry'], attrs['Order'], safeEval(attrs['Supplement'])) 1206 1207 1208 1209topDictOperators = [ 1210# opcode name argument type default converter 1211 ((12, 30), 'ROS', ('SID','SID','number'), None, ROSConverter()), 1212 ((12, 20), 'SyntheticBase', 'number', None, None), 1213 (0, 'version', 'SID', None, None), 1214 (1, 'Notice', 'SID', None, Latin1Converter()), 1215 ((12, 0), 'Copyright', 'SID', None, Latin1Converter()), 1216 (2, 'FullName', 'SID', None, None), 1217 ((12, 38), 'FontName', 'SID', None, None), 1218 (3, 'FamilyName', 'SID', None, None), 1219 (4, 'Weight', 'SID', None, None), 1220 ((12, 1), 'isFixedPitch', 'number', 0, None), 1221 ((12, 2), 'ItalicAngle', 'number', 0, None), 1222 ((12, 3), 'UnderlinePosition', 'number', None, None), 1223 ((12, 4), 'UnderlineThickness', 'number', 50, None), 1224 ((12, 5), 'PaintType', 'number', 0, None), 1225 ((12, 6), 'CharstringType', 'number', 2, None), 1226 ((12, 7), 'FontMatrix', 'array', [0.001,0,0,0.001,0,0], None), 1227 (13, 'UniqueID', 'number', None, None), 1228 (5, 'FontBBox', 'array', [0,0,0,0], None), 1229 ((12, 8), 'StrokeWidth', 'number', 0, None), 1230 (14, 'XUID', 'array', None, None), 1231 ((12, 21), 'PostScript', 'SID', None, None), 1232 ((12, 22), 'BaseFontName', 'SID', None, None), 1233 ((12, 23), 'BaseFontBlend', 'delta', None, None), 1234 ((12, 31), 'CIDFontVersion', 'number', 0, None), 1235 ((12, 32), 'CIDFontRevision', 'number', 0, None), 1236 ((12, 33), 'CIDFontType', 'number', 0, None), 1237 ((12, 34), 'CIDCount', 'number', 8720, None), 1238 (15, 'charset', 'number', 0, CharsetConverter()), 1239 ((12, 35), 'UIDBase', 'number', None, None), 1240 (16, 'Encoding', 'number', 0, EncodingConverter()), 1241 (18, 'Private', ('number','number'), None, PrivateDictConverter()), 1242 ((12, 37), 'FDSelect', 'number', None, FDSelectConverter()), 1243 ((12, 36), 'FDArray', 'number', None, FDArrayConverter()), 1244 (17, 'CharStrings', 'number', None, CharStringsConverter()), 1245] 1246 1247# Note! FDSelect and FDArray must both preceed CharStrings in the output XML build order, 1248# in order for the font to compile back from xml. 1249 1250 1251privateDictOperators = [ 1252# opcode name argument type default converter 1253 (6, 'BlueValues', 'delta', None, None), 1254 (7, 'OtherBlues', 'delta', None, None), 1255 (8, 'FamilyBlues', 'delta', None, None), 1256 (9, 'FamilyOtherBlues', 'delta', None, None), 1257 ((12, 9), 'BlueScale', 'number', 0.039625, None), 1258 ((12, 10), 'BlueShift', 'number', 7, None), 1259 ((12, 11), 'BlueFuzz', 'number', 1, None), 1260 (10, 'StdHW', 'number', None, None), 1261 (11, 'StdVW', 'number', None, None), 1262 ((12, 12), 'StemSnapH', 'delta', None, None), 1263 ((12, 13), 'StemSnapV', 'delta', None, None), 1264 ((12, 14), 'ForceBold', 'number', 0, None), 1265 ((12, 15), 'ForceBoldThreshold', 'number', None, None), # deprecated 1266 ((12, 16), 'lenIV', 'number', None, None), # deprecated 1267 ((12, 17), 'LanguageGroup', 'number', 0, None), 1268 ((12, 18), 'ExpansionFactor', 'number', 0.06, None), 1269 ((12, 19), 'initialRandomSeed', 'number', 0, None), 1270 (20, 'defaultWidthX', 'number', 0, None), 1271 (21, 'nominalWidthX', 'number', 0, None), 1272 (19, 'Subrs', 'number', None, SubrsConverter()), 1273] 1274 1275def addConverters(table): 1276 for i in range(len(table)): 1277 op, name, arg, default, conv = table[i] 1278 if conv is not None: 1279 continue 1280 if arg in ("delta", "array"): 1281 conv = ArrayConverter() 1282 elif arg == "number": 1283 conv = NumberConverter() 1284 elif arg == "SID": 1285 conv = SimpleConverter() 1286 else: 1287 assert 0 1288 table[i] = op, name, arg, default, conv 1289 1290addConverters(privateDictOperators) 1291addConverters(topDictOperators) 1292 1293 1294class TopDictDecompiler(psCharStrings.DictDecompiler): 1295 operators = buildOperatorDict(topDictOperators) 1296 1297 1298class PrivateDictDecompiler(psCharStrings.DictDecompiler): 1299 operators = buildOperatorDict(privateDictOperators) 1300 1301 1302class DictCompiler: 1303 1304 def __init__(self, dictObj, strings, parent): 1305 assert isinstance(strings, IndexedStrings) 1306 self.dictObj = dictObj 1307 self.strings = strings 1308 self.parent = parent 1309 rawDict = {} 1310 for name in dictObj.order: 1311 value = getattr(dictObj, name, None) 1312 if value is None: 1313 continue 1314 conv = dictObj.converters[name] 1315 value = conv.write(dictObj, value) 1316 if value == dictObj.defaults.get(name): 1317 continue 1318 rawDict[name] = value 1319 self.rawDict = rawDict 1320 1321 def setPos(self, pos, endPos): 1322 pass 1323 1324 def getDataLength(self): 1325 return len(self.compile("getDataLength")) 1326 1327 def compile(self, reason): 1328 if DEBUG: 1329 print "-- compiling %s for %s" % (self.__class__.__name__, reason) 1330 print "in baseDict: ", self 1331 rawDict = self.rawDict 1332 data = [] 1333 for name in self.dictObj.order: 1334 value = rawDict.get(name) 1335 if value is None: 1336 continue 1337 op, argType = self.opcodes[name] 1338 if isinstance(argType, tuple): 1339 l = len(argType) 1340 assert len(value) == l, "value doesn't match arg type" 1341 for i in range(l): 1342 arg = argType[i] 1343 v = value[i] 1344 arghandler = getattr(self, "arg_" + arg) 1345 data.append(arghandler(v)) 1346 else: 1347 arghandler = getattr(self, "arg_" + argType) 1348 data.append(arghandler(value)) 1349 data.append(op) 1350 return "".join(data) 1351 1352 def toFile(self, file): 1353 file.write(self.compile("toFile")) 1354 1355 def arg_number(self, num): 1356 return encodeNumber(num) 1357 def arg_SID(self, s): 1358 return psCharStrings.encodeIntCFF(self.strings.getSID(s)) 1359 def arg_array(self, value): 1360 data = [] 1361 for num in value: 1362 data.append(encodeNumber(num)) 1363 return "".join(data) 1364 def arg_delta(self, value): 1365 out = [] 1366 last = 0 1367 for v in value: 1368 out.append(v - last) 1369 last = v 1370 data = [] 1371 for num in out: 1372 data.append(encodeNumber(num)) 1373 return "".join(data) 1374 1375 1376def encodeNumber(num): 1377 if isinstance(num, float): 1378 return psCharStrings.encodeFloat(num) 1379 else: 1380 return psCharStrings.encodeIntCFF(num) 1381 1382 1383class TopDictCompiler(DictCompiler): 1384 1385 opcodes = buildOpcodeDict(topDictOperators) 1386 1387 def getChildren(self, strings): 1388 children = [] 1389 if hasattr(self.dictObj, "charset") and self.dictObj.charset: 1390 children.append(CharsetCompiler(strings, self.dictObj.charset, self)) 1391 if hasattr(self.dictObj, "Encoding"): 1392 encoding = self.dictObj.Encoding 1393 if not isinstance(encoding, basestring): 1394 children.append(EncodingCompiler(strings, encoding, self)) 1395 if hasattr(self.dictObj, "FDSelect"): 1396 # I have not yet supported merging a ttx CFF-CID font, as there are interesting 1397 # issues about merging the FDArrays. Here I assume that 1398 # either the font was read from XML, and teh FDSelect indices are all 1399 # in the charstring data, or the FDSelect array is already fully defined. 1400 fdSelect = self.dictObj.FDSelect 1401 if len(fdSelect) == 0: # probably read in from XML; assume fdIndex in CharString data 1402 charStrings = self.dictObj.CharStrings 1403 for name in self.dictObj.charset: 1404 charstring = charStrings[name] 1405 fdSelect.append(charStrings[name].fdSelectIndex) 1406 fdSelectComp = FDSelectCompiler(fdSelect, self) 1407 children.append(fdSelectComp) 1408 if hasattr(self.dictObj, "CharStrings"): 1409 items = [] 1410 charStrings = self.dictObj.CharStrings 1411 for name in self.dictObj.charset: 1412 items.append(charStrings[name]) 1413 charStringsComp = CharStringsCompiler(items, strings, self) 1414 children.append(charStringsComp) 1415 if hasattr(self.dictObj, "FDArray"): 1416 # I have not yet supported merging a ttx CFF-CID font, as there are interesting 1417 # issues about merging the FDArrays. Here I assume that the FDArray info is correct 1418 # and complete. 1419 fdArrayIndexComp = self.dictObj.FDArray.getCompiler(strings, self) 1420 children.append(fdArrayIndexComp) 1421 children.extend(fdArrayIndexComp.getChildren(strings)) 1422 if hasattr(self.dictObj, "Private"): 1423 privComp = self.dictObj.Private.getCompiler(strings, self) 1424 children.append(privComp) 1425 children.extend(privComp.getChildren(strings)) 1426 return children 1427 1428 1429class FontDictCompiler(DictCompiler): 1430 1431 opcodes = buildOpcodeDict(topDictOperators) 1432 1433 def getChildren(self, strings): 1434 children = [] 1435 if hasattr(self.dictObj, "Private"): 1436 privComp = self.dictObj.Private.getCompiler(strings, self) 1437 children.append(privComp) 1438 children.extend(privComp.getChildren(strings)) 1439 return children 1440 1441 1442class PrivateDictCompiler(DictCompiler): 1443 1444 opcodes = buildOpcodeDict(privateDictOperators) 1445 1446 def setPos(self, pos, endPos): 1447 size = endPos - pos 1448 self.parent.rawDict["Private"] = size, pos 1449 self.pos = pos 1450 1451 def getChildren(self, strings): 1452 children = [] 1453 if hasattr(self.dictObj, "Subrs"): 1454 children.append(self.dictObj.Subrs.getCompiler(strings, self)) 1455 return children 1456 1457 1458class BaseDict: 1459 1460 def __init__(self, strings=None, file=None, offset=None): 1461 self.rawDict = {} 1462 if DEBUG: 1463 print "loading %s at %s" % (self.__class__.__name__, offset) 1464 self.file = file 1465 self.offset = offset 1466 self.strings = strings 1467 self.skipNames = [] 1468 1469 def decompile(self, data): 1470 if DEBUG: 1471 print " length %s is %s" % (self.__class__.__name__, len(data)) 1472 dec = self.decompilerClass(self.strings) 1473 dec.decompile(data) 1474 self.rawDict = dec.getDict() 1475 self.postDecompile() 1476 1477 def postDecompile(self): 1478 pass 1479 1480 def getCompiler(self, strings, parent): 1481 return self.compilerClass(self, strings, parent) 1482 1483 def __getattr__(self, name): 1484 value = self.rawDict.get(name) 1485 if value is None: 1486 value = self.defaults.get(name) 1487 if value is None: 1488 raise AttributeError(name) 1489 conv = self.converters[name] 1490 value = conv.read(self, value) 1491 setattr(self, name, value) 1492 return value 1493 1494 def toXML(self, xmlWriter, progress): 1495 for name in self.order: 1496 if name in self.skipNames: 1497 continue 1498 value = getattr(self, name, None) 1499 if value is None: 1500 continue 1501 conv = self.converters[name] 1502 conv.xmlWrite(xmlWriter, name, value, progress) 1503 1504 def fromXML(self, (name, attrs, content)): 1505 conv = self.converters[name] 1506 value = conv.xmlRead((name, attrs, content), self) 1507 setattr(self, name, value) 1508 1509 1510class TopDict(BaseDict): 1511 1512 defaults = buildDefaults(topDictOperators) 1513 converters = buildConverters(topDictOperators) 1514 order = buildOrder(topDictOperators) 1515 decompilerClass = TopDictDecompiler 1516 compilerClass = TopDictCompiler 1517 1518 def __init__(self, strings=None, file=None, offset=None, GlobalSubrs=None): 1519 BaseDict.__init__(self, strings, file, offset) 1520 self.GlobalSubrs = GlobalSubrs 1521 1522 def getGlyphOrder(self): 1523 return self.charset 1524 1525 def postDecompile(self): 1526 offset = self.rawDict.get("CharStrings") 1527 if offset is None: 1528 return 1529 # get the number of glyphs beforehand. 1530 self.file.seek(offset) 1531 self.numGlyphs = readCard16(self.file) 1532 1533 def toXML(self, xmlWriter, progress): 1534 if hasattr(self, "CharStrings"): 1535 self.decompileAllCharStrings(progress) 1536 if hasattr(self, "ROS"): 1537 self.skipNames = ['Encoding'] 1538 if not hasattr(self, "ROS") or not hasattr(self, "CharStrings"): 1539 # these values have default values, but I only want them to show up 1540 # in CID fonts. 1541 self.skipNames = ['CIDFontVersion', 'CIDFontRevision', 'CIDFontType', 1542 'CIDCount'] 1543 BaseDict.toXML(self, xmlWriter, progress) 1544 1545 def decompileAllCharStrings(self, progress): 1546 # XXX only when doing ttdump -i? 1547 i = 0 1548 for charString in self.CharStrings.values(): 1549 try: 1550 charString.decompile() 1551 except: 1552 print "Error in charstring ", i 1553 import sys 1554 type, value = sys. exc_info()[0:2] 1555 raise type(value) 1556 if not i % 30 and progress: 1557 progress.increment(0) # update 1558 i = i + 1 1559 1560 1561class FontDict(BaseDict): 1562 1563 defaults = buildDefaults(topDictOperators) 1564 converters = buildConverters(topDictOperators) 1565 order = buildOrder(topDictOperators) 1566 decompilerClass = None 1567 compilerClass = FontDictCompiler 1568 1569 def __init__(self, strings=None, file=None, offset=None, GlobalSubrs=None): 1570 BaseDict.__init__(self, strings, file, offset) 1571 self.GlobalSubrs = GlobalSubrs 1572 1573 def getGlyphOrder(self): 1574 return self.charset 1575 1576 def toXML(self, xmlWriter, progress): 1577 self.skipNames = ['Encoding'] 1578 BaseDict.toXML(self, xmlWriter, progress) 1579 1580 1581 1582class PrivateDict(BaseDict): 1583 defaults = buildDefaults(privateDictOperators) 1584 converters = buildConverters(privateDictOperators) 1585 order = buildOrder(privateDictOperators) 1586 decompilerClass = PrivateDictDecompiler 1587 compilerClass = PrivateDictCompiler 1588 1589 1590class IndexedStrings: 1591 1592 """SID -> string mapping.""" 1593 1594 def __init__(self, file=None): 1595 if file is None: 1596 strings = [] 1597 else: 1598 strings = list(Index(file)) 1599 self.strings = strings 1600 1601 def getCompiler(self): 1602 return IndexedStringsCompiler(self, None, None) 1603 1604 def __len__(self): 1605 return len(self.strings) 1606 1607 def __getitem__(self, SID): 1608 if SID < cffStandardStringCount: 1609 return cffStandardStrings[SID] 1610 else: 1611 return self.strings[SID - cffStandardStringCount] 1612 1613 def getSID(self, s): 1614 if not hasattr(self, "stringMapping"): 1615 self.buildStringMapping() 1616 if s in cffStandardStringMapping: 1617 SID = cffStandardStringMapping[s] 1618 elif s in self.stringMapping: 1619 SID = self.stringMapping[s] 1620 else: 1621 SID = len(self.strings) + cffStandardStringCount 1622 self.strings.append(s) 1623 self.stringMapping[s] = SID 1624 return SID 1625 1626 def getStrings(self): 1627 return self.strings 1628 1629 def buildStringMapping(self): 1630 self.stringMapping = {} 1631 for index in range(len(self.strings)): 1632 self.stringMapping[self.strings[index]] = index + cffStandardStringCount 1633 1634 1635# The 391 Standard Strings as used in the CFF format. 1636# from Adobe Technical None #5176, version 1.0, 18 March 1998 1637 1638cffStandardStrings = ['.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 1639 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', 1640 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 1641 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 1642 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 1643 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 1644 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 1645 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 1646 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 1647 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 1648 'asciitilde', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 1649 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', 1650 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 1651 'daggerdbl', 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', 1652 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 1653 'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 1654 'dotaccent', 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 1655 'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 1656 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', 1657 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 1658 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 1659 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 1660 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 1661 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 1662 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 1663 'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 1664 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 1665 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', 1666 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', 1667 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', 1668 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', 1669 'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall', 1670 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 1671 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 1672 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 1673 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 1674 'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior', 1675 'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 1676 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 1677 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', 1678 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 1679 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 1680 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 1681 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 1682 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', 1683 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 1684 'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', 1685 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 1686 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 1687 'onethird', 'twothirds', 'zerosuperior', 'foursuperior', 'fivesuperior', 1688 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 1689 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 1690 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 1691 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', 1692 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 1693 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 1694 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 1695 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 1696 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 1697 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 1698 'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', 1699 '001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 1700 'Semibold' 1701] 1702 1703cffStandardStringCount = 391 1704assert len(cffStandardStrings) == cffStandardStringCount 1705# build reverse mapping 1706cffStandardStringMapping = {} 1707for _i in range(cffStandardStringCount): 1708 cffStandardStringMapping[cffStandardStrings[_i]] = _i 1709 1710cffISOAdobeStrings = [".notdef", "space", "exclam", "quotedbl", "numbersign", 1711"dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", 1712"asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", 1713"three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", 1714"less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", 1715"H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", 1716"X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", 1717"underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", 1718"k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", 1719"braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent", 1720"sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", 1721"quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", 1722"endash", "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", 1723"quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", 1724"perthousand", "questiondown", "grave", "acute", "circumflex", "tilde", 1725"macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", 1726"ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", "Oslash", "OE", 1727"ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", "germandbls", 1728"onesuperior", "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", 1729"Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn", 1730"threequarters", "twosuperior", "registered", "minus", "eth", "multiply", 1731"threesuperior", "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", 1732"Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", 1733"Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", 1734"Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", 1735"Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute", 1736"acircumflex", "adieresis", "agrave", "aring", "atilde", "ccedilla", "eacute", 1737"ecircumflex", "edieresis", "egrave", "iacute", "icircumflex", "idieresis", 1738"igrave", "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", 1739"scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", "ydieresis", 1740"zcaron"] 1741 1742cffISOAdobeStringCount = 229 1743assert len(cffISOAdobeStrings) == cffISOAdobeStringCount 1744 1745cffIExpertStrings = [".notdef", "space", "exclamsmall", "Hungarumlautsmall", 1746"dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", 1747"parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", 1748"comma", "hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle", 1749"twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", 1750"sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", "semicolon", 1751"commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", 1752"asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", 1753"lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", 1754"tsuperior", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", 1755"parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", 1756"Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", 1757"Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", 1758"Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", 1759"Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", 1760"exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", 1761"Dieresissmall", "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", 1762"figuredash", "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", 1763"onequarter", "onehalf", "threequarters", "questiondownsmall", "oneeighth", 1764"threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", 1765"zerosuperior", "onesuperior", "twosuperior", "threesuperior", "foursuperior", 1766"fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", 1767"zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", 1768"fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", 1769"centinferior", "dollarinferior", "periodinferior", "commainferior", 1770"Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", 1771"Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", 1772"Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", 1773"Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", 1774"Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", 1775"Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", 1776"Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", 1777"Ydieresissmall"] 1778 1779cffExpertStringCount = 166 1780assert len(cffIExpertStrings) == cffExpertStringCount 1781 1782cffExpertSubsetStrings = [".notdef", "space", "dollaroldstyle", 1783"dollarsuperior", "parenleftsuperior", "parenrightsuperior", "twodotenleader", 1784"onedotenleader", "comma", "hyphen", "period", "fraction", "zerooldstyle", 1785"oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", 1786"sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", 1787"semicolon", "commasuperior", "threequartersemdash", "periodsuperior", 1788"asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", 1789"lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", 1790"tsuperior", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", 1791"parenrightinferior", "hyphensuperior", "colonmonetary", "onefitted", "rupiah", 1792"centoldstyle", "figuredash", "hypheninferior", "onequarter", "onehalf", 1793"threequarters", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", 1794"onethird", "twothirds", "zerosuperior", "onesuperior", "twosuperior", 1795"threesuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", 1796"eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", 1797"threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", 1798"eightinferior", "nineinferior", "centinferior", "dollarinferior", 1799"periodinferior", "commainferior"] 1800 1801cffExpertSubsetStringCount = 87 1802assert len(cffExpertSubsetStrings) == cffExpertSubsetStringCount 1803