| 949 | } |
| 950 | |
| 951 | int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, |
| 952 | UnicodeNormalizationEnum n_type, |
| 953 | void *opaque, DynBufReallocFunc *realloc_func) |
| 954 | { |
| 955 | int *buf, buf_len, i, p, starter_pos, cc, last_cc, out_len; |
| 956 | bool is_compat; |
| 957 | DynBuf dbuf_s, *dbuf = &dbuf_s; |
| 958 | |
| 959 | is_compat = n_type >> 1; |
| 960 | |
| 961 | dbuf_init2(dbuf, opaque, realloc_func); |
| 962 | if (dbuf_claim(dbuf, sizeof(int) * src_len)) |
| 963 | goto fail; |
| 964 | |
| 965 | /* common case: latin1 is unaffected by NFC */ |
| 966 | if (n_type == UNICODE_NFC) { |
| 967 | for(i = 0; i < src_len; i++) { |
| 968 | if (src[i] >= 0x100) |
| 969 | goto not_latin1; |
| 970 | } |
| 971 | buf = (int *)dbuf->buf; |
| 972 | memcpy(buf, src, src_len * sizeof(int)); |
| 973 | *pdst = (uint32_t *)buf; |
| 974 | return src_len; |
| 975 | not_latin1: ; |
| 976 | } |
| 977 | |
| 978 | to_nfd_rec(dbuf, (const int *)src, src_len, is_compat); |
| 979 | if (dbuf_error(dbuf)) { |
| 980 | fail: |
| 981 | *pdst = NULL; |
| 982 | return -1; |
| 983 | } |
| 984 | buf = (int *)dbuf->buf; |
| 985 | buf_len = dbuf->size / sizeof(int); |
| 986 | |
| 987 | sort_cc(buf, buf_len); |
| 988 | |
| 989 | if (buf_len <= 1 || (n_type & 1) != 0) { |
| 990 | /* NFD / NFKD */ |
| 991 | *pdst = (uint32_t *)buf; |
| 992 | return buf_len; |
| 993 | } |
| 994 | |
| 995 | i = 1; |
| 996 | out_len = 1; |
| 997 | while (i < buf_len) { |
| 998 | /* find the starter character and test if it is blocked from |
| 999 | the character at 'i' */ |
| 1000 | last_cc = unicode_get_cc(buf[i]); |
| 1001 | starter_pos = out_len - 1; |
| 1002 | while (starter_pos >= 0) { |
| 1003 | cc = unicode_get_cc(buf[starter_pos]); |
| 1004 | if (cc == 0) |
| 1005 | break; |
| 1006 | if (cc >= last_cc) |
| 1007 | goto next; |
| 1008 | last_cc = 256; |
no test coverage detected