xmlReader.py revision 7ed91eca1eaa96b79eae780778e89bb9ec44c1ee
1from fontTools import ttLib 2from fontTools.misc.textTools import safeEval 3from fontTools.ttLib.tables.DefaultTable import DefaultTable 4import os 5from .py23 import * 6 7 8class TTXParseError(Exception): pass 9 10BUFSIZE = 0x4000 11 12 13class XMLReader: 14 15 def __init__(self, fileName, ttFont, progress=None, quiet=False): 16 self.ttFont = ttFont 17 self.fileName = fileName 18 self.progress = progress 19 self.quiet = quiet 20 self.root = None 21 self.contentStack = [] 22 self.stackSize = 0 23 24 def read(self): 25 if self.progress: 26 import stat 27 self.progress.set(0, os.stat(fileName)[stat.ST_SIZE] / 100 or 1) 28 file = open(self.fileName) 29 self._parseFile(file) 30 file.close() 31 32 def _parseFile(self, file): 33 from xml.parsers.expat import ParserCreate 34 parser = ParserCreate() 35 parser.returns_unicode = 0 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: 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 list = [] 101 self.contentStack[-1].append((name, attrs, list)) 102 self.contentStack.append(list) 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: 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