mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-02-21 15:16:18 +00:00
Implement parsing of URIs in Rust
This commit is contained in:
parent
5b6a05b548
commit
15865ab86b
4 changed files with 66 additions and 77 deletions
|
@ -6,6 +6,7 @@ build = "build.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
url = "1.1"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
gcc = "0.3"
|
gcc = "0.3"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#![crate_type="dylib"]
|
#![crate_type="dylib"]
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
extern crate url;
|
||||||
|
|
||||||
pub mod rsfilesrc;
|
pub mod rsfilesrc;
|
||||||
pub mod rsfilesink;
|
pub mod rsfilesink;
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
extern void * filesrc_new (void);
|
extern void * filesrc_new (void);
|
||||||
extern void filesrc_drop (void * filesrc);
|
extern void filesrc_drop (void * filesrc);
|
||||||
extern GstFlowReturn filesrc_fill (void * filesrc, uint64_t offset, void * data, size_t * data_len);
|
extern GstFlowReturn filesrc_fill (void * filesrc, uint64_t offset, void * data, size_t * data_len);
|
||||||
extern void filesrc_set_location (void * filesrc, const char *location);
|
extern gboolean filesrc_set_uri (void * filesrc, const char *uri);
|
||||||
extern char * filesrc_get_location (void * filesrc);
|
extern char * filesrc_get_uri (void * filesrc);
|
||||||
extern uint64_t filesrc_get_size (void * filesrc);
|
extern uint64_t filesrc_get_size (void * filesrc);
|
||||||
extern gboolean filesrc_is_seekable (void * filesrc);
|
extern gboolean filesrc_is_seekable (void * filesrc);
|
||||||
extern gboolean filesrc_start (void * filesrc);
|
extern gboolean filesrc_start (void * filesrc);
|
||||||
|
@ -25,7 +25,7 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_LOCATION
|
PROP_URI
|
||||||
};
|
};
|
||||||
|
|
||||||
static void gst_rsfile_src_uri_handler_init (gpointer g_iface,
|
static void gst_rsfile_src_uri_handler_init (gpointer g_iface,
|
||||||
|
@ -66,9 +66,9 @@ gst_rsfile_src_class_init (GstRsfileSrcClass * klass)
|
||||||
gobject_class->set_property = gst_rsfile_src_set_property;
|
gobject_class->set_property = gst_rsfile_src_set_property;
|
||||||
gobject_class->get_property = gst_rsfile_src_get_property;
|
gobject_class->get_property = gst_rsfile_src_get_property;
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class, PROP_LOCATION,
|
g_object_class_install_property (gobject_class, PROP_URI,
|
||||||
g_param_spec_string ("location", "File Location",
|
g_param_spec_string ("uri", "URI",
|
||||||
"Location of the file to read", NULL,
|
"URI of the file to read", NULL,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||||
GST_PARAM_MUTABLE_READY));
|
GST_PARAM_MUTABLE_READY));
|
||||||
|
|
||||||
|
@ -113,8 +113,8 @@ gst_rsfile_src_set_property (GObject * object, guint prop_id,
|
||||||
GstRsfileSrc *src = GST_RSFILE_SRC (object);
|
GstRsfileSrc *src = GST_RSFILE_SRC (object);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_LOCATION:
|
case PROP_URI:
|
||||||
filesrc_set_location (src->instance, g_value_get_string (value));
|
filesrc_set_uri (src->instance, g_value_get_string (value));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
@ -129,8 +129,8 @@ gst_rsfile_src_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
GstRsfileSrc *src = GST_RSFILE_SRC (object);
|
GstRsfileSrc *src = GST_RSFILE_SRC (object);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_LOCATION:
|
case PROP_URI:
|
||||||
g_value_take_string (value, filesrc_get_location (src->instance));
|
g_value_take_string (value, filesrc_get_uri (src->instance));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
@ -211,68 +211,23 @@ static gchar *
|
||||||
gst_rsfile_src_uri_get_uri (GstURIHandler * handler)
|
gst_rsfile_src_uri_get_uri (GstURIHandler * handler)
|
||||||
{
|
{
|
||||||
GstRsfileSrc *src = GST_RSFILE_SRC (handler);
|
GstRsfileSrc *src = GST_RSFILE_SRC (handler);
|
||||||
gchar *location, *uri;
|
|
||||||
|
|
||||||
location = filesrc_get_location (src->instance);
|
return filesrc_get_uri (src->instance);
|
||||||
if (!location)
|
|
||||||
return NULL;
|
|
||||||
uri = gst_filename_to_uri (location, NULL);
|
|
||||||
g_free (location);
|
|
||||||
|
|
||||||
return uri;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_rsfile_src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
|
gst_rsfile_src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
|
||||||
GError ** err)
|
GError ** err)
|
||||||
{
|
{
|
||||||
gchar *location, *hostname = NULL;
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
GstRsfileSrc *src = GST_RSFILE_SRC (handler);
|
GstRsfileSrc *src = GST_RSFILE_SRC (handler);
|
||||||
|
|
||||||
if (strcmp (uri, "file://") == 0) {
|
if (!filesrc_set_uri (src->instance, uri)) {
|
||||||
/* Special case for "file://" as this is used by some applications
|
|
||||||
* to test with gst_element_make_from_uri if there's an element
|
|
||||||
* that supports the URI protocol. */
|
|
||||||
filesrc_set_location (src->instance, location);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
location = g_filename_from_uri (uri, &hostname, err);
|
|
||||||
|
|
||||||
if (!location || (err != NULL && *err != NULL)) {
|
|
||||||
GST_WARNING_OBJECT (src, "Invalid URI '%s' for filesrc: %s", uri,
|
|
||||||
(err != NULL && *err != NULL) ? (*err)->message : "unknown error");
|
|
||||||
goto beach;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((hostname) && (strcmp (hostname, "localhost"))) {
|
|
||||||
/* Only 'localhost' is permitted */
|
|
||||||
GST_WARNING_OBJECT (src, "Invalid hostname '%s' for filesrc", hostname);
|
|
||||||
g_set_error (err, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
|
g_set_error (err, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
|
||||||
"File URI with invalid hostname '%s'", hostname);
|
"Can't handle URI '%s'", uri);
|
||||||
goto beach;
|
return FALSE;
|
||||||
}
|
}
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
/* Unfortunately, g_filename_from_uri() doesn't handle some UNC paths
|
|
||||||
* correctly on windows, it leaves them with an extra backslash
|
|
||||||
* at the start if they're of the mozilla-style file://///host/path/file
|
|
||||||
* form. Correct this.
|
|
||||||
*/
|
|
||||||
if (location[0] == '\\' && location[1] == '\\' && location[2] == '\\')
|
|
||||||
memmove (location, location + 1, strlen (location + 1) + 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ret = TRUE;
|
return TRUE;
|
||||||
filesrc_set_location (src->instance, location);
|
|
||||||
|
|
||||||
beach:
|
|
||||||
if (location)
|
|
||||||
g_free (location);
|
|
||||||
if (hostname)
|
|
||||||
g_free (hostname);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -5,7 +5,8 @@ use std::u64;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::Path;
|
use std::path::PathBuf;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ impl GBoolean {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FileSrc {
|
pub struct FileSrc {
|
||||||
location: Option<String>,
|
location: Option<PathBuf>,
|
||||||
file: Option<File>,
|
file: Option<File>,
|
||||||
position: u64,
|
position: u64,
|
||||||
}
|
}
|
||||||
|
@ -53,12 +54,43 @@ impl FileSrc {
|
||||||
FileSrc { location: None, file: None, position: 0 }
|
FileSrc { location: None, file: None, position: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_location(&mut self, location: &Option<String>) {
|
fn set_uri(&mut self, uri_str: &Option<String>) -> bool {
|
||||||
self.location = location.clone();
|
match *uri_str {
|
||||||
|
None => {
|
||||||
|
self.location = None;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
Some(ref uri_str) => {
|
||||||
|
let uri_parsed = Url::parse(uri_str.as_str());
|
||||||
|
match uri_parsed {
|
||||||
|
Ok(u) => {
|
||||||
|
match u.to_file_path().ok() {
|
||||||
|
Some(p) => {
|
||||||
|
self.location = Some(p);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
self.location = None;
|
||||||
|
println_err!("Unsupported file URI '{}'", uri_str);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
self.location = None;
|
||||||
|
println_err!("Failed to parse URI '{}': {}", uri_str, err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_location(&self) -> &Option<String> {
|
fn get_uri(&self) -> Option<String> {
|
||||||
&self.location
|
match self.location {
|
||||||
|
None => None,
|
||||||
|
Some(ref location) => Url::from_file_path(&location).map(|u| u.into_string()).ok()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_seekable(&self) -> bool {
|
fn is_seekable(&self) -> bool {
|
||||||
|
@ -81,13 +113,13 @@ impl FileSrc {
|
||||||
match self.location {
|
match self.location {
|
||||||
None => return false,
|
None => return false,
|
||||||
Some(ref location) => {
|
Some(ref location) => {
|
||||||
match File::open(Path::new(&location.clone())) {
|
match File::open(location.as_path()) {
|
||||||
Ok(file) => {
|
Ok(file) => {
|
||||||
self.file = Some(file);
|
self.file = Some(file);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println_err!("Failed to open file '{}': {}", location, err.to_string());
|
println_err!("Failed to open file '{}': {}", location.to_str().unwrap_or("Non-UTF8 path"), err.to_string());
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -145,24 +177,24 @@ pub extern "C" fn filesrc_drop(ptr: *mut FileSrc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn filesrc_set_location(ptr: *mut FileSrc, location_ptr: *const c_char) {
|
pub extern "C" fn filesrc_set_uri(ptr: *mut FileSrc, uri_ptr: *const c_char) -> GBoolean{
|
||||||
let filesrc: &mut FileSrc = unsafe { &mut *ptr };
|
let filesrc: &mut FileSrc = unsafe { &mut *ptr };
|
||||||
|
|
||||||
if location_ptr.is_null() {
|
if uri_ptr.is_null() {
|
||||||
filesrc.set_location(&None)
|
GBoolean::from_bool(filesrc.set_uri(&None))
|
||||||
} else {
|
} else {
|
||||||
let location = unsafe { CStr::from_ptr(location_ptr) };
|
let uri = unsafe { CStr::from_ptr(uri_ptr) };
|
||||||
filesrc.set_location(&Some(String::from(location.to_str().unwrap())));
|
GBoolean::from_bool(filesrc.set_uri(&Some(String::from(uri.to_str().unwrap()))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn filesrc_get_location(ptr: *mut FileSrc) -> *mut c_char {
|
pub extern "C" fn filesrc_get_uri(ptr: *mut FileSrc) -> *mut c_char {
|
||||||
let filesrc: &mut FileSrc = unsafe { &mut *ptr };
|
let filesrc: &mut FileSrc = unsafe { &mut *ptr };
|
||||||
|
|
||||||
match *filesrc.get_location() {
|
match filesrc.get_uri() {
|
||||||
Some(ref location) =>
|
Some(ref uri) =>
|
||||||
CString::new(location.clone().into_bytes()).unwrap().into_raw(),
|
CString::new(uri.clone().into_bytes()).unwrap().into_raw(),
|
||||||
None =>
|
None =>
|
||||||
ptr::null_mut()
|
ptr::null_mut()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue