[vlc-devel] [PATCH 2/2] playlist: export: allow export to memory

Francois Cartegnie fcvlcdev at free.fr
Thu Jul 24 17:24:44 CEST 2014


---
 include/vlc_playlist.h         |   4 ++
 modules/misc/Modules.am        |   1 +
 modules/misc/playlist/export.c |  50 ++++++++++++++++++-
 modules/misc/playlist/export.h |  34 +++++++++++++
 modules/misc/playlist/html.c   |  41 ++++++++-------
 modules/misc/playlist/m3u.c    |  55 ++++++++++++--------
 modules/misc/playlist/xspf.c   | 111 +++++++++++++++++++++++------------------
 src/libvlccore.sym             |   1 +
 src/playlist/loadsave.c        |  70 ++++++++++++++++++++------
 9 files changed, 263 insertions(+), 104 deletions(-)
 create mode 100644 modules/misc/playlist/export.h

diff --git a/include/vlc_playlist.h b/include/vlc_playlist.h
index 49dcd15..0c2a62b 100644
--- a/include/vlc_playlist.h
+++ b/include/vlc_playlist.h
@@ -128,6 +128,9 @@ typedef struct playlist_export_t
     VLC_COMMON_MEMBERS
     const char *psz_filename;
     FILE *p_file;
+    uint8_t *p_buffer;
+    size_t i_buffer_length;
+    size_t i_buffer;
     playlist_item_t *p_root;
 } playlist_export_t;
 
@@ -308,6 +311,7 @@ VLC_API int playlist_Status( playlist_t * );
  * \return VLC_SUCCESS on success
  */
 VLC_API int playlist_Export( playlist_t *p_playlist, const char *psz_name, playlist_item_t *p_export_root, const char *psz_type );
+VLC_API int playlist_ExportMemory( playlist_t *p_playlist, uint8_t **p_buffer, playlist_item_t *p_export_root, const char *psz_type );
 
 /**
  * Open a playlist file, add its content to the current playlist
diff --git a/modules/misc/Modules.am b/modules/misc/Modules.am
index 62a54d1..ce0bfef 100644
--- a/modules/misc/Modules.am
+++ b/modules/misc/Modules.am
@@ -10,6 +10,7 @@ libexport_plugin_la_SOURCES = \
 	playlist/html.c \
 	playlist/m3u.c \
 	playlist/xspf.c \
+	playlist/export.h \
 	playlist/export.c
 misc_LTLIBRARIES += libexport_plugin.la
 
diff --git a/modules/misc/playlist/export.c b/modules/misc/playlist/export.c
index a42ef39..fbf2acf 100644
--- a/modules/misc/playlist/export.c
+++ b/modules/misc/playlist/export.c
@@ -28,8 +28,9 @@
 # include "config.h"
 #endif
 
-#include <vlc_common.h>
+#include "export.h"
 #include <vlc_plugin.h>
+#include <vlc_charset.h>
 
 /***************************************************************************
  * Prototypes
@@ -71,3 +72,50 @@ vlc_module_begin ()
         set_callbacks( Export_HTML, NULL )
 
 vlc_module_end ()
+
+/*****************************************************************************
+ * Definitions
+ *****************************************************************************/
+void export_write_to_memory( playlist_export_t *p_export, const char *psz_format, ... )
+{
+    va_list args;
+    va_start( args, psz_format );
+    char *psz_buffer;
+    int i_ret = vasprintf( &psz_buffer, psz_format, args );
+    va_end( args );
+
+    if (i_ret > 0)
+    {
+        if ( p_export->i_buffer + i_ret + 1 > p_export->i_buffer_length )
+        {
+            size_t i_newsize = __MAX( p_export->i_buffer_length * 2, p_export->i_buffer_length + i_ret + 1 );
+            char *psz_newbuf = realloc( p_export->p_buffer, i_newsize );
+            if (psz_newbuf)
+            {
+                p_export->p_buffer = (uint8_t *) psz_newbuf;
+                p_export->i_buffer_length = i_newsize;
+            }
+        }
+
+        if ( p_export->i_buffer + i_ret + 1 <= p_export->i_buffer_length ) /* realloc can fail */
+            strncpy( (char *)p_export->p_buffer + p_export->i_buffer, psz_buffer, i_ret );
+        p_export->i_buffer += i_ret;
+        free(psz_buffer);
+    }
+}
+
+void export_write_to_file( playlist_export_t *p_export, const char *psz_format, ... )
+{
+    va_list args;
+    va_start( args, psz_format );
+    vfprintf( p_export->p_file, psz_format, args );
+    va_end( args );
+}
+
+void export_write_to_file_utf8( playlist_export_t *p_export, const char *psz_format, ... )
+{
+    va_list args;
+    va_start( args, psz_format );
+    utf8_vfprintf( p_export->p_file, psz_format, args );
+    va_end( args );
+}
diff --git a/modules/misc/playlist/export.h b/modules/misc/playlist/export.h
new file mode 100644
index 0000000..67e9a40
--- /dev/null
+++ b/modules/misc/playlist/export.h
@@ -0,0 +1,34 @@
+/*****************************************************************************
+ * export.h :  Playlist export module
+ *****************************************************************************
+ * Copyright (C) 2014 the VideoLAN team
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <vlc_common.h>
+#include <vlc_playlist.h>
+
+/***************************************************************************
+ * Prototypes
+ ***************************************************************************/
+typedef void(*export_writer_t)(playlist_export_t *, const char *, ...);
+
+void export_write_to_memory( playlist_export_t *p_export, const char *psz_format, ... );
+void export_write_to_file( playlist_export_t *p_export, const char *psz_format, ... );
+void export_write_to_file_utf8( playlist_export_t *p_export, const char *psz_format, ... );
diff --git a/modules/misc/playlist/html.c b/modules/misc/playlist/html.c
index 8c9d00c..1e7085f 100644
--- a/modules/misc/playlist/html.c
+++ b/modules/misc/playlist/html.c
@@ -25,8 +25,8 @@
 # include "config.h"
 #endif
 
-#include <vlc_common.h>
-#include <vlc_playlist.h>
+#include "export.h"
+
 #include <vlc_input.h>
 #include <vlc_strings.h>
 
@@ -42,7 +42,8 @@ int Export_HTML( vlc_object_t *p_this );
  * @param p_export: the export structure
  * @param p_root: the current node
  */
-static void DoChildren( playlist_export_t *p_export, playlist_item_t *p_root )
+static void DoChildren( playlist_export_t *p_export, export_writer_t pf_writer,
+                        playlist_item_t *p_root )
 {
     /* Go through the playlist and add items */
     for( int i = 0; i < p_root->i_children ; i++)
@@ -55,7 +56,7 @@ static void DoChildren( playlist_export_t *p_export, playlist_item_t *p_root )
 
         if( p_current->i_children >= 0 )
         {
-            DoChildren( p_export, p_current );
+            DoChildren( p_export, pf_writer, p_current );
             continue;
         }
 
@@ -79,9 +80,9 @@ static void DoChildren( playlist_export_t *p_export, playlist_item_t *p_root )
 
             // Print the artist if we have one
             if( psz_artist && *psz_artist )
-                fprintf( p_export->p_file, "    <li>%s - %s (%02d:%02d)</li>\n", psz_artist, psz_name, min, sec );
+                pf_writer( p_export, "    <li>%s - %s (%02d:%02d)</li>\n", psz_artist, psz_name, min, sec );
             else
-                fprintf( p_export->p_file, "    <li>%s (%2d:%2d)</li>\n", psz_name, min, sec );
+                pf_writer( p_export, "    <li>%s (%2d:%2d)</li>\n", psz_name, min, sec );
 
             free( psz_artist );
         }
@@ -89,20 +90,12 @@ static void DoChildren( playlist_export_t *p_export, playlist_item_t *p_root )
     }
 }
 
-
-/**
- * Export the playlist as an HTML page
- * @param p_this: the playlist
- * @return VLC_SUCCESS if everything goes fine
- */
-int Export_HTML( vlc_object_t *p_this )
+static int Export_HTML_internal( playlist_export_t *p_export, export_writer_t pf_writer )
 {
-    playlist_export_t *p_export = (playlist_export_t *)p_this;
-
     msg_Dbg( p_export, "saving using HTML format" );
 
     /* Write header */
-    fprintf( p_export->p_file, "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
+    pf_writer( p_export, "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
 "<head>\n"
@@ -131,13 +124,25 @@ int Export_HTML( vlc_object_t *p_this )
 "  <ol>\n" );
 
     // Call the playlist constructor
-    DoChildren( p_export, p_export->p_root );
+    DoChildren( p_export, pf_writer, p_export->p_root );
 
     // Print the footer
-    fprintf( p_export->p_file, "  </ol>\n"
+    pf_writer( p_export, "  </ol>\n"
 "  <hr />\n"
 "</body>\n"
 "</html>" );
     return VLC_SUCCESS;
 }
 
+/**
+ * Export the playlist as an HTML page
+ * @param p_this: the playlist
+ * @return VLC_SUCCESS if everything goes fine
+ */
+int Export_HTML( vlc_object_t *p_this )
+{
+    playlist_export_t *p_export = (playlist_export_t *)p_this;
+    export_writer_t pf_writer = (p_export->p_file)? export_write_to_file
+                                                  : export_write_to_memory;
+    return Export_HTML_internal( p_export, pf_writer );
+}
diff --git a/modules/misc/playlist/m3u.c b/modules/misc/playlist/m3u.c
index 72e9581..35b2555 100644
--- a/modules/misc/playlist/m3u.c
+++ b/modules/misc/playlist/m3u.c
@@ -29,8 +29,8 @@
 # include "config.h"
 #endif
 
-#include <vlc_common.h>
-#include <vlc_playlist.h>
+#include "export.h"
+
 #include <vlc_input.h>
 #include <vlc_meta.h>
 #include <vlc_charset.h>
@@ -47,11 +47,11 @@ int Export_M3U8( vlc_object_t * );
 /*****************************************************************************
  * Export_M3U: main export function
  *****************************************************************************/
-static void DoChildren( playlist_export_t *p_export, playlist_item_t *p_root,
-                        int (*pf_fprintf) (FILE *, const char *, ...) )
+static void DoChildren( playlist_export_t *p_export, export_writer_t pf_writer,
+                        playlist_item_t *p_root )
 {
     /* Write header */
-    fputs( "#EXTM3U\n", p_export->p_file );
+    pf_writer( p_export, "#EXTM3U\n" );
 
     /* Go through the playlist and add items */
     for( int i = 0; i< p_root->i_children ; i++)
@@ -64,7 +64,7 @@ static void DoChildren( playlist_export_t *p_export, playlist_item_t *p_root,
 
         if( p_current->i_children >= 0 )
         {
-            DoChildren( p_export, p_current, pf_fprintf );
+            DoChildren( p_export, pf_writer, p_current );
             continue;
         }
 
@@ -83,14 +83,14 @@ static void DoChildren( playlist_export_t *p_export, playlist_item_t *p_root,
             if( psz_artist && *psz_artist )
             {
                 /* write EXTINF with artist */
-                pf_fprintf( p_export->p_file, "#EXTINF:%"PRIu64",%s - %s\n",
-                            i_duration / CLOCK_FREQ, psz_artist, psz_name);
+                pf_writer( p_export, "#EXTINF:%"PRIu64",%s - %s\n",
+                           i_duration / CLOCK_FREQ, psz_artist, psz_name);
             }
             else
             {
                 /* write EXTINF without artist */
-                pf_fprintf( p_export->p_file, "#EXTINF:%"PRIu64",%s\n",
-                            i_duration / CLOCK_FREQ, psz_name);
+                pf_writer( p_export, "#EXTINF:%"PRIu64",%s\n",
+                           i_duration / CLOCK_FREQ, psz_name);
             }
             free( psz_artist );
         }
@@ -100,10 +100,10 @@ static void DoChildren( playlist_export_t *p_export, playlist_item_t *p_root,
         vlc_mutex_lock( &p_current->p_input->lock );
         for( int j = 0; j < p_current->p_input->i_options; j++ )
         {
-            pf_fprintf( p_export->p_file, "#EXTVLCOPT:%s\n",
-                        p_current->p_input->ppsz_options[j][0] == ':' ?
-                        p_current->p_input->ppsz_options[j] + 1 :
-                        p_current->p_input->ppsz_options[j] );
+            pf_writer( p_export, "#EXTVLCOPT:%s\n",
+                       p_current->p_input->ppsz_options[j][0] == ':' ?
+                       p_current->p_input->ppsz_options[j] + 1 :
+                       p_current->p_input->ppsz_options[j] );
         }
         vlc_mutex_unlock( &p_current->p_input->lock );
 
@@ -114,27 +114,40 @@ static void DoChildren( playlist_export_t *p_export, playlist_item_t *p_root,
             free( psz_uri );
             psz_uri = psz_path;
         }
-        fprintf( p_export->p_file, "%s\n", psz_uri );
+        pf_writer( p_export, "%s\n", psz_uri );
         free( psz_uri );
     }
 }
 
-int Export_M3U( vlc_object_t *p_this )
+static int Export_M3U_internal( playlist_export_t *p_export, export_writer_t pf_writer )
 {
-    playlist_export_t *p_export = (playlist_export_t *)p_this;
-
     msg_Dbg( p_export, "saving using M3U format");
 
-    DoChildren( p_export, p_export->p_root, utf8_fprintf );
+    DoChildren( p_export, pf_writer, p_export->p_root );
     return VLC_SUCCESS;
 }
 
-int Export_M3U8( vlc_object_t *p_this )
+int Export_M3U( vlc_object_t *p_this )
 {
     playlist_export_t *p_export = (playlist_export_t *)p_this;
+    /* FIXME: win32 encoding with memory output */
+    export_writer_t pf_writer = (p_export->p_file)? export_write_to_file_utf8
+                                                  : export_write_to_memory;
+    return Export_M3U_internal( p_export, pf_writer );
+}
 
+static int Export_M3U8_internal( playlist_export_t *p_export, export_writer_t pf_writer )
+{
     msg_Dbg( p_export, "saving using M3U8 format");
 
-    DoChildren( p_export, p_export->p_root, fprintf );
+    DoChildren( p_export, pf_writer, p_export->p_root );
     return VLC_SUCCESS;
 }
+
+int Export_M3U8( vlc_object_t *p_this )
+{
+    playlist_export_t *p_export = (playlist_export_t *)p_this;
+    export_writer_t pf_writer = (p_export->p_file)? export_write_to_file
+                                                  : export_write_to_memory;
+    return Export_M3U8_internal( p_export, pf_writer );
+}
diff --git a/modules/misc/playlist/xspf.c b/modules/misc/playlist/xspf.c
index e41cd25..cf5a1c7 100644
--- a/modules/misc/playlist/xspf.c
+++ b/modules/misc/playlist/xspf.c
@@ -30,8 +30,8 @@
 # include "config.h"
 #endif
 
-#include <vlc_common.h>
-#include <vlc_playlist.h>
+#include "export.h"
+
 #include <vlc_input.h>
 #include <vlc_strings.h>
 #include <vlc_url.h>
@@ -51,13 +51,14 @@ static char *input_xml( input_item_t *p_item, char *(*func)(input_item_t *) )
 }
 
 /**
- * \brief exports one item to file or traverse if item is a node
+ * \brief exports one item using writer function or traverse if item is a node
+ * \param p_export playlist export structure
+ * \param pf_writer pointer to export_writer function
  * \param p_item playlist item to export
- * \param p_file file to write xml-converted item to
  * \param p_i_count counter for track identifiers
  */
-static void xspf_export_item( playlist_item_t *p_item, FILE *p_file,
-                              int *p_i_count )
+static void xspf_export_item( playlist_export_t *p_export, export_writer_t pf_writer,
+                              playlist_item_t *p_item, int *p_i_count )
 {
     if( !p_item ) return;
 
@@ -65,7 +66,7 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file,
     if( p_item->i_children > 0 )
     {
         for( int i = 0; i < p_item->i_children; i++ )
-            xspf_export_item( p_item->pp_children[i], p_file, p_i_count );
+            xspf_export_item( p_export, pf_writer, p_item->pp_children[i], p_i_count );
         return;
     }
 
@@ -78,18 +79,18 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file,
     mtime_t i_duration;
 
     /* leaves can be written directly */
-    fputs( "\t\t<track>\n", p_file );
+    pf_writer( p_export, "\t\t<track>\n" );
 
     /* -> the location */
 
     char *psz_uri = input_xml( p_input, input_item_GetURI );
     if( psz_uri && *psz_uri )
-        fprintf( p_file, "\t\t\t<location>%s</location>\n", psz_uri );
+        pf_writer( p_export, "\t\t\t<location>%s</location>\n", psz_uri );
 
     /* -> the name/title (only if different from uri)*/
     psz = input_xml( p_input, input_item_GetTitle );
     if( psz && strcmp( psz_uri, psz ) )
-        fprintf( p_file, "\t\t\t<title>%s</title>\n", psz );
+        pf_writer( p_export, "\t\t\t<title>%s</title>\n", psz );
     free( psz );
     free( psz_uri );
 
@@ -101,13 +102,13 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file,
     /* -> the artist/creator */
     psz = input_xml( p_input, input_item_GetArtist );
     if( psz && *psz )
-        fprintf( p_file, "\t\t\t<creator>%s</creator>\n", psz );
+        pf_writer( p_export, "\t\t\t<creator>%s</creator>\n", psz );
     free( psz );
 
     /* -> the album */
     psz = input_xml( p_input, input_item_GetAlbum );
     if( psz && *psz )
-        fprintf( p_file, "\t\t\t<album>%s</album>\n", psz );
+        pf_writer( p_export, "\t\t\t<album>%s</album>\n", psz );
     free( psz );
 
     /* -> the track number */
@@ -118,39 +119,39 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file,
 
         free( psz );
         if( i_tracknum > 0 )
-            fprintf( p_file, "\t\t\t<trackNum>%i</trackNum>\n", i_tracknum );
+            pf_writer( p_export, "\t\t\t<trackNum>%i</trackNum>\n", i_tracknum );
     }
 
     /* -> the description */
     psz = input_xml( p_input, input_item_GetDescription );
     if( psz && *psz )
-        fprintf( p_file, "\t\t\t<annotation>%s</annotation>\n", psz );
+        pf_writer( p_export, "\t\t\t<annotation>%s</annotation>\n", psz );
     free( psz );
 
     psz = input_xml( p_input, input_item_GetURL );
     if( psz && *psz )
-        fprintf( p_file, "\t\t\t<info>%s</info>\n", psz );
+        pf_writer( p_export, "\t\t\t<info>%s</info>\n", psz );
     free( psz );
 
     psz = input_xml( p_input, input_item_GetArtURL );
     if( psz && *psz )
-        fprintf( p_file, "\t\t\t<image>%s</image>\n", psz );
+        pf_writer( p_export, "\t\t\t<image>%s</image>\n", psz );
     free( psz );
 
 xspfexportitem_end:
     /* -> the duration */
     i_duration = input_item_GetDuration( p_item->p_input );
     if( i_duration > 0 )
-        fprintf( p_file, "\t\t\t<duration>%"PRIu64"</duration>\n",
+        pf_writer( p_export, "\t\t\t<duration>%"PRIu64"</duration>\n",
                  i_duration / 1000 );
 
     /* export the intenal id and the input's options (bookmarks, ...)
      * in <extension> */
-    fputs( "\t\t\t<extension application=\""
-           "http://www.videolan.org/vlc/playlist/0\">\n", p_file );
+    pf_writer( p_export, "\t\t\t<extension application=\""
+               "http://www.videolan.org/vlc/playlist/0\">\n" );
 
     /* print the id and increase the counter */
-    fprintf( p_file, "\t\t\t\t<vlc:id>%i</vlc:id>\n", *p_i_count );
+    pf_writer( p_export, "\t\t\t\t<vlc:id>%i</vlc:id>\n", *p_i_count );
     ( *p_i_count )++;
 
     for( int i = 0; i < p_item->p_input->i_options; i++ )
@@ -165,21 +166,22 @@ xspfexportitem_end:
         if ( psz_ret == NULL )
             continue;
 
-        fprintf( p_file, "\t\t\t\t<vlc:option>%s</vlc:option>\n", psz_ret );
+        pf_writer( p_export, "\t\t\t\t<vlc:option>%s</vlc:option>\n", psz_ret );
         free( psz_ret );
     }
-    fputs( "\t\t\t</extension>\n", p_file );
-    fputs( "\t\t</track>\n", p_file );
+    pf_writer( p_export, "\t\t\t</extension>\n" );
+    pf_writer( p_export, "\t\t</track>\n" );
 }
 
 /**
- * \brief exports one item in extension to file and traverse if item is a node
+ * \brief exports one item in extension using writer funciton and traverse if item is a node
+ * \param p_export playlist export structure
+ * \param pf_writer pointer to export_writer function
  * \param p_item playlist item to export
- * \param p_file file to write xml-converted item to
  * \param p_i_count counter for track identifiers
  */
-static void xspf_extension_item( playlist_item_t *p_item, FILE *p_file,
-                                 int *p_i_count )
+static void xspf_extension_item( playlist_export_t *p_export, export_writer_t pf_writer,
+                                 playlist_item_t *p_item, int *p_i_count )
 {
     if( !p_item ) return;
 
@@ -190,43 +192,42 @@ static void xspf_extension_item( playlist_item_t *p_item, FILE *p_file,
         char *psz_temp = NULL;
         if( p_item->p_input->psz_name )
             psz_temp = convert_xml_special_chars( p_item->p_input->psz_name );
-        fprintf( p_file, "\t\t<vlc:node title=\"%s\">\n",
-                 psz_temp ? psz_temp : "" );
+        pf_writer( p_export, "\t\t<vlc:node title=\"%s\">\n",
+                   psz_temp ? psz_temp : "" );
         free( psz_temp );
 
         for( i = 0; i < p_item->i_children; i++ )
         {
-            xspf_extension_item( p_item->pp_children[i], p_file, p_i_count );
+            xspf_extension_item( p_export, pf_writer, p_item->pp_children[i], p_i_count );
         }
 
-        fprintf( p_file, "\t\t</vlc:node>\n" );
+        pf_writer( p_export, "\t\t</vlc:node>\n" );
         return;
     }
 
 
     /* print leaf and increase the counter */
-    fprintf( p_file, "\t\t\t<vlc:item tid=\"%i\"/>\n", *p_i_count );
+    pf_writer( p_export, "\t\t\t<vlc:item tid=\"%i\"/>\n", *p_i_count );
     ( *p_i_count )++;
 
     return;
 }
 
 /**
- * \brief Prints the XSPF header to file, writes each item by xspf_export_item()
- * and closes the open xml elements
- * \param p_this the VLC playlist object
- * \return VLC_SUCCESS if some memory is available, otherwise VLC_ENONMEM
+ * \brief exports playlist using writer function and traverse if item is a node
+ * \param p_export playlist export structure
+ * \param pf_writer pointer to export_writer function
+ * \return VLC_SUCCESS on success
  */
-int xspf_export_playlist( vlc_object_t *p_this )
+static int xspf_export_playlist_internal( playlist_export_t *p_export, export_writer_t pf_writer )
 {
-    const playlist_export_t *p_export = (playlist_export_t *)p_this;
     int               i, i_count;
     char             *psz_temp;
     playlist_item_t  *p_node = p_export->p_root;
 
     /* write XSPF XML header */
-    fprintf( p_export->p_file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
-    fprintf( p_export->p_file,
+    pf_writer( p_export, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
+    pf_writer( p_export,
              "<playlist xmlns=\"http://xspf.org/ns/0/\" " \
               "xmlns:vlc=\"http://www.videolan.org/vlc/playlist/ns/0/\" " \
               "version=\"1\">\n" );
@@ -237,33 +238,47 @@ int xspf_export_playlist( vlc_object_t *p_this )
     psz_temp = convert_xml_special_chars( p_node->p_input->psz_name );
     if( *psz_temp )
     {
-        fprintf(  p_export->p_file, "\t<title>%s</title>\n", psz_temp );
+        pf_writer( p_export, "\t<title>%s</title>\n", psz_temp );
     }
     free( psz_temp );
 
     /* export all items in a flat format */
-    fprintf( p_export->p_file, "\t<trackList>\n" );
+    pf_writer( p_export, "\t<trackList>\n" );
     i_count = 0;
     for( i = 0; i < p_node->i_children; i++ )
     {
-        xspf_export_item( p_node->pp_children[i], p_export->p_file,
+        xspf_export_item( p_export, pf_writer, p_node->pp_children[i],
                           &i_count );
     }
-    fprintf( p_export->p_file, "\t</trackList>\n" );
+    pf_writer( p_export, "\t</trackList>\n" );
 
     /* export the tree structure in <extension> */
-    fprintf( p_export->p_file, "\t<extension application=\"" \
+    pf_writer( p_export, "\t<extension application=\"" \
              "http://www.videolan.org/vlc/playlist/0\">\n" );
     i_count = 0;
     for( i = 0; i < p_node->i_children; i++ )
     {
-        xspf_extension_item( p_node->pp_children[i], p_export->p_file,
+        xspf_extension_item( p_export, pf_writer, p_node->pp_children[i],
                              &i_count );
     }
-    fprintf( p_export->p_file, "\t</extension>\n" );
+    pf_writer( p_export, "\t</extension>\n" );
 
     /* close the header elements */
-    fprintf( p_export->p_file, "</playlist>\n" );
+    pf_writer( p_export, "</playlist>\n" );
 
     return VLC_SUCCESS;
 }
+
+/**
+ * \brief Prints the XSPF header to file, writes each item by xspf_export_item()
+ * and closes the open xml elements
+ * \param p_this the VLC playlist object
+ * \return VLC_SUCCESS if some memory is available, otherwise VLC_ENONMEM
+ */
+int xspf_export_playlist( vlc_object_t *p_this )
+{
+    playlist_export_t *p_export = (playlist_export_t *)p_this;
+    export_writer_t pf_writer = (p_export->p_file)? export_write_to_file
+                                                  : export_write_to_memory;
+    return xspf_export_playlist_internal( p_export, pf_writer );
+}
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 325c8f6..23bbf02 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -323,6 +323,7 @@ playlist_CurrentPlayingItem
 playlist_Deactivate
 playlist_DeleteFromInput
 playlist_Export
+playlist_ExportMemory
 playlist_GetNextLeaf
 playlist_GetPrevLeaf
 playlist_GetNodeDuration
diff --git a/src/playlist/loadsave.c b/src/playlist/loadsave.c
index 605059f..25001d5 100644
--- a/src/playlist/loadsave.c
+++ b/src/playlist/loadsave.c
@@ -38,30 +38,44 @@
 #include <vlc_url.h>
 #include <vlc_modules.h>
 
-int playlist_Export( playlist_t * p_playlist, const char *psz_filename,
-                     playlist_item_t *p_export_root, const char *psz_type )
+static int playlist_Export_Internal( playlist_t * p_playlist, const char *psz_filename,
+                                     uint8_t **pp_buffer, playlist_item_t *p_export_root,
+                                     const char *psz_type )
 {
-    if( p_export_root == NULL ) return VLC_EGENERIC;
+    if( p_export_root == NULL
+        || (psz_filename == NULL && pp_buffer == NULL)
+        || (psz_filename && pp_buffer) )
+        return VLC_EGENERIC;
 
     playlist_export_t *p_export =
         vlc_custom_create( p_playlist, sizeof( *p_export ), "playlist export" );
     if( unlikely(p_export == NULL) )
         return VLC_ENOMEM;
 
-    msg_Dbg( p_export, "saving %s to file %s",
-             p_export_root->p_input->psz_name, psz_filename );
+    if ( psz_filename )
+        msg_Dbg( p_export, "saving %s to file %s",
+                 p_export_root->p_input->psz_name, psz_filename );
+    else
+        msg_Dbg( p_export, "exporting %s to memory", p_export_root->p_input->psz_name );
 
     int ret = VLC_EGENERIC;
 
     /* Prepare the playlist_export_t structure */
     p_export->p_root = p_export_root;
     p_export->psz_filename = psz_filename;
-    p_export->p_file = vlc_fopen( psz_filename, "wt" );
-    if( p_export->p_file == NULL )
+    p_export->p_buffer = NULL;
+    p_export->i_buffer_length = 0;
+    p_export->i_buffer = 0;
+    p_export->p_file = NULL;
+    if (psz_filename)
     {
-        msg_Err( p_export, "could not create playlist file %s: %s",
-                 psz_filename, vlc_strerror_c(errno) );
-        goto out;
+        p_export->p_file = vlc_fopen( psz_filename, "wt" );
+        if( p_export->p_file == NULL )
+        {
+            msg_Err( p_export, "could not create playlist file %s: %s",
+                     psz_filename, vlc_strerror_c(errno) );
+            goto out;
+        }
     }
 
     module_t *p_module;
@@ -74,20 +88,44 @@ int playlist_Export( playlist_t * p_playlist, const char *psz_filename,
     if( p_module != NULL )
     {
         module_unneed( p_export, p_module );
-        if( !ferror( p_export->p_file ) )
-            ret = VLC_SUCCESS;
+        if ( p_export->p_file )
+        {
+            if( !ferror( p_export->p_file ) )
+                ret = VLC_SUCCESS;
+            else
+                msg_Err( p_playlist, "could not write playlist file: %s",
+                         vlc_strerror_c(errno) );
+        }
+        else if ( p_export->p_buffer == NULL )
+        {
+            msg_Err( p_playlist, "could not export playlist to memory" );
+        }
         else
-            msg_Err( p_playlist, "could not write playlist file: %s",
-                     vlc_strerror_c(errno) );
+            ret = VLC_SUCCESS;
     }
     else
-        msg_Err( p_playlist, "could not export playlist" );
-   fclose( p_export->p_file );
+        msg_Err( p_playlist, "could not export playlist (can't load module)" );
+
+    if ( p_export->p_file )
+        fclose( p_export->p_file );
+    else
+        *pp_buffer = p_export->p_buffer;
 out:
    vlc_object_release( p_export );
    return ret;
 }
 
+int playlist_ExportMemory( playlist_t *p_playlist, uint8_t **p_buffer, playlist_item_t *p_export_root, const char *psz_type )
+{
+    return playlist_Export_Internal( p_playlist, NULL, p_buffer, p_export_root, psz_type );
+}
+
+int playlist_Export( playlist_t * p_playlist, const char *psz_filename,
+                     playlist_item_t *p_export_root, const char *psz_type )
+{
+    return playlist_Export_Internal( p_playlist, psz_filename, NULL, p_export_root, psz_type );
+}
+
 int playlist_Import( playlist_t *p_playlist, const char *psz_file )
 {
     input_item_t *p_input;
-- 
1.9.3




More information about the vlc-devel mailing list