+#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;
+ }
+
+ free(baseUriString);
+ free(sourceUriString);
+ if (unixFilename[0] != '/') {
+ free(absSourceFile);
+ }
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&sourceUri);
+ uriFreeUriMembersA(&relativeUri);
+
+ return output;
+}
+
+char * xml_escape_malloc(const char * input)
+{
+ const char * read = input;
+ char * output;
+ char * write;
+
+ if (input == NULL) {
+ return NULL;
+ }
+
+ output = malloc((6 * strlen(input) + 1) * sizeof(char));
+ if (output == NULL) {
+ return NULL;
+ }
+ write = output;
+
+ for (;;) {
+ if (*read == '\0') {
+ *write = '\0';
+ return output;
+ }
+
+ switch ((unsigned char)*read) {
+ case '&':
+ strcpy(write, "&");
+ write += 5;
+ break;
+ case '<':
+ strcpy(write, "<");
+ write += 4;
+ break;
+ case '>':
+ strcpy(write, ">");
+ write += 4;
+ break;
+ case '\'':
+ strcpy(write, "'");
+ write += 6;
+ break;
+ case '"':
+ strcpy(write, """);
+ write += 6;
+ break;
+ default:
+ *(write++) = *read;
+ }
+ read++;
+ }
+}
+#endif