return php_win32_cp_to_w_int(in, in_len, out_len, cp, flags);
}/*}}}*/
+#define ASCII_FAIL_RETURN() \
+ if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) { \
+ *out_len = 0; \
+ } \
+ return NULL;
PW32CP wchar_t *php_win32_cp_conv_ascii_to_w(const char* in, size_t in_len, size_t *out_len)
{/*{{{*/
- wchar_t *ret = NULL;
+ wchar_t *ret, *ret_idx;
const char *idx = in, *end;
-
+ #if PHP_DEBUG
+ size_t save_in_len = in_len;
+ #endif
+
assert(in && in_len ? in[in_len] == '\0' : 1);
if (!in) {
idx++;
}
- if (idx == end) {
- size_t i = 0;
- int k = 0;
- wchar_t *ret_idx;
+ ret = malloc((in_len+1)*sizeof(wchar_t));
+ if (!ret) {
+ SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY);
+ return NULL;
+ }
+
+ ret_idx = ret;
+ idx = in;
- ret = malloc((in_len+1)*sizeof(wchar_t));
- if (!ret) {
- SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY);
- return NULL;
+ /* Check and conversion could be merged. This however would
+ be more expencive, if a non ASCII string was passed.
+ TODO check whether the impact is acceptable. */
+ if (in_len > 15) {
+ const char *aidx = (const char *)ZEND_SLIDE_TO_ALIGNED16(in);
+
+ /* Process unaligned chunk. */
+ while (idx < aidx) {
+ *ret_idx++ = (wchar_t)*idx++;
}
- ret_idx = ret;
- do {
- k = _snwprintf(ret_idx, in_len - i, L"%.*hs", (int)(in_len - i), in);
+ /* Process aligned chunk. */
+ if (end - idx > 15) {
+ const __m128i mask = _mm_set1_epi32(0);
+ while (end - idx > 15) {
+ const __m128i block = _mm_load_si128((__m128i *)idx);
- if (-1 == k) {
- free(ret);
- SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
- return NULL;
- }
+ {
+ const __m128i lo = _mm_unpacklo_epi8(block, mask);
+ _mm_storeu_si128((__m128i *)ret_idx, lo);
+ }
- i += k + 1;
+ ret_idx += 8;
+ {
+ const __m128i hi = _mm_unpackhi_epi8(block, mask);
+ _mm_storeu_si128((__m128i *)ret_idx, hi);
+ }
- if (i < in_len) {
- /* Advance as this seems to be a string with \0 in it. */
- in += k + 1;
- ret_idx += k + 1;
+ idx += 16;
+ ret_idx += 8;
}
+ }
+ }
+ /* Process the trailing part, or otherwise process string < 16 bytes. */
+ while (idx < end) {
+ *ret_idx++ = (wchar_t)*idx++;
+ }
- } while (i < in_len);
- ret[in_len] = L'\0';
+ ret[in_len] = L'\0';
- assert(ret ? wcslen(ret) == in_len : 1);
- assert(ret && !save_in_len ? wcslen(ret) == in_len : 1);
++ assert(ret && !save_in_len ? wcslen(ret) == in_len : 1);
- if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) {
- *out_len = in_len;
- }
- } else {
- if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) {
- *out_len = 0;
- }
+ if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) {
+ *out_len = in_len;
}
return ret;