This source file includes following definitions.
- collator_regular_compare_function
- collator_numeric_compare_function
- collator_icu_compare_function
- collator_compare_func
- collator_cmp_sort_keys
- collator_get_compare_function
- collator_sort_internal
- PHP_FUNCTION
- collator_sortkey_swap
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include "php_intl.h"
23 #include "collator.h"
24 #include "collator_class.h"
25 #include "collator_sort.h"
26 #include "collator_convert.h"
27 #include "intl_convert.h"
28
29 #if !defined(HAVE_PTRDIFF_T) && !defined(_PTRDIFF_T_DEFINED)
30 typedef zend_long ptrdiff_t;
31 #endif
32
33
34
35
36
37 typedef struct _collator_sort_key_index {
38 char* key;
39 zval* zstr;
40 } collator_sort_key_index_t;
41
42 ZEND_EXTERN_MODULE_GLOBALS( intl )
43
44 static const size_t DEF_SORT_KEYS_BUF_SIZE = 1048576;
45 static const size_t DEF_SORT_KEYS_BUF_INCREMENT = 1048576;
46
47 static const size_t DEF_SORT_KEYS_INDX_BUF_SIZE = 1048576;
48 static const size_t DEF_SORT_KEYS_INDX_BUF_INCREMENT = 1048576;
49
50 static const size_t DEF_UTF16_BUF_SIZE = 1024;
51
52
53 static int collator_regular_compare_function(zval *result, zval *op1, zval *op2)
54 {
55 Collator_object* co = NULL;
56 int rc = SUCCESS;
57 zval str1, str2;
58 zval num1, num2;
59 zval norm1, norm2;
60 zval *num1_p = NULL, *num2_p = NULL;
61 zval *norm1_p = NULL, *norm2_p = NULL;
62 zval* str1_p = collator_convert_object_to_string( op1, &str1 );
63 zval* str2_p = collator_convert_object_to_string( op2, &str2 );
64
65
66
67 if( Z_TYPE_P(str1_p) == IS_STRING && Z_TYPE_P(str2_p) == IS_STRING &&
68 ( str1_p == ( num1_p = collator_convert_string_to_number_if_possible( str1_p, &num1 ) ) ||
69 str2_p == ( num2_p = collator_convert_string_to_number_if_possible( str2_p, &num2 ) ) ) )
70 {
71
72 co = Z_INTL_COLLATOR_P(&INTL_G(current_collator));
73
74 if (!co || !co->ucoll) {
75 intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) );
76 intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
77 "Object not initialized", 0 );
78 php_error_docref(NULL, E_RECOVERABLE_ERROR, "Object not initialized");
79
80 }
81
82
83 ZVAL_LONG(result, ucol_strcoll(
84 co->ucoll,
85 INTL_Z_STRVAL_P(str1_p), INTL_Z_STRLEN_P(str1_p),
86 INTL_Z_STRVAL_P(str2_p), INTL_Z_STRLEN_P(str2_p) ));
87 }
88 else
89 {
90
91 if( num1_p )
92 {
93 if( num1_p == str1_p )
94 {
95
96
97
98 norm1_p = collator_convert_zstr_utf16_to_utf8( str1_p, &norm1 );
99
100
101 norm2_p = collator_normalize_sort_argument( str2_p, &norm2 );
102 }
103 else
104 {
105
106 Z_TRY_ADDREF_P(num1_p);
107 norm1_p = num1_p;
108
109
110 Z_TRY_ADDREF_P(num2_p);
111 norm2_p = num2_p;
112 }
113 }
114 else
115 {
116
117 norm1_p = collator_normalize_sort_argument( str1_p, &norm1 );
118
119
120 norm2_p = collator_normalize_sort_argument( str2_p, &norm2 );
121 }
122
123 rc = compare_function( result, norm1_p, norm2_p );
124
125 zval_ptr_dtor( norm1_p );
126 zval_ptr_dtor( norm2_p );
127 }
128
129 if( num1_p )
130 zval_ptr_dtor( num1_p );
131
132 if( num2_p )
133 zval_ptr_dtor( num2_p );
134
135 zval_ptr_dtor( str1_p );
136 zval_ptr_dtor( str2_p );
137
138 return rc;
139 }
140
141
142
143
144
145 static int collator_numeric_compare_function(zval *result, zval *op1, zval *op2)
146 {
147 zval num1, num2;
148 zval *num1_p = NULL;
149 zval *num2_p = NULL;
150
151 if( Z_TYPE_P(op1) == IS_STRING )
152 {
153 num1_p = collator_convert_string_to_double( op1, &num1 );
154 op1 = num1_p;
155 }
156
157 if( Z_TYPE_P(op2) == IS_STRING )
158 {
159 num2_p = collator_convert_string_to_double( op2, &num2 );
160 op2 = num2_p;
161 }
162
163 ZVAL_LONG(result, numeric_compare_function(op1, op2));
164
165 if( num1_p )
166 zval_ptr_dtor( num1_p );
167 if( num2_p )
168 zval_ptr_dtor( num2_p );
169
170 return SUCCESS;
171 }
172
173
174
175
176
177 static int collator_icu_compare_function(zval *result, zval *op1, zval *op2)
178 {
179 zval str1, str2;
180 int rc = SUCCESS;
181 Collator_object* co = NULL;
182 zval *str1_p = NULL;
183 zval *str2_p = NULL;
184
185 str1_p = collator_make_printable_zval( op1, &str1);
186 str2_p = collator_make_printable_zval( op2, &str2 );
187
188
189 co = Z_INTL_COLLATOR_P(&INTL_G(current_collator));
190
191
192 ZVAL_LONG(result, ucol_strcoll(
193 co->ucoll,
194 INTL_Z_STRVAL_P(str1_p), INTL_Z_STRLEN_P(str1_p),
195 INTL_Z_STRVAL_P(str2_p), INTL_Z_STRLEN_P(str2_p) ));
196
197 zval_ptr_dtor( str1_p );
198 zval_ptr_dtor( str2_p );
199
200 return rc;
201 }
202
203
204
205
206
207 static int collator_compare_func( const void* a, const void* b )
208 {
209 Bucket *f;
210 Bucket *s;
211 zval result;
212 zval *first;
213 zval *second;
214
215 f = (Bucket *) a;
216 s = (Bucket *) b;
217
218 first = &f->val;
219 second = &s->val;
220
221 if( INTL_G(compare_func)( &result, first, second) == FAILURE )
222 return 0;
223
224 if( Z_TYPE(result) == IS_DOUBLE )
225 {
226 if( Z_DVAL(result) < 0 )
227 return -1;
228 else if( Z_DVAL(result) > 0 )
229 return 1;
230 else
231 return 0;
232 }
233
234 convert_to_long(&result);
235
236 if( Z_LVAL(result) < 0 )
237 return -1;
238 else if( Z_LVAL(result) > 0 )
239 return 1;
240
241 return 0;
242 }
243
244
245
246
247
248 static int collator_cmp_sort_keys( const void *p1, const void *p2 )
249 {
250 char* key1 = ((collator_sort_key_index_t*)p1)->key;
251 char* key2 = ((collator_sort_key_index_t*)p2)->key;
252
253 return strcmp( key1, key2 );
254 }
255
256
257
258
259
260 static collator_compare_func_t collator_get_compare_function( const zend_long sort_flags )
261 {
262 collator_compare_func_t func;
263
264 switch( sort_flags )
265 {
266 case COLLATOR_SORT_NUMERIC:
267 func = collator_numeric_compare_function;
268 break;
269
270 case COLLATOR_SORT_STRING:
271 func = collator_icu_compare_function;
272 break;
273
274 case COLLATOR_SORT_REGULAR:
275 default:
276 func = collator_regular_compare_function;
277 break;
278 }
279
280 return func;
281 }
282
283
284
285
286
287 static void collator_sort_internal( int renumber, INTERNAL_FUNCTION_PARAMETERS )
288 {
289 zval saved_collator;
290 zval* array = NULL;
291 HashTable* hash = NULL;
292 zend_long sort_flags = COLLATOR_SORT_REGULAR;
293
294 COLLATOR_METHOD_INIT_VARS
295
296
297 if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Oa/|l",
298 &object, Collator_ce_ptr, &array, &sort_flags ) == FAILURE )
299 {
300 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
301 "collator_sort_internal: unable to parse input params", 0 );
302
303 RETURN_FALSE;
304 }
305
306
307 COLLATOR_METHOD_FETCH_OBJECT;
308
309
310 INTL_G(compare_func) = collator_get_compare_function( sort_flags );
311
312 hash = Z_ARRVAL_P( array );
313
314
315 collator_convert_hash_from_utf8_to_utf16( hash, COLLATOR_ERROR_CODE_P( co ) );
316 COLLATOR_CHECK_STATUS( co, "Error converting hash from UTF-8 to UTF-16" );
317
318
319 ZVAL_COPY_VALUE(&saved_collator, &INTL_G( current_collator ));
320 ZVAL_COPY_VALUE(&INTL_G( current_collator ), object);
321
322
323 zend_hash_sort(hash, collator_compare_func, renumber);
324
325
326 ZVAL_COPY_VALUE(&INTL_G( current_collator ), &saved_collator);
327
328
329 collator_convert_hash_from_utf16_to_utf8( hash, COLLATOR_ERROR_CODE_P( co ) );
330 COLLATOR_CHECK_STATUS( co, "Error converting hash from UTF-16 to UTF-8" );
331
332 RETURN_TRUE;
333 }
334
335
336
337
338
339
340
341 PHP_FUNCTION( collator_sort )
342 {
343 collator_sort_internal( TRUE, INTERNAL_FUNCTION_PARAM_PASSTHRU );
344 }
345
346
347 static void collator_sortkey_swap(collator_sort_key_index_t *p, collator_sort_key_index_t *q)
348 {
349 collator_sort_key_index_t t;
350 t = *p;
351 *p = *q;
352 *q = t;
353 }
354
355
356
357
358
359
360
361
362
363 PHP_FUNCTION( collator_sort_with_sort_keys )
364 {
365 zval* array = NULL;
366 zval garbage;
367 HashTable* hash = NULL;
368 zval* hashData = NULL;
369
370 char* sortKeyBuf = NULL;
371 uint32_t sortKeyBufSize = DEF_SORT_KEYS_BUF_SIZE;
372 ptrdiff_t sortKeyBufOffset = 0;
373 int32_t sortKeyLen = 0;
374 uint32_t bufLeft = 0;
375 uint32_t bufIncrement = 0;
376
377 collator_sort_key_index_t* sortKeyIndxBuf = NULL;
378 uint32_t sortKeyIndxBufSize = DEF_SORT_KEYS_INDX_BUF_SIZE;
379 uint32_t sortKeyIndxSize = sizeof( collator_sort_key_index_t );
380
381 uint32_t sortKeyCount = 0;
382 uint32_t j = 0;
383
384 UChar* utf16_buf = NULL;
385 int utf16_buf_size = DEF_UTF16_BUF_SIZE;
386 int utf16_len = 0;
387
388 COLLATOR_METHOD_INIT_VARS
389
390
391 if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Oa",
392 &object, Collator_ce_ptr, &array ) == FAILURE )
393 {
394 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
395 "collator_sort_with_sort_keys: unable to parse input params", 0 );
396
397 RETURN_FALSE;
398 }
399
400
401 COLLATOR_METHOD_FETCH_OBJECT;
402
403 if (!co || !co->ucoll) {
404 intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) );
405 intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
406 "Object not initialized", 0 );
407 php_error_docref(NULL, E_RECOVERABLE_ERROR, "Object not initialized");
408
409 RETURN_FALSE;
410 }
411
412
413
414
415 hash = Z_ARRVAL_P( array );
416
417 if( !hash || zend_hash_num_elements( hash ) == 0 )
418 RETURN_TRUE;
419
420
421 sortKeyBuf = ecalloc( sortKeyBufSize, sizeof( char ) );
422 sortKeyIndxBuf = ecalloc( sortKeyIndxBufSize, sizeof( uint8_t ) );
423 utf16_buf = eumalloc( utf16_buf_size );
424
425
426 ZEND_HASH_FOREACH_VAL(hash, hashData) {
427
428
429 utf16_len = utf16_buf_size;
430
431
432 if( Z_TYPE_P( hashData ) == IS_STRING )
433 {
434 intl_convert_utf8_to_utf16( &utf16_buf, &utf16_len, Z_STRVAL_P( hashData ), Z_STRLEN_P( hashData ), COLLATOR_ERROR_CODE_P( co ) );
435
436 if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
437 {
438 intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) );
439 intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ), "Sort with sort keys failed", 0 );
440
441 if( utf16_buf )
442 efree( utf16_buf );
443
444 efree( sortKeyIndxBuf );
445 efree( sortKeyBuf );
446
447 RETURN_FALSE;
448 }
449 }
450 else
451 {
452
453 utf16_len = 0;
454 utf16_buf[utf16_len] = 0;
455 }
456
457 if( (utf16_len + 1) > utf16_buf_size )
458 utf16_buf_size = utf16_len + 1;
459
460
461 bufLeft = sortKeyBufSize - sortKeyBufOffset;
462
463 sortKeyLen = ucol_getSortKey( co->ucoll,
464 utf16_buf,
465 utf16_len,
466 (uint8_t*)sortKeyBuf + sortKeyBufOffset,
467 bufLeft );
468
469
470 if( sortKeyLen > bufLeft )
471 {
472 bufIncrement = ( sortKeyLen > DEF_SORT_KEYS_BUF_INCREMENT ) ? sortKeyLen : DEF_SORT_KEYS_BUF_INCREMENT;
473
474 sortKeyBufSize += bufIncrement;
475 bufLeft += bufIncrement;
476
477 sortKeyBuf = erealloc( sortKeyBuf, sortKeyBufSize );
478
479 sortKeyLen = ucol_getSortKey( co->ucoll, utf16_buf, utf16_len, (uint8_t*)sortKeyBuf + sortKeyBufOffset, bufLeft );
480 }
481
482
483 if( ( sortKeyCount + 1 ) * sortKeyIndxSize > sortKeyIndxBufSize )
484 {
485 bufIncrement = ( sortKeyIndxSize > DEF_SORT_KEYS_INDX_BUF_INCREMENT ) ? sortKeyIndxSize : DEF_SORT_KEYS_INDX_BUF_INCREMENT;
486
487 sortKeyIndxBufSize += bufIncrement;
488
489 sortKeyIndxBuf = erealloc( sortKeyIndxBuf, sortKeyIndxBufSize );
490 }
491
492 sortKeyIndxBuf[sortKeyCount].key = (char*)sortKeyBufOffset;
493
494 sortKeyIndxBuf[sortKeyCount].zstr = hashData;
495
496 sortKeyBufOffset += sortKeyLen;
497 ++sortKeyCount;
498
499 } ZEND_HASH_FOREACH_END();
500
501
502 for( j = 0; j < sortKeyCount; j++ )
503 sortKeyIndxBuf[j].key = sortKeyBuf + (ptrdiff_t)sortKeyIndxBuf[j].key;
504
505
506 zend_sort( sortKeyIndxBuf, sortKeyCount,
507 sortKeyIndxSize, collator_cmp_sort_keys, (swap_func_t)collator_sortkey_swap);
508
509 ZVAL_COPY_VALUE(&garbage, array);
510
511 array_init(array);
512
513 for( j = 0; j < sortKeyCount; j++ )
514 {
515 Z_TRY_ADDREF_P( sortKeyIndxBuf[j].zstr );
516 zend_hash_next_index_insert( Z_ARRVAL_P(array), sortKeyIndxBuf[j].zstr);
517 }
518
519 if( utf16_buf )
520 efree( utf16_buf );
521
522 zval_ptr_dtor(&garbage);
523 efree( sortKeyIndxBuf );
524 efree( sortKeyBuf );
525
526 RETURN_TRUE;
527 }
528
529
530
531
532
533
534
535 PHP_FUNCTION( collator_asort )
536 {
537 collator_sort_internal( FALSE, INTERNAL_FUNCTION_PARAM_PASSTHRU );
538 }
539
540
541
542
543
544
545 PHP_FUNCTION( collator_get_sort_key )
546 {
547 char* str = NULL;
548 size_t str_len = 0;
549 UChar* ustr = NULL;
550 int32_t ustr_len = 0;
551 int key_len = 0;
552 zend_string* key_str;
553
554 COLLATOR_METHOD_INIT_VARS
555
556
557 if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Os",
558 &object, Collator_ce_ptr, &str, &str_len ) == FAILURE )
559 {
560 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
561 "collator_get_sort_key: unable to parse input params", 0 );
562
563 RETURN_FALSE;
564 }
565
566
567 COLLATOR_METHOD_FETCH_OBJECT;
568
569 if (!co || !co->ucoll) {
570 intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) );
571 intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
572 "Object not initialized", 0 );
573 php_error_docref(NULL, E_RECOVERABLE_ERROR, "Object not initialized");
574
575 RETURN_FALSE;
576 }
577
578
579
580
581
582
583 intl_convert_utf8_to_utf16(
584 &ustr, &ustr_len, str, str_len, COLLATOR_ERROR_CODE_P( co ) );
585 if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
586 {
587
588 intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) );
589
590
591 intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
592 "Error converting first argument to UTF-16", 0 );
593 efree( ustr );
594 RETURN_FALSE;
595 }
596
597
598
599 key_len = ucol_getSortKey(co->ucoll, ustr, ustr_len, NULL, 0);
600 if(!key_len) {
601 efree( ustr );
602 RETURN_FALSE;
603 }
604 key_str = zend_string_alloc(key_len, 0);
605 key_len = ucol_getSortKey(co->ucoll, ustr, ustr_len, (uint8_t*)ZSTR_VAL(key_str), key_len);
606 efree( ustr );
607 if(!key_len) {
608 RETURN_FALSE;
609 }
610 ZSTR_LEN(key_str) = key_len - 1;
611 RETVAL_NEW_STR(key_str);
612 }
613
614
615
616
617
618
619
620
621
622