コード例 #1
0
    def fromwalker(cls, w, **kwArgs):
        """
        Creates and returns a new Rearrangement object from the specified
        walker, which must start at the beginning (numClasses) of the state
        table.
        
        >>> obj = _testingValues[0]
        >>> obj == Rearrangement.frombytes(
        ...   obj.binaryString(),
        ...   coverage = obj.coverage,
        ...   maskValue = 0x04000000)
        True
        """

        numClasses, oCT, oSA, oET = w.unpack("4H")

        wCT, wSA, wET = stutils.offsetsToSubWalkers(w.subWalker(0), oCT, oSA,
                                                    oET)

        rawEntries = wET.unpackRest("2H")
        maxOffset = max(offset for offset, flags in rawEntries)
        numStates = 1 + (maxOffset - oSA) // numClasses

        nsObj = namestash.NameStash.readormake(w, (oCT, oSA, oET), numStates,
                                               numClasses)

        stateNames = nsObj.allStateNames()
        classNames = nsObj.allClassNames()

        classTable = classtable.ClassTable.fromwalker(wCT,
                                                      classNames=classNames)

        rawStateArray = wSA.group("B" * numClasses, numStates)

        kwArgs.pop('classTable', None)

        r = cls({},
                classTable=classTable,
                **utilities.filterKWArgs(cls, kwArgs))

        S = staterow_rearrangement.StateRow
        E = entry_rearrangement.Entry
        V = verbs_rearrangement.Verb

        for stateIndex, rawState in enumerate(rawStateArray):
            thisRow = S()

            for classIndex, entryIndex in enumerate(rawState):
                newStateOffset, flags = rawEntries[entryIndex]

                thisRow[classNames[classIndex]] = E(
                    markFirst=bool(flags & 0x8000),
                    markLast=bool(flags & 0x2000),
                    newState=stateNames[(newStateOffset - oSA) // numClasses],
                    noAdvance=bool(flags & 0x4000),
                    verb=V(flags & 0x000F))

            r[stateNames[stateIndex]] = thisRow

        return r
コード例 #2
0
    def _buildInputs(self):
        self.w.reset()
        t = self.w.unpack("5L")
        self.numClasses, oCT, oSA, oET, oGT = t
        wCT, wSA, wET, wGT = stutils.offsetsToSubWalkers(self.w, *t[1:])
        self.entryTable = wET.unpackRest("4H", strict=False)

        self.numStates = max(
            int(wSA.length()) // (2 * self.numClasses),
            1 + max(t[0] for t in self.entryTable))

        self.classMap = lookup.Lookup.fromwalker(wCT)
        d = utilities.invertDictFull(self.classMap, asSets=True)
        self.classToGlyphs = {k: v for k, v in d.items() if k >= 4}
        self.classToGlyphs[2] = {0xFFFF}

        self.emptyClasses = (set(range(4, self.numClasses)) -
                             set(self.classToGlyphs))

        self.stateArray = wSA.group("H" * self.numClasses, self.numStates)

        numLookups = 1 + max(n for t in self.entryTable
                             for n in t[2:4] if n != 0xFFFF)

        self.glyphLookups = [None] * numLookups
        offsets = wGT.group("L", numLookups)

        for i, offset in enumerate(offsets):
            wSub = wGT.subWalker(offset)
            self.glyphLookups[i] = lookup.Lookup_OutGlyph.fromwalker(wSub)
コード例 #3
0
ファイル: format1.py プロジェクト: nickssmith/jenkinsTests
    def fromwalker(cls, w, **kwArgs):
        """
        Creates and returns a new Format1 object from the specified walker.
        
        >>> d = {'coverage': _testingValues[1].coverage.__copy__()}
        >>> obj = _testingValues[1]
        >>> obj == Format1.frombytes(obj.binaryString(), **d)
        True
        """

        numClasses, oCT, oSA, oET, oVT = w.unpack("5L")

        wCT, wSA, wET, wVT = stutils.offsetsToSubWalkers(
            w.subWalker(0), oCT, oSA, oET, oVT)

        wETCopy = wET.subWalker(0, relative=True)
        v = wETCopy.unpackRest("3H", strict=False)
        numStates = 1 + utilities.safeMax(x[0] for x in v)
        numEntries = len(v)

        nsObj = namestash.NameStash.readormake(w, (oCT, oSA, oET, oVT),
                                               numStates, numClasses)

        stateNames = nsObj.allStateNames()
        classNames = nsObj.allClassNames()

        classTable = classtable.ClassTable.fromwalker(wCT,
                                                      classNames=classNames)

        kwArgs.pop('classTable', None)

        r = cls({},
                classTable=classTable,
                **utilities.filterKWArgs(cls, kwArgs))

        # build value table
        valueDict = {}
        fw = valuetuple.ValueTuple.fromwalker
        index = 0

        while wVT.stillGoing():
            valueDict[index] = fw(wVT)
            index += 1

        # build entry table
        fw = entry.Entry.fromwalker
        d = {'stateNames': stateNames, 'valueDict': valueDict}
        entries = [fw(wET, **d) for i in range(numEntries)]

        # finally, build state table
        fw = staterow.StateRow.fromwalker
        d = {'classNames': classNames, 'entries': entries}

        for stateName in stateNames:
            r[stateName] = fw(wSA, **d)

        return r
コード例 #4
0
    def fromwalker(cls, w, **kwArgs):
        """
        Creates and returns a new Contextual object from the specified walker,
        which must start at the beginning (numClasses) of the state table.
        
        >>> obj = _testingValues[0]
        >>> obj == Contextual.frombytes(
        ...     obj.binaryString(), coverage=obj.coverage, maskValue=0x10000000)
        True
        """

        analyzer = contextanalyzer.Analyzer(w.subWalker(0, relative=True))
        markAnalysis, currAnalysis = analyzer.analyze()
        numClasses, oCT, oSA, oET, oST = w.unpack("5H")
        # in the following, note that limits are correctly set for all walkers
        wCT, wSA, wET, wST = stutils.offsetsToSubWalkers(
            w.subWalker(0), oCT, oSA, oET, oST)
        numStates = analyzer.numStates
        nsObj = namestash.NameStash.readormake(w, (oCT, oSA, oET, oST),
                                               numStates, numClasses)
        stateNames = nsObj.allStateNames()
        classNames = nsObj.allClassNames()
        classTable = classtable.ClassTable.fromwalker(wCT,
                                                      classNames=classNames)

        kwArgs.pop('classTable', None)

        r = cls({},
                classTable=classTable,
                **utilities.filterKWArgs(cls, kwArgs))

        entryTable = analyzer.entryTable
        Entry = entry_contextual.Entry
        GlyphDict = glyphdict.GlyphDict
        StateRow = staterow_contextual.StateRow

        for stateIndex, rawState in enumerate(analyzer.stateArray):
            newRow = staterow_contextual.StateRow()

            for classIndex, entryIndex in enumerate(rawState):
                newStateOffset, flags = entryTable[entryIndex][0:2]
                newStateIndex = (newStateOffset - oSA) // numClasses

                newEntry = Entry(newState=stateNames[newStateIndex],
                                 mark=bool(flags & 0x8000),
                                 noAdvance=bool(flags & 0x4000),
                                 markSubstitutionDict=GlyphDict(
                                     markAnalysis.get(entryIndex, {})),
                                 currSubstitutionDict=GlyphDict(
                                     currAnalysis.get(entryIndex, {})))

                newRow[classNames[classIndex]] = newEntry

            r[stateNames[stateIndex]] = newRow

        return r
コード例 #5
0
 def _buildInputs(self):
     self.w.reset()
     t = self.w.unpack("7H")
     self.numClasses, oCT, oSA, oET, oLA, oCP, oLG = t
     self.offsets = t[1:]
     
     wCT, wSA, wET, wLA, wCP, wLG = stutils.offsetsToSubWalkers(
       self.w,
       *self.offsets)
     
     self._findNumStates(wET.subWalker(0, relative=True), oSA)
     self._makeClassMap(wCT)
     self.stateArray = wSA.group("B" * self.numClasses, self.numStates)
     self.entryTable = wET.unpackRest("2H", strict=False)
     self.ligActions = wLA.unpackRest("L", strict=False)
     self.ligActionIsLast = [bool(n & 0x80000000) for n in self.ligActions]
     self.compOffsets = wCP.unpackRest("H")
     self.ligatures = wLG.unpackRest("H")
コード例 #6
0
 def _buildInputs(self):
     self.w.reset()
     self.numClasses, oCT, oSA, oET, oST = self.w.unpack("5H")
     self.offsets = (oSA, oST)
     
     wCT, wSA, wET, wST = stutils.offsetsToSubWalkers(
       self.w,
       oCT,
       oSA,
       oET,
       oST)
     
     self._findNumStates(
       wET.subWalker(0, relative=True),
       oSA,
       self.numClasses)
     
     self._makeClassMap(wCT)
     self.stateArray = wSA.group("B" * self.numClasses, self.numStates)
     self.entryTable = wET.unpackRest("4H", strict=False)
     self.substTable = wST.unpackRest("H")
コード例 #7
0
    def _buildInputs(self):
        self.w.reset()
        t = self.w.unpack("7L")
        self.numClasses, oCT, oSA, oET, oLA, oCP, oLG = t

        wCT, wSA, wET, wLA, wCP, wLG = stutils.offsetsToSubWalkers(
            self.w, *t[1:])

        self.entryTable = list(wET.unpackRest("3H", strict=False))

        self.numStates = max(
            int(wSA.length()) // (2 * self.numClasses),
            1 + max(t[0] for t in self.entryTable))

        self.classMap = lookup.Lookup.fromwalker(wCT)
        d = utilities.invertDictFull(self.classMap, asSets=True)
        self.classToGlyphs = {k: frozenset(v) for k, v in d.items() if k >= 4}
        self.classToGlyphs[2] = frozenset([0xFFFF])
        self.stateArray = wSA.group("H" * self.numClasses, self.numStates)
        self.ligActions = wLA.unpackRest("L")
        self.ligActionIsLast = [bool(n & 0x80000000) for n in self.ligActions]
        self.compIndices = wCP.unpackRest("H")
        self.ligatures = wLG.unpackRest("H")
コード例 #8
0
ファイル: format4.py プロジェクト: nickssmith/jenkinsTests
    def fromwalker(cls, w, **kwArgs):
        """
        Creates and returns a new Format4 object from the specified walker.
        
        >>> obj = _makePointExample()
        >>> k = {'coverage': obj.coverage, 'tupleIndex': obj.tupleIndex}
        >>> bs = obj.binaryString()
        >>> obj2 = Format4.frombytes(bs, **k)
        >>> obj == obj2
        True
        
        >>> obj = _makeAnchorExample()
        >>> bs = obj.binaryString()
        >>> obj2 = Format4.frombytes(bs, **k)
        >>> obj == obj2
        True
        
        >>> obj = _makeCoordExample()
        >>> bs = obj.binaryString()
        >>> obj2 = Format4.frombytes(bs, **k)
        >>> obj == obj2
        True
        """

        numClasses, oCT, oSA, oET, kind, oVT = w.unpack("4LBT")
        kind >>= 6

        if kind not in {0, 1, 2}:
            raise ValueError("Unknown action type mask!")

        t = (oCT, oSA, oET, oVT)
        wCT, wSA, wET, wVT = stutils.offsetsToSubWalkers(w.subWalker(0), *t)
        wETCopy = wET.subWalker(0, relative=True)
        v = wETCopy.unpackRest("3H", strict=False)
        wET = wET.subWalker(0, relative=True, newLimit=6 * len(v))
        numStates = max(2, 1 + utilities.safeMax(x[0] for x in v))
        nsObj = namestash.NameStash.readormake(w, t, numStates, numClasses)
        stateNames = nsObj.allStateNames()
        classNames = nsObj.allClassNames()
        fw = classtable.ClassTable.fromwalker
        classTable = fw(wCT, classNames=classNames)
        kwArgs.pop('classTable', None)

        r = cls({},
                classTable=classTable,
                **utilities.filterKWArgs(cls, kwArgs))

        wVTCopy = wVT.subWalker(0, relative=True)
        v = wVTCopy.unpackRest(("2H" if kind < 2 else "4h"), strict=False)

        wVT = wVT.subWalker(0,
                            relative=True,
                            newLimit=(4 if kind < 2 else 8) * len(v))

        v = _actionClasses[kind].groupfromwalker(wVT, **kwArgs)
        actionMap = dict(enumerate(v))
        gfw = entry4.Entry.groupfromwalker
        entries = gfw(wET, actionMap=actionMap, stateNames=stateNames)
        fw = staterow.StateRow.fromwalker

        for stateName in stateNames:
            r[stateName] = fw(wSA, classNames=classNames, entries=entries)

        return r
コード例 #9
0
ファイル: format4.py プロジェクト: nickssmith/jenkinsTests
    def fromvalidatedwalker(cls, w, **kwArgs):
        """
        Creates and returns a new Format4 object from the specified walker,
        doing source validation.
        
        >>> obj = _makePointExample()
        >>> k = {'coverage': obj.coverage, 'tupleIndex': obj.tupleIndex}
        >>> k['logger'] = utilities.makeDoctestLogger("fvw")
        >>> bs = obj.binaryString()
        >>> obj2 = Format4.fromvalidatedbytes(bs, **k)
        fvw.format4 - DEBUG - Walker has 152 remaining bytes.
        fvw.format4.namestash - DEBUG - Walker has 132 remaining bytes.
        fvw.format4 - DEBUG - Walker has 28 remaining bytes.
        fvw.format4.lookup_aat - DEBUG - Walker has 28 remaining bytes.
        fvw.format4.lookup_aat.binsearch.binsrch header - DEBUG - Walker has 26 remaining bytes.
        fvw.format4.actions.[0].pointentry - DEBUG - Walker has 8 remaining bytes.
        fvw.format4.actions.[1].pointentry - DEBUG - Walker has 4 remaining bytes.
        fvw.format4.entries.[0].entry4 - DEBUG - Walker has 24 remaining bytes.
        fvw.format4.entries.[1].entry4 - DEBUG - Walker has 18 remaining bytes.
        fvw.format4.entries.[2].entry4 - DEBUG - Walker has 12 remaining bytes.
        fvw.format4.entries.[3].entry4 - DEBUG - Walker has 6 remaining bytes.
        fvw.format4.state Start of text.staterow - DEBUG - Walker has 44 remaining bytes.
        fvw.format4.state Start of line.staterow - DEBUG - Walker has 30 remaining bytes.
        fvw.format4.state Saw x.staterow - DEBUG - Walker has 16 remaining bytes.
        >>> obj == obj2
        True
        """

        logger = kwArgs.pop('logger', logging.getLogger())
        logger = logger.getChild("format4")

        logger.debug(
            ('V0001', (w.length(), ), "Walker has %d remaining bytes."))

        if w.length() < 20:
            logger.error(('V0004', (), "Insufficient bytes."))
            return None

        stBaseOffset = w.getOffset()
        numClasses, oCT, oSA, oET, kind, oVT = w.unpack("4LBT")

        if numClasses < 4:
            logger.error(
                ('V0634', (numClasses, ),
                 "The number of classes in the state table must be at least "
                 "four, but is only %d."))

            return None

        if kind & 0x3F:
            logger.warning((
                'V0879', (kind, ),
                "One or more reserved bits in the flag byte %02X are not zero."
            ))

        kind >>= 6

        if kind == 3:
            logger.error(
                ('V0880', (), "Action type mask is 3, which is undefined."))

            return None

        t = (oCT, oSA, oET, oVT)
        firstValid = w.getOffset() - stBaseOffset
        lastValidPlusOne = firstValid + w.length()

        if any(o < firstValid or o >= lastValidPlusOne for o in t):
            logger.error(
                ('V0635', (),
                 "One or more offsets to state table components are outside "
                 "the bounds of the state table itself."))

            return None

        wCT, wSA, wET, wVT = stutils.offsetsToSubWalkers(w.subWalker(0), *t)

        wETCopy = wET.subWalker(0, relative=True)
        v = wETCopy.unpackRest("3H", strict=False)
        wET = wET.subWalker(0, relative=True, newLimit=6 * len(v))
        numStates = max(2, 1 + utilities.safeMax(x[0] for x in v))
        fvw = namestash.NameStash.readormake_validated
        nsObj = fvw(w, t, numStates, numClasses, logger=logger)

        if nsObj is None:
            return None

        stateNames = nsObj.allStateNames()
        classNames = nsObj.allClassNames()
        fvw = classtable.ClassTable.fromvalidatedwalker
        classTable = fvw(wCT, classNames=classNames, logger=logger)

        if classTable is None:
            return None

        kwArgs.pop('classTable', None)

        r = cls({},
                classTable=classTable,
                **utilities.filterKWArgs(cls, kwArgs))

        wVTCopy = wVT.subWalker(0, relative=True)
        v = wVTCopy.unpackRest(("2H" if kind < 2 else "4h"), strict=False)

        wVT = wVT.subWalker(0,
                            relative=True,
                            newLimit=(4 if kind < 2 else 8) * len(v))

        gfvw = _actionClasses[kind].groupfromvalidatedwalker
        v = gfvw(wVT, logger=logger.getChild("actions"), **kwArgs)

        if v is None:
            return None

        actionMap = dict(enumerate(v))

        entries = entry4.Entry.groupfromvalidatedwalker(
            wET,
            actionMap=actionMap,
            stateNames=stateNames,
            logger=logger.getChild("entries"))

        if entries is None:
            return None

        fvw = staterow.StateRow.fromvalidatedwalker

        for stateName in stateNames:
            obj = fvw(wSA,
                      classNames=classNames,
                      entries=entries,
                      logger=logger.getChild("state %s" % (stateName, )))

            if obj is None:
                return None

            r[stateName] = obj

        return r
コード例 #10
0
 def _buildInputs_validated(self, logger):
     self.w.reset()
     stBaseOffset = self.w.getOffset()
     
     if self.w.length() < 10:
         logger.error(('V0004', (), "Insufficient bytes."))
         return False
     
     t = self.w.unpack("5H")
     self.numClasses, oCT, oSA, oET, oST = t
     
     if self.numClasses < 4:
         logger.error((
           'V0634',
           (self.numClasses,),
           "The number of classes in a state table must be at least "
           "four, but is only %d."))
         
         return False
     
     firstValid = self.w.getOffset() - stBaseOffset
     lastValidPlusOne = firstValid + self.w.length()
     
     if any(o < firstValid or o >= lastValidPlusOne for o in t[1:]):
         logger.error((
           'V0635',
           (),
           "One or more offsets to state table components are outside "
           "the bounds of the state table itself."))
         
         return False
     
     self.offsets = (oSA, oST)
     wCT, wSA, wET, wST = stutils.offsetsToSubWalkers(self.w, *t[1:])
     self.entryTable = wET.unpackRest("4H", strict=False)
     
     if not self.entryTable:
         logger.error((
           'V0636',
           (),
           "The entry table is missing or incomplete."))
         
         return False
     
     maxOffset = max(t[0] for t in self.entryTable) - oSA
     self.numStates = 1 + (maxOffset // self.numClasses)
     
     okToProceed = self._makeClassMap_validated(
       wCT,
       logger = logger.getChild("classmap"))
     
     if not okToProceed:
         return False
     
     if wSA.length() < self.numClasses * self.numStates:
         logger.error((
           'V0676',
           (),
           "The state array is missing or incomplete."))
         
         return False
     
     self.stateArray = wSA.group("B" * self.numClasses, self.numStates)
     maxEntryIndex = max(n for row in self.stateArray for n in row)
     
     if maxEntryIndex >= len(self.entryTable):
         logger.error((
           'V0724',
           (stateNames[stateIndex], classNames[classIndex]),
           "At least one state array cell contains an entry index that "
           "is out of range."))
         
         return False
     
     self.substTable = wST.unpackRest("H")
     
     if not self.substTable:
         logger.error((
           'V0679',
           (),
           "The substitution table is missing or incomplete."))
         
         return False
     
     return True
コード例 #11
0
ファイル: format1.py プロジェクト: nickssmith/jenkinsTests
    def fromwalker(cls, w, **kwArgs):
        """
        Creates and returns a new Format1 object from the specified walker,
        which must start at the beginning (numClasses) of the state table. The
        following keyword arguments are supported:
        
            coverage    A Coverage object. This is required.
        """

        numClasses, oCT, oSA, oET, oVT = w.unpack("5H")

        wCT, wSA, wET, wVT = stutils.offsetsToSubWalkers(
            w.subWalker(0),  # can't just use w; it gets reset
            oCT,
            oSA,
            oET,
            oVT)

        numStates = cls._findNumStates(wET.subWalker(0, relative=True), oSA,
                                       numClasses)

        nsObj = namestash.NameStash.readormake(w, (oCT, oSA, oET, oVT),
                                               numStates, numClasses)

        stateNames = nsObj.allStateNames()
        classNames = nsObj.allClassNames()

        classTable = classtable.ClassTable.fromwalker(wCT,
                                                      classNames=classNames)

        kwArgs.pop('classTable', None)

        r = cls({},
                classTable=classTable,
                **utilities.filterKWArgs(cls, kwArgs))

        fw = staterow.StateRow.fromwalker
        cover = kwArgs['coverage']
        entryPool = {}
        valueTuplePool = {}

        delKeys = {
            'classNames', 'entryPool', 'isCrossStream', 'stateArrayBaseOffset',
            'stateNames', 'valueTuplePool', 'wEntryTable', 'wSubtable'
        }

        for delKey in delKeys:
            kwArgs.pop(delKey, None)

        for stateName in stateNames:
            r[stateName] = fw(wSA,
                              classNames=classNames,
                              entryPool=entryPool,
                              isCrossStream=cover.crossStream,
                              stateArrayBaseOffset=oSA,
                              stateNames=stateNames,
                              valueTuplePool=valueTuplePool,
                              wEntryTable=wET,
                              wSubtable=w,
                              **kwArgs)

        return r
コード例 #12
0
ファイル: format1.py プロジェクト: nickssmith/jenkinsTests
    def fromvalidatedwalker(cls, w, **kwArgs):
        """
        Creates and returns a new Format1 object from the specified walker,
        doing source validation, which must start at the beginning (numClasses)
        of the state table. The following keyword arguments are supported:
        
            coverage    A Coverage object. This is required.
        """

        logger = kwArgs.pop('logger', logging.getLogger())
        logger = logger.getChild("format1")

        logger.debug(
            ('V0001', (w.length(), ), "Walker has %d remaining bytes."))

        if w.length() < 10:
            logger.error(('V0004', (), "Insufficient bytes."))
            return None

        stBaseOffset = w.getOffset()
        t = w.unpack("5H")
        numClasses, oCT, oSA, oET, oVT = t

        if numClasses < 4:
            logger.error(
                ('V0634', (numClasses, ),
                 "The number of classes in the state table must be at least "
                 "four, but is only %d."))

            return None

        firstValid = w.getOffset() - stBaseOffset
        lastValidPlusOne = firstValid + w.length()

        if any(o < firstValid or o >= lastValidPlusOne for o in t[1:]):
            logger.error(
                ('V0635', (),
                 "One or more offsets to state table components are outside "
                 "the bounds of the state table itself."))

            return None

        wCT, wSA, wET, wVT = stutils.offsetsToSubWalkers(
            w.subWalker(0), *t[1:])

        wETCopy = wET.subWalker(0, relative=True)

        if wETCopy.length() < 4:
            logger.error(
                ('V0636', (), "The entry table is missing or incomplete."))

            return None

        v = wETCopy.unpackRest("2H")
        maxOffset = max(offset for offset, flags in v) - oSA
        numStates = 1 + (maxOffset // numClasses)

        nsObj = namestash.NameStash.readormake(w, t[1:], numStates, numClasses)
        stateNames = nsObj.allStateNames()
        classNames = nsObj.allClassNames()
        fgc = kwArgs.pop('fontGlyphCount')

        classTable = classtable.ClassTable.fromvalidatedwalker(
            wCT, classNames=classNames, logger=logger, fontGlyphCount=fgc)

        if classTable is None:
            return None

        kwArgs.pop('classTable', None)

        r = cls({},
                classTable=classTable,
                **utilities.filterKWArgs(cls, kwArgs))

        fvw = staterow.StateRow.fromvalidatedwalker
        cover = kwArgs['coverage']
        entryPool = {}
        valueTuplePool = {}

        delKeys = {
            'classNames', 'entryPool', 'isCrossStream', 'logger',
            'stateArrayBaseOffset', 'stateNames', 'valueTuplePool',
            'wEntryTable', 'wSubtable'
        }

        for delKey in delKeys:
            kwArgs.pop(delKey, None)

        for stateName in stateNames:
            itemLogger = logger.getChild("state '%s'" % (stateName, ))

            obj = fvw(wSA,
                      classNames=classNames,
                      entryPool=entryPool,
                      isCrossStream=cover.crossStream,
                      logger=itemLogger,
                      stateArrayBaseOffset=oSA,
                      stateNames=stateNames,
                      valueTuplePool=valueTuplePool,
                      wEntryTable=wET,
                      wSubtable=w,
                      **kwArgs)

            if obj is None:
                return None

            r[stateName] = obj

        return r
コード例 #13
0
 def _buildInputs_validated(self, logger):
     self.w.reset()
     stBaseOffset = self.w.getOffset()
     
     if self.w.length() < 14:
         logger.error(('V0004', (), "Insufficient bytes."))
         return False
     
     t = self.w.unpack("7H")
     self.numClasses, oCT, oSA, oET, oLA, oCP, oLG = t
     self.offsets = t[1:]
     
     if self.numClasses < 4:
         logger.error((
           'V0634',
           (self.numClasses,),
           "The number of classes in a state table must be at least "
           "four, but is only %d."))
         
         return False
     
     firstValid = self.w.getOffset() - stBaseOffset
     lastValidPlusOne = firstValid + self.w.length()
     
     if any(o < firstValid or o >= lastValidPlusOne for o in self.offsets):
         logger.error((
           'V0635',
           (),
           "One or more offsets to state table components are outside "
           "the bounds of the state table itself."))
         
         return False
     
     wCT, wSA, wET, wLA, wCP, wLG = stutils.offsetsToSubWalkers(
       self.w,
       *self.offsets)
     
     self.entryTable = wET.unpackRest("2H", strict=False)
     
     if not self.entryTable:
         logger.error((
           'V0636',
           (),
           "The entry table is missing or incomplete."))
         
         return False
     
     maxOffset = max(t[0] for t in self.entryTable) - oSA
     self.numStates = 1 + (maxOffset // self.numClasses)
     
     okToProceed = self._makeClassMap_validated(
       wCT,
       logger = logger.getChild("classmap"))
     
     if not okToProceed:
         return False
     
     if wSA.length() < self.numClasses * self.numStates:
         logger.error((
           'V0676',
           (),
           "The state array is missing or incomplete."))
         
         return False
     
     self.stateArray = wSA.group("B" * self.numClasses, self.numStates)
     maxEntryIndex = max(n for row in self.stateArray for n in row)
     
     if maxEntryIndex >= len(self.entryTable):
         logger.error((
           'V0724',
           (),
           "At least one state array cell contains an entry index that "
           "is out of range."))
         
         return False
     
     self.ligActions = wLA.unpackRest("L", strict=False)
     
     if not self.ligActions:
         logger.error((
           'V0690',
           (),
           "The ligature action list is missing or incomplete."))
         
         return False
     
     self.ligActionIsLast = [bool(n & 0x80000000) for n in self.ligActions]
     self.compOffsets = wCP.unpackRest("H")
     
     if not self.compOffsets:
         logger.error((
           'V0691',
           (),
           "The component offset table is missing or incomplete."))
         
         return False
     
     self.ligatures = wLG.unpackRest("H")
     
     if not self.ligatures:
         logger.error((
           'V0692',
           (),
           "The ligature table is missing or incomplete."))
         
         return False
     
     return True
コード例 #14
0
ファイル: insertion.py プロジェクト: nickssmith/jenkinsTests
    def fromvalidatedwalker(cls, w, **kwArgs):
        """
        Creates and returns a new Insertion object from the specified walker,
        doing source validation. The walker must start at the beginning
        (numClasses) of the state table.
        
        >>> s = _testingValues[0].binaryString()
        >>> logger = utilities.makeDoctestLogger("insertion_fvw")
        >>> fvb = Insertion.fromvalidatedbytes
        >>> d = {
        ...   'coverage': _testingValues[0].coverage,
        ...   'maskValue': 0x00000001,
        ...   'fontGlyphCount': 0x1000,
        ...   'logger': logger}
        >>> obj = fvb(s, **d)
        insertion_fvw.insertion - DEBUG - Walker has 220 remaining bytes.
        insertion_fvw.insertion.clstable - DEBUG - Walker has 32 remaining bytes.
        insertion_fvw.insertion.clstable.binsearch.binsrch header - DEBUG - Walker has 30 remaining bytes.
        
        >>> fvb(s[:9], **d)
        insertion_fvw.insertion - DEBUG - Walker has 9 remaining bytes.
        insertion_fvw.insertion - ERROR - Insufficient bytes.
        """

        logger = kwArgs.pop('logger', logging.getLogger())
        logger = logger.getChild("insertion")

        logger.debug(
            ('V0001', (w.length(), ), "Walker has %d remaining bytes."))

        if w.length() < 20:
            logger.error(('V0004', (), "Insufficient bytes."))
            return None

        fgc = utilities.getFontGlyphCount(**kwArgs)
        stBaseOffset = w.getOffset()
        tHeader = w.unpack("5L")
        numClasses, oCT, oSA, oET, oIG = tHeader

        if numClasses < 4:
            logger.error(
                ('V0634', (numClasses, ),
                 "The number of classes in the state table must be at least "
                 "four, but is only %d."))

            return None

        firstValid = w.getOffset() - stBaseOffset
        lastValidPlusOne = firstValid + w.length()

        if any(o < firstValid or o >= lastValidPlusOne for o in tHeader[1:]):
            logger.error(
                ('V0635', (),
                 "One or more offsets to state table components are outside "
                 "the bounds of the state table itself."))

            return None

        wCT, wSA, wET, wIG = stutils.offsetsToSubWalkers(
            w.subWalker(0), *tHeader[1:])

        rawEntries = wET.unpackRest("4H")

        numStates = max(
            int(wSA.length()) // (2 * numClasses),
            1 + max(t[0] for t in rawEntries))

        if numStates < 2:
            logger.error(
                ('V0725', (),
                 "The number of states in the state table is less than two. "
                 "The two fixed states must always be present."))

            return None

        rawInsertionGlyphs = wIG.unpackRest("H")

        nsObj = namestash.NameStash.readormake_validated(
            w, tHeader[1:], numStates, numClasses)

        if nsObj is None:
            return None

        stateNames = nsObj.allStateNames()
        classNames = nsObj.allClassNames()
        E = entry_insertion.Entry
        GTO = glyphtuple.GlyphTupleOutput
        entries = [None] * len(rawEntries)

        for i, raw in enumerate(rawEntries):
            newStateIndex, flags, currIGIndex, markIGIndex = raw
            currCount = (flags & 0x03E0) >> 5
            markCount = flags & 0x001F

            if currCount:
                if currIGIndex == 0xFFFF:
                    logger.error(
                        ('V0726', (i, ),
                         "The current insert count for entry %d is nonzero "
                         "but the corresponding glyph index is missing."))

                    return None

                elif currIGIndex + currCount > len(rawInsertionGlyphs):
                    logger.error((
                        'V0727', (i, ),
                        "The sum of the current insert count and the starting "
                        "glyph index for entry %d is beyond the end of the "
                        "insertion glyph array."))

                    return None

                t = rawInsertionGlyphs[currIGIndex:currIGIndex + currCount]

            else:
                t = []

            currGlyphs = GTO(t)

            if markCount:
                if markIGIndex == 0xFFFF:
                    logger.error(
                        ('V0726', (i, ),
                         "The marked insert count for entry %d is nonzero "
                         "but the corresponding glyph index is missing."))

                    return None

                elif markIGIndex + markCount > len(rawInsertionGlyphs):
                    logger.error(
                        ('V0727', (i, ),
                         "The sum of the marked insert count and the starting "
                         "glyph index for entry %d is beyond the end of the "
                         "insertion glyph array."))

                    return None

                t = rawInsertionGlyphs[markIGIndex:markIGIndex + markCount]

            else:
                t = []

            markGlyphs = GTO(t)

            entries[i] = E(newState=stateNames[newStateIndex],
                           mark=bool(flags & 0x8000),
                           noAdvance=bool(flags & 0x4000),
                           currentIsKashidaLike=bool(flags & 0x2000),
                           markedIsKashidaLike=bool(flags & 0x1000),
                           currentInsertBefore=bool(flags & 0x0800),
                           markedInsertBefore=bool(flags & 0x0400),
                           currentInsertGlyphs=currGlyphs,
                           markedInsertGlyphs=markGlyphs)

        classTable = classtable.ClassTable.fromvalidatedwalker(
            wCT, classNames=classNames, logger=logger, fontGlyphCount=fgc)

        if classTable is None:
            return None

        if wSA.length() < 2 * numClasses * numStates:
            logger.error(
                ('V0676', (), "The state array is missing or incomplete."))

            return None

        rawStateArray = wSA.group("H" * numClasses, numStates)

        kwArgs.pop('classTable', None)

        r = cls({},
                classTable=classTable,
                **utilities.filterKWArgs(cls, kwArgs))

        S = staterow_insertion.StateRow

        for stateIndex, rawState in enumerate(rawStateArray):
            r[stateNames[stateIndex]] = thisRow = S()

            for classIndex, entryIndex in enumerate(rawState):
                if entryIndex >= len(entries):
                    logger.error(
                        ('V0724', (stateNames[stateIndex],
                                   classNames[classIndex]),
                         "The state array cell for state '%s' and class '%s' "
                         "specifies an entry index that is out of range."))

                    return None

                thisRow[classNames[classIndex]] = entries[entryIndex]

        return r
コード例 #15
0
 def fromvalidatedwalker(cls, w, **kwArgs):
     """
     Creates and returns a new Ligature object from the specified walker,
     doing source validation. The walker should be based at the state table
     start (i.e. at numClasses).
     
     >>> origObj = _makeObj().trimmedToValidEntries()
     >>> s = origObj.binaryString()
     >>> logger = utilities.makeDoctestLogger("ligature_fvw")
     >>> fvb = Ligature.fromvalidatedbytes
     >>> d = {
     ...   'coverage': origObj.coverage,
     ...   'maskValue': 0x00000080,
     ...   'logger': logger,
     ...   'fontGlyphCount': 0x1000}
     >>> obj = fvb(s, **d)
     ligature_fvw.ligature - DEBUG - Walker has 514 remaining bytes.
     ligature_fvw.ligature.lookup_aat - DEBUG - Walker has 32 remaining bytes.
     ligature_fvw.ligature - WARNING - The entry for state 2, class 6 does ligature substitution, but does not lead back to the ground state. This might be problematic.
     ligature_fvw.ligature - WARNING - The entry for state 5, class 6 does ligature substitution, but does not lead back to the ground state. This might be problematic.
     ligature_fvw.ligature - WARNING - The entry for state 6, class 7 does ligature substitution, but does not lead back to the ground state. This might be problematic.
     ligature_fvw.ligature - WARNING - The entry for state 2, class 6 does ligature substitution, but does not lead back to the ground state. This might be problematic.
     ligature_fvw.ligature - WARNING - The entry for state 2, class 6 does ligature substitution, but does not lead back to the ground state. This might be problematic.
     ligature_fvw.ligature - WARNING - The entry for state 2, class 6 does ligature substitution, but does not lead back to the ground state. This might be problematic.
     ligature_fvw.ligature - WARNING - The entry for state 2, class 6 does ligature substitution, but does not lead back to the ground state. This might be problematic.
     ligature_fvw.ligature - WARNING - The entry for state 2, class 6 does ligature substitution, but does not lead back to the ground state. This might be problematic.
     ligature_fvw.ligature.namestash - DEBUG - Walker has 486 remaining bytes.
     ligature_fvw.ligature.clstable - DEBUG - Walker has 32 remaining bytes.
     >>> obj == origObj
     True
     
     >>> fvb(s[:19], **d)
     ligature_fvw.ligature - DEBUG - Walker has 19 remaining bytes.
     ligature_fvw.ligature - ERROR - Insufficient bytes.
     
     >>> fvb(s[:39], **d)
     ligature_fvw.ligature - DEBUG - Walker has 39 remaining bytes.
     ligature_fvw.ligature - ERROR - One or more offsets to state table components are outside the bounds of the state table itself.
     """
     
     logger = kwArgs.pop('logger', logging.getLogger())
     logger = logger.getChild('ligature')
     
     logger.debug((
       'V0001',
       (w.length(),),
       "Walker has %d remaining bytes."))
     
     analyzer = ligatureanalyzer.Analyzer(w.subWalker(0, relative=True))
     analyzer.analyze(logger=logger, **kwArgs)
     
     if analyzer.analysis is None:
         return None
     
     # Note that some of the size and other validation was already done in
     # the analyze() call, and is not reduplicated here.
     
     numClasses, oCT, oSA, oET, oLA, oCP, oLG = w.unpack("7L")
     offsets = (oCT, oSA, oET, oLA, oCP, oLG)
     
     wCT, wSA, wET, wLA, wCP, wLG = stutils.offsetsToSubWalkers(
       w.subWalker(0),
       *offsets)
     
     numStates = analyzer.numStates
     
     nsObj = namestash.NameStash.readormake_validated(
       w,
       offsets,
       numStates,
       numClasses,
       logger = logger)
     
     if nsObj is None:
         return None
     
     stateNames = nsObj.allStateNames()
     classNames = nsObj.allClassNames()
     fgc = utilities.getFontGlyphCount(**kwArgs)
     
     classTable = classtable.ClassTable.fromvalidatedwalker(
       wCT,
       classNames = classNames,
       logger = logger,
       fontGlyphCount = fgc)
     
     if classTable is None:
         return None
     
     kwArgs.pop('classTable', None)
     
     r = cls(
       {},
       classTable = classTable,
       **utilities.filterKWArgs(cls, kwArgs))
     
     entryPool = {}  # entryIndex -> Entry object
     
     for stateIndex, rawStateRow in enumerate(analyzer.stateArray):
         thisRow = staterow_ligature.StateRow()
         
         for classIndex, rawEntryIndex in enumerate(rawStateRow):
             if rawEntryIndex not in entryPool:
                 t = analyzer.entryTable[rawEntryIndex]
                 newStateIndex, flags, laIndex = t
                 
                 entryPool[rawEntryIndex] = entry_ligature.Entry(
                   newState = stateNames[newStateIndex],
                   push = bool(flags & 0x8000),
                   noAdvance = bool(flags & 0x4000))
             
             e = entryPool[rawEntryIndex]
             d = analyzer.finalDicts.get((stateIndex, classIndex), None)
             
             if d is not None:
                 for inGlyphs, outGlyphs in d.items():
                     gti = glyphtuple.GlyphTupleInput(inGlyphs)
                     
                     if gti not in e.actions:
                         gto = glyphtuple.GlyphTupleOutput(outGlyphs)
                         e.actions[gti] = gto
             
             thisRow[classNames[classIndex]] = e
         
         r[stateNames[stateIndex]] = thisRow
     
     return r.trimmedToValidEntries()
コード例 #16
0
ファイル: insertion.py プロジェクト: nickssmith/jenkinsTests
    def fromwalker(cls, w, **kwArgs):
        """
        Creates and returns a new Insertion object from the specified walker,
        which must start at the beginning (numClasses) of the state table.
        
        >>> obj = _testingValues[0]
        >>> s = obj.binaryString()
        >>> d = {
        ...   'maskValue': obj.maskValue,
        ...   'coverage': obj.coverage.__deepcopy__()}
        >>> obj == Insertion.frombytes(s, **d)
        True
        """

        numClasses, oCT, oSA, oET, oIG = w.unpack("5L")

        wCT, wSA, wET, wIG = stutils.offsetsToSubWalkers(
            w.subWalker(0), oCT, oSA, oET, oIG)

        rawEntries = wET.unpackRest("4H")

        numStates = max(
            int(wSA.length()) // (2 * numClasses),
            1 + max(t[0] for t in rawEntries))

        rawInsertionGlyphs = wIG.unpackRest("H")

        nsObj = namestash.NameStash.readormake(w, (oCT, oSA, oET, oIG),
                                               numStates, numClasses)

        stateNames = nsObj.allStateNames()
        classNames = nsObj.allClassNames()
        E = entry_insertion.Entry
        GTO = glyphtuple.GlyphTupleOutput
        entries = [None] * len(rawEntries)

        for i, raw in enumerate(rawEntries):
            newStateIndex, flags, currIGIndex, markIGIndex = raw
            currCount = (flags & 0x03E0) >> 5
            markCount = flags & 0x001F

            if currCount:
                t = rawInsertionGlyphs[currIGIndex:currIGIndex + currCount]
            else:
                t = []

            currGlyphs = GTO(t)

            if markCount:
                t = rawInsertionGlyphs[markIGIndex:markIGIndex + markCount]
            else:
                t = []

            markGlyphs = GTO(t)

            entries[i] = E(newState=stateNames[newStateIndex],
                           mark=bool(flags & 0x8000),
                           noAdvance=bool(flags & 0x4000),
                           currentIsKashidaLike=bool(flags & 0x2000),
                           markedIsKashidaLike=bool(flags & 0x1000),
                           currentInsertBefore=bool(flags & 0x0800),
                           markedInsertBefore=bool(flags & 0x0400),
                           currentInsertGlyphs=currGlyphs,
                           markedInsertGlyphs=markGlyphs)

        classTable = classtable.ClassTable.fromwalker(wCT,
                                                      classNames=classNames)

        rawStateArray = wSA.group("H" * numClasses, numStates)

        kwArgs.pop('classTable', None)

        r = cls({},
                classTable=classTable,
                **utilities.filterKWArgs(cls, kwArgs))

        S = staterow_insertion.StateRow

        for stateIndex, rawState in enumerate(rawStateArray):
            r[stateNames[stateIndex]] = thisRow = S()

            for classIndex, entryIndex in enumerate(rawState):
                thisRow[classNames[classIndex]] = entries[entryIndex]

        return r
コード例 #17
0
ファイル: format1.py プロジェクト: nickssmith/jenkinsTests
    def fromvalidatedwalker(cls, w, **kwArgs):
        """
        Creates and returns a new Format1 object from the specified walker,
        doing source validation.
        """

        logger = kwArgs.pop('logger', logging.getLogger())
        logger = logger.getChild("format1")

        logger.debug(
            ('V0001', (w.length(), ), "Walker has %d remaining bytes."))

        if w.length() < 20:
            logger.error(('V0004', (), "Insufficient bytes."))
            return None

        stBaseOffset = w.getOffset()
        t = w.unpack("5L")
        numClasses, oCT, oSA, oET, oVT = t

        if numClasses < 4:
            logger.error(
                ('V0634', (numClasses, ),
                 "The number of classes in the state table must be at least "
                 "four, but is only %d."))

            return None

        firstValid = w.getOffset() - stBaseOffset
        lastValidPlusOne = firstValid + w.length()

        if any(o < firstValid or o >= lastValidPlusOne for o in t[1:]):
            logger.error(
                ('V0635', (),
                 "One or more offsets to state table components are outside "
                 "the bounds of the state table itself."))

            return None

        wCT, wSA, wET, wVT = stutils.offsetsToSubWalkers(
            w.subWalker(0), *t[1:])

        wETCopy = wET.subWalker(0, relative=True)
        v = wETCopy.unpackRest("3H", strict=False)
        numStates = 1 + utilities.safeMax(x[0] for x in v)
        numEntries = len(v)

        nsObj = namestash.NameStash.readormake_validated(w,
                                                         (oCT, oSA, oET, oVT),
                                                         numStates,
                                                         numClasses,
                                                         logger=logger)

        if nsObj is None:
            return None

        stateNames = nsObj.allStateNames()
        classNames = nsObj.allClassNames()

        classTable = classtable.ClassTable.fromvalidatedwalker(
            wCT, classNames=classNames, logger=logger)

        if classTable is None:
            return None

        kwArgs.pop('classTable', None)

        r = cls({},
                classTable=classTable,
                **utilities.filterKWArgs(cls, kwArgs))

        # build value table
        valueDict = {}
        fvw = valuetuple.ValueTuple.fromvalidatedwalker
        index = 0

        while wVT.stillGoing():
            obj = fvw(wVT, logger=logger.getChild("value %d" % (index, )))

            if obj is None:
                return None

            valueDict[index] = obj
            index += 1

        # build entry table
        entries = []
        index = 0
        fvw = entry.Entry.fromvalidatedwalker

        while index < numEntries:
            obj = fvw(wET,
                      stateNames=stateNames,
                      valueDict=valueDict,
                      logger=logger.getChild("entry %d" % (index, )))

            if obj is None:
                return None

            entries.append(obj)
            index += 1

        # finally, build state table
        fvw = staterow.StateRow.fromvalidatedwalker

        for stateName in stateNames:
            obj = fvw(wSA,
                      classNames=classNames,
                      entries=entries,
                      logger=logger.getChild("state %s" % (stateName, )))

            if obj is None:
                return None

            r[stateName] = obj

        return r
コード例 #18
0
    def fromvalidatedwalker(cls, w, **kwArgs):
        """
        Creates and returns a new Contextual object from the specified walker,
        doing source validation.
        
        >>> s = _testingValues[0].binaryString()
        >>> logger = utilities.makeDoctestLogger("contextual_fvw")
        >>> fvb = Contextual.fromvalidatedbytes
        >>> d = {
        ...   'coverage': _testingValues[0].coverage,
        ...   'maskValue': 0x10000000,
        ...   'logger': logger}
        >>> obj = fvb(s, **d)
        contextual_fvw.contextual - DEBUG - Walker has 126 remaining bytes.
        contextual_fvw.contextual.namestash - DEBUG - Walker has 116 remaining bytes.
        contextual_fvw.contextual.classtable - DEBUG - Walker has 34 remaining bytes.
        >>> obj == _testingValues[0]
        True
        
        >>> fvb(s[:5], **d)
        contextual_fvw.contextual - DEBUG - Walker has 5 remaining bytes.
        contextual_fvw.contextual - ERROR - Insufficient bytes.
        
        >>> fvb(s[:23], **d)
        contextual_fvw.contextual - DEBUG - Walker has 23 remaining bytes.
        contextual_fvw.contextual - ERROR - One or more offsets to state table components are outside the bounds of the state table itself.
        """

        logger = kwArgs.pop('logger', logging.getLogger())
        logger = logger.getChild("contextual")

        logger.debug(
            ('V0001', (w.length(), ), "Walker has %d remaining bytes."))

        analyzer = contextanalyzer.Analyzer(w.subWalker(0, relative=True))
        markAnalysis, currAnalysis = analyzer.analyze(logger=logger)

        if markAnalysis is None or currAnalysis is None:
            return None

        # Note that some of the size and other validation was already done in
        # the analyze() call, and is not reduplicated here.

        t = w.unpack("5H")
        numClasses, oCT, oSA, oET, oST = t
        t = t[1:]
        wCT, wSA, wET, wST = stutils.offsetsToSubWalkers(w.subWalker(0), *t)
        numStates = analyzer.numStates

        nsObj = namestash.NameStash.readormake_validated(w,
                                                         t,
                                                         numStates,
                                                         numClasses,
                                                         logger=logger)

        if nsObj is None:
            return None

        stateNames = nsObj.allStateNames()
        classNames = nsObj.allClassNames()

        classTable = classtable.ClassTable.fromvalidatedwalker(
            wCT, classNames=classNames, logger=logger)

        if classTable is None:
            return None

        kwArgs.pop('classTable', None)

        r = cls({},
                classTable=classTable,
                **utilities.filterKWArgs(cls, kwArgs))

        entryTable = analyzer.entryTable
        Entry = entry_contextual.Entry
        GlyphDict = glyphdict.GlyphDict
        StateRow = staterow_contextual.StateRow

        for stateIndex, rawState in enumerate(analyzer.stateArray):
            newRow = staterow_contextual.StateRow()

            for classIndex, entryIndex in enumerate(rawState):
                newStateOffset, flags = entryTable[entryIndex][0:2]
                newStateIndex = (newStateOffset - oSA) // numClasses

                newEntry = Entry(newState=stateNames[newStateIndex],
                                 mark=bool(flags & 0x8000),
                                 noAdvance=bool(flags & 0x4000),
                                 markSubstitutionDict=GlyphDict(
                                     markAnalysis.get(entryIndex, {})),
                                 currSubstitutionDict=GlyphDict(
                                     currAnalysis.get(entryIndex, {})))

                newRow[classNames[classIndex]] = newEntry

            r[stateNames[stateIndex]] = newRow

        return r
コード例 #19
0
    def fromvalidatedwalker(cls, w, **kwArgs):
        """
        Creates and returns a new Rearrangement object from the specified
        walker, doing source validation. The walker must start at the
        beginning (numClasses) of the state table.
        
        >>> s = _testingValues[0].binaryString()
        >>> logger = utilities.makeDoctestLogger("rearrangement_fvw")
        >>> fvb = Rearrangement.fromvalidatedbytes
        >>> d = {
        ...   'logger': logger,
        ...   'fontGlyphCount': 0x1000,
        ...   'coverage': _testingValues[0].coverage,
        ...   'maskValue': 0x04000000}
        >>> obj = fvb(s, **d)
        rearrangement_fvw.rearrangement - DEBUG - Walker has 148 remaining bytes.
        rearrangement_fvw.rearrangement.namestash - DEBUG - Walker has 140 remaining bytes.
        rearrangement_fvw.rearrangement.classtable - DEBUG - Walker has 44 remaining bytes.
        >>> obj == _testingValues[0]
        True
        
        >>> fvb(s[:6], **d)
        rearrangement_fvw.rearrangement - DEBUG - Walker has 6 remaining bytes.
        rearrangement_fvw.rearrangement - ERROR - Insufficient bytes.
        
        >>> fvb(utilities.fromhex("00 02") + s[2:], **d)
        rearrangement_fvw.rearrangement - DEBUG - Walker has 148 remaining bytes.
        rearrangement_fvw.rearrangement - ERROR - The number of classes in the state table must be at least four, but is only 2.
        """

        logger = kwArgs.pop('logger', logging.getLogger())
        logger = logger.getChild("rearrangement")

        logger.debug(
            ('V0001', (w.length(), ), "Walker has %d remaining bytes."))

        if w.length() < 8:
            logger.error(('V0004', (), "Insufficient bytes."))
            return None

        stBaseOffset = w.getOffset()
        t = w.unpack("4H")
        numClasses, oCT, oSA, oET = t

        if numClasses < 4:
            logger.error(
                ('V0634', (numClasses, ),
                 "The number of classes in the state table must be at least "
                 "four, but is only %d."))

            return None

        firstValid = w.getOffset() - stBaseOffset
        lastValidPlusOne = firstValid + w.length()

        if any(o < firstValid or o >= lastValidPlusOne for o in t[1:]):
            logger.error(
                ('V0635', (),
                 "One or more offsets to state table components are outside "
                 "the bounds of the state table itself."))

            return None

        wCT, wSA, wET = stutils.offsetsToSubWalkers(w.subWalker(0), *t[1:])

        wETCopy = wET.subWalker(0, relative=True)

        if wETCopy.length() < 4:
            logger.error(
                ('V0636', (), "The entry table is missing or incomplete."))

            return None

        rawEntries = wET.unpackRest("2H")
        maxOffset = max(offset for offset, flags in rawEntries)
        numStates = 1 + (maxOffset - oSA) // numClasses

        nsObj = namestash.NameStash.readormake_validated(w,
                                                         t[1:],
                                                         numStates,
                                                         numClasses,
                                                         logger=logger)

        if nsObj is None:
            return nsObj

        stateNames = nsObj.allStateNames()
        classNames = nsObj.allClassNames()
        fgc = kwArgs.pop('fontGlyphCount')

        classTable = classtable.ClassTable.fromvalidatedwalker(
            wCT, classNames=classNames, logger=logger, fontGlyphCount=fgc)

        if classTable is None:
            return None

        if wSA.length() < numClasses * numStates:
            logger.error(
                ('V0676', (), "The state array is missing or incomplete."))

            return None

        rawStateArray = wSA.group("B" * numClasses, numStates)

        kwArgs.pop('classTable', None)

        r = cls({},
                classTable=classTable,
                **utilities.filterKWArgs(cls, kwArgs))

        S = staterow_rearrangement.StateRow
        E = entry_rearrangement.Entry
        V = verbs_rearrangement.Verb

        for stateIndex, rawState in enumerate(rawStateArray):
            thisRow = S()

            for classIndex, entryIndex in enumerate(rawState):
                if entryIndex >= len(rawEntries):
                    logger.error(
                        ('V0724', (stateNames[stateIndex],
                                   classNames[classIndex]),
                         "The state array cell for state '%s' and class '%s' "
                         "specifies an entry index that is out of range."))

                    return None

                newStateOffset, flags = rawEntries[entryIndex]

                thisRow[classNames[classIndex]] = E(
                    markFirst=bool(flags & 0x8000),
                    markLast=bool(flags & 0x2000),
                    newState=stateNames[(newStateOffset - oSA) // numClasses],
                    noAdvance=bool(flags & 0x4000),
                    verb=V(flags & 0x000F))

            r[stateNames[stateIndex]] = thisRow

        return r
コード例 #20
0
 def fromwalker(cls, w, **kwArgs):
     """
     Creates and returns a new Ligature object from the specified walker,
     which should be based at the state header start (numClasses).
     
     >>> origObj = _makeObj().trimmedToValidEntries()
     >>> d = {'coverage': origObj.coverage, 'maskValue': 0x00000080}
     >>> obj = Ligature.frombytes(origObj.binaryString(), **d)
     >>> obj == origObj
     True
     """
     
     analyzer = ligatureanalyzer.Analyzer(w.subWalker(0, relative=True))
     analyzer.analyze(**kwArgs)
     numClasses, oCT, oSA, oET, oLA, oCP, oLG = w.unpack("7L")
     offsets = (oCT, oSA, oET, oLA, oCP, oLG)
     
     wCT, wSA, wET, wLA, wCP, wLG = stutils.offsetsToSubWalkers(
       w.subWalker(0),
       *offsets)
     
     numStates = analyzer.numStates
     
     nsObj = namestash.NameStash.readormake(
       w,
       offsets,
       numStates,
       numClasses)
     
     stateNames = nsObj.allStateNames()
     classNames = nsObj.allClassNames()
     
     classTable = classtable.ClassTable.fromwalker(
       wCT,
       classNames = classNames)
     
     kwArgs.pop('classTable', None)
     
     r = cls(
       {},
       classTable = classTable,
       **utilities.filterKWArgs(cls, kwArgs))
     
     entryPool = {}  # entryIndex -> Entry object
     
     for stateIndex, rawStateRow in enumerate(analyzer.stateArray):
         thisRow = staterow_ligature.StateRow()
         
         for classIndex, rawEntryIndex in enumerate(rawStateRow):
             if rawEntryIndex not in entryPool:
                 t = analyzer.entryTable[rawEntryIndex]
                 newStateIndex, flags, laIndex = t
                 
                 entryPool[rawEntryIndex] = entry_ligature.Entry(
                   newState = stateNames[newStateIndex],
                   push = bool(flags & 0x8000),
                   noAdvance = bool(flags & 0x4000))
             
             e = entryPool[rawEntryIndex]
             d = analyzer.finalDicts.get((stateIndex, classIndex), None)
             
             if d is not None:
                 for inGlyphs, outGlyphs in d.items():
                     gti = glyphtuple.GlyphTupleInput(inGlyphs)
                     
                     if gti not in e.actions:
                         gto = glyphtuple.GlyphTupleOutput(outGlyphs)
                         e.actions[gti] = gto
             
             thisRow[classNames[classIndex]] = e
         
         r[stateNames[stateIndex]] = thisRow
     
     return r.trimmedToValidEntries()
コード例 #21
0
    def _buildInputs_validated(self, logger):
        self.w.reset()
        stBaseOffset = self.w.getOffset()

        if self.w.length() < 20:
            logger.error(('V0004', (), "Insufficient bytes."))
            return False

        t = self.w.unpack("5L")
        self.numClasses, oCT, oSA, oET, oGT = t

        if self.numClasses < 4:
            logger.error(
                ('V0634', (self.numClasses, ),
                 "The number of classes in a state table must be at least "
                 "four, but is only %d."))

            return False

        firstValid = self.w.getOffset() - stBaseOffset
        lastValidPlusOne = firstValid + self.w.length()

        if any(o < firstValid or o >= lastValidPlusOne for o in t[1:]):
            logger.error(
                ('V0635', (),
                 "One or more offsets to state table components are outside "
                 "the bounds of the state table itself."))

            return False

        wCT, wSA, wET, wGT = stutils.offsetsToSubWalkers(self.w, *t[1:])
        self.entryTable = wET.unpackRest("4H", strict=False)

        if not self.entryTable:
            logger.error(
                ('V0636', (), "The entry table is missing or incomplete."))

            return False

        if len(self.entryTable) != len(set(self.entryTable)):
            logger.error(
                ('Vxxxx', (),
                 "The entry table has duplicate rows; this usually means "
                 "a copy/paste error or some other problem."))

            return False

        self.numStates = max(
            int(wSA.length()) // (2 * self.numClasses),
            1 + max(t[0] for t in self.entryTable))

        if self.numStates < 2:
            logger.error(
                ('V0725', (),
                 "The number of states in the state table is less than two. "
                 "The two fixed states must always be present."))

            return None

        self.classMap = lookup.Lookup.fromvalidatedwalker(
            wCT, logger=logger.getChild("classmap"))

        if not self.classMap:
            return False

        d = utilities.invertDictFull(self.classMap, asSets=True)
        self.classToGlyphs = {k: v for k, v in d.items() if k >= 4}
        self.classToGlyphs[2] = {0xFFFF}

        self.emptyClasses = (set(range(4, self.numClasses)) -
                             set(self.classToGlyphs))

        if wSA.length() < 2 * self.numClasses * self.numStates:
            logger.error(
                ('V0676', (), "The state array is missing or incomplete."))

            return False

        self.stateArray = wSA.group("H" * self.numClasses, self.numStates)
        maxEntryIndex = max(n for row in self.stateArray for n in row)

        if maxEntryIndex >= len(self.entryTable):
            logger.error(
                ('V0724', (stateNames[stateIndex], classNames[classIndex]),
                 "At least one state array cell contains an entry index that "
                 "is out of range."))

            return False

        numLookups = 1 + max(n for t in self.entryTable
                             for n in t[2:4] if n != 0xFFFF)

        if wGT.length() < 4 * numLookups:
            logger.error(
                ('V0728', (),
                 "The offset header to the per-glyph lookup tables is "
                 "missing or incomplete."))

            return False

        self.glyphLookups = [None] * numLookups
        offsets = wGT.group("L", numLookups)
        f = lookup.Lookup_OutGlyph.fromvalidatedwalker

        for i, offset in enumerate(offsets):
            wSub = wGT.subWalker(offset)

            self.glyphLookups[i] = f(wSub,
                                     logger=logger.getChild("per-glyph %d" %
                                                            (i, )))

            if self.glyphLookups[i] is None:
                return False

        return True
コード例 #22
0
    def _buildInputs_validated(self, logger):
        self.w.reset()
        stBaseOffset = self.w.getOffset()

        if self.w.length() < 28:
            logger.error(('V0004', (), "Insufficient bytes."))
            return False

        t = self.w.unpack("7L")
        self.numClasses, oCT, oSA, oET, oLA, oCP, oLG = t

        if self.numClasses < 4:
            logger.error(
                ('V0634', (self.numClasses, ),
                 "The number of classes in a state table must be at least "
                 "four, but is only %d."))

            return False

        firstValid = self.w.getOffset() - stBaseOffset
        lastValidPlusOne = firstValid + self.w.length()

        if any(o < firstValid or o >= lastValidPlusOne for o in t[1:]):
            logger.error(
                ('V0635', (),
                 "One or more offsets to state table components are outside "
                 "the bounds of the state table itself."))

            return False

        wCT, wSA, wET, wLA, wCP, wLG = stutils.offsetsToSubWalkers(
            self.w, *t[1:])

        self.entryTable = list(wET.unpackRest("3H", strict=False))

        if not self.entryTable:
            logger.error(
                ('V0636', (), "The entry table is missing or incomplete."))

            return False

        self.numStates = max(
            int(wSA.length()) // (2 * self.numClasses),
            1 + max(t[0] for t in self.entryTable))

        if self.numStates < 2:
            logger.error(
                ('V0725', (),
                 "The number of states in the state table is less than two. "
                 "The two fixed states must always be present."))

            return None

        self.classMap = lookup.Lookup.fromvalidatedwalker(wCT, logger=logger)

        if self.classMap is None:
            return False

        d = utilities.invertDictFull(self.classMap, asSets=True)
        self.classToGlyphs = {k: frozenset(v) for k, v in d.items() if k >= 4}
        self.classToGlyphs[2] = frozenset([0xFFFF])

        if wSA.length() < 2 * self.numClasses * self.numStates:
            logger.error(
                ('V0676', (), "The state array is missing or incomplete."))

            return False

        self.stateArray = wSA.group("H" * self.numClasses, self.numStates)
        maxEntryIndex = max(n for row in self.stateArray for n in row)

        if maxEntryIndex >= len(self.entryTable):
            logger.error(
                ('V0724', (),
                 "At least one state array cell contains an entry index that "
                 "is out of range."))

            return False

        self.ligActions = wLA.unpackRest("L")

        if not self.ligActions:
            logger.error(
                ('V0690', (),
                 "The ligature action list is missing or incomplete."))

            return False

        self.ligActionIsLast = [bool(n & 0x80000000) for n in self.ligActions]
        self.compIndices = wCP.unpackRest("H")

        if not self.compIndices:
            logger.error(
                ('V0691', (), "The component table is missing or incomplete."))

            return False

        self.ligatures = wLG.unpackRest("H")

        if not self.ligatures:
            logger.error(
                ('V0692', (), "The ligature table is missing or incomplete."))

            return False

        return True
コード例 #23
0
    def fromvalidatedwalker(cls, w, **kwArgs):
        """
        Creates and returns a new Insertion object from the specified walker,
        doing source validation. The walker must start at the beginning
        (numClasses) of the state table.
        """

        logger = kwArgs.pop('logger', logging.getLogger())
        logger = logger.getChild("insertion")

        logger.debug(
            ('V0001', (w.length(), ), "Walker has %d remaining bytes."))

        if w.length() < 8:
            logger.error(('V0004', (), "Insufficient bytes."))
            return None

        stBaseOffset = w.getOffset()
        tHeader = w.unpack("4H")
        numClasses, oCT, oSA, oET = tHeader

        if numClasses < 4:
            logger.error(
                ('V0634', (numClasses, ),
                 "The number of classes in the state table must be at least "
                 "four, but is only %d."))

            return None

        firstValid = w.getOffset() - stBaseOffset
        lastValidPlusOne = firstValid + w.length()

        if any(o < firstValid or o >= lastValidPlusOne for o in tHeader[1:]):
            logger.error(
                ('V0635', (),
                 "One or more offsets to state table components are outside "
                 "the bounds of the state table itself."))

            return None

        wCT, wSA, wET = stutils.offsetsToSubWalkers(w.subWalker(0),
                                                    *tHeader[1:])

        if wET.length() < 8:
            logger.error(
                ('V0636', (), "The entry table is missing or incomplete."))

            return None

        rawEntries = wET.unpackRest("4H")
        maxOffset = max(t[0] for t in rawEntries)
        numStates = 1 + (maxOffset - oSA) // numClasses

        nsObj = namestash.NameStash.readormake_validated(w,
                                                         tHeader[1:],
                                                         numStates,
                                                         numClasses,
                                                         logger=logger)

        if nsObj is None:
            return None

        stateNames = nsObj.allStateNames()
        classNames = nsObj.allClassNames()

        classTable = classtable.ClassTable.fromvalidatedwalker(
            wCT,
            classNames=classNames,
            logger=logger,
            fontGlyphCount=kwArgs.pop('fontGlyphCount'))

        if classTable is None:
            return None

        E = entry_insertion.Entry
        GTO = glyphtuple.GlyphTupleOutput
        entries = [None] * len(rawEntries)

        for i, raw in enumerate(rawEntries):
            newStateOffset, flags, currOffset, markOffset = raw
            currCount = (flags & 0x03E0) >> 5
            markCount = flags & 0x001F

            if currCount:
                if currOffset == 0xFFFF:
                    logger.error(
                        ('V0720', (i, ),
                         "The current insert count for entry %d is nonzero "
                         "but the corresponding offset is the missing value."))

                    return None

                wSub = w.subWalker(currOffset)

                if wSub.length() < 2 * currCount:
                    logger.error(
                        ('V0721', (i, ),
                         "The current insert list for entry %d is missing "
                         "or incomplete."))

                    return None

                t = wSub.group("H", currCount)

            else:
                t = []

            currGlyphs = GTO(t)

            if markCount:
                if markOffset == 0xFFFF:
                    logger.error(
                        ('V0722', (i, ),
                         "The marked insert count for entry %d is nonzero "
                         "but the corresponding offset is the missing value."))

                    return None

                wSub = w.subWalker(markOffset)

                if wSub.length() < 2 * markCount:
                    logger.error(
                        ('V0723', (i, ),
                         "The marked insert list for entry %d is missing "
                         "or incomplete."))

                    return None

                t = wSub.group("H", markCount)

            else:
                t = []

            markGlyphs = GTO(t)

            entries[i] = E(newState=stateNames[(newStateOffset - oSA) //
                                               numClasses],
                           mark=bool(flags & 0x8000),
                           noAdvance=bool(flags & 0x4000),
                           currentIsKashidaLike=bool(flags & 0x2000),
                           markedIsKashidaLike=bool(flags & 0x1000),
                           currentInsertBefore=bool(flags & 0x0800),
                           markedInsertBefore=bool(flags & 0x0400),
                           currentInsertGlyphs=currGlyphs,
                           markedInsertGlyphs=markGlyphs)

        if wSA.length() < numClasses * numStates:
            logger.error(
                ('V0676', (), "The state array is missing or incomplete."))

            return None

        rawStateArray = wSA.group("B" * numClasses, numStates)

        kwArgs.pop('classTable', None)

        r = cls({},
                classTable=classTable,
                **utilities.filterKWArgs(cls, kwArgs))

        S = staterow_insertion.StateRow

        for stateIndex, rawState in enumerate(rawStateArray):
            r[stateNames[stateIndex]] = thisRow = S()

            for classIndex, entryIndex in enumerate(rawState):
                if entryIndex >= len(entries):
                    logger.error(
                        ('V0724', (stateNames[stateIndex],
                                   classNames[classIndex]),
                         "The state array cell for state '%s' and class '%s' "
                         "specifies an entry index that is out of range."))

                    return None

                thisRow[classNames[classIndex]] = entries[entryIndex]

        return r