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
Exemple #2
0
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), )))
Exemple #3
0
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), )))
Exemple #4
0
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
Exemple #5
0
    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
Exemple #7
0
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
Exemple #8
0
    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
Exemple #10
0
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
Exemple #11
0
    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