+ return 0;
+ }
+#endif
+}
+
+static const unsigned char utf8mblen[256] = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 4,4,4,4,4,4,4,4,5,5,5,5,6,6,6,6
+};
+static const unsigned char utf8mask[] = {
+ 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01
+};
+
+static size_t utf8towc(wchar_t *wc, const unsigned char *uc, size_t len)
+{
+ unsigned char ub = utf8mblen[*uc];
+
+ if (!ub || ub > len || ub > 3) {
+ return 0;
+ }
+
+ *wc = *uc & utf8mask[ub];
+
+ switch (ub) {
+ case 4:
+ if ((uc[1] & 0xc0) != 0x80) {
+ return 0;
+ }
+ *wc <<= 6;
+ *wc += *++uc & 0x3f;
+ /* no break */
+ case 3:
+ if ((uc[1] & 0xc0) != 0x80) {
+ return 0;
+ }
+ *wc <<= 6;
+ *wc += *++uc & 0x3f;
+ /* no break */
+ case 2:
+ if ((uc[1] & 0xc0) != 0x80) {
+ return 0;
+ }
+ *wc <<= 6;
+ *wc += *++uc & 0x3f;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return ub;
+}
+
+static size_t parse_locmb(php_http_url_t *url, const char *ptr, const char *end)
+{
+ wchar_t wchar;
+ size_t consumed = 0;
+#if defined(HAVE_MBRTOWC)
+ mbstate_t ps = {0};
+
+ consumed = mbrtowc(&wchar, ptr, end - ptr, &ps);
+#elif defined(HAVE_MBTOWC)
+ consumed = mbtowc(&wchar, ptr, end - ptr);
+#endif
+
+ if (!consumed || consumed == (size_t) -1 || !iswalnum(wchar)) {
+ return 0;
+ }
+
+ return consumed - 1;
+}
+
+#include "ualpha.h"
+
+static zend_bool isualnum(wchar_t ch)
+{
+ unsigned i;
+
+ /* digits */
+ if (ch >= 0x30 && ch <= 0x39) {
+ return 1;
+ }
+ for (i = 0; i < sizeof(utf8_ranges)/sizeof(utf8_range_t); ++i) {
+ if (utf8_ranges[i].start == ch) {
+ return 1;
+ } else if (utf8_ranges[i].start <= ch && utf8_ranges[i].end >= ch) {
+ if (utf8_ranges[i].step == 1) {
+ return 1;