[niepce] fwk+rust: port filelist to Rust



commit a36e5f072b48be11f3dad45c1b8eca3392a90036
Author: Hubert Figuière <hub figuiere net>
Date:   Wed Feb 12 23:10:29 2020 -0500

    fwk+rust: port filelist to Rust

 crates/npc-engine/build.rs                |   1 -
 crates/npc-engine/src/db/filebundle.rs    | 171 +++++++++++++++---------------
 crates/npc-engine/src/db/library.rs       |  34 +++---
 crates/npc-engine/src/library/commands.rs |   4 +-
 crates/npc-fwk/src/utils/exempi.rs        |  14 ++-
 crates/npc-fwk/src/utils/files.rs         | 165 ++++++++++++++++++++++++++--
 src/engine/db/bindings.hpp                |   1 -
 src/engine/importer/cameraimporter.cpp    |   4 +-
 src/engine/importer/directoryimporter.cpp |  22 ++--
 src/fwk/utils/Makefile.am                 |  10 +-
 src/fwk/utils/files.cpp                   |  94 +---------------
 src/fwk/utils/files.hpp                   |  45 +-------
 src/fwk/utils/modulemanager.cpp           |  23 ++--
 src/fwk/utils/t/testfiles.cpp             |  61 -----------
 src/libraryclient/clientimpl.rs           |   2 +-
 src/libraryclient/clientinterface.rs      |   4 +-
 src/libraryclient/mod.rs                  |  19 +---
 src/rust_bindings.hpp                     |   6 +-
 18 files changed, 325 insertions(+), 355 deletions(-)
---
diff --git a/crates/npc-engine/build.rs b/crates/npc-engine/build.rs
index 63776b0..562974c 100644
--- a/crates/npc-engine/build.rs
+++ b/crates/npc-engine/build.rs
@@ -22,7 +22,6 @@ fn main() {
         .constified_enum("eng::NiepceProperties")
         .prepend_enum_name(false)
         .opaque_type("std::.*")
-        .whitelist_type("fwk::FileList")
         .whitelist_type("eng::IndexToXmp")
         .whitelist_function("eng::property_index_to_xmp")
         .header("../../src/engine/db/bindings.hpp")
diff --git a/crates/npc-engine/src/db/filebundle.rs b/crates/npc-engine/src/db/filebundle.rs
index 07260c8..0add42a 100644
--- a/crates/npc-engine/src/db/filebundle.rs
+++ b/crates/npc-engine/src/db/filebundle.rs
@@ -29,13 +29,13 @@ use npc_fwk::MimeType;
 pub enum Sidecar {
     Invalid,
     /// Sidecar for Live image (MOV file form iPhone)
-    Live(String),
+    Live(PathBuf),
     /// Thumbnail file (THM from Canon)
-    Thumbnail(String),
+    Thumbnail(PathBuf),
     /// XMP Sidecar
-    Xmp(String),
+    Xmp(PathBuf),
     /// JPEG Sidecar (RAW + JPEG)
-    Jpeg(String),
+    Jpeg(PathBuf),
 }
 
 impl Sidecar {
@@ -50,8 +50,8 @@ impl Sidecar {
     }
 }
 
-impl From<(i32, String)> for Sidecar {
-    fn from(t: (i32, String)) -> Self {
+impl From<(i32, PathBuf)> for Sidecar {
+    fn from(t: (i32, PathBuf)) -> Self {
         match t.0 {
             1 => Sidecar::Live(t.1),
             2 => Sidecar::Thumbnail(t.1),
@@ -68,11 +68,11 @@ pub struct FileBundle {
     /// Type of bundle
     bundle_type: FileType,
     /// Main file.
-    main: String,
+    main: PathBuf,
     /// XMP sidecar if it exists.
-    xmp_sidecar: String,
+    xmp_sidecar: PathBuf,
     /// JPEG alternate for RAW_JPEG
-    jpeg: String,
+    jpeg: PathBuf,
     /// Other sidecars: Live, Thumbnail
     sidecars: Vec<Sidecar>,
 }
@@ -89,24 +89,23 @@ impl FileBundle {
     pub fn new() -> FileBundle {
         FileBundle {
             bundle_type: FileType::Unknown,
-            main: String::new(),
-            xmp_sidecar: String::new(),
-            jpeg: String::new(),
+            main: PathBuf::new(),
+            xmp_sidecar: PathBuf::new(),
+            jpeg: PathBuf::new(),
             sidecars: vec![],
         }
     }
 
     /// Filter the file list and turn them to bundles
     ///
-    pub fn filter_bundles(files: &[String]) -> Vec<FileBundle> {
+    pub fn filter_bundles(files: &[PathBuf]) -> Vec<FileBundle> {
         let mut bundles: Vec<FileBundle> = vec![];
-        let mut sorted_files: Vec<&String> = files.iter().collect();
+        let mut sorted_files: Vec<&PathBuf> = files.iter().collect();
         sorted_files.sort();
         let mut current_base = OsString::new();
         let mut current_bundle: Option<FileBundle> = None;
 
-        for f in sorted_files {
-            let path = Path::new(&f);
+        for path in sorted_files {
             if let Some(basename) = path.file_stem() {
                 let mut basename = basename.to_os_string();
                 while basename != current_base {
@@ -122,14 +121,14 @@ impl FileBundle {
                     }
                 }
                 if basename == current_base {
-                    current_bundle.as_mut().unwrap().add(&f);
+                    current_bundle.as_mut().unwrap().add(path);
                     continue;
                 }
                 if let Some(current_bundle) = current_bundle {
                     bundles.push(current_bundle);
                 }
                 let mut bundle = FileBundle::new();
-                bundle.add(&f);
+                bundle.add(path);
                 current_base = basename;
                 current_bundle = Some(bundle);
             }
@@ -140,49 +139,50 @@ impl FileBundle {
         bundles
     }
 
-    pub fn add(&mut self, path: &str) -> bool {
-        dbg_out!("FileBundle::add path {}", path);
+    pub fn add<P: AsRef<Path> + std::fmt::Debug>(&mut self, p: P) -> bool {
+        let path = p.as_ref();
+        dbg_out!("FileBundle::add path {:?}", path);
         let mime_type = MimeType::new(path);
         let mut added = true;
 
         match mime_type.mime_type() {
             MType::Image(is_raw) => match is_raw {
                 IsRaw::Yes => {
-                    if !self.main.is_empty() && self.jpeg.is_empty() {
+                    if !self.main.as_os_str().is_empty() && self.jpeg.as_os_str().is_empty() {
                         self.jpeg = self.main.clone();
                         self.bundle_type = FileType::RawJpeg;
                     } else {
                         self.bundle_type = FileType::Raw;
                     }
-                    self.main = String::from(path);
+                    self.main = path.to_path_buf();
                 }
                 IsRaw::No => {
-                    if !self.main.is_empty() {
-                        self.jpeg = String::from(path);
+                    if !self.main.as_os_str().is_empty() {
+                        self.jpeg = path.to_path_buf();
                         self.bundle_type = FileType::RawJpeg;
                     } else {
-                        self.main = String::from(path);
+                        self.main = path.to_path_buf();
                         self.bundle_type = FileType::Image;
                     }
                 }
             },
-            MType::Xmp => self.xmp_sidecar = String::from(path),
+            MType::Xmp => self.xmp_sidecar = path.to_path_buf(),
             MType::Movie => match self.bundle_type {
                 FileType::Unknown => {
-                    self.main = String::from(path);
+                    self.main = path.to_path_buf();
                     self.bundle_type = FileType::Video;
                 }
                 FileType::Image => {
-                    self.sidecars.push(Sidecar::Live(String::from(path)));
+                    self.sidecars.push(Sidecar::Live(path.to_path_buf()));
                 }
                 _ => {
-                    dbg_out!("Ignoring movie file {}", path);
+                    dbg_out!("Ignoring movie file {:?}", path);
                     added = false;
                 }
             },
-            MType::Thumbnail => self.sidecars.push(Sidecar::Thumbnail(String::from(path))),
+            MType::Thumbnail => self.sidecars.push(Sidecar::Thumbnail(path.to_path_buf())),
             _ => {
-                dbg_out!("Unknown file {} of type {:?}", path, mime_type);
+                dbg_out!("Unknown file {:?} of type {:?}", path, mime_type);
                 added = false;
             }
         }
@@ -193,15 +193,15 @@ impl FileBundle {
         self.bundle_type
     }
 
-    pub fn main(&self) -> &str {
+    pub fn main(&self) -> &Path {
         &self.main
     }
 
-    pub fn jpeg(&self) -> &str {
+    pub fn jpeg(&self) -> &Path {
         &self.jpeg
     }
 
-    pub fn xmp_sidecar(&self) -> &str {
+    pub fn xmp_sidecar(&self) -> &Path {
         &self.xmp_sidecar
     }
 
@@ -214,38 +214,39 @@ impl FileBundle {
 mod test {
     use super::{FileBundle, Sidecar};
     use crate::db::libfile::FileType;
+    use std::path::PathBuf;
 
     #[test]
     fn test_filebundle() {
-        let mut thelist: Vec<String> = vec![];
+        let mut thelist: Vec<PathBuf> = vec![];
 
-        thelist.push(String::from("/foo/bar/img_0001.cr2"));
-        thelist.push(String::from("/foo/bar/img_0001.jpg"));
-        thelist.push(String::from("/foo/bar/img_0001.xmp"));
+        thelist.push(PathBuf::from("/foo/bar/img_0001.cr2"));
+        thelist.push(PathBuf::from("/foo/bar/img_0001.jpg"));
+        thelist.push(PathBuf::from("/foo/bar/img_0001.xmp"));
 
-        thelist.push(String::from("/foo/bar/dcs_0001.jpg"));
-        thelist.push(String::from("/foo/bar/dcs_0001.nef"));
-        thelist.push(String::from("/foo/bar/dcs_0001.xmp"));
+        thelist.push(PathBuf::from("/foo/bar/dcs_0001.jpg"));
+        thelist.push(PathBuf::from("/foo/bar/dcs_0001.nef"));
+        thelist.push(PathBuf::from("/foo/bar/dcs_0001.xmp"));
 
-        thelist.push(String::from("/foo/bar/img_0142.jpg"));
-        thelist.push(String::from("/foo/bar/img_0142.mov"));
+        thelist.push(PathBuf::from("/foo/bar/img_0142.jpg"));
+        thelist.push(PathBuf::from("/foo/bar/img_0142.mov"));
 
-        thelist.push(String::from("/foo/bar/img_0143.mov"));
-        thelist.push(String::from("/foo/bar/img_0143.jpg"));
+        thelist.push(PathBuf::from("/foo/bar/img_0143.mov"));
+        thelist.push(PathBuf::from("/foo/bar/img_0143.jpg"));
 
-        thelist.push(String::from("/foo/bar/img_0144.crw"));
-        thelist.push(String::from("/foo/bar/img_0144.thm"));
+        thelist.push(PathBuf::from("/foo/bar/img_0144.crw"));
+        thelist.push(PathBuf::from("/foo/bar/img_0144.thm"));
 
-        thelist.push(String::from("/foo/bar/mvi_0145.mov"));
-        thelist.push(String::from("/foo/bar/mvi_0145.thm"));
+        thelist.push(PathBuf::from("/foo/bar/mvi_0145.mov"));
+        thelist.push(PathBuf::from("/foo/bar/mvi_0145.thm"));
 
-        thelist.push(String::from("/foo/bar/scs_3445.jpg"));
-        thelist.push(String::from("/foo/bar/scs_3445.raf"));
-        thelist.push(String::from("/foo/bar/scs_3445.jpg.xmp"));
+        thelist.push(PathBuf::from("/foo/bar/scs_3445.jpg"));
+        thelist.push(PathBuf::from("/foo/bar/scs_3445.raf"));
+        thelist.push(PathBuf::from("/foo/bar/scs_3445.jpg.xmp"));
 
-        thelist.push(String::from("/foo/bar/scs_3446.jpg"));
-        thelist.push(String::from("/foo/bar/scs_3446.raf"));
-        thelist.push(String::from("/foo/bar/scs_3446.raf.pp3"));
+        thelist.push(PathBuf::from("/foo/bar/scs_3446.jpg"));
+        thelist.push(PathBuf::from("/foo/bar/scs_3446.raf"));
+        thelist.push(PathBuf::from("/foo/bar/scs_3446.raf.pp3"));
 
         let bundles_list = FileBundle::filter_bundles(&thelist);
 
@@ -254,31 +255,31 @@ mod test {
         let mut iter = bundles_list.iter();
         if let Some(b) = iter.next() {
             assert_eq!(b.bundle_type(), FileType::RawJpeg);
-            assert_eq!(b.main(), "/foo/bar/dcs_0001.nef");
-            assert_eq!(b.jpeg(), "/foo/bar/dcs_0001.jpg");
-            assert_eq!(b.xmp_sidecar(), "/foo/bar/dcs_0001.xmp");
+            assert_eq!(b.main(), PathBuf::from("/foo/bar/dcs_0001.nef"));
+            assert_eq!(b.jpeg(), PathBuf::from("/foo/bar/dcs_0001.jpg"));
+            assert_eq!(b.xmp_sidecar(), PathBuf::from("/foo/bar/dcs_0001.xmp"));
         } else {
             assert!(false);
         }
 
         if let Some(b) = iter.next() {
             assert_eq!(b.bundle_type(), FileType::RawJpeg);
-            assert_eq!(b.main(), "/foo/bar/img_0001.cr2");
-            assert_eq!(b.jpeg(), "/foo/bar/img_0001.jpg");
-            assert_eq!(b.xmp_sidecar(), "/foo/bar/img_0001.xmp");
+            assert_eq!(b.main(), PathBuf::from("/foo/bar/img_0001.cr2"));
+            assert_eq!(b.jpeg(), PathBuf::from("/foo/bar/img_0001.jpg"));
+            assert_eq!(b.xmp_sidecar(), PathBuf::from("/foo/bar/img_0001.xmp"));
         } else {
             assert!(false);
         }
 
         if let Some(b) = iter.next() {
             assert_eq!(b.bundle_type(), FileType::Image);
-            assert_eq!(b.main(), "/foo/bar/img_0142.jpg");
-            assert!(b.jpeg().is_empty());
-            assert!(b.xmp_sidecar().is_empty());
+            assert_eq!(b.main(), PathBuf::from("/foo/bar/img_0142.jpg"));
+            assert!(b.jpeg().as_os_str().is_empty());
+            assert!(b.xmp_sidecar().as_os_str().is_empty());
             assert_eq!(b.sidecars.len(), 1);
             assert_eq!(
                 b.sidecars[0],
-                Sidecar::Live(String::from("/foo/bar/img_0142.mov"))
+                Sidecar::Live(PathBuf::from("/foo/bar/img_0142.mov"))
             );
         } else {
             assert!(false);
@@ -286,13 +287,13 @@ mod test {
 
         if let Some(b) = iter.next() {
             assert_eq!(b.bundle_type(), FileType::Image);
-            assert_eq!(b.main(), "/foo/bar/img_0143.jpg");
-            assert!(b.jpeg().is_empty());
-            assert!(b.xmp_sidecar().is_empty());
+            assert_eq!(b.main(), PathBuf::from("/foo/bar/img_0143.jpg"));
+            assert!(b.jpeg().as_os_str().is_empty());
+            assert!(b.xmp_sidecar().as_os_str().is_empty());
             assert_eq!(b.sidecars.len(), 1);
             assert_eq!(
                 b.sidecars[0],
-                Sidecar::Live(String::from("/foo/bar/img_0143.mov"))
+                Sidecar::Live(PathBuf::from("/foo/bar/img_0143.mov"))
             );
         } else {
             assert!(false);
@@ -300,13 +301,13 @@ mod test {
 
         if let Some(b) = iter.next() {
             assert_eq!(b.bundle_type(), FileType::Raw);
-            assert_eq!(b.main(), "/foo/bar/img_0144.crw");
-            assert!(b.jpeg().is_empty());
-            assert!(b.xmp_sidecar().is_empty());
+            assert_eq!(b.main(), PathBuf::from("/foo/bar/img_0144.crw"));
+            assert!(b.jpeg().as_os_str().is_empty());
+            assert!(b.xmp_sidecar().as_os_str().is_empty());
             assert_eq!(b.sidecars.len(), 1);
             assert_eq!(
                 b.sidecars[0],
-                Sidecar::Thumbnail(String::from("/foo/bar/img_0144.thm"))
+                Sidecar::Thumbnail(PathBuf::from("/foo/bar/img_0144.thm"))
             );
         } else {
             assert!(false);
@@ -314,13 +315,13 @@ mod test {
 
         if let Some(b) = iter.next() {
             assert_eq!(b.bundle_type(), FileType::Video);
-            assert_eq!(b.main(), "/foo/bar/mvi_0145.mov");
-            assert!(b.jpeg().is_empty());
-            assert!(b.xmp_sidecar().is_empty());
+            assert_eq!(b.main(), PathBuf::from("/foo/bar/mvi_0145.mov"));
+            assert!(b.jpeg().as_os_str().is_empty());
+            assert!(b.xmp_sidecar().as_os_str().is_empty());
             assert_eq!(b.sidecars.len(), 1);
             assert_eq!(
                 b.sidecars[0],
-                Sidecar::Thumbnail(String::from("/foo/bar/mvi_0145.thm"))
+                Sidecar::Thumbnail(PathBuf::from("/foo/bar/mvi_0145.thm"))
             );
         } else {
             assert!(false);
@@ -328,15 +329,15 @@ mod test {
 
         if let Some(b) = iter.next() {
             println!(
-                "main = {}, jpeg = {}, xmp_sidecar = {}, sidecars =",
+                "main = {:?}, jpeg = {:?}, xmp_sidecar = {:?}, sidecars =",
                 b.main(),
                 b.jpeg(),
                 b.xmp_sidecar() /*, b.sidecars()*/
             );
             assert_eq!(b.bundle_type(), FileType::RawJpeg);
-            assert_eq!(b.main(), "/foo/bar/scs_3445.raf");
-            assert_eq!(b.jpeg(), "/foo/bar/scs_3445.jpg");
-            assert_eq!(b.xmp_sidecar(), "/foo/bar/scs_3445.jpg.xmp");
+            assert_eq!(b.main(), PathBuf::from("/foo/bar/scs_3445.raf"));
+            assert_eq!(b.jpeg(), PathBuf::from("/foo/bar/scs_3445.jpg"));
+            assert_eq!(b.xmp_sidecar(), PathBuf::from("/foo/bar/scs_3445.jpg.xmp"));
             assert_eq!(b.sidecars.len(), 0);
         } else {
             assert!(false);
@@ -344,15 +345,15 @@ mod test {
 
         if let Some(b) = iter.next() {
             println!(
-                "main = {}, jpeg = {}, xmp_sidecar = {}, sidecars =",
+                "main = {:?}, jpeg = {:?}, xmp_sidecar = {:?}, sidecars =",
                 b.main(),
                 b.jpeg(),
                 b.xmp_sidecar() /*, b.sidecars()*/
             );
             assert_eq!(b.bundle_type(), FileType::RawJpeg);
-            assert_eq!(b.main(), "/foo/bar/scs_3446.raf");
-            assert_eq!(b.jpeg(), "/foo/bar/scs_3446.jpg");
-            assert!(b.xmp_sidecar().is_empty());
+            assert_eq!(b.main(), PathBuf::from("/foo/bar/scs_3446.raf"));
+            assert_eq!(b.jpeg(), PathBuf::from("/foo/bar/scs_3446.jpg"));
+            assert!(b.xmp_sidecar().as_os_str().is_empty());
             assert_eq!(b.sidecars.len(), 0);
         } else {
             assert!(false);
diff --git a/crates/npc-engine/src/db/library.rs b/crates/npc-engine/src/db/library.rs
index 73fd0c8..86ee02a 100644
--- a/crates/npc-engine/src/db/library.rs
+++ b/crates/npc-engine/src/db/library.rs
@@ -17,6 +17,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+use std::ffi::OsStr;
 use std::fs::File;
 use std::io::Write;
 use std::path::{Path, PathBuf};
@@ -372,7 +373,7 @@ impl Library {
     }
 
     pub fn add_sidecar_file_to_bundle(&self, file_id: LibraryId, sidecar: &Sidecar) -> Result<()> {
-        let sidecar_t: (i32, &String) = match *sidecar {
+        let sidecar_t: (i32, &PathBuf) = match *sidecar {
             Sidecar::Live(ref p)
             | Sidecar::Thumbnail(ref p)
             | Sidecar::Xmp(ref p)
@@ -578,8 +579,9 @@ impl Library {
         Err(Error::NoSqlDb)
     }
 
-    pub fn add_fs_file(&self, file: &str) -> Result<LibraryId> {
+    pub fn add_fs_file<P: AsRef<Path>>(&self, f: P) -> Result<LibraryId> {
         if let Some(ref conn) = self.dbconn {
+            let file = f.as_ref().to_string_lossy();
             let c = conn.execute("INSERT INTO fsfiles (path) VALUES(?1)", &[&file])?;
             if c != 1 {
                 return Err(Error::InvalidResult);
@@ -614,26 +616,26 @@ impl Library {
             err_out!("add_file returned {}", file_id);
             return Err(Error::InvalidResult);
         }
-        if !bundle.xmp_sidecar().is_empty() {
+        if !bundle.xmp_sidecar().as_os_str().is_empty() {
             let fsfile_id = self.add_fs_file(bundle.xmp_sidecar())?;
             if fsfile_id > 0 {
                 self.add_xmp_sidecar_to_bundle(file_id, fsfile_id)?;
                 self.add_sidecar_fsfile_to_bundle(
                     file_id,
                     fsfile_id,
-                    Sidecar::Xmp(String::new()).to_int(),
+                    Sidecar::Xmp(PathBuf::new()).to_int(),
                     "xmp",
                 )?;
             }
         }
-        if !bundle.jpeg().is_empty() {
+        if !bundle.jpeg().as_os_str().is_empty() {
             let fsfile_id = self.add_fs_file(bundle.jpeg())?;
             if fsfile_id > 0 {
                 self.add_jpeg_file_to_bundle(file_id, fsfile_id)?;
                 self.add_sidecar_fsfile_to_bundle(
                     file_id,
                     fsfile_id,
-                    Sidecar::Jpeg(String::new()).to_int(),
+                    Sidecar::Jpeg(PathBuf::new()).to_int(),
                     "jpg",
                 )?;
             }
@@ -642,16 +644,17 @@ impl Library {
         Ok(file_id)
     }
 
-    pub fn add_file(
+    pub fn add_file<P: AsRef<Path> + AsRef<OsStr>>(
         &self,
         folder_id: LibraryId,
-        file: &str,
+        file: P,
         bundle: Option<&FileBundle>,
         manage: Managed,
     ) -> Result<LibraryId> {
         dbg_assert!(manage == Managed::NO, "manage not supported");
         dbg_assert!(folder_id != -1, "invalid folder ID");
-        let mime = npc_fwk::MimeType::new(file);
+        let file_path: &Path = file.as_ref();
+        let mime = npc_fwk::MimeType::new(file_path);
         let file_type = libfile::mimetype_to_filetype(&mime);
         let label_id: LibraryId = 0;
         let orientation: i32;
@@ -667,10 +670,10 @@ impl Library {
             if bundle.bundle_type() == libfile::FileType::RawJpeg {
                 npc_fwk::XmpMeta::new_from_file(bundle.jpeg(), false)
             } else {
-                npc_fwk::XmpMeta::new_from_file(file, false)
+                npc_fwk::XmpMeta::new_from_file(file_path, false)
             }
         } else {
-            npc_fwk::XmpMeta::new_from_file(file, false)
+            npc_fwk::XmpMeta::new_from_file(file_path, false)
         };
 
         if let Some(ref meta) = meta {
@@ -693,8 +696,11 @@ impl Library {
             xmp = String::from("");
         }
 
-        let filename = Self::leaf_name_for_pathname(file).unwrap_or_default();
-        let fs_file_id = self.add_fs_file(file)?;
+        let filename = file_path
+            .file_name()
+            .map(|s| s.to_string_lossy())
+            .unwrap_or_default();
+        let fs_file_id = self.add_fs_file(file_path)?;
         if fs_file_id <= 0 {
             err_out!("add fsfile failed");
             return Err(Error::InvalidResult);
@@ -1080,7 +1086,7 @@ impl Library {
                         if let Ok(mut f) = File::create(p.clone()) {
                             let sidecar = xmppacket.serialize();
                             if f.write(sidecar.as_bytes()).is_ok() && (xmp_file_id <= 0) {
-                                let xmp_file_id = self.add_fs_file(p.to_string_lossy().as_ref())?;
+                                let xmp_file_id = self.add_fs_file(&p)?;
                                 dbg_assert!(xmp_file_id > 0, "couldn't add xmp_file");
                                 // XXX handle error
                                 let res = self.add_xmp_sidecar_to_bundle(id, xmp_file_id);
diff --git a/crates/npc-engine/src/library/commands.rs b/crates/npc-engine/src/library/commands.rs
index 3fcf58f..608040a 100644
--- a/crates/npc-engine/src/library/commands.rs
+++ b/crates/npc-engine/src/library/commands.rs
@@ -17,6 +17,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+use std::path::PathBuf;
+
 use super::notification::LibNotification;
 use super::notification::{Count, FileMove, MetadataChange};
 use super::queriedcontent::QueriedContent;
@@ -102,7 +104,7 @@ fn get_folder_for_import(lib: &Library, folder: &str) -> library::Result<LibFold
     }
 }
 
-pub fn cmd_import_files(lib: &Library, folder: &str, files: &[String], manage: Managed) -> bool {
+pub fn cmd_import_files(lib: &Library, folder: &str, files: &[PathBuf], manage: Managed) -> bool {
     dbg_assert!(
         manage == Managed::NO,
         "managing file is currently unsupported"
diff --git a/crates/npc-fwk/src/utils/exempi.rs b/crates/npc-fwk/src/utils/exempi.rs
index 30f269e..b33b635 100644
--- a/crates/npc-fwk/src/utils/exempi.rs
+++ b/crates/npc-fwk/src/utils/exempi.rs
@@ -18,6 +18,7 @@
  */
 
 use std::convert::From;
+use std::ffi::OsStr;
 use std::fs::File;
 use std::io::prelude::*;
 use std::path::Path;
@@ -176,10 +177,16 @@ impl XmpMeta {
         }
     }
 
-    pub fn new_from_file(file: &str, sidecar_only: bool) -> Option<XmpMeta> {
+    pub fn new_from_file<P>(p: P, sidecar_only: bool) -> Option<XmpMeta>
+    where
+        P: AsRef<Path> + AsRef<OsStr>,
+    {
+        let file: &Path = p.as_ref();
         let mut meta: Option<XmpMeta> = None;
         if !sidecar_only {
-            if let Ok(xmpfile) = exempi::XmpFile::open_new(file, exempi::OPEN_READ) {
+            if let Ok(xmpfile) =
+                exempi::XmpFile::open_new(&*file.to_string_lossy(), exempi::OPEN_READ)
+            {
                 meta = match xmpfile.get_new_xmp() {
                     Ok(xmp) => Some(Self::new_with_xmp(xmp)),
                     _ => exiv2::xmp_from_exiv2(file),
@@ -188,8 +195,7 @@ impl XmpMeta {
         }
 
         let mut sidecar_meta: Option<XmpMeta> = None;
-        let filepath = Path::new(file);
-        let sidecar = filepath.with_extension("xmp");
+        let sidecar = file.with_extension("xmp");
         let sidecaropen = File::open(sidecar);
         if let Ok(mut sidecarfile) = sidecaropen {
             let mut sidecarcontent = String::new();
diff --git a/crates/npc-fwk/src/utils/files.rs b/crates/npc-fwk/src/utils/files.rs
index bf793ea..1f053be 100644
--- a/crates/npc-fwk/src/utils/files.rs
+++ b/crates/npc-fwk/src/utils/files.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - fwk/utils/files.rs
  *
- * Copyright (C) 2018-2019 Hubert Figuière
+ * Copyright (C) 2018-2020 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,22 +17,169 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+use libc::c_char;
+use std::ffi::{CStr, CString};
+use std::path::{Path, PathBuf};
+
 use gio;
+use gio::prelude::*;
 use gio_sys;
 use glib::translate::*;
 
 use crate::toolkit::mimetype::{guess_type, MType};
 
+#[derive(Clone, Default)]
+pub struct FileList(pub Vec<PathBuf>);
+
+impl FileList {
+    pub fn get_files_from_directory<P, F>(dir: P, filter: F) -> Self
+    where
+        P: AsRef<Path>,
+        F: Fn(&gio::FileInfo) -> bool + 'static,
+    {
+        let mut l = FileList::default();
+
+        let dir = gio::File::new_for_path(dir);
+        let dir_path = dir.get_path();
+        if dir_path.is_none() {
+            err_out!("Couldn't get dir path");
+            return l;
+        }
+        let dir_path = dir_path.unwrap();
+        if let Ok(enumerator) =
+            dir.enumerate_children("*", gio::FileQueryInfoFlags::NONE, gio::NONE_CANCELLABLE)
+        {
+            for itr in enumerator.into_iter() {
+                if itr.is_err() {
+                    err_out!("Enumeration failed: {:?}", itr.err());
+                    continue;
+                }
+                let finfo = itr.unwrap();
+                let ftype = finfo.get_file_type();
+                if ftype == gio::FileType::Regular || ftype == gio::FileType::SymbolicLink {
+                    if !filter(&finfo) {
+                        err_out!("Filtered out");
+                        continue;
+                    }
+                    if let Some(name) = finfo.get_name() {
+                        if let Some(fullname) = glib::build_filenamev(&[&dir_path, &name]) {
+                            dbg_out!("Found file {:?}", &fullname);
+                            l.0.push(fullname);
+                        }
+                    }
+                }
+            }
+        }
+
+        l.0.sort();
+        l
+    }
+
+    pub fn file_is_media(fileinfo: &gio::FileInfo) -> bool {
+        if let Some(gmtype) = fileinfo.get_content_type() {
+            let t = guess_type(&gmtype);
+            return match t {
+                MType::Image(_) | MType::Movie => true,
+                _ => false,
+            };
+        }
+
+        err_out!("Coudln't get file type");
+        false
+    }
+}
+
 #[no_mangle]
-pub unsafe extern "C" fn file_is_media(finfo: *mut gio_sys::GFileInfo) -> bool {
+pub unsafe extern "C" fn fwk_file_is_media(finfo: *mut gio_sys::GFileInfo) -> bool {
     let fileinfo = gio::FileInfo::from_glib_none(finfo);
-    if let Some(gmtype) = fileinfo.get_content_type() {
-        let t = guess_type(&gmtype);
-        return match t {
-            MType::Image(_) | MType::Movie => true,
-            _ => false,
-        };
+    FileList::file_is_media(&fileinfo)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn fwk_file_list_new() -> *mut FileList {
+    Box::into_raw(Box::new(FileList::default()))
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn fwk_file_list_delete(l: *mut FileList) {
+    Box::from_raw(l);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn fwk_file_list_get_files_from_directory(
+    dir: *const c_char,
+    filter: Option<fn(*mut gio_sys::GFileInfo) -> bool>,
+) -> *mut FileList {
+    let cstr = CStr::from_ptr(dir);
+    match filter {
+        Some(filter) => {
+            let f = Box::new(filter);
+            Box::into_raw(Box::new(FileList::get_files_from_directory(
+                &PathBuf::from(&*cstr.to_string_lossy()),
+                move |finfo| f(finfo.to_glib_none().0),
+            )))
+        }
+        None => Box::into_raw(Box::new(FileList::get_files_from_directory(
+            &PathBuf::from(&*cstr.to_string_lossy()),
+            move |_| true,
+        ))),
     }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn fwk_file_list_size(l: &FileList) -> usize {
+    l.0.len()
+}
+
+/// Return the path string at index %idx
+/// The resulting string must be freeed with %rust_cstring_delete
+#[no_mangle]
+pub unsafe extern "C" fn fwk_file_list_at(l: &FileList, idx: usize) -> *mut c_char {
+    CString::new(l.0[idx].to_string_lossy().as_bytes())
+        .unwrap()
+        .into_raw()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn fwk_file_list_push_back(l: &mut FileList, value: *const c_char) {
+    assert!(!value.is_null());
+    if value.is_null() {
+        return;
+    }
+    let s = CStr::from_ptr(value);
+    l.0.push(PathBuf::from(&*s.to_string_lossy()));
+}
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+    use std::fs;
+    use std::path::PathBuf;
+
+    #[test]
+    pub fn test_files_sanity() {
+        let root_p = PathBuf::from("AAtest");
+        let mut p = root_p.clone();
+        p.push("sub");
+        assert!(fs::create_dir_all(&p).is_ok());
+        let mut file1 = root_p.clone();
+        file1.push("1");
+        assert!(fs::write(&file1, "one").is_ok());
+        let mut file2 = root_p.clone();
+        file2.push("2");
+        assert!(fs::write(file2, "two").is_ok());
+        let mut file3 = root_p.clone();
+        file3.push("3");
+        assert!(fs::write(file3, "three").is_ok());
 
-    false
+        let files = FileList::get_files_from_directory("foo", |_| true);
+
+        assert_eq!(files.0.len(), 0);
+
+        let files = FileList::get_files_from_directory(&root_p, |_| true);
+        assert_eq!(files.0.len(), 3);
+
+        assert!(fs::remove_dir_all(&root_p).is_ok());
+    }
 }
diff --git a/src/engine/db/bindings.hpp b/src/engine/db/bindings.hpp
index 12f058c..cbeadcf 100644
--- a/src/engine/db/bindings.hpp
+++ b/src/engine/db/bindings.hpp
@@ -3,4 +3,3 @@
 #include "properties-enum.hpp"
 
 #include "engine/db/libmetadata.hpp"
-#include "fwk/utils/files.hpp"
diff --git a/src/engine/importer/cameraimporter.cpp b/src/engine/importer/cameraimporter.cpp
index e17e855..402e098 100644
--- a/src/engine/importer/cameraimporter.cpp
+++ b/src/engine/importer/cameraimporter.cpp
@@ -121,7 +121,7 @@ bool CameraImporter::do_import(const std::string& source, const std::string& des
             DBG_ASSERT(!tmp_dir_path.empty(), "Dest dir is empty");
             // XXX check we don't return an empty string.
 
-            fwk::FileListPtr files = std::make_shared<fwk::FileList>();
+            fwk::FileListPtr files = fwk::wrapFileList(ffi::fwk_file_list_new());
             for (auto file: file_list) {
                 auto imported_camera_file =
                     std::dynamic_pointer_cast<CameraImportedFile>(file);
@@ -135,7 +135,7 @@ bool CameraImporter::do_import(const std::string& source, const std::string& des
                 if (this->m_camera->download_file(imported_camera_file->folder(),
                                                   imported_camera_file->name(),
                                                   output_path)) {
-                    files->push_back(output_path);
+                    ffi::fwk_file_list_push_back(files.get(), output_path.c_str());
                 }
             }
 
diff --git a/src/engine/importer/directoryimporter.cpp b/src/engine/importer/directoryimporter.cpp
index cf0e628..2a35ddd 100644
--- a/src/engine/importer/directoryimporter.cpp
+++ b/src/engine/importer/directoryimporter.cpp
@@ -2,7 +2,7 @@
 /*
  * niepce - engine/importer/directoryimporter.cpp
  *
- * Copyright (C) 2014-2018 Hubert Figuière
+ * Copyright (C) 2014-2020 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,6 +22,7 @@
 #include <glibmm/miscutils.h>
 
 #include "fwk/base/debug.hpp"
+#include "fwk/base/string.hpp"
 #include "fwk/utils/pathutils.hpp"
 #include "engine/importer/directoryimporter.hpp"
 #include "engine/importer/importedfile.hpp"
@@ -61,17 +62,23 @@ const std::string& DirectoryImporter::id() const
     return _id;
 }
 
+static bool filter_only_media(GFileInfo* info)
+{
+    return fwk::filter_only_media(Glib::wrap(info, true));
+}
+
 bool DirectoryImporter::list_source_content(const std::string & source,
                                             const SourceContentReady& callback)
 {
     auto files =
-        fwk::FileList::getFilesFromDirectory(source,
-                                             &fwk::filter_only_media);
-
+        fwk::wrapFileList(ffi::fwk_file_list_get_files_from_directory(
+                              source.c_str(), &filter_only_media));
+    DBG_OUT("files size: %lu", ffi::fwk_file_list_size(files.get()));
     std::list<ImportedFilePtr> content;
-    for(const auto & entry : *files)
+    for (size_t i = 0; i < ffi::fwk_file_list_size(files.get()); i++)
     {
-        content.push_back(ImportedFilePtr(new DirectoryImportedFile(entry)));
+        auto entry = fwk::RustFfiString(ffi::fwk_file_list_at(files.get(), i));
+        content.push_back(ImportedFilePtr(new DirectoryImportedFile(entry.str())));
     }
     callback(std::move(content));
 
@@ -95,7 +102,8 @@ bool DirectoryImporter::do_import(const std::string& source, const std::string&
                                   const FileImporter& callback)
 {
     fwk::FileListPtr files;
-    files = fwk::FileList::getFilesFromDirectory(source, &fwk::filter_none);
+    files = fwk::wrapFileList(ffi::fwk_file_list_get_files_from_directory(
+                                  source.c_str(), nullptr));
 
     return callback(source, files, Managed::NO);
 }
diff --git a/src/fwk/utils/Makefile.am b/src/fwk/utils/Makefile.am
index ad4e424..f339272 100644
--- a/src/fwk/utils/Makefile.am
+++ b/src/fwk/utils/Makefile.am
@@ -4,14 +4,12 @@ niepce_cppflags = -I$(top_srcdir)/src/ \
 
 AM_CPPFLAGS = $(niepce_cppflags)
 
-TESTS = testfiles \
-       testpathutils \
+TESTS = testpathutils \
        teststringutils
 
 EXTRA_DIST = test.xmp test2.ufraw MODULES_HOWTO
 
-check_PROGRAMS = testfiles \
-       testpathutils \
+check_PROGRAMS = testpathutils \
        teststringutils
 
 
@@ -21,10 +19,6 @@ testing_ldadd = @top_builddir@/third_party/libgtest.a \
        ../base/libfwkbase.a \
        @FRAMEWORK_LIBS@
 
-testfiles_SOURCES = t/testfiles.cpp
-testfiles_CPPFLAGS = $(testing_cppflags)
-testfiles_LDADD = $(testing_ldadd)
-
 teststringutils_SOURCES = t/teststringutils.cpp
 teststringutils_CPPFLAGS = $(testing_cppflags)
 teststringutils_LDADD = $(testing_ldadd)
diff --git a/src/fwk/utils/files.cpp b/src/fwk/utils/files.cpp
index b155858..a4971d9 100644
--- a/src/fwk/utils/files.cpp
+++ b/src/fwk/utils/files.cpp
@@ -71,102 +71,14 @@ bool filter_xmp_out(const Glib::RefPtr<Gio::FileInfo> & file)
 
 bool filter_only_media(const Glib::RefPtr<Gio::FileInfo> & file)
 {
-    return ffi::file_is_media(file->gobj());
+    return ffi::fwk_file_is_media(file->gobj());
 }
 
 
-
-FileList::FileList()
-{
-}
-
-FileList::FileList( const _impltype_t & v )
-    : _impltype_t( v )
-{
-}
-
-FileList::value_type FileList::at(size_type index) const
-{
-    return _impltype_t::at(index);
-}
-
-const FileList::value_type::value_type*
-FileList::at_cstr(size_type index) const
-{
-    return _impltype_t::at(index).c_str();
-}
-
-FileList::const_iterator FileList::begin() const
-{
-    return _impltype_t::cbegin();
-}
-
-FileList::const_iterator FileList::end() const
-{
-    return _impltype_t::cend();
-}
-
-FileList::const_iterator FileList::cbegin() const
-{
-    return _impltype_t::cbegin();
-}
-
-FileList::const_iterator FileList::cend() const
-{
-    return _impltype_t::cend();
-}
-
-FileList::size_type FileList::size() const
-{
-    return _impltype_t::size();
-}
-
-void FileList::sort()
-{
-    std::sort(_impltype_t::begin(), _impltype_t::end());
-}
-
-void FileList::push_back(const value_type & v)
+FileListPtr wrapFileList(ffi::FileList* list)
 {
-    _impltype_t::push_back(v);
-}
-
-FileList::Ptr FileList::getFilesFromDirectory(const FileList::value_type& p, std::function<bool (const 
Glib::RefPtr<Gio::FileInfo>&)> filter)
-{
-//             if(!exists( p ) ) {
-//                     DBG_OUT( "directory %s do not exist", p.c_str() );
-//                     return Ptr();
-//             }
-    try {
-        FileList::Ptr l(new FileList());
-
-        Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path(p);
-        Glib::RefPtr<Gio::FileEnumerator> enumerator = dir->enumerate_children();
-
-        for (Glib::RefPtr<Gio::FileInfo> itr = enumerator->next_file();
-             itr ; itr = enumerator->next_file()) {
-            Gio::FileType ftype = itr->get_file_type();
-            if ((ftype == Gio::FILE_TYPE_REGULAR)  || (ftype == Gio::FILE_TYPE_SYMBOLIC_LINK)) {
-                if (filter(itr)) {
-                    std::string fullname =
-                        Glib::build_filename(dir->get_path(), itr->get_name());
-                    l->push_back(fullname);
-                    DBG_OUT("found file %s", fullname.c_str());
-                }
-            }
-        }
-        enumerator->close();
-        l->sort();
-        return l;
-    } catch(const Glib::Error & e) {
-        ERR_OUT("Exception: %s", e.what().c_str());
-    } catch(const std::exception & e) {
-        ERR_OUT("Exception: %s", e.what());
-    }
-
-    return Ptr();
+    return FileListPtr(list, ffi::fwk_file_list_delete);
 }
 
-
 }
 
diff --git a/src/fwk/utils/files.hpp b/src/fwk/utils/files.hpp
index 6fe0410..6a3ffdc 100644
--- a/src/fwk/utils/files.hpp
+++ b/src/fwk/utils/files.hpp
@@ -18,8 +18,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __UTILS_FILES_H__
-#define __UTILS_FILES_H__
+#pragma once
 
 #include <algorithm>
 #include <vector>
@@ -32,6 +31,8 @@
 #include <giomm/fileinfo.h>
 #endif
 
+#include "rust_bindings.hpp"
+
 namespace fwk {
 
 #if !RUST_BINDGEN
@@ -45,44 +46,8 @@ bool filter_xmp_out(const Glib::RefPtr<Gio::FileInfo> & file);
 bool filter_only_media(const Glib::RefPtr<Gio::FileInfo> & file);
 #endif
 
-class FileList;
-typedef std::shared_ptr<FileList> FileListPtr;
-
-class FileList
-       : private std::vector<std::string>
-{
-public:
-    typedef FileListPtr Ptr;
+typedef std::shared_ptr<ffi::FileList> FileListPtr;
 
-    typedef std::vector<std::string>    _impltype_t;
-    typedef _impltype_t::value_type       value_type;
-#if !RUST_BINDGEN
-    typedef _impltype_t::iterator         iterator;
-    typedef _impltype_t::const_iterator   const_iterator;
-#endif
-    typedef _impltype_t::size_type        size_type;
-
-    FileList();
-    FileList(const _impltype_t&);
-
-#if !RUST_BINDGEN
-    static Ptr getFilesFromDirectory(const value_type& dir,
-                                     std::function<bool (const Glib::RefPtr<Gio::FileInfo>&)> filter);
-
-    value_type at(size_type index) const;
-#endif
-    const value_type::value_type* at_cstr(size_type index) const;
-#if !RUST_BINDGEN
-    const_iterator begin() const;
-    const_iterator end() const;
-    const_iterator cbegin() const;
-    const_iterator cend() const;
-#endif
-    size_type size() const;
-    void sort();
-    void push_back(const value_type & v);
-};
+FileListPtr wrapFileList(ffi::FileList* list);
 
 }
-
-#endif
diff --git a/src/fwk/utils/modulemanager.cpp b/src/fwk/utils/modulemanager.cpp
index 2f99f16..0199482 100644
--- a/src/fwk/utils/modulemanager.cpp
+++ b/src/fwk/utils/modulemanager.cpp
@@ -35,6 +35,7 @@
 #include "fwk/utils/pathutils.hpp"
 #include "fwk/base/debug.hpp"
 #include "fwk/base/map.hpp"
+#include "fwk/base/string.hpp"
 #include "dynamicmodule.hpp"
 #include "modulemanager.hpp"
 
@@ -57,24 +58,26 @@ namespace fwk {
   }
 
 
-  void ModuleManager::load_modules()
+  static bool filter(GFileInfo* f)
   {
-    std::string ext = std::string(".") + G_MODULE_SUFFIX;
+    return fwk::filter_ext(Glib::wrap(f, true), std::string(".") + G_MODULE_SUFFIX);
+  }
 
+  void ModuleManager::load_modules()
+  {
     for(auto iter = m_dirs.cbegin();
         iter != m_dirs.cend(); ++iter) {
 
-      fwk::FileList::Ptr l;
-      l = FileList::getFilesFromDirectory(*iter, [ext] (const Glib::RefPtr<Gio::FileInfo>& f) {
-          return fwk::filter_ext(f, ext);
-      });
+      fwk::FileListPtr l;
+      l = wrapFileList(ffi::fwk_file_list_get_files_from_directory(
+                         iter->c_str(), filter));
 
-      for(auto mod_iter = l->cbegin();
-          mod_iter != l->cend(); ++mod_iter) {
+      for(size_t i = 0; i < ffi::fwk_file_list_size(l.get()); i++) {
 
-        Glib::Module module(*iter + "/" + path_basename(*mod_iter), 
+        auto file_path = fwk::RustFfiString(ffi::fwk_file_list_at(l.get(), i));
+        Glib::Module module(*iter + "/" + path_basename(file_path.c_str()),
                             Glib::MODULE_BIND_LOCAL);
-        DBG_OUT("load module %s", path_basename(*mod_iter).c_str());
+        DBG_OUT("load module %s", path_basename(file_path.c_str()).c_str());
 
         if(!module) {
           DBG_OUT("error loading %s", Glib::Module::get_last_error().c_str());
diff --git a/src/libraryclient/clientimpl.rs b/src/libraryclient/clientimpl.rs
index ac6de46..58e11d6 100644
--- a/src/libraryclient/clientimpl.rs
+++ b/src/libraryclient/clientimpl.rs
@@ -187,7 +187,7 @@ impl ClientInterface for ClientImpl {
     /// Import files from a directory
     /// @param dir the directory
     /// @param manage true if imports have to be managed
-    fn import_files(&mut self, dir: String, files: Vec<String>, manage: Managed) {
+    fn import_files(&mut self, dir: String, files: Vec<PathBuf>, manage: Managed) {
         self.schedule_op(move |lib| commands::cmd_import_files(&lib, &dir, &files, manage));
     }
 }
diff --git a/src/libraryclient/clientinterface.rs b/src/libraryclient/clientinterface.rs
index 773ab70..efb1462 100644
--- a/src/libraryclient/clientinterface.rs
+++ b/src/libraryclient/clientinterface.rs
@@ -17,6 +17,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+use std::path::PathBuf;
+
 use npc_engine::db::library::Managed;
 use npc_engine::db::LibraryId;
 use npc_engine::root::eng::NiepceProperties as Np;
@@ -56,7 +58,7 @@ pub trait ClientInterface {
     /// @param dir the directory
     /// @param files the files to import
     /// @param manage true if imports have to be managed
-    fn import_files(&mut self, dir: String, files: Vec<String>, manage: Managed);
+    fn import_files(&mut self, dir: String, files: Vec<PathBuf>, manage: Managed);
 }
 
 /// Sync client interface
diff --git a/src/libraryclient/mod.rs b/src/libraryclient/mod.rs
index 41dd4ce..1cdf702 100644
--- a/src/libraryclient/mod.rs
+++ b/src/libraryclient/mod.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - libraryclient/mod.rs
  *
- * Copyright (C) 2017-2019 Hubert Figuière
+ * Copyright (C) 2017-2020 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -32,9 +32,9 @@ use npc_engine::db::library::Managed;
 use npc_engine::db::LibraryId;
 use npc_engine::library::notification::{LcChannel, LibNotification};
 use npc_engine::root::eng::NiepceProperties as Np;
-use npc_engine::root::fwk::FileList;
 use npc_fwk::base::PropertyValue;
 use npc_fwk::toolkit::PortableChannel;
+use npc_fwk::utils::files::FileList;
 
 /// Wrap the libclient Arc so that it can be passed around
 /// Used in the ffi for example.
@@ -148,7 +148,7 @@ impl ClientInterface for LibraryClient {
     /// Import files from a directory
     /// @param dir the directory
     /// @param manage true if imports have to be managed
-    fn import_files(&mut self, dir: String, files: Vec<String>, manage: Managed) {
+    fn import_files(&mut self, dir: String, files: Vec<PathBuf>, manage: Managed) {
         self.pimpl.import_files(dir, files, manage);
     }
 }
@@ -381,20 +381,11 @@ pub extern "C" fn libraryclient_process_xmp_update_queue(
 pub unsafe extern "C" fn libraryclient_import_files(
     client: &mut LibraryClientWrapper,
     dir: *const c_char,
-    cfiles: &mut FileList,
+    files: &FileList,
     manage: Managed,
 ) {
     let folder = CStr::from_ptr(dir).to_string_lossy();
-    let mut files: Vec<String> = vec![];
-    {
-        let len = cfiles.size();
-        for i in 0..len {
-            let f = cfiles.at_cstr(i);
-            let cstr = CStr::from_ptr(f).to_string_lossy();
-            files.push(String::from(cstr));
-        }
-    }
     client
         .unwrap_mut()
-        .import_files(String::from(folder), files, manage);
+        .import_files(String::from(folder), files.0.clone(), manage);
 }
diff --git a/src/rust_bindings.hpp b/src/rust_bindings.hpp
index 278a65b..c23c58b 100644
--- a/src/rust_bindings.hpp
+++ b/src/rust_bindings.hpp
@@ -25,10 +25,6 @@
 
 #include "engine/db/properties-enum.hpp"
 
-namespace fwk {
-class FileList;
-}
-
 namespace ffi {
 class rust_str;
 struct Utc;
@@ -36,7 +32,6 @@ template <class T>
 struct DateTime;
 typedef rust_str str;
 typedef eng::NiepceProperties Np;
-typedef fwk::FileList FileList;
 }
 
 #include "target/fwk_bindings.h"
@@ -51,6 +46,7 @@ typedef ffi::PropertyBag PropertyBag;
 typedef ffi::PropertySet PropertySet;
 typedef ffi::Date Date;
 typedef ffi::RgbColour RgbColour;
+typedef ffi::FileList FileList;
 }
 
 namespace eng {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]