Misc patches from rroberts:

fontTools/ttx.py
  # support virtual GIDs, support handling some GSUB offset overflows.

fontTools/ttlib/__init__.py
# 1) make getReverseGlyphMap  a public function; I find a reverse map
to often be useful
# 2) support virtual glyphs, e.g. references to GID's that are not in the font.
# Added the TTFont argument allowVID (default 0) to turn this off and on;
# added the arg requireReal ( default 0) so as to get the obvious
default behaviour when
# allowVID is 0 or 1, but to allow requiring a true GID when allowVID is 1.

fontTools/ttlib/tables/otBase.py
fontTools/ttlib/tables/otConverters.py
fontTools/ttlib/tables/otData.py
fontTools/ttlib/tables/otTables.py
# 1) speed optimization
# - collapse for loops
# - do not decompile extension lookups until a record is requested
from within the lookup.
# 2) handling offset overflows
# 3) support of extension lookups
# 4) Fixed FetauresParam converter class def so as to survive a font
that has this offset non-NULL.
# This fixes a stack dump.
# The data will now just get ignored


git-svn-id: svn://svn.code.sf.net/p/fonttools/code/trunk@511 4cde692c-a291-49d1-8350-778aa11640f8
diff --git a/Lib/fontTools/ttLib/tables/otBase.py b/Lib/fontTools/ttLib/tables/otBase.py
index 70884c9..e420329 100644
--- a/Lib/fontTools/ttLib/tables/otBase.py
+++ b/Lib/fontTools/ttLib/tables/otBase.py
@@ -3,6 +3,24 @@
 import struct
 from types import TupleType
 
+class OverflowErrorRecord:
+	def __init__(self, overflowTuple):
+		self.tableType = overflowTuple[0]
+		self.LookupListIndex = overflowTuple[1]
+		self.SubTableIndex = overflowTuple[2]
+		self.itemName = overflowTuple[3]
+		self.itemIndex = overflowTuple[4]
+
+	def __repr__(self):
+		return str((self.tableType, "LookupIndex:", self.LookupListIndex, "SubTableIndex:", self.SubTableIndex, "ItemName:", self.itemName, "ItemIndex:", self.itemIndex))
+
+class OTLOffsetOverflowError(Exception):
+	def __init__(self, overflowErrorRecord):
+		self.value = overflowErrorRecord
+
+	def __str__(self):
+		return repr(self.value)
+
 
 class BaseTTXConverter(DefaultTable):
 	
@@ -30,10 +48,31 @@
 			print "---", len(stats)
 	
 	def compile(self, font):
+		""" Create a top-level OTFWriter for the GPOS/GSUB table.
+			Call the compile method for the the table
+				for each 'convertor' record in the table convertor list
+					call convertor's write method for each item in the value. 
+						- For simple items, the write method adds a string to the
+						writer's self.items list. 
+						- For Struct/Table/Subtabl items, it add first adds new writer to the 
+						to the writer's self.items, then calls the item's compile method.
+						This creates a tree of writers, rooted at the GUSB/GPOS writer, with
+						each writer representing a table, and the writer.items list containing
+						the child data strings and writers.
+			call the GetAllData method
+				call _doneWriting, which removes duplicates
+				call _GetTables. This traverses the tables, adding unique occurences to a flat list of tables
+				Traverse the flat list of tables, calling GetDataLength on each to update their position
+				Traverse the flat list of tables again, calling GetData each get the data in the table, now that
+				pas's and offset are known.
+
+				If a lookup subtable overflows an offset, we have to start all over. 
+		"""
 		writer = OTTableWriter(self.tableTag)
+		writer.parent = None
 		self.table.compile(writer, font)
 		return writer.getAllData()
-	
+
 	def toXML(self, writer, font):
 		self.table.toXML2(writer, font)
 	
@@ -92,6 +131,13 @@
 		self.pos = newpos
 		return value
 	
+	def readULong(self):
+		pos = self.pos
+		newpos = pos + 4
+		value, = struct.unpack(">L", self.data[pos:newpos])
+		self.pos = newpos
+		return value
+	
 	def readTag(self):
 		pos = self.pos
 		newpos = pos + 4
@@ -135,29 +181,45 @@
 	def getAllData(self):
 		"""Assemble all data, including all subtables."""
 		self._doneWriting()
-		tables = self._gatherTables()
+		tables, extTables = self._gatherTables()
 		tables.reverse()
-		
+		extTables.reverse()
 		# Gather all data in two passes: the absolute positions of all
 		# subtable are needed before the actual data can be assembled.
 		pos = 0
 		for table in tables:
 			table.pos = pos
 			pos = pos + table.getDataLength()
-		
+
+		for table in extTables:
+			table.pos = pos
+			pos = pos + table.getDataLength()
+
+
 		data = []
 		for table in tables:
 			tableData = table.getData()
 			data.append(tableData)
-		
+
+		for table in extTables:
+			tableData = table.getData()
+			data.append(tableData)
+
 		return "".join(data)
 	
 	def getDataLength(self):
 		"""Return the length of this table in bytes, without subtables."""
 		l = 0
+		if hasattr(self, "Extension"):
+			longOffset = 1
+		else:
+			longOffset = 0
 		for item in self.items:
 			if hasattr(item, "getData") or hasattr(item, "getCountData"):
-				l = l + 2  # sizeof(UShort)
+				if longOffset:
+					l = l + 4  # sizeof(ULong)
+				else:
+					l = l + 2  # sizeof(UShort)
 			else:
 				l = l + len(item)
 		return l
@@ -165,10 +227,60 @@
 	def getData(self):
 		"""Assemble the data for this writer/table, without subtables."""
 		items = list(self.items)  # make a shallow copy
-		for i in range(len(items)):
+		if hasattr(self,"Extension"):
+			longOffset = 1
+		else:
+			longOffset = 0
+		pos = self.pos
+		numItems = len(items)
+		for i in range(numItems):
 			item = items[i]
+			
 			if hasattr(item, "getData"):
-				items[i] = packUShort(item.pos - self.pos)
+				if longOffset:
+					items[i] = packULong(item.pos - pos)
+				else:
+					try:
+						items[i] = packUShort(item.pos - pos)
+					except AssertionError:
+						# provide data to fix overflow problem.
+						# If the overflow is to a lookup, or from a lookup to a subtable, 
+						# just report the current item.
+						if self.name in [ 'LookupList', 'Lookup']:
+							overflowErrorRecord = self.getOverflowErrorRecord(item)
+						else:
+							# overflow is within a subTable. Life is more complicated.
+							# If we split the sub-table just before the current item, we may still suffer overflow.
+							# This is because duplicate table merging is done only within an Extension subTable tree;
+							# when we split the subtable in two, some items may no longer be duplicates. 
+							# Get worst case by adding up all the item lengths, depth first traversal.
+							# and then report the first item that overflows a short.
+							def getDeepItemLength(table):
+								if hasattr(table, "getDataLength"):
+									length = 0
+									for item in table.items:
+										length = length + getDeepItemLength(item)
+								else:
+									length = len(table)
+								return length
+	
+							length = self.getDataLength()
+							if hasattr(self, "sortCoverageLast") and item.name == "Coverage":
+								# Coverage is first in the item list, but last in the table list,
+								# The original overflow is really in the item list. Skip the Coverage 
+								# table in the following test.
+								items = items[i+1:]
+	
+							for j in range(len(items)):
+								item = items[j]
+								length = length + getDeepItemLength(item)
+								if length > 65535:
+									break
+						overflowErrorRecord = self.getOverflowErrorRecord(item)
+						
+						
+						raise OTLOffsetOverflowError, overflowErrorRecord
+
 		return "".join(items)
 	
 	def __hash__(self):
@@ -182,38 +294,109 @@
 			return cmp(id(self), id(other))
 	
 	def _doneWriting(self, internedTables=None):
+		# Convert CountData references to data string items
+		# collapse duplicate table references to a unique entry
+		# "tables" are OTTableWriter objects.
+
+		# For Extension Lookup types, we can
+		# eliminate duplicates only within the tree under the Extension Lookup,
+		# as offsets may exceed 64K even between Extension LookupTable subtables.
 		if internedTables is None:
 			internedTables = {}
 		items = self.items
-		for i in range(len(items)):
+		iRange = range(len(items))
+		
+		if hasattr(self, "Extension"):
+			newTree = 1
+		else:
+			newTree = 0
+		for i in iRange:
 			item = items[i]
 			if hasattr(item, "getCountData"):
 				items[i] = item.getCountData()
 			elif hasattr(item, "getData"):
-				item._doneWriting(internedTables)
-				if internedTables.has_key(item):
-					items[i] = item = internedTables[item]
+				if newTree:
+					item._doneWriting()
 				else:
-					internedTables[item] = item
+					item._doneWriting(internedTables)
+					if internedTables.has_key(item):
+						items[i] = item = internedTables[item]
+					else:
+						internedTables[item] = item
 		self.items = tuple(items)
 	
-	def _gatherTables(self, tables=None, done=None):
-		if tables is None:
+	def _gatherTables(self, tables=None, extTables=None, done=None):
+		# Convert table references in self.items tree to a flat
+		# list of tables in depth-first traversal order.
+		# "tables" are OTTableWriter objects.
+		# We do the traversal in reverse order at each level, in order to 
+		# resolve duplicate references to be the last reference in the list of tables.
+		# For extension lookups, duplicate references can be merged only within the
+		# writer tree under the  extension lookup.
+		if tables is None: # init call for first time.
 			tables = []
+			extTables = []
 			done = {}
-		for item in self.items:
+
+		done[self] = 1
+
+		numItems = len(self.items)
+		iRange = range(numItems)
+		iRange.reverse()
+
+		if hasattr(self, "Extension"):
+			appendExtensions = 1
+		else:
+			appendExtensions = 0
+
+		# add Coverage table if it is sorted last.
+		sortCoverageLast = 0
+		if hasattr(self, "sortCoverageLast"):
+			# Find coverage table
+			for i in range(numItems):
+				item = self.items[i]
+				if hasattr(item, "name") and (item.name == "Coverage"):
+					sortCoverageLast = 1
+					break
+			if not done.has_key(item):
+				item._gatherTables(tables, extTables, done)
+			else:
+				index = max(item.parent.keys())
+				item.parent[index + 1] = self
+
+		saveItem = None
+		for i in iRange:
+			item = self.items[i]
 			if not hasattr(item, "getData"):
 				continue
-			if not done.has_key(item):
-				item._gatherTables(tables, done)
-		done[self] = 1
+
+			if sortCoverageLast and (i==1) and item.name == 'Coverage':
+				# we've already 'gathered' it above
+				continue
+
+			if appendExtensions:
+				assert extTables != None, "Program or XML editing error. Extension subtables cannot contain extensions subtables"
+				newDone = {}
+				item._gatherTables(extTables, None, newDone)
+
+			elif not done.has_key(item):
+				item._gatherTables(tables, extTables, done)
+			else:
+				index = max(item.parent.keys())
+				item.parent[index + 1] = self
+
+
 		tables.append(self)
-		return tables
+		return tables, extTables
 	
 	# interface for gathering data, as used by table.compile()
 	
 	def getSubWriter(self):
-		return self.__class__(self.tableType, self.valueFormat)
+		subwriter = self.__class__(self.tableType, self.valueFormat)
+		subwriter.parent = {0:self} # because some subtables have idential values, we discard
+									# the duplicates under the getAllData method. Hence some
+									# subtable writers can have more than one parent writer.
+		return subwriter
 	
 	def writeUShort(self, value):
 		assert 0 <= value < 0x10000
@@ -225,6 +408,9 @@
 	def writeLong(self, value):
 		self.items.append(struct.pack(">l", value))
 	
+	def writeULong(self, value):
+		self.items.append(struct.pack(">L", value))
+	
 	def writeTag(self, tag):
 		assert len(tag) == 4
 		self.items.append(tag)
@@ -239,12 +425,48 @@
 		data = apply(struct.pack, (format,) + values)
 		self.items.append(data)
 	
+	def writeData(self, data):
+		self.items.append(data)
+	
 	def setValueFormat(self, format, which):
 		self.valueFormat[which].setFormat(format)
 	
 	def writeValueRecord(self, value, font, which):
 		return self.valueFormat[which].writeValueRecord(self, font, value)
 
+	def	getOverflowErrorRecord(self, item):
+		LookupListIndex = SubTableIndex = itemName = itemIndex = None
+		if self.name == 'LookupList':
+			LookupListIndex = item.repeatIndex
+		elif self.name == 'Lookup':
+			LookupListIndex = self.repeatIndex
+			SubTableIndex = item.repeatIndex
+		else:
+			itemName = item.name
+			if hasattr(item, 'repeatIndex'):
+				itemIndex = item.repeatIndex
+			if self.name == 'SubTable':
+				LookupListIndex = self.parent[0].repeatIndex
+				SubTableIndex = self.repeatIndex
+			elif self.name == 'ExtSubTable':
+				LookupListIndex = self.parent[0].parent[0].repeatIndex
+				SubTableIndex = self.parent[0].repeatIndex
+			else: # who knows how far below the SubTable level we are! Climb back up to the nearest subtable.
+				itemName = ".".join(self.name, item.name)
+				p1 = self.parent[0]
+				while p1 and p1.name not in ['ExtSubTable', 'SubTable']:
+					itemName = ".".join(p1.name, item.name)
+					p1 = p1.parent[0]
+				if p1:
+					if p1.name == 'ExtSubTable':
+						LookupListIndex = self.parent[0].parent[0].repeatIndex
+						SubTableIndex = self.parent[0].repeatIndex
+					else:
+						LookupListIndex = self.parent[0].repeatIndex
+						SubTableIndex = self.repeatIndex
+
+		return OverflowErrorRecord( (self.tableType, LookupListIndex, SubTableIndex, itemName, itemIndex) )
+
 
 class CountReference:
 	"""A reference to a Count value, not a count of references."""
@@ -260,6 +482,11 @@
 	return struct.pack(">H", value)
 
 
+def packULong(value):
+	assert 0 <= value < 0x1000000000, value
+	return struct.pack(">L", value)
+
+
 
 class TableStack:
 	"""A stack of table dicts, working as a stack of namespaces so we can
@@ -288,7 +515,38 @@
 
 
 class BaseTable:
+	def __init__(self):
+		self.compileStatus = 0 # 0 means table was created
+									# 1 means the table.read() function was called by a table which is subject
+									# to delayed compilation
+									# 2 means that it was subject to delayed compilation, and 
+									# has been decompiled
+									# 3 means that the start and end fields have been filled out, and that we
+									# can use the data string rather than compiling from the table data.
+
+		self.recurse = 0
 	
+	def __getattr__(self, attr):
+		# we get here only when the table does not have the attribute.
+		# This method ovveride exists so that we can try to de-compile
+		# a table which is subject to delayed decompilation, and then try
+		# to get the value again after decompilation.
+		self.recurse +=1
+		if self.recurse > 2:
+			# shouldn't ever get here - we should only get to two levels of recursion.
+			# this guards against self.decompile NOT setting compileStatus to other than 1.
+			raise AttributeError, attr 
+		if self.compileStatus == 1:
+			# table.read() has been called, but table has not yet been decompiled
+			# This happens only for extension tables.
+			self.decompile(self.reader, self.font)
+			val = getattr(self, attr)
+			self.recurse -=1
+			return val
+			
+		raise AttributeError, attr 
+
+
 	"""Generic base class for all OpenType (sub)tables."""
 	
 	def getConverters(self):
@@ -298,6 +556,7 @@
 		return self.convertersByName[name]
 	
 	def decompile(self, reader, font, tableStack=None):
+		self.compileStatus = 2 # table has been decompiled.
 		if tableStack is None:
 			tableStack = TableStack()
 		self.readFormat(reader)
@@ -308,6 +567,9 @@
 			if conv.name == "SubTable":
 				conv = conv.getConverter(reader.tableType,
 						table["LookupType"])
+			if conv.name == "ExtSubTable":
+				conv = conv.getConverter(reader.tableType,
+						table["ExtensionLookupType"])
 			if conv.repeat:
 				l = []
 				for i in range(tableStack.getValue(conv.repeat) + conv.repeatOffset):
@@ -318,11 +580,18 @@
 		tableStack.pop()
 		self.postRead(table, font)
 		del self.__rawTable  # succeeded, get rid of debugging info
-	
+
+	def preCompile(self):
+		pass # used only by the LookupList class
+
 	def compile(self, writer, font, tableStack=None):
 		if tableStack is None:
 			tableStack = TableStack()
 		table = self.preWrite(font)
+
+		if hasattr(self, 'sortCoverageLast'):
+			writer.sortCoverageLast = 1
+
 		self.writeFormat(writer)
 		tableStack.push(table)
 		for conv in self.getConverters():
@@ -331,8 +600,8 @@
 				if value is None:
 					value = []
 				tableStack.storeValue(conv.repeat, len(value) - conv.repeatOffset)
-				for item in value:
-					conv.write(writer, font, tableStack, item)
+				for i in range(len(value)):
+					conv.write(writer, font, tableStack, value[i], i)
 			elif conv.isCount:
 				# Special-case Count values.
 				# Assumption: a Count field will *always* precede
@@ -389,7 +658,6 @@
 		try:
 			conv = self.getConverterByName(name)
 		except KeyError:
-##			print self, name, attrs, content
 			raise    # XXX on KeyError, raise nice error
 		value = conv.xmlRead(attrs, content, font)
 		if conv.repeat:
diff --git a/Lib/fontTools/ttLib/tables/otConverters.py b/Lib/fontTools/ttLib/tables/otConverters.py
index 10cc02e..4d4739b 100644
--- a/Lib/fontTools/ttLib/tables/otConverters.py
+++ b/Lib/fontTools/ttLib/tables/otConverters.py
@@ -20,16 +20,18 @@
 			converterClass = Count
 		elif name == "SubTable":
 			converterClass = SubTable
+		elif name == "ExtSubTable":
+			converterClass = ExtSubTable
 		else:
 			converterClass = converterMapping[tp]
 		tableClass = tableNamespace.get(name)
 		conv = converterClass(name, repeat, repeatOffset, tableClass)
-		if name == "SubTable":
+		if name in ["SubTable", "ExtSubTable"]:
 			conv.lookupTypes = tableNamespace['lookupTypes']
 			# also create reverse mapping
 			for t in conv.lookupTypes.values():
 				for cls in t.values():
-					convertersByName[cls.__name__] = Table("SubTable", repeat, repeatOffset, cls)
+					convertersByName[cls.__name__] = Table(name, repeat, repeatOffset, cls)
 		converters.append(conv)
 		assert not convertersByName.has_key(name)
 		convertersByName[name] = conv
@@ -52,7 +54,7 @@
 		"""Read a value from the reader."""
 		raise NotImplementedError, self
 	
-	def write(self, writer, font, tableStack, value):
+	def write(self, writer, font, tableStack, value, repeatIndex=None):
 		"""Write a value to the writer."""
 		raise NotImplementedError, self
 	
@@ -79,13 +81,13 @@
 class Long(IntValue):
 	def read(self, reader, font, tableStack):
 		return reader.readLong()
-	def write(self, writer, font, tableStack, value):
+	def write(self, writer, font, tableStack, value, repeatIndex=None):
 		writer.writeLong(value)
 
 class Fixed(IntValue):
 	def read(self, reader, font, tableStack):
 		return float(reader.readLong()) / 0x10000
-	def write(self, writer, font, tableStack, value):
+	def write(self, writer, font, tableStack, value, repeatIndex=None):
 		writer.writeLong(int(round(value * 0x10000)))
 	def xmlRead(self, attrs, content, font):
 		return float(attrs["value"])
@@ -93,13 +95,13 @@
 class Short(IntValue):
 	def read(self, reader, font, tableStack):
 		return reader.readShort()
-	def write(self, writer, font, tableStack, value):
+	def write(self, writer, font, tableStack, value, repeatIndex=None):
 		writer.writeShort(value)
 
 class UShort(IntValue):
 	def read(self, reader, font, tableStack):
 		return reader.readUShort()
-	def write(self, writer, font, tableStack, value):
+	def write(self, writer, font, tableStack, value, repeatIndex=None):
 		writer.writeUShort(value)
 
 class Count(Short):
@@ -110,14 +112,18 @@
 class Tag(SimpleValue):
 	def read(self, reader, font, tableStack):
 		return reader.readTag()
-	def write(self, writer, font, tableStack, value):
+	def write(self, writer, font, tableStack, value, repeatIndex=None):
 		writer.writeTag(value)
 
 class GlyphID(SimpleValue):
 	def read(self, reader, font, tableStack):
-		return font.getGlyphName(reader.readUShort())
-	def write(self, writer, font, tableStack, value):
-		writer.writeUShort(font.getGlyphID(value))
+		value = reader.readUShort()
+		value =  font.getGlyphName(value)
+		return value
+
+	def write(self, writer, font, tableStack, value, repeatIndex=None):
+		value =  font.getGlyphID(value)
+		writer.writeUShort(value)
 
 
 class Struct(BaseConverter):
@@ -127,7 +133,7 @@
 		table.decompile(reader, font, tableStack)
 		return table
 	
-	def write(self, writer, font, tableStack, value):
+	def write(self, writer, font, tableStack, value, repeatIndex=None):
 		value.compile(writer, font, tableStack)
 	
 	def xmlWrite(self, xmlWriter, font, value, name, attrs):
@@ -166,20 +172,61 @@
 		table.decompile(subReader, font, tableStack)
 		return table
 	
-	def write(self, writer, font, tableStack, value):
+	def write(self, writer, font, tableStack, value, repeatIndex=None):
 		if value is None:
 			writer.writeUShort(0)
 		else:
 			subWriter = writer.getSubWriter()
+			subWriter.name = self.name
+			if repeatIndex is not None:
+				subWriter.repeatIndex = repeatIndex
+			value.preCompile()
 			writer.writeSubTable(subWriter)
 			value.compile(subWriter, font, tableStack)
 
-
 class SubTable(Table):
 	def getConverter(self, tableType, lookupType):
 		lookupTypes = self.lookupTypes[tableType]
 		tableClass = lookupTypes[lookupType]
-		return Table(self.name, self.repeat, self.repeatOffset, tableClass)
+		return SubTable(self.name, self.repeat, self.repeatOffset, tableClass)
+
+
+class ExtSubTable(Table):
+	def getConverter(self, tableType, lookupType):
+		lookupTypes = self.lookupTypes[tableType]
+		tableClass = lookupTypes[lookupType]
+		return ExtSubTable(self.name, self.repeat, self.repeatOffset, tableClass)
+	
+	def read(self, reader, font, tableStack):
+		offset = reader.readULong()
+		if offset == 0:
+			return None
+		subReader = reader.getSubReader(offset)
+		table = self.tableClass()
+		table.reader = subReader
+		table.font = font
+		table.compileStatus = 1
+		table.start = table.reader.offset
+		return table
+	
+	def write(self, writer, font, tableStack, value, repeatIndex=None):
+		writer.Extension = 1 # actually, mere presence of the field flags it as an Ext Subtable writer.
+		if value is None:
+			writer.writeULong(0)
+		else:
+			# If the subtable has not yet been decompiled, we need to do so.
+			if  value.compileStatus == 1:
+				value.decompile(value.reader, value.font, tableStack)
+ 			subWriter = writer.getSubWriter()
+			subWriter.name = self.name
+			writer.writeSubTable(subWriter)
+			# If the subtable has been sorted and we can just write the original
+			# data, then do so.
+			if value.compileStatus == 3:
+				data = value.reader.data[value.start:value.end]
+				subWriter.writeData(data)
+			else:
+				value.compile(subWriter, font, tableStack)
 
 
 class ValueFormat(IntValue):
@@ -190,7 +237,7 @@
 		format = reader.readUShort()
 		reader.setValueFormat(format, self.which)
 		return format
-	def write(self, writer, font, tableStack, format):
+	def write(self, writer, font, tableStack, format, repeatIndex=None):
 		writer.writeUShort(format)
 		writer.setValueFormat(format, self.which)
 
@@ -198,7 +245,7 @@
 class ValueRecord(ValueFormat):
 	def read(self, reader, font, tableStack):
 		return reader.readValueRecord(font, self.which)
-	def write(self, writer, font, tableStack, value):
+	def write(self, writer, font, tableStack, value, repeatIndex=None):
 		writer.writeValueRecord(value, font, self.which)
 	def xmlWrite(self, xmlWriter, font, value, name, attrs):
 		if value is None:
@@ -238,7 +285,7 @@
 			DeltaValue.append(value)
 		return DeltaValue
 	
-	def write(self, writer, font, tableStack, value):
+	def write(self, writer, font, tableStack, value, repeatIndex=None):
 		table = tableStack.getTop()
 		StartSize = table["StartSize"]
 		EndSize = table["EndSize"]
@@ -279,6 +326,7 @@
 	"GlyphID":     GlyphID,
 	"struct":      Struct,
 	"Offset":      Table,
+	"LOffset":     ExtSubTable,
 	"ValueRecord": ValueRecord,
 }
 
diff --git a/Lib/fontTools/ttLib/tables/otData.py b/Lib/fontTools/ttLib/tables/otData.py
index 7accf91..89358e6 100644
--- a/Lib/fontTools/ttLib/tables/otData.py
+++ b/Lib/fontTools/ttLib/tables/otData.py
@@ -357,9 +357,9 @@
 	]),
 
 	('ExtensionPosFormat1', [
-		('USHORT', 'PosFormat', None, None, 'Format identifier. Set to 1.'),
+		('USHORT', 'ExtFormat', None, None, 'Format identifier. Set to 1.'),
 		('USHORT', 'ExtensionLookupType', None, None, 'Lookup type of subtable referenced by ExtensionOffset (i.e. the extension subtable).'),
-		('ULONG', 'ExtensionOffset', None, None, 'Offset to the extension subtable, of lookup type ExtensionLookupType, relative to the start of the ExtensionPosFormat1 subtable.'),
+		('LOffset', 'ExtSubTable', None, None, 'Array of offsets to Lookup tables-from beginning of LookupList -zero based (first lookup is Lookup index = 0)'),
 	]),
 
 	('ValueRecord', [
@@ -585,9 +585,9 @@
 	]),
 
 	('ExtensionSubstFormat1', [
-		('USHORT', 'SubstFormat', None, None, 'Format identifier. Set to 1.'),
+		('USHORT', 'ExtFormat', None, None, 'Format identifier. Set to 1.'),
 		('USHORT', 'ExtensionLookupType', None, None, 'Lookup type of subtable referenced by ExtensionOffset (i.e. the extension subtable).'),
-		('ULONG', 'ExtensionOffset', None, None, 'Offset to the extension subtable, of lookup type ExtensionLookupType, relative to the start of the ExtensionSubstFormat1 subtable.'),
+		('LOffset', 'ExtSubTable', None, None, 'Array of offsets to Lookup tables-from beginning of LookupList -zero based (first lookup is Lookup index = 0)'),
 	]),
 
 	('ReverseChainSingleSubstFormat1', [
diff --git a/Lib/fontTools/ttLib/tables/otTables.py b/Lib/fontTools/ttLib/tables/otTables.py
index 7d35c93..253b211 100644
--- a/Lib/fontTools/ttLib/tables/otTables.py
+++ b/Lib/fontTools/ttLib/tables/otTables.py
@@ -4,7 +4,7 @@
 Most are constructed upon import from data in otData.py, all are populated with
 converter objects from otConverters.py.
 """
-
+import operator
 from otBase import BaseTable, FormatSwitchingBaseTable
 from types import TupleType
 
@@ -14,9 +14,14 @@
 
 
 class FeatureParams(BaseTable):
-	"""Dummy class; this table isn't defined, but is used, and is always NULL."""
+	"""This class has been used by Adobe, but but this one implementation was done wrong.
+	No other use has been made, becuase there is no way to know how to interpret
+	the data at the offset.. For now, if we see one, just skip the data on
+	decompiling and dumping to XML. """
 	# XXX The above is no longer true; the 'size' feature uses FeatureParams now.
-
+	def __init__(self):
+		BaseTable.__init__(self)
+		self.converters = []
 
 class Coverage(FormatSwitchingBaseTable):
 	
@@ -28,6 +33,7 @@
 		elif self.Format == 2:
 			glyphs = self.glyphs = []
 			ranges = rawTable["RangeRecord"]
+			getGlyphName = font.getGlyphName
 			for r in ranges:
 				assert r.StartCoverageIndex == len(glyphs), \
 					(r.StartCoverageIndex, len(glyphs))
@@ -36,8 +42,8 @@
 				startID = font.getGlyphID(start)
 				endID = font.getGlyphID(end)
 				glyphs.append(start)
-				for glyphID in range(startID + 1, endID):
-					glyphs.append(font.getGlyphName(glyphID))
+				rangeList = [getGlyphName(glyphID) for glyphID in range(startID + 1, endID) ]
+				glyphs += rangeList
 				if start != end:
 					glyphs.append(end)
 		else:
@@ -49,11 +55,10 @@
 			glyphs = self.glyphs = []
 		format = 1
 		rawTable = {"GlyphArray": glyphs}
+		getGlyphID = font.getGlyphID
 		if glyphs:
 			# find out whether Format 2 is more compact or not
-			glyphIDs = []
-			for glyphName in glyphs:
-				glyphIDs.append(font.getGlyphID(glyphName))
+			glyphIDs = [getGlyphID(glyphName) for glyphName in glyphs ]
 			
 			last = glyphIDs[0]
 			ranges = [[last]]
@@ -95,22 +100,79 @@
 		glyphs.append(attrs["value"])
 
 
+class LookupList(BaseTable):
+	def preCompile(self):
+		""" This function is used to optimize writing out extension subtables. This is useful
+		when a font has been read in, modified, and we are now writing out a new version. If the
+		the extension subtables have not been touched (proof being that they have not been decompiled)
+		then we can write them out using the original data, and do not have to recompile them. This can save
+		20-30% of the compile time for fonts with large extension tables, such as Japanese Pro fonts."""
+
+		if hasattr(self, 'LookupCount'): #not defined if loading from xml
+			lookupCount = self.LookupCount
+		else:
+			return # The optimization of not recompiling extension lookup subtables is not possible
+					# when reading from XML.
+ 
+		liRange = range(lookupCount)
+		extTables = []
+		for li in liRange:
+			lookup = self.Lookup[li]
+			if hasattr(lookup, 'SubTableCount'): #not defined if loading from xml
+				subtableCount = lookup.SubTableCount
+			else:
+				subtableCount = len(lookup.SubTable)
+			siRange = range(subtableCount)
+			for si in siRange:
+				subtable = lookup.SubTable[si]
+				if hasattr(subtable, 'ExtSubTable'):
+					extTable = subtable.ExtSubTable
+					extTables.append([extTable.start, extTable] )
+
+		# Since offsets in one subtable can and do point forward into later
+		# subtables, we can afford to simply copy data only for the last subtables 
+		# which were not decompiled. So we start figuring out the
+		# data segments starting with the last subtTable, and work our way towards
+		# the first subtable, and then quit as soon as we see a subtable that was decompiled.
+		if  extTables:
+			extTables.sort()
+			extTables.reverse()
+			lastTable = extTables[0][1]
+			if lastTable.compileStatus == 1:
+				lastTable.end = len(lastTable.reader.data)
+				lastTable.compileStatus = 3
+				for i in range(1, len(extTables)):
+					extTable = extTables[i][1]
+					if extTable.compileStatus != 1:
+						break
+					extTable.end = lastTable.start
+					extTable.compileStatus = 3
+					lastTable = extTable
+
+def doModulo(value):
+	if value < 0:
+		return value + 65536
+	return value
+
 class SingleSubst(FormatSwitchingBaseTable):
 
 	def postRead(self, rawTable, font):
 		mapping = {}
 		input = _getGlyphsFromCoverageTable(rawTable["Coverage"])
+		lenMapping = len(input)
 		if self.Format == 1:
 			delta = rawTable["DeltaGlyphID"]
-			for inGlyph in input:
-				glyphID = font.getGlyphID(inGlyph)
-				mapping[inGlyph] = font.getGlyphName(glyphID + delta)
+			inputGIDS =  [ font.getGlyphID(name) for name in input ]
+			inputGIDS = map(doModulo, inputGIDS) 
+			outGIDS = [ glyphID + delta for glyphID in inputGIDS ]
+			outGIDS = map(doModulo, outGIDS) 
+			outNames = [ font.getGlyphName(glyphID) for glyphID in outGIDS ]
+			map(operator.setitem, [mapping]*lenMapping, input, outNames)
 		elif self.Format == 2:
 			assert len(input) == rawTable["GlyphCount"], \
 					"invalid SingleSubstFormat2 table"
 			subst = rawTable["Substitute"]
-			for i in range(len(input)):
-				mapping[input[i]] = subst[i]
+			map(operator.setitem, [mapping]*lenMapping, input, subst)
 		else:
 			assert 0, "unknown format: %s" % self.Format
 		self.mapping = mapping
@@ -120,15 +182,15 @@
 		if mapping is None:
 			mapping = self.mapping = {}
 		items = mapping.items()
-		for i in range(len(items)):
-			inGlyph, outGlyph = items[i]
-			items[i] = font.getGlyphID(inGlyph), font.getGlyphID(outGlyph), \
-					inGlyph, outGlyph
-		items.sort()
-		
+		getGlyphID = font.getGlyphID
+		gidItems = [(getGlyphID(item[0]), getGlyphID(item[1])) for item in items]
+		sortableItems = zip(gidItems, items)
+		sortableItems.sort()
+
+		# figure out format
 		format = 2
 		delta = None
-		for inID, outID, inGlyph, outGlyph in items:
+		for inID, outID in gidItems:
 			if delta is None:
 				delta = outID - inID
 			else:
@@ -136,15 +198,13 @@
 					break
 		else:
 			format = 1
-		
+
 		rawTable = {}
 		self.Format = format
 		cov = Coverage()
-		cov.glyphs = input = []
-		subst = []
-		for inID, outID, inGlyph, outGlyph in items:
-			input.append(inGlyph)
-			subst.append(outGlyph)
+		input =  [ item [1][0] for item in sortableItems]
+		subst =  [ item [1][1] for item in sortableItems]
+		cov.glyphs = input
 		rawTable["Coverage"] = cov
 		if format == 1:
 			assert delta is not None
@@ -173,12 +233,18 @@
 	
 	def postRead(self, rawTable, font):
 		classDefs = {}
+		getGlyphName = font.getGlyphName
+
 		if self.Format == 1:
 			start = rawTable["StartGlyph"]
+			classList = rawTable["ClassValueArray"]
+			lenList = len(classList)
 			glyphID = font.getGlyphID(start)
-			for cls in rawTable["ClassValueArray"]:
-				classDefs[font.getGlyphName(glyphID)] = cls
-				glyphID = glyphID + 1
+			gidList = range(glyphID, glyphID + len(classList))
+			keyList = [getGlyphName(glyphID) for glyphID in gidList]
+
+			map(operator.setitem, [classDefs]*lenList, keyList, classList)
+
 		elif self.Format == 2:
 			records = rawTable["ClassRangeRecord"]
 			for rec in records:
@@ -186,9 +252,10 @@
 				end = rec.End
 				cls = rec.Class
 				classDefs[start] = cls
-				for glyphID in range(font.getGlyphID(start) + 1,
-						font.getGlyphID(end)):
-					classDefs[font.getGlyphName(glyphID)] = cls
+				glyphIDs = range(font.getGlyphID(start) + 1, font.getGlyphID(end))
+				lenList = len(glyphIDs)
+				keyList = [getGlyphName(glyphID) for glyphID in glyphIDs]
+				map(operator.setitem,  [classDefs]*lenList, keyList, [cls]*lenList)
 				classDefs[end] = cls
 		else:
 			assert 0, "unknown format: %s" % self.Format
@@ -199,9 +266,10 @@
 		if classDefs is None:
 			classDefs = self.classDefs = {}
 		items = classDefs.items()
+		getGlyphID = font.getGlyphID
 		for i in range(len(items)):
 			glyphName, cls = items[i]
-			items[i] = font.getGlyphID(glyphName), glyphName, cls
+			items[i] = getGlyphID(glyphName), glyphName, cls
 		items.sort()
 		if items:
 			last, lastName, lastCls = items[0]
@@ -247,7 +315,8 @@
 		if self.Format == 1:
 			input = _getGlyphsFromCoverageTable(rawTable["Coverage"])
 			alts = rawTable["AlternateSet"]
-			assert len(input) == len(alts)
+			if len(input) != len(alts):
+				assert len(input) == len(alts)
 			for i in range(len(input)):
 				alternates[input[i]] = alts[i].Alternate
 		else:
@@ -265,14 +334,19 @@
 			items[i] = font.getGlyphID(glyphName), glyphName, set
 		items.sort()
 		cov = Coverage()
-		glyphs = []
+		cov.glyphs = [ item[1] for item in items]
 		alternates = []
-		cov.glyphs = glyphs
-		for glyphID, glyphName, set in items:
-			glyphs.append(glyphName)
+		setList = [ item[-1] for item in items]
+		for  set in setList:
 			alts = AlternateSet()
 			alts.Alternate = set
 			alternates.append(alts)
+		# a special case to deal with the fact that several hundred Adobe Japan1-5
+		# CJK fonts will overflow an offset if the coverage table isn't pushed to the end.
+		# Also useful in that when splitting a sub-table because of an offset overflow
+		# I don't need to calculate the change in the subtable offset due to the change in the coverage table size.
+		# Allows packing more rules in subtable.
+		self.sortCoverageLast = 1 
 		return {"Coverage": cov, "AlternateSet": alternates}
 	
 	def toXML2(self, xmlWriter, font):
@@ -307,7 +381,7 @@
 	def postRead(self, rawTable, font):
 		ligatures = {}
 		if self.Format == 1:
-			input = _getGlyphsFromCoverageTable(rawTable["Coverage"])
+			input = rawTable["Coverage"].glyphs
 			ligSets = rawTable["LigatureSet"]
 			assert len(input) == len(ligSets)
 			for i in range(len(input)):
@@ -317,7 +391,6 @@
 		self.ligatures = ligatures
 	
 	def preWrite(self, font):
-		self.Format = 1
 		ligatures = getattr(self, "ligatures", None)
 		if ligatures is None:
 			ligatures = self.ligatures = {}
@@ -326,17 +399,21 @@
 			glyphName, set = items[i]
 			items[i] = font.getGlyphID(glyphName), glyphName, set
 		items.sort()
-		glyphs = []
 		cov = Coverage()
-		cov.glyphs = glyphs
+		cov.glyphs = [ item[1] for item in items]
+
 		ligSets = []
-		for glyphID, glyphName, set in items:
-			glyphs.append(glyphName)
+		setList = [ item[-1] for item in items ]
+		for set in setList:
 			ligSet = LigatureSet()
 			ligs = ligSet.Ligature = []
 			for lig in set:
 				ligs.append(lig)
 			ligSets.append(ligSet)
+		# Useful in that when splitting a sub-table because of an offset overflow
+		# I don't need to calculate the change in subtabl offset due to the coverage table size.
+		# Allows packing more rules in subtable.
+		self.sortCoverageLast = 1 
 		return {"Coverage": cov, "LigatureSet": ligSets}
 	
 	def toXML2(self, xmlWriter, font):
@@ -401,6 +478,191 @@
 }
 
 
+def fixLookupOverFlows(ttf, overflowRecord):
+	""" Either the offset from the LookupList to a lookup overflowed, or
+	an offset from a lookup to a subtable overflowed. 
+	The table layout is:
+	GPSO/GUSB
+		Script List
+		Feature List
+		LookUpList
+			Lookup[0] and contents
+				SubTable offset list
+					SubTable[0] and contents
+					...
+					SubTable[n] and contents
+			...
+			Lookup[n] and contents
+				SubTable offset list
+					SubTable[0] and contents
+					...
+					SubTable[n] and contents
+	If the offset to a lookup overflowed (SubTableIndex == None)
+		we must promote the *previous*	lookup to an Extension type.
+	If the offset from a lookup to subtable overflowed, then we must promote it 
+		to an Extension Lookup type.
+	"""
+	ok = 0
+	lookupIndex = overflowRecord.LookupListIndex
+	if (overflowRecord.SubTableIndex == None):
+		lookupIndex = lookupIndex - 1
+	if lookupIndex < 0:
+		return ok
+	if overflowRecord.tableType == 'GSUB':
+		extType = 7
+	elif overflowRecord.tableType == 'GPOS':
+		extType = 9
+
+	lookups = ttf[overflowRecord.tableType].table.LookupList.Lookup
+	lookup = lookups[lookupIndex]
+	# If the previous lookup is an extType, look further back. Very unlikely, but possible.
+	while lookup.LookupType == extType:
+		lookupIndex = lookupIndex -1
+		if lookupIndex < 0:
+			return ok
+		lookup = lookups[lookupIndex]
+		
+	for si in range(len(lookup.SubTable)):
+		subTable = lookup.SubTable[si]
+		extSubTableClass = lookupTypes[overflowRecord.tableType][extType]
+		extSubTable = extSubTableClass()
+		extSubTable.Format = 1
+		extSubTable.ExtensionLookupType = lookup.LookupType
+		extSubTable.ExtSubTable = subTable
+		lookup.SubTable[si] = extSubTable
+	lookup.LookupType = extType
+	ok = 1
+	return ok
+
+def splitAlternateSubst(oldSubTable, newSubTable, overflowRecord):
+	ok = 1
+	newSubTable.Format = oldSubTable.Format
+	if hasattr(oldSubTable, 'sortCoverageLast'):
+		newSubTable.sortCoverageLast = oldSubTable.sortCoverageLast
+	
+	oldAlts = oldSubTable.alternates.items()
+	oldAlts.sort()
+	oldLen = len(oldAlts)
+
+	if overflowRecord.itemName in [ 'Coverage', 'RangeRecord']:
+		# Coverage table is written last. overflow is to or within the
+		# the coverage table. We will just cut the subtable in half.
+		newLen = int(oldLen/2)
+
+	elif overflowRecord.itemName == 'AlternateSet':
+		# We just need to back up by two items 
+		# from the overflowed AlternateSet index to make sure the offset
+		# to the Coverage table doesn't overflow.
+		newLen  = overflowRecord.itemIndex - 1
+
+	newSubTable.alternates = {}
+	for i in range(newLen, oldLen):
+		item = oldAlts[i]
+		key = item[0]
+		newSubTable.alternates[key] = item[1]
+		del oldSubTable.alternates[key]
+
+
+	return ok
+
+
+def splitLigatureSubst(oldSubTable, newSubTable, overflowRecord):
+	ok = 1
+	newSubTable.Format = oldSubTable.Format
+	oldLigs = oldSubTable.ligatures.items()
+	oldLigs.sort()
+	oldLen = len(oldLigs)
+
+	if overflowRecord.itemName in [ 'Coverage', 'RangeRecord']:
+		# Coverage table is written last. overflow is to or within the
+		# the coverage table. We will just cut the subtable in half.
+		newLen = int(oldLen/2)
+
+	elif overflowRecord.itemName == 'LigatureSet':
+		# We just need to back up by two items 
+		# from the overflowed AlternateSet index to make sure the offset
+		# to the Coverage table doesn't overflow.
+		newLen  = overflowRecord.itemIndex - 1
+
+	newSubTable.ligatures = {}
+	for i in range(newLen, oldLen):
+		item = oldLigs[i]
+		key = item[0]
+		newSubTable.ligatures[key] = item[1]
+		del oldSubTable.ligatures[key]
+
+	return ok
+
+
+splitTable = {	'GSUB': {
+#					1: splitSingleSubst,
+#					2: splitMultipleSubst,
+					3: splitAlternateSubst,
+					4: splitLigatureSubst,
+#					5: splitContextSubst,
+#					6: splitChainContextSubst,
+#					7: splitExtensionSubst,
+#					8: splitReverseChainSingleSubst,
+					},
+				'GPOS': {
+#					1: splitSinglePos,
+#					2: splitPairPos,
+#					3: splitCursivePos,
+#					4: splitMarkBasePos,
+#					5: splitMarkLigPos,
+#					6: splitMarkMarkPos,
+#					7: splitContextPos,
+#					8: splitChainContextPos,
+#					9: splitExtensionPos,
+					}
+
+			}
+
+def fixSubTableOverFlows(ttf, overflowRecord):
+	""" 
+	An offset has overflowed within a sub-table. We need to divide this subtable into smaller parts.
+	"""
+	ok = 0
+	table = ttf[overflowRecord.tableType].table
+	lookup = table.LookupList.Lookup[overflowRecord.LookupListIndex]
+	subIndex = overflowRecord.SubTableIndex
+	subtable = lookup.SubTable[subIndex]
+
+	if hasattr(subtable, 'ExtSubTable'):
+		# We split the subtable of the Extension table, and add a new Extension table
+		# to contain the new subtable.
+
+		subTableType = subtable.ExtensionLookupType
+		extSubTable = subtable
+		subtable = extSubTable.ExtSubTable
+		newExtSubTableClass = lookupTypes[overflowRecord.tableType][lookup.LookupType]
+		newExtSubTable = newExtSubTableClass()
+		newExtSubTable.Format = extSubTable.Format
+		newExtSubTable.ExtensionLookupType = extSubTable.ExtensionLookupType
+		lookup.SubTable.insert(subIndex + 1, newExtSubTable)
+
+		newSubTableClass = lookupTypes[overflowRecord.tableType][subTableType]
+		newSubTable = newSubTableClass()
+		newExtSubTable.ExtSubTable = newSubTable
+	else:
+		subTableType = lookup.LookupType
+		newSubTableClass = lookupTypes[overflowRecord.tableType][subTableType]
+		newSubTable = newSubTableClass()
+		lookup.SubTable.insert(subIndex + 1, newSubTable)
+
+	if hasattr(lookup, 'SubTableCount'): # may not be defined yet.
+		lookup.SubTableCount = lookup.SubTableCount + 1
+
+	try:
+		splitFunc = splitTable[overflowRecord.tableType][subTableType]
+	except KeyError:
+		return ok
+
+	ok = splitFunc(subtable, newSubTable, overflowRecord)
+	return ok
+
+
+
 def _buildClasses():
 	import new, re
 	from otData import otData