encoder.py (3441B)
1 # standard imports 2 import sys 3 import logging 4 import ctypes 5 import enum 6 7 # local imports 8 from . import ( 9 LIBRLP_RLP_MAX_LIST_DEPTH, 10 librlp, 11 ) 12 13 logg = logging.getLogger().getChild(__name__) 14 15 16 class RLPState(enum.IntEnum): 17 RLP_DECODE=0, 18 RLP_ENCODE=1, 19 RLP_LIST_ASCEND=2, 20 RLP_LIST_DESCEND=3, 21 RLP_STRING=4, 22 RLP_END=5, 23 24 25 class RLPEncoder: 26 27 __nullptr = ctypes.POINTER(ctypes.c_void_p)() 28 29 def __init__(self, buffer_size): 30 31 class RLPEncoderBackend(ctypes.Structure): 32 33 _fields_ = [ 34 ('buf', ctypes.POINTER(ctypes.c_char * buffer_size)), 35 ('alloc', ctypes.c_char), 36 ('depth', ctypes.c_int), 37 ('size', ctypes.c_int), 38 ('state', ctypes.c_int), 39 ('list_ptr', ctypes.POINTER(ctypes.POINTER(ctypes.c_char)) * LIBRLP_RLP_MAX_LIST_DEPTH), 40 ('ptr', ctypes.POINTER(ctypes.c_char)), 41 ] 42 43 self.buffer_size = buffer_size 44 self.backend = RLPEncoderBackend() 45 self.encoder = ctypes.pointer(self.backend) 46 47 # decoder specific 48 self.zl = ctypes.pointer(ctypes.c_int()) 49 self.buf = None 50 51 52 def __del__(self): 53 logg.debug('free') 54 librlp.rlp_free(self.encoder) 55 56 57 def encode_item(self, v): 58 if isinstance(v, list): 59 librlp.rlp_descend(self.encoder) 60 for e in v: 61 self.encode_item(e) 62 librlp.rlp_ascend(self.encoder) 63 64 else: 65 b = (ctypes.c_char * len(v))(*v) 66 librlp.rlp_add(self.encoder, len(v), b) 67 68 return self.backend.size 69 70 71 def encode(self, v): 72 librlp.rlp_init(self.encoder, self.buffer_size, self.__nullptr) 73 r = self.encode_item(v) 74 75 return bytes(self.backend.buf.contents[:r]) 76 77 78 def decode_item(self, frame, stack): 79 logg.debug('frame {} stack {} depth {}'.format(frame, stack, self.backend.depth)) 80 r = librlp.rlp_next(self.encoder, self.zl, ctypes.pointer(self.buf)) 81 82 if self.backend.state == RLPState.RLP_LIST_DESCEND: 83 stack.append(frame) 84 frame = [] 85 86 elif self.backend.state == RLPState.RLP_LIST_ASCEND: 87 raise ValueError() 88 frame.append(stack.append(frame)) 89 90 elif self.backend.state == RLPState.RLP_STRING: 91 l = int(self.zl.contents.value) 92 b = self.buf.contents[:l] 93 logg.debug('v {}'.format(b)) 94 frame.append(b) 95 96 elif self.backend.state == RLPState.RLP_END: 97 stack = None 98 99 else: 100 raise AttributeError('unexpected state {}'.format(self.backend.state)) 101 102 return (frame, stack) 103 104 def decode(self, v, size_hint=None): 105 106 if size_hint == None: 107 size_hint = sys.getsizeof(v) 108 109 in_buffer = ctypes.c_char * len(v) 110 in_buffer_p = in_buffer.from_buffer(bytearray(v)) 111 librlp.rlp_init(self.encoder, len(v), in_buffer_p) 112 113 self.zl = ctypes.pointer(ctypes.c_int()) 114 self.buf = ctypes.pointer((ctypes.c_char * size_hint)()) 115 116 frame = [] 117 stack = [] 118 while stack != None: 119 (frame, stack) = self.decode_item(frame, stack) 120 l = self.backend.depth 121 122 if isinstance(v, str): 123 return frame[0] 124 else: 125 print('frame {}'.format(frame)) 126 return frame