File: keymap.py

package info (click to toggle)
pwntools 4.15.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 18,508 kB
  • sloc: python: 59,870; ansic: 48,351; asm: 45,047; sh: 396; makefile: 256
file content (116 lines) | stat: -rw-r--r-- 3,084 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
from __future__ import absolute_import
from __future__ import division

from pwnlib.term import key

__all__ = ['Keymap']



class Keymap:
    def __init__(self, bindings, on_match = None, on_nomatch = None,
                  on_key = None):
        self._on_match = on_match
        self._on_nomatch = on_nomatch
        self._on_key = on_key
        self._top = {}
        self._cur = self._top
        self.trace = []
        self.register(bindings)

    def handle_input(self):
        self._doread = True
        while self._doread:
            self.send(key.get())

    def stop(self):
        self._doread = False

    @property
    def currently_entered(self):
        return ' '.join(map(str, self.trace))

    def reset(self):
        self._cur = self._top
        self.trace = []

    def send(self, k):
        if k is None:
            raise EOFError
        self.trace.append(k)
        if self._on_key:
            self._on_key(self.trace)
        match = False
        for m, (t, cbs) in self._cur.items():
            if m(k):
                self._cur = t
                if cbs:
                    match = True
                    if self._on_match:
                        self._on_match(self.trace)
                    for cb in cbs:
                        cb(self.trace)
        if not match and self._on_nomatch:
            self._on_nomatch(self.trace)
        tr = self.trace
        if len(self._cur) == 0 or not match:
            self.reset()
        if len(tr) > 1 and not match:
            self.send(k)

    def register(self, desc, cb = None):
        if isinstance(desc, dict):
            for k, v in desc.items():
                self.register(k, v)
        else:
            if   desc == '<match>':
                self.on_match(cb)
            elif desc == '<nomatch>':
                self.on_nomatch(cb)
            elif desc == '<any>':
                self.on_key(cb)
            else:
                ms = map(key.Matcher, desc.split(' '))
                if not ms:
                    return
                t = self._top
                for m in ms:
                    if m not in t:
                        t[m] = ({}, [])
                    t, cbs = t[m]
                cbs.append(cb)

    def unregister(self, desc, cb = None):
        ms = map(key.Matcher, desc.split(' '))
        if not ms:
            return
        t = self._top
        bt = []
        cbs = None
        for m in ms:
            if m not in t:
                return
            bt.append((t, cbs))
            t, cbs = t[m]
        if cb and cb in cbs:
            cbs.remove(cb)
        else:
            while True:
                try:
                    cbs.pop()
                except IndexError:
                    break
        # delete empty branch by backtracking
        while not t and not cbs:
            m = ms.pop()
            t, cbs = bt.pop()
            del t[m]

    def on_match(self, cb):
        self._on_match = cb

    def on_nomatch(self, cb):
        self._on_nomatch = cb

    def on_key(self, cb):
        self._on_key = cb