1from __future__ import print_function, division, absolute_import 2from fontTools.misc.py23 import * 3from fontTools import ttLib 4from fontTools.misc.textTools import safeEval 5from fontTools.ttLib.tables.DefaultTable import DefaultTable 6import os 7 8 9class TTXParseError(Exception): pass 10 11BUFSIZE = 0x4000 12 13 14class XMLReader(object): 15 16 def __init__(self, fileName, ttFont, progress=None, quiet=False): 17 self.ttFont = ttFont 18 self.fileName = fileName 19 self.progress = progress 20 self.quiet = quiet 21 self.root = None 22 self.contentStack = [] 23 self.stackSize = 0 24 25 def read(self): 26 if self.progress: 27 import stat 28 self.progress.set(0, os.stat(self.fileName)[stat.ST_SIZE] // 100 or 1) 29 file = open(self.fileName) 30 self._parseFile(file) 31 file.close() 32 33 def _parseFile(self, file): 34 from xml.parsers.expat import ParserCreate 35 parser = ParserCreate() 36 parser.StartElementHandler = self._startElementHandler 37 parser.EndElementHandler = self._endElementHandler 38 parser.CharacterDataHandler = self._characterDataHandler 39 40 pos = 0 41 while True: 42 chunk = file.read(BUFSIZE) 43 if not chunk: 44 parser.Parse(chunk, 1) 45 break 46 pos = pos + len(chunk) 47 if self.progress: 48 self.progress.set(pos // 100) 49 parser.Parse(chunk, 0) 50 51 def _startElementHandler(self, name, attrs): 52 stackSize = self.stackSize 53 self.stackSize = stackSize + 1 54 if not stackSize: 55 if name != "ttFont": 56 raise TTXParseError("illegal root tag: %s" % name) 57 sfntVersion = attrs.get("sfntVersion") 58 if sfntVersion is not None: 59 if len(sfntVersion) != 4: 60 sfntVersion = safeEval('"' + sfntVersion + '"') 61 self.ttFont.sfntVersion = sfntVersion 62 self.contentStack.append([]) 63 elif stackSize == 1: 64 subFile = attrs.get("src") 65 if subFile is not None: 66 subFile = os.path.join(os.path.dirname(self.fileName), subFile) 67 subReader = XMLReader(subFile, self.ttFont, self.progress, self.quiet) 68 subReader.read() 69 self.contentStack.append([]) 70 return 71 tag = ttLib.xmlToTag(name) 72 msg = "Parsing '%s' table..." % tag 73 if self.progress: 74 self.progress.setlabel(msg) 75 elif self.ttFont.verbose: 76 ttLib.debugmsg(msg) 77 else: 78 if not self.quiet: 79 print(msg) 80 if tag == "GlyphOrder": 81 tableClass = ttLib.GlyphOrder 82 elif "ERROR" in attrs or ('raw' in attrs and safeEval(attrs['raw'])): 83 tableClass = DefaultTable 84 else: 85 tableClass = ttLib.getTableClass(tag) 86 if tableClass is None: 87 tableClass = DefaultTable 88 if tag == 'loca' and tag in self.ttFont: 89 # Special-case the 'loca' table as we need the 90 # original if the 'glyf' table isn't recompiled. 91 self.currentTable = self.ttFont[tag] 92 else: 93 self.currentTable = tableClass(tag) 94 self.ttFont[tag] = self.currentTable 95 self.contentStack.append([]) 96 elif stackSize == 2: 97 self.contentStack.append([]) 98 self.root = (name, attrs, self.contentStack[-1]) 99 else: 100 l = [] 101 self.contentStack[-1].append((name, attrs, l)) 102 self.contentStack.append(l) 103 104 def _characterDataHandler(self, data): 105 if self.stackSize > 1: 106 self.contentStack[-1].append(data) 107 108 def _endElementHandler(self, name): 109 self.stackSize = self.stackSize - 1 110 del self.contentStack[-1] 111 if self.stackSize == 1: 112 self.root = None 113 elif self.stackSize == 2: 114 name, attrs, content = self.root 115 self.currentTable.fromXML(name, attrs, content, self.ttFont) 116 self.root = None 117 118 119class ProgressPrinter(object): 120 121 def __init__(self, title, maxval=100): 122 print(title) 123 124 def set(self, val, maxval=None): 125 pass 126 127 def increment(self, val=1): 128 pass 129 130 def setLabel(self, text): 131 print(text) 132 133