aboutsummaryrefslogtreecommitdiff
path: root/Lib/fontTools/ttLib/tables/M_E_T_A_.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/fontTools/ttLib/tables/M_E_T_A_.py')
-rw-r--r--Lib/fontTools/ttLib/tables/M_E_T_A_.py307
1 files changed, 307 insertions, 0 deletions
diff --git a/Lib/fontTools/ttLib/tables/M_E_T_A_.py b/Lib/fontTools/ttLib/tables/M_E_T_A_.py
new file mode 100644
index 00000000..60214e84
--- /dev/null
+++ b/Lib/fontTools/ttLib/tables/M_E_T_A_.py
@@ -0,0 +1,307 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc import sstruct
+from fontTools.misc.textTools import safeEval
+from . import DefaultTable
+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, basestring):
+ 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, basestring):
+ 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 = unicode()
+ 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 + unichr(eval('0x' + valStr))
+ else:
+ uString = uString + unichr(byteord(string[i]))
+ i = i +1
+
+ return uString.encode('utf8')
+
+
+def mapUTF8toXML(string):
+ uString = string.decode('utf8')
+ 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, basestring):
+ 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 + " ]"
+