@@ -2863,7 +2863,91 @@ static int php_strtr_compare_hash_suffix(const void *a, const void *b, void *ctx
2863
2863
hash_b = php_strtr_hash (& S (& pnr_b -> pat )[res -> m - res -> B ], res -> B )
2864
2864
& res -> hash -> table_mask ;
2865
2865
/* TODO: don't recalculate the hashes all the time */
2866
- return hash_a - hash_b ;
2866
+ if (hash_a > hash_b ) {
2867
+ return 1 ;
2868
+ } else if (hash_a < hash_b ) {
2869
+ return -1 ;
2870
+ } else {
2871
+ /* longer patterns must be sorted first */
2872
+ if (L (& pnr_a -> pat ) > L (& pnr_b -> pat )) {
2873
+ return -1 ;
2874
+ } else if (L (& pnr_a -> pat ) < L (& pnr_b -> pat )) {
2875
+ return 1 ;
2876
+ } else {
2877
+ return 0 ;
2878
+ }
2879
+ }
2880
+ }
2881
+ /* }}} */
2882
+ /* {{{ php_strtr_free_strp */
2883
+ static void php_strtr_free_strp (void * strp )
2884
+ {
2885
+ STR_FREE (* (char * * )strp );
2886
+ }
2887
+ /* }}} */
2888
+ /* {{{ php_strtr_array_prepare_repls */
2889
+ static PATNREPL * php_strtr_array_prepare_repls (int slen , HashTable * pats , zend_llist * * allocs , int * outsize )
2890
+ {
2891
+ PATNREPL * patterns ;
2892
+ HashPosition hpos ;
2893
+ zval * * entry ;
2894
+ int num_pats = zend_hash_num_elements (pats ),
2895
+ i ;
2896
+
2897
+ patterns = safe_emalloc (num_pats , sizeof (* patterns ), 0 );
2898
+ * allocs = emalloc (sizeof * * allocs );
2899
+ zend_llist_init (* allocs , sizeof (void * ), & php_strtr_free_strp , 0 );
2900
+
2901
+ for (i = 0 , zend_hash_internal_pointer_reset_ex (pats , & hpos );
2902
+ zend_hash_get_current_data_ex (pats , (void * * )& entry , & hpos ) == SUCCESS ;
2903
+ zend_hash_move_forward_ex (pats , & hpos )) {
2904
+ char * string_key ;
2905
+ uint string_key_len ;
2906
+ ulong num_key ;
2907
+ zval * tzv = NULL ;
2908
+
2909
+ switch (zend_hash_get_current_key_ex (pats , & string_key , & string_key_len , & num_key , 0 , & hpos )) {
2910
+ case HASH_KEY_IS_LONG :
2911
+ string_key_len = 1 + zend_spprintf (& string_key , 0 , "%ld" , (long )num_key );
2912
+ zend_llist_add_element (* allocs , & string_key );
2913
+ /* break missing intentionally */
2914
+
2915
+ case HASH_KEY_IS_STRING :
2916
+ string_key_len -- ; /* exclude final '\0' */
2917
+ if (string_key_len == 0 ) { /* empty string given as pattern */
2918
+ efree (patterns );
2919
+ zend_llist_destroy (* allocs );
2920
+ efree (* allocs );
2921
+ * allocs = NULL ;
2922
+ return NULL ;
2923
+ }
2924
+ if (string_key_len > slen ) { /* this pattern can never match */
2925
+ continue ;
2926
+ }
2927
+
2928
+ if (Z_TYPE_PP (entry ) != IS_STRING ) {
2929
+ tzv = * entry ;
2930
+ zval_addref_p (tzv );
2931
+ SEPARATE_ZVAL (& tzv );
2932
+ convert_to_string (tzv );
2933
+ entry = & tzv ;
2934
+ zend_llist_add_element (* allocs , & Z_STRVAL_PP (entry ));
2935
+ }
2936
+
2937
+ S (& patterns [i ].pat ) = string_key ;
2938
+ L (& patterns [i ].pat ) = string_key_len ;
2939
+ S (& patterns [i ].repl ) = Z_STRVAL_PP (entry );
2940
+ L (& patterns [i ].repl ) = Z_STRLEN_PP (entry );
2941
+ i ++ ;
2942
+
2943
+ if (tzv ) {
2944
+ efree (tzv );
2945
+ }
2946
+ }
2947
+ }
2948
+
2949
+ * outsize = i ;
2950
+ return patterns ;
2867
2951
}
2868
2952
/* }}} */
2869
2953
@@ -2952,7 +3036,7 @@ static void php_strtr_array_do_repl(STR *text, PPRES *d, zval *return_value)
2952
3036
STRLEN shift = d -> shift -> entries [h ];
2953
3037
2954
3038
if (shift > 0 ) {
2955
- smart_str_appendl (& result , & S (text )[pos ], shift );
3039
+ smart_str_appendl (& result , & S (text )[pos ], MIN ( shift , L ( text ) - pos ) );
2956
3040
pos += shift ;
2957
3041
} else {
2958
3042
HASH h2 = h & d -> hash -> table_mask ,
@@ -2999,64 +3083,25 @@ end_outer_loop: ;
2999
3083
/* {{{ php_strtr_array */
3000
3084
static void php_strtr_array (zval * return_value , char * str , int slen , HashTable * pats )
3001
3085
{
3002
- PPRES * data ;
3003
- STR text ;
3004
- PATNREPL * patterns ;
3005
- HashPosition hpos ;
3006
- zval * * entry ;
3007
- int num_pats = zend_hash_num_elements (pats ),
3008
- i ;
3086
+ PPRES * data ;
3087
+ STR text ;
3088
+ PATNREPL * patterns ;
3089
+ int patterns_len ;
3090
+ zend_llist * allocs ;
3009
3091
3010
3092
S (& text ) = str ;
3011
3093
L (& text ) = slen ;
3012
- patterns = safe_emalloc (num_pats , sizeof (* patterns ), 0 );
3013
-
3014
- for (i = 0 , zend_hash_internal_pointer_reset_ex (pats , & hpos );
3015
- zend_hash_get_current_data_ex (pats , (void * * )& entry , & hpos ) == SUCCESS ;
3016
- i ++ , zend_hash_move_forward_ex (pats , & hpos )) {
3017
- char * string_key ;
3018
- uint string_key_len ;
3019
- ulong num_key ;
3020
- int free_str = 0 ,
3021
- free_repl = 0 ;
3022
- zval * tzv ;
3023
-
3024
- switch (zend_hash_get_current_key_ex (pats , & string_key , & string_key_len , & num_key , 0 , & hpos )) {
3025
- case HASH_KEY_IS_LONG :
3026
- string_key_len = 1 + zend_spprintf (& string_key , 0 , "%ld" , (long )num_key );
3027
- free_str = 1 ;
3028
- /* break missing intentionally */
3029
3094
3030
- case HASH_KEY_IS_STRING :
3031
- string_key_len -- ; /* exclude final '\0' */
3032
- if (string_key_len == 0 ) { /* empty string given as pattern */
3033
- efree (patterns );
3034
- RETURN_FALSE ;
3035
- }
3036
- if (string_key_len > slen ) { /* this pattern can never match */
3037
- continue ;
3038
- }
3039
-
3040
- if (Z_TYPE_PP (entry ) != IS_STRING ) {
3041
- tzv = * entry ;
3042
- zval_addref_p (tzv );
3043
- SEPARATE_ZVAL (& tzv );
3044
- convert_to_string (tzv );
3045
- entry = & tzv ;
3046
- free_repl = 1 ;
3047
- }
3048
-
3049
- S (& patterns [i ].pat ) = string_key ;
3050
- L (& patterns [i ].pat ) = string_key_len ;
3051
- S (& patterns [i ].repl ) = Z_STRVAL_PP (entry );
3052
- L (& patterns [i ].repl ) = Z_STRLEN_PP (entry );
3053
- }
3095
+ patterns = php_strtr_array_prepare_repls (slen , pats , & allocs , & patterns_len );
3096
+ if (patterns == NULL ) {
3097
+ RETURN_FALSE ;
3054
3098
}
3055
-
3056
- data = php_strtr_array_prepare (& text , patterns , i , 2 , 2 );
3099
+ data = php_strtr_array_prepare (& text , patterns , patterns_len , 2 , 2 );
3057
3100
efree (patterns );
3058
3101
php_strtr_array_do_repl (& text , data , return_value );
3059
3102
php_strtr_array_destroy_ppres (data );
3103
+ zend_llist_destroy (allocs );
3104
+ efree (allocs );
3060
3105
}
3061
3106
/* }}} */
3062
3107
0 commit comments