diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-03-14 05:42:27 +0000 |
---|---|---|
committer | <> | 2013-04-03 16:25:08 +0000 |
commit | c4dd7a1a684490673e25aaf4fabec5df138854c4 (patch) | |
tree | 4d57c44caae4480efff02b90b9be86f44bf25409 /ext/intl/collator/collator_convert.c | |
download | php2-master.tar.gz |
Imported from /home/lorry/working-area/delta_php2/php-5.4.13.tar.bz2.HEADphp-5.4.13master
Diffstat (limited to 'ext/intl/collator/collator_convert.c')
-rw-r--r-- | ext/intl/collator/collator_convert.c | 485 |
1 files changed, 485 insertions, 0 deletions
diff --git a/ext/intl/collator/collator_convert.c b/ext/intl/collator/collator_convert.c new file mode 100644 index 0000000..e989d4c --- /dev/null +++ b/ext/intl/collator/collator_convert.c @@ -0,0 +1,485 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Vadim Savchuk <vsavchuk@productengine.com> | + | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> | + +----------------------------------------------------------------------+ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php_intl.h" +#include "collator_class.h" +#include "collator_is_numeric.h" +#include "collator_convert.h" +#include "intl_convert.h" + +#include <unicode/ustring.h> +#include <php.h> + +#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION <= 1) +#define CAST_OBJECT_SHOULD_FREE ,0 +#else +#define CAST_OBJECT_SHOULD_FREE +#endif + +#define COLLATOR_CONVERT_RETURN_FAILED(retval) { \ + zval_add_ref( &retval ); \ + return retval; \ + } + +/* {{{ collator_convert_hash_item_from_utf8_to_utf16 */ +static void collator_convert_hash_item_from_utf8_to_utf16( + HashTable* hash, int hashKeyType, char* hashKey, ulong hashIndex, + UErrorCode* status ) +{ + const char* old_val; + int old_val_len; + UChar* new_val = NULL; + int new_val_len = 0; + zval** hashData = NULL; + zval* znew_val = NULL; + + /* Get current hash item. */ + zend_hash_get_current_data( hash, (void**) &hashData ); + + /* Process string values only. */ + if( Z_TYPE_P( *hashData ) != IS_STRING ) + return; + + old_val = Z_STRVAL_P( *hashData ); + old_val_len = Z_STRLEN_P( *hashData ); + + /* Convert it from UTF-8 to UTF-16LE and save the result to new_val[_len]. */ + intl_convert_utf8_to_utf16( &new_val, &new_val_len, old_val, old_val_len, status ); + if( U_FAILURE( *status ) ) + return; + + /* Update current hash item with the converted value. */ + MAKE_STD_ZVAL( znew_val ); + ZVAL_STRINGL( znew_val, (char*)new_val, UBYTES(new_val_len), FALSE ); + + if( hashKeyType == HASH_KEY_IS_STRING ) + { + zend_hash_update( hash, hashKey, strlen( hashKey ) + 1, + (void*) &znew_val, sizeof(zval*), NULL ); + } + else /* hashKeyType == HASH_KEY_IS_LONG */ + { + zend_hash_index_update( hash, hashIndex, + (void*) &znew_val, sizeof(zval*), NULL ); + } +} +/* }}} */ + +/* {{{ collator_convert_hash_item_from_utf16_to_utf8 */ +static void collator_convert_hash_item_from_utf16_to_utf8( + HashTable* hash, int hashKeyType, char* hashKey, ulong hashIndex, + UErrorCode* status ) +{ + const char* old_val; + int old_val_len; + char* new_val = NULL; + int new_val_len = 0; + zval** hashData = NULL; + zval* znew_val = NULL; + + /* Get current hash item. */ + zend_hash_get_current_data( hash, (void**) &hashData ); + + /* Process string values only. */ + if( Z_TYPE_P( *hashData ) != IS_STRING ) + return; + + old_val = Z_STRVAL_P( *hashData ); + old_val_len = Z_STRLEN_P( *hashData ); + + /* Convert it from UTF-16LE to UTF-8 and save the result to new_val[_len]. */ + intl_convert_utf16_to_utf8( &new_val, &new_val_len, + (UChar*)old_val, UCHARS(old_val_len), status ); + if( U_FAILURE( *status ) ) + return; + + /* Update current hash item with the converted value. */ + MAKE_STD_ZVAL( znew_val ); + ZVAL_STRINGL( znew_val, (char*)new_val, new_val_len, FALSE ); + + if( hashKeyType == HASH_KEY_IS_STRING ) + { + zend_hash_update( hash, hashKey, strlen( hashKey ) + 1, + (void*) &znew_val, sizeof(zval*), NULL ); + } + else /* hashKeyType == HASH_KEY_IS_LONG */ + { + zend_hash_index_update( hash, hashIndex, + (void*) &znew_val, sizeof(zval*), NULL ); + } +} +/* }}} */ + +/* {{{ collator_convert_hash_from_utf8_to_utf16 + * Convert values of the given hash from UTF-8 encoding to UTF-16LE. + */ +void collator_convert_hash_from_utf8_to_utf16( HashTable* hash, UErrorCode* status ) +{ + ulong hashIndex = 0; + char* hashKey = NULL; + int hashKeyType = 0; + + zend_hash_internal_pointer_reset( hash ); + while( ( hashKeyType = zend_hash_get_current_key( hash, &hashKey, &hashIndex, 0 ) ) + != HASH_KEY_NON_EXISTANT ) + { + /* Convert current hash item from UTF-8 to UTF-16LE. */ + collator_convert_hash_item_from_utf8_to_utf16( + hash, hashKeyType, hashKey, hashIndex, status ); + if( U_FAILURE( *status ) ) + return; + + /* Proceed to the next item. */ + zend_hash_move_forward( hash ); + } +} +/* }}} */ + +/* {{{ collator_convert_hash_from_utf16_to_utf8 + * Convert values of the given hash from UTF-16LE encoding to UTF-8. + */ +void collator_convert_hash_from_utf16_to_utf8( HashTable* hash, UErrorCode* status ) +{ + ulong hashIndex = 0; + char* hashKey = NULL; + int hashKeyType = 0; + + zend_hash_internal_pointer_reset( hash ); + while( ( hashKeyType = zend_hash_get_current_key( hash, &hashKey, &hashIndex, 0 ) ) + != HASH_KEY_NON_EXISTANT ) + { + /* Convert current hash item from UTF-16LE to UTF-8. */ + collator_convert_hash_item_from_utf16_to_utf8( + hash, hashKeyType, hashKey, hashIndex, status ); + if( U_FAILURE( *status ) ) { + return; + } + + /* Proceed to the next item. */ + zend_hash_move_forward( hash ); + } +} +/* }}} */ + +/* {{{ collator_convert_zstr_utf16_to_utf8 + * + * Convert string from utf16 to utf8. + * + * @param zval* utf16_zval String to convert. + * + * @return zval* Converted string. + */ +zval* collator_convert_zstr_utf16_to_utf8( zval* utf16_zval ) +{ + zval* utf8_zval = NULL; + char* str = NULL; + int str_len = 0; + UErrorCode status = U_ZERO_ERROR; + + /* Convert to utf8 then. */ + intl_convert_utf16_to_utf8( &str, &str_len, + (UChar*) Z_STRVAL_P(utf16_zval), UCHARS( Z_STRLEN_P(utf16_zval) ), &status ); + if( U_FAILURE( status ) ) + php_error( E_WARNING, "Error converting utf16 to utf8 in collator_convert_zval_utf16_to_utf8()" ); + + ALLOC_INIT_ZVAL( utf8_zval ); + ZVAL_STRINGL( utf8_zval, str, str_len, FALSE ); + + return utf8_zval; +} +/* }}} */ + +/* {{{ collator_convert_zstr_utf8_to_utf16 + * + * Convert string from utf8 to utf16. + * + * @param zval* utf8_zval String to convert. + * + * @return zval* Converted string. + */ +zval* collator_convert_zstr_utf8_to_utf16( zval* utf8_zval ) +{ + zval* zstr = NULL; + UChar* ustr = NULL; + int ustr_len = 0; + UErrorCode status = U_ZERO_ERROR; + + /* Convert the string to UTF-16. */ + intl_convert_utf8_to_utf16( + &ustr, &ustr_len, + Z_STRVAL_P( utf8_zval ), Z_STRLEN_P( utf8_zval ), + &status ); + if( U_FAILURE( status ) ) + php_error( E_WARNING, "Error casting object to string in collator_convert_zstr_utf8_to_utf16()" ); + + /* Set string. */ + ALLOC_INIT_ZVAL( zstr ); + ZVAL_STRINGL( zstr, (char*)ustr, UBYTES(ustr_len), FALSE ); + + return zstr; +} +/* }}} */ + +/* {{{ collator_convert_object_to_string + * Convert object to UTF16-encoded string. + */ +zval* collator_convert_object_to_string( zval* obj TSRMLS_DC ) +{ + zval* zstr = NULL; + UErrorCode status = U_ZERO_ERROR; + UChar* ustr = NULL; + int ustr_len = 0; + + /* Bail out if it's not an object. */ + if( Z_TYPE_P( obj ) != IS_OBJECT ) + { + COLLATOR_CONVERT_RETURN_FAILED( obj ); + } + + /* Try object's handlers. */ + if( Z_OBJ_HT_P(obj)->get ) + { + zstr = Z_OBJ_HT_P(obj)->get( obj TSRMLS_CC ); + + switch( Z_TYPE_P( zstr ) ) + { + case IS_OBJECT: + { + /* Bail out. */ + zval_ptr_dtor( &zstr ); + COLLATOR_CONVERT_RETURN_FAILED( obj ); + } break; + + case IS_STRING: + break; + + default: + { + convert_to_string( zstr ); + } break; + } + } + else if( Z_OBJ_HT_P(obj)->cast_object ) + { + ALLOC_INIT_ZVAL( zstr ); + + if( Z_OBJ_HT_P(obj)->cast_object( obj, zstr, IS_STRING CAST_OBJECT_SHOULD_FREE TSRMLS_CC ) == FAILURE ) + { + /* cast_object failed => bail out. */ + zval_ptr_dtor( &zstr ); + COLLATOR_CONVERT_RETURN_FAILED( obj ); + } + } + + /* Object wasn't successfuly converted => bail out. */ + if( zstr == NULL ) + { + COLLATOR_CONVERT_RETURN_FAILED( obj ); + } + + /* Convert the string to UTF-16. */ + intl_convert_utf8_to_utf16( + &ustr, &ustr_len, + Z_STRVAL_P( zstr ), Z_STRLEN_P( zstr ), + &status ); + if( U_FAILURE( status ) ) + php_error( E_WARNING, "Error casting object to string in collator_convert_object_to_string()" ); + + /* Cleanup zstr to hold utf16 string. */ + zval_dtor( zstr ); + + /* Set string. */ + ZVAL_STRINGL( zstr, (char*)ustr, UBYTES(ustr_len), FALSE ); + + /* Don't free ustr cause it's set in zstr without copy. + * efree( ustr ); + */ + + return zstr; +} +/* }}} */ + +/* {{{ collator_convert_string_to_number + * + * Convert string to number. + * + * @param zval* str String to convert. + * + * @return zval* Number. If str is not numeric string return number zero. + */ +zval* collator_convert_string_to_number( zval* str ) +{ + zval* num = collator_convert_string_to_number_if_possible( str ); + if( num == str ) + { + /* String wasn't converted => return zero. */ + zval_ptr_dtor( &num ); + + ALLOC_INIT_ZVAL( num ); + ZVAL_LONG( num, 0 ); + } + + return num; +} +/* }}} */ + +/* {{{ collator_convert_string_to_double + * + * Convert string to double. + * + * @param zval* str String to convert. + * + * @return zval* Number. If str is not numeric string return number zero. + */ +zval* collator_convert_string_to_double( zval* str ) +{ + zval* num = collator_convert_string_to_number( str ); + if( Z_TYPE_P(num) == IS_LONG ) + { + ZVAL_DOUBLE( num, Z_LVAL_P( num ) ); + } + + return num; +} +/* }}} */ + +/* {{{ collator_convert_string_to_number_if_possible + * + * Convert string to numer. + * + * @param zval* str String to convert. + * + * @return zval* Number if str is numeric string. Otherwise + * original str param. + */ +zval* collator_convert_string_to_number_if_possible( zval* str ) +{ + zval* num = NULL; + int is_numeric = 0; + long lval = 0; + double dval = 0; + + if( Z_TYPE_P( str ) != IS_STRING ) + { + COLLATOR_CONVERT_RETURN_FAILED( str ); + } + + if( ( is_numeric = collator_is_numeric( (UChar*) Z_STRVAL_P(str), UCHARS( Z_STRLEN_P(str) ), &lval, &dval, 1 ) ) ) + { + ALLOC_INIT_ZVAL( num ); + + if( is_numeric == IS_LONG ) + Z_LVAL_P(num) = lval; + if( is_numeric == IS_DOUBLE ) + Z_DVAL_P(num) = dval; + + Z_TYPE_P(num) = is_numeric; + } + else + { + COLLATOR_CONVERT_RETURN_FAILED( str ); + } + + return num; +} +/* }}} */ + +/* {{{ collator_make_printable_zval + * + * Returns string from input zval. + * + * @param zval* arg zval to get string from + * + * @return zval* UTF16 string. + */ +zval* collator_make_printable_zval( zval* arg ) +{ + zval arg_copy; + int use_copy = 0; + zval* str = NULL; + + if( Z_TYPE_P(arg) != IS_STRING ) + { + zend_make_printable_zval(arg, &arg_copy, &use_copy); + + if( use_copy ) + { + str = collator_convert_zstr_utf8_to_utf16( &arg_copy ); + zval_dtor( &arg_copy ); + } + else + { + str = collator_convert_zstr_utf8_to_utf16( arg ); + } + } + else + { + COLLATOR_CONVERT_RETURN_FAILED( arg ); + } + + return str; +} +/* }}} */ + +/* {{{ collator_normalize_sort_argument + * + * Normalize argument to use in sort's compare function. + * + * @param zval* arg Sort's argument to normalize. + * + * @return zval* Normalized copy of arg or unmodified arg + * if normalization is not needed. + */ +zval* collator_normalize_sort_argument( zval* arg ) +{ + zval* n_arg = NULL; + + if( Z_TYPE_P( arg ) != IS_STRING ) + { + /* If its not a string then nothing to do. + * Return original arg. + */ + COLLATOR_CONVERT_RETURN_FAILED( arg ); + } + + /* Try convert to number. */ + n_arg = collator_convert_string_to_number_if_possible( arg ); + + if( n_arg == arg ) + { + /* Conversion to number failed. */ + zval_ptr_dtor( &n_arg ); + + /* Convert string to utf8. */ + n_arg = collator_convert_zstr_utf16_to_utf8( arg ); + } + + return n_arg; +} +/* }}} */ +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ |