[vlc-devel] [PATCH 3/8] gui/skins2: add ThemeLoader::unarchive

Filip Roséen filip at atch.se
Thu Jan 12 19:21:18 CET 2017


---

This implementation could be written in a cleaner manner, but it
requires changes to the core. I will submit an independent patch for a
refactor of this function at a later time (when some upcoming (soon to
be proposed) minor changes to the core have been discussed).

---
 modules/gui/skins2/src/theme_loader.cpp | 107 ++++++++++++++++++++++++++++++++
 modules/gui/skins2/src/theme_loader.hpp |   2 +
 2 files changed, 109 insertions(+)

diff --git a/modules/gui/skins2/src/theme_loader.cpp b/modules/gui/skins2/src/theme_loader.cpp
index 31f1c550df..fb0811d4b4 100644
--- a/modules/gui/skins2/src/theme_loader.cpp
+++ b/modules/gui/skins2/src/theme_loader.cpp
@@ -29,9 +29,13 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <fstream>
+#include <memory>
 
 #include <vlc_common.h>
 #include <vlc_fs.h>
+#include <vlc_url.h>
+#include <vlc_stream_extractor.h>
 
 #include "theme_loader.hpp"
 #include "theme.hpp"
@@ -351,6 +355,109 @@ bool ThemeLoader::extract( const std::string &fileName )
     return result;
 }
 
+bool ThemeLoader::unarchive( const std::string& fileName, const std::string &tempPath )
+{
+#define UPTR_HELPER(type,deleter) []( type * data ) { \
+        return std::unique_ptr< type, decltype( deleter )> ( data, deleter ); }
+
+    auto make_input_node_ptr = UPTR_HELPER( input_item_node_t, &input_item_node_Delete );
+    auto make_input_item_ptr = UPTR_HELPER( input_item_t, &input_item_Release );
+    auto make_stream_ptr = UPTR_HELPER( stream_t, &vlc_stream_Delete );
+    auto make_cstr_ptr = UPTR_HELPER( char, &std::free );
+
+#undef UPTR_HELPER
+
+    auto uri = make_cstr_ptr( vlc_path2uri( fileName.c_str(), "file" ) );
+    if( !uri )
+    {
+        msg_Err( getIntf(), "unable to convert %s to local URI",
+                            fileName.c_str() );
+        return false;
+    }
+
+    auto input = make_stream_ptr( vlc_stream_NewURL( getIntf(), uri.get() ) );
+    if( !input )
+    {
+        msg_Err( getIntf(), "unable to open %s", uri.get() );
+        return false;
+    }
+
+    stream_t* stream = input.get();
+    if( vlc_stream_extractor_Attach( &stream, NULL, NULL ) )
+    {
+        msg_Err( getIntf(), "unable to attach extractor, treat as XML!" );
+    }
+    else
+    {
+        input.release();
+        input.reset( stream );
+
+        auto item = make_input_item_ptr( input_item_New( "vlc://dummy", "vlc://dummy" ) );
+        auto node = make_input_node_ptr( (input_item_node_t*)std::calloc( 1, sizeof( input_item_node_t ) ) );
+
+        if( !item || !node )
+            return false;
+
+        node->p_item = item.release();
+
+        if( vlc_stream_ReadDir( input.get(), node.get() ) )
+        {
+            msg_Err( getIntf(), "unable to read items in %s", uri.get() );
+            return false;
+        }
+
+        for( int i = 0; i < node->i_children; ++i )
+        {
+            auto child = node->pp_children[i]->p_item;
+            auto child_stream = make_stream_ptr( vlc_stream_NewURL( getIntf(), uri.get() ) );
+            if( !child_stream )
+            {
+                msg_Err( getIntf(), "unable to open %s for reading", child->psz_name );
+            }
+
+            stream_t* stream = child_stream.get();
+            if( vlc_stream_extractor_Attach( &stream, child->psz_name, NULL ) )
+            {
+                msg_Err( getIntf(), "unable to locate %s within %s",
+                         child->psz_name, fileName.c_str() );
+
+                return false;
+            }
+
+            child_stream.release();
+            child_stream.reset( stream );
+
+            auto out_path = tempPath + "/" + child->psz_name;
+
+            { /* create directory tree */
+                auto out_directory = out_path.substr( 0, out_path.find_last_of( '/' ) );
+
+                if( makedir( out_directory.c_str() ) == false )
+                {
+                    msg_Err( getIntf(), "failed to create directory tree for %s (%s)",
+                             out_path.c_str(), out_directory.c_str() );
+
+                    return false;
+                }
+            }
+
+            { /* write data to disk */
+                std::ofstream out_stream( out_path, std::ios::binary );
+
+                char buf[1024];
+                ssize_t n;
+
+                while( ( n = vlc_stream_Read( child_stream.get(), buf, sizeof buf ) ) > 0 )
+                    out_stream.write( buf, n );
+
+                msg_Dbg( getIntf(), "finished writing %zu bytes to %s",
+                    size_t{ out_stream.tellp() }, out_path.c_str() );
+            }
+        }
+    }
+
+    return true;
+}
 
 void ThemeLoader::deleteTempFiles( const std::string &path )
 {
diff --git a/modules/gui/skins2/src/theme_loader.hpp b/modules/gui/skins2/src/theme_loader.hpp
index b922cd367f..e5b35b150f 100644
--- a/modules/gui/skins2/src/theme_loader.hpp
+++ b/modules/gui/skins2/src/theme_loader.hpp
@@ -48,6 +48,8 @@ private:
      */
     bool extract( const std::string &fileName );
 
+    bool unarchive( const std::string &fileName, const std::string &tempPath );
+
     /// Extract files from a tar.gz archive
     /**
      * Expects strings from the current locale.
-- 
2.11.0



More information about the vlc-devel mailing list