Source code for fontTools.ttLib.tables.M_E_T_A_

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",
}


[docs] def getLabelString(labelID): try: label = METALabelDict[labelID] except KeyError: label = "Unknown label" return str(label)
[docs] class table_M_E_T_A_(DefaultTable.DefaultTable): dependencies = []
[docs] 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)
[docs] 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
[docs] 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)
[docs] 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"]))
[docs] class GlyphRecord(object): def __init__(self): self.glyphID = -1 self.nMetaEntry = -1 self.offset = -1 self.stringRecs = []
[docs] 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()
[docs] 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"]))
[docs] 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
[docs] 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")
[docs] 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
[docs] class StringRecord(object):
[docs] 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()
[docs] 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))
[docs] 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 + " ]" )