[niepce: 11/29] engine+rust: implement FileBundle and MimeType in Rust



commit a0158e2300bf59ea304aa90ff4d5df1f9b1c0916
Author: Hubert Figuière <hub figuiere net>
Date:   Fri Jun 16 22:16:15 2017 -0400

    engine+rust: implement FileBundle and MimeType in Rust

 Cargo.toml                        |    6 ++-
 build.rs                          |    7 ++-
 src/engine/Makefile.am            |    2 +-
 src/engine/db/bindings.hpp        |    3 +
 src/engine/db/filebundle.cpp      |   91 +++++++-----------------
 src/engine/db/filebundle.hpp      |   52 +++-----------
 src/engine/db/filebundle.rs       |  140 +++++++++++++++++++++++++++++++++++++
 src/engine/db/library.cpp         |   12 ++--
 src/engine/db/library.hpp         |    2 +-
 src/engine/db/mod.rs              |    1 +
 src/engine/db/test_filebundle.cpp |   18 +++--
 src/engine/library/commands.cpp   |    8 +-
 src/fwk/mod.rs                    |    4 +
 src/fwk/toolkit/mimetype.cpp      |   28 +++++---
 src/fwk/toolkit/mimetype.hpp      |   12 ++--
 src/fwk/toolkit/mimetype.rs       |  120 +++++++++++++++++++++++++++++++
 src/fwk/toolkit/mod.rs            |    2 +
 src/lib.rs                        |    3 +
 src/libraryclient/Makefile.am     |    2 +-
 src/niepce/Makefile.am            |    2 +-
 20 files changed, 370 insertions(+), 145 deletions(-)
---
diff --git a/Cargo.toml b/Cargo.toml
index dddc75e..43a3478 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,12 +7,16 @@ authors = ["Hubert Figuière <hub figuiere net>"]
 libc = "0.2.23"
 sqlite = "0.23.4"
 exempi = "2.4.1"
+glib-sys = { git = "https://github.com/gtk-rs/sys"; }
+gio-sys = { git = "https://github.com/gtk-rs/sys"; }
+gio = { git = "https://github.com/gtk-rs/gio"; }
 #gphoto = "0.1.1"
 
 [build-dependencies]
 # We need git master as currently it the crate version fail on shared_ptr<>
 bindgen = { git = "https://github.com/servo/rust-bindgen.git"; }
+pkg-config = "0.3.9"
 
 [lib]
-name = "niece_rust"
+name = "niepce_rust"
 crate-type = ["staticlib"]
diff --git a/build.rs b/build.rs
index c48b426..ac28afb 100644
--- a/build.rs
+++ b/build.rs
@@ -1,10 +1,10 @@
 extern crate bindgen;
+extern crate pkg_config;
 
 use std::env;
 use std::path::PathBuf;
 
 fn main() {
-
     // The bindgen::Builder is the main entry point
     // to bindgen, and lets you build up options for
     // the resulting bindings.
@@ -18,9 +18,12 @@ fn main() {
         // The input header we would like to generate
         // bindings for.
         .whitelisted_type("eng::NiepceProperties")
-        .header("src/engine/db/properties-enum.hpp")
+        .header("src/engine/db/bindings.hpp")
+        .clang_arg("--std=c++11")
+        .clang_arg("-DRUST_BINDGEN=1")
         .clang_arg("-I./src");
 
+
     // Finish the builder and generate the bindings.
     let bindings = builder.generate()
     // Unwrap the Result and panic on failure.
diff --git a/src/engine/Makefile.am b/src/engine/Makefile.am
index 8123f1c..9e6e83e 100644
--- a/src/engine/Makefile.am
+++ b/src/engine/Makefile.am
@@ -8,10 +8,10 @@ TESTS = test_library test_filebundle test_opqueue
 
 TEST_LIBS =  \
        libniepceengine.a \
+       $(top_builddir)/target/debug/libniepce_rust.a \
        $(top_builddir)/src/fwk/utils/libniepceutils.a \
        $(top_builddir)/src/fwk/toolkit/libniepceframework.a \
        $(top_builddir)/src/fwk/base/libfwkbase.a \
-       $(top_builddir)/target/debug/libniece_rust.a \
        @BOOST_UNIT_TEST_FRAMEWORK_LIBS@ \
        @FRAMEWORK_LIBS@ \
        @OPENRAW_LIBS@ \
diff --git a/src/engine/db/bindings.hpp b/src/engine/db/bindings.hpp
new file mode 100644
index 0000000..1d234bc
--- /dev/null
+++ b/src/engine/db/bindings.hpp
@@ -0,0 +1,3 @@
+/** @brief what to generate bindings for in Rust */
+
+#include "properties-enum.hpp"
diff --git a/src/engine/db/filebundle.cpp b/src/engine/db/filebundle.cpp
index 9b2611e..64ec299 100644
--- a/src/engine/db/filebundle.cpp
+++ b/src/engine/db/filebundle.cpp
@@ -24,81 +24,42 @@
 #include "fwk/utils/pathutils.hpp"
 #include "fwk/toolkit/mimetype.hpp"
 
+extern "C" eng::FileBundle* engine_db_filebundle_new();
+extern "C" void engine_db_filebundle_delete(eng::FileBundle*);
 
 namespace eng {
 
-bool 
-FileBundle::add(const std::string & path)
-{
-    // TODO make it more reliable with more tests.
-    fwk::MimeType mime_type(path);
-    bool added = true;
-
-    if(mime_type.isImage()) {
-        if(mime_type.isDigicamRaw()) {
-            if(!m_main.empty() && m_jpeg.empty()) {
-                m_jpeg = m_main;
-                m_type = LibFileType::RAW_JPEG;
-            }
-            else {
-                m_type = LibFileType::RAW;
-            }
-            m_main = path;
-        }
-        else {
-            if(!m_main.empty()) {
-                m_jpeg = path;
-                m_type = LibFileType::RAW_JPEG;
-            }
-            else {
-                m_main = path;
-                m_type = LibFileType::IMAGE;
-            }
-        }
-    }
-    else if(mime_type.isXmp()) {
-        m_xmp_sidecar = path;
-    }
-    else if(mime_type.isMovie()) {
-        m_main = path;
-        m_type = LibFileType::VIDEO;
-    }
-    else {
-        DBG_OUT("Unkown file %s of type %s\n", path.c_str(), 
-                mime_type.string().c_str());
-        added = false;
-    }
-    return added;
+FileBundlePtr filebundle_new() {
+    return FileBundlePtr(engine_db_filebundle_new(), &engine_db_filebundle_delete);
 }
 
-
-FileBundle::ListPtr 
-FileBundle::filter_bundles(const fwk::FileList::Ptr & files)
+FileBundleListPtr
+filebundle_filter_bundles(const fwk::FileList::Ptr & files)
 {
-    FileBundle::ListPtr bundles(new FileBundle::List());
-    FileBundle::Ptr current_bundle;
+    FileBundleListPtr bundles(new FileBundleList);
+    FileBundlePtr current_bundle;
     std::string current_base;
 
     files->sort();
 
-    std::for_each(files->cbegin(), files->cend(),
-                  [&current_base, &bundles, &current_bundle]
-                  (const std::string & f) {
-                      std::string basename = fwk::path_stem(f);
-
-                      if(basename != current_base) {
-                          FileBundle::Ptr new_bundle(new FileBundle());
-                          if(new_bundle->add(f)) {
-                              bundles->push_back(new_bundle);
-                              current_bundle = new_bundle;
-                              current_base = basename;
-                          }
-                      }
-                      else {
-                          current_bundle->add(f);
-                      }
-                  }
-        );
+    std::for_each(
+        files->cbegin(), files->cend(),
+        [&current_base, &bundles, &current_bundle] (const std::string & f) {
+            std::string basename = fwk::path_stem(f);
+            DBG_OUT("basename %s current_base %s", basename.c_str(), current_base.c_str());
+            if(basename != current_base) {
+                FileBundlePtr new_bundle(filebundle_new());
+                auto r = engine_db_filebundle_add(new_bundle.get(), f.c_str());
+                DBG_OUT("r = %d", r);
+                if (r) {
+                    bundles->push_back(new_bundle);
+                    current_bundle = new_bundle;
+                    current_base = basename;
+                }
+            } else {
+                engine_db_filebundle_add(current_bundle.get(), f.c_str());
+            }
+        });
 
     return bundles;
 }
diff --git a/src/engine/db/filebundle.hpp b/src/engine/db/filebundle.hpp
index d4300f4..8785665 100644
--- a/src/engine/db/filebundle.hpp
+++ b/src/engine/db/filebundle.hpp
@@ -17,52 +17,29 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __DB_FILEBUNDLE_H_
-#define __DB_FILEBUNDLE_H_
+#pragma once
 
 #include <list>
-#include <string>
 #include <memory>
 
 #include "fwk/utils/files.hpp"
-#include "engine/db/libfile.hpp"
 
 namespace eng {
 
+class FileBundle;
+typedef std::shared_ptr<FileBundle> FileBundlePtr;
+typedef std::list<FileBundlePtr> FileBundleList;
+typedef std::shared_ptr<FileBundleList> FileBundleListPtr;
 
-class FileBundle
-{
-public:
-    typedef std::shared_ptr<FileBundle> Ptr;
-    typedef std::list<Ptr> List;
-    typedef std::shared_ptr<List> ListPtr;
+FileBundleListPtr filebundle_filter_bundles(const fwk::FileList::Ptr & files);
 
-    FileBundle()
-        : m_type(LibFileType::UNKNOWN)
-        { }
-    LibFileType type() const
-        { return m_type; }
-
-    /** add a file to a bundle. Will determine what type it is. 
-     * @return false if it does not know about the file
-     */
-    bool add(const std::string & path);
-    const std::string & main_file() const
-        { return m_main; }
-    const std::string & jpeg() const
-        { return m_jpeg; }
-    const std::string & sidecar() const
-        { return m_xmp_sidecar; }
-    
-    static ListPtr filter_bundles(const fwk::FileList::Ptr & files);
-private:
-    LibFileType m_type;
-    std::string m_main;
-    std::string m_xmp_sidecar;
-    std::string m_jpeg;
-    std::string m_thumbnail;
-};
+FileBundlePtr filebundle_new();
+}
 
+extern "C" const char* engine_db_filebundle_sidecar(const eng::FileBundle*);
+extern "C" const char* engine_db_filebundle_main(const eng::FileBundle*);
+extern "C" const char* engine_db_filebundle_jpeg(const eng::FileBundle*);
+extern "C" bool engine_db_filebundle_add(eng::FileBundle*, const char*);
 
 /*
   Local Variables:
@@ -73,8 +50,3 @@ private:
   fill-column:99
   End:
 */
-
-}
-
-#endif
-
diff --git a/src/engine/db/filebundle.rs b/src/engine/db/filebundle.rs
new file mode 100644
index 0000000..9dc4dcd
--- /dev/null
+++ b/src/engine/db/filebundle.rs
@@ -0,0 +1,140 @@
+/*
+ * niepce - engine/db/filebundle.rs
+ *
+ * Copyright (C) 2017 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+use libc::c_char;
+use std::ffi::CStr;
+use std::ffi::CString;
+
+use super::libfile::FileType;
+use fwk::MimeType;
+
+pub struct FileBundle {
+    file_type: FileType,
+    main: String,
+    pub main_c: CString,
+    xmp_sidecar: String,
+    pub xmp_sidecar_c: CString,
+    jpeg: String,
+    pub jpeg_c: CString,
+}
+
+impl FileBundle {
+
+    pub fn new() -> FileBundle {
+        FileBundle {
+            file_type: FileType::UNKNOWN,
+            main: String::from(""),
+            main_c: CString::new("").unwrap(),
+            xmp_sidecar: String::from(""),
+            xmp_sidecar_c: CString::new("").unwrap(),
+            jpeg: String::from(""),
+            jpeg_c: CString::new("").unwrap(),
+        }
+    }
+
+    pub fn add(&mut self, path: &str) -> bool {
+        println!("path {}", path);
+        let mime_type = MimeType::new(path);
+        let mut added = true;
+
+        if mime_type.is_image() {
+            if mime_type.is_digicam_raw() {
+                println!("is RAW");
+                if !self.main.is_empty() && self.jpeg.is_empty() {
+                    println!("+JPEG");
+                    self.jpeg = self.main.clone();
+                    self.file_type = FileType::RAW_JPEG;
+                } else {
+                    println!("just RAW");
+                    self.file_type = FileType::RAW;
+                }
+                self.main = String::from(path);
+            } else {
+                println!("is JPEG?");
+                if !self.main.is_empty() {
+                    println!("RAW+JPEG");
+                    self.jpeg = String::from(path);
+                    self.file_type = FileType::RAW_JPEG;
+                } else {
+                    println!("JPEG");
+                    self.main = String::from(path);
+                    self.file_type = FileType::IMAGE;
+                }
+            }
+        } else if mime_type.is_xmp() {
+            self.xmp_sidecar = String::from(path);
+        } else if mime_type.is_movie() {
+            self.main = String::from(path);
+            self.file_type = FileType::VIDEO;
+        } else {
+//            let cstr = &*unsafe { CStr::from_ptr(mime_type.c_str()) };
+            println!("Unknown file {} of type", path);//, cstr.to_string_lossy());
+            //DBG_OUT("Unkown file %s of type %s\n", path.c_str(),
+            //        mime_type.string().c_str());
+            added = false;
+        }
+        added
+    }
+
+    pub fn main(&self) -> &str {
+        &self.main
+    }
+
+    pub fn jpeg(&self) -> &str {
+        &self.jpeg
+    }
+
+    pub fn sidecar(&self) -> &str {
+        &self.xmp_sidecar
+    }
+}
+
+#[no_mangle]
+pub extern fn engine_db_filebundle_new() -> *mut FileBundle {
+    let fb = Box::new(FileBundle::new());
+    Box::into_raw(fb)
+}
+
+#[no_mangle]
+pub extern fn engine_db_filebundle_delete(fb: *mut FileBundle) {
+    unsafe { Box::from_raw(fb) };
+}
+
+#[no_mangle]
+pub extern fn engine_db_filebundle_sidecar(this: &mut FileBundle) -> *const c_char {
+    this.xmp_sidecar_c = CString::new(this.sidecar()).unwrap();
+    this.xmp_sidecar_c.as_ptr()
+}
+
+#[no_mangle]
+pub extern fn engine_db_filebundle_main(this: &mut FileBundle) -> *const c_char {
+    this.main_c = CString::new(this.main()).unwrap();
+    this.main_c.as_ptr()
+}
+
+#[no_mangle]
+pub extern fn engine_db_filebundle_jpeg(this: &mut FileBundle) -> *const c_char {
+    this.jpeg_c = CString::new(this.jpeg()).unwrap();
+    this.jpeg_c.as_ptr()
+}
+
+#[no_mangle]
+pub extern fn engine_db_filebundle_add(this: &mut FileBundle, f: *const c_char) -> c_char {
+    this.add(&*unsafe { CStr::from_ptr(f) }.to_string_lossy()) as c_char
+}
diff --git a/src/engine/db/library.cpp b/src/engine/db/library.cpp
index 32014ae..8e6803f 100644
--- a/src/engine/db/library.cpp
+++ b/src/engine/db/library.cpp
@@ -351,24 +351,24 @@ library_id_t Library::addFileAndFolder(const std::string & folder,
 }
 
 library_id_t Library::addBundle(library_id_t folder_id,
-                                const eng::FileBundle::Ptr & bundle,
+                                const eng::FileBundlePtr & bundle,
                                 Managed manage)
 {
     library_id_t file_id = 0;
-    file_id = addFile(folder_id, bundle->main_file(), manage);
+    file_id = addFile(folder_id, engine_db_filebundle_main(bundle.get()), manage);
     if(file_id > 0) {
         library_id_t fsfile_id;
         bool success;
         // addXmpSidecar
-        if(!bundle->sidecar().empty()) {
-            fsfile_id = addFsFile(bundle->sidecar());
+        if(engine_db_filebundle_sidecar(bundle.get())[0] == 0) {
+            fsfile_id = addFsFile(engine_db_filebundle_sidecar(bundle.get()));
             if(fsfile_id > 0) {
                 success = addSidecarFileToBundle(file_id, fsfile_id);
             }
         }
         // addJpeg
-        if(!bundle->jpeg().empty()) {
-            fsfile_id = addFsFile(bundle->jpeg());
+        if(engine_db_filebundle_jpeg(bundle.get())[0] == 0) {
+            fsfile_id = addFsFile(engine_db_filebundle_jpeg(bundle.get()));
             if(fsfile_id > 0) {
                 success = addJpegFileToBundle(file_id, fsfile_id);
             }
diff --git a/src/engine/db/library.hpp b/src/engine/db/library.hpp
index 5d91341..e551ea4 100644
--- a/src/engine/db/library.hpp
+++ b/src/engine/db/library.hpp
@@ -110,7 +110,7 @@ public:
      * @param manage pass Managed::YES if the library *manage* the file. Currently unsupported.
      */
     library_id_t addBundle(library_id_t folder_id,
-                           const eng::FileBundle::Ptr & bundle,
+                           const eng::FileBundlePtr& bundle,
                            Managed manage);
     /** add a sidecar fsfile to a bundle (file)
      * @param file_id the id of the file bundle
diff --git a/src/engine/db/mod.rs b/src/engine/db/mod.rs
index 775b144..ecf0e78 100644
--- a/src/engine/db/mod.rs
+++ b/src/engine/db/mod.rs
@@ -17,6 +17,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+pub mod filebundle;
 pub mod fsfile;
 pub mod keyword;
 pub mod libfile;
diff --git a/src/engine/db/test_filebundle.cpp b/src/engine/db/test_filebundle.cpp
index 3cb17ab..91c68ce 100644
--- a/src/engine/db/test_filebundle.cpp
+++ b/src/engine/db/test_filebundle.cpp
@@ -43,21 +43,23 @@ int test_main(int, char *[])
 
 //    thelist->push_back("/tmp/some/file");
 
-    eng::FileBundle::ListPtr bundles_list = 
-        eng::FileBundle::filter_bundles(thelist);
+    eng::FileBundleListPtr bundles_list =
+        eng::filebundle_filter_bundles(thelist);
 
+    std::cout << "list size " << bundles_list->size() << std::endl;
     BOOST_CHECK(bundles_list->size() == 2);
     auto iter = bundles_list->begin();
     auto b = *iter;
-    BOOST_CHECK(b->main_file() == "/foo/bar/dcs_0001.nef");
-    BOOST_CHECK(b->jpeg() == "/foo/bar/dcs_0001.jpg");
-    BOOST_CHECK(b->sidecar() == "/foo/bar/dcs_0001.xmp");
+    BOOST_CHECK(std::string(engine_db_filebundle_main(b.get())) == "/foo/bar/dcs_0001.nef");
+    printf("jpeg %s\n", engine_db_filebundle_jpeg(b.get()));
+    BOOST_CHECK(std::string(engine_db_filebundle_jpeg(b.get())) == "/foo/bar/dcs_0001.jpg");
+    BOOST_CHECK(std::string(engine_db_filebundle_sidecar(b.get())) == "/foo/bar/dcs_0001.xmp");
 
     ++iter;
     b = *iter;
-    BOOST_CHECK(b->main_file() == "/foo/bar/img_0001.cr2");
-    BOOST_CHECK(b->jpeg() == "/foo/bar/img_0001.jpg");
-    BOOST_CHECK(b->sidecar() == "/foo/bar/img_0001.xmp");
+    BOOST_CHECK(std::string(engine_db_filebundle_main(b.get())) == "/foo/bar/img_0001.cr2");
+    BOOST_CHECK(std::string(engine_db_filebundle_jpeg(b.get())) == "/foo/bar/img_0001.jpg");
+    BOOST_CHECK(std::string(engine_db_filebundle_sidecar(b.get())) == "/foo/bar/img_0001.xmp");
 
     return 0;
 }
diff --git a/src/engine/library/commands.cpp b/src/engine/library/commands.cpp
index 45bfb32..2a2c81d 100644
--- a/src/engine/library/commands.cpp
+++ b/src/engine/library/commands.cpp
@@ -62,8 +62,8 @@ void Commands::cmdImportFile(const Library::Ptr & lib,
     DBG_ASSERT(manage == Library::Managed::NO,
                "managing file is currently unsupported");
 
-    FileBundle::Ptr bundle(new FileBundle);
-    bundle->add(file_path);
+    FileBundlePtr bundle(filebundle_new());
+    engine_db_filebundle_add(bundle.get(), file_path.c_str());
 
     std::string folder = fwk::path_dirname(file_path);
 
@@ -85,12 +85,12 @@ void Commands::cmdImportFiles(const Library::Ptr & lib,
     DBG_ASSERT(manage == Library::Managed::NO,
                "managing file is currently unsupported");
 
-    FileBundle::ListPtr bundles = FileBundle::filter_bundles(files);
+    FileBundleListPtr bundles = filebundle_filter_bundles(files);
 
     LibFolderPtr pf = lib->getFolder(folder);
     if(!pf) {
         pf = lib->addFolder(folder);
-        LibFolderListPtr l( new LibFolderList );
+        LibFolderListPtr l(new LibFolderList);
         l->push_back(pf);
         lib->notify(LibNotification::make<LibNotification::Type::ADDED_FOLDERS>({l}));
     }
diff --git a/src/fwk/mod.rs b/src/fwk/mod.rs
index be8726c..ebd81d5 100644
--- a/src/fwk/mod.rs
+++ b/src/fwk/mod.rs
@@ -19,6 +19,7 @@
 
 pub mod utils;
 pub mod base;
+pub mod toolkit;
 
 pub use self::utils::exempi::{
     NsDef,
@@ -31,6 +32,9 @@ pub use self::base::fractions::{
     fraction_to_decimal
 };
 
+pub use self::toolkit::mimetype::{
+    MimeType
+};
 
 use std::f64;
 use std::ffi::CStr;
diff --git a/src/fwk/toolkit/mimetype.cpp b/src/fwk/toolkit/mimetype.cpp
index 84d1fe3..744492f 100644
--- a/src/fwk/toolkit/mimetype.cpp
+++ b/src/fwk/toolkit/mimetype.cpp
@@ -28,18 +28,23 @@
 
 namespace fwk {
 
+MimeType::MimeType(const char* filename)
+    : MimeType(std::string(filename))
+{
+}
+
 MimeType::MimeType(const std::string & filename)
     : m_name(filename)
 {
     try {
         Glib::RefPtr<Gio::File> file = Gio::File::create_for_path(filename);
-        m_fileinfo = file->query_info();
-        m_type = m_fileinfo->get_content_type();
+        auto fileinfo = file->query_info();
+        m_type = fileinfo->get_content_type();
     }
     catch(const Glib::Exception &e) {
         gboolean uncertainty = false;
         gchar *content_type = g_content_type_guess(filename.c_str(),
-                                                         nullptr, 0, &uncertainty);
+                                                   nullptr, 0, &uncertainty);
         m_type = content_type;
 
         g_free(content_type);
@@ -49,14 +54,14 @@ MimeType::MimeType(const std::string & filename)
 MimeType::MimeType(const Glib::RefPtr<Gio::File> & file)
 {
     DBG_ASSERT(static_cast<bool>(file), "file can't be NULL");
-    m_fileinfo = file->query_info();
-    m_name = m_fileinfo->get_name();
-               m_type = m_fileinfo->get_content_type();
+    auto fileinfo = file->query_info();
+    m_name = fileinfo->get_name();
+    m_type = fileinfo->get_content_type();
 }
 
 bool MimeType::isDigicamRaw() const
 {
-               return Gio::content_type_is_a(m_type, "image/x-dcraw");
+    return Gio::content_type_is_a(m_type, "image/x-dcraw");
 }
 
 
@@ -68,7 +73,7 @@ bool MimeType::isImage() const
 bool MimeType::isMovie() const
 {
     return Gio::content_type_is_a(m_type, "video/*");
-}      
+}
 
 bool MimeType::isUnknown() const
 {
@@ -80,7 +85,12 @@ bool MimeType::isXmp() const
 {
     return fwk::path_extension(m_name) == ".xmp";
 }
-       
+
+const std::string & MimeType::string() const
+{
+    return m_type;
+}
+
 }
 
 /*
diff --git a/src/fwk/toolkit/mimetype.hpp b/src/fwk/toolkit/mimetype.hpp
index 2eef9ca..6f815bf 100644
--- a/src/fwk/toolkit/mimetype.hpp
+++ b/src/fwk/toolkit/mimetype.hpp
@@ -24,26 +24,26 @@
 #include <string>
 
 #include <giomm/file.h>
-#include <giomm/fileinfo.h>
 
 namespace fwk {
 
 class MimeType
 {
 public:
+    MimeType(const char* filename);
     MimeType(const std::string & filename);
     MimeType(const Glib::RefPtr<Gio::File> & file);
-    
+
+    ~MimeType() {}
+
     bool isDigicamRaw() const;
     bool isImage() const;
     bool isMovie() const;
     bool isUnknown() const;
     bool isXmp() const;
-    
-    const std::string & string() const
-        { return m_type; }
+
+    const std::string& string() const;
 private:
-    Glib::RefPtr<Gio::FileInfo> m_fileinfo;
     std::string m_name;
     std::string m_type;
 };
diff --git a/src/fwk/toolkit/mimetype.rs b/src/fwk/toolkit/mimetype.rs
new file mode 100644
index 0000000..0399cda
--- /dev/null
+++ b/src/fwk/toolkit/mimetype.rs
@@ -0,0 +1,120 @@
+
+use gio;
+use glib_sys;
+use glib_sys::gboolean;
+use gio_sys;
+use gio::prelude::*;
+
+use libc::c_void;
+use std::ffi::CStr;
+use std::ffi::CString;
+use std::ptr;
+use std::path::Path;
+
+#[derive(PartialEq, Debug)]
+pub enum IsRaw {
+    No,
+    Yes
+}
+
+#[derive(PartialEq, Debug)]
+pub enum MType {
+    None,
+    Image(IsRaw),
+    Movie,
+    Xmp
+}
+
+pub struct MimeType {
+//    name: String,
+    mtype: MType,
+}
+
+fn guess_type(gmtype: &str) -> MType {
+    if gio::content_type_is_a(&gmtype, "image/*") {
+        if gio::content_type_is_a(&gmtype, "image/x-dcraw") {
+            return MType::Image(IsRaw::Yes);
+        }
+        return MType::Image(IsRaw::No);
+    } else if gio::content_type_is_a(&gmtype, "video/*") {
+        return MType::Movie;
+    }
+    MType::None
+}
+
+fn guess_type_for_file(filename: &str) -> MType {
+    let path = Path::new(filename);
+    let file = gio::File::new_for_path(path);
+    if let Ok(fileinfo) = file.query_info("*", gio::FILE_QUERY_INFO_NONE, None) {
+        if let Some(gmtype) = fileinfo.get_content_type() {
+            let t = guess_type_for_file(&gmtype);
+            if t != MType::None {
+                return t;
+            }
+        }
+    }
+    if let Some(ext) = path.extension() {
+        if let Some(sext) = ext.to_str() {
+            if sext == "xmp" {
+                return MType::Xmp;
+            }
+        }
+    }
+    // alternative
+    let mut uncertainty: gboolean = 0;
+    let content_type = unsafe {
+        gio_sys::g_content_type_guess(CString::new(filename).unwrap().as_ptr(),
+                                      ptr::null_mut(), 0, &mut uncertainty)
+    };
+    let content_type_real = unsafe { CStr::from_ptr(content_type) };
+    let t = guess_type(&*content_type_real.to_string_lossy());
+    unsafe {
+        glib_sys::g_free(content_type as *mut c_void)
+    };
+
+    t
+}
+
+impl MimeType {
+
+    pub fn new(filename: &str) -> MimeType {
+        MimeType {
+//            name: String::from(filename),
+            mtype: guess_type_for_file(filename),
+        }
+    }
+
+    pub fn is_image(&self) -> bool {
+        if let MType::Image(_) = self.mtype {
+            true
+        } else {
+            false
+        }
+    }
+
+    pub fn is_digicam_raw(&self) -> bool {
+        if let MType::Image(ref b) = self.mtype {
+            return *b == IsRaw::Yes;
+        }
+        false
+    }
+
+    pub fn is_xmp(&self) -> bool {
+        self.mtype == MType::Xmp
+    }
+
+    pub fn is_movie(&self) -> bool {
+        self.mtype == MType::Movie
+    }
+}
+
+
+#[cfg(test)]
+#[test]
+fn mime_type_works() {
+
+    let mimetype = MimeType::new("/foo/bar/img_0001.cr2");
+    assert_eq!(guess_type_for_file("/foo/bar/img_0001.cr2"), MType::Image(IsRaw::Yes));
+    assert!(mimetype.is_image());
+    assert!(mimetype.is_digicam_raw());
+}
diff --git a/src/fwk/toolkit/mod.rs b/src/fwk/toolkit/mod.rs
new file mode 100644
index 0000000..75a93b8
--- /dev/null
+++ b/src/fwk/toolkit/mod.rs
@@ -0,0 +1,2 @@
+
+pub mod mimetype;
diff --git a/src/lib.rs b/src/lib.rs
index f511f12..f213538 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -19,6 +19,9 @@
 
 extern crate exempi;
 extern crate libc;
+extern crate glib_sys;
+extern crate gio_sys;
+extern crate gio;
 
 pub mod fwk;
 pub mod engine;
diff --git a/src/libraryclient/Makefile.am b/src/libraryclient/Makefile.am
index 0b01907..44d23a6 100644
--- a/src/libraryclient/Makefile.am
+++ b/src/libraryclient/Makefile.am
@@ -12,7 +12,7 @@ TEST_LIBS =  \
         $(top_builddir)/src/fwk/utils/libniepceutils.a \
        $(top_builddir)/src/fwk/toolkit/libniepceframework.a \
        $(top_builddir)/src/fwk/base/libfwkbase.a \
-       $(top_builddir)/target/debug/libniece_rust.a \
+       $(top_builddir)/target/debug/libniepce_rust.a \
         @BOOST_UNIT_TEST_FRAMEWORK_LIBS@ \
        @FRAMEWORK_LIBS@ \
        @OPENRAW_LIBS@ \
diff --git a/src/niepce/Makefile.am b/src/niepce/Makefile.am
index b9cebaf..21db85b 100644
--- a/src/niepce/Makefile.am
+++ b/src/niepce/Makefile.am
@@ -21,7 +21,7 @@ niepce_LDADD = \
        $(top_builddir)/src/fwk/base/libfwkbase.a \
        $(top_builddir)/src/ncr/libncr.a \
        $(top_builddir)/src/ext/libview/libview.a \
-       $(top_builddir)/target/debug/libniece_rust.a \
+       $(top_builddir)/target/debug/libniepce_rust.a \
        @FRAMEWORK_LIBS@ \
        @GPHOTO_LIBS@ \
        @BABL_LIBS@ \


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