/**
* @mainpage
*
* @section SEC_TOC Table of Contents
* - Introduction
* - Algorithms and Examples
* - Parsing URIs (from string to object)
* - Recomposing URIs (from object back to string)
* - Resolving References
* - Creating References
* - Filenames and URIs
* - Normalizing URIs
* - Working with query strings
* - Ansi and Unicode
* - Autoconf Check
*
*
* @section intro Introduction
* Welcome to the short uriparser integration tutorial.
* It is intended to answer upcoming questions and to shed light
* where function prototypes alone are not enough.
* Please drop me a line if you need further assistance and I will
* see what I can do for you. Good luck with uriparser!
*
*
* @subsection parsing Parsing URIs (from string to object)
* Parsing a URI with uriparser looks like this:
*
* @code
* UriParserStateA state;
* UriUriA uri;
*
* state.uri = &uri;
* if (uriParseUriA(&state, "file:///home/user/song.mp3") != URI_SUCCESS) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* uriFreeUriMembersA(&uri);
* ...
* }
* ...
* uriFreeUriMembersA(&uri);
* @endcode
*
* While the URI object (::UriUriA) holds information about the recogized
* parts of the given URI string, the parser state object (::UriParserStateA)
* keeps error code and position. This information does not belong to
* the URI itself, which is why there are two seperate objects.
*
* You can reuse parser state objects for parsing several URIs like this:
*
* @code
* UriParserStateA state;
* UriUriA uriOne;
* UriUriA uriTwo;
*
* state.uri = &uriOne;
* if (uriParseUriA(&state, "file:///home/user/one") != URI_SUCCESS) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* uriFreeUriMembersA(&uriOne);
* ...
* }
* ...
* state.uri = &uriTwo;
* if (uriParseUriA(&state, "file:///home/user/two") != URI_SUCCESS) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* uriFreeUriMembersA(&uriOne);
* uriFreeUriMembersA(&uriTwo);
* ...
* }
* ...
* uriFreeUriMembersA(&uriOne);
* uriFreeUriMembersA(&uriTwo);
* @endcode
*
*
* @subsection recomposition Recomposing URIs (from object back to string)
* According to RFC 3986
* glueing parts of a URI together to form a string is called recomposition.
* Before we can recompose a URI object we have to know how much
* space the resulting string will take:
*
* @code
* UriUriA uri;
* char * uriString;
* int charsRequired;
* ...
* if (uriToStringCharsRequiredA(&uri, &charsRequired) != URI_SUCCESS) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* ...
* }
* charsRequired++;
* @endcode
*
* Now we can tell uriToStringA() to write the string to a given buffer:
*
* @code
* uriString = malloc(charsRequired * sizeof(char));
* if (uriString == NULL) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* ...
* }
* if (uriToStringA(uriString, &uri, charsRequired, NULL) != URI_SUCCESS) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* ...
* }
* @endcode
*
* @remarks
* Incrementing charsRequired by 1 is required since
* uriToStringCharsRequiredA() returns the length of the string
* as strlen() does, but uriToStringA() works with the number
* of maximum characters to be written including the
* zero-terminator.
*
*
* @subsection resolution Resolving References
* Reference Resolution
* is the process of turning a (relative) URI reference into an absolute URI by applying a base
* URI to it. In code it looks like this:
*
* @code
* UriUriA absoluteDest;
* UriUriA relativeSource;
* UriUriA absoluteBase;
* ...
* /COMMENT_HACK* relativeSource holds "../TWO" now *COMMENT_HACK/
* /COMMENT_HACK* absoluteBase holds "file:///one/two/three" now *COMMENT_HACK/
* if (uriAddBaseUriA(&absoluteDest, &relativeSource, &absoluteBase) != URI_SUCCESS) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* uriFreeUriMembersA(&absoluteDest);
* ...
* }
* /COMMENT_HACK* absoluteDest holds "file:///one/TWO" now *COMMENT_HACK/
* ...
* uriFreeUriMembersA(&absoluteDest);
* @endcode
*
* @remarks
* uriAddBaseUriA() does not normalize the resulting URI.
* Usually you might want to pass it through uriNormalizeSyntaxA() after.
*
*
* @subsection shortening Creating References
* Reference Creation is the inverse process of Reference Resolution: A common base URI
* is "substracted" from an absolute URI to make a (relative) reference.
* If the base URI is not common the remaining URI will still be absolute, i.e. will
* carry a scheme
*
* @code
* UriUriA dest;
* UriUriA absoluteSource;
* UriUriA absoluteBase;
* ...
* /COMMENT_HACK* absoluteSource holds "file:///one/TWO" now *COMMENT_HACK/
* /COMMENT_HACK* absoluteBase holds "file:///one/two/three" now *COMMENT_HACK/
* if (uriRemoveBaseUriA(&dest, &absoluteSource, &absoluteBase, URI_FALSE) != URI_SUCCESS) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* uriFreeUriMembersA(&dest);
* ...
* }
* /COMMENT_HACK* dest holds "../TWO" now *COMMENT_HACK/
* ...
* uriFreeUriMembersA(&dest);
* @endcode
*
* The fourth parameter is the domain root mode. With URI_FALSE as above this will produce
* URIs relative to the base URI. With URI_TRUE the resulting URI will be relative to the
* domain root instead, e.g. "/one/TWO" in this case.
*
*
* @subsection filenames Filenames and URIs
* Converting filenames to and from URIs works on strings directly,
* i.e. without creating an URI object.
*
* @code
* const char * const absFilename = "E:\\Documents and Settings";
* const int bytesNeeded = 8 + 3 * strlen(absFilename) + 1;
* char * absUri = malloc(bytesNeeded * sizeof(char));
* if (uriWindowsFilenameToUriStringA(absFilename, absUri) != URI_SUCCESS) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* free(absUri);
* ...
* }
* /COMMENT_HACK* absUri is "file:///E:/Documents%20and%20Settings" now *COMMENT_HACK/
* ...
* free(absUri);
* @endcode
*
* Conversion works ..
* - for relative or absolute values,
* - in both directions (filenames <--> URIs) and
* - with Unix and Windows filenames.
*
* All you have to do is to choose the right function for the task and allocate
* the required space (in characters) for the target buffer.
* Let me present you an overview:
*
* - Filename --> URI
* - uriUnixFilenameToUriStringA()\n
* Space required: [7 +] 3 * len(filename) + 1
* - uriWindowsFilenameToUriStringA()\n
* Space required: [8 +] 3 * len(filename) + 1
* - URI --> filename
* - uriUriStringToUnixFilenameA()\n
* Space required: len(uriString) + 1 [- 7]
* - uriUriStringToWindowsFilenameA()\n
* Space required: len(uriString) + 1 [- 8]
*
*
* @subsection normalization Normalizing URIs
* Sometimes we come accross unnecessarily long URIs like "http://example.org/one/two/../../one".
* The algorithm we can use to shorten this URI down to "http://example.org/one" is called
* Syntax-Based Normalization.
* Note that normalizing a URI does more than just "stripping dot segments". Please have a look at
* Section 6.2.2 of RFC 3986
* for the full description.
*
* As we asked uriToStringCharsRequiredA() for the required space when converting
* a URI object back to a sring, we can ask uriNormalizeSyntaxMaskRequiredA() for
* the parts of a URI that require normalization and then pass this normalization
* mask to uriNormalizeSyntaxExA():
*
* @code
* const unsigned int dirtyParts = uriNormalizeSyntaxMaskRequiredA(&uri);
* if (uriNormalizeSyntaxExA(&uri, dirtyParts) != URI_SUCCESS) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* ...
* }
* @endcode
*
* If you don't want to normalize all parts of the URI you can pass a custom
* mask as well:
*
* @code
* const unsigned int normMask = URI_NORMALIZE_SCHEME | URI_NORMALIZE_USER_INFO;
* if (uriNormalizeSyntaxExA(&uri, normMask) != URI_SUCCESS) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* ...
* }
* @endcode
*
* Please see ::UriNormalizationMaskEnum for the complete set of flags.
*
* On the other hand calling plain uriNormalizeSyntaxA() (without the "Ex")
* saves you thinking about single parts, as it queries uriNormalizeSyntaxMaskRequiredA()
* internally:
*
* @code
* if (uriNormalizeSyntaxA(&uri) != URI_SUCCESS) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* ...
* }
* @endcode
*
*
* @section querystrings Working with query strings
* RFC 3986
* itself does not understand the query part of a URI as a list of key/value pairs.
* But HTML 2.0 does and defines a media type application/x-www-form-urlencoded
* in in section 8.2.1
* of RFC 1866.
* uriparser allows you to dissect (or parse) a query string into unescaped key/value pairs
* and back.
*
* To dissect the query part of a just-parsed URI you could write code like this:
*
* @code
* UriUriA uri;
* UriQueryListA * queryList;
* int itemCount;
* ...
* if (uriDissectQueryMallocA(&queryList, &itemCount, uri.query.first,
* uri.query.afterLast) != URI_SUCCESS) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* ...
* }
* ...
* uriFreeQueryListA(queryList);
* @endcode
*
* @remarks
* - NULL in the value member means there was no '=' in the item text as with "?abc&def".
* - An empty string in the value member means there was '=' in the item as with "?abc=&def".
*
*
* To compose a query string from a query list you could write code like this:
*
* @code
* int charsRequired;
* int charsWritten;
* char * queryString;
* ...
* if (uriComposeQueryCharsRequiredA(queryList, &charsRequired) != URI_SUCCESS) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* ...
* }
* queryString = malloc((charsRequired + 1) * sizeof(char));
* if (queryString == NULL) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* ...
* }
* if (uriComposeQueryA(queryString, queryList, charsRequired + 1, &charsWritten) != URI_SUCCESS) {
* /COMMENT_HACK* Failure *COMMENT_HACK/
* ...
* }
* ...
* free(queryString);
* @endcode
*
*
* @section chartypes Ansi and Unicode
* uriparser comes with two versions of every structure and function:
* one handling Ansi text (char *) and one working with Unicode text (wchar_t *),
* for instance
* - uriParseUriA() for Ansi and
* - uriParseUriW() for Unicode.
*
* This tutorial only shows the usage of the Ansi editions but
* their Unicode counterparts work in the very same way.
*
*
* @section autoconf Autoconf Check
* You can use the code below to make ./configure test for presence
* of uriparser 0.6.4 or later.
*
*
URIPARSER_MISSING="Please install uriparser 0.6.4 or later.
* On a Debian-based system enter 'sudo apt-get install liburiparser-dev'."
*AC_CHECK_LIB(uriparser, uriParseUriA,, AC_MSG_ERROR(${URIPARSER_MISSING}))
*AC_CHECK_HEADER(uriparser/Uri.h,, AC_MSG_ERROR(${URIPARSER_MISSING}))
*
*URIPARSER_TOO_OLD="uriparser 0.6.4 or later is required, your copy is too old."
*AC_COMPILE_IFELSE([
*\#include
*\#if (defined(URI_VER_MAJOR) && defined(URI_VER_MINOR) && defined(URI_VER_RELEASE) \\
*&& ((URI_VER_MAJOR > 0) \\
*|| ((URI_VER_MAJOR == 0) && (URI_VER_MINOR > 6)) \\
*|| ((URI_VER_MAJOR == 0) && (URI_VER_MINOR == 6) && (URI_VER_RELEASE >= 4)) \\
*))
*
*\#else
*\# error uriparser not recent enough
*\#endif
*],,AC_MSG_ERROR(${URIPARSER_TOO_OLD}))
*/