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