File: buffer.py

package info (click to toggle)
python-dnslib 0.9.7%2Bhg20170303-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 412 kB
  • ctags: 506
  • sloc: python: 2,776; sh: 16; makefile: 5
file content (114 lines) | stat: -rw-r--r-- 2,799 bytes parent folder | download
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
# -*- coding: utf-8 -*-

"""
    Buffer - simple data buffer
"""

import binascii,struct

class BufferError(Exception):
    pass

class Buffer(object):

    """
    A simple data buffer - supports packing/unpacking in struct format 

    # Needed for Python 2/3 doctest compatibility
    >>> def p(s):
    ...     if not isinstance(s,str):
    ...         return s.decode()
    ...     return s

    >>> b = Buffer()
    >>> b.pack("!BHI",1,2,3)
    >>> b.offset
    7
    >>> b.append(b"0123456789")
    >>> b.offset
    17
    >>> p(b.hex())
    '0100020000000330313233343536373839'
    >>> b.offset = 0
    >>> b.unpack("!BHI")
    (1, 2, 3)
    >>> bytearray(b.get(5))
    bytearray(b'01234')
    >>> bytearray(b.get(5))
    bytearray(b'56789')
    >>> b.update(7,"2s",b"xx")
    >>> b.offset = 7
    >>> bytearray(b.get(5))
    bytearray(b'xx234')
    """

    def __init__(self,data=b''):
        """
            Initialise Buffer from data
        """
        self.data = bytearray(data)
        self.offset = 0

    def remaining(self):
        """
            Return bytes remaining
        """
        return len(self.data) - self.offset

    def get(self,length):
        """
            Gen len bytes at current offset (& increment offset)
        """
        if length > self.remaining():
            raise BufferError("Not enough bytes [offset=%d,remaining=%d,requested=%d]" %
                    (self.offset,self.remaining(),length))
        start = self.offset
        end = self.offset + length
        self.offset += length
        return bytes(self.data[start:end])

    def hex(self):
        """
            Return data as hex string
        """
        return binascii.hexlify(self.data)

    def pack(self,fmt,*args):
        """
            Pack data at end of data according to fmt (from struct) & increment
            offset
        """
        self.offset += struct.calcsize(fmt)
        self.data += struct.pack(fmt,*args)

    def append(self,s):
        """
            Append s to end of data & increment offset
        """
        self.offset += len(s)
        self.data += s

    def update(self,ptr,fmt,*args):
        """
            Modify data at offset `ptr` 
        """
        s = struct.pack(fmt,*args)
        self.data[ptr:ptr+len(s)] = s

    def unpack(self,fmt):
        """
            Unpack data at current offset according to fmt (from struct)
        """
        try:
            data = self.get(struct.calcsize(fmt))
            return struct.unpack(fmt,data)
        except struct.error as e:
            raise BufferError("Error unpacking struct '%s' <%s>" % 
                    (fmt,binascii.hexlify(data).decode()))

    def __len__(self):
        return len(self.data)

if __name__ == '__main__':
    import doctest
    doctest.testmod()