def fromvalidatedwalker(cls, w, **kwArgs): """ Creates and returns a new ScriptDict object from the specified walker, doing source validation. The following keyword arguments are supported: logger A logger to which messages will be posted. """ logger = kwArgs.pop('logger', logging.getLogger()) logger = logger.getChild('scriptdict') logger.debug(( 'V0001', (w.length(),), "Walker has %d remaining bytes.")) if w.length() < 2: logger.error(('V0004', (), "Insufficient bytes.")) return None groupCount = w.unpack("H") logger.debug(('Vxxxx', (groupCount,), "Group count is %d")) if w.length() < 6 * groupCount: logger.error(( 'V0413', (), "The ScriptRecords are missing or incomplete.")) return None scriptRecs = w.group("4sH", groupCount) r = cls() fvw = langsysdict.LangSysDict.fromvalidatedwalker for tag, offset in scriptRecs: logger.debug(( 'Vxxxx', (utilities.ensureUnicode(tag), offset), "Script rec for tag '%s' at offset %d")) obj = fvw( w.subWalker(offset), logger = logger.getChild("script %s" % (utilities.ensureUnicode(tag),)), **kwArgs) if obj is None: return None r[tag] = obj return r
class RecordDict(dict, metaclass=mapmeta.FontDataMetaclass): """ Objects representing collections of Records. These are dicts whose keys are 4-byte tags and whose values are Record objects. >>> _testingValues[1].pprint(namer=namer.testingNamer()) Feature 'abcd': Minimum coordinate: Coordinate: 0 Maximum coordinate: Coordinate: 15 Device table: Tweak at 12 ppem: -2 Tweak at 14 ppem: -1 Tweak at 18 ppem: 1 Feature 'wxyz': Maximum coordinate: Coordinate: -10 Glyph: xyz15 Point: 12 """ # # Class definition variables # mapSpec = dict(item_followsprotocol=True, item_pprintlabelfunc=(lambda k: "Feature '%s'" % (utilities.ensureUnicode(k), )))
class LangSysDict(dict, metaclass=mapmeta.FontDataMetaclass): """ Objects mapping LangSys tags to MinMax objects. >>> _testingValues[1].pprint(namer=namer.testingNamer()) LangSys 'enUS': Minimum coordinate: Coordinate: -20 Maximum coordinate: Coordinate: 0 Glyph: xyz26 Point: 9 LangSys 'span': Minimum coordinate: Coordinate: -10 Device table: Tweak at 12 ppem: -5 Tweak at 13 ppem: -3 Tweak at 14 ppem: -1 Tweak at 18 ppem: 2 Tweak at 20 ppem: 3 Maximum coordinate: Coordinate: 0 Glyph: xyz26 Point: 9 Feature-specific MinMax values: Feature 'abcd': Minimum coordinate: Coordinate: 0 Maximum coordinate: Coordinate: 15 Device table: Tweak at 12 ppem: -2 Tweak at 14 ppem: -1 Tweak at 18 ppem: 1 Feature 'wxyz': Maximum coordinate: Coordinate: -10 Glyph: xyz15 Point: 12 """ # # Class definition variables # mapSpec = dict(item_followsprotocol=True, item_pprintlabelfunc=(lambda k: "LangSys '%s'" % (utilities.ensureUnicode(k), )))
class JSTF(dict, metaclass=mapmeta.FontDataMetaclass): """ Objects representing entire 'JSTF' tables. These are dicts whose keys are script tags and whose values are JstfScript objects. """ # # Class definition variables # mapSpec = dict(item_followsprotocol=True, item_pprintlabelfunc=(lambda k: "Script '%s'" % (utilities.ensureUnicode(k), ))) # # Methods # def buildBinary(self, w, **kwArgs): """ Adds the binary data for the JSTF object to the specified LinkedWriter. There is one required keyword argument: editor The Editor-class object. This is used to obtain the LookupLists for the GPOS and GSUB references made in this JSTF table. """ if 'stakeValue' in kwArgs: stakeValue = kwArgs.pop('stakeValue') w.stakeCurrentWithValue(stakeValue) else: stakeValue = w.stakeCurrent() w.add("L", 0x10000) # version w.add("H", len(self)) dStakes = {} # immut -> (obj, stake) ig0 = operator.itemgetter(0) for key, obj in sorted(self.items(), key=ig0): immut = obj.asImmutable(**kwArgs) if immut not in dStakes: dStakes[immut] = (obj, w.getNewStake()) w.addUnresolvedOffset("H", stakeValue, dStakes[immut][1]) for immut, (obj, stake) in sorted(dStakes.items(), key=ig0): obj.buildBinary(w, stakeValue=stake, **kwArgs) @classmethod def fromwalker(cls, w, **kwArgs): """ Creates and returns a JSTF object from the specified walker. There is one required keyword argument: editor The Editor-class object. This is used to obtain the LookupLists for the GPOS and GSUB references made in this JSTF table. """ version = w.unpack("L") if version != 0x10000: raise ValueError("Unknown 'JSTF' version: 0x%08X" % (version, )) r = cls() fw = jstfscript.JstfScript.fromwalker for tag, offset in w.group("4sH", w.unpack("H")): r[tag] = fw(w.subWalker(offset), **kwArgs) return r
def bestNameForGlyphIndex(self, glyphIndex, **kwArgs): """ Finds the best name for a glyph. :param int glyphIndex: The glyph needing a name :param kwArgs: Optional keyword arguments (none currently used) :return: The best name for the specified glyph :rtype: str The name will be obtained from the first source found in the following prioritized list: - ``'Zapf'`` name - ``'post'`` name - Unicode name (if enabled and Unicode is present) - U+nnnn or U+nnnnnn name (if Unicode is present) - The glyph index as a string >>> d = {'remapAFII': False, 'useUnicodeName': False, 'annotate': False} >>> f = testingNamer(**d).bestNameForGlyphIndex >>> f(10), f(77), f(95), f(99), f(300) ('xyz11', 'xyz78', 'afii60000', 'U+0163', '300') >>> d['useUnicodeName'] = True >>> f = testingNamer(**d).bestNameForGlyphIndex >>> f(10), f(77), f(95), f(99) ('xyz11', 'xyz78', 'afii60000', 'LATIN SMALL LETTER T WITH CEDILLA') >>> d['remapAFII'] = True >>> d['useUnicodeName'] = False >>> f = testingNamer(**d).bestNameForGlyphIndex >>> f(10), f(77), f(95), f(99) ('xyz11', 'xyz78', 'U+015F', 'U+0163') >>> d['useUnicodeName'] = True >>> f = testingNamer(**d).bestNameForGlyphIndex >>> f(10), f(77), f(95), f(99) ('xyz11', 'xyz78', 'LATIN SMALL LETTER S WITH CEDILLA', 'LATIN SMALL LETTER T WITH CEDILLA') >>> d = {'remapAFII': False, 'useUnicodeName': False, 'annotate': True} >>> f = testingNamer(**d).bestNameForGlyphIndex >>> for s in (f(10), f(77), f(95), f(99), f(300)): print(s) xyz11 (glyph 10) xyz78 (glyph 77) afii60000 (glyph 95) U+0163 (glyph 99) 300 >>> d['useUnicodeName'] = True >>> f = testingNamer(**d).bestNameForGlyphIndex >>> for s in (f(10), f(77), f(95), f(99)): print(s) xyz11 (glyph 10) xyz78 (glyph 77) afii60000 (glyph 95) LATIN SMALL LETTER T WITH CEDILLA (glyph 99) >>> d['remapAFII'] = True >>> d['useUnicodeName'] = False >>> f = testingNamer(**d).bestNameForGlyphIndex >>> for s in (f(10), f(77), f(95), f(99)): print(s) xyz11 (glyph 10) xyz78 (glyph 77) U+015F (glyph 95) U+0163 (glyph 99) >>> d['useUnicodeName'] = True >>> f = testingNamer(**d).bestNameForGlyphIndex >>> for s in (f(10), f(77), f(95), f(99)): print(s) xyz11 (glyph 10) xyz78 (glyph 77) LATIN SMALL LETTER S WITH CEDILLA (glyph 95) LATIN SMALL LETTER T WITH CEDILLA (glyph 99) >>> d = {'useFontWorkerName': True} >>> f = testingNamer(**d).bestNameForGlyphIndex >>> for s in (f(10), f(95), f(99), f(500)): print(s) xyz11 afii60000 u 0163 # 500 >>> f = CFFtestingNamer().bestNameForGlyphIndex >>> for s in (f(5), f(10)): print(s) cff5 cff10 >>> f = CFFtestingNamer(annotate=True, useUnicodeName=True).bestNameForGlyphIndex >>> for s in (f(49), f(50)): print(s) cff49 (glyph 49) LATIN CAPITAL LETTER R (glyph 50) >>> f = CFFtestingNamer().bestNameForGlyphIndex >>> f(None) >>> d['useUnicodeName'] = False >>> f = testingNamer(**d).bestNameForGlyphIndex >>> for s in (f(65535), f(65536), f(65537), f(65534), f(65533)): print(s) # 65535 # 65536 # 65537 # 65534 # 65533 >>> d = {'remapAFII': False, 'useUnicodeName': False, 'annotate': False} """ #>>> a = fontedit.Editor() #>>> currentDir = os.getcwd() #>>> pathFont4 = os.path.join( currentDir,'qe','testfontdata','Zapfino.ttf') #>>> b4 = a.frompath(pathFont4) #>>> nZapfinottf = Namer(b4, **d) #>>> nZapfinottf.bestNameForGlyphIndex(79) #'S.4' #>>> d['useUnicodeName']= True #>>> nZapfinottf = Namer(b4, **d) #>>> nZapfinottf.bestNameForGlyphIndex(34) #'H.3' #>>> d['useFontWorkerName']= True #>>> nZapfinottf = Namer(b4, **d) #>>> nZapfinottf.bestNameForGlyphIndex(65339) #'# 65339' if glyphIndex is None: return None if self.useFontWorkerName: self.annotate = False self.remapAFII = False self.useUnicodeName = False self._makeMaps() uNameFromZapf = None annotation = (" (glyph %d)" % (glyphIndex, ) if self.annotate else "") if glyphIndex in self._zapfTable: kn = self._zapfTable[glyphIndex].kindNames if kn: s = kn.bestName() if s is not None: return "%s%s" % (s, annotation) if glyphIndex in self._cffCharset: b = self._cffCharset[glyphIndex] s = str(utilities.ensureUnicode(b)) if not (self.remapAFII and s.startswith('afii')): return "%s%s" % (s, annotation) if glyphIndex in self._glyphToPost: s = self._glyphToPost[glyphIndex] if not (self.remapAFII and s.startswith('afii')): return "%s%s" % (s, annotation) if glyphIndex not in self._glyphToUnicode: if self.useFontWorkerName: return "# %d" % (glyphIndex, ) return str(glyphIndex) u = self._glyphToUnicode[glyphIndex] if self.useUnicodeName: try: s = unicodedata.name(chr(u), None) except ValueError: # unichr(0x10001) fails in narrow builds... bs = utilitiesbackend.utPack('L', u) s = unicodedata.name(str(bs, 'utf-32be'), None) if s is not None: return "%s%s" % (s, annotation) if self.useFontWorkerName: if u <= 0xFFFF: return "u %04X" % (u, ) return "u %X" % (u, ) if u <= 0xFFFF: return "U+%04X%s" % (u, annotation) return "U+%06X%s" % (u, annotation)
class JstfScript(dict, metaclass=mapmeta.FontDataMetaclass): """ Objects representing JstfScript tables. These are dicts mapping langSys tags to JstfLangSys objects. In addition, the following attributes are present: extenders An Extenders object, or None. defaultJstfLangSys The default JstfLangSys object, or None. """ # # Class definition variables # mapSpec = dict( item_followsprotocol = True, item_pprintlabelfunc = ( lambda k: "LangSys '%s'" % (utilities.ensureUnicode(k),))) attrSpec = dict( extenders = dict( attr_followsprotocol = True, attr_label = "Extender glyphs", attr_showonlyiffunc = functools.partial(operator.is_not, None)), defaultJstfLangSys = dict( attr_followsprotocol = True, attr_label = "Default JstfLangSys", attr_showonlyiffunc = functools.partial(operator.is_not, None))) attrSorted = ('extenders', 'defaultJstfLangSys') # # Methods # def buildBinary(self, w, **kwArgs): """ Adds the binary data for the JstfScript object to the specified LinkedWriter. """ if 'stakeValue' in kwArgs: stakeValue = kwArgs.pop('stakeValue') w.stakeCurrentWithValue(stakeValue) else: stakeValue = w.stakeCurrent() if self.extenders is None: w.add("H", 0) else: exStake = w.getNewStake() w.addUnresolvedOffset("H", stakeValue, exStake) if self.defaultJstfLangSys is None: w.add("H", 0) else: dsStake = w.getNewStake() w.addUnresolvedOffset("H", stakeValue, dsStake) w.add("H", len(self)) dStakes = {} # immut -> (obj, stake) ig0 = operator.itemgetter(0) for key, obj in sorted(self.items(), key=ig0): immut = obj.asImmutable(**kwArgs) if immut not in dStakes: dStakes[immut] = (obj, w.getNewStake()) w.add("4s", key) w.addUnresolvedOffset("H", stakeValue, dStakes[immut][1]) # Now add the deferred content if self.extenders is not None: self.extenders.buildBinary(w, stakeValue=exStake, **kwArgs) if self.defaultJstfLangSys is not None: self.defaultJstfLangSys.buildBinary( w, stakeValue = dsStake, **kwArgs) for immut, (obj, stake) in sorted(dStakes.items(), key=ig0): obj.buildBinary(w, stakeValue=stake, **kwArgs) @classmethod def fromwalker(cls, w, **kwArgs): """ Creates and returns a JstfScript object from the specified walker. """ offset = w.unpack("H") fw = extenders.Extenders.fromwalker ex = (fw(w.subWalker(offset), **kwArgs) if offset else None) offset = w.unpack("H") fw = jstflangsys.JstfLangSys.fromwalker dflt = (fw(w.subWalker(offset), **kwArgs) if offset else None) r = cls({}, extenders=ex, defaultJstfLangSys=dflt) for tag, offset in w.group("4sH", w.unpack("H")): r[tag] = fw(w.subWalker(offset), **kwArgs) return r
class BaseScript(dict, metaclass=mapmeta.FontDataMetaclass): """ Objects containing all the baseline information for a single script. These are dicts whose keys are baseline tags (4-byte bytestrings) and whose values are Coordinate objects of one kind or another. >>> _testingValues[1].pprint(namer=namer.testingNamer()) Baseline 'abcd': Coordinate: -20 Baseline 'wxyz': Coordinate: -10 Device table: Tweak at 12 ppem: -5 Tweak at 13 ppem: -3 Tweak at 14 ppem: -1 Tweak at 18 ppem: 2 Tweak at 20 ppem: 3 Default baseline tag: 'wxyz' Default MinMax data: Minimum coordinate: Coordinate: -20 Maximum coordinate: Coordinate: 0 Glyph: xyz26 Point: 9 LangSys-specific data: LangSys 'enUS': Minimum coordinate: Coordinate: -20 Maximum coordinate: Coordinate: 0 Glyph: xyz26 Point: 9 LangSys 'span': Minimum coordinate: Coordinate: -10 Device table: Tweak at 12 ppem: -5 Tweak at 13 ppem: -3 Tweak at 14 ppem: -1 Tweak at 18 ppem: 2 Tweak at 20 ppem: 3 Maximum coordinate: Coordinate: 0 Glyph: xyz26 Point: 9 Feature-specific MinMax values: Feature 'abcd': Minimum coordinate: Coordinate: 0 Maximum coordinate: Coordinate: 15 Device table: Tweak at 12 ppem: -2 Tweak at 14 ppem: -1 Tweak at 18 ppem: 1 Feature 'wxyz': Maximum coordinate: Coordinate: -10 Glyph: xyz15 Point: 12 >>> obj = _testingValues[1].__deepcopy__() >>> obj.defaultTag = b'anne' >>> logger = utilities.makeDoctestLogger("basescript_test") >>> e = _fakeEditor() >>> obj.isValid(logger=logger, editor=e) basescript_test - ERROR - The default tag is 'anne', which is not present in the currently defined keys ['abcd', 'wxyz']. False """ # # Class definition variables # mapSpec = dict(item_deepconverterfunc=( lambda n, **k: coordinate_simple.Coordinate_simple(n)), item_followsprotocol=True, item_pprintlabelfunc=(lambda k: "Baseline '%s'" % (utilities.ensureUnicode(k), )), map_validatefunc_partial=_validate) attrSpec = dict(defaultTag=dict( attr_label="Default baseline tag", attr_pprintfunc=(lambda p, x, label, **k: p.simple( "'%s'" % (utilities.ensureUnicode(x), ), label=label, **k))), defaultMinMax=dict(attr_followsprotocol=True, attr_label="Default MinMax data", attr_showonlyiffunc=functools.partial( operator.is_not, None)), langSysDict=dict( attr_followsprotocol=True, attr_initfunc=basescript_langsysdict.LangSysDict, attr_label="LangSys-specific data", attr_showonlyiftrue=True)) attrSorted = ('defaultTag', 'defaultMinMax', 'langSysDict') # # Methods # def buildBinary(self, w, **kwArgs): """ Adds the binary data for the BaseScript object to the specified LinkedWriter. >>> tl = (b'abcd', b'wxyz') >>> utilities.hexdump(_testingValues[1].binaryString(tagList=tl)) 0 | 0012 001A 0002 656E 5553 002C 7370 616E |......enUS.,span| 10 | 003E 0001 0002 007C 0076 000E 0006 0000 |.>.....|.v......| 20 | 0002 0000 0019 0009 0001 FFEC 000E 0006 |................| 30 | 0000 0002 0000 0019 0009 0001 FFEC 0016 |................| 40 | 002A 0002 6162 6364 0032 001C 7778 797A |.*..abcd.2..wxyz| 50 | 0000 0022 0003 FFF6 0020 0003 000F 0026 |..."..... .....&| 60 | 0002 FFF6 000E 000C 0002 0000 0019 0009 |................| 70 | 0001 0000 000C 0014 0002 BDF0 0020 3000 |............. 0.| 80 | 000C 0012 0001 8C04 0003 FFF6 000A 0001 |................| 90 | FFEC 000C 0014 0002 BDF0 0020 3000 |........... 0. | """ if 'stakeValue' in kwArgs: stakeValue = kwArgs.pop('stakeValue') w.stakeCurrentWithValue(stakeValue) else: stakeValue = w.stakeCurrent() doLocalCoords = 'coordinatePool' not in kwArgs coordPool = kwArgs.pop('coordinatePool', {}) doLocalDevs = 'devicePool' not in kwArgs devPool = kwArgs.pop('devicePool', {}) tagList = kwArgs['tagList'] # effectively an index-to-tag map if set(self) - set(tagList): raise ValueError("Tags in BaseScript not in base tag list!") bvStake = w.getNewStake() w.addUnresolvedOffset("H", stakeValue, bvStake) if self.defaultMinMax is not None: dmmStake = w.getNewStake() w.addUnresolvedOffset("H", stakeValue, dmmStake) else: w.add("H", 0) w.add("H", len(self.langSysDict)) lsStakes = {} for key in sorted(self.langSysDict): obj = self.langSysDict[key] w.add("4s", key) lsStakes[key] = w.getNewStake() w.addUnresolvedOffset("H", stakeValue, lsStakes[key]) # Add the actual base values ig0 = operator.itemgetter(0) w.stakeCurrentWithValue(bvStake) w.add("2H", tagList.index(self.defaultTag), len(tagList)) for tag in tagList: if tag in self and self[tag] is not None: # If the user did arithmetic on a simple coordinate, it will # have been demoted to a simple int. We need to cope with that. obj = self[tag] try: obj.asImmutable except AttributeError: obj = coordinate_simple.Coordinate_simple(obj) immut = obj.asImmutable(**kwArgs) if immut not in coordPool: coordPool[immut] = (obj, w.getNewStake()) w.addUnresolvedOffset("H", bvStake, coordPool[immut][1]) else: w.add("H", 0) # Add the default minmax, if present if self.defaultMinMax is not None: self.defaultMinMax.buildBinary(w, stakeValue=dmmStake, **kwArgs) # Add the langsys objects, if present for key in sorted(self.langSysDict): self.langSysDict[key].buildBinary(w, stakeValue=lsStakes[key], **kwArgs) if doLocalCoords: for immut, (obj, stake) in sorted(coordPool.items(), key=ig0): obj.buildBinary(w, stakeValue=stake, devicePool=devPool, **kwArgs) if doLocalDevs: for immut, (obj, stake) in sorted(devPool.items(), key=ig0): obj.buildBinary(w, stakeValue=stake, **kwArgs) @classmethod def fromvalidatedwalker(cls, w, **kwArgs): """ Creates and returns a BaseScript object from the specified walker. The following keyword arguments are used: logger A logger to which messages will be posted. tagList A sequence of bytestrings representing tags. This is required. >>> TL = (b'abcd', b'wxyz') >>> s = _testingValues[1].binaryString(tagList=TL) >>> logger = utilities.makeDoctestLogger("basescript_fvw") >>> fvb = BaseScript.fromvalidatedbytes >>> obj = fvb(s, logger=logger, tagList=TL) basescript_fvw.basescript - DEBUG - Walker has 158 remaining bytes. basescript_fvw.basescript.tag 'abcd'.coordinate - DEBUG - Coordinate format 1. basescript_fvw.basescript.tag 'abcd'.coordinate_simple - DEBUG - Walker has 16 remaining bytes. basescript_fvw.basescript.tag 'wxyz'.coordinate - DEBUG - Coordinate format 3. basescript_fvw.basescript.tag 'wxyz'.coordinate_device - DEBUG - Walker has 22 remaining bytes. basescript_fvw.basescript.tag 'wxyz'.coordinate_device.device - DEBUG - Walker has 12 remaining bytes. basescript_fvw.basescript.tag 'wxyz'.coordinate_device.device - DEBUG - StartSize=12, endSize=20, format=2 basescript_fvw.basescript.tag 'wxyz'.coordinate_device.device - DEBUG - Data are (48624, 32, 12288) basescript_fvw.basescript.default minmax.minmax - DEBUG - Walker has 132 remaining bytes. basescript_fvw.basescript.default minmax.minmax.minimum.coordinate - DEBUG - Coordinate format 1. basescript_fvw.basescript.default minmax.minmax.minimum.coordinate_simple - DEBUG - Walker has 118 remaining bytes. basescript_fvw.basescript.default minmax.minmax.maximum.coordinate - DEBUG - Coordinate format 2. basescript_fvw.basescript.default minmax.minmax.maximum.coordinate_point - DEBUG - Walker has 126 remaining bytes. basescript_fvw.basescript.langsys 'enUS'.minmax - DEBUG - Walker has 114 remaining bytes. basescript_fvw.basescript.langsys 'enUS'.minmax.minimum.coordinate - DEBUG - Coordinate format 1. basescript_fvw.basescript.langsys 'enUS'.minmax.minimum.coordinate_simple - DEBUG - Walker has 100 remaining bytes. basescript_fvw.basescript.langsys 'enUS'.minmax.maximum.coordinate - DEBUG - Coordinate format 2. basescript_fvw.basescript.langsys 'enUS'.minmax.maximum.coordinate_point - DEBUG - Walker has 108 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax - DEBUG - Walker has 96 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax.minimum.coordinate - DEBUG - Coordinate format 3. basescript_fvw.basescript.langsys 'span'.minmax.minimum.coordinate_device - DEBUG - Walker has 74 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax.minimum.coordinate_device.device - DEBUG - Walker has 42 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax.minimum.coordinate_device.device - DEBUG - StartSize=12, endSize=20, format=2 basescript_fvw.basescript.langsys 'span'.minmax.minimum.coordinate_device.device - DEBUG - Data are (48624, 32, 12288) basescript_fvw.basescript.langsys 'span'.minmax.maximum.coordinate - DEBUG - Coordinate format 2. basescript_fvw.basescript.langsys 'span'.minmax.maximum.coordinate_point - DEBUG - Walker has 54 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate - DEBUG - Coordinate format 1. basescript_fvw.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_simple - DEBUG - Walker has 46 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate - DEBUG - Coordinate format 3. basescript_fvw.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device - DEBUG - Walker has 68 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device.device - DEBUG - Walker has 30 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device.device - DEBUG - StartSize=12, endSize=18, format=1 basescript_fvw.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device.device - DEBUG - Data are (35844,) basescript_fvw.basescript.langsys 'span'.minmax.tag 'wxyz'.coordinate - DEBUG - Coordinate format 2. basescript_fvw.basescript.langsys 'span'.minmax.tag 'wxyz'.coordinate_point - DEBUG - Walker has 62 remaining bytes. >>> obj == _testingValues[1] True """ tagList = kwArgs['tagList'] logger = kwArgs.pop('logger', logging.getLogger()) logger = logger.getChild("basescript") logger.debug( ('V0001', (w.length(), ), "Walker has %d remaining bytes.")) if w.length() < 6: logger.error(('V0004', (), "Insufficient bytes.")) return None r = cls() valuesOffset, defaultMMOffset, lsCount = w.unpack("3H") wSub = w.subWalker(valuesOffset) if wSub.length() < 2: logger.error(('V0641', (), "The default tag index is missing or incomplete.")) return None r.defaultTag = tagList[wSub.unpack("H")] if wSub.length() < 2: logger.error(('V0642', (), "The count is missing or incomplete.")) return None count = wSub.unpack("H") if count and (count != len(tagList)): logger.error(('V0643', ( count, len(tagList) ), "The BaseValues count is %d, but the length of the BaseTagList " "is %d")) return None if wSub.length() < 2 * count: logger.error( ('V0644', (), "The BaseValues list is missing or incomplete.")) return None fvw = coordinate.Coordinate_validated offsets = wSub.group("H", count) for tag, offset in zip(tagList, offsets): itemLogger = logger.getChild("tag '%s'" % (utilities.ensureUnicode(tag), )) obj = fvw(wSub.subWalker(offset), logger=itemLogger, **kwArgs) if obj is None: return None r[tag] = obj fvw = minmax.MinMax.fromvalidatedwalker if defaultMMOffset: obj = fvw(w.subWalker(defaultMMOffset), logger=logger.getChild("default minmax"), **kwArgs) if obj is None: return None r.defaultMinMax = obj if w.length() < 6 * lsCount: logger.error(( 'V0645', (), "The LangSys list of MinMax values is missing or incomplete.")) return None for tag, offset in w.group("4sH", lsCount): obj = fvw(w.subWalker(offset), logger=logger.getChild("langsys '%s'" % (utilities.ensureUnicode(tag), )), **kwArgs) if obj is None: return None r.langSysDict[tag] = obj return r @classmethod def fromwalker(cls, w, **kwArgs): """ Creates and returns a BaseScript object from the specified walker. The following keyword arguments are used: tagList A sequence of bytestrings representing tags. This is required. >>> obj = _testingValues[1] >>> tl = (b'abcd', b'wxyz') >>> obj == BaseScript.frombytes( ... obj.binaryString(tagList=tl), ... tagList=tl) True """ r = cls() tagList = kwArgs['tagList'] valuesOffset, defaultMMOffset, lsCount = w.unpack("3H") wSub = w.subWalker(valuesOffset) r.defaultTag = tagList[wSub.unpack("H")] count = wSub.unpack("H") if count > 0 and count != len(tagList): raise ValueError("BaseValues count does not match BaseTagList!") fw = coordinate.Coordinate for tag in tagList: r[tag] = fw(wSub.subWalker(wSub.unpack("H")), **kwArgs) fw = minmax.MinMax.fromwalker if defaultMMOffset: r.defaultMinMax = fw(w.subWalker(defaultMMOffset), **kwArgs) for tag, offset in w.group("4sH", lsCount): r.langSysDict[tag] = fw(w.subWalker(offset), **kwArgs) return r
def fromvalidatedwalker(cls, w, **kwArgs): """ Creates and returns a BaseScript object from the specified walker. The following keyword arguments are used: logger A logger to which messages will be posted. tagList A sequence of bytestrings representing tags. This is required. >>> TL = (b'abcd', b'wxyz') >>> s = _testingValues[1].binaryString(tagList=TL) >>> logger = utilities.makeDoctestLogger("basescript_fvw") >>> fvb = BaseScript.fromvalidatedbytes >>> obj = fvb(s, logger=logger, tagList=TL) basescript_fvw.basescript - DEBUG - Walker has 158 remaining bytes. basescript_fvw.basescript.tag 'abcd'.coordinate - DEBUG - Coordinate format 1. basescript_fvw.basescript.tag 'abcd'.coordinate_simple - DEBUG - Walker has 16 remaining bytes. basescript_fvw.basescript.tag 'wxyz'.coordinate - DEBUG - Coordinate format 3. basescript_fvw.basescript.tag 'wxyz'.coordinate_device - DEBUG - Walker has 22 remaining bytes. basescript_fvw.basescript.tag 'wxyz'.coordinate_device.device - DEBUG - Walker has 12 remaining bytes. basescript_fvw.basescript.tag 'wxyz'.coordinate_device.device - DEBUG - StartSize=12, endSize=20, format=2 basescript_fvw.basescript.tag 'wxyz'.coordinate_device.device - DEBUG - Data are (48624, 32, 12288) basescript_fvw.basescript.default minmax.minmax - DEBUG - Walker has 132 remaining bytes. basescript_fvw.basescript.default minmax.minmax.minimum.coordinate - DEBUG - Coordinate format 1. basescript_fvw.basescript.default minmax.minmax.minimum.coordinate_simple - DEBUG - Walker has 118 remaining bytes. basescript_fvw.basescript.default minmax.minmax.maximum.coordinate - DEBUG - Coordinate format 2. basescript_fvw.basescript.default minmax.minmax.maximum.coordinate_point - DEBUG - Walker has 126 remaining bytes. basescript_fvw.basescript.langsys 'enUS'.minmax - DEBUG - Walker has 114 remaining bytes. basescript_fvw.basescript.langsys 'enUS'.minmax.minimum.coordinate - DEBUG - Coordinate format 1. basescript_fvw.basescript.langsys 'enUS'.minmax.minimum.coordinate_simple - DEBUG - Walker has 100 remaining bytes. basescript_fvw.basescript.langsys 'enUS'.minmax.maximum.coordinate - DEBUG - Coordinate format 2. basescript_fvw.basescript.langsys 'enUS'.minmax.maximum.coordinate_point - DEBUG - Walker has 108 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax - DEBUG - Walker has 96 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax.minimum.coordinate - DEBUG - Coordinate format 3. basescript_fvw.basescript.langsys 'span'.minmax.minimum.coordinate_device - DEBUG - Walker has 74 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax.minimum.coordinate_device.device - DEBUG - Walker has 42 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax.minimum.coordinate_device.device - DEBUG - StartSize=12, endSize=20, format=2 basescript_fvw.basescript.langsys 'span'.minmax.minimum.coordinate_device.device - DEBUG - Data are (48624, 32, 12288) basescript_fvw.basescript.langsys 'span'.minmax.maximum.coordinate - DEBUG - Coordinate format 2. basescript_fvw.basescript.langsys 'span'.minmax.maximum.coordinate_point - DEBUG - Walker has 54 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate - DEBUG - Coordinate format 1. basescript_fvw.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_simple - DEBUG - Walker has 46 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate - DEBUG - Coordinate format 3. basescript_fvw.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device - DEBUG - Walker has 68 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device.device - DEBUG - Walker has 30 remaining bytes. basescript_fvw.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device.device - DEBUG - StartSize=12, endSize=18, format=1 basescript_fvw.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device.device - DEBUG - Data are (35844,) basescript_fvw.basescript.langsys 'span'.minmax.tag 'wxyz'.coordinate - DEBUG - Coordinate format 2. basescript_fvw.basescript.langsys 'span'.minmax.tag 'wxyz'.coordinate_point - DEBUG - Walker has 62 remaining bytes. >>> obj == _testingValues[1] True """ tagList = kwArgs['tagList'] logger = kwArgs.pop('logger', logging.getLogger()) logger = logger.getChild("basescript") logger.debug( ('V0001', (w.length(), ), "Walker has %d remaining bytes.")) if w.length() < 6: logger.error(('V0004', (), "Insufficient bytes.")) return None r = cls() valuesOffset, defaultMMOffset, lsCount = w.unpack("3H") wSub = w.subWalker(valuesOffset) if wSub.length() < 2: logger.error(('V0641', (), "The default tag index is missing or incomplete.")) return None r.defaultTag = tagList[wSub.unpack("H")] if wSub.length() < 2: logger.error(('V0642', (), "The count is missing or incomplete.")) return None count = wSub.unpack("H") if count and (count != len(tagList)): logger.error(('V0643', ( count, len(tagList) ), "The BaseValues count is %d, but the length of the BaseTagList " "is %d")) return None if wSub.length() < 2 * count: logger.error( ('V0644', (), "The BaseValues list is missing or incomplete.")) return None fvw = coordinate.Coordinate_validated offsets = wSub.group("H", count) for tag, offset in zip(tagList, offsets): itemLogger = logger.getChild("tag '%s'" % (utilities.ensureUnicode(tag), )) obj = fvw(wSub.subWalker(offset), logger=itemLogger, **kwArgs) if obj is None: return None r[tag] = obj fvw = minmax.MinMax.fromvalidatedwalker if defaultMMOffset: obj = fvw(w.subWalker(defaultMMOffset), logger=logger.getChild("default minmax"), **kwArgs) if obj is None: return None r.defaultMinMax = obj if w.length() < 6 * lsCount: logger.error(( 'V0645', (), "The LangSys list of MinMax values is missing or incomplete.")) return None for tag, offset in w.group("4sH", lsCount): obj = fvw(w.subWalker(offset), logger=logger.getChild("langsys '%s'" % (utilities.ensureUnicode(tag), )), **kwArgs) if obj is None: return None r.langSysDict[tag] = obj return r
def fromvalidatedwalker(cls, w, **kwArgs): """ Creates and returns a new FeatureDict from the specified walker, doing validation of the input source along the way. The following keyword arguments are used: featureIndexToTag If the client provides this argument, it should be an empty list. When this method returns, the list's contents will be the feature tags. This is used to be able to map from a feature list index to a tag. forGPOS True if this FeatureDict is part of the 'GPOS' table; False if it's part of the 'GSUB' table. This keyword argument must be present. logger A logger to which messages will be logged. This is optional; one will be created if needed. lookupList The LookupList (not used directly in this method, but passed down to the FeatureTable fromwalker() method). This keyword argument must be present. """ logger = kwArgs.pop('logger', None) if logger is None: logger = logging.getLogger().getChild('featuredict') else: logger = logger.getChild('featuredict') logger.debug( ('V0001', (w.length(), ), "Walker has %d remaining bytes.")) forGPOS = kwArgs['forGPOS'] assert 'lookupList' in kwArgs if w.length() < 2: logger.error(('V0004', (), "Insufficient bytes.")) return None count = w.unpack("H") logger.debug(('Vxxxx', (count, ), "Count is %d")) if w.length() < 6 * count: logger.error( ('V0316', (), "Insufficient bytes for FeatureRecords based on count.")) return None recs = w.group("4sH", count) r = cls() if forGPOS: fpMakers = featureparams.dispatchTableGPOS_validated else: fpMakers = featureparams.dispatchTableGSUB_validated fvw = featuretable.FeatureTable.fromvalidatedwalker v = [None] * len(recs) for i, t in enumerate(recs): subLogger = logger.getChild("feature table %d" % (i, )) tag, offset = t logger.debug(('Vxxxx', (i, utilities.ensureUnicode(tag), offset), "Feature %d: tag is '%s', offset is %d")) tag += (("%04d" % (i + 1, )).encode("ascii")) v[i] = tag maker = fpMakers.get(tag[:4], None) obj = fvw(w.subWalker(offset), fpMaker=maker, logger=subLogger, **kwArgs) if obj is not None: r[tag] = obj if 'featureIndexToTag' in kwArgs: kwArgs['featureIndexToTag'][:] = v return r or None
class Axis(dict, metaclass=mapmeta.FontDataMetaclass): """ Objects representing a single axis in a BASE table. These are dicts which map script tags to BaseScript objects. (Note this is something of a simplification from the OpenType-specified layout) >>> _testingValues[1].pprint(namer=namer.testingNamer()) Script 'latn': Baseline 'abcd': Coordinate: -20 Baseline 'wxyz': Coordinate: -10 Device table: Tweak at 12 ppem: -5 Tweak at 13 ppem: -3 Tweak at 14 ppem: -1 Tweak at 18 ppem: 2 Tweak at 20 ppem: 3 Default baseline tag: 'wxyz' Default MinMax data: Minimum coordinate: Coordinate: -20 Maximum coordinate: Coordinate: 0 Glyph: xyz26 Point: 9 LangSys-specific data: LangSys 'enUS': Minimum coordinate: Coordinate: -20 Maximum coordinate: Coordinate: 0 Glyph: xyz26 Point: 9 LangSys 'span': Minimum coordinate: Coordinate: -10 Device table: Tweak at 12 ppem: -5 Tweak at 13 ppem: -3 Tweak at 14 ppem: -1 Tweak at 18 ppem: 2 Tweak at 20 ppem: 3 Maximum coordinate: Coordinate: 0 Glyph: xyz26 Point: 9 Feature-specific MinMax values: Feature 'abcd': Minimum coordinate: Coordinate: 0 Maximum coordinate: Coordinate: 15 Device table: Tweak at 12 ppem: -2 Tweak at 14 ppem: -1 Tweak at 18 ppem: 1 Feature 'wxyz': Maximum coordinate: Coordinate: -10 Glyph: xyz15 Point: 12 """ # # Class definition variables # mapSpec = dict(item_followsprotocol=True, item_pprintlabelfunc=(lambda k: "Script '%s'" % (utilities.ensureUnicode(k), ))) # # Methods # def buildBinary(self, w, **kwArgs): """ Adds the binary data for the Axis object to the specified LinkedWriter. >>> utilities.hexdump(_testingValues[1].binaryString()) 0 | 0004 000E 0002 6162 6364 7778 797A 0001 |......abcdwxyz..| 10 | 6C61 746E 0008 0012 001A 0002 656E 5553 |latn........enUS| 20 | 002C 7370 616E 003E 0001 0002 007C 0076 |.,span.>.....|.v| 30 | 000E 0006 0000 0002 0000 0019 0009 0001 |................| 40 | FFEC 000E 0006 0000 0002 0000 0019 0009 |................| 50 | 0001 FFEC 0016 002A 0002 6162 6364 0032 |.......*..abcd.2| 60 | 001C 7778 797A 0000 0022 0003 FFF6 0020 |..wxyz..."..... | 70 | 0003 000F 0026 0002 FFF6 000E 000C 0002 |.....&..........| 80 | 0000 0019 0009 0001 0000 000C 0014 0002 |................| 90 | BDF0 0020 3000 000C 0012 0001 8C04 0003 |... 0...........| A0 | FFF6 000A 0001 FFEC 000C 0014 0002 BDF0 |................| B0 | 0020 3000 |. 0. | """ if 'stakeValue' in kwArgs: stakeValue = kwArgs.pop('stakeValue') w.stakeCurrentWithValue(stakeValue) else: stakeValue = w.stakeCurrent() # Make the tagList by gathering all the keys from the BaseScripts s = set() for d in self.values(): s.update(d) tagList = sorted(s) tlStake = w.getNewStake() w.addUnresolvedOffset("H", stakeValue, tlStake) slStake = w.getNewStake() w.addUnresolvedOffset("H", stakeValue, slStake) # Add the tag list w.stakeCurrentWithValue(tlStake) w.add("H", len(tagList)) w.addGroup("4s", tagList) # Add the script list w.stakeCurrentWithValue(slStake) w.add("H", len(self)) stakes = {} for tag in sorted(self): w.add("4s", tag) stakes[tag] = w.getNewStake() w.addUnresolvedOffset("H", slStake, stakes[tag]) # Finally, add the actual BaseScripts d = kwArgs.copy() cp = d['coordinatePool'] = {} dp = d['devicePool'] = {} d['tagList'] = tagList for tag in sorted(self): self[tag].buildBinary(w, stakeValue=stakes[tag], **d) ig0 = operator.itemgetter(0) kwArgs.pop('devicePool', None) for immut, (obj, stake) in sorted(cp.items(), key=ig0): obj.buildBinary(w, stakeValue=stake, devicePool=dp, **kwArgs) for immut, (obj, stake) in sorted(dp.items(), key=ig0): obj.buildBinary(w, stakeValue=stake, **kwArgs) @classmethod def fromvalidatedwalker(cls, w, **kwArgs): """ Creates and returns a new Axis object from the specified walker, doing source validation. >>> s = _testingValues[1].binaryString() >>> logger = utilities.makeDoctestLogger("axis_fvw") >>> fvb = Axis.fromvalidatedbytes >>> obj = fvb(s, logger=logger) axis_fvw.axis - DEBUG - Walker has 180 remaining bytes. axis_fvw.axis.script 'latn'.basescript - DEBUG - Walker has 158 remaining bytes. axis_fvw.axis.script 'latn'.basescript.tag 'abcd'.coordinate - DEBUG - Coordinate format 1. axis_fvw.axis.script 'latn'.basescript.tag 'abcd'.coordinate_simple - DEBUG - Walker has 16 remaining bytes. axis_fvw.axis.script 'latn'.basescript.tag 'wxyz'.coordinate - DEBUG - Coordinate format 3. axis_fvw.axis.script 'latn'.basescript.tag 'wxyz'.coordinate_device - DEBUG - Walker has 22 remaining bytes. axis_fvw.axis.script 'latn'.basescript.tag 'wxyz'.coordinate_device.device - DEBUG - Walker has 12 remaining bytes. axis_fvw.axis.script 'latn'.basescript.tag 'wxyz'.coordinate_device.device - DEBUG - StartSize=12, endSize=20, format=2 axis_fvw.axis.script 'latn'.basescript.tag 'wxyz'.coordinate_device.device - DEBUG - Data are (48624, 32, 12288) axis_fvw.axis.script 'latn'.basescript.default minmax.minmax - DEBUG - Walker has 132 remaining bytes. axis_fvw.axis.script 'latn'.basescript.default minmax.minmax.minimum.coordinate - DEBUG - Coordinate format 1. axis_fvw.axis.script 'latn'.basescript.default minmax.minmax.minimum.coordinate_simple - DEBUG - Walker has 118 remaining bytes. axis_fvw.axis.script 'latn'.basescript.default minmax.minmax.maximum.coordinate - DEBUG - Coordinate format 2. axis_fvw.axis.script 'latn'.basescript.default minmax.minmax.maximum.coordinate_point - DEBUG - Walker has 126 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'enUS'.minmax - DEBUG - Walker has 114 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'enUS'.minmax.minimum.coordinate - DEBUG - Coordinate format 1. axis_fvw.axis.script 'latn'.basescript.langsys 'enUS'.minmax.minimum.coordinate_simple - DEBUG - Walker has 100 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'enUS'.minmax.maximum.coordinate - DEBUG - Coordinate format 2. axis_fvw.axis.script 'latn'.basescript.langsys 'enUS'.minmax.maximum.coordinate_point - DEBUG - Walker has 108 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax - DEBUG - Walker has 96 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.minimum.coordinate - DEBUG - Coordinate format 3. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.minimum.coordinate_device - DEBUG - Walker has 74 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.minimum.coordinate_device.device - DEBUG - Walker has 42 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.minimum.coordinate_device.device - DEBUG - StartSize=12, endSize=20, format=2 axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.minimum.coordinate_device.device - DEBUG - Data are (48624, 32, 12288) axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.maximum.coordinate - DEBUG - Coordinate format 2. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.maximum.coordinate_point - DEBUG - Walker has 54 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate - DEBUG - Coordinate format 1. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_simple - DEBUG - Walker has 46 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate - DEBUG - Coordinate format 3. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device - DEBUG - Walker has 68 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device.device - DEBUG - Walker has 30 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device.device - DEBUG - StartSize=12, endSize=18, format=1 axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device.device - DEBUG - Data are (35844,) axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'wxyz'.coordinate - DEBUG - Coordinate format 2. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'wxyz'.coordinate_point - DEBUG - Walker has 62 remaining bytes. >>> obj == _testingValues[1] True """ logger = kwArgs.pop('logger', logging.getLogger()) logger = logger.getChild("axis") logger.debug( ('V0001', (w.length(), ), "Walker has %d remaining bytes.")) if w.length() < 4: logger.error(('V0004', (), "Insufficient bytes")) return None tagListOffset, scriptListOffset = w.unpack("2H") wSub = w.subWalker(tagListOffset) if wSub.length() < 2: logger.error( ('V0647', (), "The tagList count is missing or incomplete.")) return None tagListCount = wSub.unpack("H") if wSub.length() < 4 * tagListCount: logger.error( ('V0648', (), "The tagList is missing or incomplete.")) return None tagList = wSub.group("4s", tagListCount) if sorted(tagList) != list(tagList): logger.error(('V0649', (), "The tagList is not sorted.")) return None wSub = w.subWalker(scriptListOffset) if wSub.length() < 2: logger.error(('V0650', (), "The ScriptList count is missing or incomplete.")) return None scriptListCount = wSub.unpack("H") if wSub.length() < 6 * scriptListCount: logger.error( ('V0651', (), "The ScriptList is missing or incomplete.")) return None scriptsOffsets = wSub.group("4sH", scriptListCount) r = cls() fvw = basescript.BaseScript.fromvalidatedwalker for scriptTag, offset in scriptsOffsets: obj = fvw( wSub.subWalker(offset), tagList=tagList, logger=logger.getChild("script '%s'" % (utilities.ensureUnicode(scriptTag), ))) if obj is None: return None r[scriptTag] = obj return r @classmethod def fromwalker(cls, w, **kwArgs): """ Creates and returns an Axis object from the specified walker. >>> obj = _testingValues[1] >>> obj == Axis.frombytes(obj.binaryString()) True """ tagListOffset, scriptListOffset = w.unpack("2H") wSub = w.subWalker(tagListOffset) tagList = wSub.group("4s", wSub.unpack("H")) wSub = w.subWalker(scriptListOffset) scriptsOffsets = wSub.group("4sH", wSub.unpack("H")) r = cls() fw = basescript.BaseScript.fromwalker for scriptTag, offset in scriptsOffsets: r[scriptTag] = fw(wSub.subWalker(offset), tagList=tagList) return r
def fromvalidatedwalker(cls, w, **kwArgs): """ Creates and returns a new Axis object from the specified walker, doing source validation. >>> s = _testingValues[1].binaryString() >>> logger = utilities.makeDoctestLogger("axis_fvw") >>> fvb = Axis.fromvalidatedbytes >>> obj = fvb(s, logger=logger) axis_fvw.axis - DEBUG - Walker has 180 remaining bytes. axis_fvw.axis.script 'latn'.basescript - DEBUG - Walker has 158 remaining bytes. axis_fvw.axis.script 'latn'.basescript.tag 'abcd'.coordinate - DEBUG - Coordinate format 1. axis_fvw.axis.script 'latn'.basescript.tag 'abcd'.coordinate_simple - DEBUG - Walker has 16 remaining bytes. axis_fvw.axis.script 'latn'.basescript.tag 'wxyz'.coordinate - DEBUG - Coordinate format 3. axis_fvw.axis.script 'latn'.basescript.tag 'wxyz'.coordinate_device - DEBUG - Walker has 22 remaining bytes. axis_fvw.axis.script 'latn'.basescript.tag 'wxyz'.coordinate_device.device - DEBUG - Walker has 12 remaining bytes. axis_fvw.axis.script 'latn'.basescript.tag 'wxyz'.coordinate_device.device - DEBUG - StartSize=12, endSize=20, format=2 axis_fvw.axis.script 'latn'.basescript.tag 'wxyz'.coordinate_device.device - DEBUG - Data are (48624, 32, 12288) axis_fvw.axis.script 'latn'.basescript.default minmax.minmax - DEBUG - Walker has 132 remaining bytes. axis_fvw.axis.script 'latn'.basescript.default minmax.minmax.minimum.coordinate - DEBUG - Coordinate format 1. axis_fvw.axis.script 'latn'.basescript.default minmax.minmax.minimum.coordinate_simple - DEBUG - Walker has 118 remaining bytes. axis_fvw.axis.script 'latn'.basescript.default minmax.minmax.maximum.coordinate - DEBUG - Coordinate format 2. axis_fvw.axis.script 'latn'.basescript.default minmax.minmax.maximum.coordinate_point - DEBUG - Walker has 126 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'enUS'.minmax - DEBUG - Walker has 114 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'enUS'.minmax.minimum.coordinate - DEBUG - Coordinate format 1. axis_fvw.axis.script 'latn'.basescript.langsys 'enUS'.minmax.minimum.coordinate_simple - DEBUG - Walker has 100 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'enUS'.minmax.maximum.coordinate - DEBUG - Coordinate format 2. axis_fvw.axis.script 'latn'.basescript.langsys 'enUS'.minmax.maximum.coordinate_point - DEBUG - Walker has 108 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax - DEBUG - Walker has 96 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.minimum.coordinate - DEBUG - Coordinate format 3. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.minimum.coordinate_device - DEBUG - Walker has 74 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.minimum.coordinate_device.device - DEBUG - Walker has 42 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.minimum.coordinate_device.device - DEBUG - StartSize=12, endSize=20, format=2 axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.minimum.coordinate_device.device - DEBUG - Data are (48624, 32, 12288) axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.maximum.coordinate - DEBUG - Coordinate format 2. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.maximum.coordinate_point - DEBUG - Walker has 54 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate - DEBUG - Coordinate format 1. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_simple - DEBUG - Walker has 46 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate - DEBUG - Coordinate format 3. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device - DEBUG - Walker has 68 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device.device - DEBUG - Walker has 30 remaining bytes. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device.device - DEBUG - StartSize=12, endSize=18, format=1 axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'abcd'.coordinate_device.device - DEBUG - Data are (35844,) axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'wxyz'.coordinate - DEBUG - Coordinate format 2. axis_fvw.axis.script 'latn'.basescript.langsys 'span'.minmax.tag 'wxyz'.coordinate_point - DEBUG - Walker has 62 remaining bytes. >>> obj == _testingValues[1] True """ logger = kwArgs.pop('logger', logging.getLogger()) logger = logger.getChild("axis") logger.debug( ('V0001', (w.length(), ), "Walker has %d remaining bytes.")) if w.length() < 4: logger.error(('V0004', (), "Insufficient bytes")) return None tagListOffset, scriptListOffset = w.unpack("2H") wSub = w.subWalker(tagListOffset) if wSub.length() < 2: logger.error( ('V0647', (), "The tagList count is missing or incomplete.")) return None tagListCount = wSub.unpack("H") if wSub.length() < 4 * tagListCount: logger.error( ('V0648', (), "The tagList is missing or incomplete.")) return None tagList = wSub.group("4s", tagListCount) if sorted(tagList) != list(tagList): logger.error(('V0649', (), "The tagList is not sorted.")) return None wSub = w.subWalker(scriptListOffset) if wSub.length() < 2: logger.error(('V0650', (), "The ScriptList count is missing or incomplete.")) return None scriptListCount = wSub.unpack("H") if wSub.length() < 6 * scriptListCount: logger.error( ('V0651', (), "The ScriptList is missing or incomplete.")) return None scriptsOffsets = wSub.group("4sH", scriptListCount) r = cls() fvw = basescript.BaseScript.fromvalidatedwalker for scriptTag, offset in scriptsOffsets: obj = fvw( wSub.subWalker(offset), tagList=tagList, logger=logger.getChild("script '%s'" % (utilities.ensureUnicode(scriptTag), ))) if obj is None: return None r[scriptTag] = obj return r
def fromvalidatedwalker(cls, w, **kwArgs): """ Creates and returns a new LangSysDict object from the specified walker, doing source validation. The following keyword arguments are supported: logger A logger to which messages will be posted. """ logger = kwArgs.pop('logger', logging.getLogger()) logger = logger.getChild('langsysdict') logger.debug( ('V0001', (w.length(), ), "Walker has %d remaining bytes.")) if w.length() < 4: logger.error(('V0004', (), "Insufficient bytes.")) return None defOffset, lsCount = w.unpack("2H") logger.debug(('Vxxxx', (defOffset, lsCount), "Default offset is %d; langSys count is %d")) fvw = langsys.LangSys.fromvalidatedwalker if defOffset: defLS = fvw(w.subWalker(defOffset), logger=logger.getChild("default"), **kwArgs) if defLS is None: return None else: defLS = None r = cls({}, defaultLangSys=defLS) if w.length() < 6 * lsCount: logger.error(('V0412', (), "The LangSys records are missing or incomplete.")) return None lsRecs = w.group("4sH", lsCount) for tag, offset in lsRecs: logger.debug(('Vxxxx', (utilities.ensureUnicode(tag), offset), "LangSys tag '%s' has offset %d")) obj = fvw(w.subWalker(offset), logger=logger.getChild("tag %s" % (utilities.ensureUnicode(tag), )), **kwArgs) if obj is None: return None r[tag] = obj return r