@@ -43,6 +43,18 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_init, 0, 0, 1)
43
43
ZEND_ARG_INFO (0 , base )
44
44
ZEND_END_ARG_INFO ()
45
45
46
+ ZEND_BEGIN_ARG_INFO_EX (arginfo_gmp_import , 0 , 0 , 1 )
47
+ ZEND_ARG_INFO (0 , data )
48
+ ZEND_ARG_INFO (0 , word_size )
49
+ ZEND_ARG_INFO (0 , options )
50
+ ZEND_END_ARG_INFO ()
51
+
52
+ ZEND_BEGIN_ARG_INFO_EX (arginfo_gmp_export , 0 , 0 , 1 )
53
+ ZEND_ARG_INFO (0 , gmpnumber )
54
+ ZEND_ARG_INFO (0 , word_size )
55
+ ZEND_ARG_INFO (0 , options )
56
+ ZEND_END_ARG_INFO ()
57
+
46
58
ZEND_BEGIN_ARG_INFO_EX (arginfo_gmp_intval , 0 , 0 , 1 )
47
59
ZEND_ARG_INFO (0 , gmpnumber )
48
60
ZEND_END_ARG_INFO ()
@@ -117,6 +129,8 @@ static ZEND_GINIT_FUNCTION(gmp);
117
129
*/
118
130
const zend_function_entry gmp_functions [] = {
119
131
ZEND_FE (gmp_init , arginfo_gmp_init )
132
+ ZEND_FE (gmp_import , arginfo_gmp_import )
133
+ ZEND_FE (gmp_export , arginfo_gmp_export )
120
134
ZEND_FE (gmp_intval , arginfo_gmp_intval )
121
135
ZEND_FE (gmp_strval , arginfo_gmp_strval )
122
136
ZEND_FE (gmp_add , arginfo_gmp_binary )
@@ -204,6 +218,12 @@ typedef struct _gmp_temp {
204
218
#define GMP_ROUND_PLUSINF 1
205
219
#define GMP_ROUND_MINUSINF 2
206
220
221
+ #define GMP_MSW_FIRST (1 << 0)
222
+ #define GMP_LSW_FIRST (1 << 1)
223
+ #define GMP_LITTLE_ENDIAN (1 << 2)
224
+ #define GMP_BIG_ENDIAN (1 << 3)
225
+ #define GMP_NATIVE_ENDIAN (1 << 4)
226
+
207
227
#define GMP_42_OR_NEWER \
208
228
((__GNU_MP_VERSION >= 5) || (__GNU_MP_VERSION >= 4 && __GNU_MP_VERSION_MINOR >= 2))
209
229
@@ -297,7 +317,7 @@ static void gmp_strval(zval *result, mpz_t gmpnum, long base);
297
317
static int convert_to_gmp (mpz_t gmpnumber , zval * val , int base TSRMLS_DC );
298
318
static void gmp_cmp (zval * return_value , zval * a_arg , zval * b_arg TSRMLS_DC );
299
319
300
- /*
320
+ /*
301
321
* The gmp_*_op functions provide an implementation for several common types
302
322
* of GMP functions. The gmp_zval_(unary|binary)_*_op functions have to be manually
303
323
* passed zvals to work on, whereas the gmp_(unary|binary)_*_op macros already
@@ -599,7 +619,7 @@ static int gmp_serialize(zval *object, unsigned char **buffer, zend_uint *buf_le
599
619
600
620
PHP_VAR_SERIALIZE_INIT (serialize_data );
601
621
INIT_PZVAL (zv_ptr );
602
-
622
+
603
623
gmp_strval (zv_ptr , gmpnum , 10 );
604
624
php_var_serialize (& buf , & zv_ptr , & serialize_data TSRMLS_CC );
605
625
zval_dtor (zv_ptr );
@@ -697,6 +717,12 @@ ZEND_MINIT_FUNCTION(gmp)
697
717
#endif
698
718
REGISTER_STRING_CONSTANT ("GMP_VERSION" , (char * )gmp_version , CONST_CS | CONST_PERSISTENT );
699
719
720
+ REGISTER_LONG_CONSTANT ("GMP_MSW_FIRST" , GMP_MSW_FIRST , CONST_CS | CONST_PERSISTENT );
721
+ REGISTER_LONG_CONSTANT ("GMP_LSW_FIRST" , GMP_LSW_FIRST , CONST_CS | CONST_PERSISTENT );
722
+ REGISTER_LONG_CONSTANT ("GMP_LITTLE_ENDIAN" , GMP_LITTLE_ENDIAN , CONST_CS | CONST_PERSISTENT );
723
+ REGISTER_LONG_CONSTANT ("GMP_BIG_ENDIAN" , GMP_BIG_ENDIAN , CONST_CS | CONST_PERSISTENT );
724
+ REGISTER_LONG_CONSTANT ("GMP_NATIVE_ENDIAN" , GMP_NATIVE_ENDIAN , CONST_CS | CONST_PERSISTENT );
725
+
700
726
mp_set_memory_functions (gmp_emalloc , gmp_erealloc , gmp_efree );
701
727
702
728
return SUCCESS ;
@@ -734,7 +760,7 @@ ZEND_MODULE_INFO_D(gmp)
734
760
735
761
/* {{{ convert_to_gmp
736
762
* Convert zval to be gmp number */
737
- static int convert_to_gmp (mpz_t gmpnumber , zval * val , int base TSRMLS_DC )
763
+ static int convert_to_gmp (mpz_t gmpnumber , zval * val , int base TSRMLS_DC )
738
764
{
739
765
switch (Z_TYPE_P (val )) {
740
766
case IS_LONG :
@@ -788,8 +814,8 @@ static void gmp_strval(zval *result, mpz_t gmpnum, long base) /* {{{ */
788
814
789
815
out_string = emalloc (num_len + 1 );
790
816
mpz_get_str (out_string , base , gmpnum );
791
-
792
- /*
817
+
818
+ /*
793
819
* From GMP documentation for mpz_sizeinbase():
794
820
* The returned value will be exact or 1 too big. If base is a power of
795
821
* 2, the returned value will always be exact.
@@ -831,22 +857,22 @@ static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg TSRMLS_DC) /* {
831
857
832
858
FREE_GMP_TEMP (temp_a );
833
859
FREE_GMP_TEMP (temp_b );
834
-
860
+
835
861
RETURN_LONG (res );
836
862
}
837
863
/* }}} */
838
864
839
865
/* {{{ gmp_zval_binary_ui_op
840
866
Execute GMP binary operation.
841
867
*/
842
- static inline void gmp_zval_binary_ui_op (zval * return_value , zval * a_arg , zval * b_arg , gmp_binary_op_t gmp_op , gmp_binary_ui_op_t gmp_ui_op , int check_b_zero TSRMLS_DC )
868
+ static inline void gmp_zval_binary_ui_op (zval * return_value , zval * a_arg , zval * b_arg , gmp_binary_op_t gmp_op , gmp_binary_ui_op_t gmp_ui_op , int check_b_zero TSRMLS_DC )
843
869
{
844
870
mpz_ptr gmpnum_a , gmpnum_b , gmpnum_result ;
845
871
int use_ui = 0 ;
846
872
gmp_temp_t temp_a , temp_b ;
847
873
848
874
FETCH_GMP_ZVAL (gmpnum_a , a_arg , temp_a );
849
-
875
+
850
876
if (gmp_ui_op && Z_TYPE_P (b_arg ) == IS_LONG && Z_LVAL_P (b_arg ) >= 0 ) {
851
877
use_ui = 1 ;
852
878
temp_b .is_used = 0 ;
@@ -942,7 +968,7 @@ static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op
942
968
if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "zz" , & a_arg , & b_arg ) == FAILURE ){
943
969
return ;
944
970
}
945
-
971
+
946
972
gmp_zval_binary_ui_op (return_value , a_arg , b_arg , gmp_op , gmp_ui_op , check_b_zero TSRMLS_CC );
947
973
}
948
974
/* }}} */
@@ -951,11 +977,11 @@ static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op
951
977
952
978
/* {{{ gmp_zval_unary_op
953
979
*/
954
- static inline void gmp_zval_unary_op (zval * return_value , zval * a_arg , gmp_unary_op_t gmp_op TSRMLS_DC )
980
+ static inline void gmp_zval_unary_op (zval * return_value , zval * a_arg , gmp_unary_op_t gmp_op TSRMLS_DC )
955
981
{
956
982
mpz_ptr gmpnum_a , gmpnum_result ;
957
983
gmp_temp_t temp_a ;
958
-
984
+
959
985
FETCH_GMP_ZVAL (gmpnum_a , a_arg , temp_a );
960
986
961
987
INIT_GMP_RETVAL (gmpnum_result );
@@ -1000,7 +1026,7 @@ static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gm
1000
1026
if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "z" , & a_arg ) == FAILURE ){
1001
1027
return ;
1002
1028
}
1003
-
1029
+
1004
1030
gmp_zval_unary_op (return_value , a_arg , gmp_op TSRMLS_CC );
1005
1031
}
1006
1032
/* }}} */
@@ -1016,7 +1042,7 @@ static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t
1016
1042
if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "z" , & a_arg ) == FAILURE ){
1017
1043
return ;
1018
1044
}
1019
-
1045
+
1020
1046
FETCH_GMP_ZVAL (gmpnum_a , a_arg , temp_a );
1021
1047
RETVAL_LONG (gmp_op (gmpnum_a ));
1022
1048
FREE_GMP_TEMP (temp_a );
@@ -1070,6 +1096,118 @@ ZEND_FUNCTION(gmp_init)
1070
1096
}
1071
1097
/* }}} */
1072
1098
1099
+ int gmp_import_export_validate (long size , long options , int * order , int * endian TSRMLS_DC )
1100
+ {
1101
+ if (size < 1 ) {
1102
+ php_error_docref (NULL TSRMLS_CC , E_WARNING ,
1103
+ "Word size must be positive, %ld given" , size );
1104
+ return FAILURE ;
1105
+ }
1106
+
1107
+ switch (options & (GMP_LSW_FIRST | GMP_MSW_FIRST )) {
1108
+ case GMP_LSW_FIRST :
1109
+ * order = -1 ;
1110
+ break ;
1111
+ case GMP_MSW_FIRST :
1112
+ case 0 : /* default */
1113
+ * order = 1 ;
1114
+ break ;
1115
+ default :
1116
+ php_error_docref (NULL TSRMLS_CC , E_WARNING ,
1117
+ "Invalid options: Conflicting word orders" );
1118
+ return FAILURE ;
1119
+ }
1120
+
1121
+ switch (options & (GMP_LITTLE_ENDIAN | GMP_BIG_ENDIAN | GMP_NATIVE_ENDIAN )) {
1122
+ case GMP_LITTLE_ENDIAN :
1123
+ * endian = -1 ;
1124
+ break ;
1125
+ case GMP_BIG_ENDIAN :
1126
+ * endian = 1 ;
1127
+ break ;
1128
+ case GMP_NATIVE_ENDIAN :
1129
+ case 0 : /* default */
1130
+ * endian = 0 ;
1131
+ break ;
1132
+ default :
1133
+ php_error_docref (NULL TSRMLS_CC , E_WARNING ,
1134
+ "Invalid options: Conflicting word endianness" );
1135
+ return FAILURE ;
1136
+ }
1137
+
1138
+ return SUCCESS ;
1139
+ }
1140
+
1141
+ /* {{{ proto GMP gmp_import(string data [, int word_size = 1, int options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN])
1142
+ Imports a GMP number from a binary string */
1143
+ ZEND_FUNCTION (gmp_import )
1144
+ {
1145
+ char * data ;
1146
+ int data_len ;
1147
+ long size = 1 ;
1148
+ long options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN ;;
1149
+ int order , endian ;
1150
+ mpz_ptr gmpnumber ;
1151
+
1152
+ if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "s|ll" , & data , & data_len , & size , & options ) == FAILURE ) {
1153
+ return ;
1154
+ }
1155
+
1156
+ if (gmp_import_export_validate (size , options , & order , & endian TSRMLS_CC ) == FAILURE ) {
1157
+ RETURN_FALSE ;
1158
+ }
1159
+
1160
+ if ((data_len % size ) != 0 ) {
1161
+ php_error_docref (NULL TSRMLS_CC , E_WARNING ,
1162
+ "Input length must be a multiple of word size" );
1163
+ RETURN_FALSE ;
1164
+ }
1165
+
1166
+ INIT_GMP_RETVAL (gmpnumber );
1167
+
1168
+ mpz_import (gmpnumber , data_len / size , order , size , endian , 0 , data );
1169
+ }
1170
+ /* }}} */
1171
+
1172
+ /* {{{ proto string gmp_export(GMP gmpnumber [, int word_size = 1, int options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN])
1173
+ Exports a GMP number to a binary string */
1174
+ ZEND_FUNCTION (gmp_export )
1175
+ {
1176
+ zval * gmpnumber_arg ;
1177
+ long size = 1 ;
1178
+ long options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN ;;
1179
+ int order , endian ;
1180
+ mpz_ptr gmpnumber ;
1181
+ gmp_temp_t temp_a ;
1182
+
1183
+ if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "z|ll" , & gmpnumber_arg , & size , & options ) == FAILURE ) {
1184
+ return ;
1185
+ }
1186
+
1187
+ if (gmp_import_export_validate (size , options , & order , & endian TSRMLS_CC ) == FAILURE ) {
1188
+ RETURN_FALSE ;
1189
+ }
1190
+
1191
+ FETCH_GMP_ZVAL (gmpnumber , gmpnumber_arg , temp_a );
1192
+
1193
+ if (mpz_sgn (gmpnumber ) == 0 ) {
1194
+ ZVAL_STRING (return_value , "" , 1 );
1195
+ } else {
1196
+ size_t bits_per_word = size * 8 ;
1197
+ size_t count = (mpz_sizeinbase (gmpnumber , 2 ) + bits_per_word - 1 ) / bits_per_word ;
1198
+ size_t out_len = count * size ;
1199
+
1200
+ char * out_string = emalloc (out_len + 1 );
1201
+ mpz_export (out_string , NULL , order , size , endian , 0 , gmpnumber );
1202
+ out_string [out_len ] = '\0' ;
1203
+
1204
+ ZVAL_STRINGL (return_value , out_string , out_len , 0 );
1205
+ }
1206
+
1207
+ FREE_GMP_TEMP (temp_a );
1208
+ }
1209
+ /* }}} */
1210
+
1073
1211
/* {{{ proto int gmp_intval(mixed gmpnumber)
1074
1212
Gets signed long value of GMP number */
1075
1213
ZEND_FUNCTION (gmp_intval )
@@ -1079,7 +1217,7 @@ ZEND_FUNCTION(gmp_intval)
1079
1217
if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "z" , & gmpnumber_arg ) == FAILURE ){
1080
1218
return ;
1081
1219
}
1082
-
1220
+
1083
1221
if (IS_GMP (gmpnumber_arg )) {
1084
1222
RETVAL_LONG (mpz_get_si (GET_GMP_FROM_ZVAL (gmpnumber_arg )));
1085
1223
} else {
@@ -1226,7 +1364,7 @@ ZEND_FUNCTION(gmp_div_q)
1226
1364
php_error_docref (NULL TSRMLS_CC , E_WARNING , "Invalid rounding mode ");
1227
1365
RETURN_FALSE ;
1228
1366
}
1229
-
1367
+
1230
1368
}
1231
1369
/* }}} */
1232
1370
@@ -1306,7 +1444,7 @@ ZEND_FUNCTION(gmp_pow)
1306
1444
php_error_docref (NULL TSRMLS_CC , E_WARNING , "Negative exponent not supported" );
1307
1445
RETURN_FALSE ;
1308
1446
}
1309
-
1447
+
1310
1448
INIT_GMP_RETVAL (gmpnum_result );
1311
1449
if (Z_TYPE_P (base_arg ) == IS_LONG && Z_LVAL_P (base_arg ) >= 0 ) {
1312
1450
mpz_ui_pow_ui (gmpnum_result , Z_LVAL_P (base_arg ), exp );
@@ -1380,14 +1518,14 @@ ZEND_FUNCTION(gmp_sqrt)
1380
1518
if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "z" , & a_arg ) == FAILURE ){
1381
1519
return ;
1382
1520
}
1383
-
1521
+
1384
1522
FETCH_GMP_ZVAL (gmpnum_a , a_arg , temp_a );
1385
1523
1386
1524
if (mpz_sgn (gmpnum_a ) < 0 ) {
1387
1525
php_error_docref (NULL TSRMLS_CC , E_WARNING , "Number has to be greater than or equal to 0" );
1388
1526
FREE_GMP_TEMP (temp_a );
1389
1527
RETURN_FALSE ;
1390
- }
1528
+ }
1391
1529
1392
1530
INIT_GMP_RETVAL (gmpnum_result );
1393
1531
mpz_sqrt (gmpnum_result , gmpnum_a );
@@ -1414,7 +1552,7 @@ ZEND_FUNCTION(gmp_sqrtrem)
1414
1552
FREE_GMP_TEMP (temp_a );
1415
1553
RETURN_FALSE ;
1416
1554
}
1417
-
1555
+
1418
1556
array_init (return_value );
1419
1557
add_index_zval (return_value , 0 , gmp_create (& gmpnum_result1 TSRMLS_CC ));
1420
1558
add_index_zval (return_value , 1 , gmp_create (& gmpnum_result2 TSRMLS_CC ));
@@ -1494,7 +1632,7 @@ ZEND_FUNCTION(gmp_rootrem)
1494
1632
mpz_sub (gmpnum_result2 , gmpnum_a , gmpnum_result2 );
1495
1633
mpz_abs (gmpnum_result2 , gmpnum_result2 );
1496
1634
#endif
1497
-
1635
+
1498
1636
FREE_GMP_TEMP (temp_a );
1499
1637
}
1500
1638
/* }}} */
0 commit comments