Пример #1
0
class DataReader:
    data = attrib()

    def __attrs_post_init__(self):
        if not hasattr(self.data, 'read'):
            self.data = BytesIO(self.data)

    def close(self):
        self.data.close()

    def peek(self, size=DEFAULT_BUFFER_SIZE):
        if size > DEFAULT_BUFFER_SIZE:
            size = DEFAULT_BUFFER_SIZE

        peeked = None
        try:
            peeked = self.data.peek(size)[:size]
        except AttributeError:
            pass

        if peeked is None or len(peeked) != size:
            peeked = self.data.read(size)
            self.data.seek(-len(peeked), os.SEEK_CUR)

        return peeked

    def read(self, size=None):
        return self.data.read(size)

    def seek(self, offset, whence=os.SEEK_SET):
        self.data.seek(offset, whence)

    def tell(self):
        return self.data.tell()
Пример #2
0
def bdecode(f_or_data):
    """
	bdecodes data by looking up the type byte,
	and using it to look up the respective decoding function,
	which in turn is used to return the decoded object
	
	The parameter can be a file opened in bytes mode,
	bytes or a string (the last of which will be decoded)
	"""
    if isinstance(f_or_data, str):
        f_or_data = f_or_data.encode()
    if isinstance(f_or_data, bytes):
        f_or_data = BytesIO(f_or_data)

    #TODO: the following line is the only one that needs readahead.
    #peek returns a arbitrary amount of bytes, so we have to slice.
    if f_or_data.seekable():
        first_byte = f_or_data.read(1)
        f_or_data.seek(-1, SEEK_CUR)
    else:
        first_byte = f_or_data.peek(1)[:1]
    btype = TYPES.get(first_byte)
    if btype is not None:
        return btype(f_or_data)
    else:  #Used in dicts and lists to designate an end
        assert_btype(f_or_data.read(1), _TYPE_END)
        return None
Пример #3
0
    def from_bytes(cls, bytestr):
        # TODO: generify
        bio = BytesIO(bytestr)
        reader = ResponseReader()
        state = reader.state
        while True:
            if state is M.Complete:
                break
            elif state.type == M.NeedLine.type:
                line = bio.readline()  # TODO: limit?
                next_state = M.HaveLine(value=line)
            elif state.type == M.NeedData.type:
                data = bio.read(state.amount)
                # TODO: can this block or return None if empty etc?
                next_state = M.HaveData(value=data)
            elif state.type == M.NeedPeek.type:
                peeked = bio.peek(state.amount)
                if not peeked:
                    pass  # TODO: again, what happens on end of stream
                next_state = M.HavePeek(amount=peeked)
            else:
                raise RuntimeError('Unknown state %r' % (state,))
            state = reader.send(next_state)

        return reader.raw_response
Пример #4
0
def bdecode(f_or_data):
    """
    bdecodes data by looking up the type byte,
    and using it to look up the respective decoding function,
    which in turn is used to return the decoded object

    The parameter can be a file opened in bytes mode,
    bytes or a string (the last of which will be decoded)
    """
    if isinstance(f_or_data, str):
        f_or_data = f_or_data.encode()
    if isinstance(f_or_data, bytes):
        f_or_data = BytesIO(f_or_data)

    #TODO: the following line is the only one that needs readahead.
    #peek returns a arbitrary amount of bytes, so we have to slice.
    if f_or_data.seekable():
        first_byte = f_or_data.read(1)
        f_or_data.seek(-1, SEEK_CUR)
    else:
        #FIXME: muted bug!
        first_byte = f_or_data.peek(1)[:1]  # pylint: disable=no-member
    btype = TYPES.get(first_byte)
    if btype is not None:
        return btype(f_or_data)
    else: #Used in dicts and lists to designate an end
        assert_btype(f_or_data.read(1), _TYPE_END)
        return None
Пример #5
0
    def deserialize(cls, list_: BytesIO, type_) -> typing.List:
        # We need to know the type of the objects contained in the list,
        # otherwise we'd have no idea how to deserialize it.

        # We wrap the BytesIO in a BufferedReader to get the .peek() method.
        list_ = BufferedReader(list_)

        length = int.from_bytes(list_.read(cls.size_length), "big")
        items = []
        while list_.peek(1) != b"":
            i = type_.deserialize(list_)
            if i == b"":
                break
            items.append(i)

        return items
Пример #6
0
 def parse(cls, string, ctx=None):
     if not isinstance(string, io.BufferedReader):
         if not isinstance(string, BytesIO):
             if isinstance(string, str):
                 string = bytes(string, encoding="utf-8")
             string = BytesIO(string)
         string = io.BufferedReader(string)
     d = string.peek()
     big_enough = len(d) > 1
     if big_enough:
         _c = cacher.retrieve(cls, d)
         if _c is not None:
             return _c
     if ctx is None:
         ctx = {}
     res = cls.parse_stream(string, ctx)
     if big_enough:
         cacher.set(cls, res, d)
     return res
Пример #7
0
 def parse(cls, string, ctx=None):
     if not isinstance(string, io.BufferedReader):
         if not isinstance(string, BytesIO):
             if isinstance(string, str):
                 string = bytes(string, encoding="utf-8")
             string = BytesIO(string)
         string = io.BufferedReader(string)
     d = string.peek()
     big_enough = len(d) > 1
     if big_enough:
         k = cacher.get_key(d)
         _c = cacher.retrieve(cls, d)
         if _c is not None:
             #print("Returning cached item")
             return _c
     if ctx is None:
         ctx = OrderedDotDict()
     res = cls.parse_stream(string, ctx)
     if big_enough:
         cacher.set(cls, res, d)
     return res