Re: [PATCH 2 of 7] * Use uriparser 0.7.5 and move needed stuff to uriparser directory

Tobias Oetiker <[email protected]>
Newsgroups gmane.comp.db.rrdtool.devel
Message-ID <[email protected]>
Hi Peter,

seems like a large junke of code you are introducing here ... do we
realy need all this ?

cheers
tobi


Monday Peter Stamfest wrote:

> # HG changeset patch
> # User Peter Stamfest <[email protected]>
> # Date 1299524476 -3600
> # Node ID c70c412d2399f71640bbb08adaff1037b2a13004
> # Parent  2e1ec35bef337eee041078d583cfe5aaa7068509
> * Use uriparser 0.7.5 and move needed stuff to uriparser directory
> * Used under the BSD license
> * Downloaded from http://downloads.sourceforge.net/project/uriparser/Sources/0.7.5/uriparser-0.7.5.tar.gz
>
> diff --git a/uriparser/include/uriparser/Uri.h b/uriparser/include/uriparser/Uri.h
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/include/uriparser/Uri.h
> @@ -0,0 +1,752 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 Uri.h
> + * Holds the RFC 3986 %URI parser interface.
> + * NOTE: This header includes itself twice.
> + */
> +
> +#if (defined(URI_PASS_ANSI) && !defined(URI_H_ANSI)) \
> +	|| (defined(URI_PASS_UNICODE) && !defined(URI_H_UNICODE)) \
> +	|| (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
> +/* 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 "Uri.h"
> +# undef URI_PASS_ANSI
> +# define URI_PASS_UNICODE 1
> +# include "Uri.h"
> +# undef URI_PASS_UNICODE
> +/* Only one pass for each encoding */
> +#elif (defined(URI_PASS_ANSI) && !defined(URI_H_ANSI) \
> +	&& defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \
> +	&& !defined(URI_H_UNICODE) && defined(URI_ENABLE_UNICODE))
> +# ifdef URI_PASS_ANSI
> +#  define URI_H_ANSI 1
> +#  include "UriDefsAnsi.h"
> +# else
> +#  define URI_H_UNICODE 1
> +#  include "UriDefsUnicode.h"
> +# endif
> +
> +
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +
> +
> +#ifndef URI_DOXYGEN
> +# include "UriBase.h"
> +#endif
> +
> +
> +
> +/**
> + * Specifies a range of characters within a string.
> + * The range includes all characters from <c>first</c>
> + * to one before <c>afterLast</c>. So if both are
> + * non-NULL the difference is the length of the text range.
> + *
> + * @see UriUriA
> + * @see UriPathSegmentA
> + * @see UriHostDataA
> + * @since 0.3.0
> + */
> +typedef struct URI_TYPE(TextRangeStruct) {
> +	const URI_CHAR * first; /**< Pointer to first character */
> +	const URI_CHAR * afterLast; /**< Pointer to character after the last one still in */
> +} URI_TYPE(TextRange); /**< @copydoc UriTextRangeStructA */
> +
> +
> +
> +/**
> + * Represents a path segment within a %URI path.
> + * More precisely it is a node in a linked
> + * list of path segments.
> + *
> + * @see UriUriA
> + * @since 0.3.0
> + */
> +typedef struct URI_TYPE(PathSegmentStruct) {
> +	URI_TYPE(TextRange) text; /**< Path segment name */
> +	struct URI_TYPE(PathSegmentStruct) * next; /**< Pointer to the next path segment in the list, can be NULL if last already */
> +
> +	void * reserved; /**< Reserved to the parser */
> +} URI_TYPE(PathSegment); /**< @copydoc UriPathSegmentStructA */
> +
> +
> +
> +/**
> + * Holds structured host information.
> + * This is either a IPv4, IPv6, plain
> + * text for IPvFuture or all zero for
> + * a registered name.
> + *
> + * @see UriUriA
> + * @since 0.3.0
> + */
> +typedef struct URI_TYPE(HostDataStruct) {
> +	UriIp4 * ip4; /**< IPv4 address */
> +	UriIp6 * ip6; /**< IPv6 address */
> +	URI_TYPE(TextRange) ipFuture; /**< IPvFuture address */
> +} URI_TYPE(HostData); /**< @copydoc UriHostDataStructA */
> +
> +
> +
> +/**
> + * Represents an RFC 3986 %URI.
> + * Missing components can be {NULL, NULL} ranges.
> + *
> + * @see uriParseUriA
> + * @see uriFreeUriMembersA
> + * @see UriParserStateA
> + * @since 0.3.0
> + */
> +typedef struct URI_TYPE(UriStruct) {
> +	URI_TYPE(TextRange) scheme; /**< Scheme (e.g. "http") */
> +	URI_TYPE(TextRange) userInfo; /**< User info (e.g. "user:pass") */
> +	URI_TYPE(TextRange) hostText; /**< Host text (set for all hosts, excluding square brackets) */
> +	URI_TYPE(HostData) hostData; /**< Structured host type specific data */
> +	URI_TYPE(TextRange) portText; /**< Port (e.g. "80") */
> +	URI_TYPE(PathSegment) * pathHead; /**< Head of a linked list of path segments */
> +	URI_TYPE(PathSegment) * pathTail; /**< Tail of the list behind pathHead */
> +	URI_TYPE(TextRange) query; /**< Query without leading "?" */
> +	URI_TYPE(TextRange) fragment; /**< Query without leading "#" */
> +	UriBool absolutePath; /**< Absolute path flag, distincting "a" and "/a" */
> +	UriBool owner; /**< Memory owner flag */
> +
> +	void * reserved; /**< Reserved to the parser */
> +} URI_TYPE(Uri); /**< @copydoc UriUriStructA */
> +
> +
> +
> +/**
> + * Represents a state of the %URI parser.
> + * Missing components can be NULL to reflect
> + * a components absence.
> + *
> + * @see uriFreeUriMembersA
> + * @since 0.3.0
> + */
> +typedef struct URI_TYPE(ParserStateStruct) {
> +	URI_TYPE(Uri) * uri; /**< Plug in the %URI structure to be filled while parsing here */
> +	int errorCode; /**< Code identifying the occured error */
> +	const URI_CHAR * errorPos; /**< Pointer to position in case of a syntax error */
> +
> +	void * reserved; /**< Reserved to the parser */
> +} URI_TYPE(ParserState); /**< @copydoc UriParserStateStructA */
> +
> +
> +
> +/**
> + * Represents a query element.
> + * More precisely it is a node in a linked
> + * list of query elements.
> + *
> + * @since 0.7.0
> + */
> +typedef struct URI_TYPE(QueryListStruct) {
> +	const URI_CHAR * key; /**< Key of the query element */
> +	const URI_CHAR * value; /**< Value of the query element, can be NULL */
> +
> +	struct URI_TYPE(QueryListStruct) * next; /**< Pointer to the next key/value pair in the list, can be NULL if last already */
> +} URI_TYPE(QueryList); /**< @copydoc UriQueryListStructA */
> +
> +
> +
> +/**
> + * Parses a RFC 3986 URI.
> + *
> + * @param state       <b>INOUT</b>: Parser state with set output %URI, must not be NULL
> + * @param first       <b>IN</b>: Pointer to the first character to parse, must not be NULL
> + * @param afterLast   <b>IN</b>: Pointer to the character after the last to parse, must not be NULL
> + * @return            0 on success, error code otherwise
> + *
> + * @see uriParseUriA
> + * @see uriToStringA
> + * @since 0.3.0
> + */
> +int URI_FUNC(ParseUriEx)(URI_TYPE(ParserState) * state,
> +		const URI_CHAR * first, const URI_CHAR * afterLast);
> +
> +
> +
> +/**
> + * Parses a RFC 3986 %URI.
> + *
> + * @param state   <b>INOUT</b>: Parser state with set output %URI, must not be NULL
> + * @param text    <b>IN</b>: Text to parse, must not be NULL
> + * @return        0 on success, error code otherwise
> + *
> + * @see uriParseUriExA
> + * @see uriToStringA
> + * @since 0.3.0
> + */
> +int URI_FUNC(ParseUri)(URI_TYPE(ParserState) * state,
> +		const URI_CHAR * text);
> +
> +
> +
> +/**
> + * Frees all memory associated with the members
> + * of the %URI structure. Note that the structure
> + * itself is not freed, only its members.
> + *
> + * @param uri   <b>INOUT</b>: %URI structure whose members should be freed
> + *
> + * @since 0.3.0
> + */
> +void URI_FUNC(FreeUriMembers)(URI_TYPE(Uri) * uri);
> +
> +
> +
> +/**
> + * Percent-encodes all unreserved characters from the input string and
> + * writes the encoded version to the output string.
> + * Be sure to allocate <b>3 times</b> the space of the input buffer for
> + * the output buffer for <c>normalizeBreaks == URI_FALSE</c> and <b>6 times</b>
> + * the space for <c>normalizeBreaks == URI_TRUE</c>
> + * (since e.g. "\x0d" becomes "%0D%0A" in that case)
> + *
> + * @param inFirst           <b>IN</b>: Pointer to first character of the input text
> + * @param inAfterLast       <b>IN</b>: Pointer after the last character of the input text
> + * @param out               <b>OUT</b>: Encoded text destination
> + * @param spaceToPlus       <b>IN</b>: Wether to convert ' ' to '+' or not
> + * @param normalizeBreaks   <b>IN</b>: Wether to convert CR and LF to CR-LF or not.
> + * @return                  Position of terminator in output string
> + *
> + * @see uriEscapeA
> + * @see uriUnescapeInPlaceExA
> + * @since 0.5.2
> + */
> +URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst,
> +		const URI_CHAR * inAfterLast, URI_CHAR * out,
> +		UriBool spaceToPlus, UriBool normalizeBreaks);
> +
> +
> +
> +/**
> + * Percent-encodes all unreserved characters from the input string and
> + * writes the encoded version to the output string.
> + * Be sure to allocate <b>3 times</b> the space of the input buffer for
> + * the output buffer for <c>normalizeBreaks == URI_FALSE</c> and <b>6 times</b>
> + * the space for <c>normalizeBreaks == URI_FALSE</c>
> + * (since e.g. "\x0d" becomes "%0D%0A" in that case)
> + *
> + * @param in                <b>IN</b>: Text source
> + * @param out               <b>OUT</b>: Encoded text destination
> + * @param spaceToPlus       <b>IN</b>: Wether to convert ' ' to '+' or not
> + * @param normalizeBreaks   <b>IN</b>: Wether to convert CR and LF to CR-LF or not.
> + * @return                  Position of terminator in output string
> + *
> + * @see uriEscapeExA
> + * @see uriUnescapeInPlaceA
> + * @since 0.5.0
> + */
> +URI_CHAR * URI_FUNC(Escape)(const URI_CHAR * in, URI_CHAR * out,
> +		UriBool spaceToPlus, UriBool normalizeBreaks);
> +
> +
> +
> +/**
> + * Unescapes percent-encoded groups in a given string.
> + * E.g. "%20" will become " ". Unescaping is done in place.
> + * The return value will be point to the new position
> + * of the terminating zero. Use this value to get the new
> + * length of the string. NULL is only returned if <c>inout</c>
> + * is NULL.
> + *
> + * @param inout             <b>INOUT</b>: Text to unescape/decode
> + * @param plusToSpace       <b>IN</b>: Whether to convert '+' to ' ' or not
> + * @param breakConversion   <b>IN</b>: Line break conversion mode
> + * @return                  Pointer to new position of the terminating zero
> + *
> + * @see uriUnescapeInPlaceA
> + * @see uriEscapeExA
> + * @since 0.5.0
> + */
> +const URI_CHAR * URI_FUNC(UnescapeInPlaceEx)(URI_CHAR * inout,
> +		UriBool plusToSpace, UriBreakConversion breakConversion);
> +
> +
> +
> +/**
> + * Unescapes percent-encoded groups in a given string.
> + * E.g. "%20" will become " ". Unescaping is done in place.
> + * The return value will be point to the new position
> + * of the terminating zero. Use this value to get the new
> + * length of the string. NULL is only returned if <c>inout</c>
> + * is NULL.
> + *
> + * NOTE: '+' is not decoded to ' ' and line breaks are not converted.
> + * Use the more advanced UnescapeInPlaceEx for that features instead.
> + *
> + * @param inout   <b>INOUT</b>: Text to unescape/decode
> + * @return        Pointer to new position of the terminating zero
> + *
> + * @see uriUnescapeInPlaceExA
> + * @see uriEscapeA
> + * @since 0.3.0
> + */
> +const URI_CHAR * URI_FUNC(UnescapeInPlace)(URI_CHAR * inout);
> +
> +
> +
> +/**
> + * Performs reference resolution as described in
> + * <a href="http://tools.ietf.org/html/rfc3986#section-5.2.2">section 5.2.2 of RFC 3986</a>.
> + * NOTE: On success you have to call uriFreeUriMembersA on \p absoluteDest manually later.
> + *
> + * @param absoluteDest     <b>OUT</b>: Result %URI
> + * @param relativeSource   <b>IN</b>: Reference to resolve
> + * @param absoluteBase     <b>IN</b>: Base %URI to apply
> + * @return                 Error code or 0 on success
> + *
> + * @see uriRemoveBaseUriA
> + * @since 0.4.0
> + */
> +int URI_FUNC(AddBaseUri)(URI_TYPE(Uri) * absoluteDest,
> +		const URI_TYPE(Uri) * relativeSource,
> +		const URI_TYPE(Uri) * absoluteBase);
> +
> +
> +
> +/**
> + * Tries to make a relative %URI (a reference) from an
> + * absolute %URI and a given base %URI. This can only work if
> + * the absolute %URI shares scheme and authority with
> + * the base %URI. If it does not the result will still be
> + * an absolute URI (with scheme part if necessary).
> + * NOTE: On success you have to call uriFreeUriMembersA on
> + * \p dest manually later.
> + *
> + * @param dest             <b>OUT</b>: Result %URI
> + * @param absoluteSource   <b>IN</b>: Absolute %URI to make relative
> + * @param absoluteBase     <b>IN</b>: Base %URI
> + * @param domainRootMode   <b>IN</b>: Create %URI with path relative to domain root
> + * @return                 Error code or 0 on success
> + *
> + * @see uriAddBaseUriA
> + * @since 0.5.2
> + */
> +int URI_FUNC(RemoveBaseUri)(URI_TYPE(Uri) * dest,
> +		const URI_TYPE(Uri) * absoluteSource,
> +		const URI_TYPE(Uri) * absoluteBase,
> +		UriBool domainRootMode);
> +
> +
> +
> +/**
> + * Checks two URIs for equivalence. Comparison is done
> + * the naive way, without prior normalization.
> + * NOTE: Two <c>NULL</c> URIs are equal as well.
> + *
> + * @param a   <b>IN</b>: First %URI
> + * @param b   <b>IN</b>: Second %URI
> + * @return    <c>URI_TRUE</c> when equal, <c>URI_FAlSE</c> else
> + *
> + * @since 0.4.0
> + */
> +UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, const URI_TYPE(Uri) * b);
> +
> +
> +
> +/**
> + * Calculates the number of characters needed to store the
> + * string representation of the given %URI excluding the
> + * terminator.
> + *
> + * @param uri             <b>IN</b>: %URI to measure
> + * @param charsRequired   <b>OUT</b>: Length of the string representation in characters <b>excluding</b> terminator
> + * @return                Error code or 0 on success
> + *
> + * @see uriToStringA
> + * @since 0.5.0
> + */
> +int URI_FUNC(ToStringCharsRequired)(const URI_TYPE(Uri) * uri,
> +		int * charsRequired);
> +
> +
> +
> +/**
> + * Converts a %URI structure back to text as described in
> + * <a href="http://tools.ietf.org/html/rfc3986#section-5.3">section 5.3 of RFC 3986</a>.
> + *
> + * @param dest           <b>OUT</b>: Output destination
> + * @param uri            <b>IN</b>: %URI to convert
> + * @param maxChars       <b>IN</b>: Maximum number of characters to copy <b>including</b> terminator
> + * @param charsWritten   <b>OUT</b>: Number of characters written, can be lower than maxChars even if the %URI is too long!
> + * @return               Error code or 0 on success
> + *
> + * @see uriToStringCharsRequiredA
> + * @since 0.4.0
> + */
> +int URI_FUNC(ToString)(URI_CHAR * dest, const URI_TYPE(Uri) * uri, int maxChars, int * charsWritten);
> +
> +
> +
> +/**
> + * Determines the components of a %URI that are not normalized.
> + *
> + * @param uri   <b>IN</b>: %URI to check
> + * @return      Normalization job mask
> + *
> + * @see uriNormalizeSyntaxA
> + * @since 0.5.0
> + */
> +unsigned int URI_FUNC(NormalizeSyntaxMaskRequired)(const URI_TYPE(Uri) * uri);
> +
> +
> +
> +/**
> + * Normalizes a %URI using a normalization mask.
> + * The normalization mask decides what components are normalized.
> + *
> + * NOTE: If necessary the %URI becomes owner of all memory
> + * behind the text pointed to. Text is duplicated in that case.
> + *
> + * @param uri    <b>INOUT</b>: %URI to normalize
> + * @param mask   <b>IN</b>: Normalization mask
> + * @return       Error code or 0 on success
> + *
> + * @see uriNormalizeSyntaxA
> + * @see uriNormalizeSyntaxMaskRequiredA
> + * @since 0.5.0
> + */
> +int URI_FUNC(NormalizeSyntaxEx)(URI_TYPE(Uri) * uri, unsigned int mask);
> +
> +
> +
> +/**
> + * Normalizes all components of a %URI.
> + *
> + * NOTE: If necessary the %URI becomes owner of all memory
> + * behind the text pointed to. Text is duplicated in that case.
> + *
> + * @param uri   <b>INOUT</b>: %URI to normalize
> + * @return      Error code or 0 on success
> + *
> + * @see uriNormalizeSyntaxExA
> + * @see uriNormalizeSyntaxMaskRequiredA
> + * @since 0.5.0
> + */
> +int URI_FUNC(NormalizeSyntax)(URI_TYPE(Uri) * uri);
> +
> +
> +
> +/**
> + * Converts a Unix filename to a %URI string.
> + * The destination buffer must be large enough to hold 7 + 3 * len(filename) + 1
> + * characters in case of an absolute filename or 3 * len(filename) + 1 in case
> + * of a relative filename.
> + *
> + * EXAMPLE
> + *   Input:  "/bin/bash"
> + *   Output: "file:///bin/bash"
> + *
> + * @param filename     <b>IN</b>: Unix filename to convert
> + * @param uriString    <b>OUT</b>: Destination to write %URI string to
> + * @return             Error code or 0 on success
> + *
> + * @see uriUriStringToUnixFilenameA
> + * @see uriWindowsFilenameToUriStringA
> + * @since 0.5.2
> + */
> +int URI_FUNC(UnixFilenameToUriString)(const URI_CHAR * filename,
> +		URI_CHAR * uriString);
> +
> +
> +
> +/**
> + * Converts a Windows filename to a %URI string.
> + * The destination buffer must be large enough to hold 8 + 3 * len(filename) + 1
> + * characters in case of an absolute filename or 3 * len(filename) + 1 in case
> + * of a relative filename.
> + *
> + * EXAMPLE
> + *   Input:  "E:\\Documents and Settings"
> + *   Output: "file:///E:/Documents%20and%20Settings"
> + *
> + * @param filename     <b>IN</b>: Windows filename to convert
> + * @param uriString    <b>OUT</b>: Destination to write %URI string to
> + * @return             Error code or 0 on success
> + *
> + * @see uriUriStringToWindowsFilenameA
> + * @see uriUnixFilenameToUriStringA
> + * @since 0.5.2
> + */
> +int URI_FUNC(WindowsFilenameToUriString)(const URI_CHAR * filename,
> +		URI_CHAR * uriString);
> +
> +
> +
> +/**
> + * Extracts a Unix filename from a %URI string.
> + * The destination buffer must be large enough to hold len(uriString) + 1 - 7
> + * characters in case of an absolute %URI or len(uriString) + 1 in case
> + * of a relative %URI.
> + *
> + * @param uriString    <b>IN</b>: %URI string to convert
> + * @param filename     <b>OUT</b>: Destination to write filename to
> + * @return             Error code or 0 on success
> + *
> + * @see uriUnixFilenameToUriStringA
> + * @see uriUriStringToWindowsFilenameA
> + * @since 0.5.2
> + */
> +int URI_FUNC(UriStringToUnixFilename)(const URI_CHAR * uriString,
> +		URI_CHAR * filename);
> +
> +
> +
> +/**
> + * Extracts a Windows filename from a %URI string.
> + * The destination buffer must be large enough to hold len(uriString) + 1 - 8
> + * characters in case of an absolute %URI or len(uriString) + 1 in case
> + * of a relative %URI.
> + *
> + * @param uriString    <b>IN</b>: %URI string to convert
> + * @param filename     <b>OUT</b>: Destination to write filename to
> + * @return             Error code or 0 on success
> + *
> + * @see uriWindowsFilenameToUriStringA
> + * @see uriUriStringToUnixFilenameA
> + * @since 0.5.2
> + */
> +int URI_FUNC(UriStringToWindowsFilename)(const URI_CHAR * uriString,
> +		URI_CHAR * filename);
> +
> +
> +
> +/**
> + * Calculates the number of characters needed to store the
> + * string representation of the given query list excluding the
> + * terminator. It is assumed that line breaks are will be
> + * normalized to "%0D%0A".
> + *
> + * @param queryList         <b>IN</b>: Query list to measure
> + * @param charsRequired     <b>OUT</b>: Length of the string representation in characters <b>excluding</b> terminator
> + * @return                  Error code or 0 on success
> + *
> + * @see uriComposeQueryCharsRequiredExA
> + * @see uriComposeQueryA
> + * @since 0.7.0
> + */
> +int URI_FUNC(ComposeQueryCharsRequired)(const URI_TYPE(QueryList) * queryList,
> +		int * charsRequired);
> +
> +
> +
> +/**
> + * Calculates the number of characters needed to store the
> + * string representation of the given query list excluding the
> + * terminator.
> + *
> + * @param queryList         <b>IN</b>: Query list to measure
> + * @param charsRequired     <b>OUT</b>: Length of the string representation in characters <b>excluding</b> terminator
> + * @param spaceToPlus       <b>IN</b>: Wether to convert ' ' to '+' or not
> + * @param normalizeBreaks   <b>IN</b>: Wether to convert CR and LF to CR-LF or not.
> + * @return                  Error code or 0 on success
> + *
> + * @see uriComposeQueryCharsRequiredA
> + * @see uriComposeQueryExA
> + * @since 0.7.0
> + */
> +int URI_FUNC(ComposeQueryCharsRequiredEx)(const URI_TYPE(QueryList) * queryList,
> +		int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks);
> +
> +
> +
> +/**
> + * Converts a query list structure back to a query string.
> + * The composed string does not start with '?',
> + * on the way ' ' is converted to '+' and line breaks are
> + * normalized to "%0D%0A".
> + *
> + * @param dest              <b>OUT</b>: Output destination
> + * @param queryList         <b>IN</b>: Query list to convert
> + * @param maxChars          <b>IN</b>: Maximum number of characters to copy <b>including</b> terminator
> + * @param charsWritten      <b>OUT</b>: Number of characters written, can be lower than maxChars even if the query list is too long!
> + * @return                  Error code or 0 on success
> + *
> + * @see uriComposeQueryExA
> + * @see uriComposeQueryMallocA
> + * @see uriComposeQueryCharsRequiredA
> + * @see uriDissectQueryMallocA
> + * @since 0.7.0
> + */
> +int URI_FUNC(ComposeQuery)(URI_CHAR * dest,
> +		const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten);
> +
> +
> +
> +/**
> + * Converts a query list structure back to a query string.
> + * The composed string does not start with '?'.
> + *
> + * @param dest              <b>OUT</b>: Output destination
> + * @param queryList         <b>IN</b>: Query list to convert
> + * @param maxChars          <b>IN</b>: Maximum number of characters to copy <b>including</b> terminator
> + * @param charsWritten      <b>OUT</b>: Number of characters written, can be lower than maxChars even if the query list is too long!
> + * @param spaceToPlus       <b>IN</b>: Wether to convert ' ' to '+' or not
> + * @param normalizeBreaks   <b>IN</b>: Wether to convert CR and LF to CR-LF or not.
> + * @return                  Error code or 0 on success
> + *
> + * @see uriComposeQueryA
> + * @see uriComposeQueryMallocExA
> + * @see uriComposeQueryCharsRequiredExA
> + * @see uriDissectQueryMallocExA
> + * @since 0.7.0
> + */
> +int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest,
> +		const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten,
> +		UriBool spaceToPlus, UriBool normalizeBreaks);
> +
> +
> +
> +/**
> + * Converts a query list structure back to a query string.
> + * Memory for this string is allocated internally.
> + * The composed string does not start with '?',
> + * on the way ' ' is converted to '+' and line breaks are
> + * normalized to "%0D%0A".
> + *
> + * @param dest              <b>OUT</b>: Output destination
> + * @param queryList         <b>IN</b>: Query list to convert
> + * @return                  Error code or 0 on success
> + *
> + * @see uriComposeQueryMallocExA
> + * @see uriComposeQueryA
> + * @see uriDissectQueryMallocA
> + * @since 0.7.0
> + */
> +int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest,
> +		const URI_TYPE(QueryList) * queryList);
> +
> +
> +
> +/**
> + * Converts a query list structure back to a query string.
> + * Memory for this string is allocated internally.
> + * The composed string does not start with '?'.
> + *
> + * @param dest              <b>OUT</b>: Output destination
> + * @param queryList         <b>IN</b>: Query list to convert
> + * @param spaceToPlus       <b>IN</b>: Wether to convert ' ' to '+' or not
> + * @param normalizeBreaks   <b>IN</b>: Wether to convert CR and LF to CR-LF or not.
> + * @return                  Error code or 0 on success
> + *
> + * @see uriComposeQueryMallocA
> + * @see uriComposeQueryExA
> + * @see uriDissectQueryMallocExA
> + * @since 0.7.0
> + */
> +int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest,
> +		const URI_TYPE(QueryList) * queryList,
> +		UriBool spaceToPlus, UriBool normalizeBreaks);
> +
> +
> +
> +/**
> + * Constructs a query list from the raw query string of a given URI.
> + * On the way '+' is converted back to ' ', line breaks are not modified.
> + *
> + * @param dest              <b>OUT</b>: Output destination
> + * @param itemCount         <b>OUT</b>: Number of items found, can be NULL
> + * @param first             <b>IN</b>: Pointer to first character <b>after</b> '?'
> + * @param afterLast         <b>IN</b>: Pointer to character after the last one still in
> + * @return                  Error code or 0 on success
> + *
> + * @see uriDissectQueryMallocExA
> + * @see uriComposeQueryA
> + * @see uriFreeQueryListA
> + * @since 0.7.0
> + */
> +int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest, int * itemCount,
> +		const URI_CHAR * first, const URI_CHAR * afterLast);
> +
> +
> +
> +/**
> + * Constructs a query list from the raw query string of a given URI.
> + *
> + * @param dest              <b>OUT</b>: Output destination
> + * @param itemCount         <b>OUT</b>: Number of items found, can be NULL
> + * @param first             <b>IN</b>: Pointer to first character <b>after</b> '?'
> + * @param afterLast         <b>IN</b>: Pointer to character after the last one still in
> + * @param plusToSpace       <b>IN</b>: Whether to convert '+' to ' ' or not
> + * @param breakConversion   <b>IN</b>: Line break conversion mode
> + * @return                  Error code or 0 on success
> + *
> + * @see uriDissectQueryMallocA
> + * @see uriComposeQueryExA
> + * @see uriFreeQueryListA
> + * @since 0.7.0
> + */
> +int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest, int * itemCount,
> +		const URI_CHAR * first, const URI_CHAR * afterLast,
> +		UriBool plusToSpace, UriBreakConversion breakConversion);
> +
> +
> +
> +/**
> + * Frees all memory associated with the given query list.
> + * The structure itself is freed as well.
> + *
> + * @param queryList   <b>INOUT</b>: Query list to free
> + *
> + * @since 0.7.0
> + */
> +void URI_FUNC(FreeQueryList)(URI_TYPE(QueryList) * queryList);
> +
> +
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +
> +
> +#endif
> +#endif
> diff --git a/uriparser/include/uriparser/UriBase.h b/uriparser/include/uriparser/UriBase.h
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/include/uriparser/UriBase.h
> @@ -0,0 +1,188 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 UriBase.h
> + * Holds definitions independent of the encoding pass.
> + */
> +
> +#ifndef URI_BASE_H
> +#define URI_BASE_H 1
> +
> +
> +
> +/* Version helper macro */
> +#define URI_ANSI_TO_UNICODE(x) L##x
> +
> +
> +
> +/* Version */
> +#define URI_VER_MAJOR           0
> +#define URI_VER_MINOR           7
> +#define URI_VER_RELEASE         5
> +#define URI_VER_SUFFIX_ANSI     ""
> +#define URI_VER_SUFFIX_UNICODE  URI_ANSI_TO_UNICODE(URI_VER_SUFFIX_ANSI)
> +
> +
> +
> +/* More version helper macros */
> +#define URI_INT_TO_ANSI_HELPER(x) #x
> +#define URI_INT_TO_ANSI(x) URI_INT_TO_ANSI_HELPER(x)
> +
> +#define URI_INT_TO_UNICODE_HELPER(x) URI_ANSI_TO_UNICODE(#x)
> +#define URI_INT_TO_UNICODE(x) URI_INT_TO_UNICODE_HELPER(x)
> +
> +#define URI_VER_ANSI_HELPER(ma, mi, r, s) \
> +	URI_INT_TO_ANSI(ma) "." \
> +	URI_INT_TO_ANSI(mi) "." \
> +	URI_INT_TO_ANSI(r) \
> +	s
> +
> +#define URI_VER_UNICODE_HELPER(ma, mi, r, s) \
> +	URI_INT_TO_UNICODE(ma) L"." \
> +	URI_INT_TO_UNICODE(mi) L"." \
> +	URI_INT_TO_UNICODE(r) \
> +	s
> +
> +
> +
> +/* Full version strings */
> +#define URI_VER_ANSI     URI_VER_ANSI_HELPER(URI_VER_MAJOR, URI_VER_MINOR, URI_VER_RELEASE, URI_VER_SUFFIX_ANSI)
> +#define URI_VER_UNICODE  URI_VER_UNICODE_HELPER(URI_VER_MAJOR, URI_VER_MINOR, URI_VER_RELEASE, URI_VER_SUFFIX_UNICODE)
> +
> +
> +
> +/* Unused parameter macro */
> +#ifdef __GNUC__
> +# define URI_UNUSED(x) unused_##x __attribute__((unused))
> +#else
> +# define URI_UNUSED(x) x
> +#endif
> +
> +
> +
> +typedef int UriBool; /**< Boolean type */
> +
> +#define URI_TRUE     1
> +#define URI_FALSE    0
> +
> +
> +
> +/* Shared errors */
> +#define URI_SUCCESS                        0
> +#define URI_ERROR_SYNTAX                   1 /* Parsed text violates expected format */
> +#define URI_ERROR_NULL                     2 /* One of the params passed was NULL
> +                                                although it mustn't be */
> +#define URI_ERROR_MALLOC                   3 /* Requested memory could not be allocated */
> +#define URI_ERROR_OUTPUT_TOO_LARGE         4 /* Some output is to large for the receiving buffer */
> +#define URI_ERROR_NOT_IMPLEMENTED          8 /* The called function is not implemented yet */
> +#define URI_ERROR_RANGE_INVALID            9 /* The parameters passed contained invalid ranges */
> +
> +
> +/* Errors specific to ToString */
> +#define URI_ERROR_TOSTRING_TOO_LONG        URI_ERROR_OUTPUT_TOO_LARGE /* Deprecated, test for URI_ERROR_OUTPUT_TOO_LARGE instead */
> +
> +/* Errors specific to AddBaseUri */
> +#define URI_ERROR_ADDBASE_REL_BASE         5 /* Given base is not absolute */
> +
> +/* Errors specific to RemoveBaseUri */
> +#define URI_ERROR_REMOVEBASE_REL_BASE      6 /* Given base is not absolute */
> +#define URI_ERROR_REMOVEBASE_REL_SOURCE    7 /* Given base is not absolute */
> +
> +
> +
> +#ifndef URI_DOXYGEN
> +# include <stdio.h> /* For NULL, snprintf */
> +# include <ctype.h> /* For wchar_t */
> +# include <string.h> /* For strlen, memset, memcpy */
> +# include <stdlib.h> /* For malloc */
> +#endif /* URI_DOXYGEN */
> +
> +
> +
> +/**
> + * Holds an IPv4 address.
> + */
> +typedef struct UriIp4Struct {
> +	unsigned char data[4]; /**< Each octet in one byte */
> +} UriIp4; /**< @copydoc UriIp4Struct */
> +
> +
> +
> +/**
> + * Holds an IPv6 address.
> + */
> +typedef struct UriIp6Struct {
> +	unsigned char data[16]; /**< Each quad in two bytes */
> +} UriIp6; /**< @copydoc UriIp6Struct */
> +
> +
> +
> +/**
> + * Specifies a line break conversion mode
> + */
> +typedef enum UriBreakConversionEnum {
> +	URI_BR_TO_LF, /**< Convert to Unix line breaks ("\\x0a") */
> +	URI_BR_TO_CRLF, /**< Convert to Windows line breaks ("\\x0d\\x0a") */
> +	URI_BR_TO_CR, /**< Convert to Macintosh line breaks ("\\x0d") */
> +	URI_BR_TO_UNIX = URI_BR_TO_LF, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_LF */
> +	URI_BR_TO_WINDOWS = URI_BR_TO_CRLF, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_CRLF */
> +	URI_BR_TO_MAC = URI_BR_TO_CR, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_CR */
> +	URI_BR_DONT_TOUCH /**< Copy line breaks unmodified */
> +} UriBreakConversion; /**< @copydoc UriBreakConversionEnum */
> +
> +
> +
> +/**
> + * Specifies which component of a %URI has to be normalized.
> + */
> +typedef enum UriNormalizationMaskEnum {
> +	URI_NORMALIZED = 0, /**< Do not normalize anything */
> +	URI_NORMALIZE_SCHEME = 1 << 0, /**< Normalize scheme (fix uppercase letters) */
> +	URI_NORMALIZE_USER_INFO = 1 << 1, /**< Normalize user info (fix uppercase percent-encodings) */
> +	URI_NORMALIZE_HOST = 1 << 2, /**< Normalize host (fix uppercase letters) */
> +	URI_NORMALIZE_PATH = 1 << 3, /**< Normalize path (fix uppercase percent-encodings and redundant dot segments) */
> +	URI_NORMALIZE_QUERY = 1 << 4, /**< Normalize query (fix uppercase percent-encodings) */
> +	URI_NORMALIZE_FRAGMENT = 1 << 5 /**< Normalize fragment (fix uppercase percent-encodings) */
> +} UriNormalizationMask; /**< @copydoc UriNormalizationMaskEnum */
> +
> +
> +
> +#endif /* URI_BASE_H */
> +
> diff --git a/uriparser/include/uriparser/UriDefsAnsi.h b/uriparser/include/uriparser/UriDefsAnsi.h
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/include/uriparser/UriDefsAnsi.h
> @@ -0,0 +1,82 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 UriDefsAnsi.h
> + * Holds definitions for the ANSI pass.
> + * NOTE: This header is included N times, not once.
> + */
> +
> +/* Allow multi inclusion */
> +#include "UriDefsConfig.h"
> +
> +
> +
> +#undef URI_CHAR
> +#define URI_CHAR char
> +
> +#undef _UT
> +#define _UT(x) x
> +
> +
> +
> +#undef URI_FUNC
> +#define URI_FUNC(x) uri##x##A
> +
> +#undef URI_TYPE
> +#define URI_TYPE(x) Uri##x##A
> +
> +
> +
> +#undef URI_STRLEN
> +#define URI_STRLEN strlen
> +#undef URI_STRCPY
> +#define URI_STRCPY strcpy
> +#undef URI_STRCMP
> +#define URI_STRCMP strcmp
> +#undef URI_STRNCMP
> +#define URI_STRNCMP strncmp
> +
> +/* TODO Remove on next source-compatibility break */
> +#undef URI_SNPRINTF
> +#if (defined(__WIN32__) || defined(_WIN32) || defined(WIN32))
> +# define URI_SNPRINTF _snprintf
> +#else
> +# define URI_SNPRINTF snprintf
> +#endif
> diff --git a/uriparser/include/uriparser/UriDefsConfig.h b/uriparser/include/uriparser/UriDefsConfig.h
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/include/uriparser/UriDefsConfig.h
> @@ -0,0 +1,105 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 UriDefsConfig.h
> + * Adjusts the internal configuration after processing external definitions.
> + */
> +
> +#ifndef URI_DEFS_CONFIG_H
> +#define URI_DEFS_CONFIG_H 1
> +
> +
> +
> +/* Deny external overriding */
> +#undef URI_ENABLE_ANSI      /* Internal for !URI_NO_ANSI */
> +#undef URI_ENABLE_UNICODE   /* Internal for !URI_NO_UNICODE */
> +
> +
> +
> +/* Encoding */
> +#ifdef URI_NO_ANSI
> +# ifdef URI_NO_UNICODE
> +/* No encoding at all */
> +#  error URI_NO_ANSI and URI_NO_UNICODE cannot go together.
> +# else
> +/* Unicode only */
> +#  define URI_ENABLE_UNICODE   1
> +# endif
> +#else
> +# ifdef URI_NO_UNICODE
> +/* ANSI only */
> +#  define URI_ENABLE_ANSI       1
> +# else
> +/* Both ANSI and Unicode */
> +#  define URI_ENABLE_ANSI       1
> +#  define URI_ENABLE_UNICODE    1
> +# endif
> +#endif
> +
> +
> +
> +/* Function inlining, not ANSI/ISO C! */
> +#if (defined(URI_DOXYGEN) || defined(URI_SIZEDOWN))
> +# define URI_INLINE
> +#elif defined(__INTEL_COMPILER)
> +/* Intel C/C++ */
> +/* http://predef.sourceforge.net/precomp.html#sec20 */
> +/* http://www.intel.com/support/performancetools/c/windows/sb/CS-007751.htm#2 */
> +# define URI_INLINE __force_inline
> +#elif defined(_MSC_VER)
> +/* Microsoft Visual C++ */
> +/* http://predef.sourceforge.net/precomp.html#sec32 */
> +/* http://msdn2.microsoft.com/en-us/library/ms882281.aspx */
> +# define URI_INLINE __forceinline
> +#elif (__GNUC__ >= 4)
> +/* GCC C/C++ 4.x.x */
> +/* http://predef.sourceforge.net/precomp.html#sec13 */
> +# define URI_INLINE __attribute__((always_inline))
> +#elif (__STDC_VERSION__ >= 199901L)
> +/* C99, "inline" is a keyword */
> +# define URI_INLINE inline
> +#else
> +/* No inlining */
> +# define URI_INLINE
> +#endif
> +
> +
> +
> +#endif /* URI_DEFS_CONFIG_H */
> diff --git a/uriparser/include/uriparser/UriDefsUnicode.h b/uriparser/include/uriparser/UriDefsUnicode.h
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/include/uriparser/UriDefsUnicode.h
> @@ -0,0 +1,82 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 UriDefsUnicode.h
> + * Holds definitions for the Unicode pass.
> + * NOTE: This header is included N times, not once.
> + */
> +
> +/* Allow multi inclusion */
> +#include "UriDefsConfig.h"
> +
> +
> +
> +#undef URI_CHAR
> +#define URI_CHAR wchar_t
> +
> +#undef _UT
> +#define _UT(x) L##x
> +
> +
> +
> +#undef URI_FUNC
> +#define URI_FUNC(x) uri##x##W
> +
> +#undef URI_TYPE
> +#define URI_TYPE(x) Uri##x##W
> +
> +
> +
> +#undef URI_STRLEN
> +#define URI_STRLEN wcslen
> +#undef URI_STRCPY
> +#define URI_STRCPY wcscpy
> +#undef URI_STRCMP
> +#define URI_STRCMP wcscmp
> +#undef URI_STRNCMP
> +#define URI_STRNCMP wcsncmp
> +
> +/* TODO Remove on next source-compatibility break */
> +#undef URI_SNPRINTF
> +#if (defined(__WIN32__) || defined(_WIN32) || defined(WIN32))
> +# define URI_SNPRINTF _snwprintf
> +#else
> +# define URI_SNPRINTF swprintf
> +#endif
> diff --git a/uriparser/include/uriparser/UriIp4.h b/uriparser/include/uriparser/UriIp4.h
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/include/uriparser/UriIp4.h
> @@ -0,0 +1,87 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 UriIp4.h
> + * Holds the IPv4 parser interface.
> + * NOTE: This header includes itself twice.
> + */
> +
> +#if (defined(URI_PASS_ANSI) && !defined(URI_IP4_TWICE_H_ANSI)) \
> +	|| (defined(URI_PASS_UNICODE) && !defined(URI_IP4_TWICE_H_UNICODE)) \
> +	|| (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
> +/* 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 "UriIp4.h"
> +# undef URI_PASS_ANSI
> +# define URI_PASS_UNICODE 1
> +# include "UriIp4.h"
> +# undef URI_PASS_UNICODE
> +/* Only one pass for each encoding */
> +#elif (defined(URI_PASS_ANSI) && !defined(URI_IP4_TWICE_H_ANSI) \
> +	&& defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \
> +	&& !defined(URI_IP4_TWICE_H_UNICODE) && defined(URI_ENABLE_UNICODE))
> +# ifdef URI_PASS_ANSI
> +#  define URI_IP4_TWICE_H_ANSI 1
> +#  include "UriDefsAnsi.h"
> +# else
> +#  define URI_IP4_TWICE_H_UNICODE 1
> +#  include "UriDefsUnicode.h"
> +# endif
> +
> +
> +
> +/**
> + * Converts a IPv4 text representation into four bytes.
> + *
> + * @param octetOutput  Output destination
> + * @param first        First character of IPv4 text to parse
> + * @param afterLast    Position to stop parsing at
> + * @return Error code or 0 on success
> + */
> +int URI_FUNC(ParseIpFourAddress)(unsigned char * octetOutput,
> +		const URI_CHAR * first, const URI_CHAR * afterLast);
> +
> +
> +
> +#endif
> +#endif
> diff --git a/uriparser/lib/UriCommon.c b/uriparser/lib/UriCommon.c
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriCommon.c
> @@ -0,0 +1,527 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 <uriparser/UriDefsConfig.h>
> +#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
> +/* Include SELF twice */
> +# define URI_PASS_ANSI 1
> +# include "UriCommon.c"
> +# undef URI_PASS_ANSI
> +# define URI_PASS_UNICODE 1
> +# include "UriCommon.c"
> +# undef URI_PASS_UNICODE
> +#else
> +# ifdef URI_PASS_ANSI
> +#  include <uriparser/UriDefsAnsi.h>
> +# else
> +#  include <uriparser/UriDefsUnicode.h>
> +#  include <wchar.h>
> +# endif
> +
> +
> +
> +#ifndef URI_DOXYGEN
> +# include <uriparser/Uri.h>
> +# include "UriCommon.h"
> +#endif
> +
> +
> +
> +/*extern*/ const URI_CHAR * const URI_FUNC(SafeToPointTo) = _UT("X");
> +/*extern*/ const URI_CHAR * const URI_FUNC(ConstPwd) = _UT(".");
> +/*extern*/ const URI_CHAR * const URI_FUNC(ConstParent) = _UT("..");
> +
> +
> +
> +void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri) {
> +	memset(uri, 0, sizeof(URI_TYPE(Uri)));
> +}
> +
> +
> +
> +/* Properly removes "." and ".." path segments */
> +UriBool URI_FUNC(RemoveDotSegments)(URI_TYPE(Uri) * uri,
> +		UriBool relative) {
> +	if (uri == NULL) {
> +		return URI_TRUE;
> +	}
> +	return URI_FUNC(RemoveDotSegmentsEx)(uri, relative, uri->owner);
> +}
> +
> +
> +
> +UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri,
> +        UriBool relative, UriBool pathOwned) {
> +	URI_TYPE(PathSegment) * walker;
> +	if ((uri == NULL) || (uri->pathHead == NULL)) {
> +		return URI_TRUE;
> +	}
> +
> +	walker = uri->pathHead;
> +	walker->reserved = NULL; /* Prev pointer */
> +	do {
> +		UriBool removeSegment = URI_FALSE;
> +		int len = (int)(walker->text.afterLast - walker->text.first);
> +		switch (len) {
> +		case 1:
> +			if ((walker->text.first)[0] == _UT('.')) {
> +				/* "." segment -> remove if not essential */
> +				URI_TYPE(PathSegment) * const prev = walker->reserved;
> +				URI_TYPE(PathSegment) * const nextBackup = walker->next;
> +
> +				/* Is this dot segment essential? */
> +				removeSegment = URI_TRUE;
> +				if (relative && (walker == uri->pathHead) && (walker->next != NULL)) {
> +					const URI_CHAR * ch = walker->next->text.first;
> +					for (; ch < walker->next->text.afterLast; ch++) {
> +						if (*ch == _UT(':')) {
> +							removeSegment = URI_FALSE;
> +							break;
> +						}
> +					}
> +				}
> +
> +				if (removeSegment) {
> +					/* Last segment? */
> +					if (walker->next != NULL) {
> +						/* Not last segment */
> +						walker->next->reserved = prev;
> +
> +						if (prev == NULL) {
> +							/* First but not last segment */
> +							uri->pathHead = walker->next;
> +						} else {
> +							/* Middle segment */
> +							prev->next = walker->next;
> +						}
> +
> +						if (pathOwned && (walker->text.first != walker->text.afterLast)) {
> +							free((URI_CHAR *)walker->text.first);
> +						}
> +						free(walker);
> +					} else {
> +						/* Last segment */
> +						if (pathOwned && (walker->text.first != walker->text.afterLast)) {
> +							free((URI_CHAR *)walker->text.first);
> +						}
> +
> +						if (prev == NULL) {
> +							/* Last and first */
> +							if (URI_FUNC(IsHostSet)(uri)) {
> +								/* Replace "." with empty segment to represent trailing slash */
> +								walker->text.first = URI_FUNC(SafeToPointTo);
> +								walker->text.afterLast = URI_FUNC(SafeToPointTo);
> +							} else {
> +								free(walker);
> +
> +								uri->pathHead = NULL;
> +								uri->pathTail = NULL;
> +							}
> +						} else {
> +							/* Last but not first, replace "." with empty segment to represent trailing slash */
> +							walker->text.first = URI_FUNC(SafeToPointTo);
> +							walker->text.afterLast = URI_FUNC(SafeToPointTo);
> +						}
> +					}
> +
> +					walker = nextBackup;
> +				}
> +			}
> +			break;
> +
> +		case 2:
> +			if (((walker->text.first)[0] == _UT('.'))
> +					&& ((walker->text.first)[1] == _UT('.'))) {
> +				/* Path ".." -> remove this and the previous segment */
> +				URI_TYPE(PathSegment) * const prev = walker->reserved;
> +				URI_TYPE(PathSegment) * prevPrev;
> +				URI_TYPE(PathSegment) * const nextBackup = walker->next;
> +
> +				removeSegment = URI_TRUE;
> +				if (relative) {
> +					if (prev == NULL) {
> +						removeSegment = URI_FALSE;
> +					} else if ((prev != NULL)
> +							&& ((prev->text.afterLast - prev->text.first) == 2)
> +							&& ((prev->text.first)[0] == _UT('.'))
> +							&& ((prev->text.first)[1] == _UT('.'))) {
> +						removeSegment = URI_FALSE;
> +					}
> +				}
> +
> +				if (removeSegment) {
> +					if (prev != NULL) {
> +						/* Not first segment */
> +						prevPrev = prev->reserved;
> +						if (prevPrev != NULL) {
> +							/* Not even prev is the first one */
> +							prevPrev->next = walker->next;
> +							if (walker->next != NULL) {
> +								walker->next->reserved = prevPrev;
> +							} else {
> +								/* Last segment -> insert "" segment to represent trailing slash, update tail */
> +								URI_TYPE(PathSegment) * const segment = malloc(1 * sizeof(URI_TYPE(PathSegment)));
> +								if (segment == NULL) {
> +									if (pathOwned && (walker->text.first != walker->text.afterLast)) {
> +										free((URI_CHAR *)walker->text.first);
> +									}
> +									free(walker);
> +
> +									if (pathOwned && (prev->text.first != prev->text.afterLast)) {
> +										free((URI_CHAR *)prev->text.first);
> +									}
> +									free(prev);
> +
> +									return URI_FALSE; /* Raises malloc error */
> +								}
> +								memset(segment, 0, sizeof(URI_TYPE(PathSegment)));
> +								segment->text.first = URI_FUNC(SafeToPointTo);
> +								segment->text.afterLast = URI_FUNC(SafeToPointTo);
> +								prevPrev->next = segment;
> +								uri->pathTail = segment;
> +							}
> +
> +							if (pathOwned && (walker->text.first != walker->text.afterLast)) {
> +								free((URI_CHAR *)walker->text.first);
> +							}
> +							free(walker);
> +
> +							if (pathOwned && (prev->text.first != prev->text.afterLast)) {
> +								free((URI_CHAR *)prev->text.first);
> +							}
> +							free(prev);
> +
> +							walker = nextBackup;
> +						} else {
> +							/* Prev is the first segment */
> +							if (walker->next != NULL) {
> +								uri->pathHead = walker->next;
> +								walker->next->reserved = NULL;
> +
> +								if (pathOwned && (walker->text.first != walker->text.afterLast)) {
> +									free((URI_CHAR *)walker->text.first);
> +								}
> +								free(walker);
> +							} else {
> +								/* Re-use segment for "" path segment to represent trailing slash, update tail */
> +								URI_TYPE(PathSegment) * const segment = walker;
> +								if (pathOwned && (segment->text.first != segment->text.afterLast)) {
> +									free((URI_CHAR *)segment->text.first);
> +								}
> +								segment->text.first = URI_FUNC(SafeToPointTo);
> +								segment->text.afterLast = URI_FUNC(SafeToPointTo);
> +								uri->pathHead = segment;
> +								uri->pathTail = segment;
> +							}
> +
> +							if (pathOwned && (prev->text.first != prev->text.afterLast)) {
> +								free((URI_CHAR *)prev->text.first);
> +							}
> +							free(prev);
> +
> +							walker = nextBackup;
> +						}
> +					} else {
> +						URI_TYPE(PathSegment) * const nextBackup = walker->next;
> +						/* First segment -> update head pointer */
> +						uri->pathHead = walker->next;
> +						if (walker->next != NULL) {
> +							walker->next->reserved = NULL;
> +						} else {
> +							/* Last segment -> update tail */
> +							uri->pathTail = NULL;
> +						}
> +
> +						if (pathOwned && (walker->text.first != walker->text.afterLast)) {
> +							free((URI_CHAR *)walker->text.first);
> +						}
> +						free(walker);
> +
> +						walker = nextBackup;
> +					}
> +				}
> +			}
> +			break;
> +
> +		}
> +
> +		if (!removeSegment) {
> +			if (walker->next != NULL) {
> +				walker->next->reserved = walker;
> +			} else {
> +				/* Last segment -> update tail */
> +				uri->pathTail = walker;
> +			}
> +			walker = walker->next;
> +		}
> +	} while (walker != NULL);
> +
> +	return URI_TRUE;
> +}
> +
> +
> +
> +/* Properly removes "." and ".." path segments */
> +UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri) {
> +	const UriBool ABSOLUTE = URI_FALSE;
> +	return URI_FUNC(RemoveDotSegments)(uri, ABSOLUTE);
> +}
> +
> +
> +
> +unsigned char URI_FUNC(HexdigToInt)(URI_CHAR hexdig) {
> +	switch (hexdig) {
> +	case _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'):
> +		return (unsigned char)(9 + hexdig - _UT('9'));
> +
> +	case _UT('a'):
> +	case _UT('b'):
> +	case _UT('c'):
> +	case _UT('d'):
> +	case _UT('e'):
> +	case _UT('f'):
> +		return (unsigned char)(15 + hexdig - _UT('f'));
> +
> +	case _UT('A'):
> +	case _UT('B'):
> +	case _UT('C'):
> +	case _UT('D'):
> +	case _UT('E'):
> +	case _UT('F'):
> +		return (unsigned char)(15 + hexdig - _UT('F'));
> +
> +	default:
> +		return 0;
> +	}
> +}
> +
> +
> +
> +URI_CHAR URI_FUNC(HexToLetter)(unsigned int value) {
> +	/* Uppercase recommended in section 2.1. of RFC 3986 *
> +	 * http://tools.ietf.org/html/rfc3986#section-2.1    */
> +	return URI_FUNC(HexToLetterEx)(value, URI_TRUE);
> +}
> +
> +
> +
> +URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase) {
> +	switch (value) {
> +	case  0: return _UT('0');
> +	case  1: return _UT('1');
> +	case  2: return _UT('2');
> +	case  3: return _UT('3');
> +	case  4: return _UT('4');
> +	case  5: return _UT('5');
> +	case  6: return _UT('6');
> +	case  7: return _UT('7');
> +	case  8: return _UT('8');
> +	case  9: return _UT('9');
> +
> +	case 10: return (uppercase == URI_TRUE) ? _UT('A') : _UT('a');
> +	case 11: return (uppercase == URI_TRUE) ? _UT('B') : _UT('b');
> +	case 12: return (uppercase == URI_TRUE) ? _UT('C') : _UT('c');
> +	case 13: return (uppercase == URI_TRUE) ? _UT('D') : _UT('d');
> +	case 14: return (uppercase == URI_TRUE) ? _UT('E') : _UT('e');
> +	default: return (uppercase == URI_TRUE) ? _UT('F') : _UT('f');
> +	}
> +}
> +
> +
> +
> +/* Checks if a URI has the host component set. */
> +UriBool URI_FUNC(IsHostSet)(const URI_TYPE(Uri) * uri) {
> +	return (uri != NULL)
> +			&& ((uri->hostText.first != NULL)
> +				|| (uri->hostData.ip4 != NULL)
> +				|| (uri->hostData.ip6 != NULL)
> +				|| (uri->hostData.ipFuture.first != NULL)
> +			);
> +}
> +
> +
> +
> +/* Copies the path segment list from one URI to another. */
> +UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest,
> +		const URI_TYPE(Uri) * source) {
> +	if (source->pathHead == NULL) {
> +		/* No path component */
> +		dest->pathHead = NULL;
> +		dest->pathTail = NULL;
> +	} else {
> +		/* Copy list but not the text contained */
> +		URI_TYPE(PathSegment) * sourceWalker = source->pathHead;
> +		URI_TYPE(PathSegment) * destPrev = NULL;
> +		do {
> +			URI_TYPE(PathSegment) * cur = malloc(sizeof(URI_TYPE(PathSegment)));
> +			if (cur == NULL) {
> +				/* Fix broken list */
> +				if (destPrev != NULL) {
> +					destPrev->next = NULL;
> +				}
> +				return URI_FALSE; /* Raises malloc error */
> +			}
> +
> +			/* From this functions usage we know that *
> +			 * the dest URI cannot be uri->owner      */
> +			cur->text = sourceWalker->text;
> +			if (destPrev == NULL) {
> +				/* First segment ever */
> +				dest->pathHead = cur;
> +			} else {
> +				destPrev->next = cur;
> +			}
> +			destPrev = cur;
> +			sourceWalker = sourceWalker->next;
> +		} while (sourceWalker != NULL);
> +		dest->pathTail = destPrev;
> +		dest->pathTail->next = NULL;
> +	}
> +
> +	dest->absolutePath = source->absolutePath;
> +	return URI_TRUE;
> +}
> +
> +
> +
> +/* Copies the authority part of an URI over to another. */
> +UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest,
> +		const URI_TYPE(Uri) * source) {
> +	/* From this functions usage we know that *
> +	 * the dest URI cannot be uri->owner      */
> +
> +	/* Copy userInfo */
> +	dest->userInfo = source->userInfo;
> +
> +	/* Copy hostText */
> +	dest->hostText = source->hostText;
> +
> +	/* Copy hostData */
> +	if (source->hostData.ip4 != NULL) {
> +		dest->hostData.ip4 = malloc(sizeof(UriIp4));
> +		if (dest->hostData.ip4 == NULL) {
> +			return URI_FALSE; /* Raises malloc error */
> +		}
> +		*(dest->hostData.ip4) = *(source->hostData.ip4);
> +		dest->hostData.ip6 = NULL;
> +		dest->hostData.ipFuture.first = NULL;
> +		dest->hostData.ipFuture.afterLast = NULL;
> +	} else if (source->hostData.ip6 != NULL) {
> +		dest->hostData.ip4 = NULL;
> +		dest->hostData.ip6 = malloc(sizeof(UriIp6));
> +		if (dest->hostData.ip6 == NULL) {
> +			return URI_FALSE; /* Raises malloc error */
> +		}
> +		*(dest->hostData.ip6) = *(source->hostData.ip6);
> +		dest->hostData.ipFuture.first = NULL;
> +		dest->hostData.ipFuture.afterLast = NULL;
> +	} else {
> +		dest->hostData.ip4 = NULL;
> +		dest->hostData.ip6 = NULL;
> +		dest->hostData.ipFuture = source->hostData.ipFuture;
> +	}
> +
> +	/* Copy portText */
> +	dest->portText = source->portText;
> +
> +	return URI_TRUE;
> +}
> +
> +
> +
> +UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri) {
> +	URI_TYPE(PathSegment) * segment;
> +
> +	if (	/* Case 1: absolute path, empty first segment */
> +			(uri->absolutePath
> +			&& (uri->pathHead != NULL)
> +			&& (uri->pathHead->text.afterLast == uri->pathHead->text.first))
> +
> +			/* Case 2: relative path, empty first and second segment */
> +			|| (!uri->absolutePath
> +			&& (uri->pathHead != NULL)
> +			&& (uri->pathHead->next != NULL)
> +			&& (uri->pathHead->text.afterLast == uri->pathHead->text.first)
> +			&& (uri->pathHead->next->text.afterLast == uri->pathHead->next->text.first))) {
> +		/* NOOP */
> +	} else {
> +		return URI_TRUE;
> +	}
> +
> +	segment = malloc(1 * sizeof(URI_TYPE(PathSegment)));
> +	if (segment == NULL) {
> +		return URI_FALSE; /* Raises malloc error */
> +	}
> +
> +	/* Insert "." segment in front */
> +	segment->next = uri->pathHead;
> +	segment->text.first = URI_FUNC(ConstPwd);
> +	segment->text.afterLast = URI_FUNC(ConstPwd) + 1;
> +	uri->pathHead = segment;
> +	return URI_TRUE;
> +}
> +
> +
> +
> +void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri) {
> +	/* Fix path if only one empty segment */
> +	if (!uri->absolutePath
> +			&& !URI_FUNC(IsHostSet)(uri)
> +			&& (uri->pathHead != NULL)
> +			&& (uri->pathHead->next == NULL)
> +			&& (uri->pathHead->text.first == uri->pathHead->text.afterLast)) {
> +		free(uri->pathHead);
> +		uri->pathHead = NULL;
> +		uri->pathTail = NULL;
> +	}
> +}
> +
> +
> +
> +#endif
> diff --git a/uriparser/lib/UriCommon.h b/uriparser/lib/UriCommon.h
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriCommon.h
> @@ -0,0 +1,96 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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.
> + */
> +
> +#if (defined(URI_PASS_ANSI) && !defined(URI_COMMON_H_ANSI)) \
> +	|| (defined(URI_PASS_UNICODE) && !defined(URI_COMMON_H_UNICODE)) \
> +	|| (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
> +/* What encodings are enabled? */
> +#include <uriparser/UriDefsConfig.h>
> +#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
> +/* Include SELF twice */
> +# define URI_PASS_ANSI 1
> +# include "UriCommon.h"
> +# undef URI_PASS_ANSI
> +# define URI_PASS_UNICODE 1
> +# include "UriCommon.h"
> +# undef URI_PASS_UNICODE
> +/* Only one pass for each encoding */
> +#elif (defined(URI_PASS_ANSI) && !defined(URI_COMMON_H_ANSI) \
> +	&& defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \
> +	&& !defined(URI_COMMON_H_UNICODE) && defined(URI_ENABLE_UNICODE))
> +# ifdef URI_PASS_ANSI
> +#  define URI_COMMON_H_ANSI 1
> +#  include <uriparser/UriDefsAnsi.h>
> +# else
> +#  define URI_COMMON_H_UNICODE 1
> +#  include <uriparser/UriDefsUnicode.h>
> +# endif
> +
> +
> +
> +/* Used to point to from empty path segments.
> + * X.first and X.afterLast must be the same non-NULL value then. */
> +extern const URI_CHAR * const URI_FUNC(SafeToPointTo);
> +extern const URI_CHAR * const URI_FUNC(ConstPwd);
> +extern const URI_CHAR * const URI_FUNC(ConstParent);
> +
> +
> +
> +void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri);
> +
> +UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri);
> +UriBool URI_FUNC(RemoveDotSegments)(URI_TYPE(Uri) * uri, UriBool relative);
> +UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri,
> +        UriBool relative, UriBool pathOwned);
> +
> +unsigned char URI_FUNC(HexdigToInt)(URI_CHAR hexdig);
> +URI_CHAR URI_FUNC(HexToLetter)(unsigned int value);
> +URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase);
> +
> +UriBool URI_FUNC(IsHostSet)(const URI_TYPE(Uri) * uri);
> +
> +UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source);
> +UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source);
> +
> +UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri);
> +void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri);
> +
> +
> +#endif
> +#endif
> diff --git a/uriparser/lib/UriCompare.c b/uriparser/lib/UriCompare.c
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriCompare.c
> @@ -0,0 +1,191 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 <uriparser/UriDefsConfig.h>
> +#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
> +/* Include SELF twice */
> +# define URI_PASS_ANSI 1
> +# include "UriCompare.c"
> +# undef URI_PASS_ANSI
> +# define URI_PASS_UNICODE 1
> +# include "UriCompare.c"
> +# undef URI_PASS_UNICODE
> +#else
> +# ifdef URI_PASS_ANSI
> +#  include <uriparser/UriDefsAnsi.h>
> +# else
> +#  include <uriparser/UriDefsUnicode.h>
> +#  include <wchar.h>
> +# endif
> +
> +
> +
> +#ifndef URI_DOXYGEN
> +# include <uriparser/Uri.h>
> +# include <uriparser/UriIp4.h>
> +# include "UriCommon.h"
> +#endif
> +
> +
> +
> +static int URI_FUNC(CompareRange)(const URI_TYPE(TextRange) * a,
> +		const URI_TYPE(TextRange) * b);
> +
> +
> +
> +/* Compares two text ranges for equal text content */
> +static URI_INLINE int URI_FUNC(CompareRange)(const URI_TYPE(TextRange) * a,
> +		const URI_TYPE(TextRange) * b) {
> +	int diff;
> +
> +	/* NOTE: Both NULL means equal! */
> +	if ((a == NULL) || (b == NULL)) {
> +		return ((a == NULL) && (b == NULL)) ? URI_TRUE : URI_FALSE;
> +	}
> +
> +	diff = ((int)(a->afterLast - a->first) - (int)(b->afterLast - b->first));
> +	if (diff > 0) {
> +		return 1;
> +	} else if (diff < 0) {
> +		return -1;
> +	}
> +
> +	return URI_STRNCMP(a->first, b->first, (a->afterLast - a->first));
> +}
> +
> +
> +
> +UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a,
> +		const URI_TYPE(Uri) * b) {
> +	/* NOTE: Both NULL means equal! */
> +	if ((a == NULL) || (b == NULL)) {
> +		return ((a == NULL) && (b == NULL)) ? URI_TRUE : URI_FALSE;
> +	}
> +
> +	/* scheme */
> +	if (URI_FUNC(CompareRange)(&(a->scheme), &(b->scheme))) {
> +		return URI_FALSE;
> +	}
> +
> +	/* absolutePath */
> +	if ((a->scheme.first == NULL)&& (a->absolutePath != b->absolutePath)) {
> +		return URI_FALSE;
> +	}
> +
> +	/* userInfo */
> +	if (URI_FUNC(CompareRange)(&(a->userInfo), &(b->userInfo))) {
> +		return URI_FALSE;
> +	}
> +
> +	/* Host */
> +	if (((a->hostData.ip4 == NULL) != (b->hostData.ip4 == NULL))
> +			|| ((a->hostData.ip6 == NULL) != (b->hostData.ip6 == NULL))
> +			|| ((a->hostData.ipFuture.first == NULL)
> +				!= (b->hostData.ipFuture.first == NULL))) {
> +		return URI_FALSE;
> +	}
> +
> +	if (a->hostData.ip4 != NULL) {
> +		if (memcmp(a->hostData.ip4->data, b->hostData.ip4->data, 4)) {
> +			return URI_FALSE;
> +		}
> +	}
> +
> +	if (a->hostData.ip6 != NULL) {
> +		if (memcmp(a->hostData.ip6->data, b->hostData.ip6->data, 16)) {
> +			return URI_FALSE;
> +		}
> +	}
> +
> +	if (a->hostData.ipFuture.first != NULL) {
> +		if (URI_FUNC(CompareRange)(&(a->hostData.ipFuture), &(b->hostData.ipFuture))) {
> +			return URI_FALSE;
> +		}
> +	}
> +
> +	if ((a->hostData.ip4 == NULL)
> +			&& (a->hostData.ip6 == NULL)
> +			&& (a->hostData.ipFuture.first == NULL)) {
> +		if (URI_FUNC(CompareRange)(&(a->hostText), &(b->hostText))) {
> +			return URI_FALSE;
> +		}
> +	}
> +
> +	/* portText */
> +	if (URI_FUNC(CompareRange)(&(a->portText), &(b->portText))) {
> +		return URI_FALSE;
> +	}
> +
> +	/* Path */
> +	if ((a->pathHead == NULL) != (b->pathHead == NULL)) {
> +		return URI_FALSE;
> +	}
> +
> +	if (a->pathHead != NULL) {
> +		URI_TYPE(PathSegment) * walkA = a->pathHead;
> +		URI_TYPE(PathSegment) * walkB = b->pathHead;
> +		do {
> +			if (URI_FUNC(CompareRange)(&(walkA->text), &(walkB->text))) {
> +				return URI_FALSE;
> +			}
> +			if ((walkA->next == NULL) != (walkB->next == NULL)) {
> +				return URI_FALSE;
> +			}
> +			walkA = walkA->next;
> +			walkB = walkB->next;
> +		} while (walkA != NULL);
> +	}
> +
> +	/* query */
> +	if (URI_FUNC(CompareRange)(&(a->query), &(b->query))) {
> +		return URI_FALSE;
> +	}
> +
> +	/* fragment */
> +	if (URI_FUNC(CompareRange)(&(a->fragment), &(b->fragment))) {
> +		return URI_FALSE;
> +	}
> +
> +	return URI_TRUE; /* Equal*/
> +}
> +
> +
> +
> +#endif
> diff --git a/uriparser/lib/UriEscape.c b/uriparser/lib/UriEscape.c
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriEscape.c
> @@ -0,0 +1,449 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 <uriparser/UriDefsConfig.h>
> +#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
> +/* Include SELF twice */
> +# define URI_PASS_ANSI 1
> +# include "UriEscape.c"
> +# undef URI_PASS_ANSI
> +# define URI_PASS_UNICODE 1
> +# include "UriEscape.c"
> +# undef URI_PASS_UNICODE
> +#else
> +# ifdef URI_PASS_ANSI
> +#  include <uriparser/UriDefsAnsi.h>
> +# else
> +#  include <uriparser/UriDefsUnicode.h>
> +#  include <wchar.h>
> +# endif
> +
> +
> +
> +#ifndef URI_DOXYGEN
> +# include <uriparser/Uri.h>
> +# include "UriCommon.h"
> +#endif
> +
> +
> +
> +URI_CHAR * URI_FUNC(Escape)(const URI_CHAR * in, URI_CHAR * out,
> +		UriBool spaceToPlus, UriBool normalizeBreaks) {
> +	return URI_FUNC(EscapeEx)(in, NULL, out, spaceToPlus, normalizeBreaks);
> +}
> +
> +
> +
> +URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst,
> +		const URI_CHAR * inAfterLast, URI_CHAR * out,
> +		UriBool spaceToPlus, UriBool normalizeBreaks) {
> +	const URI_CHAR * read = inFirst;
> +	URI_CHAR * write = out;
> +	UriBool prevWasCr = URI_FALSE;
> +	if ((out == NULL) || (inFirst == out)) {
> +		return NULL;
> +	} else if (inFirst == NULL) {
> +		if (out != NULL) {
> +			out[0] = _UT('\0');
> +		}
> +		return out;
> +	}
> +
> +	for (;;) {
> +		if ((inAfterLast != NULL) && (read >= inAfterLast)) {
> +			write[0] = _UT('\0');
> +			return write;
> +		}
> +
> +		switch (read[0]) {
> +		case _UT('\0'):
> +			write[0] = _UT('\0');
> +			return write;
> +
> +		case _UT(' '):
> +			if (spaceToPlus) {
> +				write[0] = _UT('+');
> +				write++;
> +			} else {
> +				write[0] = _UT('%');
> +				write[1] = _UT('2');
> +				write[2] = _UT('0');
> +				write += 3;
> +			}
> +			prevWasCr = URI_FALSE;
> +			break;
> +
> +		case _UT('a'): /* ALPHA */
> +		case _UT('A'):
> +		case _UT('b'):
> +		case _UT('B'):
> +		case _UT('c'):
> +		case _UT('C'):
> +		case _UT('d'):
> +		case _UT('D'):
> +		case _UT('e'):
> +		case _UT('E'):
> +		case _UT('f'):
> +		case _UT('F'):
> +		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'):
> +		case _UT('0'): /* DIGIT */
> +		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'):
> +		case _UT('-'): /* "-" / "." / "_" / "~" */
> +		case _UT('.'):
> +		case _UT('_'):
> +		case _UT('~'):
> +			/* Copy unmodified */
> +			write[0] = read[0];
> +			write++;
> +
> +			prevWasCr = URI_FALSE;
> +			break;
> +
> +		case _UT('\x0a'):
> +			if (normalizeBreaks) {
> +				if (!prevWasCr) {
> +					write[0] = _UT('%');
> +					write[1] = _UT('0');
> +					write[2] = _UT('D');
> +					write[3] = _UT('%');
> +					write[4] = _UT('0');
> +					write[5] = _UT('A');
> +					write += 6;
> +				}
> +			} else {
> +				write[0] = _UT('%');
> +				write[1] = _UT('0');
> +				write[2] = _UT('A');
> +				write += 3;
> +			}
> +			prevWasCr = URI_FALSE;
> +			break;
> +
> +		case _UT('\x0d'):
> +			if (normalizeBreaks) {
> +				write[0] = _UT('%');
> +				write[1] = _UT('0');
> +				write[2] = _UT('D');
> +				write[3] = _UT('%');
> +				write[4] = _UT('0');
> +				write[5] = _UT('A');
> +				write += 6;
> +			} else {
> +				write[0] = _UT('%');
> +				write[1] = _UT('0');
> +				write[2] = _UT('D');
> +				write += 3;
> +			}
> +			prevWasCr = URI_TRUE;
> +			break;
> +
> +		default:
> +			/* Percent encode */
> +			{
> +				const unsigned char code = (unsigned char)read[0];
> +				write[0] = _UT('%');
> +				write[1] = URI_FUNC(HexToLetter)(code >> 4);
> +				write[2] = URI_FUNC(HexToLetter)(code & 0x0f);
> +				write += 3;
> +			}
> +			prevWasCr = URI_FALSE;
> +			break;
> +		}
> +
> +		read++;
> +	}
> +}
> +
> +
> +
> +const URI_CHAR * URI_FUNC(UnescapeInPlace)(URI_CHAR * inout) {
> +	return URI_FUNC(UnescapeInPlaceEx)(inout, URI_FALSE, URI_BR_DONT_TOUCH);
> +}
> +
> +
> +
> +const URI_CHAR * URI_FUNC(UnescapeInPlaceEx)(URI_CHAR * inout,
> +		UriBool plusToSpace, UriBreakConversion breakConversion) {
> +	URI_CHAR * read = inout;
> +	URI_CHAR * write = inout;
> +	UriBool prevWasCr = URI_FALSE;
> +
> +	if (inout == NULL) {
> +		return NULL;
> +	}
> +
> +	for (;;) {
> +		switch (read[0]) {
> +		case _UT('\0'):
> +			if (read > write) {
> +				write[0] = _UT('\0');
> +			}
> +			return write;
> +
> +		case _UT('%'):
> +			switch (read[1]) {
> +			case _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'):
> +			case _UT('a'):
> +			case _UT('b'):
> +			case _UT('c'):
> +			case _UT('d'):
> +			case _UT('e'):
> +			case _UT('f'):
> +			case _UT('A'):
> +			case _UT('B'):
> +			case _UT('C'):
> +			case _UT('D'):
> +			case _UT('E'):
> +			case _UT('F'):
> +				switch (read[2]) {
> +				case _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'):
> +				case _UT('a'):
> +				case _UT('b'):
> +				case _UT('c'):
> +				case _UT('d'):
> +				case _UT('e'):
> +				case _UT('f'):
> +				case _UT('A'):
> +				case _UT('B'):
> +				case _UT('C'):
> +				case _UT('D'):
> +				case _UT('E'):
> +				case _UT('F'):
> +					{
> +						/* Percent group found */
> +						const unsigned char left = URI_FUNC(HexdigToInt)(read[1]);
> +						const unsigned char right = URI_FUNC(HexdigToInt)(read[2]);
> +						const int code = 16 * left + right;
> +						switch (code) {
> +						case 10:
> +							switch (breakConversion) {
> +							case URI_BR_TO_LF:
> +								if (!prevWasCr) {
> +									write[0] = (URI_CHAR)10;
> +									write++;
> +								}
> +								break;
> +
> +							case URI_BR_TO_CRLF:
> +								if (!prevWasCr) {
> +									write[0] = (URI_CHAR)13;
> +									write[1] = (URI_CHAR)10;
> +									write += 2;
> +								}
> +								break;
> +
> +							case URI_BR_TO_CR:
> +								if (!prevWasCr) {
> +									write[0] = (URI_CHAR)13;
> +									write++;
> +								}
> +								break;
> +
> +							case URI_BR_DONT_TOUCH:
> +							default:
> +								write[0] = (URI_CHAR)10;
> +								write++;
> +
> +							}
> +							prevWasCr = URI_FALSE;
> +							break;
> +
> +						case 13:
> +							switch (breakConversion) {
> +							case URI_BR_TO_LF:
> +								write[0] = (URI_CHAR)10;
> +								write++;
> +								break;
> +
> +							case URI_BR_TO_CRLF:
> +								write[0] = (URI_CHAR)13;
> +								write[1] = (URI_CHAR)10;
> +								write += 2;
> +								break;
> +
> +							case URI_BR_TO_CR:
> +								write[0] = (URI_CHAR)13;
> +								write++;
> +								break;
> +
> +							case URI_BR_DONT_TOUCH:
> +							default:
> +								write[0] = (URI_CHAR)13;
> +								write++;
> +
> +							}
> +							prevWasCr = URI_TRUE;
> +							break;
> +
> +						default:
> +							write[0] = (URI_CHAR)(code);
> +							write++;
> +
> +							prevWasCr = URI_FALSE;
> +
> +						}
> +						read += 3;
> +					}
> +					break;
> +
> +				default:
> +					/* Copy two chars unmodified and */
> +					/* look at this char again */
> +					if (read > write) {
> +						write[0] = read[0];
> +						write[1] = read[1];
> +					}
> +					read += 2;
> +					write += 2;
> +
> +					prevWasCr = URI_FALSE;
> +				}
> +				break;
> +
> +			default:
> +				/* Copy one char unmodified and */
> +				/* look at this char again */
> +				if (read > write) {
> +					write[0] = read[0];
> +				}
> +				read++;
> +				write++;
> +
> +				prevWasCr = URI_FALSE;
> +			}
> +			break;
> +
> +		case _UT('+'):
> +			if (plusToSpace) {
> +				/* Convert '+' to ' ' */
> +				write[0] = _UT(' ');
> +			} else {
> +				/* Copy one char unmodified */
> +				if (read > write) {
> +					write[0] = read[0];
> +				}
> +			}
> +			read++;
> +			write++;
> +
> +			prevWasCr = URI_FALSE;
> +			break;
> +
> +		default:
> +			/* Copy one char unmodified */
> +			if (read > write) {
> +				write[0] = read[0];
> +			}
> +			read++;
> +			write++;
> +
> +			prevWasCr = URI_FALSE;
> +		}
> +	}
> +}
> +
> +
> +
> +#endif
> diff --git a/uriparser/lib/UriFile.c b/uriparser/lib/UriFile.c
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriFile.c
> @@ -0,0 +1,182 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 <uriparser/UriDefsConfig.h>
> +#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
> +/* Include SELF twice */
> +# define URI_PASS_ANSI 1
> +# include "UriFile.c"
> +# undef URI_PASS_ANSI
> +# define URI_PASS_UNICODE 1
> +# include "UriFile.c"
> +# undef URI_PASS_UNICODE
> +#else
> +# ifdef URI_PASS_ANSI
> +#  include <uriparser/UriDefsAnsi.h>
> +# else
> +#  include <uriparser/UriDefsUnicode.h>
> +#  include <wchar.h>
> +# endif
> +
> +
> +
> +#ifndef URI_DOXYGEN
> +# include <uriparser/Uri.h>
> +#endif
> +
> +
> +
> +static URI_INLINE int URI_FUNC(FilenameToUriString)(const URI_CHAR * filename,
> +		URI_CHAR * uriString, UriBool fromUnix) {
> +	const URI_CHAR * input = filename;
> +	const URI_CHAR * lastSep = input - 1;
> +	UriBool firstSegment = URI_TRUE;
> +	URI_CHAR * output = uriString;
> +	const UriBool absolute = (filename != NULL) && ((fromUnix && (filename[0] == _UT('/')))
> +			|| (!fromUnix && (filename[0] != _UT('\0')) && (filename[1] == _UT(':'))));
> +
> +	if ((filename == NULL) || (uriString == NULL)) {
> +		return URI_ERROR_NULL;
> +	}
> +
> +	if (absolute) {
> +		const URI_CHAR * const prefix = fromUnix ? _UT("file://") : _UT("file:///");
> +		const int prefixLen = fromUnix ? 7 : 8;
> +
> +		/* Copy prefix */
> +		memcpy(uriString, prefix, prefixLen * sizeof(URI_CHAR));
> +		output += prefixLen;
> +	}
> +
> +	/* Copy and escape on the fly */
> +	for (;;) {
> +		if ((input[0] == _UT('\0'))
> +				|| (fromUnix && input[0] == _UT('/'))
> +				|| (!fromUnix && input[0] == _UT('\\'))) {
> +			/* Copy text after last seperator */
> +			if (lastSep + 1 < input) {
> +				if (!fromUnix && absolute && (firstSegment == URI_TRUE)) {
> +					/* Quick hack to not convert "C:" to "C%3A" */
> +					const int charsToCopy = (int)(input - (lastSep + 1));
> +					memcpy(output, lastSep + 1, charsToCopy * sizeof(URI_CHAR));
> +					output += charsToCopy;
> +				} else {
> +					output = URI_FUNC(EscapeEx)(lastSep + 1, input, output,
> +							URI_FALSE, URI_FALSE);
> +				}
> +			}
> +			firstSegment = URI_FALSE;
> +		}
> +
> +		if (input[0] == _UT('\0')) {
> +			output[0] = _UT('\0');
> +			break;
> +		} else if (fromUnix && (input[0] == _UT('/'))) {
> +			/* Copy separators unmodified */
> +			output[0] = _UT('/');
> +			output++;
> +			lastSep = input;
> +		} else if (!fromUnix && (input[0] == _UT('\\'))) {
> +			/* Convert backslashes to forward slashes */
> +			output[0] = _UT('/');
> +			output++;
> +			lastSep = input;
> +		}
> +		input++;
> +	}
> +
> +	return URI_SUCCESS;
> +}
> +
> +
> +
> +static URI_INLINE int URI_FUNC(UriStringToFilename)(const URI_CHAR * uriString,
> +		URI_CHAR * filename, UriBool toUnix) {
> +	const URI_CHAR * const prefix = toUnix ? _UT("file://") : _UT("file:///");
> +	const int prefixLen = toUnix ? 7 : 8;
> +	URI_CHAR * walker = filename;
> +	size_t charsToCopy;
> +	const UriBool absolute = (URI_STRNCMP(uriString, prefix, prefixLen) == 0);
> +	const int charsToSkip = (absolute ? prefixLen : 0);
> +
> +	charsToCopy = URI_STRLEN(uriString + charsToSkip) + 1;
> +	memcpy(filename, uriString + charsToSkip, charsToCopy * sizeof(URI_CHAR));
> +	URI_FUNC(UnescapeInPlaceEx)(filename, URI_FALSE, URI_BR_DONT_TOUCH);
> +
> +	/* Convert forward slashes to backslashes */
> +	if (!toUnix) {
> +		while (walker[0] != _UT('\0')) {
> +			if (walker[0] == _UT('/')) {
> +				walker[0] = _UT('\\');
> +			}
> +			walker++;
> +		}
> +	}
> +
> +	return URI_SUCCESS;
> +}
> +
> +
> +
> +int URI_FUNC(UnixFilenameToUriString)(const URI_CHAR * filename, URI_CHAR * uriString) {
> +	return URI_FUNC(FilenameToUriString)(filename, uriString, URI_TRUE);
> +}
> +
> +
> +
> +int URI_FUNC(WindowsFilenameToUriString)(const URI_CHAR * filename, URI_CHAR * uriString) {
> +	return URI_FUNC(FilenameToUriString)(filename, uriString, URI_FALSE);
> +}
> +
> +
> +
> +int URI_FUNC(UriStringToUnixFilename)(const URI_CHAR * uriString, URI_CHAR * filename) {
> +	return URI_FUNC(UriStringToFilename)(uriString, filename, URI_TRUE);
> +}
> +
> +
> +
> +int URI_FUNC(UriStringToWindowsFilename)(const URI_CHAR * uriString, URI_CHAR * filename) {
> +	return URI_FUNC(UriStringToFilename)(uriString, filename, URI_FALSE);
> +}
> +
> +
> +
> +#endif
> diff --git a/uriparser/lib/UriIp4.c b/uriparser/lib/UriIp4.c
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriIp4.c
> @@ -0,0 +1,325 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 UriIp4.c
> + * Holds the IPv4 parser implementation.
> + * NOTE: This source file includes itself twice.
> + */
> +
> +/* What encodings are enabled? */
> +#include <uriparser/UriDefsConfig.h>
> +#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
> +/* Include SELF twice */
> +# define URI_PASS_ANSI 1
> +# include "UriIp4.c"
> +# undef URI_PASS_ANSI
> +# define URI_PASS_UNICODE 1
> +# include "UriIp4.c"
> +# undef URI_PASS_UNICODE
> +#else
> +# ifdef URI_PASS_ANSI
> +#  include <uriparser/UriDefsAnsi.h>
> +# else
> +#  include <uriparser/UriDefsUnicode.h>
> +# endif
> +
> +
> +
> +#ifndef URI_DOXYGEN
> +# include <uriparser/UriIp4.h>
> +# include "UriIp4Base.h"
> +# include <uriparser/UriBase.h>
> +#endif
> +
> +
> +
> +/* Prototypes */
> +static const URI_CHAR * URI_FUNC(ParseDecOctet)(UriIp4Parser * parser,
> +		const URI_CHAR * first, const URI_CHAR * afterLast);
> +static const URI_CHAR * URI_FUNC(ParseDecOctetOne)(UriIp4Parser * parser,
> +		const URI_CHAR * first, const URI_CHAR * afterLast);
> +static const URI_CHAR * URI_FUNC(ParseDecOctetTwo)(UriIp4Parser * parser,
> +		const URI_CHAR * first, const URI_CHAR * afterLast);
> +static const URI_CHAR * URI_FUNC(ParseDecOctetThree)(UriIp4Parser * parser,
> +		const URI_CHAR * first, const URI_CHAR * afterLast);
> +static const URI_CHAR * URI_FUNC(ParseDecOctetFour)(UriIp4Parser * parser,
> +		const URI_CHAR * first, const URI_CHAR * afterLast);
> +
> +
> +
> +/*
> + * [ipFourAddress]->[decOctet]<.>[decOctet]<.>[decOctet]<.>[decOctet]
> + */
> +int URI_FUNC(ParseIpFourAddress)(unsigned char * octetOutput,
> +		const URI_CHAR * first, const URI_CHAR * afterLast) {
> +	const URI_CHAR * after;
> +	UriIp4Parser parser;
> +
> +	/* Essential checks */
> +	if ((octetOutput == NULL) || (first == NULL)
> +			|| (afterLast <= first)) {
> +		return URI_ERROR_SYNTAX;
> +	}
> +
> +	/* Reset parser */
> +	parser.stackCount = 0;
> +
> +	/* Octet #1 */
> +	after = URI_FUNC(ParseDecOctet)(&parser, first, afterLast);
> +	if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) {
> +		return URI_ERROR_SYNTAX;
> +	}
> +	uriStackToOctet(&parser, octetOutput);
> +
> +	/* Octet #2 */
> +	after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast);
> +	if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) {
> +		return URI_ERROR_SYNTAX;
> +	}
> +	uriStackToOctet(&parser, octetOutput + 1);
> +
> +	/* Octet #3 */
> +	after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast);
> +	if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) {
> +		return URI_ERROR_SYNTAX;
> +	}
> +	uriStackToOctet(&parser, octetOutput + 2);
> +
> +	/* Octet #4 */
> +	after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast);
> +	if (after != afterLast) {
> +		return URI_ERROR_SYNTAX;
> +	}
> +	uriStackToOctet(&parser, octetOutput + 3);
> +
> +	return URI_SUCCESS;
> +}
> +
> +
> +
> +/*
> + * [decOctet]-><0>
> + * [decOctet]-><1>[decOctetOne]
> + * [decOctet]-><2>[decOctetTwo]
> + * [decOctet]-><3>[decOctetThree]
> + * [decOctet]-><4>[decOctetThree]
> + * [decOctet]-><5>[decOctetThree]
> + * [decOctet]-><6>[decOctetThree]
> + * [decOctet]-><7>[decOctetThree]
> + * [decOctet]-><8>[decOctetThree]
> + * [decOctet]-><9>[decOctetThree]
> + */
> +static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctet)(UriIp4Parser * parser,
> +		const URI_CHAR * first, const URI_CHAR * afterLast) {
> +	if (first >= afterLast) {
> +		return NULL;
> +	}
> +
> +	switch (*first) {
> +	case _UT('0'):
> +		uriPushToStack(parser, 0);
> +		return first + 1;
> +
> +	case _UT('1'):
> +		uriPushToStack(parser, 1);
> +		return (const URI_CHAR *)URI_FUNC(ParseDecOctetOne)(parser, first + 1, afterLast);
> +
> +	case _UT('2'):
> +		uriPushToStack(parser, 2);
> +		return (const URI_CHAR *)URI_FUNC(ParseDecOctetTwo)(parser, first + 1, afterLast);
> +
> +	case _UT('3'):
> +	case _UT('4'):
> +	case _UT('5'):
> +	case _UT('6'):
> +	case _UT('7'):
> +	case _UT('8'):
> +	case _UT('9'):
> +		uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
> +		return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, afterLast);
> +
> +	default:
> +		return NULL;
> +	}
> +}
> +
> +
> +
> +/*
> + * [decOctetOne]-><NULL>
> + * [decOctetOne]->[DIGIT][decOctetThree]
> + */
> +static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetOne)(UriIp4Parser * parser,
> +		const URI_CHAR * first, const URI_CHAR * afterLast) {
> +	if (first >= afterLast) {
> +		return afterLast;
> +	}
> +
> +	switch (*first) {
> +	case _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'):
> +		uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
> +		return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, afterLast);
> +
> +	default:
> +		return first;
> +	}
> +}
> +
> +
> +
> +/*
> + * [decOctetTwo]-><NULL>
> + * [decOctetTwo]-><0>[decOctetThree]
> + * [decOctetTwo]-><1>[decOctetThree]
> + * [decOctetTwo]-><2>[decOctetThree]
> + * [decOctetTwo]-><3>[decOctetThree]
> + * [decOctetTwo]-><4>[decOctetThree]
> + * [decOctetTwo]-><5>[decOctetFour]
> + * [decOctetTwo]-><6>
> + * [decOctetTwo]-><7>
> + * [decOctetTwo]-><8>
> + * [decOctetTwo]-><9>
> +*/
> +static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetTwo)(UriIp4Parser * parser,
> +		const URI_CHAR * first, const URI_CHAR * afterLast) {
> +	if (first >= afterLast) {
> +		return afterLast;
> +	}
> +
> +	switch (*first) {
> +	case _UT('0'):
> +	case _UT('1'):
> +	case _UT('2'):
> +	case _UT('3'):
> +	case _UT('4'):
> +		uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
> +		return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, afterLast);
> +
> +	case _UT('5'):
> +		uriPushToStack(parser, 5);
> +		return (const URI_CHAR *)URI_FUNC(ParseDecOctetFour)(parser, first + 1, afterLast);
> +
> +	case _UT('6'):
> +	case _UT('7'):
> +	case _UT('8'):
> +	case _UT('9'):
> +		uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
> +		return first + 1;
> +
> +	default:
> +		return first;
> +	}
> +}
> +
> +
> +
> +/*
> + * [decOctetThree]-><NULL>
> + * [decOctetThree]->[DIGIT]
> + */
> +static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetThree)(UriIp4Parser * parser,
> +		const URI_CHAR * first, const URI_CHAR * afterLast) {
> +	if (first >= afterLast) {
> +		return afterLast;
> +	}
> +
> +	switch (*first) {
> +	case _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'):
> +		uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
> +		return first + 1;
> +
> +	default:
> +		return first;
> +	}
> +}
> +
> +
> +
> +/*
> + * [decOctetFour]-><NULL>
> + * [decOctetFour]-><0>
> + * [decOctetFour]-><1>
> + * [decOctetFour]-><2>
> + * [decOctetFour]-><3>
> + * [decOctetFour]-><4>
> + * [decOctetFour]-><5>
> + */
> +static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetFour)(UriIp4Parser * parser,
> +		const URI_CHAR * first, const URI_CHAR * afterLast) {
> +	if (first >= afterLast) {
> +		return afterLast;
> +	}
> +
> +	switch (*first) {
> +	case _UT('0'):
> +	case _UT('1'):
> +	case _UT('2'):
> +	case _UT('3'):
> +	case _UT('4'):
> +	case _UT('5'):
> +		uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
> +		return first + 1;
> +
> +	default:
> +		return first;
> +	}
> +}
> +
> +
> +
> +#endif
> diff --git a/uriparser/lib/UriIp4Base.c b/uriparser/lib/UriIp4Base.c
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriIp4Base.c
> @@ -0,0 +1,96 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 UriIp4Base.c
> + * Holds code independent of the encoding pass.
> + */
> +
> +#ifndef URI_DOXYGEN
> +# include "UriIp4Base.h"
> +#endif
> +
> +
> +
> +void uriStackToOctet(UriIp4Parser * parser, unsigned char * octet) {
> +	switch (parser->stackCount) {
> +	case 1:
> +		*octet = parser->stackOne;
> +		break;
> +
> +	case 2:
> +		*octet = parser->stackOne * 10
> +				+ parser->stackTwo;
> +		break;
> +
> +	case 3:
> +		*octet = parser->stackOne * 100
> +				+ parser->stackTwo * 10
> +				+ parser->stackThree;
> +		break;
> +
> +	default:
> +		;
> +	}
> +	parser->stackCount = 0;
> +}
> +
> +
> +
> +void uriPushToStack(UriIp4Parser * parser, unsigned char digit) {
> +	switch (parser->stackCount) {
> +	case 0:
> +		parser->stackOne = digit;
> +		parser->stackCount = 1;
> +		break;
> +
> +	case 1:
> +		parser->stackTwo = digit;
> +		parser->stackCount = 2;
> +		break;
> +
> +	case 2:
> +		parser->stackThree = digit;
> +		parser->stackCount = 3;
> +		break;
> +
> +	default:
> +		;
> +	}
> +}
> diff --git a/uriparser/lib/UriIp4Base.h b/uriparser/lib/UriIp4Base.h
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriIp4Base.h
> @@ -0,0 +1,59 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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_IP4_BASE_H
> +#define URI_IP4_BASE_H 1
> +
> +
> +
> +typedef struct UriIp4ParserStruct {
> +	unsigned char stackCount;
> +	unsigned char stackOne;
> +	unsigned char stackTwo;
> +	unsigned char stackThree;
> +} UriIp4Parser;
> +
> +
> +
> +void uriPushToStack(UriIp4Parser * parser, unsigned char digit);
> +void uriStackToOctet(UriIp4Parser * parser, unsigned char * octet);
> +
> +
> +
> +#endif /* URI_IP4_BASE_H */
> diff --git a/uriparser/lib/UriNormalize.c b/uriparser/lib/UriNormalize.c
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriNormalize.c
> @@ -0,0 +1,722 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 UriNormalize.c
> + * Holds the RFC 3986 %URI normalization implementation.
> + * NOTE: This source file includes itself twice.
> + */
> +
> +/* What encodings are enabled? */
> +#include <uriparser/UriDefsConfig.h>
> +#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
> +/* Include SELF twice */
> +# define URI_PASS_ANSI 1
> +# include "UriNormalize.c"
> +# undef URI_PASS_ANSI
> +# define URI_PASS_UNICODE 1
> +# include "UriNormalize.c"
> +# undef URI_PASS_UNICODE
> +#else
> +# ifdef URI_PASS_ANSI
> +#  include <uriparser/UriDefsAnsi.h>
> +# else
> +#  include <uriparser/UriDefsUnicode.h>
> +#  include <wchar.h>
> +# endif
> +
> +
> +
> +#ifndef URI_DOXYGEN
> +# include <uriparser/Uri.h>
> +# include "UriNormalizeBase.h"
> +# include "UriCommon.h"
> +#endif
> +
> +
> +
> +static int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri, unsigned int inMask,
> +		unsigned int * outMask);
> +
> +static UriBool URI_FUNC(MakeRangeOwner)(unsigned int * doneMask,
> +		unsigned int maskTest, URI_TYPE(TextRange) * range);
> +static UriBool URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri,
> +		unsigned int * doneMask);
> +
> +static void URI_FUNC(FixPercentEncodingInplace)(const URI_CHAR * first,
> +		const URI_CHAR ** afterLast);
> +static UriBool URI_FUNC(FixPercentEncodingMalloc)(const URI_CHAR ** first,
> +		const URI_CHAR ** afterLast);
> +static void URI_FUNC(FixPercentEncodingEngine)(
> +		const URI_CHAR * inFirst, const URI_CHAR * inAfterLast,
> +		const URI_CHAR * outFirst, const URI_CHAR ** outAfterLast);
> +
> +static UriBool URI_FUNC(ContainsUppercaseLetters)(const URI_CHAR * first,
> +		const URI_CHAR * afterLast);
> +static UriBool URI_FUNC(ContainsUglyPercentEncoding)(const URI_CHAR * first,
> +		const URI_CHAR * afterLast);
> +
> +static void URI_FUNC(LowercaseInplace)(const URI_CHAR * first,
> +		const URI_CHAR * afterLast);
> +static UriBool URI_FUNC(LowercaseMalloc)(const URI_CHAR ** first,
> +		const URI_CHAR ** afterLast);
> +
> +static void URI_FUNC(PreventLeakage)(URI_TYPE(Uri) * uri,
> +		unsigned int revertMask);
> +
> +
> +
> +static URI_INLINE void URI_FUNC(PreventLeakage)(URI_TYPE(Uri) * uri,
> +		unsigned int revertMask) {
> +	if (revertMask & URI_NORMALIZE_SCHEME) {
> +		free((URI_CHAR *)uri->scheme.first);
> +		uri->scheme.first = NULL;
> +		uri->scheme.afterLast = NULL;
> +	}
> +
> +	if (revertMask & URI_NORMALIZE_USER_INFO) {
> +		free((URI_CHAR *)uri->userInfo.first);
> +		uri->userInfo.first = NULL;
> +		uri->userInfo.afterLast = NULL;
> +	}
> +
> +	if (revertMask & URI_NORMALIZE_HOST) {
> +		if (uri->hostData.ipFuture.first != NULL) {
> +			/* IPvFuture */
> +			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;
> +		} else if ((uri->hostText.first != NULL)
> +				&& (uri->hostData.ip4 == NULL)
> +				&& (uri->hostData.ip6 == NULL)) {
> +			/* Regname */
> +			free((URI_CHAR *)uri->hostText.first);
> +			uri->hostText.first = NULL;
> +			uri->hostText.afterLast = NULL;
> +		}
> +	}
> +
> +	/* NOTE: Port cannot happen! */
> +
> +	if (revertMask & URI_NORMALIZE_PATH) {
> +		URI_TYPE(PathSegment) * walker = uri->pathHead;
> +		while (walker != NULL) {
> +			URI_TYPE(PathSegment) * const next = walker->next;
> +			if (walker->text.afterLast > walker->text.first) {
> +				free((URI_CHAR *)walker->text.first);
> +			}
> +			free(walker);
> +			walker = next;
> +		}
> +		uri->pathHead = NULL;
> +		uri->pathTail = NULL;
> +	}
> +
> +	if (revertMask & URI_NORMALIZE_QUERY) {
> +		free((URI_CHAR *)uri->query.first);
> +		uri->query.first = NULL;
> +		uri->query.afterLast = NULL;
> +	}
> +
> +	if (revertMask & URI_NORMALIZE_FRAGMENT) {
> +		free((URI_CHAR *)uri->fragment.first);
> +		uri->fragment.first = NULL;
> +		uri->fragment.afterLast = NULL;
> +	}
> +}
> +
> +
> +
> +static URI_INLINE UriBool URI_FUNC(ContainsUppercaseLetters)(const URI_CHAR * first,
> +		const URI_CHAR * afterLast) {
> +	if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) {
> +		const URI_CHAR * i = first;
> +		for (; i < afterLast; i++) {
> +			/* 6.2.2.1 Case Normalization: uppercase letters in scheme or host */
> +			if ((*i >= _UT('A')) && (*i <= _UT('Z'))) {
> +				return URI_TRUE;
> +			}
> +		}
> +	}
> +	return URI_FALSE;
> +}
> +
> +
> +
> +static URI_INLINE UriBool URI_FUNC(ContainsUglyPercentEncoding)(const URI_CHAR * first,
> +		const URI_CHAR * afterLast) {
> +	if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) {
> +		const URI_CHAR * i = first;
> +		for (; i + 2 < afterLast; i++) {
> +			if (i[0] == _UT('%')) {
> +				/* 6.2.2.1 Case Normalization: *
> +				 * lowercase percent-encodings */
> +				if (((i[1] >= _UT('a')) && (i[1] <= _UT('f')))
> +						|| ((i[2] >= _UT('a')) && (i[2] <= _UT('f')))) {
> +					return URI_TRUE;
> +				} else {
> +					/* 6.2.2.2 Percent-Encoding Normalization: *
> +					 * percent-encoded unreserved characters   */
> +					const unsigned char left = URI_FUNC(HexdigToInt)(i[1]);
> +					const unsigned char right = URI_FUNC(HexdigToInt)(i[2]);
> +					const int code = 16 * left + right;
> +					if (uriIsUnreserved(code)) {
> +						return URI_TRUE;
> +					}
> +				}
> +			}
> +		}
> +	}
> +	return URI_FALSE;
> +}
> +
> +
> +
> +static URI_INLINE void URI_FUNC(LowercaseInplace)(const URI_CHAR * first,
> +		const URI_CHAR * afterLast) {
> +	if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) {
> +		URI_CHAR * i = (URI_CHAR *)first;
> +		const int lowerUpperDiff = (_UT('a') - _UT('A'));
> +		for (; i < afterLast; i++) {
> +			if ((*i >= _UT('A')) && (*i <=_UT('Z'))) {
> +				*i = (URI_CHAR)(*i + lowerUpperDiff);
> +			}
> +		}
> +	}
> +}
> +
> +
> +
> +static URI_INLINE UriBool URI_FUNC(LowercaseMalloc)(const URI_CHAR ** first,
> +		const URI_CHAR ** afterLast) {
> +	int lenInChars;
> +	const int lowerUpperDiff = (_UT('a') - _UT('A'));
> +	URI_CHAR * buffer;
> +	int i = 0;
> +
> +	if ((first == NULL) || (afterLast == NULL) || (*first == NULL)
> +			|| (*afterLast == NULL)) {
> +		return URI_FALSE;
> +	}
> +
> +	lenInChars = (int)(*afterLast - *first);
> +	if (lenInChars == 0) {
> +		return URI_TRUE;
> +	} else if (lenInChars < 0) {
> +		return URI_FALSE;
> +	}
> +
> +	buffer = malloc(lenInChars * sizeof(URI_CHAR));
> +	if (buffer == NULL) {
> +		return URI_FALSE;
> +	}
> +
> +	for (; i < lenInChars; i++) {
> +		if (((*first)[i] >= _UT('A')) && ((*first)[i] <=_UT('Z'))) {
> +			buffer[i] = (URI_CHAR)((*first)[i] + lowerUpperDiff);
> +		} else {
> +			buffer[i] = (*first)[i];
> +		}
> +	}
> +
> +	*first = buffer;
> +	*afterLast = buffer + lenInChars;
> +	return URI_TRUE;
> +}
> +
> +
> +
> +/* NOTE: Implementation must stay inplace-compatible */
> +static URI_INLINE void URI_FUNC(FixPercentEncodingEngine)(
> +		const URI_CHAR * inFirst, const URI_CHAR * inAfterLast,
> +		const URI_CHAR * outFirst, const URI_CHAR ** outAfterLast) {
> +	URI_CHAR * write = (URI_CHAR *)outFirst;
> +	const int lenInChars = (int)(inAfterLast - inFirst);
> +	int i = 0;
> +
> +	/* All but last two */
> +	for (; i + 2 < lenInChars; i++) {
> +		if (inFirst[i] != _UT('%')) {
> +			write[0] = inFirst[i];
> +			write++;
> +		} else {
> +			/* 6.2.2.2 Percent-Encoding Normalization: *
> +			 * percent-encoded unreserved characters   */
> +			const URI_CHAR one = inFirst[i + 1];
> +			const URI_CHAR two = inFirst[i + 2];
> +			const unsigned char left = URI_FUNC(HexdigToInt)(one);
> +			const unsigned char right = URI_FUNC(HexdigToInt)(two);
> +			const int code = 16 * left + right;
> +			if (uriIsUnreserved(code)) {
> +				write[0] = (URI_CHAR)(code);
> +				write++;
> +			} else {
> +				/* 6.2.2.1 Case Normalization: *
> +				 * lowercase percent-encodings */
> +				write[0] = _UT('%');
> +				write[1] = URI_FUNC(HexToLetter)(left);
> +				write[2] = URI_FUNC(HexToLetter)(right);
> +				write += 3;
> +			}
> +
> +			i += 2; /* For the two chars of the percent group we just ate */
> +		}
> +	}
> +
> +	/* Last two */
> +	for (; i < lenInChars; i++) {
> +		write[0] = inFirst[i];
> +		write++;
> +	}
> +
> +	*outAfterLast = write;
> +}
> +
> +
> +
> +static URI_INLINE void URI_FUNC(FixPercentEncodingInplace)(const URI_CHAR * first,
> +		const URI_CHAR ** afterLast) {
> +	/* Death checks */
> +	if ((first == NULL) || (afterLast == NULL) || (*afterLast == NULL)) {
> +		return;
> +	}
> +
> +	/* Fix inplace */
> +	URI_FUNC(FixPercentEncodingEngine)(first, *afterLast, first, afterLast);
> +}
> +
> +
> +
> +static URI_INLINE UriBool URI_FUNC(FixPercentEncodingMalloc)(const URI_CHAR ** first,
> +		const URI_CHAR ** afterLast) {
> +	int lenInChars;
> +	URI_CHAR * buffer;
> +
> +	/* Death checks */
> +	if ((first == NULL) || (afterLast == NULL)
> +			|| (*first == NULL) || (*afterLast == NULL)) {
> +		return URI_FALSE;
> +	}
> +
> +	/* Old text length */
> +	lenInChars = (int)(*afterLast - *first);
> +	if (lenInChars == 0) {
> +		return URI_TRUE;
> +	} else if (lenInChars < 0) {
> +		return URI_FALSE;
> +	}
> +
> +	/* New buffer */
> +	buffer = malloc(lenInChars * sizeof(URI_CHAR));
> +	if (buffer == NULL) {
> +		return URI_FALSE;
> +	}
> +
> +	/* Fix on copy */
> +	URI_FUNC(FixPercentEncodingEngine)(*first, *afterLast, buffer, afterLast);
> +	*first = buffer;
> +	return URI_TRUE;
> +}
> +
> +
> +
> +static URI_INLINE UriBool URI_FUNC(MakeRangeOwner)(unsigned int * doneMask,
> +		unsigned int maskTest, URI_TYPE(TextRange) * range) {
> +	if (((*doneMask & maskTest) == 0)
> +			&& (range->first != NULL)
> +			&& (range->afterLast != NULL)
> +			&& (range->afterLast > range->first)) {
> +		const int lenInChars = (int)(range->afterLast - range->first);
> +		const int lenInBytes = lenInChars * sizeof(URI_CHAR);
> +		URI_CHAR * dup = malloc(lenInBytes);
> +		if (dup == NULL) {
> +			return URI_FALSE; /* Raises malloc error */
> +		}
> +		memcpy(dup, range->first, lenInBytes);
> +		range->first = dup;
> +		range->afterLast = dup + lenInChars;
> +		*doneMask |= maskTest;
> +	}
> +	return URI_TRUE;
> +}
> +
> +
> +
> +static URI_INLINE UriBool URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri,
> +		unsigned int * doneMask) {
> +	URI_TYPE(PathSegment) * walker = uri->pathHead;
> +	if (!URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_SCHEME,
> +				&(uri->scheme))
> +			|| !URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_USER_INFO,
> +				&(uri->userInfo))
> +			|| !URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_QUERY,
> +				&(uri->query))
> +			|| !URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_FRAGMENT,
> +				&(uri->fragment))) {
> +		return URI_FALSE; /* Raises malloc error */
> +	}
> +
> +	/* Host */
> +	if ((*doneMask & URI_NORMALIZE_HOST) == 0) {
> +		if ((uri->hostData.ip4 == NULL)
> +				&& (uri->hostData.ip6 == NULL)) {
> +			if (uri->hostData.ipFuture.first != NULL) {
> +				/* IPvFuture */
> +				if (!URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_HOST,
> +						&(uri->hostData.ipFuture))) {
> +					return URI_FALSE; /* Raises malloc error */
> +				}
> +				uri->hostText.first = uri->hostData.ipFuture.first;
> +				uri->hostText.afterLast = uri->hostData.ipFuture.afterLast;
> +			} else if (uri->hostText.first != NULL) {
> +				/* Regname */
> +				if (!URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_HOST,
> +						&(uri->hostText))) {
> +					return URI_FALSE; /* Raises malloc error */
> +				}
> +			}
> +		}
> +	}
> +
> +	/* Path */
> +	if ((*doneMask & URI_NORMALIZE_PATH) == 0) {
> +		while (walker != NULL) {
> +			if (!URI_FUNC(MakeRangeOwner)(doneMask, 0, &(walker->text))) {
> +				/* Kill path to one before walker */
> +				URI_TYPE(PathSegment) * ranger = uri->pathHead;
> +				while (ranger->next != walker) {
> +					URI_TYPE(PathSegment) * const next = ranger->next;
> +					if ((ranger->text.first != NULL)
> +							&& (ranger->text.afterLast != NULL)
> +							&& (ranger->text.afterLast > ranger->text.first)) {
> +						free((URI_CHAR *)ranger->text.first);
> +						free(ranger);
> +					}
> +					ranger = next;
> +				}
> +
> +				/* Kill path from walker */
> +				while (walker != NULL) {
> +					URI_TYPE(PathSegment) * const next = walker->next;
> +					free(walker);
> +					walker = next;
> +				}
> +
> +				uri->pathHead = NULL;
> +				uri->pathTail = NULL;
> +				return URI_FALSE; /* Raises malloc error */
> +			}
> +			walker = walker->next;
> +		}
> +		*doneMask |= URI_NORMALIZE_PATH;
> +	}
> +
> +	/* Port text, must come last so we don't have to undo that one if it fails. *
> +	 * Otherwise we would need and extra enum flag for it although the port      *
> +	 * cannot go unnormalized...                                                */
> +	if (!URI_FUNC(MakeRangeOwner)(doneMask, 0, &(uri->portText))) {
> +		return URI_FALSE; /* Raises malloc error */
> +	}
> +
> +	return URI_TRUE;
> +}
> +
> +
> +
> +unsigned int URI_FUNC(NormalizeSyntaxMaskRequired)(const URI_TYPE(Uri) * uri) {
> +	unsigned int res;
> +#if defined(__GNUC__) && ((__GNUC__ > 4) \
> +        || ((__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 2)))
> +    /* Slower code that fixes a warning, not sure if this is a smart idea */
> +	URI_TYPE(Uri) writeableClone;
> +	memcpy(&writeableClone, uri, 1 * sizeof(URI_TYPE(Uri)));
> +	URI_FUNC(NormalizeSyntaxEngine)(&writeableClone, 0, &res);
> +#else
> +	URI_FUNC(NormalizeSyntaxEngine)((URI_TYPE(Uri) *)uri, 0, &res);
> +#endif
> +	return res;
> +}
> +
> +
> +
> +int URI_FUNC(NormalizeSyntaxEx)(URI_TYPE(Uri) * uri, unsigned int mask) {
> +	return URI_FUNC(NormalizeSyntaxEngine)(uri, mask, NULL);
> +}
> +
> +
> +
> +int URI_FUNC(NormalizeSyntax)(URI_TYPE(Uri) * uri) {
> +	return URI_FUNC(NormalizeSyntaxEx)(uri, (unsigned int)-1);
> +}
> +
> +
> +
> +static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri, unsigned int inMask, unsigned int * outMask) {
> +	unsigned int doneMask = URI_NORMALIZED;
> +	if (uri == NULL) {
> +		if (outMask != NULL) {
> +			*outMask = URI_NORMALIZED;
> +			return URI_SUCCESS;
> +		} else {
> +			return URI_ERROR_NULL;
> +		}
> +	}
> +
> +	if (outMask != NULL) {
> +		/* Reset mask */
> +		*outMask = URI_NORMALIZED;
> +	} else if (inMask == URI_NORMALIZED) {
> +		/* Nothing to do */
> +		return URI_SUCCESS;
> +	}
> +
> +	/* Scheme, host */
> +	if (outMask != NULL) {
> +		const UriBool normalizeScheme = URI_FUNC(ContainsUppercaseLetters)(
> +				uri->scheme.first, uri->scheme.afterLast);
> +		const UriBool normalizeHostCase = URI_FUNC(ContainsUppercaseLetters)(
> +			uri->hostText.first, uri->hostText.afterLast);
> +		if (normalizeScheme) {
> +			*outMask |= URI_NORMALIZE_SCHEME;
> +		}
> +
> +		if (normalizeHostCase) {
> +			*outMask |= URI_NORMALIZE_HOST;
> +		} else {
> +			const UriBool normalizeHostPrecent = URI_FUNC(ContainsUglyPercentEncoding)(
> +					uri->hostText.first, uri->hostText.afterLast);
> +			if (normalizeHostPrecent) {
> +				*outMask |= URI_NORMALIZE_HOST;
> +			}
> +		}
> +	} else {
> +		/* Scheme */
> +		if ((inMask & URI_NORMALIZE_SCHEME) && (uri->scheme.first != NULL)) {
> +			if (uri->owner) {
> +				URI_FUNC(LowercaseInplace)(uri->scheme.first, uri->scheme.afterLast);
> +			} else {
> +				if (!URI_FUNC(LowercaseMalloc)(&(uri->scheme.first), &(uri->scheme.afterLast))) {
> +					URI_FUNC(PreventLeakage)(uri, doneMask);
> +					return URI_ERROR_MALLOC;
> +				}
> +				doneMask |= URI_NORMALIZE_SCHEME;
> +			}
> +		}
> +
> +		/* Host */
> +		if (inMask & URI_NORMALIZE_HOST) {
> +			if (uri->hostData.ipFuture.first != NULL) {
> +				/* IPvFuture */
> +				if (uri->owner) {
> +					URI_FUNC(LowercaseInplace)(uri->hostData.ipFuture.first,
> +							uri->hostData.ipFuture.afterLast);
> +				} else {
> +					if (!URI_FUNC(LowercaseMalloc)(&(uri->hostData.ipFuture.first),
> +							&(uri->hostData.ipFuture.afterLast))) {
> +						URI_FUNC(PreventLeakage)(uri, doneMask);
> +						return URI_ERROR_MALLOC;
> +					}
> +					doneMask |= URI_NORMALIZE_HOST;
> +				}
> +				uri->hostText.first = uri->hostData.ipFuture.first;
> +				uri->hostText.afterLast = uri->hostData.ipFuture.afterLast;
> +			} else if ((uri->hostText.first != NULL)
> +					&& (uri->hostData.ip4 == NULL)
> +					&& (uri->hostData.ip6 == NULL)) {
> +				/* Regname */
> +				if (uri->owner) {
> +					URI_FUNC(FixPercentEncodingInplace)(uri->hostText.first,
> +							&(uri->hostText.afterLast));
> +				} else {
> +					if (!URI_FUNC(FixPercentEncodingMalloc)(
> +							&(uri->hostText.first),
> +							&(uri->hostText.afterLast))) {
> +						URI_FUNC(PreventLeakage)(uri, doneMask);
> +						return URI_ERROR_MALLOC;
> +					}
> +					doneMask |= URI_NORMALIZE_HOST;
> +				}
> +
> +				URI_FUNC(LowercaseInplace)(uri->hostText.first,
> +						uri->hostText.afterLast);
> +			}
> +		}
> +	}
> +
> +	/* User info */
> +	if (outMask != NULL) {
> +		const UriBool normalizeUserInfo = URI_FUNC(ContainsUglyPercentEncoding)(
> +			uri->userInfo.first, uri->userInfo.afterLast);
> +		if (normalizeUserInfo) {
> +			*outMask |= URI_NORMALIZE_USER_INFO;
> +		}
> +	} else {
> +		if ((inMask & URI_NORMALIZE_USER_INFO) && (uri->userInfo.first != NULL)) {
> +			if (uri->owner) {
> +				URI_FUNC(FixPercentEncodingInplace)(uri->userInfo.first, &(uri->userInfo.afterLast));
> +			} else {
> +				if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->userInfo.first),
> +						&(uri->userInfo.afterLast))) {
> +					URI_FUNC(PreventLeakage)(uri, doneMask);
> +					return URI_ERROR_MALLOC;
> +				}
> +				doneMask |= URI_NORMALIZE_USER_INFO;
> +			}
> +		}
> +	}
> +
> +	/* Path */
> +	if (outMask != NULL) {
> +		const URI_TYPE(PathSegment) * walker = uri->pathHead;
> +		while (walker != NULL) {
> +			const URI_CHAR * const first = walker->text.first;
> +			const URI_CHAR * const afterLast = walker->text.afterLast;
> +			if ((first != NULL)
> +					&& (afterLast != NULL)
> +					&& (afterLast > first)
> +					&& (
> +						(((afterLast - first) == 1)
> +							&& (first[0] == _UT('.')))
> +						||
> +						(((afterLast - first) == 2)
> +							&& (first[0] == _UT('.'))
> +							&& (first[1] == _UT('.')))
> +						||
> +						URI_FUNC(ContainsUglyPercentEncoding)(first, afterLast)
> +					)) {
> +				*outMask |= URI_NORMALIZE_PATH;
> +				break;
> +			}
> +			walker = walker->next;
> +		}
> +	} else if (inMask & URI_NORMALIZE_PATH) {
> +		URI_TYPE(PathSegment) * walker;
> +		const UriBool relative = ((uri->scheme.first == NULL)
> +				&& !uri->absolutePath) ? URI_TRUE : URI_FALSE;
> +
> +		/* Fix percent-encoding for each segment */
> +		walker = uri->pathHead;
> +		if (uri->owner) {
> +			while (walker != NULL) {
> +				URI_FUNC(FixPercentEncodingInplace)(walker->text.first, &(walker->text.afterLast));
> +				walker = walker->next;
> +			}
> +		} else {
> +			while (walker != NULL) {
> +				if (!URI_FUNC(FixPercentEncodingMalloc)(&(walker->text.first),
> +						&(walker->text.afterLast))) {
> +					URI_FUNC(PreventLeakage)(uri, doneMask);
> +					return URI_ERROR_MALLOC;
> +				}
> +				walker = walker->next;
> +			}
> +			doneMask |= URI_NORMALIZE_PATH;
> +		}
> +
> +		/* 6.2.2.3 Path Segment Normalization */
> +		if (!URI_FUNC(RemoveDotSegmentsEx)(uri, relative,
> +				(uri->owner == URI_TRUE)
> +				|| ((doneMask & URI_NORMALIZE_PATH) != 0)
> +				)) {
> +			URI_FUNC(PreventLeakage)(uri, doneMask);
> +			return URI_ERROR_MALLOC;
> +		}
> +		URI_FUNC(FixEmptyTrailSegment)(uri);
> +	}
> +
> +	/* Query, fragment */
> +	if (outMask != NULL) {
> +		const UriBool normalizeQuery = URI_FUNC(ContainsUglyPercentEncoding)(
> +				uri->query.first, uri->query.afterLast);
> +		const UriBool normalizeFragment = URI_FUNC(ContainsUglyPercentEncoding)(
> +				uri->fragment.first, uri->fragment.afterLast);
> +		if (normalizeQuery) {
> +			*outMask |= URI_NORMALIZE_QUERY;
> +		}
> +
> +		if (normalizeFragment) {
> +			*outMask |= URI_NORMALIZE_FRAGMENT;
> +		}
> +	} else {
> +		/* Query */
> +		if ((inMask & URI_NORMALIZE_QUERY) && (uri->query.first != NULL)) {
> +			if (uri->owner) {
> +				URI_FUNC(FixPercentEncodingInplace)(uri->query.first, &(uri->query.afterLast));
> +			} else {
> +				if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->query.first),
> +						&(uri->query.afterLast))) {
> +					URI_FUNC(PreventLeakage)(uri, doneMask);
> +					return URI_ERROR_MALLOC;
> +				}
> +				doneMask |= URI_NORMALIZE_QUERY;
> +			}
> +		}
> +
> +		/* Fragment */
> +		if ((inMask & URI_NORMALIZE_FRAGMENT) && (uri->fragment.first != NULL)) {
> +			if (uri->owner) {
> +				URI_FUNC(FixPercentEncodingInplace)(uri->fragment.first, &(uri->fragment.afterLast));
> +			} else {
> +				if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->fragment.first),
> +						&(uri->fragment.afterLast))) {
> +					URI_FUNC(PreventLeakage)(uri, doneMask);
> +					return URI_ERROR_MALLOC;
> +				}
> +				doneMask |= URI_NORMALIZE_FRAGMENT;
> +			}
> +		}
> +	}
> +
> +	/* Dup all not duped yet */
> +	if ((outMask == NULL) && !uri->owner) {
> +		if (!URI_FUNC(MakeOwner)(uri, &doneMask)) {
> +			URI_FUNC(PreventLeakage)(uri, doneMask);
> +			return URI_ERROR_MALLOC;
> +		}
> +		uri->owner = URI_TRUE;
> +	}
> +
> +	return URI_SUCCESS;
> +}
> +
> +
> +
> +#endif
> diff --git a/uriparser/lib/UriNormalizeBase.c b/uriparser/lib/UriNormalizeBase.c
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriNormalizeBase.c
> @@ -0,0 +1,119 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 "UriNormalizeBase.h"
> +#endif
> +
> +
> +
> +UriBool uriIsUnreserved(int code) {
> +	switch (code) {
> +	case L'a': /* ALPHA */
> +	case L'A':
> +	case L'b':
> +	case L'B':
> +	case L'c':
> +	case L'C':
> +	case L'd':
> +	case L'D':
> +	case L'e':
> +	case L'E':
> +	case L'f':
> +	case L'F':
> +	case L'g':
> +	case L'G':
> +	case L'h':
> +	case L'H':
> +	case L'i':
> +	case L'I':
> +	case L'j':
> +	case L'J':
> +	case L'k':
> +	case L'K':
> +	case L'l':
> +	case L'L':
> +	case L'm':
> +	case L'M':
> +	case L'n':
> +	case L'N':
> +	case L'o':
> +	case L'O':
> +	case L'p':
> +	case L'P':
> +	case L'q':
> +	case L'Q':
> +	case L'r':
> +	case L'R':
> +	case L's':
> +	case L'S':
> +	case L't':
> +	case L'T':
> +	case L'u':
> +	case L'U':
> +	case L'v':
> +	case L'V':
> +	case L'w':
> +	case L'W':
> +	case L'x':
> +	case L'X':
> +	case L'y':
> +	case L'Y':
> +	case L'z':
> +	case L'Z':
> +	case L'0': /* DIGIT */
> +	case L'1':
> +	case L'2':
> +	case L'3':
> +	case L'4':
> +	case L'5':
> +	case L'6':
> +	case L'7':
> +	case L'8':
> +	case L'9':
> +	case L'-': /* "-" / "." / "_" / "~" */
> +	case L'.':
> +	case L'_':
> +	case L'~':
> +		return URI_TRUE;
> +
> +	default:
> +		return URI_FALSE;
> +	}
> +}
> diff --git a/uriparser/lib/UriNormalizeBase.h b/uriparser/lib/UriNormalizeBase.h
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriNormalizeBase.h
> @@ -0,0 +1,53 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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_NORMALIZE_BASE_H
> +#define URI_NORMALIZE_BASE_H 1
> +
> +
> +
> +#include <uriparser/UriBase.h>
> +
> +
> +
> +UriBool uriIsUnreserved(int code);
> +
> +
> +
> +#endif /* URI_NORMALIZE_BASE_H */
> diff --git a/uriparser/lib/UriParse.c b/uriparser/lib/UriParse.c
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriParse.c
> @@ -0,0 +1,2205 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 <uriparser/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 <uriparser/UriDefsAnsi.h>
> +# else
> +#  include <uriparser/UriDefsUnicode.h>
> +#  include <wchar.h>
> +# endif
> +
> +
> +
> +#ifndef URI_DOXYGEN
> +# include <uriparser/Uri.h>
> +# include <uriparser/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
> diff --git a/uriparser/lib/UriParseBase.c b/uriparser/lib/UriParseBase.c
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriParseBase.c
> @@ -0,0 +1,90 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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];
> +
> +	}
> +}
> diff --git a/uriparser/lib/UriParseBase.h b/uriparser/lib/UriParseBase.h
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriParseBase.h
> @@ -0,0 +1,55 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 <uriparser/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 */
> diff --git a/uriparser/lib/UriQuery.c b/uriparser/lib/UriQuery.c
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriQuery.c
> @@ -0,0 +1,456 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 <uriparser/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 <uriparser/UriDefsAnsi.h>
> +# else
> +#  include <uriparser/UriDefsUnicode.h>
> +#  include <wchar.h>
> +# endif
> +
> +
> +
> +#ifndef URI_DOXYGEN
> +# include <uriparser/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
> diff --git a/uriparser/lib/UriRecompose.c b/uriparser/lib/UriRecompose.c
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriRecompose.c
> @@ -0,0 +1,573 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 <uriparser/UriDefsConfig.h>
> +#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
> +/* Include SELF twice */
> +# define URI_PASS_ANSI 1
> +# include "UriRecompose.c"
> +# undef URI_PASS_ANSI
> +# define URI_PASS_UNICODE 1
> +# include "UriRecompose.c"
> +# undef URI_PASS_UNICODE
> +#else
> +# ifdef URI_PASS_ANSI
> +#  include <uriparser/UriDefsAnsi.h>
> +# else
> +#  include <uriparser/UriDefsUnicode.h>
> +#  include <wchar.h>
> +# endif
> +
> +
> +
> +#ifndef URI_DOXYGEN
> +# include <uriparser/Uri.h>
> +# include "UriCommon.h"
> +#endif
> +
> +
> +
> +static int URI_FUNC(ToStringEngine)(URI_CHAR * dest, const URI_TYPE(Uri) * uri,
> +		int maxChars, int * charsWritten, int * charsRequired);
> +
> +
> +
> +int URI_FUNC(ToStringCharsRequired)(const URI_TYPE(Uri) * uri,
> +		int * charsRequired) {
> +	const int MAX_CHARS = ((unsigned int)-1) >> 1;
> +	return URI_FUNC(ToStringEngine)(NULL, uri, MAX_CHARS, NULL, charsRequired);
> +}
> +
> +
> +
> +int URI_FUNC(ToString)(URI_CHAR * dest, const URI_TYPE(Uri) * uri,
> +		int maxChars, int * charsWritten) {
> +	return URI_FUNC(ToStringEngine)(dest, uri, maxChars, charsWritten, NULL);
> +}
> +
> +
> +
> +static URI_INLINE int URI_FUNC(ToStringEngine)(URI_CHAR * dest,
> +		const URI_TYPE(Uri) * uri, int maxChars, int * charsWritten,
> +		int * charsRequired) {
> +	int written = 0;
> +	if ((uri == NULL) || ((dest == NULL) && (charsRequired == NULL))) {
> +		if (charsWritten != NULL) {
> +			*charsWritten = 0;
> +		}
> +		return URI_ERROR_NULL;
> +	}
> +
> +	if (maxChars < 1) {
> +		if (charsWritten != NULL) {
> +			*charsWritten = 0;
> +		}
> +		return URI_ERROR_TOSTRING_TOO_LONG;
> +	}
> +	maxChars--; /* So we don't have to substract 1 for '\0' all the time */
> +
> +	/* [01/19]	result = "" */
> +				if (dest != NULL) {
> +					dest[0] = _UT('\0');
> +				} else {
> +					(*charsRequired) = 0;
> +				}
> +	/* [02/19]	if defined(scheme) then */
> +				if (uri->scheme.first != NULL) {
> +	/* [03/19]		append scheme to result; */
> +					const int charsToWrite
> +							= (int)(uri->scheme.afterLast - uri->scheme.first);
> +					if (dest != NULL) {
> +						if (written + charsToWrite <= maxChars) {
> +							memcpy(dest + written, uri->scheme.first,
> +									charsToWrite * sizeof(URI_CHAR));
> +							written += charsToWrite;
> +						} else {
> +							dest[0] = _UT('\0');
> +							if (charsWritten != NULL) {
> +								*charsWritten = 0;
> +							}
> +							return URI_ERROR_TOSTRING_TOO_LONG;
> +						}
> +					} else {
> +						(*charsRequired) += charsToWrite;
> +					}
> +	/* [04/19]		append ":" to result; */
> +					if (dest != NULL) {
> +						if (written + 1 <= maxChars) {
> +							memcpy(dest + written, _UT(":"),
> +									1 * sizeof(URI_CHAR));
> +							written += 1;
> +						} else {
> +							dest[0] = _UT('\0');
> +							if (charsWritten != NULL) {
> +								*charsWritten = 0;
> +							}
> +							return URI_ERROR_TOSTRING_TOO_LONG;
> +						}
> +					} else {
> +						(*charsRequired) += 1;
> +					}
> +	/* [05/19]	endif; */
> +				}
> +	/* [06/19]	if defined(authority) then */
> +				if (URI_FUNC(IsHostSet)(uri)) {
> +	/* [07/19]		append "//" to result; */
> +					if (dest != NULL) {
> +						if (written + 2 <= maxChars) {
> +							memcpy(dest + written, _UT("//"),
> +									2 * sizeof(URI_CHAR));
> +							written += 2;
> +						} else {
> +							dest[0] = _UT('\0');
> +							if (charsWritten != NULL) {
> +								*charsWritten = 0;
> +							}
> +							return URI_ERROR_TOSTRING_TOO_LONG;
> +						}
> +					} else {
> +						(*charsRequired) += 2;
> +					}
> +	/* [08/19]		append authority to result; */
> +					/* UserInfo */
> +					if (uri->userInfo.first != NULL) {
> +						const int charsToWrite = (int)(uri->userInfo.afterLast - uri->userInfo.first);
> +						if (dest != NULL) {
> +							if (written + charsToWrite <= maxChars) {
> +								memcpy(dest + written, uri->userInfo.first,
> +										charsToWrite * sizeof(URI_CHAR));
> +								written += charsToWrite;
> +							} else {
> +								dest[0] = _UT('\0');
> +								if (charsWritten != NULL) {
> +									*charsWritten = 0;
> +								}
> +								return URI_ERROR_TOSTRING_TOO_LONG;
> +							}
> +
> +							if (written + 1 <= maxChars) {
> +								memcpy(dest + written, _UT("@"),
> +										1 * sizeof(URI_CHAR));
> +								written += 1;
> +							} else {
> +								dest[0] = _UT('\0');
> +								if (charsWritten != NULL) {
> +									*charsWritten = 0;
> +								}
> +								return URI_ERROR_TOSTRING_TOO_LONG;
> +							}
> +						} else {
> +							(*charsRequired) += charsToWrite + 1;
> +						}
> +					}
> +
> +					/* Host */
> +					if (uri->hostData.ip4 != NULL) {
> +						/* IPv4 */
> +						int i = 0;
> +						for (; i < 4; i++) {
> +							const unsigned char value = uri->hostData.ip4->data[i];
> +							const int charsToWrite = (value > 99) ? 3 : ((value > 9) ? 2 : 1);
> +							if (dest != NULL) {
> +								if (written + charsToWrite <= maxChars) {
> +									URI_CHAR text[4];
> +									if (value > 99) {
> +										text[0] = _UT('0') + (value / 100);
> +										text[1] = _UT('0') + ((value % 100) / 10);
> +										text[2] = _UT('0') + (value % 10);
> +									} else if (value > 9)  {
> +										text[0] = _UT('0') + (value / 10);
> +										text[1] = _UT('0') + (value % 10);
> +									} else {
> +										text[0] = _UT('0') + value;
> +									}
> +									text[charsToWrite] = _UT('\0');
> +									memcpy(dest + written, text, charsToWrite * sizeof(URI_CHAR));
> +									written += charsToWrite;
> +								} else {
> +									dest[0] = _UT('\0');
> +									if (charsWritten != NULL) {
> +										*charsWritten = 0;
> +									}
> +									return URI_ERROR_TOSTRING_TOO_LONG;
> +								}
> +								if (i < 3) {
> +									if (written + 1 <= maxChars) {
> +										memcpy(dest + written, _UT("."),
> +												1 * sizeof(URI_CHAR));
> +										written += 1;
> +									} else {
> +										dest[0] = _UT('\0');
> +										if (charsWritten != NULL) {
> +											*charsWritten = 0;
> +										}
> +										return URI_ERROR_TOSTRING_TOO_LONG;
> +									}
> +								}
> +							} else {
> +								(*charsRequired) += charsToWrite + 1;
> +							}
> +						}
> +					} else if (uri->hostData.ip6 != NULL) {
> +						/* IPv6 */
> +						int i = 0;
> +						if (dest != NULL) {
> +							if (written + 1 <= maxChars) {
> +								memcpy(dest + written, _UT("["),
> +										1 * sizeof(URI_CHAR));
> +								written += 1;
> +							} else {
> +								dest[0] = _UT('\0');
> +								if (charsWritten != NULL) {
> +									*charsWritten = 0;
> +								}
> +								return URI_ERROR_TOSTRING_TOO_LONG;
> +							}
> +						} else {
> +							(*charsRequired) += 1;
> +						}
> +
> +						for (; i < 16; i++) {
> +							const unsigned char value = uri->hostData.ip6->data[i];
> +							if (dest != NULL) {
> +								if (written + 2 <= maxChars) {
> +									URI_CHAR text[3];
> +									text[0] = URI_FUNC(HexToLetterEx)(value / 16, URI_FALSE);
> +									text[1] = URI_FUNC(HexToLetterEx)(value % 16, URI_FALSE);
> +									text[2] = _UT('\0');
> +									memcpy(dest + written, text, 2 * sizeof(URI_CHAR));
> +									written += 2;
> +								} else {
> +									dest[0] = _UT('\0');
> +									if (charsWritten != NULL) {
> +										*charsWritten = 0;
> +									}
> +									return URI_ERROR_TOSTRING_TOO_LONG;
> +								}
> +							} else {
> +								(*charsRequired) += 2;
> +							}
> +							if (((i & 1) == 1) && (i < 15)) {
> +								if (dest != NULL) {
> +									if (written + 1 <= maxChars) {
> +										memcpy(dest + written, _UT(":"),
> +												1 * sizeof(URI_CHAR));
> +										written += 1;
> +									} else {
> +										dest[0] = _UT('\0');
> +										if (charsWritten != NULL) {
> +											*charsWritten = 0;
> +										}
> +										return URI_ERROR_TOSTRING_TOO_LONG;
> +									}
> +								} else {
> +									(*charsRequired) += 1;
> +								}
> +							}
> +						}
> +
> +						if (dest != NULL) {
> +							if (written + 1 <= maxChars) {
> +								memcpy(dest + written, _UT("]"),
> +										1 * sizeof(URI_CHAR));
> +								written += 1;
> +							} else {
> +								dest[0] = _UT('\0');
> +								if (charsWritten != NULL) {
> +									*charsWritten = 0;
> +								}
> +								return URI_ERROR_TOSTRING_TOO_LONG;
> +							}
> +						} else {
> +							(*charsRequired) += 1;
> +						}
> +					} else if (uri->hostData.ipFuture.first != NULL) {
> +						/* IPvFuture */
> +						const int charsToWrite = (int)(uri->hostData.ipFuture.afterLast
> +								- uri->hostData.ipFuture.first);
> +						if (dest != NULL) {
> +							if (written + 1 <= maxChars) {
> +								memcpy(dest + written, _UT("["),
> +										1 * sizeof(URI_CHAR));
> +								written += 1;
> +							} else {
> +								dest[0] = _UT('\0');
> +								if (charsWritten != NULL) {
> +									*charsWritten = 0;
> +								}
> +								return URI_ERROR_TOSTRING_TOO_LONG;
> +							}
> +
> +							if (written + charsToWrite <= maxChars) {
> +								memcpy(dest + written, uri->hostData.ipFuture.first, charsToWrite * sizeof(URI_CHAR));
> +								written += charsToWrite;
> +							} else {
> +								dest[0] = _UT('\0');
> +								if (charsWritten != NULL) {
> +									*charsWritten = 0;
> +								}
> +								return URI_ERROR_TOSTRING_TOO_LONG;
> +							}
> +
> +							if (written + 1 <= maxChars) {
> +								memcpy(dest + written, _UT("]"),
> +										1 * sizeof(URI_CHAR));
> +								written += 1;
> +							} else {
> +								dest[0] = _UT('\0');
> +								if (charsWritten != NULL) {
> +									*charsWritten = 0;
> +								}
> +								return URI_ERROR_TOSTRING_TOO_LONG;
> +							}
> +						} else {
> +							(*charsRequired) += 1 + charsToWrite + 1;
> +						}
> +					} else if (uri->hostText.first != NULL) {
> +						/* Regname */
> +						const int charsToWrite = (int)(uri->hostText.afterLast - uri->hostText.first);
> +						if (dest != NULL) {
> +							if (written + charsToWrite <= maxChars) {
> +								memcpy(dest + written, uri->hostText.first,
> +										charsToWrite * sizeof(URI_CHAR));
> +								written += charsToWrite;
> +							} else {
> +								dest[0] = _UT('\0');
> +								if (charsWritten != NULL) {
> +									*charsWritten = 0;
> +								}
> +								return URI_ERROR_TOSTRING_TOO_LONG;
> +							}
> +						} else {
> +							(*charsRequired) += charsToWrite;
> +						}
> +					}
> +
> +					/* Port */
> +					if (uri->portText.first != NULL) {
> +						const int charsToWrite = (int)(uri->portText.afterLast - uri->portText.first);
> +						if (dest != NULL) {
> +							/* Leading ':' */
> +							if (written + 1 <= maxChars) {
> +									memcpy(dest + written, _UT(":"),
> +											1 * sizeof(URI_CHAR));
> +									written += 1;
> +							} else {
> +								dest[0] = _UT('\0');
> +								if (charsWritten != NULL) {
> +									*charsWritten = 0;
> +								}
> +								return URI_ERROR_TOSTRING_TOO_LONG;
> +							}
> +
> +							/* Port number */
> +							if (written + charsToWrite <= maxChars) {
> +								memcpy(dest + written, uri->portText.first,
> +										charsToWrite * sizeof(URI_CHAR));
> +								written += charsToWrite;
> +							} else {
> +								dest[0] = _UT('\0');
> +								if (charsWritten != NULL) {
> +									*charsWritten = 0;
> +								}
> +								return URI_ERROR_TOSTRING_TOO_LONG;
> +							}
> +						} else {
> +							(*charsRequired) += 1 + charsToWrite;
> +						}
> +					}
> +	/* [09/19]	endif; */
> +				}
> +	/* [10/19]	append path to result; */
> +				/* Slash needed here? */
> +				if (uri->absolutePath || ((uri->pathHead != NULL)
> +						&& URI_FUNC(IsHostSet)(uri))) {
> +					if (dest != NULL) {
> +						if (written + 1 <= maxChars) {
> +							memcpy(dest + written, _UT("/"),
> +									1 * sizeof(URI_CHAR));
> +							written += 1;
> +						} else {
> +							dest[0] = _UT('\0');
> +							if (charsWritten != NULL) {
> +								*charsWritten = 0;
> +							}
> +							return URI_ERROR_TOSTRING_TOO_LONG;
> +						}
> +					} else {
> +						(*charsRequired) += 1;
> +					}
> +				}
> +
> +				if (uri->pathHead != NULL) {
> +					URI_TYPE(PathSegment) * walker = uri->pathHead;
> +					do {
> +						const int charsToWrite = (int)(walker->text.afterLast - walker->text.first);
> +						if (dest != NULL) {
> +							if (written + charsToWrite <= maxChars) {
> +								memcpy(dest + written, walker->text.first,
> +										charsToWrite * sizeof(URI_CHAR));
> +								written += charsToWrite;
> +							} else {
> +								dest[0] = _UT('\0');
> +								if (charsWritten != NULL) {
> +									*charsWritten = 0;
> +								}
> +								return URI_ERROR_TOSTRING_TOO_LONG;
> +							}
> +						} else {
> +							(*charsRequired) += charsToWrite;
> +						}
> +
> +						/* Not last segment -> append slash */
> +						if (walker->next != NULL) {
> +							if (dest != NULL) {
> +								if (written + 1 <= maxChars) {
> +									memcpy(dest + written, _UT("/"),
> +											1 * sizeof(URI_CHAR));
> +									written += 1;
> +								} else {
> +									dest[0] = _UT('\0');
> +									if (charsWritten != NULL) {
> +										*charsWritten = 0;
> +									}
> +									return URI_ERROR_TOSTRING_TOO_LONG;
> +								}
> +							} else {
> +								(*charsRequired) += 1;
> +							}
> +						}
> +
> +						walker = walker->next;
> +					} while (walker != NULL);
> +				}
> +	/* [11/19]	if defined(query) then */
> +				if (uri->query.first != NULL) {
> +	/* [12/19]		append "?" to result; */
> +					if (dest != NULL) {
> +						if (written + 1 <= maxChars) {
> +							memcpy(dest + written, _UT("?"),
> +									1 * sizeof(URI_CHAR));
> +							written += 1;
> +						} else {
> +							dest[0] = _UT('\0');
> +							if (charsWritten != NULL) {
> +								*charsWritten = 0;
> +							}
> +							return URI_ERROR_TOSTRING_TOO_LONG;
> +						}
> +					} else {
> +						(*charsRequired) += 1;
> +					}
> +	/* [13/19]		append query to result; */
> +					{
> +						const int charsToWrite
> +								= (int)(uri->query.afterLast - uri->query.first);
> +						if (dest != NULL) {
> +							if (written + charsToWrite <= maxChars) {
> +								memcpy(dest + written, uri->query.first,
> +										charsToWrite * sizeof(URI_CHAR));
> +								written += charsToWrite;
> +							} else {
> +								dest[0] = _UT('\0');
> +								if (charsWritten != NULL) {
> +									*charsWritten = 0;
> +								}
> +								return URI_ERROR_TOSTRING_TOO_LONG;
> +							}
> +						} else {
> +							(*charsRequired) += charsToWrite;
> +						}
> +					}
> +	/* [14/19]	endif; */
> +				}
> +	/* [15/19]	if defined(fragment) then */
> +				if (uri->fragment.first != NULL) {
> +	/* [16/19]		append "#" to result; */
> +					if (dest != NULL) {
> +						if (written + 1 <= maxChars) {
> +							memcpy(dest + written, _UT("#"),
> +									1 * sizeof(URI_CHAR));
> +							written += 1;
> +						} else {
> +							dest[0] = _UT('\0');
> +							if (charsWritten != NULL) {
> +								*charsWritten = 0;
> +							}
> +							return URI_ERROR_TOSTRING_TOO_LONG;
> +						}
> +					} else {
> +						(*charsRequired) += 1;
> +					}
> +	/* [17/19]		append fragment to result; */
> +					{
> +						const int charsToWrite
> +								= (int)(uri->fragment.afterLast - uri->fragment.first);
> +						if (dest != NULL) {
> +							if (written + charsToWrite <= maxChars) {
> +								memcpy(dest + written, uri->fragment.first,
> +										charsToWrite * sizeof(URI_CHAR));
> +								written += charsToWrite;
> +							} else {
> +								dest[0] = _UT('\0');
> +								if (charsWritten != NULL) {
> +									*charsWritten = 0;
> +								}
> +								return URI_ERROR_TOSTRING_TOO_LONG;
> +							}
> +						} else {
> +							(*charsRequired) += charsToWrite;
> +						}
> +					}
> +	/* [18/19]	endif; */
> +				}
> +	/* [19/19]	return result; */
> +				if (dest != NULL) {
> +					dest[written++] = _UT('\0');
> +					if (charsWritten != NULL) {
> +						*charsWritten = written;
> +					}
> +				}
> +				return URI_SUCCESS;
> +}
> +
> +
> +
> +#endif
> diff --git a/uriparser/lib/UriResolve.c b/uriparser/lib/UriResolve.c
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriResolve.c
> @@ -0,0 +1,255 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 <uriparser/UriDefsConfig.h>
> +#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
> +/* Include SELF twice */
> +# define URI_PASS_ANSI 1
> +# include "UriResolve.c"
> +# undef URI_PASS_ANSI
> +# define URI_PASS_UNICODE 1
> +# include "UriResolve.c"
> +# undef URI_PASS_UNICODE
> +#else
> +# ifdef URI_PASS_ANSI
> +#  include <uriparser/UriDefsAnsi.h>
> +# else
> +#  include <uriparser/UriDefsUnicode.h>
> +#  include <wchar.h>
> +# endif
> +
> +
> +
> +#ifndef URI_DOXYGEN
> +# include <uriparser/Uri.h>
> +# include "UriCommon.h"
> +#endif
> +
> +
> +
> +/* Appends a relative URI to an absolute. The last path segement of
> + * the absolute URI is replaced. */
> +static URI_INLINE UriBool URI_FUNC(MergePath)(URI_TYPE(Uri) * absWork,
> +		const URI_TYPE(Uri) * relAppend) {
> +	URI_TYPE(PathSegment) * sourceWalker;
> +	URI_TYPE(PathSegment) * destPrev;
> +	if (relAppend->pathHead == NULL) {
> +		return URI_TRUE;
> +	}
> +
> +	/* Replace last segment ("" if trailing slash) with first of append chain */
> +	if (absWork->pathHead == NULL) {
> +		URI_TYPE(PathSegment) * const dup = malloc(sizeof(URI_TYPE(PathSegment)));
> +		if (dup == NULL) {
> +			return URI_FALSE; /* Raises malloc error */
> +		}
> +		dup->next = NULL;
> +		absWork->pathHead = dup;
> +		absWork->pathTail = dup;
> +	}
> +	absWork->pathTail->text.first = relAppend->pathHead->text.first;
> +	absWork->pathTail->text.afterLast = relAppend->pathHead->text.afterLast;
> +
> +	/* Append all the others */
> +	sourceWalker = relAppend->pathHead->next;
> +	if (sourceWalker == NULL) {
> +		return URI_TRUE;
> +	}
> +	destPrev = absWork->pathTail;
> +
> +	for (;;) {
> +		URI_TYPE(PathSegment) * const dup = malloc(sizeof(URI_TYPE(PathSegment)));
> +		if (dup == NULL) {
> +			destPrev->next = NULL;
> +			absWork->pathTail = destPrev;
> +			return URI_FALSE; /* Raises malloc error */
> +		}
> +		dup->text = sourceWalker->text;
> +		destPrev->next = dup;
> +
> +		if (sourceWalker->next == NULL) {
> +			absWork->pathTail = dup;
> +			absWork->pathTail->next = NULL;
> +			break;
> +		}
> +		destPrev = dup;
> +		sourceWalker = sourceWalker->next;
> +	}
> +
> +	return URI_TRUE;
> +}
> +
> +
> +
> +static int URI_FUNC(AddBaseUriImpl)(URI_TYPE(Uri) * absDest,
> +		const URI_TYPE(Uri) * relSource,
> +		const URI_TYPE(Uri) * absBase) {
> +	if (absDest == NULL) {
> +		return URI_ERROR_NULL;
> +	}
> +	URI_FUNC(ResetUri)(absDest);
> +
> +	if ((relSource == NULL) || (absBase == NULL)) {
> +		return URI_ERROR_NULL;
> +	}
> +
> +	/* absBase absolute? */
> +	if (absBase->scheme.first == NULL) {
> +		return URI_ERROR_ADDBASE_REL_BASE;
> +	}
> +
> +	/* [01/32]	if defined(R.scheme) then */
> +				if (relSource->scheme.first != NULL) {
> +	/* [02/32]		T.scheme = R.scheme; */
> +					absDest->scheme = relSource->scheme;
> +	/* [03/32]		T.authority = R.authority; */
> +					if (!URI_FUNC(CopyAuthority)(absDest, relSource)) {
> +						return URI_ERROR_MALLOC;
> +					}
> +	/* [04/32]		T.path = remove_dot_segments(R.path); */
> +					if (!URI_FUNC(CopyPath)(absDest, relSource)) {
> +						return URI_ERROR_MALLOC;
> +					}
> +					if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest)) {
> +						return URI_ERROR_MALLOC;
> +					}
> +	/* [05/32]		T.query = R.query; */
> +					absDest->query = relSource->query;
> +	/* [06/32]	else */
> +				} else {
> +	/* [07/32]		if defined(R.authority) then */
> +					if (URI_FUNC(IsHostSet)(relSource)) {
> +	/* [08/32]			T.authority = R.authority; */
> +						if (!URI_FUNC(CopyAuthority)(absDest, relSource)) {
> +							return URI_ERROR_MALLOC;
> +						}
> +	/* [09/32]			T.path = remove_dot_segments(R.path); */
> +						if (!URI_FUNC(CopyPath)(absDest, relSource)) {
> +							return URI_ERROR_MALLOC;
> +						}
> +						if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest)) {
> +							return URI_ERROR_MALLOC;
> +						}
> +	/* [10/32]			T.query = R.query; */
> +						absDest->query = relSource->query;
> +	/* [11/32]		else */
> +					} else {
> +	/* [28/32]			T.authority = Base.authority; */
> +						if (!URI_FUNC(CopyAuthority)(absDest, absBase)) {
> +							return URI_ERROR_MALLOC;
> +						}
> +	/* [12/32]			if (R.path == "") then */
> +						if (relSource->pathHead == NULL) {
> +	/* [13/32]				T.path = Base.path; */
> +							if (!URI_FUNC(CopyPath)(absDest, absBase)) {
> +								return URI_ERROR_MALLOC;
> +							}
> +	/* [14/32]				if defined(R.query) then */
> +							if (relSource->query.first != NULL) {
> +	/* [15/32]					T.query = R.query; */
> +								absDest->query = relSource->query;
> +	/* [16/32]				else */
> +							} else {
> +	/* [17/32]					T.query = Base.query; */
> +								absDest->query = absBase->query;
> +	/* [18/32]				endif; */
> +							}
> +	/* [19/32]			else */
> +						} else {
> +	/* [20/32]				if (R.path starts-with "/") then */
> +							if (relSource->absolutePath) {
> +	/* [21/32]					T.path = remove_dot_segments(R.path); */
> +								if (!URI_FUNC(CopyPath)(absDest, relSource)) {
> +									return URI_ERROR_MALLOC;
> +								}
> +								if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest)) {
> +									return URI_ERROR_MALLOC;
> +								}
> +	/* [22/32]				else */
> +							} else {
> +	/* [23/32]					T.path = merge(Base.path, R.path); */
> +								if (!URI_FUNC(CopyPath)(absDest, absBase)) {
> +									return URI_ERROR_MALLOC;
> +								}
> +								if (!URI_FUNC(MergePath)(absDest, relSource)) {
> +									return URI_ERROR_MALLOC;
> +								}
> +	/* [24/32]					T.path = remove_dot_segments(T.path); */
> +								if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest)) {
> +									return URI_ERROR_MALLOC;
> +								}
> +
> +								if (!URI_FUNC(FixAmbiguity)(absDest)) {
> +									return URI_ERROR_MALLOC;
> +								}
> +	/* [25/32]				endif; */
> +							}
> +	/* [26/32]				T.query = R.query; */
> +							absDest->query = relSource->query;
> +	/* [27/32]			endif; */
> +						}
> +						URI_FUNC(FixEmptyTrailSegment)(absDest);
> +	/* [29/32]		endif; */
> +					}
> +	/* [30/32]		T.scheme = Base.scheme; */
> +					absDest->scheme = absBase->scheme;
> +	/* [31/32]	endif; */
> +				}
> +	/* [32/32]	T.fragment = R.fragment; */
> +				absDest->fragment = relSource->fragment;
> +
> +	return URI_SUCCESS;
> +
> +}
> +
> +
> +
> +int URI_FUNC(AddBaseUri)(URI_TYPE(Uri) * absDest,
> +		const URI_TYPE(Uri) * relSource, const URI_TYPE(Uri) * absBase) {
> +	const int res = URI_FUNC(AddBaseUriImpl)(absDest, relSource, absBase);
> +	if ((res != URI_SUCCESS) && (absDest != NULL)) {
> +		URI_FUNC(FreeUriMembers)(absDest);
> +	}
> +	return res;
> +}
> +
> +
> +
> +#endif
> diff --git a/uriparser/lib/UriShorten.c b/uriparser/lib/UriShorten.c
> new file mode 100644
> --- /dev/null
> +++ b/uriparser/lib/UriShorten.c
> @@ -0,0 +1,316 @@
> +/*
> + * uriparser - RFC 3986 URI parsing library
> + *
> + * Copyright (C) 2007, Weijia Song <[email protected]>
> + * Copyright (C) 2007, Sebastian Pipping <[email protected]>
> + * 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 <uriparser/UriDefsConfig.h>
> +#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
> +/* Include SELF twice */
> +# define URI_PASS_ANSI 1
> +# include "UriShorten.c"
> +# undef URI_PASS_ANSI
> +# define URI_PASS_UNICODE 1
> +# include "UriShorten.c"
> +# undef URI_PASS_UNICODE
> +#else
> +# ifdef URI_PASS_ANSI
> +#  include <uriparser/UriDefsAnsi.h>
> +# else
> +#  include <uriparser/UriDefsUnicode.h>
> +#  include <wchar.h>
> +# endif
> +
> +
> +
> +#ifndef URI_DOXYGEN
> +# include <uriparser/Uri.h>
> +# include "UriCommon.h"
> +#endif
> +
> +
> +
> +static URI_INLINE UriBool URI_FUNC(AppendSegment)(URI_TYPE(Uri) * uri,
> +		const URI_CHAR * first, const URI_CHAR * afterLast) {
> +	/* Create segment */
> +	URI_TYPE(PathSegment) * segment = malloc(1 * sizeof(URI_TYPE(PathSegment)));
> +	if (segment == NULL) {
> +		return URI_FALSE; /* Raises malloc error */
> +	}
> +	segment->next = NULL;
> +	segment->text.first = first;
> +	segment->text.afterLast = afterLast;
> +
> +	/* Put into chain */
> +	if (uri->pathTail == NULL) {
> +		uri->pathHead = segment;
> +	} else {
> +		uri->pathTail->next = segment;
> +	}
> +	uri->pathTail = segment;
> +
> +	return URI_TRUE;
> +}
> +
> +
> +
> +static URI_INLINE UriBool URI_FUNC(EqualsAuthority)(const URI_TYPE(Uri) * first,
> +		const URI_TYPE(Uri) * second) {
> +	/* IPv4 */
> +	if (first->hostData.ip4 != NULL) {
> +		return ((second->hostData.ip4 != NULL)
> +				&& !memcmp(first->hostData.ip4->data,
> +					second->hostData.ip4->data, 4)) ? URI_TRUE : URI_FALSE;
> +	}
> +
> +	/* IPv6 */
> +	if (first->hostData.ip6 != NULL) {
> +		return ((second->hostData.ip6 != NULL)
> +				&& !memcmp(first->hostData.ip6->data,
> +					second->hostData.ip6->data, 16)) ? URI_TRUE : URI_FALSE;
> +	}
> +
> +	/* IPvFuture */
> +	if (first->hostData.ipFuture.first != NULL) {
> +		return ((second->hostData.ipFuture.first != NULL)
> +				&& !URI_STRNCMP(first->hostData.ipFuture.first,
> +					second->hostData.ipFuture.first,
> +					first->hostData.ipFuture.afterLast
> +					- first->hostData.ipFuture.first))
> +						? URI_TRUE : URI_FALSE;
> +	}
> +
> +	if (first->hostText.first != NULL) {
> +		return ((second->hostText.first != NULL)
> +				&& !URI_STRNCMP(first->hostText.first,
> +					second->hostText.first,
> +					first->hostText.afterLast
> +					- first->hostText.first)) ? URI_TRUE : URI_FALSE;
> +	}
> +
> +	return (second->hostText.first == NULL);
> +}
> +
> +
> +
> +int URI_FUNC(RemoveBaseUriImpl)(URI_TYPE(Uri) * dest,
> +		const URI_TYPE(Uri) * absSource,
> +		const URI_TYPE(Uri) * absBase,
> +		UriBool domainRootMode) {
> +	if (dest == NULL) {
> +		return URI_ERROR_NULL;
> +	}
> +	URI_FUNC(ResetUri)(dest);
> +
> +	if ((absSource == NULL) || (absBase == NULL)) {
> +		return URI_ERROR_NULL;
> +	}
> +
> +	/* absBase absolute? */
> +	if (absBase->scheme.first == NULL) {
> +		return URI_ERROR_REMOVEBASE_REL_BASE;
> +	}
> +
> +	/* absSource absolute? */
> +	if (absSource->scheme.first == NULL) {
> +		return URI_ERROR_REMOVEBASE_REL_SOURCE;
> +	}
> +
> +	/* [01/50]	if (A.scheme != Base.scheme) then */
> +				if (URI_STRNCMP(absSource->scheme.first, absBase->scheme.first,
> +						absSource->scheme.afterLast - absSource->scheme.first)) {
> +	/* [02/50]	   T.scheme    = A.scheme; */
> +					dest->scheme = absSource->scheme;
> +	/* [03/50]	   T.authority = A.authority; */
> +					if (!URI_FUNC(CopyAuthority)(dest, absSource)) {
> +						return URI_ERROR_MALLOC;
> +					}
> +	/* [04/50]	   T.path      = A.path; */
> +					if (!URI_FUNC(CopyPath)(dest, absSource)) {
> +						return URI_ERROR_MALLOC;
> +					}
> +	/* [05/50]	else */
> +				} else {
> +	/* [06/50]	   undef(T.scheme); */
> +					/* NOOP */
> +	/* [07/50]	   if (A.authority != Base.authority) then */
> +					if (!URI_FUNC(EqualsAuthority)(absSource, absBase)) {
> +	/* [08/50]	      T.authority = A.authority; */
> +						if (!URI_FUNC(CopyAuthority)(dest, absSource)) {
> +							return URI_ERROR_MALLOC;
> +						}
> +	/* [09/50]	      T.path      = A.path; */
> +						if (!URI_FUNC(CopyPath)(dest, absSource)) {
> +							return URI_ERROR_MALLOC;
> +						}
> +	/* [10/50]	   else */
> +					} else {
> +	/* [11/50]	      if domainRootMode then */
> +						if (domainRootMode == URI_TRUE) {
> +	/* [12/50]	         undef(T.authority); */
> +							/* NOOP */
> +	/* [13/50]	         if (first(A.path) == "") then */
> +							/* GROUPED */
> +	/* [14/50]	            T.path   = "/." + A.path; */
> +								/* GROUPED */
> +	/* [15/50]	         else */
> +								/* GROUPED */
> +	/* [16/50]	            T.path   = A.path; */
> +								/* GROUPED */
> +	/* [17/50]	         endif; */
> +							if (!URI_FUNC(CopyPath)(dest, absSource)) {
> +								return URI_ERROR_MALLOC;
> +							}
> +							dest->absolutePath = URI_TRUE;
> +
> +							if (!URI_FUNC(FixAmbiguity)(dest)) {
> +								return URI_ERROR_MALLOC;
> +							}
> +	/* [18/50]	      else */
> +						} else {
> +							const URI_TYPE(PathSegment) * sourceSeg = absSource->pathHead;
> +							const URI_TYPE(PathSegment) * baseSeg = absBase->pathHead;
> +	/* [19/50]	         bool pathNaked = true; */
> +							UriBool pathNaked = URI_TRUE;
> +	/* [20/50]	         undef(last(Base.path)); */
> +							/* NOOP */
> +	/* [21/50]	         T.path = ""; */
> +							dest->absolutePath = URI_FALSE;
> +	/* [22/50]	         while (first(A.path) == first(Base.path)) do */
> +							while ((sourceSeg != NULL) && (baseSeg != NULL)
> +									&& !URI_STRNCMP(sourceSeg->text.first, baseSeg->text.first,
> +									sourceSeg->text.afterLast - sourceSeg->text.first)
> +									&& !((sourceSeg->text.first == sourceSeg->text.afterLast)
> +										&& ((sourceSeg->next == NULL) != (baseSeg->next == NULL)))) {
> +	/* [23/50]	            A.path++; */
> +								sourceSeg = sourceSeg->next;
> +	/* [24/50]	            Base.path++; */
> +								baseSeg = baseSeg->next;
> +	/* [25/50]	         endwhile; */
> +							}
> +	/* [26/50]	         while defined(first(Base.path)) do */
> +							while ((baseSeg != NULL) && (baseSeg->next != NULL)) {
> +	/* [27/50]	            Base.path++; */
> +								baseSeg = baseSeg->next;
> +	/* [28/50]	            T.path += "../"; */
> +								if (!URI_FUNC(AppendSegment)(dest, URI_FUNC(ConstParent),
> +										URI_FUNC(ConstParent) + 2)) {
> +									return URI_ERROR_MALLOC;
> +								}
> +	/* [29/50]	            pathNaked = false; */
> +								pathNaked = URI_FALSE;
> +	/* [30/50]	         endwhile; */
> +							}
> +	/* [31/50]	         while defined(first(A.path)) do */
> +							while (sourceSeg != NULL) {
> +	/* [32/50]	            if pathNaked then */
> +								if (pathNaked == URI_TRUE) {
> +	/* [33/50]	               if (first(A.path) contains ":") then */
> +									UriBool containsColon = URI_FALSE;
> +									const URI_CHAR * ch = sourceSeg->text.first;
> +									for (; ch < sourceSeg->text.afterLast; ch++) {
> +										if (*ch == _UT(':')) {
> +											containsColon = URI_TRUE;
> +											break;
> +										}
> +									}
> +
> +									if (containsColon) {
> +	/* [34/50]	                  T.path += "./"; */
> +										if (!URI_FUNC(AppendSegment)(dest, URI_FUNC(ConstPwd),
> +												URI_FUNC(ConstPwd) + 1)) {
> +											return URI_ERROR_MALLOC;
> +										}
> +	/* [35/50]	               elseif (first(A.path) == "") then */
> +									} else if (sourceSeg->text.first == sourceSeg->text.afterLast) {
> +	/* [36/50]	                  T.path += "/."; */
> +										if (!URI_FUNC(AppendSegment)(dest, URI_FUNC(ConstPwd),
> +												URI_FUNC(ConstPwd) + 1)) {
> +											return URI_ERROR_MALLOC;
> +										}
> +	/* [37/50]	               endif; */
> +									}
> +	/* [38/50]	            endif; */
> +								}
> +	/* [39/50]	            T.path += first(A.path); */
> +								if (!URI_FUNC(AppendSegment)(dest, sourceSeg->text.first,
> +										sourceSeg->text.afterLast)) {
> +									return URI_ERROR_MALLOC;
> +								}
> +	/* [40/50]	            pathNaked = false; */
> +								pathNaked = URI_FALSE;
> +	/* [41/50]	            A.path++; */
> +								sourceSeg = sourceSeg->next;
> +	/* [42/50]	            if defined(first(A.path)) then */
> +								/* NOOP */
> +	/* [43/50]	               T.path += + "/"; */
> +								/* NOOP */
> +	/* [44/50]	            endif; */
> +								/* NOOP */
> +	/* [45/50]	         endwhile; */
> +							}
> +	/* [46/50]	      endif; */
> +						}
> +	/* [47/50]	   endif; */
> +					}
> +	/* [48/50]	endif; */
> +				}
> +	/* [49/50]	T.query     = A.query; */
> +				dest->query = absSource->query;
> +	/* [50/50]	T.fragment  = A.fragment; */
> +				dest->fragment = absSource->fragment;
> +
> +	return URI_SUCCESS;
> +}
> +
> +
> +
> +int URI_FUNC(RemoveBaseUri)(URI_TYPE(Uri) * dest,
> +		const URI_TYPE(Uri) * absSource,
> +		const URI_TYPE(Uri) * absBase,
> +		UriBool domainRootMode) {
> +	const int res = URI_FUNC(RemoveBaseUriImpl)(dest, absSource,
> +			absBase, domainRootMode);
> +	if ((res != URI_SUCCESS) && (dest != NULL)) {
> +		URI_FUNC(FreeUriMembers)(dest);
> +	}
> +	return res;
> +}
> +
> +
> +
> +#endif
>
> _______________________________________________
> rrd-developers mailing list
> [email protected]
> https://lists.oetiker.ch/cgi-bin/listinfo/rrd-developers
>
>

-- 
Tobi Oetiker, OETIKER+PARTNER AG, Aarweg 15 CH-4600 Olten, Switzerland
http://it.oetiker.ch [email protected] ++41 62 775 9902 / sb: -9900
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.