major refactoring, now evaluates everything lazily, so it should be really fast if you only need (say) the glyph order.

git-svn-id: svn://svn.code.sf.net/p/fonttools/code/trunk@241 4cde692c-a291-49d1-8350-778aa11640f8
This commit is contained in:
jvr 2002-05-16 18:17:32 +00:00
parent 357d71b438
commit 4756b3a040

View File

@ -1,7 +1,7 @@
"""cffLib.py -- read/write tools for Adobe CFF fonts.""" """cffLib.py -- read/write tools for Adobe CFF fonts."""
# #
# $Id: cffLib.py,v 1.12 2002-05-15 07:41:30 jvr Exp $ # $Id: cffLib.py,v 1.13 2002-05-16 18:17:32 jvr Exp $
# #
import struct, sstruct import struct, sstruct
@ -20,36 +20,34 @@ cffHeaderFormat = """
class CFFFontSet: class CFFFontSet:
def __init__(self): def __init__(self):
self.fonts = {} pass
def decompile(self, file): def decompile(self, file):
sstruct.unpack(cffHeaderFormat, file.read(4), self) sstruct.unpack(cffHeaderFormat, file.read(4), self)
assert self.major == 1 and self.minor == 0, \ assert self.major == 1 and self.minor == 0, \
"unknown CFF format: %d.%d" % (self.major, self.minor) "unknown CFF format: %d.%d" % (self.major, self.minor)
self.fontNames = readINDEX(file) self.fontNames = list(Index(file))
topDicts = readINDEX(file) self.topDictIndex = TopDictIndex(file)
strings = IndexedStrings(readINDEX(file)) self.strings = IndexedStrings(list(Index(file)))
globalSubrs = readINDEX(file) self.GlobalSubrs = SubrsIndex(file)
self.topDictIndex.strings = self.strings
file.seek(4) def __len__(self):
xfnames = Index(file) return len(self.fontNames)
xtopds = Index(file)
xstrings = Index(file)
xgsubrs = Index(file)
assert xfnames.toList() == self.fontNames def keys(self):
assert xtopds.toList() == topDicts return self.fontNames[:]
assert xstrings.toList() == strings.strings
assert xgsubrs.toList() == globalSubrs
self.GlobalSubrs = map(psCharStrings.T2CharString, globalSubrs) def __getitem__(self, name):
try:
for i in range(len(topDicts)): index = self.fontNames.index(name)
font = self.fonts[self.fontNames[i]] = CFFFont() except ValueError:
raise KeyError, name
font = self.topDictIndex[index]
if not hasattr(font, "GlobalSubrs"):
font.GlobalSubrs = self.GlobalSubrs font.GlobalSubrs = self.GlobalSubrs
file.seek(0) return font
font.decompile(file, topDicts[i], strings, self)
def compile(self): def compile(self):
strings = IndexedStrings() strings = IndexedStrings()
@ -60,21 +58,14 @@ class CFFFontSet:
for fontName in self.fontNames: for fontName in self.fontNames:
xmlWriter.begintag("CFFFont", name=fontName) xmlWriter.begintag("CFFFont", name=fontName)
xmlWriter.newline() xmlWriter.newline()
font = self.fonts[fontName] font = self[fontName]
font.toXML(xmlWriter, progress) font.toXML(xmlWriter, progress)
xmlWriter.endtag("CFFFont") xmlWriter.endtag("CFFFont")
xmlWriter.newline() xmlWriter.newline()
xmlWriter.newline() xmlWriter.newline()
xmlWriter.begintag("GlobalSubrs") xmlWriter.begintag("GlobalSubrs")
xmlWriter.newline() xmlWriter.newline()
for i in range(len(self.GlobalSubrs)): self.GlobalSubrs.toXML(xmlWriter, progress)
xmlWriter.newline()
xmlWriter.begintag("CharString", index=i)
xmlWriter.newline()
self.GlobalSubrs[i].toXML(xmlWriter)
xmlWriter.endtag("CharString")
xmlWriter.newline()
xmlWriter.newline()
xmlWriter.endtag("GlobalSubrs") xmlWriter.endtag("GlobalSubrs")
xmlWriter.newline() xmlWriter.newline()
xmlWriter.newline() xmlWriter.newline()
@ -83,102 +74,347 @@ class CFFFontSet:
xxx xxx
class CFFFont: class Index:
def __init__(self): """This class represents what the CFF spec calls an INDEX."""
pass
def __getattr__(self, attr): def __init__(self, file):
if not topDictDefaults.has_key(attr): self.file = file
raise AttributeError, attr count, = struct.unpack(">H", file.read(2))
return topDictDefaults[attr] self.count = count
self.items = [None] * count
if count == 0:
self.offsets = []
return
offSize = ord(file.read(1))
self.offsets = offsets = []
pad = '\0' * (4 - offSize)
for index in range(count+1):
chunk = file.read(offSize)
chunk = pad + chunk
offset, = struct.unpack(">L", chunk)
offsets.append(int(offset))
self.offsetBase = file.tell() - 1
file.seek(self.offsetBase + offsets[-1]) # pretend we've read the whole lot
def fromDict(self, d): def __len__(self):
self.__dict__.update(d) return self.count
def decompile(self, file, topDictData, strings, fontSet): def __getitem__(self, index):
top = TopDictDecompiler(strings) item = self.items[index]
top.decompile(topDictData) if item is not None:
self.fromDict(top.getDict()) return item
offset = self.offsets[index] + self.offsetBase
if hasattr(self, "ROS"): size = self.offsets[index+1] - self.offsets[index]
isCID = 1 file = self.file
# XXX CID subFonts
offset = self.FDArray
file.seek(offset) file.seek(offset)
fontDicts = readINDEX(file) data = file.read(size)
subFonts = self.subFonts = [] assert len(data) == size
for topDictData in fontDicts: item = self.produceItem(data, file, offset, size)
subFont = CFFFont() self.items[index] = item
subFonts.append(subFont) return item
subFont.decompile(file, topDictData, strings, None)
# XXX
else:
isCID = 0
size, offset = self.Private
file.seek(offset)
privateData = file.read(size)
file.seek(offset)
assert len(privateData) == size
self.Private = PrivateDict()
self.Private.decompile(file, privateData, strings)
if hasattr(self, "CharStrings"): def produceItem(self, data, file, offset, size):
file.seek(self.CharStrings) return data
rawCharStrings = Index(file)
nGlyphs = len(rawCharStrings)
# get charset (or rather: get glyphNames)
if self.charset > 2: class SubrsIndex(Index):
file.seek(self.charset)
def produceItem(self, data, file, offset, size):
return psCharStrings.T2CharString(data)
def toXML(self, xmlWriter, progress):
for i in range(len(self)):
xmlWriter.begintag("CharString", index=i)
xmlWriter.newline()
self[i].toXML(xmlWriter)
xmlWriter.endtag("CharString")
xmlWriter.newline()
class CharStrings:
def __init__(self, file, charset):
self.charStringsIndex = SubrsIndex(file)
self.nameToIndex = nameToIndex = {}
for i in range(len(charset)):
nameToIndex[charset[i]] = i
def keys(self):
return self.nameToIndex.keys()
def has_key(self, name):
return self.nameToIndex.has_key(name)
def __getitem__(self, name):
index = self.nameToIndex[name]
return self.charStringsIndex[index]
def toXML(self, xmlWriter, progress):
names = self.keys()
names.sort()
for name in names:
xmlWriter.begintag("CharString", name=name)
xmlWriter.newline()
self[name].toXML(xmlWriter)
xmlWriter.endtag("CharString")
xmlWriter.newline()
class TopDictIndex(Index):
def produceItem(self, data, file, offset, size):
top = TopDict(self.strings, file, offset)
top.decompile(data)
return top
def buildOperatorDict(table):
d = {}
for op, name, arg, default, conv in table:
d[op] = (name, arg)
return d
def buildOrder(table):
l = []
for op, name, arg, default, conv in table:
l.append(name)
return l
def buildDefaults(table):
d = {}
for op, name, arg, default, conv in table:
if default is not None:
d[name] = default
return d
def buildConverters(table):
d = {}
for op, name, arg, default, conv in table:
d[name] = conv
return d
class PrivateDictConverter:
def read(self, parent, value):
size, offset = value
file = parent.file
pr = PrivateDict(parent.strings, file, offset)
file.seek(offset)
data = file.read(size)
len(data) == size
pr.decompile(data)
return pr
def xmlWrite(self, xmlWriter, name, value):
xmlWriter.begintag(name)
xmlWriter.newline()
value.toXML(xmlWriter, None)
xmlWriter.endtag(name)
xmlWriter.newline()
class SubrsConverter(PrivateDictConverter):
def read(self, parent, value):
file = parent.file
file.seek(parent.offset + value) # Offset(self)
return SubrsIndex(file)
class CharStringsConverter(PrivateDictConverter):
def read(self, parent, value):
file = parent.file
file.seek(value) # Offset(0)
return CharStrings(file, parent.charset)
class CharsetConverter:
def read(self, parent, value):
isCID = hasattr(parent, "ROS")
if value > 2:
numGlyphs = parent.numGlyphs
file = parent.file
file.seek(value)
format = ord(file.read(1)) format = ord(file.read(1))
if format == 0: if format == 0:
raise NotImplementedError raise NotImplementedError
elif format == 1: elif format == 1 or format == 2:
charset = parseCharsetFormat1(nGlyphs, file, strings, isCID) charset = parseCharset(numGlyphs, file, parent.strings, isCID, format)
elif format == 2:
charset = parseCharsetFormat2(nGlyphs, file, strings, isCID)
elif format == 3: elif format == 3:
raise NotImplementedError raise NotImplementedError
else: else:
raise NotImplementedError raise NotImplementedError
self.charset = charset assert len(charset) == numGlyphs
assert len(charset) == nGlyphs
else: else:
if isCID:
assert value == 0
charset = None
elif value == 0:
charset = ISOAdobe
elif value == 1:
charset = Expert
elif value == 2:
charset = ExpertSubset
# self.charset: # self.charset:
# 0: ISOAdobe (or CID font!) # 0: ISOAdobe (or CID font!)
# 1: Expert # 1: Expert
# 2: ExpertSubset # 2: ExpertSubset
charset = None #
return charset
def xmlWrite(self, xmlWriter, name, value):
# XXX GlyphOrder needs to be stored *somewhere*, but not here...
xmlWriter.simpletag("charset", value=value)
xmlWriter.newline()
def parseCharset(numGlyphs, file, strings, isCID, format):
charset = ['.notdef']
count = 1
if format == 1:
def nLeftFunc(file):
return ord(file.read(1))
else:
def nLeftFunc(file):
return struct.unpack(">H", file.read(2))[0]
while count < numGlyphs:
first, = struct.unpack(">H", file.read(2))
nLeft = nLeftFunc(file)
if isCID:
for CID in range(first, first+nLeft+1):
charset.append(CID)
else:
for SID in range(first, first+nLeft+1):
charset.append(strings[SID])
count = count + nLeft + 1
return charset
topDictOperators = [
# opcode name argument type default converter
(0, 'version', 'SID', None, None),
(1, 'Notice', 'SID', None, None),
((12, 0), 'Copyright', 'SID', None, None),
(2, 'FullName', 'SID', None, None),
(3, 'FamilyName', 'SID', None, None),
(4, 'Weight', 'SID', None, None),
((12, 1), 'isFixedPitch', 'number', 0, None),
((12, 2), 'ItalicAngle', 'number', 0, None),
((12, 3), 'UnderlinePosition', 'number', None, None),
((12, 4), 'UnderlineThickness', 'number', 50, None),
((12, 5), 'PaintType', 'number', 0, None),
((12, 6), 'CharstringType', 'number', 2, None),
((12, 7), 'FontMatrix', 'array', [0.001,0,0,0.001,0,0], None),
(13, 'UniqueID', 'number', None, None),
(5, 'FontBBox', 'array', [0,0,0,0], None),
((12, 8), 'StrokeWidth', 'number', 0, None),
(14, 'XUID', 'array', None, None),
(15, 'charset', 'number', 0, CharsetConverter()),
(16, 'Encoding', 'number', 0, None),
(18, 'Private', ('number','number'), None, PrivateDictConverter()),
(17, 'CharStrings', 'number', None, CharStringsConverter()), # XXX
((12, 20), 'SyntheticBase', 'number', None, None),
((12, 21), 'PostScript', 'SID', None, None),
((12, 22), 'BaseFontName', 'SID', None, None),
((12, 23), 'BaseFontBlend', 'delta', None, None),
((12, 30), 'ROS', ('SID','SID','number'), None, None),
((12, 31), 'CIDFontVersion', 'number', 0, None),
((12, 32), 'CIDFontRevision', 'number', 0, None),
((12, 33), 'CIDFontType', 'number', 0, None),
((12, 34), 'CIDCount', 'number', 8720, None),
((12, 35), 'UIDBase', 'number', None, None),
((12, 36), 'FDArray', 'number', None, None),
((12, 37), 'FDSelect', 'number', None, None),
((12, 38), 'FontName', 'SID', None, None),
]
privateDictOperators = [
# opcode name argument type default converter
(6, 'BlueValues', 'delta', None, None),
(7, 'OtherBlues', 'delta', None, None),
(8, 'FamilyBlues', 'delta', None, None),
(9, 'FamilyOtherBlues', 'delta', None, None),
((12, 9), 'BlueScale', 'number', 0.039625, None),
((12, 10), 'BlueShift', 'number', 7, None),
((12, 11), 'BlueFuzz', 'number', 1, None),
(10, 'StdHW', 'number', None, None),
(11, 'StdVW', 'number', None, None),
((12, 12), 'StemSnapH', 'delta', None, None),
((12, 13), 'StemSnapV', 'delta', None, None),
((12, 14), 'ForceBold', 'number', 0, None),
((12, 17), 'LanguageGroup', 'number', 0, None),
((12, 18), 'ExpansionFactor', 'number', 0.06, None),
((12, 19), 'initialRandomSeed', 'number', 0, None),
(20, 'defaultWidthX', 'number', 0, None),
(21, 'nominalWidthX', 'number', 0, None),
(19, 'Subrs', 'number', None, SubrsConverter()),
]
class TopDictDecompiler(psCharStrings.DictDecompiler):
operators = buildOperatorDict(topDictOperators)
class PrivateDictDecompiler(psCharStrings.DictDecompiler):
operators = buildOperatorDict(privateDictOperators)
class BaseDict:
def __init__(self, strings, file, offset):
self.rawDict = {}
self.file = file
self.offset = offset
self.strings = strings
def decompile(self, data):
dec = self.decompiler(self.strings)
dec.decompile(data)
self.rawDict = dec.getDict()
self.postDecompile()
def postDecompile(self):
pass pass
if hasattr(self, "CharStrings"): def __getattr__(self, name):
self.CharStrings = charStrings = {} value = self.rawDict.get(name)
if self.CharstringType == 2: if value is None:
# Type 2 CharStrings value = self.defaults.get(name)
charStringClass = psCharStrings.T2CharString if value is None:
else: raise AttributeError, name
# Type 1 CharStrings conv = self.converters[name]
charStringClass = psCharStrings.T1CharString if conv is not None:
for i in range(nGlyphs): value = conv.read(self, value)
charStrings[charset[i]] = charStringClass(rawCharStrings[i]) setattr(self, name, value)
assert len(charStrings) == nGlyphs return value
encoding = self.Encoding def toXML(self, xmlWriter, progress):
if encoding > 1: for name in self.order:
# encoding is an offset from the beginning of 'data' to an encoding subtable value = getattr(self, name, None)
raise NotImplementedError if value is None:
self.Encoding = encoding continue
conv = self.converters.get(name)
if conv is not None:
conv.xmlWrite(xmlWriter, name, value)
else: else:
# self.Encoding: if isinstance(value, types.ListType):
# 0 Standard Encoding value = " ".join(map(str, value))
# 1 Expert Encoding xmlWriter.simpletag(name, value=value)
pass xmlWriter.newline()
class TopDict(BaseDict):
defaults = buildDefaults(topDictOperators)
converters = buildConverters(topDictOperators)
order = buildOrder(topDictOperators)
decompiler = TopDictDecompiler
def getGlyphOrder(self): def getGlyphOrder(self):
return self.charset return self.charset
def setGlyphOrder(self, glyphOrder): def postDecompile(self):
self.charset = glyphOrder offset = self.rawDict.get("CharStrings")
if offset is None:
return
# get the number of glyphs beforehand.
self.file.seek(offset)
self.numGlyphs, = struct.unpack(">H", self.file.read(2))
def decompileAllCharStrings(self): def decompileAllCharStrings(self):
if self.CharstringType == 2: if self.CharstringType == 2:
@ -193,300 +429,16 @@ class CFFFont:
for charString in self.CharStrings.values(): for charString in self.CharStrings.values():
charString.decompile() charString.decompile()
def toXML(self, xmlWriter, progress=None):
xmlWriter.newline() class PrivateDict(BaseDict):
genericToXML(self, topDictOrder, {'CharStrings': 'CharString'}, xmlWriter) defaults = buildDefaults(privateDictOperators)
converters = buildConverters(privateDictOperators)
order = buildOrder(privateDictOperators)
decompiler = PrivateDictDecompiler
class PrivateDict:
def __init__(self):
pass
def decompile(self, file, privateData, strings):
p = PrivateDictDecompiler(strings)
p.decompile(privateData)
self.fromDict(p.getDict())
# get local subrs
if hasattr(self, "Subrs"):
file.seek(self.Subrs, 1)
localSubrs = Index(file)
self.Subrs = map(psCharStrings.T2CharString, localSubrs)
else:
self.Subrs = []
def toXML(self, xmlWriter):
xmlWriter.newline()
genericToXML(self, privateDictOrder, {'Subrs': 'CharString'}, xmlWriter)
def __getattr__(self, attr):
if not privateDictDefaults.has_key(attr):
raise AttributeError, attr
return privateDictDefaults[attr]
def fromDict(self, d):
self.__dict__.update(d)
def readINDEX(file):
count, = struct.unpack(">H", file.read(2))
if count == 0:
return []
offSize = ord(file.read(1))
offsets = []
for index in range(count+1):
chunk = file.read(offSize)
chunk = '\0' * (4 - offSize) + chunk
offset, = struct.unpack(">L", chunk)
offset = int(offset)
offsets.append(offset)
offsetBase = file.tell() - 1
prev = offsets[0]
stuff = []
for next in offsets[1:]:
assert offsetBase + prev == file.tell()
chunk = file.read(next - prev)
assert len(chunk) == next - prev
stuff.append(chunk)
prev = next
return stuff
class Index:
def __init__(self, file):
self.file = file
count, = struct.unpack(">H", file.read(2))
self.count = count
if count == 0:
self.offsets = []
return
offSize = ord(file.read(1))
self.offsets = offsets = []
pad = '\0' * (4 - offSize)
for index in range(count+1):
chunk = file.read(offSize)
chunk = pad + chunk
offset, = struct.unpack(">L", chunk)
offsets.append(int(offset))
self.offsetBase = file.tell() - 1
file.seek(self.offsetBase + offsets[-1])
def __len__(self):
return self.count
def __getitem__(self, index):
offset = self.offsets[index] + self.offsetBase
size = self.offsets[index+1] - self.offsets[index]
return FileString(self.file, offset, size)
def toList(self):
l = []
for item in self:
l.append(item[:])
return l
class FileString:
def __init__(self, file, offset, size):
self.file = file
self.offset = offset
self.size = size
self.string = None
def __len__(self):
return self.size
def __getitem__(self, index):
return self.get()[index]
def __getslice__(self, i, j):
return self.get()[i:j]
def get(self):
if self.string is None:
self.file.seek(self.offset)
self.string = self.file.read(self.size)
return self.string
def getItems(o):
if hasattr(o, "items"):
items = o.items()
items.sort()
return "name", items
else:
return "index", map(None, range(len(o)), o)
def genericToXML(obj, order, arrayTypes, xmlWriter):
for name in order:
value = getattr(obj, name, None)
if value is None:
continue
if hasattr(value, "toXML"):
xmlWriter.newline()
xmlWriter.begintag(name)
xmlWriter.newline()
value.toXML(xmlWriter)
xmlWriter.endtag(name)
xmlWriter.newline()
xmlWriter.newline()
elif arrayTypes.has_key(name):
typeName = arrayTypes[name]
xmlWriter.newline()
xmlWriter.begintag(name)
xmlWriter.newline()
xmlWriter.newline()
label, items = getItems(value)
for k, v in items:
xmlWriter.begintag(typeName, [(label, k)])
xmlWriter.newline()
v.toXML(xmlWriter)
xmlWriter.endtag(typeName)
xmlWriter.newline()
xmlWriter.newline()
xmlWriter.endtag(name)
xmlWriter.newline()
xmlWriter.newline()
else:
if isinstance(value, types.ListType):
value = " ".join(map(str, value))
xmlWriter.simpletag(name, value=value)
xmlWriter.newline()
def parseCharsetFormat1(nGlyphs, file, strings, isCID):
charset = ['.notdef']
count = 1
while count < nGlyphs:
first, = struct.unpack(">H", file.read(2))
nLeft = ord(file.read(1))
if isCID:
for CID in range(first, first+nLeft+1):
charset.append(CID)
else:
for SID in range(first, first+nLeft+1):
charset.append(strings[SID])
count = count + nLeft + 1
return charset
def parseCharsetFormat2(nGlyphs, file, strings, isCID):
charset = ['.notdef']
count = 1
while count < nGlyphs:
first, = struct.unpack(">H", file.read(2))
nLeft, = struct.unpack(">H", file.read(2))
if isCID:
for CID in range(first, first+nLeft+1):
charset.append(CID)
else:
for SID in range(first, first+nLeft+1):
charset.append(strings[SID])
count = count + nLeft + 1
return charset
def buildOperatorDict(table):
d = {}
for row in table:
d[row[0]] = row[1:3]
return d
def buildOrder(table):
l = []
for row in table:
l.append(row[1])
return l
def buildDefaults(table):
d = {}
for row in table:
if row[3] is not None:
d[row[1]] = row[3]
return d
topDictOperators = [
# opcode name argument type default
(0, 'version', 'SID', None),
(1, 'Notice', 'SID', None),
((12, 0), 'Copyright', 'SID', None),
(2, 'FullName', 'SID', None),
(3, 'FamilyName', 'SID', None),
(4, 'Weight', 'SID', None),
((12, 1), 'isFixedPitch', 'number', 0),
((12, 2), 'ItalicAngle', 'number', 0),
((12, 3), 'UnderlinePosition', 'number', None),
((12, 4), 'UnderlineThickness', 'number', 50),
((12, 5), 'PaintType', 'number', 0),
((12, 6), 'CharstringType', 'number', 2),
((12, 7), 'FontMatrix', 'array', [0.001,0,0,0.001,0,0]),
(13, 'UniqueID', 'number', None),
(5, 'FontBBox', 'array', [0,0,0,0]),
((12, 8), 'StrokeWidth', 'number', 0),
(14, 'XUID', 'array', None),
(15, 'charset', 'number', 0),
(16, 'Encoding', 'number', 0),
(18, 'Private', ('number','number'), None),
(17, 'CharStrings', 'number', None),
((12, 20), 'SyntheticBase', 'number', None),
((12, 21), 'PostScript', 'SID', None),
((12, 22), 'BaseFontName', 'SID', None),
((12, 23), 'BaseFontBlend', 'delta', None),
((12, 30), 'ROS', ('SID','SID','number'), None),
((12, 31), 'CIDFontVersion', 'number', 0),
((12, 32), 'CIDFontRevision', 'number', 0),
((12, 33), 'CIDFontType', 'number', 0),
((12, 34), 'CIDCount', 'number', 8720),
((12, 35), 'UIDBase', 'number', None),
((12, 36), 'FDArray', 'number', None),
((12, 37), 'FDSelect', 'number', None),
((12, 38), 'FontName', 'SID', None),
]
topDictDefaults = buildDefaults(topDictOperators)
topDictOrder = buildOrder(topDictOperators)
class TopDictDecompiler(psCharStrings.DictDecompiler):
operators = buildOperatorDict(topDictOperators)
dictDefaults = topDictDefaults
privateDictOperators = [
# opcode name argument type default
(6, 'BlueValues', 'delta', None),
(7, 'OtherBlues', 'delta', None),
(8, 'FamilyBlues', 'delta', None),
(9, 'FamilyOtherBlues', 'delta', None),
((12, 9), 'BlueScale', 'number', 0.039625),
((12, 10), 'BlueShift', 'number', 7),
((12, 11), 'BlueFuzz', 'number', 1),
(10, 'StdHW', 'number', None),
(11, 'StdVW', 'number', None),
((12, 12), 'StemSnapH', 'delta', None),
((12, 13), 'StemSnapV', 'delta', None),
((12, 14), 'ForceBold', 'number', 0),
((12, 17), 'LanguageGroup', 'number', 0),
((12, 18), 'ExpansionFactor', 'number', 0.06),
((12, 19), 'initialRandomSeed', 'number', 0),
(20, 'defaultWidthX', 'number', 0),
(21, 'nominalWidthX', 'number', 0),
(19, 'Subrs', 'number', None),
]
privateDictDefaults = buildDefaults(privateDictOperators)
privateDictOrder = buildOrder(privateDictOperators)
class PrivateDictDecompiler(psCharStrings.DictDecompiler):
operators = buildOperatorDict(privateDictOperators)
dictDefaults = privateDictDefaults
# SID
class IndexedStrings: class IndexedStrings: