+ int err =
+ uc->prot->url_open2 ? uc->prot->url_open2(uc,
+ uc->filename,
+ uc->flags,
+ options) :
+ uc->prot->url_open(uc, uc->filename, uc->flags);
+ if (err)
+ return err;
+ uc->is_connected = 1;
+ /* We must be careful here as ffurl_seek() could be slow,
+ * for example for http */
+ if ((uc->flags & AVIO_FLAG_WRITE) || !strcmp(uc->prot->name, "file"))
+ if (!uc->is_streamed && ffurl_seek(uc, 0, SEEK_SET) < 0)
+ uc->is_streamed = 1;
+ return 0;
+}
+
+#define URL_SCHEME_CHARS \
+ "abcdefghijklmnopqrstuvwxyz" \
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+ "0123456789+-."
+
+int ffurl_alloc(URLContext **puc, const char *filename, int flags,
+ const AVIOInterruptCB *int_cb)
+{
+ URLProtocol *up = NULL;
+ char proto_str[128], proto_nested[128], *ptr;
+ size_t proto_len = strspn(filename, URL_SCHEME_CHARS);
+
+ if (filename[proto_len] != ':' || is_dos_path(filename))
+ strcpy(proto_str, "file");
+ else
+ av_strlcpy(proto_str, filename,
+ FFMIN(proto_len + 1, sizeof(proto_str)));
+
+ av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));
+ if ((ptr = strchr(proto_nested, '+')))
+ *ptr = '\0';
+
+ while (up = ffurl_protocol_next(up)) {
+ if (!strcmp(proto_str, up->name))
+ return url_alloc_for_protocol(puc, up, filename, flags, int_cb);
+ if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
+ !strcmp(proto_nested, up->name))
+ return url_alloc_for_protocol(puc, up, filename, flags, int_cb);
+ }
+ *puc = NULL;
+ return AVERROR_PROTOCOL_NOT_FOUND;
+}
+
+int ffurl_open(URLContext **puc, const char *filename, int flags,
+ const AVIOInterruptCB *int_cb, AVDictionary **options)
+{
+ int ret = ffurl_alloc(puc, filename, flags, int_cb);
+ if (ret)
+ return ret;
+ if (options && (*puc)->prot->priv_data_class &&
+ (ret = av_opt_set_dict((*puc)->priv_data, options)) < 0)
+ goto fail;
+ ret = ffurl_connect(*puc, options);
+ if (!ret)
+ return 0;
+fail:
+ ffurl_close(*puc);
+ *puc = NULL;