Annotation of embedaddon/php/ext/intl/collator/collator_convert.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      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_class.h"
                     24: #include "collator_is_numeric.h"
                     25: #include "collator_convert.h"
                     26: #include "intl_convert.h"
                     27: 
                     28: #include <unicode/ustring.h>
                     29: #include <php.h>
                     30: 
                     31: #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION <= 1)
                     32: #define CAST_OBJECT_SHOULD_FREE ,0
                     33: #else
                     34: #define CAST_OBJECT_SHOULD_FREE
                     35: #endif
                     36: 
                     37: #define COLLATOR_CONVERT_RETURN_FAILED(retval) { \
                     38:                        zval_add_ref( &retval );             \
                     39:                        return retval;                       \
                     40:        }
                     41: 
                     42: /* {{{ collator_convert_hash_item_from_utf8_to_utf16 */
                     43: static void collator_convert_hash_item_from_utf8_to_utf16(
                     44:        HashTable* hash, int hashKeyType, char* hashKey, ulong hashIndex,
                     45:        UErrorCode* status )
                     46: {
                     47:        const char* old_val;
                     48:        int         old_val_len;
                     49:        UChar*      new_val      = NULL;
                     50:        int         new_val_len  = 0;
                     51:        zval**      hashData     = NULL;
                     52:        zval*       znew_val     = NULL;
                     53: 
                     54:        /* Get current hash item. */
                     55:        zend_hash_get_current_data( hash, (void**) &hashData );
                     56: 
                     57:        /* Process string values only. */
                     58:        if( Z_TYPE_P( *hashData ) != IS_STRING )
                     59:                return;
                     60: 
                     61:        old_val     = Z_STRVAL_P( *hashData );
                     62:        old_val_len = Z_STRLEN_P( *hashData );
                     63: 
                     64:        /* Convert it from UTF-8 to UTF-16LE and save the result to new_val[_len]. */
                     65:        intl_convert_utf8_to_utf16( &new_val, &new_val_len, old_val, old_val_len, status );
                     66:        if( U_FAILURE( *status ) )
                     67:                return;
                     68: 
                     69:        /* Update current hash item with the converted value. */
                     70:        MAKE_STD_ZVAL( znew_val );
                     71:        ZVAL_STRINGL( znew_val, (char*)new_val, UBYTES(new_val_len), FALSE );
                     72: 
                     73:        if( hashKeyType == HASH_KEY_IS_STRING )
                     74:        {
                     75:                zend_hash_update( hash, hashKey, strlen( hashKey ) + 1,
                     76:                        (void*) &znew_val, sizeof(zval*), NULL );
                     77:        }
                     78:        else /* hashKeyType == HASH_KEY_IS_LONG */
                     79:        {
                     80:                zend_hash_index_update( hash, hashIndex,
                     81:                        (void*) &znew_val, sizeof(zval*), NULL );
                     82:        }
                     83: }
                     84: /* }}} */
                     85: 
                     86: /* {{{ collator_convert_hash_item_from_utf16_to_utf8 */
                     87: static void collator_convert_hash_item_from_utf16_to_utf8(
                     88:        HashTable* hash, int hashKeyType, char* hashKey, ulong hashIndex,
                     89:        UErrorCode* status )
                     90: {
                     91:        const char* old_val;
                     92:        int         old_val_len;
                     93:        char*       new_val      = NULL;
                     94:        int         new_val_len  = 0;
                     95:        zval**      hashData     = NULL;
                     96:        zval*       znew_val     = NULL;
                     97: 
                     98:        /* Get current hash item. */
                     99:        zend_hash_get_current_data( hash, (void**) &hashData );
                    100: 
                    101:        /* Process string values only. */
                    102:        if( Z_TYPE_P( *hashData ) != IS_STRING )
                    103:                return;
                    104: 
                    105:        old_val     = Z_STRVAL_P( *hashData );
                    106:        old_val_len = Z_STRLEN_P( *hashData );
                    107: 
                    108:        /* Convert it from UTF-16LE to UTF-8 and save the result to new_val[_len]. */
                    109:        intl_convert_utf16_to_utf8( &new_val, &new_val_len,
                    110:                (UChar*)old_val, UCHARS(old_val_len), status );
                    111:        if( U_FAILURE( *status ) )
                    112:                return;
                    113: 
                    114:        /* Update current hash item with the converted value. */
                    115:        MAKE_STD_ZVAL( znew_val );
                    116:        ZVAL_STRINGL( znew_val, (char*)new_val, new_val_len, FALSE );
                    117: 
                    118:        if( hashKeyType == HASH_KEY_IS_STRING )
                    119:        {
                    120:                zend_hash_update( hash, hashKey, strlen( hashKey ) + 1,
                    121:                        (void*) &znew_val, sizeof(zval*), NULL );
                    122:        }
                    123:        else /* hashKeyType == HASH_KEY_IS_LONG */
                    124:        {
                    125:                zend_hash_index_update( hash, hashIndex,
                    126:                        (void*) &znew_val, sizeof(zval*), NULL );
                    127:        }
                    128: }
                    129: /* }}} */
                    130: 
                    131: /* {{{ collator_convert_hash_from_utf8_to_utf16
                    132:  *  Convert values of the given hash from UTF-8 encoding to UTF-16LE.
                    133:  */
                    134: void collator_convert_hash_from_utf8_to_utf16( HashTable* hash, UErrorCode* status )
                    135: {
                    136:        ulong    hashIndex    = 0;
                    137:        char*    hashKey      = NULL;
                    138:        int      hashKeyType  = 0;
                    139: 
                    140:        zend_hash_internal_pointer_reset( hash );
                    141:        while( ( hashKeyType = zend_hash_get_current_key( hash, &hashKey, &hashIndex, 0 ) )
                    142:                        != HASH_KEY_NON_EXISTANT )
                    143:        {
                    144:                /* Convert current hash item from UTF-8 to UTF-16LE. */
                    145:                collator_convert_hash_item_from_utf8_to_utf16(
                    146:                        hash, hashKeyType, hashKey, hashIndex, status );
                    147:                if( U_FAILURE( *status ) )
                    148:                        return;
                    149: 
                    150:                /* Proceed to the next item. */
                    151:                zend_hash_move_forward( hash );
                    152:        }
                    153: }
                    154: /* }}} */
                    155: 
                    156: /* {{{ collator_convert_hash_from_utf16_to_utf8
                    157:  * Convert values of the given hash from UTF-16LE encoding to UTF-8.
                    158:  */
                    159: void collator_convert_hash_from_utf16_to_utf8( HashTable* hash, UErrorCode* status )
                    160: {
                    161:        ulong    hashIndex    = 0;
                    162:        char*    hashKey      = NULL;
                    163:        int      hashKeyType  = 0;
                    164: 
                    165:        zend_hash_internal_pointer_reset( hash );
                    166:        while( ( hashKeyType = zend_hash_get_current_key( hash, &hashKey, &hashIndex, 0 ) )
                    167:                        != HASH_KEY_NON_EXISTANT )
                    168:        {
                    169:                /* Convert current hash item from UTF-16LE to UTF-8. */
                    170:                collator_convert_hash_item_from_utf16_to_utf8(
                    171:                        hash, hashKeyType, hashKey, hashIndex, status );
                    172:                if( U_FAILURE( *status ) ) {
                    173:                        return;
                    174:                }
                    175: 
                    176:                /* Proceed to the next item. */
                    177:                zend_hash_move_forward( hash );
                    178:        }
                    179: }
                    180: /* }}} */
                    181: 
                    182: /* {{{ collator_convert_zstr_utf16_to_utf8
                    183:  *
                    184:  * Convert string from utf16 to utf8.
                    185:  *
                    186:  * @param  zval* utf16_zval String to convert.
                    187:  *
                    188:  * @return zval* Converted string.
                    189:  */
                    190: zval* collator_convert_zstr_utf16_to_utf8( zval* utf16_zval )
                    191: {
                    192:        zval* utf8_zval   = NULL;
                    193:        char* str         = NULL;
                    194:        int   str_len     = 0;
                    195:        UErrorCode status = U_ZERO_ERROR;
                    196: 
                    197:        /* Convert to utf8 then. */
                    198:        intl_convert_utf16_to_utf8( &str, &str_len,
                    199:                (UChar*) Z_STRVAL_P(utf16_zval), UCHARS( Z_STRLEN_P(utf16_zval) ), &status );
                    200:        if( U_FAILURE( status ) )
                    201:                php_error( E_WARNING, "Error converting utf16 to utf8 in collator_convert_zval_utf16_to_utf8()" );
                    202: 
                    203:        ALLOC_INIT_ZVAL( utf8_zval );
                    204:        ZVAL_STRINGL( utf8_zval, str, str_len, FALSE );
                    205: 
                    206:        return utf8_zval;
                    207: }
                    208: /* }}} */
                    209: 
                    210: /* {{{ collator_convert_zstr_utf8_to_utf16
                    211:  *
                    212:  * Convert string from utf8 to utf16.
                    213:  *
                    214:  * @param  zval* utf8_zval String to convert.
                    215:  *
                    216:  * @return zval* Converted string.
                    217:  */
                    218: zval* collator_convert_zstr_utf8_to_utf16( zval* utf8_zval )
                    219: {
                    220:        zval* zstr        = NULL;
                    221:        UChar* ustr       = NULL;
                    222:        int    ustr_len   = 0;
                    223:        UErrorCode status = U_ZERO_ERROR;
                    224: 
                    225:        /* Convert the string to UTF-16. */
                    226:        intl_convert_utf8_to_utf16(
                    227:                        &ustr, &ustr_len,
                    228:                        Z_STRVAL_P( utf8_zval ), Z_STRLEN_P( utf8_zval ),
                    229:                        &status );
                    230:        if( U_FAILURE( status ) )
                    231:                php_error( E_WARNING, "Error casting object to string in collator_convert_zstr_utf8_to_utf16()" );
                    232: 
                    233:        /* Set string. */
                    234:        ALLOC_INIT_ZVAL( zstr );
                    235:        ZVAL_STRINGL( zstr, (char*)ustr, UBYTES(ustr_len), FALSE );
                    236: 
                    237:        return zstr;
                    238: }
                    239: /* }}} */
                    240: 
                    241: /* {{{ collator_convert_object_to_string
                    242:  * Convert object to UTF16-encoded string.
                    243:  */
                    244: zval* collator_convert_object_to_string( zval* obj TSRMLS_DC )
                    245: {
                    246:        zval* zstr        = NULL;
                    247:        UErrorCode status = U_ZERO_ERROR;
                    248:        UChar* ustr       = NULL;
                    249:        int    ustr_len   = 0;
                    250: 
                    251:        /* Bail out if it's not an object. */
                    252:        if( Z_TYPE_P( obj ) != IS_OBJECT )
                    253:        {
                    254:                COLLATOR_CONVERT_RETURN_FAILED( obj );
                    255:        }
                    256: 
                    257:        /* Try object's handlers. */
                    258:        if( Z_OBJ_HT_P(obj)->get )
                    259:        {
                    260:                zstr = Z_OBJ_HT_P(obj)->get( obj TSRMLS_CC );
                    261: 
                    262:                switch( Z_TYPE_P( zstr ) )
                    263:                {
                    264:                        case IS_OBJECT:
                    265:                                {
                    266:                                        /* Bail out. */
                    267:                                        zval_ptr_dtor( &zstr );
                    268:                                        COLLATOR_CONVERT_RETURN_FAILED( obj );
                    269:                                } break;
                    270: 
                    271:                        case IS_STRING:
                    272:                                break;
                    273: 
                    274:                        default:
                    275:                                {
                    276:                                        convert_to_string( zstr );
                    277:                                } break;
                    278:                }
                    279:        }
                    280:        else if( Z_OBJ_HT_P(obj)->cast_object )
                    281:        {
                    282:                ALLOC_INIT_ZVAL( zstr );
                    283: 
                    284:                if( Z_OBJ_HT_P(obj)->cast_object( obj, zstr, IS_STRING CAST_OBJECT_SHOULD_FREE TSRMLS_CC ) == FAILURE )
                    285:                {
                    286:                        /* cast_object failed => bail out. */
                    287:                        zval_ptr_dtor( &zstr );
                    288:                        COLLATOR_CONVERT_RETURN_FAILED( obj );
                    289:                }
                    290:        }
                    291: 
                    292:        /* Object wasn't successfuly converted => bail out. */
                    293:        if( zstr == NULL )
                    294:        {
                    295:                COLLATOR_CONVERT_RETURN_FAILED( obj );
                    296:        }
                    297: 
                    298:        /* Convert the string to UTF-16. */
                    299:        intl_convert_utf8_to_utf16(
                    300:                        &ustr, &ustr_len,
                    301:                        Z_STRVAL_P( zstr ), Z_STRLEN_P( zstr ),
                    302:                        &status );
                    303:        if( U_FAILURE( status ) )
                    304:                php_error( E_WARNING, "Error casting object to string in collator_convert_object_to_string()" );
                    305: 
                    306:        /* Cleanup zstr to hold utf16 string. */
                    307:        zval_dtor( zstr );
                    308: 
                    309:        /* Set string. */
                    310:        ZVAL_STRINGL( zstr, (char*)ustr, UBYTES(ustr_len), FALSE );
                    311: 
                    312:        /* Don't free ustr cause it's set in zstr without copy.
                    313:         * efree( ustr );
                    314:         */
                    315: 
                    316:        return zstr;
                    317: }
                    318: /* }}} */
                    319: 
                    320: /* {{{ collator_convert_string_to_number
                    321:  *
                    322:  * Convert string to number.
                    323:  *
                    324:  * @param  zval* str String to convert.
                    325:  *
                    326:  * @return zval* Number. If str is not numeric string return number zero.
                    327:  */
                    328: zval* collator_convert_string_to_number( zval* str )
                    329: {
                    330:        zval* num = collator_convert_string_to_number_if_possible( str );
                    331:        if( num == str )
                    332:        {
                    333:                /* String wasn't converted => return zero. */
                    334:                zval_ptr_dtor( &num );
                    335: 
                    336:                ALLOC_INIT_ZVAL( num );
                    337:                ZVAL_LONG( num, 0 );
                    338:        }
                    339: 
                    340:        return num;
                    341: }
                    342: /* }}} */
                    343: 
                    344: /* {{{ collator_convert_string_to_double
                    345:  *
                    346:  * Convert string to double.
                    347:  *
                    348:  * @param  zval* str String to convert.
                    349:  *
                    350:  * @return zval* Number. If str is not numeric string return number zero.
                    351:  */
                    352: zval* collator_convert_string_to_double( zval* str )
                    353: {
                    354:        zval* num = collator_convert_string_to_number( str );
                    355:        if( Z_TYPE_P(num) == IS_LONG )
                    356:        {
                    357:                ZVAL_DOUBLE( num, Z_LVAL_P( num ) );
                    358:        }
                    359: 
                    360:        return num;
                    361: }
                    362: /* }}} */
                    363: 
                    364: /* {{{ collator_convert_string_to_number_if_possible
                    365:  *
                    366:  * Convert string to numer.
                    367:  *
                    368:  * @param  zval* str String to convert.
                    369:  *
                    370:  * @return zval* Number if str is numeric string. Otherwise
                    371:  *               original str param.
                    372:  */
                    373: zval* collator_convert_string_to_number_if_possible( zval* str )
                    374: {
                    375:        zval* num      = NULL;
                    376:        int is_numeric = 0;
                    377:        long lval      = 0;
                    378:        double dval    = 0;
                    379: 
                    380:        if( Z_TYPE_P( str ) != IS_STRING )
                    381:        {
                    382:                COLLATOR_CONVERT_RETURN_FAILED( str );
                    383:        }
                    384: 
                    385:        if( ( is_numeric = collator_is_numeric( (UChar*) Z_STRVAL_P(str), UCHARS( Z_STRLEN_P(str) ), &lval, &dval, 1 ) ) )
                    386:        {
                    387:                ALLOC_INIT_ZVAL( num );
                    388: 
                    389:                if( is_numeric == IS_LONG )
                    390:                        Z_LVAL_P(num) = lval;
                    391:                if( is_numeric == IS_DOUBLE )
                    392:                        Z_DVAL_P(num) = dval;
                    393: 
                    394:                Z_TYPE_P(num) = is_numeric;
                    395:        }
                    396:        else
                    397:        {
                    398:                COLLATOR_CONVERT_RETURN_FAILED( str );
                    399:        }
                    400: 
                    401:        return num;
                    402: }
                    403: /* }}} */
                    404: 
                    405: /* {{{ collator_make_printable_zval
                    406:  *
                    407:  * Returns string from input zval.
                    408:  *
                    409:  * @param  zval* arg zval to get string from
                    410:  *
                    411:  * @return zval* UTF16 string.
                    412:  */
                    413: zval* collator_make_printable_zval( zval* arg )
                    414: {
                    415:        zval arg_copy;
                    416:        int use_copy = 0;
                    417:        zval* str    = NULL;
                    418: 
                    419:        if( Z_TYPE_P(arg) != IS_STRING )
                    420:        {
                    421:                zend_make_printable_zval(arg, &arg_copy, &use_copy);
                    422: 
                    423:                if( use_copy )
                    424:                {
                    425:                        str = collator_convert_zstr_utf8_to_utf16( &arg_copy );
                    426:                        zval_dtor( &arg_copy );
                    427:                }
                    428:                else
                    429:                {
                    430:                        str = collator_convert_zstr_utf8_to_utf16( arg );
                    431:                }
                    432:        }
                    433:        else
                    434:        {
                    435:                COLLATOR_CONVERT_RETURN_FAILED( arg );
                    436:        }
                    437: 
                    438:        return str;
                    439: }
                    440: /* }}} */
                    441: 
                    442: /* {{{ collator_normalize_sort_argument
                    443:  *
                    444:  * Normalize argument to use in sort's compare function.
                    445:  *
                    446:  * @param  zval* arg Sort's argument to normalize.
                    447:  *
                    448:  * @return zval* Normalized copy of arg or unmodified arg
                    449:  *               if normalization is not needed.
                    450:  */
                    451: zval* collator_normalize_sort_argument( zval* arg )
                    452: {
                    453:        zval* n_arg = NULL;
                    454: 
                    455:        if( Z_TYPE_P( arg ) != IS_STRING )
                    456:        {
                    457:                /* If its not a string then nothing to do.
                    458:                 * Return original arg.
                    459:                 */
                    460:                COLLATOR_CONVERT_RETURN_FAILED( arg );
                    461:        }
                    462: 
                    463:        /* Try convert to number. */
                    464:        n_arg = collator_convert_string_to_number_if_possible( arg );
                    465: 
                    466:        if( n_arg == arg )
                    467:        {
                    468:                /* Conversion to number failed. */
                    469:                zval_ptr_dtor( &n_arg );
                    470: 
                    471:                /* Convert string to utf8. */
                    472:                n_arg = collator_convert_zstr_utf16_to_utf8( arg );
                    473:        }
                    474: 
                    475:        return n_arg;
                    476: }
                    477: /* }}} */
                    478: /*
                    479:  * Local variables:
                    480:  * tab-width: 4
                    481:  * c-basic-offset: 4
                    482:  * End:
                    483:  * vim600: noet sw=4 ts=4 fdm=marker
                    484:  * vim<600: noet sw=4 ts=4
                    485:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>