first working version of CFF/T2 compiler; needs cleanup/refactoring, and doesn't import from XML yet; hardly tested.
git-svn-id: svn://svn.code.sf.net/p/fonttools/code/trunk@253 4cde692c-a291-49d1-8350-778aa11640f8
This commit is contained in:
parent
0011bb6910
commit
f2cf9c5d6d
@ -1,12 +1,12 @@
|
||||
"""cffLib.py -- read/write tools for Adobe CFF fonts."""
|
||||
|
||||
#
|
||||
# $Id: cffLib.py,v 1.20 2002-05-18 20:07:01 jvr Exp $
|
||||
# $Id: cffLib.py,v 1.21 2002-05-23 21:50:36 jvr Exp $
|
||||
#
|
||||
|
||||
import struct, sstruct
|
||||
import string
|
||||
import types
|
||||
from types import FloatType, ListType, TupleType
|
||||
from fontTools.misc import psCharStrings
|
||||
|
||||
|
||||
@ -30,10 +30,11 @@ class CFFFontSet:
|
||||
assert self.major == 1 and self.minor == 0, \
|
||||
"unknown CFF format: %d.%d" % (self.major, self.minor)
|
||||
|
||||
file.seek(self.hdrSize)
|
||||
self.fontNames = list(Index(file, "fontNames"))
|
||||
self.topDictIndex = TopDictIndex(file)
|
||||
self.strings = IndexedStrings(file)
|
||||
self.GlobalSubrs = CharStringIndex(file, name="GlobalSubrsIndex")
|
||||
self.GlobalSubrs = GlobalSubrsIndex(file, name="GlobalSubrsIndex")
|
||||
self.topDictIndex.strings = self.strings
|
||||
self.topDictIndex.GlobalSubrs = self.GlobalSubrs
|
||||
|
||||
@ -53,9 +54,25 @@ class CFFFontSet:
|
||||
raise KeyError, name
|
||||
return self.topDictIndex[index]
|
||||
|
||||
def compile(self):
|
||||
def compile(self, file):
|
||||
strings = IndexedStrings()
|
||||
XXXX
|
||||
writer = CFFWriter()
|
||||
writer.add(sstruct.pack(cffHeaderFormat, self))
|
||||
fontNames = Index()
|
||||
for name in self.fontNames:
|
||||
fontNames.append(name)
|
||||
writer.add(fontNames.getCompiler(strings, None))
|
||||
topCompiler = self.topDictIndex.getCompiler(strings, None)
|
||||
writer.add(topCompiler)
|
||||
writer.add(strings.getCompiler())
|
||||
writer.add(self.GlobalSubrs.getCompiler(strings, None))
|
||||
|
||||
for child in topCompiler.getChildren(strings):
|
||||
writer.add(child)
|
||||
|
||||
print writer.data
|
||||
|
||||
writer.toFile(file)
|
||||
|
||||
def toXML(self, xmlWriter, progress=None):
|
||||
xmlWriter.newline()
|
||||
@ -78,13 +95,163 @@ class CFFFontSet:
|
||||
xxx
|
||||
|
||||
|
||||
class CFFWriter:
|
||||
|
||||
def __init__(self):
|
||||
self.data = []
|
||||
|
||||
def add(self, table):
|
||||
self.data.append(table)
|
||||
|
||||
def toFile(self, file):
|
||||
lastPosList = None
|
||||
count = 1
|
||||
while 1:
|
||||
print "XXX iteration", count
|
||||
count += 1
|
||||
pos = 0
|
||||
posList = [pos]
|
||||
for item in self.data:
|
||||
if hasattr(item, "setPos"):
|
||||
item.setPos(pos)
|
||||
if hasattr(item, "getDataLength"):
|
||||
pos = pos + item.getDataLength()
|
||||
else:
|
||||
pos = pos + len(item)
|
||||
posList.append(pos)
|
||||
if posList == lastPosList:
|
||||
break
|
||||
lastPosList = posList
|
||||
begin = file.tell()
|
||||
posList = [0]
|
||||
for item in self.data:
|
||||
if hasattr(item, "toFile"):
|
||||
item.toFile(file)
|
||||
else:
|
||||
file.write(item)
|
||||
posList.append(file.tell() - begin)
|
||||
if posList != lastPosList:
|
||||
print "++++"
|
||||
print posList
|
||||
print lastPosList
|
||||
assert posList == lastPosList
|
||||
|
||||
|
||||
def calcOffSize(largestOffset):
|
||||
if largestOffset < 0x100:
|
||||
offSize = 1
|
||||
elif largestOffset < 0x10000:
|
||||
offSize = 2
|
||||
elif largestOffset < 0x1000000:
|
||||
offSize = 3
|
||||
else:
|
||||
offSize = 4
|
||||
return offSize
|
||||
|
||||
|
||||
class IndexCompiler:
|
||||
|
||||
def __init__(self, items, strings, parent):
|
||||
self.items = self.getItems(items, strings)
|
||||
self.parent = parent
|
||||
|
||||
def getItems(self, items, strings):
|
||||
return items
|
||||
|
||||
def getOffsets(self):
|
||||
pos = 1
|
||||
offsets = [pos]
|
||||
for item in self.items:
|
||||
if hasattr(item, "getDataLength"):
|
||||
pos = pos + item.getDataLength()
|
||||
else:
|
||||
pos = pos + len(item)
|
||||
offsets.append(pos)
|
||||
return offsets
|
||||
|
||||
def getDataLength(self):
|
||||
lastOffset = self.getOffsets()[-1]
|
||||
offSize = calcOffSize(lastOffset)
|
||||
dataLength = (
|
||||
2 + # count
|
||||
1 + # offSize
|
||||
(len(self.items) + 1) * offSize + # the offsets
|
||||
lastOffset - 1 # size of object data
|
||||
)
|
||||
return dataLength
|
||||
|
||||
def toFile(self, file):
|
||||
size = self.getDataLength()
|
||||
start = file.tell()
|
||||
offsets = self.getOffsets()
|
||||
writeCard16(file, len(self.items))
|
||||
offSize = calcOffSize(offsets[-1])
|
||||
writeCard8(file, offSize)
|
||||
offSize = -offSize
|
||||
pack = struct.pack
|
||||
for offset in offsets:
|
||||
binOffset = pack(">l", offset)[offSize:]
|
||||
assert len(binOffset) == -offSize
|
||||
file.write(binOffset)
|
||||
for item in self.items:
|
||||
if hasattr(item, "toFile"):
|
||||
item.toFile(file)
|
||||
else:
|
||||
file.write(item)
|
||||
assert start + size == file.tell()
|
||||
|
||||
|
||||
class IndexedStringsCompiler(IndexCompiler):
|
||||
|
||||
def getItems(self, items, strings):
|
||||
return items.strings
|
||||
|
||||
|
||||
class TopDictIndexCompiler(IndexCompiler):
|
||||
|
||||
def getItems(self, items, strings):
|
||||
out = []
|
||||
for item in items:
|
||||
out.append(item.getCompiler(strings, self))
|
||||
return out
|
||||
|
||||
def getChildren(self, strings):
|
||||
children = []
|
||||
for topDict in self.items:
|
||||
children.extend(topDict.getChildren(strings))
|
||||
return children
|
||||
|
||||
|
||||
class GlobalSubrsCompiler(IndexCompiler):
|
||||
def getItems(self, items, strings):
|
||||
out = []
|
||||
for cs in items:
|
||||
cs.compile()
|
||||
out.append(cs.bytecode)
|
||||
return out
|
||||
|
||||
class SubrsCompiler(GlobalSubrsCompiler):
|
||||
def setPos(self, pos):
|
||||
offset = pos - self.parent.pos
|
||||
self.parent.rawDict["Subrs"] = offset
|
||||
|
||||
class CharStringsCompiler(GlobalSubrsCompiler):
|
||||
def setPos(self, pos):
|
||||
self.parent.rawDict["CharStrings"] = pos
|
||||
|
||||
|
||||
class Index:
|
||||
|
||||
"""This class represents what the CFF spec calls an INDEX."""
|
||||
|
||||
def __init__(self, file, name=None):
|
||||
compilerClass = IndexCompiler
|
||||
|
||||
def __init__(self, file=None, name=None):
|
||||
if name is None:
|
||||
name = self.__class__.__name__
|
||||
if file is None:
|
||||
self.items = []
|
||||
return
|
||||
if DEBUG:
|
||||
print "loading %s at %s" % (name, file.tell())
|
||||
self.file = file
|
||||
@ -92,11 +259,11 @@ class Index:
|
||||
self.count = count
|
||||
self.items = [None] * count
|
||||
if count == 0:
|
||||
self.offsets = []
|
||||
self.items = []
|
||||
return
|
||||
offSize = readCard8(file)
|
||||
if DEBUG:
|
||||
print "index count: %s offSize: %s" % (count, offSize)
|
||||
print " index count: %s offSize: %s" % (count, offSize)
|
||||
assert offSize <= 4, "offSize too large: %s" % offSize
|
||||
self.offsets = offsets = []
|
||||
pad = '\0' * (4 - offSize)
|
||||
@ -107,9 +274,11 @@ class Index:
|
||||
offsets.append(int(offset))
|
||||
self.offsetBase = file.tell() - 1
|
||||
file.seek(self.offsetBase + offsets[-1]) # pretend we've read the whole lot
|
||||
if DEBUG:
|
||||
print " end of %s at %s" % (name, file.tell())
|
||||
|
||||
def __len__(self):
|
||||
return self.count
|
||||
return len(self.items)
|
||||
|
||||
def __getitem__(self, index):
|
||||
item = self.items[index]
|
||||
@ -127,11 +296,19 @@ class Index:
|
||||
|
||||
def produceItem(self, index, data, file, offset, size):
|
||||
return data
|
||||
|
||||
|
||||
class CharStringIndex(Index):
|
||||
|
||||
def __init__(self, file, globalSubrs=None, private=None, fdSelect=None, fdArray=None,
|
||||
def append(self, item):
|
||||
self.items.append(item)
|
||||
|
||||
def getCompiler(self, strings, parent):
|
||||
return self.compilerClass(self, strings, parent)
|
||||
|
||||
|
||||
class GlobalSubrsIndex(Index):
|
||||
|
||||
compilerClass = GlobalSubrsCompiler
|
||||
|
||||
def __init__(self, file=None, globalSubrs=None, private=None, fdSelect=None, fdArray=None,
|
||||
name=None):
|
||||
Index.__init__(self, file, name)
|
||||
self.globalSubrs = globalSubrs
|
||||
@ -168,10 +345,15 @@ class CharStringIndex(Index):
|
||||
else:
|
||||
sel = fdSelect[index]
|
||||
return self[index], sel
|
||||
|
||||
|
||||
class SubrsIndex(GlobalSubrsIndex):
|
||||
compilerClass = SubrsCompiler
|
||||
|
||||
|
||||
class TopDictIndex(Index):
|
||||
|
||||
compilerClass = TopDictIndexCompiler
|
||||
|
||||
def produceItem(self, index, data, file, offset, size):
|
||||
top = TopDict(self.strings, file, offset, self.GlobalSubrs)
|
||||
top.decompile(data)
|
||||
@ -189,7 +371,7 @@ class TopDictIndex(Index):
|
||||
class CharStrings:
|
||||
|
||||
def __init__(self, file, charset, globalSubrs, private, fdSelect, fdArray):
|
||||
self.charStringsIndex = CharStringIndex(file, globalSubrs, private, fdSelect, fdArray)
|
||||
self.charStringsIndex = SubrsIndex(file, globalSubrs, private, fdSelect, fdArray)
|
||||
self.nameToIndex = nameToIndex = {}
|
||||
for i in range(len(charset)):
|
||||
nameToIndex[charset[i]] = i
|
||||
@ -237,12 +419,34 @@ def readCard16(file):
|
||||
value, = struct.unpack(">H", file.read(2))
|
||||
return value
|
||||
|
||||
def writeCard8(file, value):
|
||||
file.write(chr(value))
|
||||
|
||||
def writeCard16(file, value):
|
||||
file.write(struct.pack(">H", value))
|
||||
|
||||
def packCard8(value):
|
||||
return chr(value)
|
||||
|
||||
def packCard16(value):
|
||||
return struct.pack(">H", value)
|
||||
|
||||
def buildOperatorDict(table):
|
||||
d = {}
|
||||
for op, name, arg, default, conv in table:
|
||||
d[op] = (name, arg)
|
||||
return d
|
||||
|
||||
def buildOpcodeDict(table):
|
||||
d = {}
|
||||
for op, name, arg, default, conv in table:
|
||||
if type(op) == TupleType:
|
||||
op = chr(op[0]) + chr(op[1])
|
||||
else:
|
||||
op = chr(op)
|
||||
d[name] = (op, arg)
|
||||
return d
|
||||
|
||||
def buildOrder(table):
|
||||
l = []
|
||||
for op, name, arg, default, conv in table:
|
||||
@ -266,6 +470,8 @@ def buildConverters(table):
|
||||
class BaseConverter:
|
||||
def read(self, parent, value):
|
||||
return value
|
||||
def write(self, parent, value):
|
||||
return value
|
||||
def xmlWrite(self, xmlWriter, name, value):
|
||||
xmlWriter.begintag(name)
|
||||
xmlWriter.newline()
|
||||
@ -283,12 +489,16 @@ class PrivateDictConverter(BaseConverter):
|
||||
len(data) == size
|
||||
pr.decompile(data)
|
||||
return pr
|
||||
def write(self, parent, value):
|
||||
return (0, 0) # dummy value
|
||||
|
||||
class SubrsConverter(BaseConverter):
|
||||
def read(self, parent, value):
|
||||
file = parent.file
|
||||
file.seek(parent.offset + value) # Offset(self)
|
||||
return CharStringIndex(file, name="SubrsIndex")
|
||||
return SubrsIndex(file, name="SubrsIndex")
|
||||
def write(self, parent, value):
|
||||
return 0 # dummy value
|
||||
|
||||
class CharStringsConverter(BaseConverter):
|
||||
def read(self, parent, value):
|
||||
@ -303,6 +513,8 @@ class CharStringsConverter(BaseConverter):
|
||||
private = parent.Private
|
||||
file.seek(value) # Offset(0)
|
||||
return CharStrings(file, charset, globalSubrs, private, fdSelect, fdArray)
|
||||
def write(self, parent, value):
|
||||
return 0 # dummy value
|
||||
|
||||
class CharsetConverter:
|
||||
def read(self, parent, value):
|
||||
@ -311,14 +523,18 @@ class CharsetConverter:
|
||||
numGlyphs = parent.numGlyphs
|
||||
file = parent.file
|
||||
file.seek(value)
|
||||
if DEBUG:
|
||||
print "loading charset at %s" % value
|
||||
format = readCard8(file)
|
||||
if format == 0:
|
||||
raise NotImplementedError
|
||||
charset =parseCharset0(numGlyphs, file, parent.strings)
|
||||
elif format == 1 or format == 2:
|
||||
charset = parseCharset(numGlyphs, file, parent.strings, isCID, format)
|
||||
else:
|
||||
raise NotImplementedError
|
||||
assert len(charset) == numGlyphs
|
||||
if DEBUG:
|
||||
print " charset end at %s" % file.tell()
|
||||
else:
|
||||
if isCID or not hasattr(parent, "CharStrings"):
|
||||
assert value == 0
|
||||
@ -335,12 +551,42 @@ class CharsetConverter:
|
||||
# 2: ExpertSubset
|
||||
charset = None #
|
||||
return charset
|
||||
def write(self, parent, value):
|
||||
return 0 # dummy value
|
||||
def xmlWrite(self, xmlWriter, name, value):
|
||||
# XXX GlyphOrder needs to be stored *somewhere*, but not here...
|
||||
xmlWriter.simpletag("charset", value=value)
|
||||
xmlWriter.newline()
|
||||
|
||||
|
||||
class CharsetCompiler:
|
||||
|
||||
def __init__(self, strings, charset, parent):
|
||||
assert charset[0] == '.notdef'
|
||||
format = 0 # XXX!
|
||||
data = [packCard8(format)]
|
||||
for name in charset[1:]:
|
||||
data.append(packCard16(strings.getSID(name)))
|
||||
self.data = "".join(data)
|
||||
self.parent = parent
|
||||
|
||||
def setPos(self, pos):
|
||||
self.parent.rawDict["charset"] = pos
|
||||
|
||||
def getDataLength(self):
|
||||
return len(self.data)
|
||||
|
||||
def toFile(self, file):
|
||||
file.write(self.data)
|
||||
|
||||
|
||||
def parseCharset0(numGlyphs, file, strings):
|
||||
charset = [".notdef"]
|
||||
for i in range(numGlyphs - 1):
|
||||
SID = readCard16(file)
|
||||
charset.append(strings[SID])
|
||||
return charset
|
||||
|
||||
def parseCharset(numGlyphs, file, strings, isCID, format):
|
||||
charset = ['.notdef']
|
||||
count = 1
|
||||
@ -405,14 +651,15 @@ class FDSelectConverter:
|
||||
class ROSConverter(BaseConverter):
|
||||
def xmlWrite(self, xmlWriter, name, value):
|
||||
registry, order, supplement = value
|
||||
xmlWriter.simpletag(name, [('registry', registry), ('order', order),
|
||||
('supplement', supplement)])
|
||||
xmlWriter.simpletag(name, [('Registry', registry), ('Order', order),
|
||||
('Supplement', supplement)])
|
||||
xmlWriter.newline()
|
||||
|
||||
|
||||
topDictOperators = [
|
||||
# opcode name argument type default converter
|
||||
((12, 30), 'ROS', ('SID','SID','number'), None, ROSConverter()),
|
||||
((12, 20), 'SyntheticBase', 'number', None, None),
|
||||
(0, 'version', 'SID', None, None),
|
||||
(1, 'Notice', 'SID', None, None),
|
||||
((12, 0), 'Copyright', 'SID', None, None),
|
||||
@ -432,7 +679,6 @@ topDictOperators = [
|
||||
((12, 8), 'StrokeWidth', 'number', 0, None),
|
||||
(14, 'XUID', 'array', None, None),
|
||||
(15, 'charset', 'number', 0, CharsetConverter()),
|
||||
((12, 20), 'SyntheticBase', 'number', None, None),
|
||||
((12, 21), 'PostScript', 'SID', None, None),
|
||||
((12, 22), 'BaseFontName', 'SID', None, None),
|
||||
((12, 23), 'BaseFontBlend', 'delta', None, None),
|
||||
@ -462,6 +708,8 @@ privateDictOperators = [
|
||||
((12, 12), 'StemSnapH', 'delta', None, None),
|
||||
((12, 13), 'StemSnapV', 'delta', None, None),
|
||||
((12, 14), 'ForceBold', 'number', 0, None),
|
||||
((12, 15), 'ForceBoldThreshold', 'number', None, None), # deprecated
|
||||
((12, 16), 'lenIV', 'number', None, None), # deprecated
|
||||
((12, 17), 'LanguageGroup', 'number', 0, None),
|
||||
((12, 18), 'ExpansionFactor', 'number', 0.06, None),
|
||||
((12, 19), 'initialRandomSeed', 'number', 0, None),
|
||||
@ -479,20 +727,138 @@ class PrivateDictDecompiler(psCharStrings.DictDecompiler):
|
||||
operators = buildOperatorDict(privateDictOperators)
|
||||
|
||||
|
||||
class DictCompiler:
|
||||
|
||||
def __init__(self, dictObj, strings, parent):
|
||||
assert isinstance(strings, IndexedStrings)
|
||||
self.dictObj = dictObj
|
||||
self.strings = strings
|
||||
self.parent = parent
|
||||
rawDict = {}
|
||||
for name in dictObj.order:
|
||||
value = getattr(dictObj, name, None)
|
||||
if value is None:
|
||||
continue
|
||||
conv = dictObj.converters[name]
|
||||
if conv:
|
||||
value = conv.write(dictObj, value)
|
||||
if value == dictObj.defaults.get(name):
|
||||
continue
|
||||
rawDict[name] = value
|
||||
self.rawDict = rawDict
|
||||
|
||||
def setPos(self, pos):
|
||||
pass
|
||||
|
||||
def getDataLength(self):
|
||||
return len(self.compile())
|
||||
|
||||
def compile(self):
|
||||
rawDict = self.rawDict
|
||||
data = []
|
||||
for name in self.dictObj.order:
|
||||
value = rawDict.get(name)
|
||||
if value is None:
|
||||
continue
|
||||
op, argType = self.opcodes[name]
|
||||
if type(argType) == TupleType:
|
||||
l = len(argType)
|
||||
assert len(value) == l, "value doesn't match arg type"
|
||||
for i in range(l):
|
||||
arg = argType[l - i - 1]
|
||||
v = value[i]
|
||||
arghandler = getattr(self, "arg_" + arg)
|
||||
data.append(arghandler(v))
|
||||
else:
|
||||
arghandler = getattr(self, "arg_" + argType)
|
||||
data.append(arghandler(value))
|
||||
data.append(op)
|
||||
return "".join(data)
|
||||
|
||||
def toFile(self, file):
|
||||
file.write(self.compile())
|
||||
|
||||
def arg_number(self, num):
|
||||
return encodeNumber(num)
|
||||
def arg_SID(self, s):
|
||||
return psCharStrings.encodeIntCFF(self.strings.getSID(s))
|
||||
def arg_array(self, value):
|
||||
data = []
|
||||
for num in value:
|
||||
data.append(encodeNumber(num))
|
||||
return "".join(data)
|
||||
def arg_delta(self, value):
|
||||
out = []
|
||||
last = 0
|
||||
for v in value:
|
||||
out.append(v - last)
|
||||
last = v
|
||||
data = []
|
||||
for num in out:
|
||||
data.append(encodeNumber(num))
|
||||
return "".join(data)
|
||||
|
||||
|
||||
def encodeNumber(num):
|
||||
if type(num) == FloatType:
|
||||
return psCharStrings.encodeFloat(num)
|
||||
else:
|
||||
return psCharStrings.encodeIntCFF(num)
|
||||
|
||||
|
||||
class TopDictCompiler(DictCompiler):
|
||||
|
||||
opcodes = buildOpcodeDict(topDictOperators)
|
||||
|
||||
def getChildren(self, strings):
|
||||
children = []
|
||||
if hasattr(self.dictObj, "charset"):
|
||||
children.append(CharsetCompiler(strings, self.dictObj.charset, self))
|
||||
if hasattr(self.dictObj, "CharStrings"):
|
||||
items = []
|
||||
charStrings = self.dictObj.CharStrings
|
||||
for name in self.dictObj.charset:
|
||||
items.append(charStrings[name])
|
||||
charStringsComp = CharStringsCompiler(items, strings, self)
|
||||
children.append(charStringsComp)
|
||||
if hasattr(self.dictObj, "Private"):
|
||||
privComp = self.dictObj.Private.getCompiler(strings, self)
|
||||
children.append(privComp)
|
||||
children.extend(privComp.getChildren(strings))
|
||||
return children
|
||||
|
||||
|
||||
class PrivateDictCompiler(DictCompiler):
|
||||
|
||||
opcodes = buildOpcodeDict(privateDictOperators)
|
||||
|
||||
def setPos(self, pos):
|
||||
size = len(self.compile())
|
||||
self.parent.rawDict["Private"] = size, pos
|
||||
self.pos = pos
|
||||
|
||||
def getChildren(self, strings):
|
||||
children = []
|
||||
if hasattr(self.dictObj, "Subrs"):
|
||||
children.append(self.dictObj.Subrs.getCompiler(strings, self))
|
||||
return children
|
||||
|
||||
|
||||
class BaseDict:
|
||||
|
||||
def __init__(self, strings, file, offset):
|
||||
self.rawDict = {}
|
||||
if DEBUG:
|
||||
print "loading %s at %s" % (self, offset)
|
||||
print "loading %s at %s" % (self.__class__.__name__, offset)
|
||||
self.file = file
|
||||
self.offset = offset
|
||||
self.strings = strings
|
||||
self.skipNames = []
|
||||
|
||||
def decompile(self, data):
|
||||
dec = self.decompiler(self.strings)
|
||||
if DEBUG:
|
||||
print " length %s is %s" % (self.__class__.__name__, len(data))
|
||||
dec = self.decompilerClass(self.strings)
|
||||
dec.decompile(data)
|
||||
self.rawDict = dec.getDict()
|
||||
self.postDecompile()
|
||||
@ -500,6 +866,9 @@ class BaseDict:
|
||||
def postDecompile(self):
|
||||
pass
|
||||
|
||||
def getCompiler(self, strings, parent):
|
||||
return self.compilerClass(self, strings, parent)
|
||||
|
||||
def __getattr__(self, name):
|
||||
value = self.rawDict.get(name)
|
||||
if value is None:
|
||||
@ -523,7 +892,7 @@ class BaseDict:
|
||||
if conv is not None:
|
||||
conv.xmlWrite(xmlWriter, name, value)
|
||||
else:
|
||||
if isinstance(value, types.ListType):
|
||||
if isinstance(value, ListType):
|
||||
value = " ".join(map(str, value))
|
||||
xmlWriter.simpletag(name, value=value)
|
||||
xmlWriter.newline()
|
||||
@ -534,7 +903,8 @@ class TopDict(BaseDict):
|
||||
defaults = buildDefaults(topDictOperators)
|
||||
converters = buildConverters(topDictOperators)
|
||||
order = buildOrder(topDictOperators)
|
||||
decompiler = TopDictDecompiler
|
||||
decompilerClass = TopDictDecompiler
|
||||
compilerClass = TopDictCompiler
|
||||
|
||||
def __init__(self, strings, file, offset, GlobalSubrs):
|
||||
BaseDict.__init__(self, strings, file, offset)
|
||||
@ -570,7 +940,8 @@ class PrivateDict(BaseDict):
|
||||
defaults = buildDefaults(privateDictOperators)
|
||||
converters = buildConverters(privateDictOperators)
|
||||
order = buildOrder(privateDictOperators)
|
||||
decompiler = PrivateDictDecompiler
|
||||
decompilerClass = PrivateDictDecompiler
|
||||
compilerClass = PrivateDictCompiler
|
||||
|
||||
|
||||
class IndexedStrings:
|
||||
@ -584,6 +955,12 @@ class IndexedStrings:
|
||||
strings = list(Index(file, "IndexedStrings"))
|
||||
self.strings = strings
|
||||
|
||||
def getCompiler(self):
|
||||
return IndexedStringsCompiler(self, None, None)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.strings)
|
||||
|
||||
def __getitem__(self, SID):
|
||||
if SID < cffStandardStringCount:
|
||||
return cffStandardStrings[SID]
|
||||
@ -595,7 +972,7 @@ class IndexedStrings:
|
||||
self.buildStringMapping()
|
||||
if cffStandardStringMapping.has_key(s):
|
||||
SID = cffStandardStringMapping[s]
|
||||
if self.stringMapping.has_key(s):
|
||||
elif self.stringMapping.has_key(s):
|
||||
SID = self.stringMapping[s]
|
||||
else:
|
||||
SID = len(self.strings) + cffStandardStringCount
|
||||
@ -687,4 +1064,3 @@ cffStandardStringMapping = {}
|
||||
for _i in range(cffStandardStringCount):
|
||||
cffStandardStringMapping[cffStandardStrings[_i]] = _i
|
||||
|
||||
|
||||
|
@ -29,9 +29,12 @@ cffDictOperandEncoding[255] = "reserved"
|
||||
|
||||
realNibbles = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'.', 'E', 'E-', None, '-']
|
||||
realNibblesDict = {}
|
||||
for _i in range(len(realNibbles)):
|
||||
realNibblesDict[realNibbles[_i]] = _i
|
||||
|
||||
|
||||
class ByteCodeDecompilerBase:
|
||||
class ByteCodeBase:
|
||||
|
||||
def read_byte(self, b0, data, index):
|
||||
return b0 - 139, index
|
||||
@ -140,7 +143,64 @@ t2Operators = [
|
||||
((12, 37), 'flex1'),
|
||||
]
|
||||
|
||||
class T2CharString(ByteCodeDecompilerBase):
|
||||
|
||||
def getIntEncoder(format):
|
||||
fourByteOp = chr(255)
|
||||
isT1 = 0
|
||||
if format == "cff":
|
||||
fourByteOp = chr(29)
|
||||
elif format == "t1":
|
||||
isT1 = 1
|
||||
else:
|
||||
assert format == "t2"
|
||||
|
||||
def encodeInt(value, fourByteOp=fourByteOp, isT1=isT1,
|
||||
chr=chr, pack=struct.pack, unpack=struct.unpack):
|
||||
if -107 <= value <= 107:
|
||||
code = chr(value + 139)
|
||||
elif 108 <= value <= 1131:
|
||||
value = value - 108
|
||||
code = chr((value >> 8) + 247) + chr(value & 0xFF)
|
||||
elif -1131 <= value <= -108:
|
||||
value = -value - 108
|
||||
code = chr((value >> 8) + 251) + chr(value & 0xFF)
|
||||
elif not isT1 and -32768 <= value <= 32767:
|
||||
code = chr(28) + pack(">h", value)
|
||||
else:
|
||||
code = fourByteOp + pack(">l", value)
|
||||
return code
|
||||
|
||||
return encodeInt
|
||||
|
||||
|
||||
encodeIntCFF = getIntEncoder("cff")
|
||||
encodeIntT1 = getIntEncoder("t1")
|
||||
encodeIntT2 = getIntEncoder("t2")
|
||||
|
||||
def encodeFloat(f):
|
||||
s = str(f).upper()
|
||||
if s[:2] == "0.":
|
||||
s = s[1:]
|
||||
elif s[:3] == "-0.":
|
||||
s = "-" + s[2:]
|
||||
nibbles = []
|
||||
while s:
|
||||
c = s[0]
|
||||
s = s[1:]
|
||||
if c == "E" and s[:1] == "-":
|
||||
s = s[1:]
|
||||
c = "E-"
|
||||
nibbles.append(realNibblesDict[c])
|
||||
nibbles.append(0xf)
|
||||
if len(nibbles) % 2:
|
||||
nibbles.append(0xf)
|
||||
d = chr(30)
|
||||
for i in range(0, len(nibbles), 2):
|
||||
d = d + chr(nibbles[i] << 4 | nibbles[i+1])
|
||||
return d
|
||||
|
||||
|
||||
class T2CharString(ByteCodeBase):
|
||||
|
||||
operandEncoding = t2OperandEncoding
|
||||
operators, opcodes = buildOperatorDict(t2Operators)
|
||||
@ -178,41 +238,24 @@ class T2CharString(ByteCodeDecompilerBase):
|
||||
bytecode.extend(map(chr, opcodes[token]))
|
||||
else:
|
||||
bytecode.append(token) # hint mask
|
||||
elif tp == types.FloatType:
|
||||
# only in CFF
|
||||
raise NotImplementedError
|
||||
elif tp == types.IntType:
|
||||
# XXX factor out, is largely OK for CFF dicts, too.
|
||||
if -107 <= token <= 107:
|
||||
code = chr(token + 139)
|
||||
elif 108 <= token <= 1131:
|
||||
token = token - 108
|
||||
code = chr((token >> 8) + 247) + chr(token & 0xFF)
|
||||
elif -1131 <= token <= -108:
|
||||
token = -token - 108
|
||||
code = chr((token >> 8) + 251) + chr(token & 0xFF)
|
||||
elif -32768 <= token <= 32767:
|
||||
# XXX T2/CFF-specific: doesn't exist in T1
|
||||
code = chr(28) + struct.pack(">h", token)
|
||||
else:
|
||||
# XXX T1/T2-specific: different opcode in CFF
|
||||
code = chr(255) + struct.pack(">l", token)
|
||||
bytecode.append(code)
|
||||
bytecode.append(encodeIntT2(token))
|
||||
else:
|
||||
assert 0
|
||||
assert 0, "unsupported type: %s" % tp
|
||||
bytecode = "".join(bytecode)
|
||||
if DEBUG:
|
||||
assert bytecode == self.__bytecode
|
||||
|
||||
self.setBytecode(bytecode)
|
||||
|
||||
def needsDecompilation(self):
|
||||
return self.bytecode is not None
|
||||
|
||||
def setProgram(self, program):
|
||||
self.program = program
|
||||
if DEBUG:
|
||||
self.__bytecode = self.bytecode
|
||||
self.bytecode = None
|
||||
|
||||
def setBytecode(self, bytecode):
|
||||
self.bytecode = bytecode
|
||||
self.program = None
|
||||
|
||||
def getToken(self, index,
|
||||
len=len, ord=ord, getattr=getattr, type=type, StringType=types.StringType):
|
||||
if self.bytecode is not None:
|
||||
@ -847,7 +890,7 @@ class T1OutlineExtractor(T2OutlineExtractor):
|
||||
self.popall() # XXX
|
||||
|
||||
|
||||
class DictDecompiler(ByteCodeDecompilerBase):
|
||||
class DictDecompiler(ByteCodeBase):
|
||||
|
||||
operandEncoding = cffDictOperandEncoding
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user