@@ -459,25 +459,65 @@ import_twos_complement(cass_byte_t* data, size_t size, mpz_t* number)
459459
460460 /* negative value */
461461 if ((data [0 ] & 0x80 ) == 0x80 ) {
462- /* invert bits */
463- mpz_com (* number , * number );
464- /* add one */
465- mpz_add_ui (* number , * number , 1 );
466- /* negate the value */
467- mpz_neg (* number , * number );
462+ /* mpz_import() imports the two's complement value as an unsigned integer
463+ * so this needs to subtract 2^(8 * num_bytes) to get the negative value.
464+ */
465+ mpz_t temp ;
466+ mpz_init (temp );
467+ mpz_set_ui (temp , 1 );
468+ mpz_mul_2exp (temp , temp , 8 * size );
469+ mpz_sub (* number , * number , temp );
470+ mpz_clear (temp );
468471 }
469472}
470473
471474cass_byte_t *
472475export_twos_complement (mpz_t number , size_t * size )
473476{
474- /* negative, do two's complement */
475- if (mpz_sgn (number ) == -1 ) {
476- /* invert bits */
477- mpz_com (number , number );
478- /* add one */
479- mpz_add_ui (number , number , 1 );
477+ cass_byte_t * bytes ;
478+
479+ if (mpz_sgn (number ) == 0 ) {
480+ /* mpz_export() returns NULL for 0 */
481+ bytes = (cass_byte_t * ) malloc (sizeof (cass_byte_t ));
482+ * bytes = 0 ;
483+ * size = 1 ;
484+ } else if (mpz_sgn (number ) == -1 ) {
485+ /* mpz_export() ignores sign and only exports abs(number)
486+ * so this needs to convert the number to the two's complement
487+ * unsigned value.
488+ */
489+ size_t n ;
490+ mpz_t temp ;
491+
492+ /* determine the number of bytes used in the two's complement
493+ * respresentation.
494+ */
495+ n = mpz_sizeinbase (number , 2 ) / 8 + 1 ;
496+
497+ /* there's a special case for -2^(8 * n) numbers e.g. -128 (1000 0000) and
498+ * -32768 (100 0000 0000 0000), etc. that can be handled by n - 1 bytes in
499+ * two's complement.
500+ */
501+ if (mpz_scan1 (number , 0 ) == (8 * (n - 1 )) - 1 ) {
502+ n -- ;
503+ }
504+
505+ /* Add 2^(8 * num_bytes) to get the unsigned value e.g.
506+ * -1 + 2^8 = 255
507+ * -128 + 2^8 = 128
508+ * -129 + 2^16 = 65407
509+ * -32768 + 2^16 = 32768
510+ * ...
511+ */
512+ mpz_init (temp );
513+ mpz_set_ui (temp , 1 );
514+ mpz_mul_2exp (temp , temp , 8 * n );
515+ mpz_add (temp , number , temp );
516+ bytes = (cass_byte_t * ) mpz_export (NULL , size , 1 , sizeof (cass_byte_t ), 1 , 0 , temp );
517+ mpz_clear (temp );
518+ } else {
519+ bytes = (cass_byte_t * ) mpz_export (NULL , size , 1 , sizeof (cass_byte_t ), 1 , 0 , number );
480520 }
481521
482- return ( cass_byte_t * ) mpz_export ( NULL , size , 1 , sizeof ( cass_byte_t ), 1 , 0 , number ) ;
522+ return bytes ;
483523}
0 commit comments