Annotation of embedaddon/php/ext/mbstring/php_unicode.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 1997-2012 The PHP Group |
! 6: +----------------------------------------------------------------------+
! 7: | This source file is subject to version 3.01 of the PHP license, |
! 8: | that is bundled with this package in the file LICENSE, and is |
! 9: | available through the world-wide-web at the following url: |
! 10: | http://www.php.net/license/3_01.txt |
! 11: | If you did not receive a copy of the PHP license and are unable to |
! 12: | obtain it through the world-wide-web, please send a note to |
! 13: | license@php.net so we can mail you a copy immediately. |
! 14: +----------------------------------------------------------------------+
! 15: | Author: Wez Furlong (wez@thebrainroom.com) |
! 16: +----------------------------------------------------------------------+
! 17:
! 18: Based on code from ucdata-2.5, which has the following Copyright:
! 19:
! 20: Copyright 2001 Computing Research Labs, New Mexico State University
! 21:
! 22: Permission is hereby granted, free of charge, to any person obtaining a
! 23: copy of this software and associated documentation files (the "Software"),
! 24: to deal in the Software without restriction, including without limitation
! 25: the rights to use, copy, modify, merge, publish, distribute, sublicense,
! 26: and/or sell copies of the Software, and to permit persons to whom the
! 27: Software is furnished to do so, subject to the following conditions:
! 28:
! 29: The above copyright notice and this permission notice shall be included in
! 30: all copies or substantial portions of the Software.
! 31: */
! 32:
! 33: #ifdef HAVE_CONFIG_H
! 34: #include "config.h"
! 35: #endif
! 36:
! 37: #include "php.h"
! 38: #include "php_ini.h"
! 39:
! 40: #if HAVE_MBSTRING
! 41:
! 42: /* include case folding data generated from the official UnicodeData.txt file */
! 43: #include "mbstring.h"
! 44: #include "php_unicode.h"
! 45: #include "unicode_data.h"
! 46:
! 47: ZEND_EXTERN_MODULE_GLOBALS(mbstring)
! 48:
! 49: /*
! 50: * A simple array of 32-bit masks for lookup.
! 51: */
! 52: static unsigned long masks32[32] = {
! 53: 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020,
! 54: 0x00000040, 0x00000080, 0x00000100, 0x00000200, 0x00000400, 0x00000800,
! 55: 0x00001000, 0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000,
! 56: 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, 0x00800000,
! 57: 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000,
! 58: 0x40000000, 0x80000000
! 59: };
! 60:
! 61:
! 62: static int prop_lookup(unsigned long code, unsigned long n)
! 63: {
! 64: long l, r, m;
! 65:
! 66: /*
! 67: * There is an extra node on the end of the offsets to allow this routine
! 68: * to work right. If the index is 0xffff, then there are no nodes for the
! 69: * property.
! 70: */
! 71: if ((l = _ucprop_offsets[n]) == 0xffff)
! 72: return 0;
! 73:
! 74: /*
! 75: * Locate the next offset that is not 0xffff. The sentinel at the end of
! 76: * the array is the max index value.
! 77: */
! 78: for (m = 1; n + m < _ucprop_size && _ucprop_offsets[n + m] == 0xffff; m++)
! 79: ;
! 80:
! 81: r = _ucprop_offsets[n + m] - 1;
! 82:
! 83: while (l <= r) {
! 84: /*
! 85: * Determine a "mid" point and adjust to make sure the mid point is at
! 86: * the beginning of a range pair.
! 87: */
! 88: m = (l + r) >> 1;
! 89: m -= (m & 1);
! 90: if (code > _ucprop_ranges[m + 1])
! 91: l = m + 2;
! 92: else if (code < _ucprop_ranges[m])
! 93: r = m - 2;
! 94: else if (code >= _ucprop_ranges[m] && code <= _ucprop_ranges[m + 1])
! 95: return 1;
! 96: }
! 97: return 0;
! 98:
! 99: }
! 100:
! 101: MBSTRING_API int php_unicode_is_prop(unsigned long code, unsigned long mask1,
! 102: unsigned long mask2)
! 103: {
! 104: unsigned long i;
! 105:
! 106: if (mask1 == 0 && mask2 == 0)
! 107: return 0;
! 108:
! 109: for (i = 0; mask1 && i < 32; i++) {
! 110: if ((mask1 & masks32[i]) && prop_lookup(code, i))
! 111: return 1;
! 112: }
! 113:
! 114: for (i = 32; mask2 && i < _ucprop_size; i++) {
! 115: if ((mask2 & masks32[i & 31]) && prop_lookup(code, i))
! 116: return 1;
! 117: }
! 118:
! 119: return 0;
! 120: }
! 121:
! 122: static unsigned long case_lookup(unsigned long code, long l, long r, int field)
! 123: {
! 124: long m;
! 125:
! 126: /*
! 127: * Do the binary search.
! 128: */
! 129: while (l <= r) {
! 130: /*
! 131: * Determine a "mid" point and adjust to make sure the mid point is at
! 132: * the beginning of a case mapping triple.
! 133: */
! 134: m = (l + r) >> 1;
! 135: m -= (m % 3);
! 136: if (code > _uccase_map[m])
! 137: l = m + 3;
! 138: else if (code < _uccase_map[m])
! 139: r = m - 3;
! 140: else if (code == _uccase_map[m])
! 141: return _uccase_map[m + field];
! 142: }
! 143:
! 144: return code;
! 145: }
! 146:
! 147: MBSTRING_API unsigned long php_turkish_toupper(unsigned long code, long l, long r, int field)
! 148: {
! 149: if (code == 0x0069L) {
! 150: return 0x0130L;
! 151: }
! 152: return case_lookup(code, l, r, field);
! 153: }
! 154:
! 155: MBSTRING_API unsigned long php_turkish_tolower(unsigned long code, long l, long r, int field)
! 156: {
! 157: if (code == 0x0049L) {
! 158: return 0x0131L;
! 159: }
! 160: return case_lookup(code, l, r, field);
! 161: }
! 162:
! 163: MBSTRING_API unsigned long php_unicode_toupper(unsigned long code, enum mbfl_no_encoding enc TSRMLS_DC)
! 164: {
! 165: int field;
! 166: long l, r;
! 167:
! 168: if (php_unicode_is_upper(code))
! 169: return code;
! 170:
! 171: if (php_unicode_is_lower(code)) {
! 172: /*
! 173: * The character is lower case.
! 174: */
! 175: field = 2;
! 176: l = _uccase_len[0];
! 177: r = (l + _uccase_len[1]) - 3;
! 178:
! 179: if (enc == mbfl_no_encoding_8859_9) {
! 180: return php_turkish_toupper(code, l, r, field);
! 181: }
! 182:
! 183: } else {
! 184: /*
! 185: * The character is title case.
! 186: */
! 187: field = 1;
! 188: l = _uccase_len[0] + _uccase_len[1];
! 189: r = _uccase_size - 3;
! 190: }
! 191: return case_lookup(code, l, r, field);
! 192: }
! 193:
! 194: MBSTRING_API unsigned long php_unicode_tolower(unsigned long code, enum mbfl_no_encoding enc TSRMLS_DC)
! 195: {
! 196: int field;
! 197: long l, r;
! 198:
! 199: if (php_unicode_is_lower(code))
! 200: return code;
! 201:
! 202: if (php_unicode_is_upper(code)) {
! 203: /*
! 204: * The character is upper case.
! 205: */
! 206: field = 1;
! 207: l = 0;
! 208: r = _uccase_len[0] - 3;
! 209:
! 210: if (enc == mbfl_no_encoding_8859_9) {
! 211: return php_turkish_tolower(code, l, r, field);
! 212: }
! 213:
! 214: } else {
! 215: /*
! 216: * The character is title case.
! 217: */
! 218: field = 2;
! 219: l = _uccase_len[0] + _uccase_len[1];
! 220: r = _uccase_size - 3;
! 221: }
! 222: return case_lookup(code, l, r, field);
! 223: }
! 224:
! 225: MBSTRING_API unsigned long php_unicode_totitle(unsigned long code, enum mbfl_no_encoding enc TSRMLS_DC)
! 226: {
! 227: int field;
! 228: long l, r;
! 229:
! 230: if (php_unicode_is_title(code))
! 231: return code;
! 232:
! 233: /*
! 234: * The offset will always be the same for converting to title case.
! 235: */
! 236: field = 2;
! 237:
! 238: if (php_unicode_is_upper(code)) {
! 239: /*
! 240: * The character is upper case.
! 241: */
! 242: l = 0;
! 243: r = _uccase_len[0] - 3;
! 244: } else {
! 245: /*
! 246: * The character is lower case.
! 247: */
! 248: l = _uccase_len[0];
! 249: r = (l + _uccase_len[1]) - 3;
! 250: }
! 251: return case_lookup(code, l, r, field);
! 252:
! 253: }
! 254:
! 255:
! 256: #define BE_ARY_TO_UINT32(ptr) (\
! 257: ((unsigned char*)(ptr))[0]<<24 |\
! 258: ((unsigned char*)(ptr))[1]<<16 |\
! 259: ((unsigned char*)(ptr))[2]<< 8 |\
! 260: ((unsigned char*)(ptr))[3] )
! 261:
! 262: #define UINT32_TO_BE_ARY(ptr,val) { \
! 263: unsigned int v = val; \
! 264: ((unsigned char*)(ptr))[0] = (v>>24) & 0xff,\
! 265: ((unsigned char*)(ptr))[1] = (v>>16) & 0xff,\
! 266: ((unsigned char*)(ptr))[2] = (v>> 8) & 0xff,\
! 267: ((unsigned char*)(ptr))[3] = (v ) & 0xff;\
! 268: }
! 269:
! 270: MBSTRING_API char *php_unicode_convert_case(int case_mode, const char *srcstr, size_t srclen, size_t *ret_len,
! 271: const char *src_encoding TSRMLS_DC)
! 272: {
! 273: char *unicode, *newstr;
! 274: size_t unicode_len;
! 275: unsigned char *unicode_ptr;
! 276: size_t i;
! 277: enum mbfl_no_encoding _src_encoding = mbfl_name2no_encoding(src_encoding);
! 278:
! 279: if (_src_encoding == mbfl_no_encoding_invalid) {
! 280: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", src_encoding);
! 281: return NULL;
! 282: }
! 283:
! 284: unicode = php_mb_convert_encoding(srcstr, srclen, "UCS-4BE", src_encoding, &unicode_len TSRMLS_CC);
! 285: if (unicode == NULL)
! 286: return NULL;
! 287:
! 288: unicode_ptr = (unsigned char *)unicode;
! 289:
! 290: switch(case_mode) {
! 291: case PHP_UNICODE_CASE_UPPER:
! 292: for (i = 0; i < unicode_len; i+=4) {
! 293: UINT32_TO_BE_ARY(&unicode_ptr[i],
! 294: php_unicode_toupper(BE_ARY_TO_UINT32(&unicode_ptr[i]), _src_encoding TSRMLS_CC));
! 295: }
! 296: break;
! 297:
! 298: case PHP_UNICODE_CASE_LOWER:
! 299: for (i = 0; i < unicode_len; i+=4) {
! 300: UINT32_TO_BE_ARY(&unicode_ptr[i],
! 301: php_unicode_tolower(BE_ARY_TO_UINT32(&unicode_ptr[i]), _src_encoding TSRMLS_CC));
! 302: }
! 303: break;
! 304:
! 305: case PHP_UNICODE_CASE_TITLE: {
! 306: int mode = 0;
! 307:
! 308: for (i = 0; i < unicode_len; i+=4) {
! 309: int res = php_unicode_is_prop(
! 310: BE_ARY_TO_UINT32(&unicode_ptr[i]),
! 311: UC_MN|UC_ME|UC_CF|UC_LM|UC_SK|UC_LU|UC_LL|UC_LT|UC_PO|UC_OS, 0);
! 312: if (mode) {
! 313: if (res) {
! 314: UINT32_TO_BE_ARY(&unicode_ptr[i],
! 315: php_unicode_tolower(BE_ARY_TO_UINT32(&unicode_ptr[i]), _src_encoding TSRMLS_CC));
! 316: } else {
! 317: mode = 0;
! 318: }
! 319: } else {
! 320: if (res) {
! 321: mode = 1;
! 322: UINT32_TO_BE_ARY(&unicode_ptr[i],
! 323: php_unicode_totitle(BE_ARY_TO_UINT32(&unicode_ptr[i]), _src_encoding TSRMLS_CC));
! 324: }
! 325: }
! 326: }
! 327: } break;
! 328:
! 329: }
! 330:
! 331: newstr = php_mb_convert_encoding(unicode, unicode_len, src_encoding, "UCS-4BE", ret_len TSRMLS_CC);
! 332: efree(unicode);
! 333:
! 334: return newstr;
! 335: }
! 336:
! 337:
! 338: #endif /* HAVE_MBSTRING */
! 339:
! 340: /*
! 341: * Local variables:
! 342: * tab-width: 4
! 343: * c-basic-offset: 4
! 344: * End:
! 345: * vim600: sw=4 ts=4 fdm=marker
! 346: * vim<600: sw=4 ts=4
! 347: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>