You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by bo...@apache.org on 2016/03/14 16:35:55 UTC

[2/5] hadoop git commit: HDFS-9932: added uriparser2 library to HDFS-8707. Contributed by Bob Hansen.

http://git-wip-us.apache.org/repos/asf/hadoop/blob/196db0d6/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriParse.c
----------------------------------------------------------------------
diff --git a/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriParse.c b/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriParse.c
new file mode 100644
index 0000000..dd777b4
--- /dev/null
+++ b/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriParse.c
@@ -0,0 +1,2205 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2007, Weijia Song <so...@gmail.com>
+ * Copyright (C) 2007, Sebastian Pipping <we...@hartwork.org>
+ * All rights reserved.
+ *
+ * Redistribution  and use in source and binary forms, with or without
+ * modification,  are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions   of  source  code  must  retain  the   above
+ *       copyright  notice, this list of conditions and the  following
+ *       disclaimer.
+ *
+ *     * Redistributions  in  binary  form must  reproduce  the  above
+ *       copyright  notice, this list of conditions and the  following
+ *       disclaimer   in  the  documentation  and/or  other  materials
+ *       provided with the distribution.
+ *
+ *     * Neither  the name of the <ORGANIZATION> nor the names of  its
+ *       contributors  may  be  used to endorse  or  promote  products
+ *       derived  from  this software without specific  prior  written
+ *       permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT  NOT
+ * LIMITED  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS
+ * FOR  A  PARTICULAR  PURPOSE ARE DISCLAIMED. IN NO EVENT  SHALL  THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL,    SPECIAL,   EXEMPLARY,   OR   CONSEQUENTIAL   DAMAGES
+ * (INCLUDING,  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES;  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT  LIABILITY,  OR  TORT (INCLUDING  NEGLIGENCE  OR  OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file UriParse.c
+ * Holds the RFC 3986 %URI parsing implementation.
+ * NOTE: This source file includes itself twice.
+ */
+
+/* What encodings are enabled? */
+#include "UriDefsConfig.h"
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# define URI_PASS_ANSI 1
+# include "UriParse.c"
+# undef URI_PASS_ANSI
+# define URI_PASS_UNICODE 1
+# include "UriParse.c"
+# undef URI_PASS_UNICODE
+#else
+# ifdef URI_PASS_ANSI
+#  include "UriDefsAnsi.h"
+# else
+#  include "UriDefsUnicode.h"
+#  include <wchar.h>
+# endif
+
+
+
+#ifndef URI_DOXYGEN
+# include "Uri.h"
+# include "UriIp4.h"
+# include "UriCommon.h"
+# include "UriParseBase.h"
+#endif
+
+
+
+#define URI_SET_DIGIT \
+	     _UT('0'): \
+	case _UT('1'): \
+	case _UT('2'): \
+	case _UT('3'): \
+	case _UT('4'): \
+	case _UT('5'): \
+	case _UT('6'): \
+	case _UT('7'): \
+	case _UT('8'): \
+	case _UT('9')
+
+#define URI_SET_HEX_LETTER_UPPER \
+	     _UT('A'): \
+	case _UT('B'): \
+	case _UT('C'): \
+	case _UT('D'): \
+	case _UT('E'): \
+	case _UT('F')
+
+#define URI_SET_HEX_LETTER_LOWER \
+	     _UT('a'): \
+	case _UT('b'): \
+	case _UT('c'): \
+	case _UT('d'): \
+	case _UT('e'): \
+	case _UT('f')
+
+#define URI_SET_HEXDIG \
+	URI_SET_DIGIT: \
+	case URI_SET_HEX_LETTER_UPPER: \
+	case URI_SET_HEX_LETTER_LOWER
+
+#define URI_SET_ALPHA \
+	URI_SET_HEX_LETTER_UPPER: \
+	case URI_SET_HEX_LETTER_LOWER: \
+	case _UT('g'): \
+	case _UT('G'): \
+	case _UT('h'): \
+	case _UT('H'): \
+	case _UT('i'): \
+	case _UT('I'): \
+	case _UT('j'): \
+	case _UT('J'): \
+	case _UT('k'): \
+	case _UT('K'): \
+	case _UT('l'): \
+	case _UT('L'): \
+	case _UT('m'): \
+	case _UT('M'): \
+	case _UT('n'): \
+	case _UT('N'): \
+	case _UT('o'): \
+	case _UT('O'): \
+	case _UT('p'): \
+	case _UT('P'): \
+	case _UT('q'): \
+	case _UT('Q'): \
+	case _UT('r'): \
+	case _UT('R'): \
+	case _UT('s'): \
+	case _UT('S'): \
+	case _UT('t'): \
+	case _UT('T'): \
+	case _UT('u'): \
+	case _UT('U'): \
+	case _UT('v'): \
+	case _UT('V'): \
+	case _UT('w'): \
+	case _UT('W'): \
+	case _UT('x'): \
+	case _UT('X'): \
+	case _UT('y'): \
+	case _UT('Y'): \
+	case _UT('z'): \
+	case _UT('Z')
+
+
+
+static const URI_CHAR * URI_FUNC(ParseAuthority)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseHexZero)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseHierPart)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseIpFutLoop)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseIpFutStopGo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseIpLit2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseIPv6address2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseOwnHost)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseOwnHost2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfoNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParsePartHelperTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParsePathAbsEmpty)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParsePathAbsNoLeadSlash)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParsePathRootless)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParsePchar)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParsePctEncoded)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParsePctSubUnres)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParsePort)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseQueryFrag)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseSegment)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseSegmentNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseUriReference)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseUriTail)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseUriTailTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseZeroMoreSlashSegs)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+
+static UriBool URI_FUNC(OnExitOwnHost2)(URI_TYPE(ParserState) * state, const URI_CHAR * first);
+static UriBool URI_FUNC(OnExitOwnHostUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first);
+static UriBool URI_FUNC(OnExitOwnPortUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first);
+static UriBool URI_FUNC(OnExitSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, const URI_CHAR * first);
+static void URI_FUNC(OnExitPartHelperTwo)(URI_TYPE(ParserState) * state);
+
+static void URI_FUNC(ResetParserState)(URI_TYPE(ParserState) * state);
+
+static UriBool URI_FUNC(PushPathSegment)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+
+static void URI_FUNC(StopSyntax)(URI_TYPE(ParserState) * state, const URI_CHAR * errorPos);
+static void URI_FUNC(StopMalloc)(URI_TYPE(ParserState) * state);
+
+
+
+static URI_INLINE void URI_FUNC(StopSyntax)(URI_TYPE(ParserState) * state,
+		const URI_CHAR * errorPos) {
+	URI_FUNC(FreeUriMembers)(state->uri);
+	state->errorPos = errorPos;
+	state->errorCode = URI_ERROR_SYNTAX;
+}
+
+
+
+static URI_INLINE void URI_FUNC(StopMalloc)(URI_TYPE(ParserState) * state) {
+	URI_FUNC(FreeUriMembers)(state->uri);
+	state->errorPos = NULL;
+	state->errorCode = URI_ERROR_MALLOC;
+}
+
+
+
+/*
+ * [authority]-><[>[ipLit2][authorityTwo]
+ * [authority]->[ownHostUserInfoNz]
+ * [authority]-><NULL>
+ */
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseAuthority)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		/* "" regname host */
+		state->uri->hostText.first = URI_FUNC(SafeToPointTo);
+		state->uri->hostText.afterLast = URI_FUNC(SafeToPointTo);
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('['):
+		{
+			const URI_CHAR * const afterIpLit2
+					= URI_FUNC(ParseIpLit2)(state, first + 1, afterLast);
+			if (afterIpLit2 == NULL) {
+				return NULL;
+			}
+			state->uri->hostText.first = first + 1; /* HOST BEGIN */
+			return URI_FUNC(ParseAuthorityTwo)(state, afterIpLit2, afterLast);
+		}
+
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('%'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('-'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT('.'):
+	case _UT(':'):
+	case _UT(';'):
+	case _UT('@'):
+	case _UT('\''):
+	case _UT('_'):
+	case _UT('~'):
+	case _UT('+'):
+	case _UT('='):
+	case URI_SET_DIGIT:
+	case URI_SET_ALPHA:
+		state->uri->userInfo.first = first; /* USERINFO BEGIN */
+		return URI_FUNC(ParseOwnHostUserInfoNz)(state, first, afterLast);
+
+	default:
+		/* "" regname host */
+		state->uri->hostText.first = URI_FUNC(SafeToPointTo);
+		state->uri->hostText.afterLast = URI_FUNC(SafeToPointTo);
+		return first;
+	}
+}
+
+
+
+/*
+ * [authorityTwo]-><:>[port]
+ * [authorityTwo]-><NULL>
+ */
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT(':'):
+		{
+			const URI_CHAR * const afterPort = URI_FUNC(ParsePort)(state, first + 1, afterLast);
+			if (afterPort == NULL) {
+				return NULL;
+			}
+			state->uri->portText.first = first + 1; /* PORT BEGIN */
+			state->uri->portText.afterLast = afterPort; /* PORT END */
+			return afterPort;
+		}
+
+	default:
+		return first;
+	}
+}
+
+
+
+/*
+ * [hexZero]->[HEXDIG][hexZero]
+ * [hexZero]-><NULL>
+ */
+static const URI_CHAR * URI_FUNC(ParseHexZero)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		return afterLast;
+	}
+
+	switch (*first) {
+	case URI_SET_HEXDIG:
+		return URI_FUNC(ParseHexZero)(state, first + 1, afterLast);
+
+	default:
+		return first;
+	}
+}
+
+
+
+/*
+ * [hierPart]->[pathRootless]
+ * [hierPart]-></>[partHelperTwo]
+ * [hierPart]-><NULL>
+ */
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseHierPart)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('%'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('-'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT('.'):
+	case _UT(':'):
+	case _UT(';'):
+	case _UT('@'):
+	case _UT('\''):
+	case _UT('_'):
+	case _UT('~'):
+	case _UT('+'):
+	case _UT('='):
+	case URI_SET_DIGIT:
+	case URI_SET_ALPHA:
+		return URI_FUNC(ParsePathRootless)(state, first, afterLast);
+
+	case _UT('/'):
+		return URI_FUNC(ParsePartHelperTwo)(state, first + 1, afterLast);
+
+	default:
+		return first;
+	}
+}
+
+
+
+/*
+ * [ipFutLoop]->[subDelims][ipFutStopGo]
+ * [ipFutLoop]->[unreserved][ipFutStopGo]
+ * [ipFutLoop]-><:>[ipFutStopGo]
+ */
+static const URI_CHAR * URI_FUNC(ParseIpFutLoop)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+
+	switch (*first) {
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('-'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT('.'):
+	case _UT(':'):
+	case _UT(';'):
+	case _UT('\''):
+	case _UT('_'):
+	case _UT('~'):
+	case _UT('+'):
+	case _UT('='):
+	case URI_SET_DIGIT:
+	case URI_SET_ALPHA:
+		return URI_FUNC(ParseIpFutStopGo)(state, first + 1, afterLast);
+
+	default:
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+}
+
+
+
+/*
+ * [ipFutStopGo]->[ipFutLoop]
+ * [ipFutStopGo]-><NULL>
+ */
+static const URI_CHAR * URI_FUNC(ParseIpFutStopGo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('-'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT('.'):
+	case _UT(':'):
+	case _UT(';'):
+	case _UT('\''):
+	case _UT('_'):
+	case _UT('~'):
+	case _UT('+'):
+	case _UT('='):
+	case URI_SET_DIGIT:
+	case URI_SET_ALPHA:
+		return URI_FUNC(ParseIpFutLoop)(state, first, afterLast);
+
+	default:
+		return first;
+	}
+}
+
+
+
+/*
+ * [ipFuture]-><v>[HEXDIG][hexZero]<.>[ipFutLoop]
+ */
+static const URI_CHAR * URI_FUNC(ParseIpFuture)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+
+	/*
+	First character has already been
+	checked before entering this rule.
+
+	switch (*first) {
+	case _UT('v'):
+	*/
+		if (first + 1 >= afterLast) {
+			URI_FUNC(StopSyntax)(state, first + 1);
+			return NULL;
+		}
+
+		switch (first[1]) {
+		case URI_SET_HEXDIG:
+			{
+				const URI_CHAR * afterIpFutLoop;
+				const URI_CHAR * const afterHexZero
+						= URI_FUNC(ParseHexZero)(state, first + 2, afterLast);
+				if (afterHexZero == NULL) {
+					return NULL;
+				}
+				if ((afterHexZero >= afterLast)
+						|| (*afterHexZero != _UT('.'))) {
+					URI_FUNC(StopSyntax)(state, afterHexZero);
+					return NULL;
+				}
+				state->uri->hostText.first = first; /* HOST BEGIN */
+				state->uri->hostData.ipFuture.first = first; /* IPFUTURE BEGIN */
+				afterIpFutLoop = URI_FUNC(ParseIpFutLoop)(state, afterHexZero + 1, afterLast);
+				if (afterIpFutLoop == NULL) {
+					return NULL;
+				}
+				state->uri->hostText.afterLast = afterIpFutLoop; /* HOST END */
+				state->uri->hostData.ipFuture.afterLast = afterIpFutLoop; /* IPFUTURE END */
+				return afterIpFutLoop;
+			}
+
+		default:
+			URI_FUNC(StopSyntax)(state, first + 1);
+			return NULL;
+		}
+
+	/*
+	default:
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+	*/
+}
+
+
+
+/*
+ * [ipLit2]->[ipFuture]<]>
+ * [ipLit2]->[IPv6address2]
+ */
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseIpLit2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+
+	switch (*first) {
+	case _UT('v'):
+		{
+			const URI_CHAR * const afterIpFuture
+					= URI_FUNC(ParseIpFuture)(state, first, afterLast);
+			if (afterIpFuture == NULL) {
+				return NULL;
+			}
+			if ((afterIpFuture >= afterLast)
+					|| (*afterIpFuture != _UT(']'))) {
+				URI_FUNC(StopSyntax)(state, first);
+				return NULL;
+			}
+			return afterIpFuture + 1;
+		}
+
+	case _UT(':'):
+	case _UT(']'):
+	case URI_SET_HEXDIG:
+		state->uri->hostData.ip6 = malloc(1 * sizeof(UriIp6)); /* Freed when stopping on parse error */
+		if (state->uri->hostData.ip6 == NULL) {
+			URI_FUNC(StopMalloc)(state);
+			return NULL;
+		}
+		return URI_FUNC(ParseIPv6address2)(state, first, afterLast);
+
+	default:
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+}
+
+
+
+/*
+ * [IPv6address2]->..<]>
+ */
+static const URI_CHAR * URI_FUNC(ParseIPv6address2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	int zipperEver = 0;
+	int quadsDone = 0;
+	int digitCount = 0;
+	unsigned char digitHistory[4];
+	int ip4OctetsDone = 0;
+
+	unsigned char quadsAfterZipper[14];
+	int quadsAfterZipperCount = 0;
+
+
+	for (;;) {
+		if (first >= afterLast) {
+			URI_FUNC(StopSyntax)(state, first);
+			return NULL;
+		}
+
+		/* Inside IPv4 part? */
+		if (ip4OctetsDone > 0) {
+			/* Eat rest of IPv4 address */
+			for (;;) {
+				switch (*first) {
+				case URI_SET_DIGIT:
+					if (digitCount == 4) {
+						URI_FUNC(StopSyntax)(state, first);
+						return NULL;
+					}
+					digitHistory[digitCount++] = (unsigned char)(9 + *first - _UT('9'));
+					break;
+
+				case _UT('.'):
+					if ((ip4OctetsDone == 4) /* NOTE! */
+							|| (digitCount == 0)
+							|| (digitCount == 4)) {
+						/* Invalid digit or octet count */
+						URI_FUNC(StopSyntax)(state, first);
+						return NULL;
+					} else if ((digitCount > 1)
+							&& (digitHistory[0] == 0)) {
+						/* Leading zero */
+						URI_FUNC(StopSyntax)(state, first - digitCount);
+						return NULL;
+					} else if ((digitCount > 2)
+							&& (digitHistory[1] == 0)) {
+						/* Leading zero */
+						URI_FUNC(StopSyntax)(state, first - digitCount + 1);
+						return NULL;
+					} else if ((digitCount == 3)
+							&& (100 * digitHistory[0]
+								+ 10 * digitHistory[1]
+								+ digitHistory[2] > 255)) {
+						/* Octet value too large */
+						if (digitHistory[0] > 2) {
+							URI_FUNC(StopSyntax)(state, first - 3);
+						} else if (digitHistory[1] > 5) {
+							URI_FUNC(StopSyntax)(state, first - 2);
+						} else {
+							URI_FUNC(StopSyntax)(state, first - 1);
+						}
+						return NULL;
+					}
+
+					/* Copy IPv4 octet */
+					state->uri->hostData.ip6->data[16 - 4 + ip4OctetsDone] = uriGetOctetValue(digitHistory, digitCount);
+					digitCount = 0;
+					ip4OctetsDone++;
+					break;
+
+				case _UT(']'):
+					if ((ip4OctetsDone != 3) /* NOTE! */
+							|| (digitCount == 0)
+							|| (digitCount == 4)) {
+						/* Invalid digit or octet count */
+						URI_FUNC(StopSyntax)(state, first);
+						return NULL;
+					} else if ((digitCount > 1)
+							&& (digitHistory[0] == 0)) {
+						/* Leading zero */
+						URI_FUNC(StopSyntax)(state, first - digitCount);
+						return NULL;
+					} else if ((digitCount > 2)
+							&& (digitHistory[1] == 0)) {
+						/* Leading zero */
+						URI_FUNC(StopSyntax)(state, first - digitCount + 1);
+						return NULL;
+					} else if ((digitCount == 3)
+							&& (100 * digitHistory[0]
+								+ 10 * digitHistory[1]
+								+ digitHistory[2] > 255)) {
+						/* Octet value too large */
+						if (digitHistory[0] > 2) {
+							URI_FUNC(StopSyntax)(state, first - 3);
+						} else if (digitHistory[1] > 5) {
+							URI_FUNC(StopSyntax)(state, first - 2);
+						} else {
+							URI_FUNC(StopSyntax)(state, first - 1);
+						}
+						return NULL;
+					}
+
+					state->uri->hostText.afterLast = first; /* HOST END */
+
+					/* Copy missing quads right before IPv4 */
+					memcpy(state->uri->hostData.ip6->data + 16 - 4 - 2 * quadsAfterZipperCount,
+								quadsAfterZipper, 2 * quadsAfterZipperCount);
+
+					/* Copy last IPv4 octet */
+					state->uri->hostData.ip6->data[16 - 4 + 3] = uriGetOctetValue(digitHistory, digitCount);
+
+					return first + 1;
+
+				default:
+					URI_FUNC(StopSyntax)(state, first);
+					return NULL;
+				}
+				first++;
+			}
+		} else {
+			/* Eat while no dot in sight */
+			int letterAmong = 0;
+			int walking = 1;
+			do {
+				switch (*first) {
+				case URI_SET_HEX_LETTER_LOWER:
+					letterAmong = 1;
+					if (digitCount == 4) {
+						URI_FUNC(StopSyntax)(state, first);
+						return NULL;
+					}
+					digitHistory[digitCount] = (unsigned char)(15 + *first - _UT('f'));
+					digitCount++;
+					break;
+
+				case URI_SET_HEX_LETTER_UPPER:
+					letterAmong = 1;
+					if (digitCount == 4) {
+						URI_FUNC(StopSyntax)(state, first);
+						return NULL;
+					}
+					digitHistory[digitCount] = (unsigned char)(15 + *first - _UT('F'));
+					digitCount++;
+					break;
+
+				case URI_SET_DIGIT:
+					if (digitCount == 4) {
+						URI_FUNC(StopSyntax)(state, first);
+						return NULL;
+					}
+					digitHistory[digitCount] = (unsigned char)(9 + *first - _UT('9'));
+					digitCount++;
+					break;
+
+				case _UT(':'):
+					{
+						int setZipper = 0;
+
+						/* Too many quads? */
+						if (quadsDone > 8 - zipperEver) {
+							URI_FUNC(StopSyntax)(state, first);
+							return NULL;
+						}
+
+						/* "::"? */
+						if (first + 1 >= afterLast) {
+							URI_FUNC(StopSyntax)(state, first + 1);
+							return NULL;
+						}
+						if (first[1] == _UT(':')) {
+							const int resetOffset = 2 * (quadsDone + (digitCount > 0));
+
+							first++;
+							if (zipperEver) {
+								URI_FUNC(StopSyntax)(state, first);
+								return NULL; /* "::.+::" */
+							}
+
+							/* Zero everything after zipper */
+							memset(state->uri->hostData.ip6->data + resetOffset, 0, 16 - resetOffset);
+							setZipper = 1;
+
+							/* ":::+"? */
+							if (first + 1 >= afterLast) {
+								URI_FUNC(StopSyntax)(state, first + 1);
+								return NULL; /* No ']' yet */
+							}
+							if (first[1] == _UT(':')) {
+								URI_FUNC(StopSyntax)(state, first + 1);
+								return NULL; /* ":::+ "*/
+							}
+						}
+						if (digitCount > 0) {
+							if (zipperEver) {
+								uriWriteQuadToDoubleByte(digitHistory, digitCount, quadsAfterZipper + 2 * quadsAfterZipperCount);
+								quadsAfterZipperCount++;
+							} else {
+								uriWriteQuadToDoubleByte(digitHistory, digitCount, state->uri->hostData.ip6->data + 2 * quadsDone);
+							}
+							quadsDone++;
+							digitCount = 0;
+						}
+						letterAmong = 0;
+
+						if (setZipper) {
+							zipperEver = 1;
+						}
+					}
+					break;
+
+				case _UT('.'):
+					if ((quadsDone > 6) /* NOTE */
+							|| (!zipperEver && (quadsDone < 6))
+							|| letterAmong
+							|| (digitCount == 0)
+							|| (digitCount == 4)) {
+						/* Invalid octet before */
+						URI_FUNC(StopSyntax)(state, first);
+						return NULL;
+					} else if ((digitCount > 1)
+							&& (digitHistory[0] == 0)) {
+						/* Leading zero */
+						URI_FUNC(StopSyntax)(state, first - digitCount);
+						return NULL;
+					} else if ((digitCount > 2)
+							&& (digitHistory[1] == 0)) {
+						/* Leading zero */
+						URI_FUNC(StopSyntax)(state, first - digitCount + 1);
+						return NULL;
+					} else if ((digitCount == 3)
+							&& (100 * digitHistory[0]
+								+ 10 * digitHistory[1]
+								+ digitHistory[2] > 255)) {
+						/* Octet value too large */
+						if (digitHistory[0] > 2) {
+							URI_FUNC(StopSyntax)(state, first - 3);
+						} else if (digitHistory[1] > 5) {
+							URI_FUNC(StopSyntax)(state, first - 2);
+						} else {
+							URI_FUNC(StopSyntax)(state, first - 1);
+						}
+						return NULL;
+					}
+
+					/* Copy first IPv4 octet */
+					state->uri->hostData.ip6->data[16 - 4] = uriGetOctetValue(digitHistory, digitCount);
+					digitCount = 0;
+
+					/* Switch over to IPv4 loop */
+					ip4OctetsDone = 1;
+					walking = 0;
+					break;
+
+				case _UT(']'):
+					/* Too little quads? */
+					if (!zipperEver && !((quadsDone == 7) && (digitCount > 0))) {
+						URI_FUNC(StopSyntax)(state, first);
+						return NULL;
+					}
+
+					if (digitCount > 0) {
+						if (zipperEver) {
+							uriWriteQuadToDoubleByte(digitHistory, digitCount, quadsAfterZipper + 2 * quadsAfterZipperCount);
+							quadsAfterZipperCount++;
+						} else {
+							uriWriteQuadToDoubleByte(digitHistory, digitCount, state->uri->hostData.ip6->data + 2 * quadsDone);
+						}
+						/*
+						quadsDone++;
+						digitCount = 0;
+						*/
+					}
+
+					/* Copy missing quads to the end */
+					memcpy(state->uri->hostData.ip6->data + 16 - 2 * quadsAfterZipperCount,
+								quadsAfterZipper, 2 * quadsAfterZipperCount);
+
+					state->uri->hostText.afterLast = first; /* HOST END */
+					return first + 1; /* Fine */
+
+				default:
+					URI_FUNC(StopSyntax)(state, first);
+					return NULL;
+				}
+				first++;
+
+				if (first >= afterLast) {
+					URI_FUNC(StopSyntax)(state, first);
+					return NULL; /* No ']' yet */
+				}
+			} while (walking);
+		}
+	}
+}
+
+
+
+/*
+ * [mustBeSegmentNzNc]->[pctEncoded][mustBeSegmentNzNc]
+ * [mustBeSegmentNzNc]->[subDelims][mustBeSegmentNzNc]
+ * [mustBeSegmentNzNc]->[unreserved][mustBeSegmentNzNc]
+ * [mustBeSegmentNzNc]->[uriTail] // can take <NULL>
+ * [mustBeSegmentNzNc]-></>[segment][zeroMoreSlashSegs][uriTail]
+ * [mustBeSegmentNzNc]-><@>[mustBeSegmentNzNc]
+ */
+static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first)) { /* SEGMENT BOTH */
+			URI_FUNC(StopMalloc)(state);
+			return NULL;
+		}
+		state->uri->scheme.first = NULL; /* Not a scheme, reset */
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('%'):
+		{
+			const URI_CHAR * const afterPctEncoded
+					= URI_FUNC(ParsePctEncoded)(state, first, afterLast);
+			if (afterPctEncoded == NULL) {
+				return NULL;
+			}
+			return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast);
+		}
+
+	case _UT('@'):
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT(';'):
+	case _UT('\''):
+	case _UT('+'):
+	case _UT('='):
+	case _UT('-'):
+	case _UT('.'):
+	case _UT('_'):
+	case _UT('~'):
+	case URI_SET_DIGIT:
+	case URI_SET_ALPHA:
+		return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast);
+
+	case _UT('/'):
+		{
+			const URI_CHAR * afterZeroMoreSlashSegs;
+			const URI_CHAR * afterSegment;
+			if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first)) { /* SEGMENT BOTH */
+				URI_FUNC(StopMalloc)(state);
+				return NULL;
+			}
+			state->uri->scheme.first = NULL; /* Not a scheme, reset */
+			afterSegment = URI_FUNC(ParseSegment)(state, first + 1, afterLast);
+			if (afterSegment == NULL) {
+				return NULL;
+			}
+			if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment)) { /* SEGMENT BOTH */
+				URI_FUNC(StopMalloc)(state);
+				return NULL;
+			}
+			afterZeroMoreSlashSegs
+					= URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast);
+			if (afterZeroMoreSlashSegs == NULL) {
+				return NULL;
+			}
+			return URI_FUNC(ParseUriTail)(state, afterZeroMoreSlashSegs, afterLast);
+		}
+
+	default:
+		if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first)) { /* SEGMENT BOTH */
+			URI_FUNC(StopMalloc)(state);
+			return NULL;
+		}
+		state->uri->scheme.first = NULL; /* Not a scheme, reset */
+		return URI_FUNC(ParseUriTail)(state, first, afterLast);
+	}
+}
+
+
+
+/*
+ * [ownHost]-><[>[ipLit2][authorityTwo]
+ * [ownHost]->[ownHost2] // can take <NULL>
+ */
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseOwnHost)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('['):
+		{
+			const URI_CHAR * const afterIpLit2
+					= URI_FUNC(ParseIpLit2)(state, first + 1, afterLast);
+			if (afterIpLit2 == NULL) {
+				return NULL;
+			}
+			state->uri->hostText.first = first + 1; /* HOST BEGIN */
+			return URI_FUNC(ParseAuthorityTwo)(state, afterIpLit2, afterLast);
+		}
+
+	default:
+		return URI_FUNC(ParseOwnHost2)(state, first, afterLast);
+	}
+}
+
+
+
+static URI_INLINE UriBool URI_FUNC(OnExitOwnHost2)(URI_TYPE(ParserState) * state, const URI_CHAR * first) {
+	state->uri->hostText.afterLast = first; /* HOST END */
+
+	/* Valid IPv4 or just a regname? */
+	state->uri->hostData.ip4 = malloc(1 * sizeof(UriIp4)); /* Freed when stopping on parse error */
+	if (state->uri->hostData.ip4 == NULL) {
+		return URI_FALSE; /* Raises malloc error */
+	}
+	if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data,
+			state->uri->hostText.first, state->uri->hostText.afterLast)) {
+		/* Not IPv4 */
+		free(state->uri->hostData.ip4);
+		state->uri->hostData.ip4 = NULL;
+	}
+	return URI_TRUE; /* Success */
+}
+
+
+
+/*
+ * [ownHost2]->[authorityTwo] // can take <NULL>
+ * [ownHost2]->[pctSubUnres][ownHost2]
+ */
+static const URI_CHAR * URI_FUNC(ParseOwnHost2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		if (!URI_FUNC(OnExitOwnHost2)(state, first)) {
+			URI_FUNC(StopMalloc)(state);
+			return NULL;
+		}
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('%'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('-'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT('.'):
+	case _UT(';'):
+	case _UT('\''):
+	case _UT('_'):
+	case _UT('~'):
+	case _UT('+'):
+	case _UT('='):
+	case URI_SET_DIGIT:
+	case URI_SET_ALPHA:
+		{
+			const URI_CHAR * const afterPctSubUnres
+					= URI_FUNC(ParsePctSubUnres)(state, first, afterLast);
+			if (afterPctSubUnres == NULL) {
+				return NULL;
+			}
+			return URI_FUNC(ParseOwnHost2)(state, afterPctSubUnres, afterLast);
+		}
+
+	default:
+		if (!URI_FUNC(OnExitOwnHost2)(state, first)) {
+			URI_FUNC(StopMalloc)(state);
+			return NULL;
+		}
+		return URI_FUNC(ParseAuthorityTwo)(state, first, afterLast);
+	}
+}
+
+
+
+static URI_INLINE UriBool URI_FUNC(OnExitOwnHostUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first) {
+	state->uri->hostText.first = state->uri->userInfo.first; /* Host instead of userInfo, update */
+	state->uri->userInfo.first = NULL; /* Not a userInfo, reset */
+	state->uri->hostText.afterLast = first; /* HOST END */
+
+	/* Valid IPv4 or just a regname? */
+	state->uri->hostData.ip4 = malloc(1 * sizeof(UriIp4)); /* Freed when stopping on parse error */
+	if (state->uri->hostData.ip4 == NULL) {
+		return URI_FALSE; /* Raises malloc error */
+	}
+	if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data,
+			state->uri->hostText.first, state->uri->hostText.afterLast)) {
+		/* Not IPv4 */
+		free(state->uri->hostData.ip4);
+		state->uri->hostData.ip4 = NULL;
+	}
+	return URI_TRUE; /* Success */
+}
+
+
+
+/*
+ * [ownHostUserInfo]->[ownHostUserInfoNz]
+ * [ownHostUserInfo]-><NULL>
+ */
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseOwnHostUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		if (!URI_FUNC(OnExitOwnHostUserInfo)(state, first)) {
+			URI_FUNC(StopMalloc)(state);
+			return NULL;
+		}
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('%'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('-'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT('.'):
+	case _UT(':'):
+	case _UT(';'):
+	case _UT('@'):
+	case _UT('\''):
+	case _UT('_'):
+	case _UT('~'):
+	case _UT('+'):
+	case _UT('='):
+	case URI_SET_DIGIT:
+	case URI_SET_ALPHA:
+		return URI_FUNC(ParseOwnHostUserInfoNz)(state, first, afterLast);
+
+	default:
+		if (!URI_FUNC(OnExitOwnHostUserInfo)(state, first)) {
+			URI_FUNC(StopMalloc)(state);
+			return NULL;
+		}
+		return first;
+	}
+}
+
+
+
+/*
+ * [ownHostUserInfoNz]->[pctSubUnres][ownHostUserInfo]
+ * [ownHostUserInfoNz]-><:>[ownPortUserInfo]
+ * [ownHostUserInfoNz]-><@>[ownHost]
+ */
+static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfoNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+
+	switch (*first) {
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('%'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('-'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT('.'):
+	case _UT(';'):
+	case _UT('\''):
+	case _UT('_'):
+	case _UT('~'):
+	case _UT('+'):
+	case _UT('='):
+	case URI_SET_DIGIT:
+	case URI_SET_ALPHA:
+		{
+			const URI_CHAR * const afterPctSubUnres
+					= URI_FUNC(ParsePctSubUnres)(state, first, afterLast);
+			if (afterPctSubUnres == NULL) {
+				return NULL;
+			}
+			return URI_FUNC(ParseOwnHostUserInfo)(state, afterPctSubUnres, afterLast);
+		}
+
+	case _UT(':'):
+		state->uri->hostText.afterLast = first; /* HOST END */
+		state->uri->portText.first = first + 1; /* PORT BEGIN */
+		return URI_FUNC(ParseOwnPortUserInfo)(state, first + 1, afterLast);
+
+	case _UT('@'):
+		state->uri->userInfo.afterLast = first; /* USERINFO END */
+		state->uri->hostText.first = first + 1; /* HOST BEGIN */
+		return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast);
+
+	default:
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+}
+
+
+
+static URI_INLINE UriBool URI_FUNC(OnExitOwnPortUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first) {
+	state->uri->hostText.first = state->uri->userInfo.first; /* Host instead of userInfo, update */
+	state->uri->userInfo.first = NULL; /* Not a userInfo, reset */
+	state->uri->portText.afterLast = first; /* PORT END */
+
+	/* Valid IPv4 or just a regname? */
+	state->uri->hostData.ip4 = malloc(1 * sizeof(UriIp4)); /* Freed when stopping on parse error */
+	if (state->uri->hostData.ip4 == NULL) {
+		return URI_FALSE; /* Raises malloc error */
+	}
+	if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data,
+			state->uri->hostText.first, state->uri->hostText.afterLast)) {
+		/* Not IPv4 */
+		free(state->uri->hostData.ip4);
+		state->uri->hostData.ip4 = NULL;
+	}
+	return URI_TRUE; /* Success */
+}
+
+
+
+/*
+ * [ownPortUserInfo]->[ALPHA][ownUserInfo]
+ * [ownPortUserInfo]->[DIGIT][ownPortUserInfo]
+ * [ownPortUserInfo]-><.>[ownUserInfo]
+ * [ownPortUserInfo]-><_>[ownUserInfo]
+ * [ownPortUserInfo]-><~>[ownUserInfo]
+ * [ownPortUserInfo]-><->[ownUserInfo]
+ * [ownPortUserInfo]-><@>[ownHost]
+ * [ownPortUserInfo]-><NULL>
+ */
+static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		if (!URI_FUNC(OnExitOwnPortUserInfo)(state, first)) {
+			URI_FUNC(StopMalloc)(state);
+			return NULL;
+		}
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('.'):
+	case _UT('_'):
+	case _UT('~'):
+	case _UT('-'):
+	case URI_SET_ALPHA:
+		state->uri->hostText.afterLast = NULL; /* Not a host, reset */
+		state->uri->portText.first = NULL; /* Not a port, reset */
+		return URI_FUNC(ParseOwnUserInfo)(state, first + 1, afterLast);
+
+	case URI_SET_DIGIT:
+		return URI_FUNC(ParseOwnPortUserInfo)(state, first + 1, afterLast);
+
+	case _UT('@'):
+		state->uri->hostText.afterLast = NULL; /* Not a host, reset */
+		state->uri->portText.first = NULL; /* Not a port, reset */
+		state->uri->userInfo.afterLast = first; /* USERINFO END */
+		state->uri->hostText.first = first + 1; /* HOST BEGIN */
+		return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast);
+
+	default:
+		if (!URI_FUNC(OnExitOwnPortUserInfo)(state, first)) {
+			URI_FUNC(StopMalloc)(state);
+			return NULL;
+		}
+		return first;
+	}
+}
+
+
+
+/*
+ * [ownUserInfo]->[pctSubUnres][ownUserInfo]
+ * [ownUserInfo]-><:>[ownUserInfo]
+ * [ownUserInfo]-><@>[ownHost]
+ */
+static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+
+	switch (*first) {
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('%'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('-'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT('.'):
+	case _UT(';'):
+	case _UT('\''):
+	case _UT('_'):
+	case _UT('~'):
+	case _UT('+'):
+	case _UT('='):
+	case URI_SET_DIGIT:
+	case URI_SET_ALPHA:
+		{
+			const URI_CHAR * const afterPctSubUnres
+					= URI_FUNC(ParsePctSubUnres)(state, first, afterLast);
+			if (afterPctSubUnres == NULL) {
+				return NULL;
+			}
+			return URI_FUNC(ParseOwnUserInfo)(state, afterPctSubUnres, afterLast);
+		}
+
+	case _UT(':'):
+		return URI_FUNC(ParseOwnUserInfo)(state, first + 1, afterLast);
+
+	case _UT('@'):
+		/* SURE */
+		state->uri->userInfo.afterLast = first; /* USERINFO END */
+		state->uri->hostText.first = first + 1; /* HOST BEGIN */
+		return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast);
+
+	default:
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+}
+
+
+
+static URI_INLINE void URI_FUNC(OnExitPartHelperTwo)(URI_TYPE(ParserState) * state) {
+	state->uri->absolutePath = URI_TRUE;
+}
+
+
+
+/*
+ * [partHelperTwo]->[pathAbsNoLeadSlash] // can take <NULL>
+ * [partHelperTwo]-></>[authority][pathAbsEmpty]
+ */
+static URI_INLINE const URI_CHAR * URI_FUNC(ParsePartHelperTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		URI_FUNC(OnExitPartHelperTwo)(state);
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('/'):
+		{
+			const URI_CHAR * const afterAuthority
+					= URI_FUNC(ParseAuthority)(state, first + 1, afterLast);
+			const URI_CHAR * afterPathAbsEmpty;
+			if (afterAuthority == NULL) {
+				return NULL;
+			}
+			afterPathAbsEmpty = URI_FUNC(ParsePathAbsEmpty)(state, afterAuthority, afterLast);
+
+			URI_FUNC(FixEmptyTrailSegment)(state->uri);
+
+			return afterPathAbsEmpty;
+		}
+
+	default:
+		URI_FUNC(OnExitPartHelperTwo)(state);
+		return URI_FUNC(ParsePathAbsNoLeadSlash)(state, first, afterLast);
+	}
+}
+
+
+
+/*
+ * [pathAbsEmpty]-></>[segment][pathAbsEmpty]
+ * [pathAbsEmpty]-><NULL>
+ */
+static const URI_CHAR * URI_FUNC(ParsePathAbsEmpty)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('/'):
+		{
+			const URI_CHAR * const afterSegment
+					= URI_FUNC(ParseSegment)(state, first + 1, afterLast);
+			if (afterSegment == NULL) {
+				return NULL;
+			}
+			if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment)) { /* SEGMENT BOTH */
+				URI_FUNC(StopMalloc)(state);
+				return NULL;
+			}
+			return URI_FUNC(ParsePathAbsEmpty)(state, afterSegment, afterLast);
+		}
+
+	default:
+		return first;
+	}
+}
+
+
+
+/*
+ * [pathAbsNoLeadSlash]->[segmentNz][zeroMoreSlashSegs]
+ * [pathAbsNoLeadSlash]-><NULL>
+ */
+static URI_INLINE const URI_CHAR * URI_FUNC(ParsePathAbsNoLeadSlash)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('%'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('-'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT('.'):
+	case _UT(':'):
+	case _UT(';'):
+	case _UT('@'):
+	case _UT('\''):
+	case _UT('_'):
+	case _UT('~'):
+	case _UT('+'):
+	case _UT('='):
+	case URI_SET_DIGIT:
+	case URI_SET_ALPHA:
+		{
+			const URI_CHAR * const afterSegmentNz
+					= URI_FUNC(ParseSegmentNz)(state, first, afterLast);
+			if (afterSegmentNz == NULL) {
+				return NULL;
+			}
+			if (!URI_FUNC(PushPathSegment)(state, first, afterSegmentNz)) { /* SEGMENT BOTH */
+				URI_FUNC(StopMalloc)(state);
+				return NULL;
+			}
+			return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegmentNz, afterLast);
+		}
+
+	default:
+		return first;
+	}
+}
+
+
+
+/*
+ * [pathRootless]->[segmentNz][zeroMoreSlashSegs]
+ */
+static URI_INLINE const URI_CHAR * URI_FUNC(ParsePathRootless)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	const URI_CHAR * const afterSegmentNz
+			= URI_FUNC(ParseSegmentNz)(state, first, afterLast);
+	if (afterSegmentNz == NULL) {
+		return NULL;
+	} else {
+		if (!URI_FUNC(PushPathSegment)(state, first, afterSegmentNz)) { /* SEGMENT BOTH */
+			URI_FUNC(StopMalloc)(state);
+			return NULL;
+		}
+	}
+	return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegmentNz, afterLast);
+}
+
+
+
+/*
+ * [pchar]->[pctEncoded]
+ * [pchar]->[subDelims]
+ * [pchar]->[unreserved]
+ * [pchar]-><:>
+ * [pchar]-><@>
+ */
+static const URI_CHAR * URI_FUNC(ParsePchar)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+
+	switch (*first) {
+	case _UT('%'):
+		return URI_FUNC(ParsePctEncoded)(state, first, afterLast);
+
+	case _UT(':'):
+	case _UT('@'):
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT(';'):
+	case _UT('\''):
+	case _UT('+'):
+	case _UT('='):
+	case _UT('-'):
+	case _UT('.'):
+	case _UT('_'):
+	case _UT('~'):
+	case URI_SET_DIGIT:
+	case URI_SET_ALPHA:
+		return first + 1;
+
+	default:
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+}
+
+
+
+/*
+ * [pctEncoded]-><%>[HEXDIG][HEXDIG]
+ */
+static const URI_CHAR * URI_FUNC(ParsePctEncoded)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+
+	/*
+	First character has already been
+	checked before entering this rule.
+
+	switch (*first) {
+	case _UT('%'):
+	*/
+		if (first + 1 >= afterLast) {
+			URI_FUNC(StopSyntax)(state, first + 1);
+			return NULL;
+		}
+
+		switch (first[1]) {
+		case URI_SET_HEXDIG:
+			if (first + 2 >= afterLast) {
+				URI_FUNC(StopSyntax)(state, first + 2);
+				return NULL;
+			}
+
+			switch (first[2]) {
+			case URI_SET_HEXDIG:
+				return first + 3;
+
+			default:
+				URI_FUNC(StopSyntax)(state, first + 2);
+				return NULL;
+			}
+
+		default:
+			URI_FUNC(StopSyntax)(state, first + 1);
+			return NULL;
+		}
+
+	/*
+	default:
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+	*/
+}
+
+
+
+/*
+ * [pctSubUnres]->[pctEncoded]
+ * [pctSubUnres]->[subDelims]
+ * [pctSubUnres]->[unreserved]
+ */
+static const URI_CHAR * URI_FUNC(ParsePctSubUnres)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+
+	switch (*first) {
+	case _UT('%'):
+		return URI_FUNC(ParsePctEncoded)(state, first, afterLast);
+
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT(';'):
+	case _UT('\''):
+	case _UT('+'):
+	case _UT('='):
+	case _UT('-'):
+	case _UT('.'):
+	case _UT('_'):
+	case _UT('~'):
+	case URI_SET_DIGIT:
+	case URI_SET_ALPHA:
+		return first + 1;
+
+	default:
+		URI_FUNC(StopSyntax)(state, first);
+		return NULL;
+	}
+}
+
+
+
+/*
+ * [port]->[DIGIT][port]
+ * [port]-><NULL>
+ */
+static const URI_CHAR * URI_FUNC(ParsePort)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		return afterLast;
+	}
+
+	switch (*first) {
+	case URI_SET_DIGIT:
+		return URI_FUNC(ParsePort)(state, first + 1, afterLast);
+
+	default:
+		return first;
+	}
+}
+
+
+
+/*
+ * [queryFrag]->[pchar][queryFrag]
+ * [queryFrag]-></>[queryFrag]
+ * [queryFrag]-><?>[queryFrag]
+ * [queryFrag]-><NULL>
+ */
+static const URI_CHAR * URI_FUNC(ParseQueryFrag)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('%'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('-'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT('.'):
+	case _UT(':'):
+	case _UT(';'):
+	case _UT('@'):
+	case _UT('\''):
+	case _UT('_'):
+	case _UT('~'):
+	case _UT('+'):
+	case _UT('='):
+	case URI_SET_DIGIT:
+	case URI_SET_ALPHA:
+		{
+			const URI_CHAR * const afterPchar
+					= URI_FUNC(ParsePchar)(state, first, afterLast);
+			if (afterPchar == NULL) {
+				return NULL;
+			}
+			return URI_FUNC(ParseQueryFrag)(state, afterPchar, afterLast);
+		}
+
+	case _UT('/'):
+	case _UT('?'):
+		return URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast);
+
+	default:
+		return first;
+	}
+}
+
+
+
+/*
+ * [segment]->[pchar][segment]
+ * [segment]-><NULL>
+ */
+static const URI_CHAR * URI_FUNC(ParseSegment)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('%'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('-'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT('.'):
+	case _UT(':'):
+	case _UT(';'):
+	case _UT('@'):
+	case _UT('\''):
+	case _UT('_'):
+	case _UT('~'):
+	case _UT('+'):
+	case _UT('='):
+	case URI_SET_DIGIT:
+	case URI_SET_ALPHA:
+		{
+			const URI_CHAR * const afterPchar
+					= URI_FUNC(ParsePchar)(state, first, afterLast);
+			if (afterPchar == NULL) {
+				return NULL;
+			}
+			return URI_FUNC(ParseSegment)(state, afterPchar, afterLast);
+		}
+
+	default:
+		return first;
+	}
+}
+
+
+
+/*
+ * [segmentNz]->[pchar][segment]
+ */
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseSegmentNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	const URI_CHAR * const afterPchar
+			= URI_FUNC(ParsePchar)(state, first, afterLast);
+	if (afterPchar == NULL) {
+		return NULL;
+	}
+	return URI_FUNC(ParseSegment)(state, afterPchar, afterLast);
+}
+
+
+
+static URI_INLINE UriBool URI_FUNC(OnExitSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, const URI_CHAR * first) {
+	if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first)) { /* SEGMENT BOTH */
+		return URI_FALSE; /* Raises malloc error*/
+	}
+	state->uri->scheme.first = NULL; /* Not a scheme, reset */
+	return URI_TRUE; /* Success */
+}
+
+
+
+/*
+ * [segmentNzNcOrScheme2]->[ALPHA][segmentNzNcOrScheme2]
+ * [segmentNzNcOrScheme2]->[DIGIT][segmentNzNcOrScheme2]
+ * [segmentNzNcOrScheme2]->[pctEncoded][mustBeSegmentNzNc]
+ * [segmentNzNcOrScheme2]->[uriTail] // can take <NULL>
+ * [segmentNzNcOrScheme2]-><!>[mustBeSegmentNzNc]
+ * [segmentNzNcOrScheme2]-><$>[mustBeSegmentNzNc]
+ * [segmentNzNcOrScheme2]-><&>[mustBeSegmentNzNc]
+ * [segmentNzNcOrScheme2]-><(>[mustBeSegmentNzNc]
+ * [segmentNzNcOrScheme2]-><)>[mustBeSegmentNzNc]
+ * [segmentNzNcOrScheme2]-><*>[mustBeSegmentNzNc]
+ * [segmentNzNcOrScheme2]-><,>[mustBeSegmentNzNc]
+ * [segmentNzNcOrScheme2]-><.>[segmentNzNcOrScheme2]
+ * [segmentNzNcOrScheme2]-></>[segment][zeroMoreSlashSegs][uriTail]
+ * [segmentNzNcOrScheme2]-><:>[hierPart][uriTail]
+ * [segmentNzNcOrScheme2]-><;>[mustBeSegmentNzNc]
+ * [segmentNzNcOrScheme2]-><@>[mustBeSegmentNzNc]
+ * [segmentNzNcOrScheme2]-><_>[mustBeSegmentNzNc]
+ * [segmentNzNcOrScheme2]-><~>[mustBeSegmentNzNc]
+ * [segmentNzNcOrScheme2]-><+>[segmentNzNcOrScheme2]
+ * [segmentNzNcOrScheme2]-><=>[mustBeSegmentNzNc]
+ * [segmentNzNcOrScheme2]-><'>[mustBeSegmentNzNc]
+ * [segmentNzNcOrScheme2]-><->[segmentNzNcOrScheme2]
+ */
+static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		if (!URI_FUNC(OnExitSegmentNzNcOrScheme2)(state, first)) {
+			URI_FUNC(StopMalloc)(state);
+			return NULL;
+		}
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('.'):
+	case _UT('+'):
+	case _UT('-'):
+	case URI_SET_ALPHA:
+	case URI_SET_DIGIT:
+		return URI_FUNC(ParseSegmentNzNcOrScheme2)(state, first + 1, afterLast);
+
+	case _UT('%'):
+		{
+			const URI_CHAR * const afterPctEncoded
+					= URI_FUNC(ParsePctEncoded)(state, first, afterLast);
+			if (afterPctEncoded == NULL) {
+				return NULL;
+			}
+			return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast);
+		}
+
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT(';'):
+	case _UT('@'):
+	case _UT('_'):
+	case _UT('~'):
+	case _UT('='):
+	case _UT('\''):
+		return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast);
+
+	case _UT('/'):
+		{
+			const URI_CHAR * afterZeroMoreSlashSegs;
+			const URI_CHAR * const afterSegment
+					= URI_FUNC(ParseSegment)(state, first + 1, afterLast);
+			if (afterSegment == NULL) {
+				return NULL;
+			}
+			if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first)) { /* SEGMENT BOTH */
+				URI_FUNC(StopMalloc)(state);
+				return NULL;
+			}
+			state->uri->scheme.first = NULL; /* Not a scheme, reset */
+			if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment)) { /* SEGMENT BOTH */
+				URI_FUNC(StopMalloc)(state);
+				return NULL;
+			}
+			afterZeroMoreSlashSegs
+					= URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast);
+			if (afterZeroMoreSlashSegs == NULL) {
+				return NULL;
+			}
+			return URI_FUNC(ParseUriTail)(state, afterZeroMoreSlashSegs, afterLast);
+		}
+
+	case _UT(':'):
+		{
+			const URI_CHAR * const afterHierPart
+					= URI_FUNC(ParseHierPart)(state, first + 1, afterLast);
+			state->uri->scheme.afterLast = first; /* SCHEME END */
+			if (afterHierPart == NULL) {
+				return NULL;
+			}
+			return URI_FUNC(ParseUriTail)(state, afterHierPart, afterLast);
+		}
+
+	default:
+		if (!URI_FUNC(OnExitSegmentNzNcOrScheme2)(state, first)) {
+			URI_FUNC(StopMalloc)(state);
+			return NULL;
+		}
+		return URI_FUNC(ParseUriTail)(state, first, afterLast);
+	}
+}
+
+
+
+/*
+ * [uriReference]->[ALPHA][segmentNzNcOrScheme2]
+ * [uriReference]->[DIGIT][mustBeSegmentNzNc]
+ * [uriReference]->[pctEncoded][mustBeSegmentNzNc]
+ * [uriReference]->[subDelims][mustBeSegmentNzNc]
+ * [uriReference]->[uriTail] // can take <NULL>
+ * [uriReference]-><.>[mustBeSegmentNzNc]
+ * [uriReference]-></>[partHelperTwo][uriTail]
+ * [uriReference]-><@>[mustBeSegmentNzNc]
+ * [uriReference]-><_>[mustBeSegmentNzNc]
+ * [uriReference]-><~>[mustBeSegmentNzNc]
+ * [uriReference]-><->[mustBeSegmentNzNc]
+ */
+static const URI_CHAR * URI_FUNC(ParseUriReference)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		return afterLast;
+	}
+
+	switch (*first) {
+	case URI_SET_ALPHA:
+		state->uri->scheme.first = first; /* SCHEME BEGIN */
+		return URI_FUNC(ParseSegmentNzNcOrScheme2)(state, first + 1, afterLast);
+
+	case URI_SET_DIGIT:
+	case _UT('!'):
+	case _UT('$'):
+	case _UT('&'):
+	case _UT('('):
+	case _UT(')'):
+	case _UT('*'):
+	case _UT(','):
+	case _UT(';'):
+	case _UT('\''):
+	case _UT('+'):
+	case _UT('='):
+	case _UT('.'):
+	case _UT('_'):
+	case _UT('~'):
+	case _UT('-'):
+	case _UT('@'):
+		state->uri->scheme.first = first; /* SEGMENT BEGIN, ABUSE SCHEME POINTER */
+		return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast);
+
+	case _UT('%'):
+		{
+			const URI_CHAR * const afterPctEncoded
+					= URI_FUNC(ParsePctEncoded)(state, first, afterLast);
+			if (afterPctEncoded == NULL) {
+				return NULL;
+			}
+			state->uri->scheme.first = first; /* SEGMENT BEGIN, ABUSE SCHEME POINTER */
+			return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast);
+		}
+
+	case _UT('/'):
+		{
+			const URI_CHAR * const afterPartHelperTwo
+					= URI_FUNC(ParsePartHelperTwo)(state, first + 1, afterLast);
+			if (afterPartHelperTwo == NULL) {
+				return NULL;
+			}
+			return URI_FUNC(ParseUriTail)(state, afterPartHelperTwo, afterLast);
+		}
+
+	default:
+		return URI_FUNC(ParseUriTail)(state, first, afterLast);
+	}
+}
+
+
+
+/*
+ * [uriTail]-><#>[queryFrag]
+ * [uriTail]-><?>[queryFrag][uriTailTwo]
+ * [uriTail]-><NULL>
+ */
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseUriTail)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('#'):
+		{
+			const URI_CHAR * const afterQueryFrag = URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast);
+			if (afterQueryFrag == NULL) {
+				return NULL;
+			}
+			state->uri->fragment.first = first + 1; /* FRAGMENT BEGIN */
+			state->uri->fragment.afterLast = afterQueryFrag; /* FRAGMENT END */
+			return afterQueryFrag;
+		}
+
+	case _UT('?'):
+		{
+			const URI_CHAR * const afterQueryFrag
+					= URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast);
+			if (afterQueryFrag == NULL) {
+				return NULL;
+			}
+			state->uri->query.first = first + 1; /* QUERY BEGIN */
+			state->uri->query.afterLast = afterQueryFrag; /* QUERY END */
+			return URI_FUNC(ParseUriTailTwo)(state, afterQueryFrag, afterLast);
+		}
+
+	default:
+		return first;
+	}
+}
+
+
+
+/*
+ * [uriTailTwo]-><#>[queryFrag]
+ * [uriTailTwo]-><NULL>
+ */
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseUriTailTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('#'):
+		{
+			const URI_CHAR * const afterQueryFrag = URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast);
+			if (afterQueryFrag == NULL) {
+				return NULL;
+			}
+			state->uri->fragment.first = first + 1; /* FRAGMENT BEGIN */
+			state->uri->fragment.afterLast = afterQueryFrag; /* FRAGMENT END */
+			return afterQueryFrag;
+		}
+
+	default:
+		return first;
+	}
+}
+
+
+
+/*
+ * [zeroMoreSlashSegs]-></>[segment][zeroMoreSlashSegs]
+ * [zeroMoreSlashSegs]-><NULL>
+ */
+static const URI_CHAR * URI_FUNC(ParseZeroMoreSlashSegs)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	if (first >= afterLast) {
+		return afterLast;
+	}
+
+	switch (*first) {
+	case _UT('/'):
+		{
+			const URI_CHAR * const afterSegment
+					= URI_FUNC(ParseSegment)(state, first + 1, afterLast);
+			if (afterSegment == NULL) {
+				return NULL;
+			}
+			if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment)) { /* SEGMENT BOTH */
+				URI_FUNC(StopMalloc)(state);
+				return NULL;
+			}
+			return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast);
+		}
+
+	default:
+		return first;
+	}
+}
+
+
+
+static URI_INLINE void URI_FUNC(ResetParserState)(URI_TYPE(ParserState) * state) {
+	URI_TYPE(Uri) * const uriBackup = state->uri;
+	memset(state, 0, sizeof(URI_TYPE(ParserState)));
+	state->uri = uriBackup;
+}
+
+
+
+static URI_INLINE UriBool URI_FUNC(PushPathSegment)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	URI_TYPE(PathSegment) * segment = malloc(1 * sizeof(URI_TYPE(PathSegment)));
+	if (segment == NULL) {
+		return URI_FALSE; /* Raises malloc error */
+	}
+	memset(segment, 0, sizeof(URI_TYPE(PathSegment)));
+	if (first == afterLast) {
+		segment->text.first = URI_FUNC(SafeToPointTo);
+		segment->text.afterLast = URI_FUNC(SafeToPointTo);
+	} else {
+		segment->text.first = first;
+		segment->text.afterLast = afterLast;
+	}
+
+	/* First segment ever? */
+	if (state->uri->pathHead == NULL) {
+		/* First segement ever, set head and tail */
+		state->uri->pathHead = segment;
+		state->uri->pathTail = segment;
+	} else {
+		/* Append, update tail */
+		state->uri->pathTail->next = segment;
+		state->uri->pathTail = segment;
+	}
+
+	return URI_TRUE; /* Success */
+}
+
+
+
+int URI_FUNC(ParseUriEx)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+	const URI_CHAR * afterUriReference;
+	URI_TYPE(Uri) * uri;
+
+	/* Check params */
+	if ((state == NULL) || (first == NULL) || (afterLast == NULL)) {
+		return URI_ERROR_NULL;
+	}
+	uri = state->uri;
+
+	/* Init parser */
+	URI_FUNC(ResetParserState)(state);
+	URI_FUNC(ResetUri)(uri);
+
+	/* Parse */
+	afterUriReference = URI_FUNC(ParseUriReference)(state, first, afterLast);
+	if (afterUriReference == NULL) {
+		return state->errorCode;
+	}
+	if (afterUriReference != afterLast) {
+		return URI_ERROR_SYNTAX;
+	}
+	return URI_SUCCESS;
+}
+
+
+
+int URI_FUNC(ParseUri)(URI_TYPE(ParserState) * state, const URI_CHAR * text) {
+	if ((state == NULL) || (text == NULL)) {
+		return URI_ERROR_NULL;
+	}
+	return URI_FUNC(ParseUriEx)(state, text, text + URI_STRLEN(text));
+}
+
+
+
+void URI_FUNC(FreeUriMembers)(URI_TYPE(Uri) * uri) {
+	if (uri == NULL) {
+		return;
+	}
+
+	if (uri->owner) {
+		/* Scheme */
+		if (uri->scheme.first != NULL) {
+			if (uri->scheme.first != uri->scheme.afterLast) {
+				free((URI_CHAR *)uri->scheme.first);
+			}
+			uri->scheme.first = NULL;
+			uri->scheme.afterLast = NULL;
+		}
+
+		/* User info */
+		if (uri->userInfo.first != NULL) {
+			if (uri->userInfo.first != uri->userInfo.afterLast) {
+				free((URI_CHAR *)uri->userInfo.first);
+			}
+			uri->userInfo.first = NULL;
+			uri->userInfo.afterLast = NULL;
+		}
+
+		/* Host data - IPvFuture */
+		if (uri->hostData.ipFuture.first != NULL) {
+			if (uri->hostData.ipFuture.first != uri->hostData.ipFuture.afterLast) {
+				free((URI_CHAR *)uri->hostData.ipFuture.first);
+			}
+			uri->hostData.ipFuture.first = NULL;
+			uri->hostData.ipFuture.afterLast = NULL;
+			uri->hostText.first = NULL;
+			uri->hostText.afterLast = NULL;
+		}
+
+		/* Host text (if regname, after IPvFuture!) */
+		if ((uri->hostText.first != NULL)
+				&& (uri->hostData.ip4 == NULL)
+				&& (uri->hostData.ip6 == NULL)) {
+			/* Real regname */
+			if (uri->hostText.first != uri->hostText.afterLast) {
+				free((URI_CHAR *)uri->hostText.first);
+			}
+			uri->hostText.first = NULL;
+			uri->hostText.afterLast = NULL;
+		}
+	}
+
+	/* Host data - IPv4 */
+	if (uri->hostData.ip4 != NULL) {
+		free(uri->hostData.ip4);
+		uri->hostData.ip4 = NULL;
+	}
+
+	/* Host data - IPv6 */
+	if (uri->hostData.ip6 != NULL) {
+		free(uri->hostData.ip6);
+		uri->hostData.ip6 = NULL;
+	}
+
+	/* Port text */
+	if (uri->owner && (uri->portText.first != NULL)) {
+		if (uri->portText.first != uri->portText.afterLast) {
+			free((URI_CHAR *)uri->portText.first);
+		}
+		uri->portText.first = NULL;
+		uri->portText.afterLast = NULL;
+	}
+
+	/* Path */
+	if (uri->pathHead != NULL) {
+		URI_TYPE(PathSegment) * segWalk = uri->pathHead;
+		while (segWalk != NULL) {
+			URI_TYPE(PathSegment) * const next = segWalk->next;
+			if (uri->owner && (segWalk->text.first != NULL)
+					&& (segWalk->text.first < segWalk->text.afterLast)) {
+				free((URI_CHAR *)segWalk->text.first);
+			}
+			free(segWalk);
+			segWalk = next;
+		}
+		uri->pathHead = NULL;
+		uri->pathTail = NULL;
+	}
+
+	if (uri->owner) {
+		/* Query */
+		if (uri->query.first != NULL) {
+			if (uri->query.first != uri->query.afterLast) {
+				free((URI_CHAR *)uri->query.first);
+			}
+			uri->query.first = NULL;
+			uri->query.afterLast = NULL;
+		}
+
+		/* Fragment */
+		if (uri->fragment.first != NULL) {
+			if (uri->fragment.first != uri->fragment.afterLast) {
+				free((URI_CHAR *)uri->fragment.first);
+			}
+			uri->fragment.first = NULL;
+			uri->fragment.afterLast = NULL;
+		}
+	}
+}
+
+
+
+UriBool URI_FUNC(_TESTING_ONLY_ParseIpSix)(const URI_CHAR * text) {
+	URI_TYPE(Uri) uri;
+	URI_TYPE(ParserState) parser;
+	const URI_CHAR * const afterIpSix = text + URI_STRLEN(text);
+	const URI_CHAR * res;
+
+	URI_FUNC(ResetParserState)(&parser);
+	URI_FUNC(ResetUri)(&uri);
+	parser.uri = &uri;
+	parser.uri->hostData.ip6 = malloc(1 * sizeof(UriIp6));
+	res = URI_FUNC(ParseIPv6address2)(&parser, text, afterIpSix);
+	URI_FUNC(FreeUriMembers)(&uri);
+	return res == afterIpSix ? URI_TRUE : URI_FALSE;
+}
+
+
+
+UriBool URI_FUNC(_TESTING_ONLY_ParseIpFour)(const URI_CHAR * text) {
+	unsigned char octets[4];
+	int res = URI_FUNC(ParseIpFourAddress)(octets, text, text + URI_STRLEN(text));
+	return (res == URI_SUCCESS) ? URI_TRUE : URI_FALSE;
+}
+
+
+
+#undef URI_SET_DIGIT
+#undef URI_SET_HEX_LETTER_UPPER
+#undef URI_SET_HEX_LETTER_LOWER
+#undef URI_SET_HEXDIG
+#undef URI_SET_ALPHA
+
+
+
+#endif

http://git-wip-us.apache.org/repos/asf/hadoop/blob/196db0d6/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriParseBase.c
----------------------------------------------------------------------
diff --git a/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriParseBase.c b/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriParseBase.c
new file mode 100644
index 0000000..75e4761
--- /dev/null
+++ b/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriParseBase.c
@@ -0,0 +1,90 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2007, Weijia Song <so...@gmail.com>
+ * Copyright (C) 2007, Sebastian Pipping <we...@hartwork.org>
+ * All rights reserved.
+ *
+ * Redistribution  and use in source and binary forms, with or without
+ * modification,  are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions   of  source  code  must  retain  the   above
+ *       copyright  notice, this list of conditions and the  following
+ *       disclaimer.
+ *
+ *     * Redistributions  in  binary  form must  reproduce  the  above
+ *       copyright  notice, this list of conditions and the  following
+ *       disclaimer   in  the  documentation  and/or  other  materials
+ *       provided with the distribution.
+ *
+ *     * Neither  the name of the <ORGANIZATION> nor the names of  its
+ *       contributors  may  be  used to endorse  or  promote  products
+ *       derived  from  this software without specific  prior  written
+ *       permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT  NOT
+ * LIMITED  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS
+ * FOR  A  PARTICULAR  PURPOSE ARE DISCLAIMED. IN NO EVENT  SHALL  THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL,    SPECIAL,   EXEMPLARY,   OR   CONSEQUENTIAL   DAMAGES
+ * (INCLUDING,  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES;  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT  LIABILITY,  OR  TORT (INCLUDING  NEGLIGENCE  OR  OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef URI_DOXYGEN
+# include "UriParseBase.h"
+#endif
+
+
+
+void uriWriteQuadToDoubleByte(const unsigned char * hexDigits, int digitCount, unsigned char * output) {
+	switch (digitCount) {
+	case 1:
+		/* 0x___? -> \x00 \x0? */
+		output[0] = 0;
+		output[1] = hexDigits[0];
+		break;
+
+	case 2:
+		/* 0x__?? -> \0xx \x?? */
+		output[0] = 0;
+		output[1] = 16 * hexDigits[0] + hexDigits[1];
+		break;
+
+	case 3:
+		/* 0x_??? -> \0x? \x?? */
+		output[0] = hexDigits[0];
+		output[1] = 16 * hexDigits[1] + hexDigits[2];
+		break;
+
+	case 4:
+		/* 0x???? -> \0?? \x?? */
+		output[0] = 16 * hexDigits[0] + hexDigits[1];
+		output[1] = 16 * hexDigits[2] + hexDigits[3];
+		break;
+
+	}
+}
+
+
+
+unsigned char uriGetOctetValue(const unsigned char * digits, int digitCount) {
+	switch (digitCount) {
+	case 1:
+		return digits[0];
+
+	case 2:
+		return 10 * digits[0] + digits[1];
+
+	case 3:
+	default:
+		return 100 * digits[0] + 10 * digits[1] + digits[2];
+
+	}
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/196db0d6/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriParseBase.h
----------------------------------------------------------------------
diff --git a/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriParseBase.h b/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriParseBase.h
new file mode 100644
index 0000000..e93f336
--- /dev/null
+++ b/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriParseBase.h
@@ -0,0 +1,55 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2007, Weijia Song <so...@gmail.com>
+ * Copyright (C) 2007, Sebastian Pipping <we...@hartwork.org>
+ * All rights reserved.
+ *
+ * Redistribution  and use in source and binary forms, with or without
+ * modification,  are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions   of  source  code  must  retain  the   above
+ *       copyright  notice, this list of conditions and the  following
+ *       disclaimer.
+ *
+ *     * Redistributions  in  binary  form must  reproduce  the  above
+ *       copyright  notice, this list of conditions and the  following
+ *       disclaimer   in  the  documentation  and/or  other  materials
+ *       provided with the distribution.
+ *
+ *     * Neither  the name of the <ORGANIZATION> nor the names of  its
+ *       contributors  may  be  used to endorse  or  promote  products
+ *       derived  from  this software without specific  prior  written
+ *       permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT  NOT
+ * LIMITED  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS
+ * FOR  A  PARTICULAR  PURPOSE ARE DISCLAIMED. IN NO EVENT  SHALL  THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL,    SPECIAL,   EXEMPLARY,   OR   CONSEQUENTIAL   DAMAGES
+ * (INCLUDING,  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES;  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT  LIABILITY,  OR  TORT (INCLUDING  NEGLIGENCE  OR  OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef URI_PARSE_BASE_H
+#define URI_PARSE_BASE_H 1
+
+
+
+#include "UriBase.h"
+
+
+
+void uriWriteQuadToDoubleByte(const unsigned char * hexDigits, int digitCount,
+		unsigned char * output);
+unsigned char uriGetOctetValue(const unsigned char * digits, int digitCount);
+
+
+
+#endif /* URI_PARSE_BASE_H */

http://git-wip-us.apache.org/repos/asf/hadoop/blob/196db0d6/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriQuery.c
----------------------------------------------------------------------
diff --git a/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriQuery.c b/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriQuery.c
new file mode 100644
index 0000000..7cb031d
--- /dev/null
+++ b/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfspp/third_party/uriparser2/uriparser2/uriparser/UriQuery.c
@@ -0,0 +1,456 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2007, Weijia Song <so...@gmail.com>
+ * Copyright (C) 2007, Sebastian Pipping <we...@hartwork.org>
+ * All rights reserved.
+ *
+ * Redistribution  and use in source and binary forms, with or without
+ * modification,  are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions   of  source  code  must  retain  the   above
+ *       copyright  notice, this list of conditions and the  following
+ *       disclaimer.
+ *
+ *     * Redistributions  in  binary  form must  reproduce  the  above
+ *       copyright  notice, this list of conditions and the  following
+ *       disclaimer   in  the  documentation  and/or  other  materials
+ *       provided with the distribution.
+ *
+ *     * Neither  the name of the <ORGANIZATION> nor the names of  its
+ *       contributors  may  be  used to endorse  or  promote  products
+ *       derived  from  this software without specific  prior  written
+ *       permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT  NOT
+ * LIMITED  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS
+ * FOR  A  PARTICULAR  PURPOSE ARE DISCLAIMED. IN NO EVENT  SHALL  THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL,    SPECIAL,   EXEMPLARY,   OR   CONSEQUENTIAL   DAMAGES
+ * (INCLUDING,  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES;  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT  LIABILITY,  OR  TORT (INCLUDING  NEGLIGENCE  OR  OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include "UriDefsConfig.h"
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# define URI_PASS_ANSI 1
+# include "UriQuery.c"
+# undef URI_PASS_ANSI
+# define URI_PASS_UNICODE 1
+# include "UriQuery.c"
+# undef URI_PASS_UNICODE
+#else
+# ifdef URI_PASS_ANSI
+#  include "UriDefsAnsi.h"
+# else
+#  include "UriDefsUnicode.h"
+#  include <wchar.h>
+# endif
+
+
+
+#ifndef URI_DOXYGEN
+# include "Uri.h"
+# include "UriCommon.h"
+#endif
+
+
+
+static int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest,
+		const URI_TYPE(QueryList) * queryList,
+		int maxChars, int * charsWritten, int * charsRequired,
+		UriBool spaceToPlus, UriBool normalizeBreaks);
+
+static UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext,
+		int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter,
+		const URI_CHAR * valueFirst, const URI_CHAR * valueAfter,
+		UriBool plusToSpace, UriBreakConversion breakConversion);
+
+
+
+int URI_FUNC(ComposeQueryCharsRequired)(const URI_TYPE(QueryList) * queryList,
+		int * charsRequired) {
+	const UriBool spaceToPlus = URI_TRUE;
+	const UriBool normalizeBreaks = URI_TRUE;
+
+	return URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, charsRequired,
+			spaceToPlus, normalizeBreaks);
+}
+
+
+
+int URI_FUNC(ComposeQueryCharsRequiredEx)(const URI_TYPE(QueryList) * queryList,
+		int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks) {
+	if ((queryList == NULL) || (charsRequired == NULL)) {
+		return URI_ERROR_NULL;
+	}
+
+	return URI_FUNC(ComposeQueryEngine)(NULL, queryList, 0, NULL,
+			charsRequired, spaceToPlus, normalizeBreaks);
+}
+
+
+
+int URI_FUNC(ComposeQuery)(URI_CHAR * dest,
+						   const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten) {
+	const UriBool spaceToPlus = URI_TRUE;
+	const UriBool normalizeBreaks = URI_TRUE;
+
+	return URI_FUNC(ComposeQueryEx)(dest, queryList, maxChars, charsWritten,
+			spaceToPlus, normalizeBreaks);
+}
+
+
+
+int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest,
+		const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten,
+		UriBool spaceToPlus, UriBool normalizeBreaks) {
+	if ((dest == NULL) || (queryList == NULL)) {
+		return URI_ERROR_NULL;
+	}
+
+	if (maxChars < 1) {
+		return URI_ERROR_OUTPUT_TOO_LARGE;
+	}
+
+	return URI_FUNC(ComposeQueryEngine)(dest, queryList, maxChars,
+			charsWritten, NULL, spaceToPlus, normalizeBreaks);
+}
+
+
+
+int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest,
+		const URI_TYPE(QueryList) * queryList) {
+	const UriBool spaceToPlus = URI_TRUE;
+	const UriBool normalizeBreaks = URI_TRUE;
+
+	return URI_FUNC(ComposeQueryMallocEx)(dest, queryList,
+			spaceToPlus, normalizeBreaks);
+}
+
+
+
+int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest,
+		const URI_TYPE(QueryList) * queryList,
+		UriBool spaceToPlus, UriBool normalizeBreaks) {
+	int charsRequired;
+	int res;
+	URI_CHAR * queryString;
+
+	if (dest == NULL) {
+		return URI_ERROR_NULL;
+	}
+
+	/* Calculate space */
+	res = URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, &charsRequired,
+			spaceToPlus, normalizeBreaks);
+	if (res != URI_SUCCESS) {
+		return res;
+	}
+	charsRequired++;
+
+	/* Allocate space */
+	queryString = malloc(charsRequired * sizeof(URI_CHAR));
+	if (queryString == NULL) {
+		return URI_ERROR_MALLOC;
+	}
+
+	/* Put query in */
+	res = URI_FUNC(ComposeQueryEx)(queryString, queryList, charsRequired,
+			NULL, spaceToPlus, normalizeBreaks);
+	if (res != URI_SUCCESS) {
+		free(queryString);
+		return res;
+	}
+
+	*dest = queryString;
+	return URI_SUCCESS;
+}
+
+
+
+int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest,
+		const URI_TYPE(QueryList) * queryList,
+		int maxChars, int * charsWritten, int * charsRequired,
+		UriBool spaceToPlus, UriBool normalizeBreaks) {
+	UriBool firstItem = URI_TRUE;
+	int ampersandLen = 0;
+	URI_CHAR * write = dest;
+
+	/* Subtract terminator */
+	if (dest == NULL) {
+		*charsRequired = 0;
+	} else {
+		maxChars--;
+	}
+			
+	while (queryList != NULL) {
+		const URI_CHAR * const key = queryList->key;
+		const URI_CHAR * const value = queryList->value;
+		const int worstCase = (normalizeBreaks == URI_TRUE ? 6 : 3);
+		const int keyLen = (key == NULL) ? 0 : (int)URI_STRLEN(key);
+		const int keyRequiredChars = worstCase * keyLen;
+		const int valueLen = (value == NULL) ? 0 : (int)URI_STRLEN(value);
+		const int valueRequiredChars = worstCase * valueLen;
+
+		if (dest == NULL) {
+			if (firstItem == URI_TRUE) {
+				ampersandLen = 1;
+				firstItem = URI_FALSE;
+			}
+
+			(*charsRequired) += ampersandLen + keyRequiredChars + ((value == NULL)
+						? 0
+						: 1 + valueRequiredChars);
+		} else {
+			URI_CHAR * afterKey;
+
+			if ((write - dest) + ampersandLen + keyRequiredChars > maxChars) {
+				return URI_ERROR_OUTPUT_TOO_LARGE;
+			}
+
+			/* Copy key */
+			if (firstItem == URI_TRUE) {
+				firstItem = URI_FALSE;
+			} else {
+				write[0] = _UT('&');
+				write++;
+			}
+			afterKey = URI_FUNC(EscapeEx)(key, key + keyLen,
+					write, spaceToPlus, normalizeBreaks);
+			write += (afterKey - write);
+
+			if (value != NULL) {
+				URI_CHAR * afterValue;
+
+				if ((write - dest) + 1 + valueRequiredChars > maxChars) {
+					return URI_ERROR_OUTPUT_TOO_LARGE;
+				}
+
+				/* Copy value */
+				write[0] = _UT('=');
+				write++;
+				afterValue = URI_FUNC(EscapeEx)(value, value + valueLen,
+						write, spaceToPlus, normalizeBreaks);
+				write += (afterValue - write);
+			}
+		}
+
+		queryList = queryList->next;
+	}
+
+	if (dest != NULL) {
+		write[0] = _UT('\0');
+		if (charsWritten != NULL) {
+			*charsWritten = (int)(write - dest) + 1; /* .. for terminator */
+		}
+	}
+
+	return URI_SUCCESS;
+}
+
+
+
+UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext,
+		int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter,
+		const URI_CHAR * valueFirst, const URI_CHAR * valueAfter,
+		UriBool plusToSpace, UriBreakConversion breakConversion) {
+	const int keyLen = (int)(keyAfter - keyFirst);
+	const int valueLen = (int)(valueAfter - valueFirst);
+	URI_CHAR * key;
+	URI_CHAR * value;
+
+	if ((prevNext == NULL) || (itemCount == NULL)
+			|| (keyFirst == NULL) || (keyAfter == NULL)
+			|| (keyFirst > keyAfter) || (valueFirst > valueAfter)
+			|| ((keyFirst == keyAfter)
+				&& (valueFirst == NULL) && (valueAfter == NULL))) {
+		return URI_TRUE;
+	}
+
+	/* Append new empty item */
+	*prevNext = malloc(1 * sizeof(URI_TYPE(QueryList)));
+	if (*prevNext == NULL) {
+		return URI_FALSE; /* Raises malloc error */
+	}
+	(*prevNext)->next = NULL;
+
+
+	/* Fill key */
+	key = malloc((keyLen + 1) * sizeof(URI_CHAR));
+	if (key == NULL) {
+		free(*prevNext);
+		*prevNext = NULL;
+		return URI_FALSE; /* Raises malloc error */
+	}
+
+	key[keyLen] = _UT('\0');
+	if (keyLen > 0) {
+		/* Copy 1:1 */
+		memcpy(key, keyFirst, keyLen * sizeof(URI_CHAR));
+
+		/* Unescape */
+		URI_FUNC(UnescapeInPlaceEx)(key, plusToSpace, breakConversion);
+	}
+	(*prevNext)->key = key;
+
+
+	/* Fill value */
+	if (valueFirst != NULL) {
+		value = malloc((valueLen + 1) * sizeof(URI_CHAR));
+		if (value == NULL) {
+			free(key);
+			free(*prevNext);
+			*prevNext = NULL;
+			return URI_FALSE; /* Raises malloc error */
+		}
+
+		value[valueLen] = _UT('\0');
+		if (valueLen > 0) {
+			/* Copy 1:1 */
+			memcpy(value, valueFirst, valueLen * sizeof(URI_CHAR));
+
+			/* Unescape */
+			URI_FUNC(UnescapeInPlaceEx)(value, plusToSpace, breakConversion);
+		}
+		(*prevNext)->value = value;
+	} else {
+		value = NULL;
+	}
+	(*prevNext)->value = value;
+
+	(*itemCount)++;
+	return URI_TRUE;
+}
+
+
+
+void URI_FUNC(FreeQueryList)(URI_TYPE(QueryList) * queryList) {
+	while (queryList != NULL) {
+		URI_TYPE(QueryList) * nextBackup = queryList->next;
+		free(queryList->key);
+		free(queryList->value);
+		free(queryList);
+		queryList = nextBackup;
+	}
+}
+
+
+
+int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest, int * itemCount,
+		const URI_CHAR * first, const URI_CHAR * afterLast) {
+	const UriBool plusToSpace = URI_TRUE;
+	const UriBreakConversion breakConversion = URI_BR_DONT_TOUCH;
+
+	return URI_FUNC(DissectQueryMallocEx)(dest, itemCount, first, afterLast,
+			plusToSpace, breakConversion);
+}
+
+
+
+int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest, int * itemCount,
+		const URI_CHAR * first, const URI_CHAR * afterLast,
+		UriBool plusToSpace, UriBreakConversion breakConversion) {
+	const URI_CHAR * walk = first;
+	const URI_CHAR * keyFirst = first;
+	const URI_CHAR * keyAfter = NULL;
+	const URI_CHAR * valueFirst = NULL;
+	const URI_CHAR * valueAfter = NULL;
+	URI_TYPE(QueryList) ** prevNext = dest;
+	int nullCounter;
+	int * itemsAppended = (itemCount == NULL) ? &nullCounter : itemCount;
+
+	if ((dest == NULL) || (first == NULL) || (afterLast == NULL)) {
+		return URI_ERROR_NULL;
+	}
+
+	if (first > afterLast) {
+		return URI_ERROR_RANGE_INVALID;
+	}
+
+	*dest = NULL;
+	*itemsAppended = 0;
+
+	/* Parse query string */
+	for (; walk < afterLast; walk++) {
+		switch (*walk) {
+		case _UT('&'):
+			if (valueFirst != NULL) {
+				valueAfter = walk;
+			} else {
+				keyAfter = walk;
+			}
+
+			if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended,
+					keyFirst, keyAfter, valueFirst, valueAfter,
+					plusToSpace, breakConversion)
+					== URI_FALSE) {
+				/* Free list we built */
+				*itemsAppended = 0;
+				URI_FUNC(FreeQueryList)(*dest);
+				return URI_ERROR_MALLOC;
+			}
+
+			/* Make future items children of the current */
+			if ((prevNext != NULL) && (*prevNext != NULL)) {
+				prevNext = &((*prevNext)->next);
+			}
+
+			if (walk + 1 < afterLast) {
+				keyFirst = walk + 1;
+			} else {
+				keyFirst = NULL;
+			}
+			keyAfter = NULL;
+			valueFirst = NULL;
+			valueAfter = NULL;
+			break;
+
+		case _UT('='):
+			/* NOTE: WE treat the first '=' as a separator, */
+			/*       all following go into the value part   */
+			if (keyAfter == NULL) {
+				keyAfter = walk;
+				if (walk + 1 < afterLast) {
+					valueFirst = walk + 1;
+					valueAfter = walk + 1;
+				}
+			}
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	if (valueFirst != NULL) {
+		/* Must be key/value pair */
+		valueAfter = walk;
+	} else {
+		/* Must be key only */
+		keyAfter = walk;
+	}
+
+	if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, keyFirst, keyAfter,
+			valueFirst, valueAfter, plusToSpace, breakConversion)
+			== URI_FALSE) {
+		/* Free list we built */
+		*itemsAppended = 0;
+		URI_FUNC(FreeQueryList)(*dest);
+		return URI_ERROR_MALLOC;
+	}
+
+	return URI_SUCCESS;
+}
+
+
+
+#endif