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