text: from fontTools.misc import sstruct
  from fontTools.misc.textTools import byteord, safeEval
  from . import DefaultTable
  import pdb
  import struct
  
  
  METAHeaderFormat = """
  		>	# big endian
  		tableVersionMajor:			H
  		tableVersionMinor:			H
  		metaEntriesVersionMajor:	H
  		metaEntriesVersionMinor:	H
  		unicodeVersion:				L
  		metaFlags:					H
  		nMetaRecs:					H
  """
  # This record is followed by nMetaRecs of METAGlyphRecordFormat.
  # This in turn is followd by as many METAStringRecordFormat entries
  # as specified by the METAGlyphRecordFormat entries
  # this is followed by the strings specifried in the  METAStringRecordFormat
  METAGlyphRecordFormat = """
  		>	# big endian
  		glyphID:			H
  		nMetaEntry:			H
  """
  # This record is followd by a variable data length field:
  # 	USHORT or ULONG	hdrOffset
  # Offset from start of META table to the beginning
  # of this glyphs array of ns Metadata string entries.
  # Size determined by metaFlags field
  # METAGlyphRecordFormat entries must be sorted by glyph ID
  
  METAStringRecordFormat = """
  		>	# big endian
  		labelID:			H
  		stringLen:			H
  """
  # This record is followd by a variable data length field:
  # 	USHORT or ULONG	stringOffset
  # METAStringRecordFormat entries must be sorted in order of labelID
  # There may be more than one entry with the same labelID
  # There may be more than one strign with the same content.
  
  # Strings shall be Unicode UTF-8 encoded, and null-terminated.
  
  METALabelDict = {
  	0: "MojikumiX4051", # An integer in the range 1-20
  	1: "UNIUnifiedBaseChars",
  	2: "BaseFontName",
  	3: "Language",
  	4: "CreationDate",
  	5: "FoundryName",
  	6: "FoundryCopyright",
  	7: "OwnerURI",
  	8: "WritingScript",
  	10: "StrokeCount",
  	11: "IndexingRadical",
  }
  
  
  def getLabelString(labelID):
  	try:
  		label = METALabelDict[labelID]
  	except KeyError:
  		label = "Unknown label"
  	return str(label)
  
  
  class table_M_E_T_A_(DefaultTable.DefaultTable):
  
  	dependencies = []
  
  	def decompile(self, data, ttFont):
  		dummy, newData = sstruct.unpack2(METAHeaderFormat, data, self)
  		self.glyphRecords = []
  		for i in range(self.nMetaRecs):
  			glyphRecord, newData = sstruct.unpack2(METAGlyphRecordFormat, newData, GlyphRecord())
  			if self.metaFlags == 0:
  				[glyphRecord.offset] = struct.unpack(">H", newData[:2])
  				newData = newData[2:]
  			elif self.metaFlags == 1:
  				[glyphRecord.offset] = struct.unpack(">H", newData[:4])
  				newData = newData[4:]
  			else:
  				assert 0, "The metaFlags field in the META table header has a value other than 0 or 1 :" + str(self.metaFlags)
  			glyphRecord.stringRecs = []
  			newData = data[glyphRecord.offset:]
  			for j in range(glyphRecord.nMetaEntry):
  				stringRec, newData = sstruct.unpack2(METAStringRecordFormat, newData, StringRecord())
  				if self.metaFlags == 0:
  					[stringRec.offset] = struct.unpack(">H", newData[:2])
  					newData = newData[2:]
  				else:
  					[stringRec.offset] = struct.unpack(">H", newData[:4])
  					newData = newData[4:]
  				stringRec.string = data[stringRec.offset:stringRec.offset + stringRec.stringLen]
  				glyphRecord.stringRecs.append(stringRec)
  			self.glyphRecords.append(glyphRecord)
  
  	def compile(self, ttFont):
  		offsetOK = 0
  		self.nMetaRecs = len(self.glyphRecords)
  		count = 0
  		while (offsetOK != 1):
  			count = count + 1
  			if count > 4:
  				pdb.set_trace()
  			metaData = sstruct.pack(METAHeaderFormat, self)
  			stringRecsOffset = len(metaData) + self.nMetaRecs * (6 + 2*(self.metaFlags & 1))
  			stringRecSize = (6 + 2*(self.metaFlags & 1))
  			for glyphRec in self.glyphRecords:
  				glyphRec.offset = stringRecsOffset
  				if (glyphRec.offset > 65535) and ((self.metaFlags & 1) == 0):
  					self.metaFlags = self.metaFlags + 1
  					offsetOK = -1
  					break
  				metaData = metaData + glyphRec.compile(self)
  				stringRecsOffset = stringRecsOffset + (glyphRec.nMetaEntry * stringRecSize)
  				# this will be the String Record offset for the next GlyphRecord.
  			if offsetOK == -1:
  				offsetOK = 0
  				continue
  
  			# metaData now contains the header and all of the GlyphRecords. Its length should bw
  			# the offset to the first StringRecord.
  			stringOffset = stringRecsOffset
  			for glyphRec in self.glyphRecords:
  				assert (glyphRec.offset == len(metaData)), "Glyph record offset did not compile correctly! for rec:" + str(glyphRec)
  				for stringRec in glyphRec.stringRecs:
  					stringRec.offset = stringOffset
  					if (stringRec.offset > 65535) and ((self.metaFlags & 1) == 0):
  						self.metaFlags = self.metaFlags + 1
  						offsetOK = -1
  						break
  					metaData = metaData + stringRec.compile(self)
  					stringOffset = stringOffset + stringRec.stringLen
  			if 	offsetOK == -1:
  				offsetOK = 0
  				continue
  
  			if ((self.metaFlags & 1) == 1) and (stringOffset < 65536):
  				self.metaFlags = self.metaFlags - 1
  				continue
  			else:
  				offsetOK = 1
  
  			# metaData now contains the header and all of the GlyphRecords and all of the String Records.
  			# Its length should be the offset to the first string datum.
  			for glyphRec in self.glyphRecords:
  				for stringRec in glyphRec.stringRecs:
  					assert (stringRec.offset == len(metaData)), "String offset did not compile correctly! for string:" + str(stringRec.string)
  					metaData = metaData + stringRec.string
  
  		return metaData
  
  	def toXML(self, writer, ttFont):
  		writer.comment("Lengths and number of entries in this table will be recalculated by the compiler")
  		writer.newline()
  		formatstring, names, fixes = sstruct.getformat(METAHeaderFormat)
  		for name in names:
  			value = getattr(self, name)
  			writer.simpletag(name, value=value)
  			writer.newline()
  		for glyphRec in self.glyphRecords:
  			glyphRec.toXML(writer, ttFont)
  
  	def fromXML(self, name, attrs, content, ttFont):
  		if name == "GlyphRecord":
  			if not hasattr(self, "glyphRecords"):
  				self.glyphRecords = []
  			glyphRec = GlyphRecord()
  			self.glyphRecords.append(glyphRec)
  			for element in content:
  				if isinstance(element, str):
  					continue
  				name, attrs, content = element
  				glyphRec.fromXML(name, attrs, content, ttFont)
  			glyphRec.offset = -1
  			glyphRec.nMetaEntry = len(glyphRec.stringRecs)
  		else:
  			setattr(self, name, safeEval(attrs["value"]))
  
  
  class GlyphRecord(object):
  	def __init__(self):
  		self.glyphID = -1
  		self.nMetaEntry = -1
  		self.offset = -1
  		self.stringRecs = []
  
  	def toXML(self, writer, ttFont):
  		writer.begintag("GlyphRecord")
  		writer.newline()
  		writer.simpletag("glyphID", value=self.glyphID)
  		writer.newline()
  		writer.simpletag("nMetaEntry", value=self.nMetaEntry)
  		writer.newline()
  		for stringRec in self.stringRecs:
  			stringRec.toXML(writer, ttFont)
  		writer.endtag("GlyphRecord")
  		writer.newline()
  
  	def fromXML(self, name, attrs, content, ttFont):
  		if name == "StringRecord":
  			stringRec = StringRecord()
  			self.stringRecs.append(stringRec)
  			for element in content:
  				if isinstance(element, str):
  					continue
  				stringRec.fromXML(name, attrs, content, ttFont)
  			stringRec.stringLen = len(stringRec.string)
  		else:
  			setattr(self, name, safeEval(attrs["value"]))
  
  	def compile(self, parentTable):
  		data = sstruct.pack(METAGlyphRecordFormat, self)
  		if parentTable.metaFlags == 0:
  			datum = struct.pack(">H", self.offset)
  		elif parentTable.metaFlags == 1:
  			datum = struct.pack(">L", self.offset)
  		data = data + datum
  		return data
  
  	def __repr__(self):
  		return "GlyphRecord[ glyphID: " + str(self.glyphID) + ", nMetaEntry: " + str(self.nMetaEntry) + ", offset: " + str(self.offset) + " ]"
  
  # XXX The following two functions are really broken around UTF-8 vs Unicode
  
  def mapXMLToUTF8(string):
  	uString = str()
  	strLen = len(string)
  	i = 0
  	while i < strLen:
  		prefixLen = 0
  		if  (string[i:i+3] == "&#x"):
  			prefixLen = 3
  		elif  (string[i:i+7] == "&amp;#x"):
  			prefixLen = 7
  		if prefixLen:
  			i = i+prefixLen
  			j= i
  			while string[i] != ";":
  				i = i+1
  			valStr = string[j:i]
  
  			uString = uString + chr(eval('0x' + valStr))
  		else:
  			uString = uString + chr(byteord(string[i]))
  		i = i +1
  
  	return uString.encode('utf_8')
  
  
  def mapUTF8toXML(string):
  	uString = string.decode('utf_8')
  	string = ""
  	for uChar in uString:
  		i = ord(uChar)
  		if (i < 0x80) and (i > 0x1F):
  			string = string + uChar
  		else:
  			string = string + "&#x" + hex(i)[2:] + ";"
  	return string
  
  
  class StringRecord(object):
  
  	def toXML(self, writer, ttFont):
  		writer.begintag("StringRecord")
  		writer.newline()
  		writer.simpletag("labelID", value=self.labelID)
  		writer.comment(getLabelString(self.labelID))
  		writer.newline()
  		writer.newline()
  		writer.simpletag("string", value=mapUTF8toXML(self.string))
  		writer.newline()
  		writer.endtag("StringRecord")
  		writer.newline()
  
  	def fromXML(self, name, attrs, content, ttFont):
  		for element in content:
  			if isinstance(element, str):
  				continue
  			name, attrs, content = element
  			value = attrs["value"]
  			if name == "string":
  				self.string = mapXMLToUTF8(value)
  			else:
  				setattr(self, name, safeEval(value))
  
  	def compile(self, parentTable):
  		data = sstruct.pack(METAStringRecordFormat, self)
  		if parentTable.metaFlags == 0:
  			datum = struct.pack(">H", self.offset)
  		elif parentTable.metaFlags == 1:
  			datum = struct.pack(">L", self.offset)
  		data = data + datum
  		return data
  
  	def __repr__(self):
  		return "StringRecord [ labelID: " + str(self.labelID) + " aka " + getLabelString(self.labelID) \
  			+ ", offset: " + str(self.offset) + ", length: " + str(self.stringLen) + ", string: " +self.string + " ]"
  