xmlReader.py revision d57c4346e5725bbfe0e1b13067b292c3faaaeb8e
17842e56b97ce677b83bdab09cda48bc2d89ac75aJustfrom fontTools import ttLib 27842e56b97ce677b83bdab09cda48bc2d89ac75aJustfrom fontTools.misc.textTools import safeEval 3f8fd4777d273836a1222b72f6761cb6fdf9ec87aJustfrom fontTools.ttLib.tables.DefaultTable import DefaultTable 44bb05c6ad4b112de40642d77663aa87d145f863fjvrimport os 57842e56b97ce677b83bdab09cda48bc2d89ac75aJust 67842e56b97ce677b83bdab09cda48bc2d89ac75aJust 7ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvrclass TTXParseError(Exception): pass 87842e56b97ce677b83bdab09cda48bc2d89ac75aJust 99b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvrBUFSIZE = 0x4000 109b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvr 117842e56b97ce677b83bdab09cda48bc2d89ac75aJust 12ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvrclass ExpatParser: 137842e56b97ce677b83bdab09cda48bc2d89ac75aJust 144bb05c6ad4b112de40642d77663aa87d145f863fjvr def __init__(self, ttFont, fileName, progress=None): 157842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.ttFont = ttFont 164bb05c6ad4b112de40642d77663aa87d145f863fjvr self.fileName = fileName 177842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.progress = progress 187842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.root = None 19ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.contentStack = [] 20ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.stackSize = 0 21ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr 224bb05c6ad4b112de40642d77663aa87d145f863fjvr def parse(self): 2356bfea43176d03cede26f8de51638c4ab9f4bd64jvr file = open(self.fileName) 2456bfea43176d03cede26f8de51638c4ab9f4bd64jvr self.parseFile(file) 2556bfea43176d03cede26f8de51638c4ab9f4bd64jvr file.close() 2656bfea43176d03cede26f8de51638c4ab9f4bd64jvr 2756bfea43176d03cede26f8de51638c4ab9f4bd64jvr def parseFile(self, file): 28e493669d196f292f24d4c09ce340c3e67749bce5jvr from xml.parsers.expat import ParserCreate 29e493669d196f292f24d4c09ce340c3e67749bce5jvr parser = ParserCreate() 30e493669d196f292f24d4c09ce340c3e67749bce5jvr parser.returns_unicode = 0 31e493669d196f292f24d4c09ce340c3e67749bce5jvr parser.StartElementHandler = self.startElementHandler 32e493669d196f292f24d4c09ce340c3e67749bce5jvr parser.EndElementHandler = self.endElementHandler 33e493669d196f292f24d4c09ce340c3e67749bce5jvr parser.CharacterDataHandler = self.characterDataHandler 34e493669d196f292f24d4c09ce340c3e67749bce5jvr 359b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvr pos = 0 369b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvr while 1: 379b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvr chunk = file.read(BUFSIZE) 389b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvr if not chunk: 399b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvr parser.Parse(chunk, 1) 409b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvr break 419b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvr pos = pos + len(chunk) 429b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvr if self.progress: 439b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvr self.progress.set(pos / 100) 449b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvr parser.Parse(chunk, 0) 45ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr 46e493669d196f292f24d4c09ce340c3e67749bce5jvr def startElementHandler(self, name, attrs): 47ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr stackSize = self.stackSize 48e82b4d5658a7a38cf92b4b9392861257a2cfbb36jvr self.stackSize = stackSize + 1 49f8fd4777d273836a1222b72f6761cb6fdf9ec87aJust if not stackSize: 507842e56b97ce677b83bdab09cda48bc2d89ac75aJust if name <> "ttFont": 51ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr raise TTXParseError, "illegal root tag: %s" % name 524bb05c6ad4b112de40642d77663aa87d145f863fjvr sfntVersion = attrs.get("sfntVersion") 534bb05c6ad4b112de40642d77663aa87d145f863fjvr if sfntVersion is not None: 544bb05c6ad4b112de40642d77663aa87d145f863fjvr if len(sfntVersion) <> 4: 554bb05c6ad4b112de40642d77663aa87d145f863fjvr sfntVersion = safeEval('"' + sfntVersion + '"') 564bb05c6ad4b112de40642d77663aa87d145f863fjvr self.ttFont.sfntVersion = sfntVersion 57ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.contentStack.append([]) 58f8fd4777d273836a1222b72f6761cb6fdf9ec87aJust elif stackSize == 1: 594bb05c6ad4b112de40642d77663aa87d145f863fjvr subFile = attrs.get("src") 604bb05c6ad4b112de40642d77663aa87d145f863fjvr if subFile is not None: 614bb05c6ad4b112de40642d77663aa87d145f863fjvr subFile = os.path.join(os.path.dirname(self.fileName), subFile) 624bb05c6ad4b112de40642d77663aa87d145f863fjvr importXML(self.ttFont, subFile, self.progress) 634bb05c6ad4b112de40642d77663aa87d145f863fjvr self.contentStack.append([]) 644bb05c6ad4b112de40642d77663aa87d145f863fjvr return 650011bb691018c7feed1f8c3554d88b9ae096e127jvr tag = ttLib.xmlToTag(name) 660011bb691018c7feed1f8c3554d88b9ae096e127jvr msg = "Parsing '%s' table..." % tag 677842e56b97ce677b83bdab09cda48bc2d89ac75aJust if self.progress: 687842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.progress.setlabel(msg) 697842e56b97ce677b83bdab09cda48bc2d89ac75aJust elif self.ttFont.verbose: 707842e56b97ce677b83bdab09cda48bc2d89ac75aJust ttLib.debugmsg(msg) 717842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 727842e56b97ce677b83bdab09cda48bc2d89ac75aJust print msg 730011bb691018c7feed1f8c3554d88b9ae096e127jvr if tag == "GlyphOrder": 740011bb691018c7feed1f8c3554d88b9ae096e127jvr tableClass = ttLib.GlyphOrder 750011bb691018c7feed1f8c3554d88b9ae096e127jvr elif attrs.has_key("ERROR"): 76f8fd4777d273836a1222b72f6761cb6fdf9ec87aJust tableClass = DefaultTable 77f8fd4777d273836a1222b72f6761cb6fdf9ec87aJust else: 78f8fd4777d273836a1222b72f6761cb6fdf9ec87aJust tableClass = ttLib.getTableClass(tag) 79f8fd4777d273836a1222b72f6761cb6fdf9ec87aJust if tableClass is None: 80f8fd4777d273836a1222b72f6761cb6fdf9ec87aJust tableClass = DefaultTable 81d57c4346e5725bbfe0e1b13067b292c3faaaeb8ejvr if tag == 'loca' and self.ttFont.has_key(tag): 82d57c4346e5725bbfe0e1b13067b292c3faaaeb8ejvr # Special-case the 'loca' table as we need the 83e82b4d5658a7a38cf92b4b9392861257a2cfbb36jvr # original if the 'glyf' table isn't recompiled. 84ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.currentTable = self.ttFont[tag] 851670f7af0edf5af2447f9fb157febe8cfb44b629Just else: 86ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.currentTable = tableClass(tag) 87ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.ttFont[tag] = self.currentTable 88ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.contentStack.append([]) 89f8fd4777d273836a1222b72f6761cb6fdf9ec87aJust elif stackSize == 2: 90ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.contentStack.append([]) 91ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.root = (name, attrs, self.contentStack[-1]) 927842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 937842e56b97ce677b83bdab09cda48bc2d89ac75aJust list = [] 94ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.contentStack[-1].append((name, attrs, list)) 95ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.contentStack.append(list) 967842e56b97ce677b83bdab09cda48bc2d89ac75aJust 97e493669d196f292f24d4c09ce340c3e67749bce5jvr def characterDataHandler(self, data): 98ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr if self.stackSize > 1: 99ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.contentStack[-1].append(data) 1007842e56b97ce677b83bdab09cda48bc2d89ac75aJust 101e493669d196f292f24d4c09ce340c3e67749bce5jvr def endElementHandler(self, name): 102ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.stackSize = self.stackSize - 1 103ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr del self.contentStack[-1] 104ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr if self.stackSize == 1: 1057842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.root = None 106ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr elif self.stackSize == 2: 107ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.currentTable.fromXML(self.root, self.ttFont) 1087842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.root = None 1097842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1107842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1117842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass ProgressPrinter: 1127842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1137842e56b97ce677b83bdab09cda48bc2d89ac75aJust def __init__(self, title, maxval=100): 1147842e56b97ce677b83bdab09cda48bc2d89ac75aJust print title 1157842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1167842e56b97ce677b83bdab09cda48bc2d89ac75aJust def set(self, val, maxval=None): 1177842e56b97ce677b83bdab09cda48bc2d89ac75aJust pass 1187842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1197842e56b97ce677b83bdab09cda48bc2d89ac75aJust def increment(self, val=1): 1207842e56b97ce677b83bdab09cda48bc2d89ac75aJust pass 1217842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1227842e56b97ce677b83bdab09cda48bc2d89ac75aJust def setlabel(self, text): 1237842e56b97ce677b83bdab09cda48bc2d89ac75aJust print text 1247842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1257842e56b97ce677b83bdab09cda48bc2d89ac75aJust 126ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvrdef importXML(ttFont, fileName, progress=None): 127ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr """Import a TTX file (an XML-based text format), so as to recreate 128ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr a font object. 129ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr """ 1309b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvr if progress: 1319b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvr import stat 1329b7b8e0f5b5f968acb95f8c3a484ea8d42924d65jvr progress.set(0, os.stat(fileName)[stat.ST_SIZE] / 100 or 1) 1334bb05c6ad4b112de40642d77663aa87d145f863fjvr p = ExpatParser(ttFont, fileName, progress) 1344bb05c6ad4b112de40642d77663aa87d145f863fjvr p.parse() 135ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr 136