text: #!/usr/bin/python
  
  # FontDame-to-FontTools for OpenType Layout tables
  #
  # Source language spec is available at:
  # http://monotype.github.io/OpenType_Table_Source/otl_source.html
  # https://github.com/Monotype/OpenType_Table_Source/
  
  from __future__ import print_function, division, absolute_import
  from __future__ import unicode_literals
  from fontTools.misc.py23 import *
  from fontTools import ttLib
  from fontTools.ttLib.tables._c_m_a_p import cmap_classes
  from fontTools.ttLib.tables import otTables as ot
  from fontTools.ttLib.tables.otBase import ValueRecord, valueRecordFormatDict
  from fontTools.otlLib import builder as otl
  from contextlib import contextmanager
  from operator import setitem
  import logging
  import warnings
  
  class MtiLibError(Exception): pass
  class ReferenceNotFoundError(MtiLibError): pass
  class FeatureNotFoundError(ReferenceNotFoundError): pass
  class LookupNotFoundError(ReferenceNotFoundError): pass
  
  
  log = logging.getLogger(__name__)
  
  
  def makeGlyph(s):
  	if s[:2] in ['U ', 'u ']:
  		return ttLib.TTFont._makeGlyphName(int(s[2:], 16))
  	elif s[:2] == '# ':
  		return "glyph%.5d" % int(s[2:])
  	assert s.find(' ') < 0, "Space found in glyph name: %s" % s
  	assert s, "Glyph name is empty"
  	return s
  
  def makeGlyphs(l):
  	return [makeGlyph(g) for g in l]
  
  def mapLookup(sym, mapping):
  	# Lookups are addressed by name.  So resolved them using a map if available.
  	# Fallback to parsing as lookup index if a map isn't provided.
  	if mapping is not None:
  		try:
  			idx = mapping[sym]
  		except KeyError:
  			raise LookupNotFoundError(sym)
  	else:
  		idx = int(sym)
  	return idx
  
  def mapFeature(sym, mapping):
  	# Features are referenced by index according the spec.  So, if symbol is an
  	# integer, use it directly.  Otherwise look up in the map if provided.
  	try:
  		idx = int(sym)
  	except ValueError:
  		try:
  			idx = mapping[sym]
  		except KeyError:
  			raise FeatureNotFoundError(sym)
  	return idx
  
  def setReference(mapper, mapping, sym, setter, collection, key):
  	try:
  		mapped = mapper(sym, mapping)
  	except ReferenceNotFoundError as e:
  		try:
  			if mapping is not None:
  				mapping.addDeferredMapping(lambda ref: setter(collection, key, ref), sym, e)
  				return
  		except AttributeError:
  			pass
  		raise
  	setter(collection, key, mapped)
  
  class DeferredMapping(dict):
  
  	def __init__(self):
  		self._deferredMappings = []
  
  	def addDeferredMapping(self, setter, sym, e):
  		log.debug("Adding deferred mapping for symbol '%s' %s", sym, type(e).__name__)
  		self._deferredMappings.append((setter,sym, e))
  
  	def applyDeferredMappings(self):
  		for setter,sym,e in self._deferredMappings:
  			log.debug("Applying deferred mapping for symbol '%s' %s", sym, type(e).__name__)
  			try:
  				mapped = self[sym]
  			except KeyError:
  				raise e
  			setter(mapped)
  			log.debug("Set to %s", mapped)
  		self._deferredMappings = []
  
  
  def parseScriptList(lines, featureMap=None):
  	self = ot.ScriptList()
  	records = []
  	with lines.between('script table'):
  		for line in lines:
  			scriptTag, langSysTag, defaultFeature, features = line
  			log.debug("Adding script %s language-system %s", scriptTag, langSysTag)
  
  			langSys = ot.LangSys()
  			langSys.LookupOrder = None
  			if defaultFeature:
  				setReference(mapFeature, featureMap, defaultFeature, setattr, langSys, 'ReqFeatureIndex')
  			else:
  				langSys.ReqFeatureIndex = 0xFFFF
  			syms = stripSplitComma(features)
  			langSys.FeatureIndex = theList = [3] * len(syms)
  			for i,sym in enumerate(syms):
  				setReference(mapFeature, featureMap, sym, setitem, theList, i)
  			langSys.FeatureCount = len(langSys.FeatureIndex)
  
  			script = [s for s in records if s.ScriptTag == scriptTag]
  			if script:
  				script = script[0].Script
  			else:
  				scriptRec = ot.ScriptRecord()
  				scriptRec.ScriptTag = scriptTag
  				scriptRec.Script = ot.Script()
  				records.append(scriptRec)
  				script = scriptRec.Script
  				script.DefaultLangSys = None
  				script.LangSysRecord = []
  				script.LangSysCount = 0
  
  			if langSysTag == 'default':
  				script.DefaultLangSys = langSys
  			else:
  				langSysRec = ot.LangSysRecord()
  				langSysRec.LangSysTag = langSysTag + ' '*(4 - len(langSysTag))
  				langSysRec.LangSys = langSys
  				script.LangSysRecord.append(langSysRec)
  				script.LangSysCount = len(script.LangSysRecord)
  
  	for script in records:
  		script.Script.LangSysRecord = sorted(script.Script.LangSysRecord, key=lambda rec: rec.LangSysTag)
  	self.ScriptRecord = sorted(records, key=lambda rec: rec.ScriptTag)
  	self.ScriptCount = len(self.ScriptRecord)
  	return self
  
  def parseFeatureList(lines, lookupMap=None, featureMap=None):
  	self = ot.FeatureList()
  	self.FeatureRecord = []
  	with lines.between('feature table'):
  		for line in lines:
  			name, featureTag, lookups = line
  			if featureMap is not None:
  				assert name not in featureMap, "Duplicate feature name: %s" % name
  				featureMap[name] = len(self.FeatureRecord)
  			# If feature name is integer, make sure it matches its index.
  			try:
  				assert int(name) == len(self.FeatureRecord), "%d %d" % (name, len(self.FeatureRecord))
  			except ValueError:
  				pass
  			featureRec = ot.FeatureRecord()
  			featureRec.FeatureTag = featureTag
  			featureRec.Feature = ot.Feature()
  			self.FeatureRecord.append(featureRec)
  			feature = featureRec.Feature
  			feature.FeatureParams = None
  			syms = stripSplitComma(lookups)
  			feature.LookupListIndex = theList = [None] * len(syms)
  			for i,sym in enumerate(syms):
  				setReference(mapLookup, lookupMap, sym, setitem, theList, i)
  			feature.LookupCount = len(feature.LookupListIndex)
  
  	self.FeatureCount = len(self.FeatureRecord)
  	return self
  
  def parseLookupFlags(lines):
  	flags = 0
  	filterset = None
  	allFlags = [
  		'righttoleft',
  		'ignorebaseglyphs',
  		'ignoreligatures',
  		'ignoremarks',
  		'markattachmenttype',
  		'markfiltertype',
  	]
  	while lines.peek()[0].lower() in allFlags:
  		line = next(lines)
  		flag = {
  			'righttoleft':		0x0001,
  			'ignorebaseglyphs':	0x0002,
  			'ignoreligatures':	0x0004,
  			'ignoremarks':		0x0008,
  			}.get(line[0].lower())
  		if flag:
  			assert line[1].lower() in ['yes', 'no'], line[1]
  			if line[1].lower() == 'yes':
  				flags |= flag
  			continue
  		if line[0].lower() == 'markattachmenttype':
  			flags |= int(line[1]) << 8
  			continue
  		if line[0].lower() == 'markfiltertype':
  			flags |= 0x10
  			filterset = int(line[1])
  	return flags, filterset
  
  def parseSingleSubst(lines, font, _lookupMap=None):
  	mapping = {}
  	for line in lines:
  		assert len(line) == 2, line
  		line = makeGlyphs(line)
  		mapping[line[0]] = line[1]
  	return otl.buildSingleSubstSubtable(mapping)
  
  def parseMultiple(lines, font, _lookupMap=None):
  	mapping = {}
  	for line in lines:
  		line = makeGlyphs(line)
  		mapping[line[0]] = line[1:]
  	return otl.buildMultipleSubstSubtable(mapping)
  
  def parseAlternate(lines, font, _lookupMap=None):
  	mapping = {}
  	for line in lines:
  		line = makeGlyphs(line)
  		mapping[line[0]] = line[1:]
  	return otl.buildAlternateSubstSubtable(mapping)
  
  def parseLigature(lines, font, _lookupMap=None):
  	mapping = {}
  	for line in lines:
  		assert len(line) >= 2, line
  		line = makeGlyphs(line)
  		mapping[tuple(line[1:])] = line[0]
  	return otl.buildLigatureSubstSubtable(mapping)
  
  def parseSinglePos(lines, font, _lookupMap=None):
  	values = {}
  	for line in lines:
  		assert len(line) == 3, line
  		w = line[0].title().replace(' ', '')
  		assert w in valueRecordFormatDict
  		g = makeGlyph(line[1])
  		v = int(line[2])
  		if g not in values:
  			values[g] = ValueRecord()
  		assert not hasattr(values[g], w), (g, w)
  		setattr(values[g], w, v)
  	return otl.buildSinglePosSubtable(values, font.getReverseGlyphMap())
  
  def parsePair(self, lines, font, _lookupMap=None):
  	self.ValueFormat1 = self.ValueFormat2 = 0
  	typ = lines.peek()[0].split()[0].lower()
  	if typ in ('left', 'right'):
  		self.Format = 1
  		values = {}
  		for line in lines:
  			assert len(line) == 4, line
  			side = line[0].split()[0].lower()
  			assert side in ('left', 'right'), side
  			what = line[0][len(side):].title().replace(' ', '')
  			mask = valueRecordFormatDict[what][0]
  			glyph1, glyph2 = makeGlyphs(line[1:3])
  			value = int(line[3])
  			if not glyph1 in values: values[glyph1] = {}
  			if not glyph2 in values[glyph1]: values[glyph1][glyph2] = (ValueRecord(),ValueRecord())
  			rec2 = values[glyph1][glyph2]
  			if side == 'left':
  				self.ValueFormat1 |= mask
  				vr = rec2[0]
  			else:
  				self.ValueFormat2 |= mask
  				vr = rec2[1]
  			assert not hasattr(vr, what), (vr, what)
  			setattr(vr, what, value)
  		self.Coverage = makeCoverage(values.keys(), font)
  		self.PairSet = []
  		for glyph1 in self.Coverage.glyphs:
  			values1 = values[glyph1]
  			pairset = ot.PairSet()
  			records = pairset.PairValueRecord = []
  			for glyph2 in sorted(values1.keys(), key=font.getGlyphID):
  				values2 = values1[glyph2]
  				pair = ot.PairValueRecord()
  				pair.SecondGlyph = glyph2
  				pair.Value1,pair.Value2 = values2
  				records.append(pair)
  			pairset.PairValueCount = len(pairset.PairValueRecord)
  			self.PairSet.append(pairset)
  		self.PairSetCount = len(self.PairSet)
  	elif typ.endswith('class'):
  		self.Format = 2
  		classDefs = [None, None]
  		while lines.peek()[0].endswith("class definition begin"):
  			typ = lines.peek()[0][:-len("class definition begin")].lower()
  			idx,klass = {
  				'first':	(0,ot.ClassDef1),
  				'second':	(1,ot.ClassDef2),
  			}[typ]
  			assert classDefs[idx] is None
  			classDefs[idx] = parseClassDef(lines, klass=klass)
  		self.ClassDef1, self.ClassDef2 = classDefs
  		self.Class1Count, self.Class2Count = (1+max(c.classDefs.values()) for c in classDefs)
  		self.Class1Record = [ot.Class1Record() for i in range(self.Class1Count)]
  		for rec1 in self.Class1Record:
  			rec1.Class2Record = [ot.Class2Record() for j in range(self.Class2Count)]
  			for rec2 in rec1.Class2Record:
  				rec2.Value1 = ValueRecord()
  				rec2.Value2 = ValueRecord()
  		for line in lines:
  			assert len(line) == 4, line
  			side = line[0].split()[0].lower()
  			assert side in ('left', 'right'), side
  			what = line[0][len(side):].title().replace(' ', '')
  			mask = valueRecordFormatDict[what][0]
  			class1, class2, value = (int(x) for x in line[1:4])
  			rec2 = self.Class1Record[class1].Class2Record[class2]
  			if side == 'left':
  				self.ValueFormat1 |= mask
  				vr = rec2.Value1
  			else:
  				self.ValueFormat2 |= mask
  				vr = rec2.Value2
  			assert not hasattr(vr, what), (vr, what)
  			setattr(vr, what, value)
  		self.Coverage = makeCoverage(self.ClassDef1.classDefs.keys(), font)
  	else:
  		assert 0, typ
  
  def parseKernset(self, lines, font, _lookupMap=None):
  	typ = lines.peek()[0].split()[0].lower()
  	if typ in ('left', 'right'):
  		with lines.until(("firstclass definition begin", "secondclass definition begin")):
  			return parsePair(self, lines, font)
  	return parsePair(self, lines, font)
  
  def makeAnchor(data, klass=ot.Anchor):
  	assert len(data) <= 2
  	anchor = klass()
  	anchor.Format = 1
  	anchor.XCoordinate,anchor.YCoordinate = intSplitComma(data[0])
  	if len(data) > 1 and data[1] != '':
  		anchor.Format = 2
  		anchor.AnchorPoint = int(data[1])
  	return anchor
  
  def parseCursive(lines, font, _lookupMap=None):
  	records = {}
  	for line in lines:
  		assert len(line) in [3,4], line
  		idx,klass = {
  			'entry':	(0,ot.EntryAnchor),
  			'exit':		(1,ot.ExitAnchor),
  		}[line[0]]
  		glyph = makeGlyph(line[1])
  		if glyph not in records:
  			records[glyph] = [None,None]
  		assert records[glyph][idx] is None, (glyph, idx)
  		records[glyph][idx] = makeAnchor(line[2:], klass)
  	return otl.buildCursivePosSubtable(records, font.getReverseGlyphMap())
  
  def makeMarkRecords(data, coverage, c):
  	records = []
  	for glyph in coverage.glyphs:
  		klass, anchor = data[glyph]
  		record = c.MarkRecordClass()
  		record.Class = klass
  		setattr(record, c.MarkAnchor, anchor)
  		records.append(record)
  	return records
  
  def makeBaseRecords(data, coverage, c, classCount):
  	records = []
  	idx = {}
  	for glyph in coverage.glyphs:
  		idx[glyph] = len(records)
  		record = c.BaseRecordClass()
  		anchors = [None] * classCount
  		setattr(record, c.BaseAnchor, anchors)
  		records.append(record)
  	for (glyph,klass),anchor in data.items():
  		record = records[idx[glyph]]
  		anchors = getattr(record, c.BaseAnchor)
  		assert anchors[klass] is None, (glyph, klass)
  		anchors[klass] = anchor
  	return records
  
  def makeLigatureRecords(data, coverage, c, classCount):
  	records = [None] * len(coverage.glyphs)
  	idx = {g:i for i,g in enumerate(coverage.glyphs)}
  
  	for (glyph,klass,compIdx,compCount),anchor in data.items():
  		record = records[idx[glyph]]
  		if record is None:
  			record = records[idx[glyph]] = ot.LigatureAttach()
  			record.ComponentCount = compCount
  			record.ComponentRecord = [ot.ComponentRecord() for i in range(compCount)]
  			for compRec in record.ComponentRecord:
  				compRec.LigatureAnchor = [None] * classCount
  		assert record.ComponentCount == compCount, (glyph, record.ComponentCount, compCount)
  
  		anchors = record.ComponentRecord[compIdx - 1].LigatureAnchor
  		assert anchors[klass] is None, (glyph, compIdx, klass)
  		anchors[klass] = anchor
  	return records
  
  def parseMarkToSomething(self, lines, font, c):
  	self.Format = 1
  	markData = {}
  	baseData = {}
  	Data = {
  		'mark':		(markData, c.MarkAnchorClass),
  		'base':		(baseData, c.BaseAnchorClass),
  		'ligature':	(baseData, c.BaseAnchorClass),
  	}
  	for line in lines:
  		typ = line[0]
  		assert typ in ('mark', 'base', 'ligature')
  		glyph = makeGlyph(line[1])
  		data, anchorClass = Data[typ]
  		extraItems = 2 if typ == 'ligature' else 0
  		extras = tuple(int(i) for i in line[2:2+extraItems])
  		klass = int(line[2+extraItems])
  		anchor = makeAnchor(line[3+extraItems:], anchorClass)
  		if typ == 'mark':
  			key,value = glyph,(klass,anchor)
  		else:
  			key,value = ((glyph,klass)+extras),anchor
  		assert key not in data, key
  		data[key] = value
  
  	# Mark
  	markCoverage = makeCoverage(markData.keys(), font, c.MarkCoverageClass)
  	markArray = c.MarkArrayClass()
  	markRecords = makeMarkRecords(markData, markCoverage, c)
  	setattr(markArray, c.MarkRecord, markRecords)
  	setattr(markArray, c.MarkCount, len(markRecords))
  	setattr(self, c.MarkCoverage, markCoverage)
  	setattr(self, c.MarkArray, markArray)
  
  	# Base
  	self.classCount = 0 if not baseData else 1+max(k[1] for k,v in baseData.items())
  	baseCoverage = makeCoverage([k[0] for k in baseData.keys()], font, c.BaseCoverageClass)
  	baseArray = c.BaseArrayClass()
  	if c.Base == 'Ligature':
  		baseRecords = makeLigatureRecords(baseData, baseCoverage, c, self.classCount)
  	else:
  		baseRecords = makeBaseRecords(baseData, baseCoverage, c, self.classCount)
  	setattr(baseArray, c.BaseRecord, baseRecords)
  	setattr(baseArray, c.BaseCount, len(baseRecords))
  	setattr(self, c.BaseCoverage, baseCoverage)
  	setattr(self, c.BaseArray, baseArray)
  
  class MarkHelper(object):
  	def __init__(self):
  		for Which in ('Mark', 'Base'):
  			for What in ('Coverage', 'Array', 'Count', 'Record', 'Anchor'):
  				key = Which + What
  				if Which == 'Mark' and What in ('Count', 'Record', 'Anchor'):
  					value = key
  				else:
  					value = getattr(self, Which) + What
  				if value == 'LigatureRecord':
  					value = 'LigatureAttach'
  				setattr(self, key, value)
  				if What != 'Count':
  					klass = getattr(ot, value)
  					setattr(self, key+'Class', klass)
  
  class MarkToBaseHelper(MarkHelper):
  	Mark = 'Mark'
  	Base = 'Base'
  class MarkToMarkHelper(MarkHelper):
  	Mark = 'Mark1'
  	Base = 'Mark2'
  class MarkToLigatureHelper(MarkHelper):
  	Mark = 'Mark'
  	Base = 'Ligature'
  
  def parseMarkToBase(self, lines, font, _lookupMap=None):
  	return parseMarkToSomething(self, lines, font, MarkToBaseHelper())
  def parseMarkToMark(self, lines, font, _lookupMap=None):
  	return parseMarkToSomething(self, lines, font, MarkToMarkHelper())
  def parseMarkToLigature(self, lines, font, _lookupMap=None):
  	return parseMarkToSomething(self, lines, font, MarkToLigatureHelper())
  
  def stripSplitComma(line):
  	return [s.strip() for s in line.split(',')] if line else []
  
  def intSplitComma(line):
  	return [int(i) for i in line.split(',')] if line else []
  
  # Copied from fontTools.subset
  class ContextHelper(object):
  	def __init__(self, klassName, Format):
  		if klassName.endswith('Subst'):
  			Typ = 'Sub'
  			Type = 'Subst'
  		else:
  			Typ = 'Pos'
  			Type = 'Pos'
  		if klassName.startswith('Chain'):
  			Chain = 'Chain'
  			InputIdx = 1
  			DataLen = 3
  		else:
  			Chain = ''
  			InputIdx = 0
  			DataLen = 1
  		ChainTyp = Chain+Typ
  
  		self.Typ = Typ
  		self.Type = Type
  		self.Chain = Chain
  		self.ChainTyp = ChainTyp
  		self.InputIdx = InputIdx
  		self.DataLen = DataLen
  
  		self.LookupRecord = Type+'LookupRecord'
  
  		if Format == 1:
  			Coverage = lambda r: r.Coverage
  			ChainCoverage = lambda r: r.Coverage
  			ContextData = lambda r:(None,)
  			ChainContextData = lambda r:(None, None, None)
  			SetContextData = None
  			SetChainContextData = None
  			RuleData = lambda r:(r.Input,)
  			ChainRuleData = lambda r:(r.Backtrack, r.Input, r.LookAhead)
  			def SetRuleData(r, d):
  				(r.Input,) = d
  				(r.GlyphCount,) = (len(x)+1 for x in d)
  			def ChainSetRuleData(r, d):
  				(r.Backtrack, r.Input, r.LookAhead) = d
  				(r.BacktrackGlyphCount,r.InputGlyphCount,r.LookAheadGlyphCount,) = (len(d[0]),len(d[1])+1,len(d[2]))
  		elif Format == 2:
  			Coverage = lambda r: r.Coverage
  			ChainCoverage = lambda r: r.Coverage
  			ContextData = lambda r:(r.ClassDef,)
  			ChainContextData = lambda r:(r.BacktrackClassDef,
  						     r.InputClassDef,
  						     r.LookAheadClassDef)
  			def SetContextData(r, d):
  				(r.ClassDef,) = d
  			def SetChainContextData(r, d):
  				(r.BacktrackClassDef,
  				 r.InputClassDef,
  				 r.LookAheadClassDef) = d
  			RuleData = lambda r:(r.Class,)
  			ChainRuleData = lambda r:(r.Backtrack, r.Input, r.LookAhead)
  			def SetRuleData(r, d):
  				(r.Class,) = d
  				(r.GlyphCount,) = (len(x)+1 for x in d)
  			def ChainSetRuleData(r, d):
  				(r.Backtrack, r.Input, r.LookAhead) = d
  				(r.BacktrackGlyphCount,r.InputGlyphCount,r.LookAheadGlyphCount,) = (len(d[0]),len(d[1])+1,len(d[2]))
  		elif Format == 3:
  			Coverage = lambda r: r.Coverage[0]
  			ChainCoverage = lambda r: r.InputCoverage[0]
  			ContextData = None
  			ChainContextData = None
  			SetContextData = None
  			SetChainContextData = None
  			RuleData = lambda r: r.Coverage
  			ChainRuleData = lambda r:(r.BacktrackCoverage +
  						  r.InputCoverage +
  						  r.LookAheadCoverage)
  			def SetRuleData(r, d):
  				(r.Coverage,) = d
  				(r.GlyphCount,) = (len(x) for x in d)
  			def ChainSetRuleData(r, d):
  				(r.BacktrackCoverage, r.InputCoverage, r.LookAheadCoverage) = d
  				(r.BacktrackGlyphCount,r.InputGlyphCount,r.LookAheadGlyphCount,) = (len(x) for x in d)
  		else:
  			assert 0, "unknown format: %s" % Format
  
  		if Chain:
  			self.Coverage = ChainCoverage
  			self.ContextData = ChainContextData
  			self.SetContextData = SetChainContextData
  			self.RuleData = ChainRuleData
  			self.SetRuleData = ChainSetRuleData
  		else:
  			self.Coverage = Coverage
  			self.ContextData = ContextData
  			self.SetContextData = SetContextData
  			self.RuleData = RuleData
  			self.SetRuleData = SetRuleData
  
  		if Format == 1:
  			self.Rule = ChainTyp+'Rule'
  			self.RuleCount = ChainTyp+'RuleCount'
  			self.RuleSet = ChainTyp+'RuleSet'
  			self.RuleSetCount = ChainTyp+'RuleSetCount'
  			self.Intersect = lambda glyphs, c, r: [r] if r in glyphs else []
  		elif Format == 2:
  			self.Rule = ChainTyp+'ClassRule'
  			self.RuleCount = ChainTyp+'ClassRuleCount'
  			self.RuleSet = ChainTyp+'ClassSet'
  			self.RuleSetCount = ChainTyp+'ClassSetCount'
  			self.Intersect = lambda glyphs, c, r: (c.intersect_class(glyphs, r) if c
  							       else (set(glyphs) if r == 0 else set()))
  
  			self.ClassDef = 'InputClassDef' if Chain else 'ClassDef'
  			self.ClassDefIndex = 1 if Chain else 0
  			self.Input = 'Input' if Chain else 'Class'
  
  def parseLookupRecords(items, klassName, lookupMap=None):
  	klass = getattr(ot, klassName)
  	lst = []
  	for item in items:
  		rec = klass()
  		item = stripSplitComma(item)
  		assert len(item) == 2, item
  		idx = int(item[0])
  		assert idx > 0, idx
  		rec.SequenceIndex = idx - 1
  		setReference(mapLookup, lookupMap, item[1], setattr, rec, 'LookupListIndex')
  		lst.append(rec)
  	return lst
  
  def makeClassDef(classDefs, klass=ot.Coverage):
  	if not classDefs: return None
  	self = klass()
  	self.classDefs = dict(classDefs)
  	return self
  
  def parseClassDef(lines, klass=ot.ClassDef):
  	classDefs = {}
  	with lines.between('class definition'):
  		for line in lines:
  			glyph = makeGlyph(line[0])
  			assert glyph not in classDefs, glyph
  			classDefs[glyph] = int(line[1])
  	return makeClassDef(classDefs, klass)
  
  def makeCoverage(glyphs, font, klass=ot.Coverage):
  	if not glyphs: return None
  	coverage = klass()
  	coverage.glyphs = sorted(set(glyphs), key=font.getGlyphID)
  	return coverage
  
  def parseCoverage(lines, font, klass=ot.Coverage):
  	glyphs = []
  	with lines.between('coverage definition'):
  		for line in lines:
  			glyphs.append(makeGlyph(line[0]))
  	return makeCoverage(glyphs, font, klass)
  
  def bucketizeRules(self, c, rules, bucketKeys):
  	buckets = {}
  	for seq,recs in rules:
  		buckets.setdefault(seq[c.InputIdx][0], []).append((tuple(s[1 if i==c.InputIdx else 0:] for i,s in enumerate(seq)), recs))
  
  	rulesets = []
  	for firstGlyph in bucketKeys:
  		if firstGlyph not in buckets:
  			rulesets.append(None)
  			continue
  		thisRules = []
  		for seq,recs in buckets[firstGlyph]:
  			rule = getattr(ot, c.Rule)()
  			c.SetRuleData(rule, seq)
  			setattr(rule, c.Type+'Count', len(recs))
  			setattr(rule, c.LookupRecord, recs)
  			thisRules.append(rule)
  
  		ruleset = getattr(ot, c.RuleSet)()
  		setattr(ruleset, c.Rule, thisRules)
  		setattr(ruleset, c.RuleCount, len(thisRules))
  		rulesets.append(ruleset)
  
  	setattr(self, c.RuleSet, rulesets)
  	setattr(self, c.RuleSetCount, len(rulesets))
  
  def parseContext(self, lines, font, Type, lookupMap=None):
  	typ = lines.peek()[0].split()[0].lower()
  	if typ == 'glyph':
  		self.Format = 1
  		log.debug("Parsing %s format %s", Type, self.Format)
  		c = ContextHelper(Type, self.Format)
  		rules = []
  		for line in lines:
  			assert line[0].lower() == 'glyph', line[0]
  			while len(line) < 1+c.DataLen: line.append('')
  			seq = tuple(makeGlyphs(stripSplitComma(i)) for i in line[1:1+c.DataLen])
  			recs = parseLookupRecords(line[1+c.DataLen:], c.LookupRecord, lookupMap)
  			rules.append((seq, recs))
  
  		firstGlyphs = set(seq[c.InputIdx][0] for seq,recs in rules)
  		self.Coverage = makeCoverage(firstGlyphs, font)
  		bucketizeRules(self, c, rules, self.Coverage.glyphs)
  	elif typ.endswith('class'):
  		self.Format = 2
  		log.debug("Parsing %s format %s", Type, self.Format)
  		c = ContextHelper(Type, self.Format)
  		classDefs = [None] * c.DataLen
  		while lines.peek()[0].endswith("class definition begin"):
  			typ = lines.peek()[0][:-len("class definition begin")].lower()
  			idx,klass = {
  			1: {
  				'':		(0,ot.ClassDef),
  			},
  			3: {
  				'backtrack':	(0,ot.BacktrackClassDef),
  				'':		(1,ot.InputClassDef),
  				'lookahead':	(2,ot.LookAheadClassDef),
  			},
  			}[c.DataLen][typ]
  			assert classDefs[idx] is None, idx
  			classDefs[idx] = parseClassDef(lines, klass=klass)
  		c.SetContextData(self, classDefs)
  		rules = []
  		for line in lines:
  			assert line[0].lower().startswith('class'), line[0]
  			while len(line) < 1+c.DataLen: line.append('')
  			seq = tuple(intSplitComma(i) for i in line[1:1+c.DataLen])
  			recs = parseLookupRecords(line[1+c.DataLen:], c.LookupRecord, lookupMap)
  			rules.append((seq, recs))
  		firstClasses = set(seq[c.InputIdx][0] for seq,recs in rules)
  		firstGlyphs = set(g for g,c in classDefs[c.InputIdx].classDefs.items() if c in firstClasses)
  		self.Coverage = makeCoverage(firstGlyphs, font)
  		bucketizeRules(self, c, rules, range(max(firstClasses) + 1))
  	elif typ.endswith('coverage'):
  		self.Format = 3
  		log.debug("Parsing %s format %s", Type, self.Format)
  		c = ContextHelper(Type, self.Format)
  		coverages = tuple([] for i in range(c.DataLen))
  		while lines.peek()[0].endswith("coverage definition begin"):
  			typ = lines.peek()[0][:-len("coverage definition begin")].lower()
  			idx,klass = {
  			1: {
  				'':		(0,ot.Coverage),
  			},
  			3: {
  				'backtrack':	(0,ot.BacktrackCoverage),
  				'input':	(1,ot.InputCoverage),
  				'lookahead':	(2,ot.LookAheadCoverage),
  			},
  			}[c.DataLen][typ]
  			coverages[idx].append(parseCoverage(lines, font, klass=klass))
  		c.SetRuleData(self, coverages)
  		lines = list(lines)
  		assert len(lines) == 1
  		line = lines[0]
  		assert line[0].lower() == 'coverage', line[0]
  		recs = parseLookupRecords(line[1:], c.LookupRecord, lookupMap)
  		setattr(self, c.Type+'Count', len(recs))
  		setattr(self, c.LookupRecord, recs)
  	else:
  		assert 0, typ
  
  def parseContextSubst(self, lines, font, lookupMap=None):
  	return parseContext(self, lines, font, "ContextSubst", lookupMap=lookupMap)
  def parseContextPos(self, lines, font, lookupMap=None):
  	return parseContext(self, lines, font, "ContextPos", lookupMap=lookupMap)
  def parseChainedSubst(self, lines, font, lookupMap=None):
  	return parseContext(self, lines, font, "ChainContextSubst", lookupMap=lookupMap)
  def parseChainedPos(self, lines, font, lookupMap=None):
  	return parseContext(self, lines, font, "ChainContextPos", lookupMap=lookupMap)
  
  def parseReverseChainedSubst(self, lines, font, _lookupMap=None):
  	self.Format = 1
  	coverages = ([], [])
  	while lines.peek()[0].endswith("coverage definition begin"):
  		typ = lines.peek()[0][:-len("coverage definition begin")].lower()
  		idx,klass = {
  			'backtrack':	(0,ot.BacktrackCoverage),
  			'lookahead':	(1,ot.LookAheadCoverage),
  		}[typ]
  		coverages[idx].append(parseCoverage(lines, font, klass=klass))
  	self.BacktrackCoverage = coverages[0]
  	self.BacktrackGlyphCount = len(self.BacktrackCoverage)
  	self.LookAheadCoverage = coverages[1]
  	self.LookAheadGlyphCount = len(self.LookAheadCoverage)
  	mapping = {}
  	for line in lines:
  		assert len(line) == 2, line
  		line = makeGlyphs(line)
  		mapping[line[0]] = line[1]
  	self.Coverage = makeCoverage(mapping.keys(), font)
  	self.Substitute = [mapping[k] for k in self.Coverage.glyphs]
  	self.GlyphCount = len(self.Substitute)
  
  def parseLookup(lines, tableTag, font, lookupMap=None):
  	line = lines.expect('lookup')
  	_, name, typ = line
  	log.debug("Parsing lookup type %s %s", typ, name)
  	lookup = ot.Lookup()
  	with lines.until('lookup end'):
  
  		lookup.LookupFlag,filterset = parseLookupFlags(lines)
  		if filterset is not None:
  			lookup.MarkFilteringSet = filterset
  		lookup.LookupType, parseLookupSubTable = {
  			'GSUB': {
  				'single':	(0,	parseSingleSubst),
  				'multiple':	(0,	parseMultiple),
  				'alternate':	(0,	parseAlternate),
  				'ligature':	(0,	parseLigature),
  				'context':	(5,	parseContextSubst),
  				'chained':	(6,	parseChainedSubst),
  				'reversechained':(8,	parseReverseChainedSubst),
  			},
  			'GPOS': {
  				'single':	(0,	parseSinglePos),
  				'pair':		(2,	parsePair),
  				'kernset':	(2,	parseKernset),
  				'cursive':	(0,	parseCursive),
  				'mark to base':	(4,	parseMarkToBase),
  				'mark to ligature':(5,	parseMarkToLigature),
  				'mark to mark':	(6,	parseMarkToMark),
  				'context':	(7,	parseContextPos),
  				'chained':	(8,	parseChainedPos),
  			},
  		}[tableTag][typ]
  
  		subtables = []
  
  		while lines.peek():
  			with lines.until(('% subtable', 'subtable end')):
  				while lines.peek():
  					if lookup.LookupType is 0:
  						subtable = parseLookupSubTable(lines, font, lookupMap)
  						lookup.LookupType = subtable.LookupType
  					else:
  						subtable = ot.lookupTypes[tableTag][lookup.LookupType]()
  						parseLookupSubTable(subtable, lines, font, lookupMap)
  					subtables.append(subtable)
  			if lines.peek() and lines.peek()[0] in ('% subtable', 'subtable end'):
  				next(lines)
  	lines.expect('lookup end')
  
  	lookup.SubTable = subtables
  	lookup.SubTableCount = len(lookup.SubTable)
  	if lookup.SubTableCount is 0:
  		return None
  	return lookup
  
  def parseGSUBGPOS(lines, font, tableTag):
  	container = ttLib.getTableClass(tableTag)()
  	lookupMap = DeferredMapping()
  	featureMap = DeferredMapping()
  	assert tableTag in ('GSUB', 'GPOS')
  	log.debug("Parsing %s", tableTag)
  	self = getattr(ot, tableTag)()
  	self.Version = 1.0
  	fields = {
  		'script table begin':
  		('ScriptList',
  		 lambda lines: parseScriptList (lines, featureMap)),
  		'feature table begin':
  		('FeatureList',
  		 lambda lines: parseFeatureList (lines, lookupMap, featureMap)),
  		'lookup':
  		('LookupList',
  		 None),
  	}
  	for attr,parser in fields.values():
  		setattr(self, attr, None)
  	while lines.peek() is not None:
  		typ = lines.peek()[0].lower()
  		if typ not in fields:
  			log.debug('Skipping %s', lines.peek())
  			next(lines)
  			continue
  		attr,parser = fields[typ]
  		if typ == 'lookup':
  			if self.LookupList is None:
  				self.LookupList = ot.LookupList()
  				self.LookupList.Lookup = []
  			_, name, _ = lines.peek()
  			lookup = parseLookup(lines, tableTag, font, lookupMap)
  			if lookupMap is not None:
  				assert name not in lookupMap, "Duplicate lookup name: %s" % name
  				lookupMap[name] = len(self.LookupList.Lookup)
  			else:
  				assert int(name) == len(self.LookupList.Lookup), "%d %d" % (name, len(self.Lookup))
  			self.LookupList.Lookup.append(lookup)
  		else:
  			assert getattr(self, attr) is None, attr
  			setattr(self, attr, parser(lines))
  	if self.LookupList:
  		self.LookupList.LookupCount = len(self.LookupList.Lookup)
  	if lookupMap is not None:
  		lookupMap.applyDeferredMappings()
  	if featureMap is not None:
  		featureMap.applyDeferredMappings()
  	container.table = self
  	return container
  
  def parseGSUB(lines, font):
  	return parseGSUBGPOS(lines, font, 'GSUB')
  def parseGPOS(lines, font):
  	return parseGSUBGPOS(lines, font, 'GPOS')
  
  def parseAttachList(lines, font):
  	points = {}
  	with lines.between('attachment list'):
  		for line in lines:
  			glyph = makeGlyph(line[0])
  			assert glyph not in points, glyph
  			points[glyph] = [int(i) for i in line[1:]]
  	return otl.buildAttachList(points, font.getReverseGlyphMap())
  
  def parseCaretList(lines, font):
  	carets = {}
  	with lines.between('carets'):
  		for line in lines:
  			glyph = makeGlyph(line[0])
  			assert glyph not in carets, glyph
  			num = int(line[1])
  			thisCarets = [int(i) for i in line[2:]]
  			assert num == len(thisCarets), line
  			carets[glyph] = thisCarets
  	return otl.buildLigCaretList(carets, {}, font.getReverseGlyphMap())
  
  def makeMarkFilteringSets(sets, font):
  	self = ot.MarkGlyphSetsDef()
  	self.MarkSetTableFormat = 1
  	self.MarkSetCount = 1 + max(sets.keys())
  	self.Coverage = [None] * self.MarkSetCount
  	for k,v in sets.items():
  		self.Coverage[k] = makeCoverage(v, font)
  	return self
  
  def parseMarkFilteringSets(lines, font):
  	sets = {}
  	with lines.between('set definition'):
  		for line in lines:
  			assert len(line) == 2, line
  			glyph = makeGlyph(line[0])
  			# TODO accept set names
  			st = int(line[1])
  			if st not in sets:
  				sets[st] = []
  			sets[st].append(glyph)
  	return makeMarkFilteringSets(sets, font)
  
  def parseGDEF(lines, font):
  	container = ttLib.getTableClass('GDEF')()
  	log.debug("Parsing GDEF")
  	self = ot.GDEF()
  	fields = {
  		'class definition begin':
  			('GlyphClassDef',
  			 lambda lines, font: parseClassDef(lines, klass=ot.GlyphClassDef)),
  		'attachment list begin':
  			('AttachList', parseAttachList),
  		'carets begin':
  			('LigCaretList', parseCaretList),
  		'mark attachment class definition begin':
  			('MarkAttachClassDef',
  			 lambda lines, font: parseClassDef(lines, klass=ot.MarkAttachClassDef)),
  		'markfilter set definition begin':
  			('MarkGlyphSetsDef', parseMarkFilteringSets),
  	}
  	for attr,parser in fields.values():
  		setattr(self, attr, None)
  	while lines.peek() is not None:
  		typ = lines.peek()[0].lower()
  		if typ not in fields:
  			log.debug('Skipping %s', typ)
  			next(lines)
  			continue
  		attr,parser = fields[typ]
  		assert getattr(self, attr) is None, attr
  		setattr(self, attr, parser(lines, font))
  	self.Version = 1.0 if self.MarkGlyphSetsDef is None else 0x00010002
  	container.table = self
  	return container
  
  def parseCmap(lines, font):
  	container = ttLib.getTableClass('cmap')()
  	log.debug("Parsing cmap")
  	tables = []
  	while lines.peek() is not None:
  		lines.expect('cmap subtable %d' % len(tables))
  		platId, encId, fmt, lang = [
  			parseCmapId(lines, field)
  			for field in ('platformID', 'encodingID', 'format', 'language')]
  		table = cmap_classes[fmt](fmt)
  		table.platformID = platId
  		table.platEncID = encId
  		table.language = lang
  		table.cmap = {}
  		line = next(lines)
  		while line[0] != 'end subtable':
  			table.cmap[int(line[0], 16)] = line[1]
  			line = next(lines)
  		tables.append(table)
  	container.tableVersion = 0
  	container.tables = tables
  	return container
  
  def parseCmapId(lines, field):
  	line = next(lines)
  	assert field == line[0]
  	return int(line[1])
  
  def parseTable(lines, font, tableTag=None):
  	log.debug("Parsing table")
  	line = lines.peek()
  	tag = None
  	if line[0].split()[0] == 'FontDame':
  		tag = line[0].split()[1]
  	elif ' '.join(line[0].split()[:3]) == 'Font Chef Table':
  		tag = line[0].split()[3]
  	if tag is not None:
  		next(lines)
  		tag = tag.ljust(4)
  		if tableTag is None:
  			tableTag = tag
  		else:
  			assert tableTag == tag, (tableTag, tag)
  
  	assert tableTag is not None, "Don't know what table to parse and data doesn't specify"
  
  	return {
  		'GSUB': parseGSUB,
  		'GPOS': parseGPOS,
  		'GDEF': parseGDEF,
  		'cmap': parseCmap,
  		}[tableTag](lines, font)
  
  class Tokenizer(object):
  
  	def __init__(self, f):
  		# TODO BytesIO / StringIO as needed?  also, figure out whether we work on bytes or unicode
  		lines = iter(f)
  		try:
  			self.filename = f.name
  		except:
  			self.filename = None
  		self.lines = iter(lines)
  		self.line = ''
  		self.lineno = 0
  		self.stoppers = []
  		self.buffer = None
  
  	def __iter__(self):
  		return self
  
  	def _next_line(self):
  		self.lineno += 1
  		line = self.line = next(self.lines)
  		line = [s.strip() for s in line.split('\t')]
  		if len(line) == 1 and not line[0]:
  			del line[0]
  		if line and not line[-1]:
  			warnings.warn('trailing tab found on line %d: %s' % (self.lineno, self.line))
  			while line and not line[-1]:
  				del line[-1]
  		return line
  
  	def _next_nonempty(self):
  		while True:
  			line = self._next_line()
  			# Skip comments and empty lines
  			if line and line[0] and (line[0][0] != '%' or line[0] == '% subtable'):
  				return line
  
  	def _next_buffered(self):
  		if self.buffer:
  			ret = self.buffer
  			self.buffer = None
  			return ret
  		else:
  			return self._next_nonempty()
  
  	def __next__(self):
  		line = self._next_buffered()
  		if line[0].lower() in self.stoppers:
  			self.buffer = line
  			raise StopIteration
  		return line
  
  	def next(self):
  		return self.__next__()
  
  	def peek(self):
  		if not self.buffer:
  			try:
  				self.buffer = self._next_nonempty()
  			except StopIteration:
  				return None
  		if self.buffer[0].lower() in self.stoppers:
  			return None
  		return self.buffer
  
  	@contextmanager
  	def between(self, tag):
  		start = tag + ' begin'
  		end = tag + ' end'
  		self.expectendswith(start)
  		self.stoppers.append(end)
  		yield
  		del self.stoppers[-1]
  		self.expect(tag + ' end')
  
  	@contextmanager
  	def until(self, tags):
  		if type(tags) is not tuple:
  			tags = (tags,)
  		self.stoppers.extend(tags)
  		yield
  		del self.stoppers[-len(tags):]
  
  	def expect(self, s):
  		line = next(self)
  		tag = line[0].lower()
  		assert tag == s, "Expected '%s', got '%s'" % (s, tag)
  		return line
  
  	def expectendswith(self, s):
  		line = next(self)
  		tag = line[0].lower()
  		assert tag.endswith(s), "Expected '*%s', got '%s'" % (s, tag)
  		return line
  
  def build(f, font, tableTag=None):
  	lines = Tokenizer(f)
  	return parseTable(lines, font, tableTag=tableTag)
  
  
  class MockFont(object):
  
  	def __init__(self):
  		self._glyphOrder = ['.notdef']
  		class AllocatingDict(dict):
  			def __missing__(reverseDict, key):
  				self._glyphOrder.append(key)
  				gid = len(reverseDict)
  				reverseDict[key] = gid
  				return gid
  		self._reverseGlyphOrder = AllocatingDict({'.notdef': 0})
  		self.lazy = False
  
  	def getGlyphID(self, glyph, requireReal=None):
  		gid = self._reverseGlyphOrder[glyph]
  		return gid
  
  	def getReverseGlyphMap(self):
  		return self._reverseGlyphOrder
  
  	def getGlyphName(self, gid):
  		return self._glyphOrder[gid]
  
  	def getGlyphOrder(self):
  		return self._glyphOrder
  
  def main(args):
  	from fontTools import configLogger
  	# configure the library logger (for >= WARNING)
  	configLogger()
  	# comment this out to enable debug messages from mtiLib's logger
  	# log.setLevel(logging.DEBUG)
  	font = MockFont()
  	tableTag = None
  	if args[0].startswith('-t'):
  		tableTag = args[0][2:]
  		del args[0]
  	for f in args:
  		log.debug("Processing %s", f)
  		table = build(open(f, 'rt', encoding="utf-8"), font, tableTag=tableTag)
  		blob = table.compile(font) # Make sure it compiles
  		decompiled = table.__class__()
  		decompiled.decompile(blob, font) # Make sure it decompiles!
  
  		#continue
  		from fontTools.misc import xmlWriter
  		tag = table.tableTag
  		writer = xmlWriter.XMLWriter(sys.stdout)
  		writer.begintag(tag)
  		writer.newline()
  		table.toXML(writer, font)
  		#decompiled.toXML(writer, font)
  		writer.endtag(tag)
  		writer.newline()
  
  if __name__ == '__main__':
  	import sys
  	main (sys.argv[1:])
  