@@ -831,46 +831,37 @@ StringWriter_len_internal(PyObject *self) {
831831
832832// End of StringWriter
833833
834- static PyObject *
835- write_i16_le (PyObject * module , PyObject * const * args , size_t nargs ) {
834+ // Helper for write_i*_le/be functions - validates args and returns BytesWriter
835+ static inline BytesWriterObject *
836+ parse_write_int_args (PyObject * const * args , size_t nargs , const char * func_name ) {
836837 if (unlikely (nargs != 2 )) {
837838 PyErr_Format (PyExc_TypeError ,
838- "write_i16_le () takes exactly 2 arguments (%zu given)" , nargs );
839+ "%s () takes exactly 2 arguments (%zu given)" , func_name , nargs );
839840 return NULL ;
840841 }
841842 PyObject * writer = args [0 ];
842843 if (!check_bytes_writer (writer )) {
843844 return NULL ;
844845 }
845- PyObject * value = args [1 ];
846- int16_t unboxed = CPyLong_AsInt16 (value );
847- if (unlikely (unboxed == CPY_LL_INT_ERROR && PyErr_Occurred ())) {
848- // Error already set by CPyLong_AsInt16 (ValueError for overflow, TypeError for wrong type)
849- return NULL ;
850- }
851- BytesWriterObject * bw = (BytesWriterObject * )writer ;
852- if (unlikely (!ensure_bytes_writer_size (bw , 2 ))) {
853- return NULL ;
854- }
855- BytesWriter_write_i16_le_unchecked (bw , unboxed );
856- Py_INCREF (Py_None );
857- return Py_None ;
846+ return (BytesWriterObject * )writer ;
858847}
859848
860- static PyObject *
861- read_i16_le (PyObject * module , PyObject * const * args , size_t nargs ) {
849+ // Helper for read_i*_le/be functions - validates args and returns data pointer
850+ // Returns NULL on error, sets *out_index to the validated index on success
851+ static inline const unsigned char *
852+ parse_read_int_args (PyObject * const * args , size_t nargs , const char * func_name ,
853+ Py_ssize_t num_bytes , int64_t * out_index ) {
862854 if (unlikely (nargs != 2 )) {
863855 PyErr_Format (PyExc_TypeError ,
864- "read_i16_le () takes exactly 2 arguments (%zu given)" , nargs );
856+ "%s () takes exactly 2 arguments (%zu given)" , func_name , nargs );
865857 return NULL ;
866858 }
867859 PyObject * bytes_obj = args [0 ];
868860 if (unlikely (!PyBytes_Check (bytes_obj ))) {
869- PyErr_SetString (PyExc_TypeError , "read_i16_le () argument 1 must be bytes" );
861+ PyErr_Format (PyExc_TypeError , "%s () argument 1 must be bytes" , func_name );
870862 return NULL ;
871863 }
872- PyObject * index_obj = args [1 ];
873- int64_t index = CPyLong_AsInt64 (index_obj );
864+ int64_t index = CPyLong_AsInt64 (args [1 ]);
874865 if (unlikely (index == CPY_LL_INT_ERROR && PyErr_Occurred ())) {
875866 return NULL ;
876867 }
@@ -879,15 +870,83 @@ read_i16_le(PyObject *module, PyObject *const *args, size_t nargs) {
879870 return NULL ;
880871 }
881872 Py_ssize_t size = PyBytes_GET_SIZE (bytes_obj );
882- if (unlikely (index > size - 2 )) {
873+ if (unlikely (index > size - num_bytes )) {
883874 PyErr_Format (PyExc_IndexError ,
884875 "index %lld out of range for bytes of length %zd" ,
885876 (long long )index , size );
886877 return NULL ;
887878 }
888- const unsigned char * data = (const unsigned char * )PyBytes_AS_STRING (bytes_obj );
889- int16_t value = read_i16_le_unchecked (data + index );
890- return PyLong_FromLong (value );
879+ * out_index = index ;
880+ return (const unsigned char * )PyBytes_AS_STRING (bytes_obj );
881+ }
882+
883+ static PyObject *
884+ write_i16_le (PyObject * module , PyObject * const * args , size_t nargs ) {
885+ BytesWriterObject * bw = parse_write_int_args (args , nargs , "write_i16_le" );
886+ if (bw == NULL )
887+ return NULL ;
888+ int16_t unboxed = CPyLong_AsInt16 (args [1 ]);
889+ if (unlikely (unboxed == CPY_LL_INT_ERROR && PyErr_Occurred ()))
890+ return NULL ;
891+ if (unlikely (!ensure_bytes_writer_size (bw , 2 )))
892+ return NULL ;
893+ BytesWriter_WriteI16LEUnsafe (bw , unboxed );
894+ Py_RETURN_NONE ;
895+ }
896+
897+ static PyObject *
898+ read_i16_le (PyObject * module , PyObject * const * args , size_t nargs ) {
899+ int64_t index ;
900+ const unsigned char * data = parse_read_int_args (args , nargs , "read_i16_le" , 2 , & index );
901+ if (data == NULL )
902+ return NULL ;
903+ return PyLong_FromLong (CPyBytes_ReadI16LEUnsafe (data + index ));
904+ }
905+
906+ static PyObject *
907+ write_i32_le (PyObject * module , PyObject * const * args , size_t nargs ) {
908+ BytesWriterObject * bw = parse_write_int_args (args , nargs , "write_i32_le" );
909+ if (bw == NULL )
910+ return NULL ;
911+ int32_t unboxed = CPyLong_AsInt32 (args [1 ]);
912+ if (unlikely (unboxed == CPY_LL_INT_ERROR && PyErr_Occurred ()))
913+ return NULL ;
914+ if (unlikely (!ensure_bytes_writer_size (bw , 4 )))
915+ return NULL ;
916+ BytesWriter_WriteI32LEUnsafe (bw , unboxed );
917+ Py_RETURN_NONE ;
918+ }
919+
920+ static PyObject *
921+ read_i32_le (PyObject * module , PyObject * const * args , size_t nargs ) {
922+ int64_t index ;
923+ const unsigned char * data = parse_read_int_args (args , nargs , "read_i32_le" , 4 , & index );
924+ if (data == NULL )
925+ return NULL ;
926+ return PyLong_FromLong (CPyBytes_ReadI32LEUnsafe (data + index ));
927+ }
928+
929+ static PyObject *
930+ write_i64_le (PyObject * module , PyObject * const * args , size_t nargs ) {
931+ BytesWriterObject * bw = parse_write_int_args (args , nargs , "write_i64_le" );
932+ if (bw == NULL )
933+ return NULL ;
934+ int64_t unboxed = CPyLong_AsInt64 (args [1 ]);
935+ if (unlikely (unboxed == CPY_LL_INT_ERROR && PyErr_Occurred ()))
936+ return NULL ;
937+ if (unlikely (!ensure_bytes_writer_size (bw , 8 )))
938+ return NULL ;
939+ BytesWriter_WriteI64LEUnsafe (bw , unboxed );
940+ Py_RETURN_NONE ;
941+ }
942+
943+ static PyObject *
944+ read_i64_le (PyObject * module , PyObject * const * args , size_t nargs ) {
945+ int64_t index ;
946+ const unsigned char * data = parse_read_int_args (args , nargs , "read_i64_le" , 8 , & index );
947+ if (data == NULL )
948+ return NULL ;
949+ return PyLong_FromLongLong (CPyBytes_ReadI64LEUnsafe (data + index ));
891950}
892951
893952#endif
@@ -900,6 +959,18 @@ static PyMethodDef librt_strings_module_methods[] = {
900959 {"read_i16_le" , (PyCFunction ) read_i16_le , METH_FASTCALL ,
901960 PyDoc_STR ("Read a 16-bit signed integer from bytes in little-endian format" )
902961 },
962+ {"write_i32_le" , (PyCFunction ) write_i32_le , METH_FASTCALL ,
963+ PyDoc_STR ("Write a 32-bit signed integer to BytesWriter in little-endian format" )
964+ },
965+ {"read_i32_le" , (PyCFunction ) read_i32_le , METH_FASTCALL ,
966+ PyDoc_STR ("Read a 32-bit signed integer from bytes in little-endian format" )
967+ },
968+ {"write_i64_le" , (PyCFunction ) write_i64_le , METH_FASTCALL ,
969+ PyDoc_STR ("Write a 64-bit signed integer to BytesWriter in little-endian format" )
970+ },
971+ {"read_i64_le" , (PyCFunction ) read_i64_le , METH_FASTCALL ,
972+ PyDoc_STR ("Read a 64-bit signed integer from bytes in little-endian format" )
973+ },
903974#endif
904975 {NULL , NULL , 0 , NULL }
905976};
0 commit comments