root/ext/intl/collator/collator_sort.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. collator_regular_compare_function
  2. collator_numeric_compare_function
  3. collator_icu_compare_function
  4. collator_compare_func
  5. collator_cmp_sort_keys
  6. collator_get_compare_function
  7. collator_sort_internal
  8. PHP_FUNCTION
  9. collator_sortkey_swap
  10. PHP_FUNCTION
  11. PHP_FUNCTION
  12. PHP_FUNCTION

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | This source file is subject to version 3.01 of the PHP license,      |
   6    | that is bundled with this package in the file LICENSE, and is        |
   7    | available through the world-wide-web at the following url:           |
   8    | http://www.php.net/license/3_01.txt                                  |
   9    | If you did not receive a copy of the PHP license and are unable to   |
  10    | obtain it through the world-wide-web, please send a note to          |
  11    | license@php.net so we can mail you a copy immediately.               |
  12    +----------------------------------------------------------------------+
  13    | Authors: Vadim Savchuk <vsavchuk@productengine.com>                  |
  14    |          Dmitry Lakhtyuk <dlakhtyuk@productengine.com>               |
  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  * Declare 'index' which will point to sort key in sort key
  35  * buffer.
  36  */
  37 typedef struct _collator_sort_key_index {
  38         char* key;       /* pointer to sort key */
  39         zval* zstr;     /* pointer to original string(hash-item) */
  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 /* {{{ collator_regular_compare_function */
  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         /* If both args are strings AND either of args is not numeric string
  66          * then use ICU-compare. Otherwise PHP-compare. */
  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                 /* Fetch collator object. */
  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                 /* Compare the strings using ICU. */
  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                 /* num1 is set if str1 and str2 are strings. */
  91                 if( num1_p )
  92                 {
  93                         if( num1_p == str1_p )
  94                         {
  95                                 /* str1 is string but not numeric string
  96                                  * just convert it to utf8.
  97                                  */
  98                                 norm1_p = collator_convert_zstr_utf16_to_utf8( str1_p, &norm1 );
  99 
 100                                 /* num2 is not set but str2 is string => do normalization. */
 101                                 norm2_p = collator_normalize_sort_argument( str2_p, &norm2 );
 102                         }
 103                         else
 104                         {
 105                                 /* str1 is numeric strings => passthru to PHP-compare. */
 106                                 Z_TRY_ADDREF_P(num1_p);
 107                                 norm1_p = num1_p;
 108 
 109                                 /* str2 is numeric strings => passthru to PHP-compare. */
 110                                 Z_TRY_ADDREF_P(num2_p);
 111                                 norm2_p = num2_p;
 112                         }
 113                 }
 114                 else
 115                 {
 116                         /* num1 is not set if str1 or str2 is not a string => do normalization. */
 117                         norm1_p = collator_normalize_sort_argument( str1_p, &norm1 );
 118 
 119                         /* if num1 is not set then num2 is not set as well => do normalization. */
 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 /* {{{ collator_numeric_compare_function
 143  * Convert input args to double and compare it.
 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 /* {{{ collator_icu_compare_function
 175  * Direct use of ucol_strcoll.
 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         /* Fetch collator object. */
 189         co = Z_INTL_COLLATOR_P(&INTL_G(current_collator));
 190 
 191         /* Compare the strings using ICU. */
 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 /* {{{ collator_compare_func
 205  * Taken from PHP7 source (array_data_compare).
 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 /* {{{ collator_cmp_sort_keys
 246  * Compare sort keys
 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 /* {{{ collator_get_compare_function
 258  * Choose compare function according to sort flags.
 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 /* {{{ collator_sort_internal
 285  * Common code shared by collator_sort() and collator_asort() API functions.
 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         /* Parse parameters. */
 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         /* Fetch the object. */
 307         COLLATOR_METHOD_FETCH_OBJECT;
 308 
 309         /* Set 'compare function' according to sort flags. */
 310         INTL_G(compare_func) = collator_get_compare_function( sort_flags );
 311 
 312         hash = Z_ARRVAL_P( array );
 313 
 314         /* Convert strings in the specified array from UTF-8 to UTF-16. */
 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         /* Save specified collator in the request-global (?) variable. */
 319         ZVAL_COPY_VALUE(&saved_collator, &INTL_G( current_collator ));
 320         ZVAL_COPY_VALUE(&INTL_G( current_collator ), object);
 321 
 322         /* Sort specified array. */
 323         zend_hash_sort(hash, collator_compare_func, renumber);
 324 
 325         /* Restore saved collator. */
 326         ZVAL_COPY_VALUE(&INTL_G( current_collator ), &saved_collator);
 327 
 328         /* Convert strings in the specified array back to UTF-8. */
 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 /* {{{ proto bool Collator::sort( Collator $coll, array(string) $arr [, int $sort_flags] )
 337  * Sort array using specified collator. }}} */
 338 /* {{{ proto bool collator_sort(  Collator $coll, array(string) $arr [, int $sort_flags] )
 339  * Sort array using specified collator.
 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 /* {{{ proto bool Collator::sortWithSortKeys( Collator $coll, array(string) $arr )
 357  * Equivalent to standard PHP sort using Collator.
 358  * Uses ICU ucol_getSortKey for performance. }}} */
 359 /* {{{ proto bool collator_sort_with_sort_keys( Collator $coll, array(string) $arr )
 360  * Equivalent to standard PHP sort using Collator.
 361  * Uses ICU ucol_getSortKey for performance.
 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;                     /* currently processed item of input hash */
 369 
 370         char*       sortKeyBuf           = NULL;                     /* buffer to store sort keys */
 371         uint32_t    sortKeyBufSize       = DEF_SORT_KEYS_BUF_SIZE;   /* buffer size */
 372         ptrdiff_t   sortKeyBufOffset     = 0;                        /* pos in buffer to store sort key */
 373         int32_t     sortKeyLen           = 0;                        /* the length of currently processing key */
 374         uint32_t    bufLeft              = 0;
 375         uint32_t    bufIncrement         = 0;
 376 
 377         collator_sort_key_index_t* sortKeyIndxBuf = NULL;            /* buffer to store 'indexes' which will be passed to 'qsort' */
 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;                     /* tmp buffer to hold current processing string in utf-16 */
 385         int         utf16_buf_size       = DEF_UTF16_BUF_SIZE;       /* the length of utf16_buf */
 386         int         utf16_len            = 0;                        /* length of converted string */
 387 
 388         COLLATOR_METHOD_INIT_VARS
 389 
 390         /* Parse parameters. */
 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         /* Fetch the object. */
 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          * Sort specified array.
 414          */
 415         hash = Z_ARRVAL_P( array );
 416 
 417         if( !hash || zend_hash_num_elements( hash ) == 0 )
 418                 RETURN_TRUE;
 419 
 420         /* Create bufers */
 421         sortKeyBuf     = ecalloc( sortKeyBufSize,     sizeof( char    ) );
 422         sortKeyIndxBuf = ecalloc( sortKeyIndxBufSize, sizeof( uint8_t ) );
 423         utf16_buf      = eumalloc( utf16_buf_size );
 424 
 425         /* Iterate through input hash and create a sort key for each value. */
 426         ZEND_HASH_FOREACH_VAL(hash, hashData) {
 427                 /* Convert current hash item from UTF-8 to UTF-16LE and save the result to utf16_buf. */
 428 
 429                 utf16_len = utf16_buf_size;
 430 
 431                 /* Process string values only. */
 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                         /* Set empty string */
 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                 /* Get sort key, reallocating the buffer if needed. */
 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                 /* check for sortKeyBuf overflow, increasing its size of the buffer if needed */
 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                 /*  check sortKeyIndxBuf overflow, increasing its size of the buffer if needed */
 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;    /* remember just offset, cause address */
 493                                                                                /* of 'sortKeyBuf' may be changed due to realloc. */
 494                 sortKeyIndxBuf[sortKeyCount].zstr = hashData;
 495 
 496                 sortKeyBufOffset += sortKeyLen;
 497                 ++sortKeyCount;
 498 
 499         } ZEND_HASH_FOREACH_END();
 500 
 501         /* update ptrs to point to valid keys. */
 502         for( j = 0; j < sortKeyCount; j++ )
 503                 sortKeyIndxBuf[j].key = sortKeyBuf + (ptrdiff_t)sortKeyIndxBuf[j].key;
 504 
 505         /* sort it */
 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         /* for resulting hash we'll assign new hash keys rather then reordering */
 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 /* {{{ proto bool Collator::asort( Collator $coll, array(string) $arr )
 531  * Sort array using specified collator, maintaining index association. }}} */
 532 /* {{{ proto bool collator_asort( Collator $coll, array(string) $arr )
 533  * Sort array using specified collator, maintaining index association.
 534  */
 535 PHP_FUNCTION( collator_asort )
 536 {
 537         collator_sort_internal( FALSE, INTERNAL_FUNCTION_PARAM_PASSTHRU );
 538 }
 539 /* }}} */
 540 
 541 /* {{{ proto bool Collator::getSortKey( Collator $coll, string $str )
 542  * Get a sort key for a string from a Collator. }}} */
 543 /* {{{ proto bool collator_get_sort_key( Collator $coll, string $str )
 544  * Get a sort key for a string from a Collator. */
 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         /* Parse parameters. */
 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         /* Fetch the object. */
 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          * Compare given strings (converting them to UTF-16 first).
 580          */
 581 
 582         /* First convert the strings to UTF-16. */
 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                 /* Set global error code. */
 588                 intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) );
 589 
 590                 /* Set error messages. */
 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         /* ucol_getSortKey is exception in that the key length includes the
 598          * NUL terminator*/
 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  * Local variables:
 617  * tab-width: 4
 618  * c-basic-offset: 4
 619  * End:
 620  * vim600: noet sw=4 ts=4 fdm=marker
 621  * vim<600: noet sw=4 ts=4
 622  */

/* [<][>][^][v][top][bottom][index][help] */