@@ -394,37 +394,86 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp
394394 return MP_OBJ_NULL ; // op not supported
395395}
396396
397- // this is a classmethod
398- static mp_obj_t int_from_bytes (size_t n_args , const mp_obj_t * args ) {
399- // TODO: Support signed param (assumes signed=False at the moment)
400-
401- // get the buffer info
402- mp_buffer_info_t bufinfo ;
403- mp_get_buffer_raise (args [1 ], & bufinfo , MP_BUFFER_READ );
397+ void * reverce_memcpy (void * dest , const void * src , size_t len ) {
398+ char * d = (char * )dest + len - 1 ;
399+ const char * s = src ;
400+ while (len -- ) {
401+ * d -- = * s ++ ;
402+ }
403+ return dest ;
404+ }
404405
405- const byte * buf = (const byte * )bufinfo .buf ;
406- int delta = 1 ;
407- bool big_endian = n_args < 3 || args [2 ] != MP_OBJ_NEW_QSTR (MP_QSTR_little );
408- if (!big_endian ) {
409- buf += bufinfo .len - 1 ;
410- delta = -1 ;
406+ mp_obj_t mp_obj_integer_from_bytes_impl (bool big_endian , bool is_signed , size_t len , const byte * buf ) {
407+ if (len > sizeof (mp_int_t )) {
408+ #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
409+ // Result will overflow a small-int size so construct a big-int
410+ return mp_obj_int_from_bytes_impl (big_endian , is_signed , len , buf );
411+ #else
412+ mp_raise_msg (& mp_type_OverflowError , MP_ERROR_TEXT ("small-int overflow" ));
413+ #endif
414+ }
415+ union {
416+ mp_int_t value ;
417+ mp_uint_t uvalue ;
418+ byte buf [sizeof (mp_int_t )];
419+ } result = {0 };
420+ // #if sizeof(mp_int_t) != sizeof(mp_uint_t)
421+ // #error "sizeof(mp_int_t) != sizeof(mp_uint_t)"
422+ // #endif
423+
424+ if (big_endian ) {
425+ reverce_memcpy (& result , buf , len );
426+ } else { // little-endian
427+ memcpy (& result , buf , len );
411428 }
412429
413- mp_uint_t value = 0 ;
414- size_t len = bufinfo .len ;
415- for (; len -- ; buf += delta ) {
430+ if ((is_signed ) && (sizeof (result ) > len ) && (result .buf [len - 1 ] & 0x80 )) {
431+ // Sign propagation in little-endian
432+ // x = 2
433+ // x.to_bytes(1, 'little', True) -> b'\x02'
434+ // x.to_bytes(4, 'little', True) -> b'\x02\x00\x00\x00'
435+ // x = -2
436+ // x.to_bytes(1, 'little', True) -> b'\xFE'
437+ // x.to_bytes(4, 'little', True) -> b'\xFE\xFF\xFF\xFF'
438+ memset (result .buf + len , 0xFF , sizeof (result ) - len );
439+ }
440+ if (((!is_signed ) && (result .uvalue > MP_SMALL_INT_MAX )) || (is_signed && ((result .value < MP_SMALL_INT_MIN ) || (result .value > MP_SMALL_INT_MAX )))) {
441+ // Result will overflow a small-int so construct a big-int
416442 #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
417- if (value > (MP_SMALL_INT_MAX >> 8 )) {
418- // Result will overflow a small-int so construct a big-int
419- return mp_obj_int_from_bytes_impl (big_endian , bufinfo .len , bufinfo .buf );
420- }
443+ return mp_obj_int_from_bytes_impl (big_endian , is_signed , len , buf );
444+ #else
445+ mp_raise_msg (& mp_type_OverflowError , MP_ERROR_TEXT ("small-int overflow" ));
421446 #endif
422- value = (value << 8 ) | * buf ;
423447 }
424- return mp_obj_new_int_from_uint ( value );
448+ return mp_obj_new_int ( result . value );
425449}
426450
427- static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (int_from_bytes_fun_obj , 2 , 4 , int_from_bytes ) ;
451+ // this is a classmethod
452+ // result = int.from_bytes(bytearray(), [[length=,] byteorder='big',] signed=False)
453+ static mp_obj_t int_from_bytes (size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
454+ enum { ARG_length , ARG_byteorder , ARG_signed };
455+ static const mp_arg_t allowed_args [] = {
456+ { MP_QSTR_length , MP_ARG_INT , { .u_int = 0 } },
457+ { MP_QSTR_byteorder , MP_ARG_OBJ , { .u_rom_obj = MP_ROM_QSTR (MP_QSTR_big ) } },
458+ { MP_QSTR_signed , MP_ARG_BOOL , {.u_bool = false} },
459+ };
460+ mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
461+ mp_arg_parse_all (n_args - 2 , pos_args + 2 , kw_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
462+
463+ // get the buffer info
464+ mp_buffer_info_t bufinfo ;
465+ mp_get_buffer_raise (pos_args [1 ], & bufinfo , MP_BUFFER_READ );
466+
467+ size_t len = args [ARG_length ].u_int ;
468+ bool big_endian = args [ARG_byteorder ].u_obj != MP_OBJ_NEW_QSTR (MP_QSTR_little );
469+ bool is_signed = args [ARG_signed ].u_bool ;
470+
471+ if ((len <= 0 ) || (len > bufinfo .len )) {
472+ len = bufinfo .len ;
473+ }
474+ return mp_obj_integer_from_bytes_impl (big_endian , is_signed , len , bufinfo .buf );
475+ }
476+ static MP_DEFINE_CONST_FUN_OBJ_KW (int_from_bytes_fun_obj , 2 , int_from_bytes ) ;
428477static MP_DEFINE_CONST_CLASSMETHOD_OBJ (int_from_bytes_obj , MP_ROM_PTR (& int_from_bytes_fun_obj )) ;
429478
430479static mp_obj_t int_to_bytes (size_t n_args , const mp_obj_t * args ) {
0 commit comments