+#ifdef HAVE_LIBURIPARSER
+char * relative_uri_malloc(const char * unixFilename, const char * baseDir)
+{
+ char * absSourceFile;
+ size_t absSourceLen;
+ char * sourceUriString;
+ char * baseUriString;
+ UriParserStateA state;
+ UriUriA sourceUri;
+ UriUriA baseUri;
+ UriUriA relativeUri;
+ int charsRequired;
+ char * output;
+
+ /* checks */
+ if ((unixFilename == NULL) || (baseDir == NULL)) {
+ return NULL;
+ }
+
+ /* base URI */
+ baseUriString = malloc((7 + 3 * strlen(baseDir) + 1) * sizeof(char));
+ if (baseUriString == NULL) {
+ return NULL;
+ }
+ if (uriUnixFilenameToUriStringA(baseDir, baseUriString) != 0) {
+ free(baseUriString);
+ return NULL;
+ }
+ state.uri = &baseUri;
+ if (uriParseUriA(&state, baseUriString) != 0) {
+ free(baseUriString);
+ uriFreeUriMembersA(&baseUri);
+ return NULL;
+ }
+
+ /* source URI */
+ if (unixFilename[0] != '/') {
+ const int baseDirLen = strlen(baseDir);
+ const int sourceFileLen = strlen(unixFilename);
+ absSourceLen = baseDirLen + sourceFileLen;
+ absSourceFile = malloc((absSourceLen + 1) * sizeof(char));
+ sprintf(absSourceFile, "%s%s", baseDir, unixFilename);
+ } else {
+ absSourceLen = strlen(unixFilename);
+ absSourceFile = (char *)unixFilename;
+ }
+ sourceUriString = malloc((7 + 3 * absSourceLen + 1) * sizeof(char));
+ if (sourceUriString == NULL) {
+ free(baseUriString);
+ if (unixFilename[0] != '/') {
+ free(absSourceFile);
+ }
+ uriFreeUriMembersA(&baseUri);
+ return NULL;
+ }
+ if (uriUnixFilenameToUriStringA(absSourceFile, sourceUriString) != 0) {
+ free(baseUriString);
+ free(sourceUriString);
+ if (unixFilename[0] != '/') {
+ free(absSourceFile);
+ }
+ uriFreeUriMembersA(&baseUri);
+ return NULL;
+ }
+ state.uri = &sourceUri;
+ if (uriParseUriA(&state, sourceUriString) != 0) {
+ free(baseUriString);
+ free(sourceUriString);
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&sourceUri);
+ return NULL;
+ }
+ if (uriNormalizeSyntaxA(&sourceUri) != 0) {
+ free(baseUriString);
+ free(sourceUriString);
+ if (unixFilename[0] != '/') {
+ free(absSourceFile);
+ }
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&sourceUri);
+ return NULL;
+ }
+
+ /* make relative (or keep absolute if necessary) */
+ if (uriRemoveBaseUriA(&relativeUri, &sourceUri, &baseUri, URI_FALSE) != 0) {
+ free(baseUriString);
+ free(sourceUriString);
+ if (unixFilename[0] != '/') {
+ free(absSourceFile);
+ }
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&sourceUri);
+ uriFreeUriMembersA(&relativeUri);
+ return NULL;
+ }
+
+ /* back to string */
+ if (uriToStringCharsRequiredA(&relativeUri, &charsRequired) != 0) {
+ free(baseUriString);
+ free(sourceUriString);
+ if (unixFilename[0] != '/') {
+ free(absSourceFile);
+ }
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&sourceUri);
+ uriFreeUriMembersA(&relativeUri);
+ return NULL;
+ }
+ output = malloc((charsRequired + 1) * sizeof(char));
+ if (uriToStringA(output, &relativeUri, charsRequired + 1, NULL) != 0) {
+ free(baseUriString);
+ free(sourceUriString);
+ if (unixFilename[0] != '/') {
+ free(absSourceFile);
+ }
+ free(output);
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&sourceUri);
+ uriFreeUriMembersA(&relativeUri);
+ return NULL;
+ }