+# include <io.h>
+#endif
+
+/**
+ * Convert a file path to an URI.
+ * If already an URI, return a copy of the string.
+ * @param path path to convert (or URI to copy)
+ * @param scheme URI scheme to use (default is auto: "file", "fd" or "smb")
+ * @return a nul-terminated URI string (use free() to release it),
+ * or NULL in case of error
+ */
+char *make_URI (const char *path, const char *scheme)
+{
+ if (path == NULL)
+ return NULL;
+ if (scheme == NULL && !strcmp (path, "-"))
+ return strdup ("fd://0"); // standard input
+ if (strstr (path, "://") != NULL)
+ return strdup (path); /* Already an URI */
+ /* Note: VLC cannot handle URI schemes without double slash after the
+ * scheme name (such as mailto: or news:). */
+
+ char *buf;
+#ifdef WIN32
+ /* Drive letter */
+ if (isalpha (path[0]) && (path[1] == ':'))
+ {
+ if (asprintf (&buf, "%s:///%c:", scheme ? scheme : "file",
+ path[0]) == -1)
+ buf = NULL;
+ path += 2;
+# warning Drive letter-relative path not implemented!
+ if (path[0] != DIR_SEP_CHAR)
+ return NULL;
+ }
+ else
+#endif
+ if (!strncmp (path, "\\\\", 2))
+ { /* Windows UNC paths */
+#ifndef WIN32
+ if (scheme != NULL)
+ return NULL; /* remote files not supported */
+
+ /* \\host\share\path -> smb://host/share/path */
+ if (strchr (path + 2, '\\') != NULL)
+ { /* Convert backslashes to slashes */
+ char *dup = strdup (path);
+ if (dup == NULL)
+ return NULL;
+ for (size_t i = 2; dup[i]; i++)
+ if (dup[i] == '\\')
+ dup[i] = DIR_SEP_CHAR;
+
+ char *ret = make_URI (dup, scheme);
+ free (dup);
+ return ret;
+ }
+# define SMB_SCHEME "smb"
+#else
+ /* \\host\share\path -> file://host/share/path */
+# define SMB_SCHEME "file"
+#endif
+ size_t hostlen = strcspn (path + 2, DIR_SEP);
+
+ buf = malloc (sizeof (SMB_SCHEME) + 3 + hostlen);
+ if (buf != NULL)
+ snprintf (buf, sizeof (SMB_SCHEME) + 3 + hostlen,
+ SMB_SCHEME"://%s", path + 2);
+ path += 2 + hostlen;
+
+ if (path[0] == '\0')
+ return buf; /* Hostname without path */
+ }
+ else
+ if (path[0] != DIR_SEP_CHAR)
+ { /* Relative path: prepend the current working directory */
+ char cwd[PATH_MAX];
+
+ if (getcwd (cwd, sizeof (cwd)) == NULL) /* FIXME: UTF8? */
+ return NULL;
+ if (asprintf (&buf, "%s/%s", cwd, path) == -1)
+ return NULL;
+ char *ret = make_URI (buf, scheme);
+ free (buf);
+ return ret;
+ }
+ else
+ if (asprintf (&buf, "%s://", scheme ? scheme : "file") == -1)
+ buf = NULL;
+ if (buf == NULL)
+ return NULL;
+
+ assert (path[0] == DIR_SEP_CHAR);
+
+ /* Absolute file path */
+ for (const char *ptr = path + 1;; ptr++)
+ {
+ size_t len = strcspn (ptr, DIR_SEP);
+ char *component = encode_URI_bytes (ptr, len);
+ if (component == NULL)