# Source code for fontTools.ttLib.tables.E_B_L_C_

    from fontTools.misc import sstruct
    from . import DefaultTable
    from fontTools.misc.textTools import bytesjoin, safeEval
    from .BitmapGlyphMetrics import BigGlyphMetrics, bigGlyphMetricsFormat, SmallGlyphMetrics, smallGlyphMetricsFormat
    import struct
    import itertools
    from collections import deque
    import logging

    log = logging.getLogger(__name__)

    eblcHeaderFormat = """
    	> # big endian
    	version:  16.16F
    	numSizes: I
    """
    # The table format string is split to handle sbitLineMetrics simply.
    bitmapSizeTableFormatPart1 = """
    	> # big endian
    	indexSubTableArrayOffset: I
    	indexTablesSize:          I
    	numberOfIndexSubTables:   I
    	colorRef:                 I
    """
    # The compound type for hori and vert.
    sbitLineMetricsFormat = """
    	> # big endian
    	ascender:              b
    	descender:             b
    	widthMax:              B
    	caretSlopeNumerator:   b
    	caretSlopeDenominator: b
    	caretOffset:           b
    	minOriginSB:           b
    	minAdvanceSB:          b
    	maxBeforeBL:           b
    	minAfterBL:            b
    	pad1:                  b
    	pad2:                  b
    """
    # hori and vert go between the two parts.
    bitmapSizeTableFormatPart2 = """
    	> # big endian
    	startGlyphIndex: H
    	endGlyphIndex:   H
    	ppemX:           B
    	ppemY:           B
    	bitDepth:        B
    	flags:           b
    """

    indexSubTableArrayFormat = ">HHL"
    indexSubTableArraySize = struct.calcsize(indexSubTableArrayFormat)

    indexSubHeaderFormat = ">HHL"
    indexSubHeaderSize = struct.calcsize(indexSubHeaderFormat)

    codeOffsetPairFormat = ">HH"
    codeOffsetPairSize = struct.calcsize(codeOffsetPairFormat)

    class table_E_B_L_C_(DefaultTable.DefaultTable):

    	dependencies = ['EBDT']

    	# This method can be overridden in subclasses to support new formats
    	# without changing the other implementation. Also can be used as a
    	# convenience method for coverting a font file to an alternative format.
    	def getIndexFormatClass(self, indexFormat):
    		return eblc_sub_table_classes[indexFormat]

    	def decompile(self, data, ttFont):

    		# Save the original data because offsets are from the start of the table.
    		origData = data
    		i = 0;

    		dummy = sstruct.unpack(eblcHeaderFormat, data[:8], self)
    		i += 8;

    		self.strikes = []
    		for curStrikeIndex in range(self.numSizes):
    			curStrike = Strike()
    			self.strikes.append(curStrike)
    			curTable = curStrike.bitmapSizeTable
    			dummy = sstruct.unpack2(bitmapSizeTableFormatPart1, data[i:i+16], curTable)
    			i += 16
    			for metric in ('hori', 'vert'):
    				metricObj = SbitLineMetrics()
    				vars(curTable)[metric] = metricObj
    				dummy = sstruct.unpack2(sbitLineMetricsFormat, data[i:i+12], metricObj)
    				i += 12
    			dummy = sstruct.unpack(bitmapSizeTableFormatPart2, data[i:i+8], curTable)
    			i += 8

    		for curStrike in self.strikes:
    			curTable = curStrike.bitmapSizeTable
    			for subtableIndex in range(curTable.numberOfIndexSubTables):
    				i = curTable.indexSubTableArrayOffset + subtableIndex * indexSubTableArraySize

    				tup = struct.unpack(indexSubTableArrayFormat, data[i:i+indexSubTableArraySize])
    				(firstGlyphIndex, lastGlyphIndex, additionalOffsetToIndexSubtable) = tup
    				i = curTable.indexSubTableArrayOffset + additionalOffsetToIndexSubtable

    				tup = struct.unpack(indexSubHeaderFormat, data[i:i+indexSubHeaderSize])
    				(indexFormat, imageFormat, imageDataOffset) = tup

    				indexFormatClass = self.getIndexFormatClass(indexFormat)
    				indexSubTable = indexFormatClass(data[i+indexSubHeaderSize:], ttFont)
    				indexSubTable.firstGlyphIndex = firstGlyphIndex
    				indexSubTable.lastGlyphIndex = lastGlyphIndex
    				indexSubTable.additionalOffsetToIndexSubtable = additionalOffsetToIndexSubtable
    				indexSubTable.indexFormat = indexFormat
    				indexSubTable.imageFormat = imageFormat
    				indexSubTable.imageDataOffset = imageDataOffset
    				indexSubTable.decompile() # https://github.com/fonttools/fonttools/issues/317
    				curStrike.indexSubTables.append(indexSubTable)

    	def compile(self, ttFont):

    		dataList = []
    		self.numSizes = len(self.strikes)
    		dataList.append(sstruct.pack(eblcHeaderFormat, self))

    		# Data size of the header + bitmapSizeTable needs to be calculated
    		# in order to form offsets. This value will hold the size of the data
    		# in dataList after all the data is consolidated in dataList.
    		dataSize = len(dataList[0])

    		# The table will be structured in the following order:
    		# (0) header
    		# (1) Each bitmapSizeTable [1 ... self.numSizes]
    		# (2) Alternate between indexSubTableArray and indexSubTable
    		#     for each bitmapSizeTable present.
    		#
    		# The issue is maintaining the proper offsets when table information
    		# gets moved around. All offsets and size information must be recalculated
    		# when building the table to allow editing within ttLib and also allow easy
    		# import/export to and from XML. All of this offset information is lost
    		# when exporting to XML so everything must be calculated fresh so importing
    		# from XML will work cleanly. Only byte offset and size information is
    		# calculated fresh. Count information like numberOfIndexSubTables is
    		# checked through assertions. If the information in this table was not
    		# touched or was changed properly then these types of values should match.
    		#
    		# The table will be rebuilt the following way:
    		# (0) Precompute the size of all the bitmapSizeTables. This is needed to
    		#     compute the offsets properly.
    		# (1) For each bitmapSizeTable compute the indexSubTable and
    		#    	indexSubTableArray pair. The indexSubTable must be computed first
    		#     so that the offset information in indexSubTableArray can be
    		#     calculated. Update the data size after each pairing.
    		# (2) Build each bitmapSizeTable.
    		# (3) Consolidate all the data into the main dataList in the correct order.

    		for _ in self.strikes:
    			dataSize += sstruct.calcsize(bitmapSizeTableFormatPart1)
    			dataSize += len(('hori', 'vert')) * sstruct.calcsize(sbitLineMetricsFormat)
    			dataSize += sstruct.calcsize(bitmapSizeTableFormatPart2)

    		indexSubTablePairDataList = []
    		for curStrike in self.strikes:
    			curTable = curStrike.bitmapSizeTable
    			curTable.numberOfIndexSubTables = len(curStrike.indexSubTables)
    			curTable.indexSubTableArrayOffset = dataSize

    			# Precompute the size of the indexSubTableArray. This information
    			# is important for correctly calculating the new value for
    			# additionalOffsetToIndexSubtable.
    			sizeOfSubTableArray = curTable.numberOfIndexSubTables * indexSubTableArraySize
    			lowerBound = dataSize
    			dataSize += sizeOfSubTableArray
    			upperBound = dataSize

    			indexSubTableDataList = []
    			for indexSubTable in curStrike.indexSubTables:
    				indexSubTable.additionalOffsetToIndexSubtable = dataSize - curTable.indexSubTableArrayOffset
    				glyphIds = list(map(ttFont.getGlyphID, indexSubTable.names))
    				indexSubTable.firstGlyphIndex = min(glyphIds)
    				indexSubTable.lastGlyphIndex = max(glyphIds)
    				data = indexSubTable.compile(ttFont)
    				indexSubTableDataList.append(data)
    				dataSize += len(data)
    			curTable.startGlyphIndex = min(ist.firstGlyphIndex for ist in curStrike.indexSubTables)
    			curTable.endGlyphIndex = max(ist.lastGlyphIndex for ist in curStrike.indexSubTables)

    			for i in curStrike.indexSubTables:
    				data = struct.pack(indexSubHeaderFormat, i.firstGlyphIndex, i.lastGlyphIndex, i.additionalOffsetToIndexSubtable)
    				indexSubTablePairDataList.append(data)
    			indexSubTablePairDataList.extend(indexSubTableDataList)
    			curTable.indexTablesSize = dataSize - curTable.indexSubTableArrayOffset

    		for curStrike in self.strikes:
    			curTable = curStrike.bitmapSizeTable
    			data = sstruct.pack(bitmapSizeTableFormatPart1, curTable)
    			dataList.append(data)
    			for metric in ('hori', 'vert'):
    				metricObj = vars(curTable)[metric]
    				data = sstruct.pack(sbitLineMetricsFormat, metricObj)
    				dataList.append(data)
    			data = sstruct.pack(bitmapSizeTableFormatPart2, curTable)
    			dataList.append(data)
    		dataList.extend(indexSubTablePairDataList)

    		return bytesjoin(dataList)

    	def toXML(self, writer, ttFont):
    		writer.simpletag('header', [('version', self.version)])
    		writer.newline()
    		for curIndex, curStrike in enumerate(self.strikes):
    			curStrike.toXML(curIndex, writer, ttFont)

    	def fromXML(self, name, attrs, content, ttFont):
    		if name == 'header':
    			self.version = safeEval(attrs['version'])
    		elif name == 'strike':
    			if not hasattr(self, 'strikes'):
    				self.strikes = []
    			strikeIndex = safeEval(attrs['index'])
    			curStrike = Strike()
    			curStrike.fromXML(name, attrs, content, ttFont, self)

    			# Grow the strike array to the appropriate size. The XML format
    			# allows for the strike index value to be out of order.
    			if strikeIndex >= len(self.strikes):
    				self.strikes += [None] * (strikeIndex + 1 - len(self.strikes))
    			assert self.strikes[strikeIndex] is None, "Duplicate strike EBLC indices."
    			self.strikes[strikeIndex] = curStrike

    class Strike(object):

    	def __init__(self):
    		self.bitmapSizeTable = BitmapSizeTable()
    		self.indexSubTables = []

    	def toXML(self, strikeIndex, writer, ttFont):
    		writer.begintag('strike', [('index', strikeIndex)])
    		writer.newline()
    		self.bitmapSizeTable.toXML(writer, ttFont)
    		writer.comment('GlyphIds are written but not read. The firstGlyphIndex and\nlastGlyphIndex values will be recalculated by the compiler.')
    		writer.newline()
    		for indexSubTable in self.indexSubTables:
    			indexSubTable.toXML(writer, ttFont)
    		writer.endtag('strike')
    		writer.newline()

    	def fromXML(self, name, attrs, content, ttFont, locator):
    		for element in content:
    			if not isinstance(element, tuple):
    				continue
    			name, attrs, content = element
    			if name == 'bitmapSizeTable':
    				self.bitmapSizeTable.fromXML(name, attrs, content, ttFont)
    			elif name.startswith(_indexSubTableSubclassPrefix):
    				indexFormat = safeEval(name[len(_indexSubTableSubclassPrefix):])
    				indexFormatClass = locator.getIndexFormatClass(indexFormat)
    				indexSubTable = indexFormatClass(None, None)
    				indexSubTable.indexFormat = indexFormat
    				indexSubTable.fromXML(name, attrs, content, ttFont)
    				self.indexSubTables.append(indexSubTable)

    class BitmapSizeTable(object):

    	# Returns all the simple metric names that bitmap size table
    	# cares about in terms of XML creation.
    	def _getXMLMetricNames(self):
    		dataNames = sstruct.getformat(bitmapSizeTableFormatPart1)[1]
    		dataNames = dataNames + sstruct.getformat(bitmapSizeTableFormatPart2)[1]
    		# Skip the first 3 data names because they are byte offsets and counts.
    		return dataNames[3:]

    	def toXML(self, writer, ttFont):
    		writer.begintag('bitmapSizeTable')
    		writer.newline()
    		for metric in ('hori', 'vert'):
    			getattr(self, metric).toXML(metric, writer, ttFont)
    		for metricName in self._getXMLMetricNames():
    			writer.simpletag(metricName, value=getattr(self, metricName))
    			writer.newline()
    		writer.endtag('bitmapSizeTable')
    		writer.newline()

    	def fromXML(self, name, attrs, content, ttFont):
    		# Create a lookup for all the simple names that make sense to
    		# bitmap size table. Only read the information from these names.
    		dataNames = set(self._getXMLMetricNames())
    		for element in content:
    			if not isinstance(element, tuple):
    				continue
    			name, attrs, content = element
    			if name == 'sbitLineMetrics':
    				direction = attrs['direction']
    				assert direction in ('hori', 'vert'), "SbitLineMetrics direction specified invalid."
    				metricObj = SbitLineMetrics()
    				metricObj.fromXML(name, attrs, content, ttFont)
    				vars(self)[direction] = metricObj
    			elif name in dataNames:
    				vars(self)[name] = safeEval(attrs['value'])
    			else:
    				log.warning("unknown name '%s' being ignored in BitmapSizeTable.", name)

    class SbitLineMetrics(object):

    	def toXML(self, name, writer, ttFont):
    		writer.begintag('sbitLineMetrics', [('direction', name)])
    		writer.newline()
    		for metricName in sstruct.getformat(sbitLineMetricsFormat)[1]:
    			writer.simpletag(metricName, value=getattr(self, metricName))
    			writer.newline()
    		writer.endtag('sbitLineMetrics')
    		writer.newline()

    	def fromXML(self, name, attrs, content, ttFont):
    		metricNames = set(sstruct.getformat(sbitLineMetricsFormat)[1])
    		for element in content:
    			if not isinstance(element, tuple):
    				continue
    			name, attrs, content = element
    			if name in metricNames:
    				vars(self)[name] = safeEval(attrs['value'])

    # Important information about the naming scheme. Used for identifying subtables.
    _indexSubTableSubclassPrefix = 'eblc_index_sub_table_'

    class EblcIndexSubTable(object):

    	def __init__(self, data, ttFont):
    		self.data = data
    		self.ttFont = ttFont
    		# TODO Currently non-lazy decompiling doesn't work for this class...
    		#if not ttFont.lazy:
    		#	self.decompile()
    		#	del self.data, self.ttFont

    	def __getattr__(self, attr):
    		# Allow lazy decompile.
    		if attr[:2] == '__':
    			raise AttributeError(attr)
    		if attr == "data":
    			raise AttributeError(attr)
    		self.decompile()
    		return getattr(self, attr)

    	def ensureDecompiled(self, recurse=False):
    		if hasattr(self, "data"):
    			self.decompile()

    	# This method just takes care of the indexSubHeader. Implementing subclasses
    	# should call it to compile the indexSubHeader and then continue compiling
    	# the remainder of their unique format.
    	def compile(self, ttFont):
    		return struct.pack(indexSubHeaderFormat, self.indexFormat, self.imageFormat, self.imageDataOffset)

    	# Creates the XML for bitmap glyphs. Each index sub table basically makes
    	# the same XML except for specific metric information that is written
    	# out via a method call that a subclass implements optionally.
    	def toXML(self, writer, ttFont):
    		writer.begintag(self.__class__.__name__, [
    				('imageFormat', self.imageFormat),
    				('firstGlyphIndex', self.firstGlyphIndex),
    				('lastGlyphIndex', self.lastGlyphIndex),
    				])
    		writer.newline()
    		self.writeMetrics(writer, ttFont)
    		# Write out the names as thats all thats needed to rebuild etc.
    		# For font debugging of consecutive formats the ids are also written.
    		# The ids are not read when moving from the XML format.
    		glyphIds = map(ttFont.getGlyphID, self.names)
    		for glyphName, glyphId in zip(self.names, glyphIds):
    			writer.simpletag('glyphLoc', name=glyphName, id=glyphId)
    			writer.newline()
    		writer.endtag(self.__class__.__name__)
    		writer.newline()

    	def fromXML(self, name, attrs, content, ttFont):
    		# Read all the attributes. Even though the glyph indices are
    		# recalculated, they are still read in case there needs to
    		# be an immediate export of the data.
    		self.imageFormat = safeEval(attrs['imageFormat'])
    		self.firstGlyphIndex = safeEval(attrs['firstGlyphIndex'])
    		self.lastGlyphIndex = safeEval(attrs['lastGlyphIndex'])

    		self.readMetrics(name, attrs, content, ttFont)

    		self.names = []
    		for element in content:
    			if not isinstance(element, tuple):
    				continue
    			name, attrs, content = element
    			if name == 'glyphLoc':
    				self.names.append(attrs['name'])

    	# A helper method that writes the metrics for the index sub table. It also
    	# is responsible for writing the image size for fixed size data since fixed
    	# size is not recalculated on compile. Default behavior is to do nothing.
    	def writeMetrics(self, writer, ttFont):
    		pass

    	# A helper method that is the inverse of writeMetrics.
    	def readMetrics(self, name, attrs, content, ttFont):
    		pass

    	# This method is for fixed glyph data sizes. There are formats where
    	# the glyph data is fixed but are actually composite glyphs. To handle
    	# this the font spec in indexSubTable makes the data the size of the
    	# fixed size by padding the component arrays. This function abstracts
    	# out this padding process. Input is data unpadded. Output is data
    	# padded only in fixed formats. Default behavior is to return the data.
    	def padBitmapData(self, data):
    		return data

    	# Remove any of the glyph locations and names that are flagged as skipped.
    	# This only occurs in formats {1,3}.
    	def removeSkipGlyphs(self):
    		# Determines if a name, location pair is a valid data location.
    		# Skip glyphs are marked when the size is equal to zero.
    		def isValidLocation(args):
    			(name, (startByte, endByte)) = args
    			return startByte < endByte
    		# Remove all skip glyphs.
    		dataPairs = list(filter(isValidLocation, zip(self.names, self.locations)))
    		self.names, self.locations = list(map(list, zip(*dataPairs)))

    # A closure for creating a custom mixin. This is done because formats 1 and 3
    # are very similar. The only difference between them is the size per offset
    # value. Code put in here should handle both cases generally.
    def _createOffsetArrayIndexSubTableMixin(formatStringForDataType):

    	# Prep the data size for the offset array data format.
    	dataFormat = '>'+formatStringForDataType
    	offsetDataSize = struct.calcsize(dataFormat)

    	class OffsetArrayIndexSubTableMixin(object):

    		def decompile(self):

    			numGlyphs = self.lastGlyphIndex - self.firstGlyphIndex + 1
    			indexingOffsets = [glyphIndex * offsetDataSize for glyphIndex in range(numGlyphs+2)]
    			indexingLocations = zip(indexingOffsets, indexingOffsets[1:])
    			offsetArray = [struct.unpack(dataFormat, self.data[slice(*loc)])[0] for loc in indexingLocations]

    			glyphIds = list(range(self.firstGlyphIndex, self.lastGlyphIndex+1))
    			modifiedOffsets = [offset + self.imageDataOffset for offset in offsetArray]
    			self.locations = list(zip(modifiedOffsets, modifiedOffsets[1:]))

    			self.names = list(map(self.ttFont.getGlyphName, glyphIds))
    			self.removeSkipGlyphs()
    			del self.data, self.ttFont

    		def compile(self, ttFont):
    			# First make sure that all the data lines up properly. Formats 1 and 3
    			# must have all its data lined up consecutively. If not this will fail.
    			for curLoc, nxtLoc in zip(self.locations, self.locations[1:]):
    				assert curLoc[1] == nxtLoc[0], "Data must be consecutive in indexSubTable offset formats"

    			glyphIds = list(map(ttFont.getGlyphID, self.names))
    			# Make sure that all ids are sorted strictly increasing.
    			assert all(glyphIds[i] < glyphIds[i+1] for i in range(len(glyphIds)-1))

    			# Run a simple algorithm to add skip glyphs to the data locations at
    			# the places where an id is not present.
    			idQueue = deque(glyphIds)
    			locQueue = deque(self.locations)
    			allGlyphIds = list(range(self.firstGlyphIndex, self.lastGlyphIndex+1))
    			allLocations = []
    			for curId in allGlyphIds:
    				if curId != idQueue[0]:
    					allLocations.append((locQueue[0][0], locQueue[0][0]))
    				else:
    					idQueue.popleft()
    					allLocations.append(locQueue.popleft())

    			# Now that all the locations are collected, pack them appropriately into
    			# offsets. This is the form where offset[i] is the location and
    			# offset[i+1]-offset[i] is the size of the data location.
    			offsets = list(allLocations[0]) + [loc[1] for loc in allLocations[1:]]
    			# Image data offset must be less than or equal to the minimum of locations.
    			# This offset may change the value for round tripping but is safer and
    			# allows imageDataOffset to not be required to be in the XML version.
    			self.imageDataOffset = min(offsets)
    			offsetArray = [offset - self.imageDataOffset for offset in offsets]

    			dataList = [EblcIndexSubTable.compile(self, ttFont)]
    			dataList += [struct.pack(dataFormat, offsetValue) for offsetValue in offsetArray]
    			# Take care of any padding issues. Only occurs in format 3.
    			if offsetDataSize * len(offsetArray) % 4 != 0:
    				dataList.append(struct.pack(dataFormat, 0))
    			return bytesjoin(dataList)

    	return OffsetArrayIndexSubTableMixin

    # A Mixin for functionality shared between the different kinds
    # of fixed sized data handling. Both kinds have big metrics so
    # that kind of special processing is also handled in this mixin.
    class FixedSizeIndexSubTableMixin(object):

    	def writeMetrics(self, writer, ttFont):
    		writer.simpletag('imageSize', value=self.imageSize)
    		writer.newline()
    		self.metrics.toXML(writer, ttFont)

    	def readMetrics(self, name, attrs, content, ttFont):
    		for element in content:
    			if not isinstance(element, tuple):
    				continue
    			name, attrs, content = element
    			if name == 'imageSize':
    				self.imageSize = safeEval(attrs['value'])
    			elif name == BigGlyphMetrics.__name__:
    				self.metrics = BigGlyphMetrics()
    				self.metrics.fromXML(name, attrs, content, ttFont)
    			elif name == SmallGlyphMetrics.__name__:
    				log.warning("SmallGlyphMetrics being ignored in format %d.", self.indexFormat)

    	def padBitmapData(self, data):
    		# Make sure that the data isn't bigger than the fixed size.
    		assert len(data) <= self.imageSize, "Data in indexSubTable format %d must be less than the fixed size." % self.indexFormat
    		# Pad the data so that it matches the fixed size.
    		pad = (self.imageSize - len(data)) * b'\0'
    		return data + pad

    class eblc_index_sub_table_1(_createOffsetArrayIndexSubTableMixin('L'), EblcIndexSubTable):
    	pass

    class eblc_index_sub_table_2(FixedSizeIndexSubTableMixin, EblcIndexSubTable):

    	def decompile(self):
    		(self.imageSize,) = struct.unpack(">L", self.data[:4])
    		self.metrics = BigGlyphMetrics()
    		sstruct.unpack2(bigGlyphMetricsFormat, self.data[4:], self.metrics)
    		glyphIds = list(range(self.firstGlyphIndex, self.lastGlyphIndex+1))
    		offsets = [self.imageSize * i + self.imageDataOffset for i in range(len(glyphIds)+1)]
    		self.locations = list(zip(offsets, offsets[1:]))
    		self.names = list(map(self.ttFont.getGlyphName, glyphIds))
    		del self.data, self.ttFont

    	def compile(self, ttFont):
    		glyphIds = list(map(ttFont.getGlyphID, self.names))
    		# Make sure all the ids are consecutive. This is required by Format 2.
    		assert glyphIds == list(range(self.firstGlyphIndex, self.lastGlyphIndex+1)), "Format 2 ids must be consecutive."
    		self.imageDataOffset = min(next(iter(zip(*self.locations))))

    		dataList = [EblcIndexSubTable.compile(self, ttFont)]
    		dataList.append(struct.pack(">L", self.imageSize))
    		dataList.append(sstruct.pack(bigGlyphMetricsFormat, self.metrics))
    		return bytesjoin(dataList)

    class eblc_index_sub_table_3(_createOffsetArrayIndexSubTableMixin('H'), EblcIndexSubTable):
    	pass

    class eblc_index_sub_table_4(EblcIndexSubTable):

    	def decompile(self):

    		(numGlyphs,) = struct.unpack(">L", self.data[:4])
    		data = self.data[4:]
    		indexingOffsets = [glyphIndex * codeOffsetPairSize for glyphIndex in range(numGlyphs+2)]
    		indexingLocations = zip(indexingOffsets, indexingOffsets[1:])
    		glyphArray = [struct.unpack(codeOffsetPairFormat, data[slice(*loc)]) for loc in indexingLocations]
    		glyphIds, offsets = list(map(list, zip(*glyphArray)))
    		# There are one too many glyph ids. Get rid of the last one.
    		glyphIds.pop()

    		offsets = [offset + self.imageDataOffset for offset in offsets]
    		self.locations = list(zip(offsets, offsets[1:]))
    		self.names = list(map(self.ttFont.getGlyphName, glyphIds))
    		del self.data, self.ttFont

    	def compile(self, ttFont):
    		# First make sure that all the data lines up properly. Format 4
    		# must have all its data lined up consecutively. If not this will fail.
    		for curLoc, nxtLoc in zip(self.locations, self.locations[1:]):
    			assert curLoc[1] == nxtLoc[0], "Data must be consecutive in indexSubTable format 4"

    		offsets = list(self.locations[0]) + [loc[1] for loc in self.locations[1:]]
    		# Image data offset must be less than or equal to the minimum of locations.
    		# Resetting this offset may change the value for round tripping but is safer
    		# and allows imageDataOffset to not be required to be in the XML version.
    		self.imageDataOffset = min(offsets)
    		offsets = [offset - self.imageDataOffset for offset in offsets]
    		glyphIds = list(map(ttFont.getGlyphID, self.names))
    		# Create an iterator over the ids plus a padding value.
    		idsPlusPad = list(itertools.chain(glyphIds, [0]))

    		dataList = [EblcIndexSubTable.compile(self, ttFont)]
    		dataList.append(struct.pack(">L", len(glyphIds)))
    		tmp = [struct.pack(codeOffsetPairFormat, *cop) for cop in zip(idsPlusPad, offsets)]
    		dataList += tmp
    		data = bytesjoin(dataList)
    		return data

    class eblc_index_sub_table_5(FixedSizeIndexSubTableMixin, EblcIndexSubTable):

    	def decompile(self):
    		self.origDataLen = 0
    		(self.imageSize,) = struct.unpack(">L", self.data[:4])
    		data = self.data[4:]
    		self.metrics, data = sstruct.unpack2(bigGlyphMetricsFormat, data, BigGlyphMetrics())
    		(numGlyphs,) = struct.unpack(">L", data[:4])
    		data = data[4:]
    		glyphIds = [struct.unpack(">H", data[2*i:2*(i+1)])[0] for i in range(numGlyphs)]

    		offsets = [self.imageSize * i + self.imageDataOffset for i in range(len(glyphIds)+1)]
    		self.locations = list(zip(offsets, offsets[1:]))
    		self.names = list(map(self.ttFont.getGlyphName, glyphIds))
    		del self.data, self.ttFont

    	def compile(self, ttFont):
    		self.imageDataOffset = min(next(iter(zip(*self.locations))))
    		dataList = [EblcIndexSubTable.compile(self, ttFont)]
    		dataList.append(struct.pack(">L", self.imageSize))
    		dataList.append(sstruct.pack(bigGlyphMetricsFormat, self.metrics))
    		glyphIds = list(map(ttFont.getGlyphID, self.names))
    		dataList.append(struct.pack(">L", len(glyphIds)))
    		dataList += [struct.pack(">H", curId) for curId in glyphIds]
    		if len(glyphIds) % 2 == 1:
    			dataList.append(struct.pack(">H", 0))
    		return bytesjoin(dataList)

    # Dictionary of indexFormat to the class representing that format.
    eblc_sub_table_classes = {
    		1: eblc_index_sub_table_1,
    		2: eblc_index_sub_table_2,
    		3: eblc_index_sub_table_3,
    		4: eblc_index_sub_table_4,
    		5: eblc_index_sub_table_5,
    	}