_m_e_t_a.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. from fontTools.misc import sstruct
  2. from fontTools.misc.textTools import bytesjoin, strjoin, readHex
  3. from fontTools.ttLib import TTLibError
  4. from . import DefaultTable
  5. # Apple's documentation of 'meta':
  6. # https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6meta.html
  7. META_HEADER_FORMAT = """
  8. > # big endian
  9. version: L
  10. flags: L
  11. dataOffset: L
  12. numDataMaps: L
  13. """
  14. DATA_MAP_FORMAT = """
  15. > # big endian
  16. tag: 4s
  17. dataOffset: L
  18. dataLength: L
  19. """
  20. class table__m_e_t_a(DefaultTable.DefaultTable):
  21. def __init__(self, tag=None):
  22. DefaultTable.DefaultTable.__init__(self, tag)
  23. self.data = {}
  24. def decompile(self, data, ttFont):
  25. headerSize = sstruct.calcsize(META_HEADER_FORMAT)
  26. header = sstruct.unpack(META_HEADER_FORMAT, data[0:headerSize])
  27. if header["version"] != 1:
  28. raise TTLibError("unsupported 'meta' version %d" % header["version"])
  29. dataMapSize = sstruct.calcsize(DATA_MAP_FORMAT)
  30. for i in range(header["numDataMaps"]):
  31. dataMapOffset = headerSize + i * dataMapSize
  32. dataMap = sstruct.unpack(
  33. DATA_MAP_FORMAT, data[dataMapOffset : dataMapOffset + dataMapSize]
  34. )
  35. tag = dataMap["tag"]
  36. offset = dataMap["dataOffset"]
  37. self.data[tag] = data[offset : offset + dataMap["dataLength"]]
  38. if tag in ["dlng", "slng"]:
  39. self.data[tag] = self.data[tag].decode("utf-8")
  40. def compile(self, ttFont):
  41. keys = sorted(self.data.keys())
  42. headerSize = sstruct.calcsize(META_HEADER_FORMAT)
  43. dataOffset = headerSize + len(keys) * sstruct.calcsize(DATA_MAP_FORMAT)
  44. header = sstruct.pack(
  45. META_HEADER_FORMAT,
  46. {
  47. "version": 1,
  48. "flags": 0,
  49. "dataOffset": dataOffset,
  50. "numDataMaps": len(keys),
  51. },
  52. )
  53. dataMaps = []
  54. dataBlocks = []
  55. for tag in keys:
  56. if tag in ["dlng", "slng"]:
  57. data = self.data[tag].encode("utf-8")
  58. else:
  59. data = self.data[tag]
  60. dataMaps.append(
  61. sstruct.pack(
  62. DATA_MAP_FORMAT,
  63. {"tag": tag, "dataOffset": dataOffset, "dataLength": len(data)},
  64. )
  65. )
  66. dataBlocks.append(data)
  67. dataOffset += len(data)
  68. return bytesjoin([header] + dataMaps + dataBlocks)
  69. def toXML(self, writer, ttFont):
  70. for tag in sorted(self.data.keys()):
  71. if tag in ["dlng", "slng"]:
  72. writer.begintag("text", tag=tag)
  73. writer.newline()
  74. writer.write(self.data[tag])
  75. writer.newline()
  76. writer.endtag("text")
  77. writer.newline()
  78. else:
  79. writer.begintag("hexdata", tag=tag)
  80. writer.newline()
  81. data = self.data[tag]
  82. if min(data) >= 0x20 and max(data) <= 0x7E:
  83. writer.comment("ascii: " + data.decode("ascii"))
  84. writer.newline()
  85. writer.dumphex(data)
  86. writer.endtag("hexdata")
  87. writer.newline()
  88. def fromXML(self, name, attrs, content, ttFont):
  89. if name == "hexdata":
  90. self.data[attrs["tag"]] = readHex(content)
  91. elif name == "text" and attrs["tag"] in ["dlng", "slng"]:
  92. self.data[attrs["tag"]] = strjoin(content).strip()
  93. else:
  94. raise TTLibError("can't handle '%s' element" % name)