zipstream.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:26k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * zipstream.c: stream_filter that creates a XSPF playlist from a Zip archive
  3.  *****************************************************************************
  4.  * Copyright (C) 2009 the VideoLAN team
  5.  * $Id: 03a7dfdd023d1ee5013a7bd101f2e41e21692f1a $
  6.  *
  7.  * Authors: Jean-Philippe André <jpeg@videolan.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /** **************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include "zip.h"
  30. #include <stddef.h>
  31. /* FIXME remove */
  32. #include <vlc_input.h>
  33. #define FILENAME_TEXT N_( "Media in Zip" )
  34. #define FILENAME_LONGTEXT N_( "Path to the media in the Zip archive" )
  35. /** **************************************************************************
  36.  * Module descriptor
  37.  *****************************************************************************/
  38. vlc_module_begin()
  39.     set_shortname( "Zip" )
  40.     set_category( CAT_INPUT )
  41.     set_subcategory( SUBCAT_INPUT_STREAM_FILTER )
  42.     set_description( N_( "Zip files filter" ) )
  43.     set_capability( "stream_filter", 1 )
  44.     set_callbacks( StreamOpen, StreamClose )
  45.     add_submodule()
  46.         set_subcategory( SUBCAT_INPUT_ACCESS )
  47.         set_description( N_( "Zip access" ) )
  48.         set_capability( "access", 0 )
  49.         add_shortcut( "unzip" )
  50.         add_shortcut( "zip" )
  51.         set_callbacks( AccessOpen, AccessClose )
  52. vlc_module_end()
  53. /** *************************************************************************
  54.  * Local prototypes
  55.  ****************************************************************************/
  56. static int Read   ( stream_t *, void *p_read, unsigned int i_read );
  57. static int Peek   ( stream_t *, const uint8_t **pp_peek, unsigned int i_peek );
  58. static int Control( stream_t *, int i_query, va_list );
  59. typedef struct node node;
  60. typedef struct item item;
  61. static int CreatePlaylist( stream_t *s, char **pp_buffer );
  62. static int GetFilesInZip( stream_t*, unzFile, vlc_array_t*, vlc_array_t* );
  63. static node* findOrCreateParentNode( node *root, const char *fullpath );
  64. static int WriteXSPF( char **pp_buffer, vlc_array_t *p_filenames,
  65.                       const char *psz_zippath );
  66. static int nodeToXSPF( char **pp_buffer, node *n, bool b_root );
  67. static node* findOrCreateParentNode( node *root, const char *fullpath );
  68. /** **************************************************************************
  69.  * Struct definitions
  70.  *****************************************************************************/
  71. struct stream_sys_t
  72. {
  73.     /* zlib / unzip members */
  74.     unzFile zipFile;
  75.     zlib_filefunc_def *fileFunctions;
  76.     char *psz_path;
  77.     /* xspf data */
  78.     char *psz_xspf;
  79.     size_t i_len;
  80.     size_t i_pos;
  81. };
  82. struct item {
  83.     int id;
  84.     item *next;
  85. };
  86. struct node {
  87.     char *name;
  88.     item *media;
  89.     node *child;
  90.     node *next;
  91. };
  92. /** **************************************************************************
  93.  * Some helpers
  94.  *****************************************************************************/
  95. inline static node* new_node( char *name )
  96. {
  97.     node *n = (node*) calloc( 1, sizeof(node) );
  98.     n->name = convert_xml_special_chars( name );
  99.     return n;
  100. }
  101. inline static item* new_item( int id )
  102. {
  103.     item *media = (item*) calloc( 1, sizeof(item) );
  104.     media->id = id;
  105.     return media;
  106. }
  107. inline static void free_all_node( node *root )
  108. {
  109.     while( root )
  110.     {
  111.         free_all_node( root->child );
  112.         free( root->name );
  113.         node *tmp = root->next;
  114.         free( root );
  115.         root = tmp;
  116.     }
  117. }
  118. /* Allocate strcat and format */
  119. static int astrcatf( char **ppsz_dest, const char *psz_fmt_src, ... )
  120. {
  121.     va_list args;
  122.     va_start( args, psz_fmt_src );
  123.     char *psz_tmp;
  124.     int i_ret = vasprintf( &psz_tmp, psz_fmt_src, args );
  125.     if( i_ret == -1 ) return -1;
  126.     va_end( args );
  127.     int i_len = strlen( *ppsz_dest ) + strlen( psz_tmp ) + 1;
  128.     char *psz_out = realloc( *ppsz_dest, i_len );
  129.     if( !psz_out ) return -1;
  130.     strcat( psz_out, psz_tmp );
  131.     free( psz_tmp );
  132.     *ppsz_dest = psz_out;
  133.     return i_len;
  134. }
  135. /** **************************************************************************
  136.  * Zip file identifier
  137.  *****************************************************************************/
  138. static const uint8_t p_zip_marker[] = { 0x50, 0x4b, 0x03, 0x04 }; // "PK^C^D"
  139. static const int i_zip_marker = 4;
  140. /** **************************************************************************
  141.  * Open
  142.  *****************************************************************************/
  143. int StreamOpen( vlc_object_t *p_this )
  144. {
  145.     stream_t *s = (stream_t*) p_this;
  146.     stream_sys_t *p_sys;
  147.     /* Verify file format */
  148.     const uint8_t *p_peek;
  149.     if( stream_Peek( s->p_source, &p_peek, i_zip_marker ) < i_zip_marker )
  150.         return VLC_EGENERIC;
  151.     if( memcmp( p_peek, p_zip_marker, i_zip_marker ) )
  152.         return VLC_EGENERIC;
  153.     s->p_sys = p_sys = calloc( 1, sizeof( *p_sys ) );
  154.     if( !p_sys )
  155.         return VLC_ENOMEM;
  156.     s->pf_read = Read;
  157.     s->pf_peek = Peek;
  158.     s->pf_control = Control;
  159.     p_sys->fileFunctions = ( zlib_filefunc_def * )
  160.             calloc( 1, sizeof( zlib_filefunc_def ) );
  161.     if( !p_sys->fileFunctions )
  162.     {
  163.         free( p_sys );
  164.         return VLC_ENOMEM;
  165.     }
  166.     p_sys->fileFunctions->zopen_file   = ZipIO_Open;
  167.     p_sys->fileFunctions->zread_file   = ZipIO_Read;
  168.     p_sys->fileFunctions->zwrite_file  = ZipIO_Write;
  169.     p_sys->fileFunctions->ztell_file   = ZipIO_Tell;
  170.     p_sys->fileFunctions->zseek_file   = ZipIO_Seek;
  171.     p_sys->fileFunctions->zclose_file  = ZipIO_Close;
  172.     p_sys->fileFunctions->zerror_file  = ZipIO_Error;
  173.     p_sys->fileFunctions->opaque       = ( void * ) s;
  174.     p_sys->zipFile = unzOpen2( NULL /* path */, p_sys->fileFunctions );
  175.     if( !p_sys->zipFile )
  176.     {
  177.         msg_Warn( s, "unable to open file" );
  178.         free( p_sys->fileFunctions );
  179.         free( p_sys );
  180.         return VLC_EGENERIC;
  181.     }
  182.     /* Find the stream uri */
  183.     char *psz_tmp;
  184.     if( asprintf( &psz_tmp, "%s.xspf", s->psz_path ) == -1 )
  185.     {
  186.         free( p_sys->fileFunctions );
  187.         free( p_sys );
  188.         return VLC_ENOMEM;
  189.     }
  190.     p_sys->psz_path = s->psz_path;
  191.     s->psz_path = psz_tmp;
  192.     return VLC_SUCCESS;
  193. }
  194. /** *************************************************************************
  195.  * Close
  196.  ****************************************************************************/
  197. void StreamClose( vlc_object_t *p_this )
  198. {
  199.     stream_t *s = (stream_t*)p_this;
  200.     stream_sys_t *p_sys = s->p_sys;
  201.     free( p_sys->fileFunctions );
  202.     free( p_sys->psz_xspf );
  203.     free( p_sys->psz_path );
  204.     free( p_sys );
  205. }
  206. /** *************************************************************************
  207.  * Stream filters functions
  208.  ****************************************************************************/
  209. /** *************************************************************************
  210.  * Read
  211.  ****************************************************************************/
  212. static int Read( stream_t *s, void *p_read, unsigned int i_read )
  213. {
  214.     stream_sys_t *p_sys = s->p_sys;
  215.     if( !p_read ) return 0;
  216.     /* Fill the buffer */
  217.     if( p_sys->psz_xspf == NULL )
  218.     {
  219.         int i_ret = CreatePlaylist( s, &p_sys->psz_xspf );
  220.         if( i_ret < 0 )
  221.             return -1;
  222.         p_sys->i_len = strlen( p_sys->psz_xspf );
  223.         p_sys->i_pos = 0;
  224.     }
  225.     /* Read the buffer */
  226.     int i_len = __MIN( i_read, p_sys->i_len - p_sys->i_pos );
  227.     memcpy( p_read, p_sys->psz_xspf + p_sys->i_pos, i_len );
  228.     p_sys->i_pos += i_len;
  229.     return i_len;
  230. }
  231. /** *************************************************************************
  232.  * Peek
  233.  ****************************************************************************/
  234. static int Peek( stream_t *s, const uint8_t **pp_peek, unsigned int i_peek )
  235. {
  236.     stream_sys_t *p_sys = s->p_sys;
  237.     /* Fill the buffer */
  238.     if( p_sys->psz_xspf == NULL )
  239.     {
  240.         int i_ret = CreatePlaylist( s, &p_sys->psz_xspf );
  241.         if( i_ret < 0 )
  242.             return -1;
  243.         p_sys->i_len = strlen( p_sys->psz_xspf );
  244.         p_sys->i_pos = 0;
  245.     }
  246.     /* Point to the buffer */
  247.     int i_len = __MIN( i_peek, p_sys->i_len - p_sys->i_pos );
  248.     *pp_peek = (uint8_t*) p_sys->psz_xspf + p_sys->i_pos;
  249.     return i_len;
  250. }
  251. /** *************************************************************************
  252.  * Control
  253.  ****************************************************************************/
  254. static int Control( stream_t *s, int i_query, va_list args )
  255. {
  256.     stream_sys_t *p_sys = s->p_sys;
  257.     switch( i_query )
  258.     {
  259.         case STREAM_SET_POSITION:
  260.         {
  261.             int64_t i_position = (int64_t)va_arg( args, int64_t );
  262.             if( i_position >= p_sys->i_len )
  263.                 return VLC_EGENERIC;
  264.             else
  265.             {
  266.                 p_sys->i_pos = (size_t) i_position;
  267.                 return VLC_SUCCESS;
  268.             }
  269.         }
  270.         case STREAM_GET_POSITION:
  271.         {
  272.             int64_t *pi_position = (int64_t*)va_arg( args, int64_t* );
  273.             *pi_position = p_sys->i_pos;
  274.             return VLC_SUCCESS;
  275.         }
  276.         case STREAM_GET_SIZE:
  277.         {
  278.             int64_t *pi_size = (int64_t*)va_arg( args, int64_t* );
  279.             *pi_size = (int64_t) p_sys->i_len;
  280.             return VLC_SUCCESS;
  281.         }
  282.         case STREAM_GET_CONTENT_TYPE:
  283.             return VLC_EGENERIC;
  284.         case STREAM_UPDATE_SIZE:
  285.         case STREAM_CONTROL_ACCESS:
  286.         case STREAM_CAN_SEEK:
  287.         case STREAM_CAN_FASTSEEK:
  288.         case STREAM_SET_RECORD_STATE:
  289.             return stream_vaControl( s->p_source, i_query, args );
  290.         default:
  291.             return VLC_EGENERIC;
  292.     }
  293. }
  294. static int CreatePlaylist( stream_t *s, char **pp_buffer )
  295. {
  296.     /* Get some infos about zip archive */
  297.     int i_ret = 0;
  298.     unzFile file = s->p_sys->zipFile;
  299.     vlc_array_t *p_filenames = vlc_array_new(); /* Will contain char* */
  300.     /* List all file names in Zip archive */
  301.     i_ret = GetFilesInZip( s, file, p_filenames, NULL );
  302.     if( i_ret < 0 )
  303.     {
  304.         unzClose( file );
  305.         i_ret = -1;
  306.         goto exit;
  307.     }
  308.     /* Close archive */
  309.     unzClose( file );
  310.     s->p_sys->zipFile = NULL;
  311.     /* Construct the xspf playlist */
  312.     i_ret = WriteXSPF( pp_buffer, p_filenames, s->p_sys->psz_path );
  313.     if( i_ret > 0 )
  314.         i_ret = 1;
  315.     else if( i_ret < 0 )
  316.         i_ret = -1;
  317. exit:
  318.     for( int i = 0; i < vlc_array_count( p_filenames ); i++ )
  319.     {
  320.         free( vlc_array_item_at_index( p_filenames, i ) );
  321.     }
  322.     vlc_array_destroy( p_filenames );
  323.     return i_ret;
  324. }
  325. /** **************************************************************************
  326.  * Zip utility functions
  327.  *****************************************************************************/
  328. /** **************************************************************************
  329.  * brief List files in zip and append their names to p_array
  330.  * param p_this
  331.  * param file Opened zip file
  332.  * param p_array vlc_array_t which will receive all filenames
  333.  *
  334.  * In case of error, returns VLC_EGENERIC.
  335.  * In case of success, returns number of files found, and goes back to first file.
  336.  *****************************************************************************/
  337. static int GetFilesInZip( stream_t *p_this, unzFile file,
  338.                           vlc_array_t *p_filenames, vlc_array_t *p_fileinfos )
  339. {
  340.     if( !p_filenames || !p_this )
  341.         return VLC_EGENERIC;
  342.     int i_ret = 0;
  343.     /* Get global info */
  344.     unz_global_info info;
  345.     if( unzGetGlobalInfo( file, &info ) != UNZ_OK )
  346.     {
  347.         msg_Warn( p_this, "this is not a valid zip archive" );
  348.         return VLC_EGENERIC;
  349.     }
  350.     /* Go to first file in archive */
  351.     unzGoToFirstFile( file );
  352.     /* Get info about each file */
  353.     for( unsigned long i = 0; i < info.number_entry; i++ )
  354.     {
  355.         char *psz_fileName = calloc( ZIP_FILENAME_LEN, 1 );
  356.         unz_file_info *p_fileInfo = calloc( 1, sizeof( unz_file_info ) );
  357.         if( !p_fileInfo || !psz_fileName )
  358.         {
  359.             free( psz_fileName );
  360.             free( p_fileInfo );
  361.             return VLC_ENOMEM;
  362.         }
  363.         if( unzGetCurrentFileInfo( file, p_fileInfo, psz_fileName,
  364.                                    ZIP_FILENAME_LEN, NULL, 0, NULL, 0 )
  365.             != UNZ_OK )
  366.         {
  367.             msg_Warn( p_this, "can't get info about file in zip" );
  368.             return VLC_EGENERIC;
  369.         }
  370.         if( p_filenames )
  371.             vlc_array_append( p_filenames, strdup( psz_fileName ) );
  372.         free( psz_fileName );
  373.         if( p_fileinfos )
  374.             vlc_array_append( p_fileinfos, p_fileInfo );
  375.         else
  376.             free( p_fileInfo );
  377.         if( i < ( info.number_entry - 1 ) )
  378.         {
  379.             /* Go the next file in the archive */
  380.             if( unzGoToNextFile( file ) != UNZ_OK )
  381.             {
  382.                 msg_Warn( p_this, "can't go to next file in zip" );
  383.                 return VLC_EGENERIC;
  384.             }
  385.         }
  386.         i_ret++;
  387.     }
  388.     /* i_ret should be equal to info.number_entry */
  389.     unzGoToFirstFile( file );
  390.     return i_ret;
  391. }
  392. /** **************************************************************************
  393.  * XSPF generation functions
  394.  *****************************************************************************/
  395. /** **************************************************************************
  396.  * brief Check a character for allowance in the Xml.
  397.  * Allowed chars are: a-z, A-Z, 0-9, , /, ., ' ', _ and :
  398.  *****************************************************************************/
  399. bool isAllowedChar( char c )
  400. {
  401.     return ( c >= 'a' && c <= 'z' )
  402.            || ( c >= 'A' && c <= 'Z' )
  403.            || ( c >= '0' && c <= '9' )
  404.            || ( c == ':' ) || ( c == '/' )
  405.            || ( c == '\' ) || ( c == '.' )
  406.            || ( c == ' ' ) || ( c == '_' );
  407. }
  408. /** **************************************************************************
  409.  * brief Escape string to be XML valid
  410.  * Allowed chars are defined by the above function isAllowedChar()
  411.  * Invalid chars are escaped using non standard '?XX' notation.
  412.  * NOTE: We cannot trust VLC internal Web encoding functions
  413.  *       because they are not able to encode and decode some rare utf-8
  414.  *       characters properly. Also, we don't control exactly when they are
  415.  *       called (from this module).
  416.  *****************************************************************************/
  417. static int escapeToXml( char **ppsz_encoded, const char *psz_url )
  418. {
  419.     char *psz_iter, *psz_tmp;
  420.     /* Count number of unallowed characters in psz_url */
  421.     size_t i_num = 0, i_len = 0;
  422.     for( psz_iter = (char*) psz_url; *psz_iter; ++psz_iter )
  423.     {
  424.         if( isAllowedChar( *psz_iter ) )
  425.         {
  426.             i_len++;
  427.         }
  428.         else
  429.         {
  430.             i_len++;
  431.             i_num++;
  432.         }
  433.     }
  434.     /* Special case */
  435.     if( i_num == 0 )
  436.     {
  437.         *ppsz_encoded = malloc( i_len + 1 );
  438.         memcpy( *ppsz_encoded, psz_url, i_len + 1 );
  439.         return VLC_SUCCESS;
  440.     }
  441.     /* Copy string, replacing invalid characters */
  442.     char *psz_ret = malloc( i_len + 3*i_num + 2 );
  443.     if( !psz_ret ) return VLC_ENOMEM;
  444.     for( psz_iter = (char*) psz_url, psz_tmp = psz_ret;
  445.          *psz_iter; ++psz_iter, ++psz_tmp )
  446.     {
  447.         if( isAllowedChar( *psz_iter ) )
  448.         {
  449.             *psz_tmp = *psz_iter;
  450.         }
  451.         else
  452.         {
  453.             *(psz_tmp++) = '?';
  454.             snprintf( psz_tmp, 3, "%02x", ( *psz_iter & 0x000000FF ) );
  455.             psz_tmp++;
  456.         }
  457.     }
  458.     *psz_tmp = '';
  459.     /* Return success */
  460.     *ppsz_encoded = psz_ret;
  461.     return VLC_SUCCESS;
  462. }
  463. /** **************************************************************************
  464.  * brief Write the XSPF playlist given the list of files
  465.  *****************************************************************************/
  466. static int WriteXSPF( char **pp_buffer, vlc_array_t *p_filenames,
  467.                       const char *psz_zippath )
  468. {
  469.     char *psz_zip = strrchr( psz_zippath, DIR_SEP_CHAR );
  470.     psz_zip = convert_xml_special_chars( psz_zip ? (psz_zip+1) : psz_zippath );
  471.     if( asprintf( pp_buffer, "<?xml version="1.0" encoding="UTF-8"?>n"
  472.         "<playlist version="1" xmlns="http://xspf.org/ns/0/" "
  473.                 "xmlns:vlc="http://www.videolan.org/vlc/playlist/ns/0/">n"
  474.                 " <title>%s</title>n"
  475.                 " <trackList>n", psz_zip ) == -1)
  476.         return -1;
  477.     /* Root node */
  478.     node *playlist = new_node( psz_zip );
  479.     /* Encode the URI and append ZIP_SEP */
  480.     char *psz_pathtozip;
  481.     escapeToXml( &psz_pathtozip, psz_zippath );
  482.     if( astrcatf( &psz_pathtozip, "%s", ZIP_SEP ) < 0 ) return -1;
  483.     int i_track = 0;
  484.     for( int i = 0; i < vlc_array_count( p_filenames ); ++i )
  485.     {
  486.         char *psz_name = (char*) vlc_array_item_at_index( p_filenames, i );
  487.         int i_len = strlen( psz_name );
  488.         if( !i_len ) continue;
  489.         /* Is it a folder ? */
  490.         if( psz_name[i_len-1] == '/' )
  491.         {
  492.             /* Do nothing */
  493.         }
  494.         else /* File */
  495.         {
  496.             /* Extract file name */
  497.             char *psz_file = strrchr( psz_name, '/' );
  498.             psz_file = convert_xml_special_chars( psz_file ?
  499.                     (psz_file+1) : psz_name );
  500.             /* Build full MRL */
  501.             char *psz_path = strdup( psz_pathtozip );
  502.             char *psz_escapedName;
  503.             escapeToXml( &psz_escapedName, psz_name );
  504.             if( astrcatf( &psz_path, "%s", psz_escapedName ) < 0 ) return -1;
  505.             /* Track information */
  506.             if( astrcatf( pp_buffer,
  507.                         "  <track>n"
  508.                         "   <location>zip://%s</location>n"
  509.                         "   <title>%s</title>n"
  510.                         "   <extension application="http://www.videolan.org/vlc/playlist/0">n"
  511.                         "    <vlc:id>%d</vlc:id>n"
  512.                         "   </extension>n"
  513.                         "  </track>n",
  514.                         psz_path, psz_file, i_track ) < 0 ) return -1;
  515.             free( psz_file );
  516.             free( psz_path );
  517.             /* Find the parent node */
  518.             node *parent = findOrCreateParentNode( playlist, psz_name );
  519.             assert( parent );
  520.             /* Add the item to this node */
  521.             item *tmp = parent->media;
  522.             if( !tmp )
  523.             {
  524.                 parent->media = new_item( i_track );
  525.             }
  526.             else
  527.             {
  528.                 while( tmp->next )
  529.                 {
  530.                     tmp = tmp->next;
  531.                 }
  532.                 tmp->next = new_item( i_track );
  533.             }
  534.             ++i_track;
  535.         }
  536.     }
  537.     free( psz_pathtozip );
  538.     /* Close tracklist, open the extension */
  539.     if( astrcatf( pp_buffer,
  540.         " </trackList>n"
  541.         " <extension application="http://www.videolan.org/vlc/playlist/0">n"
  542.                 ) < 0 ) return -1;
  543.     /* Write the tree */
  544.     if( nodeToXSPF( pp_buffer, playlist, true ) < 0 ) return -1;
  545.     /* Close extension and playlist */
  546.     if( astrcatf( pp_buffer, " </extension>n</playlist>n" ) < 0 ) return -1;
  547.     /* printf( "%s", *pp_buffer ); */
  548.     free_all_node( playlist );
  549.     return VLC_SUCCESS;
  550. }
  551. /** **************************************************************************
  552.  * brief Recursively convert a node to its XSPF representation
  553.  *****************************************************************************/
  554. static int nodeToXSPF( char **pp_buffer, node *n, bool b_root )
  555. {
  556.     if( !b_root )
  557.     {
  558.         if( astrcatf( pp_buffer, "  <vlc:node title="%s">n", n->name ) < 0 )
  559.             return -1;
  560.     }
  561.     if( n->child )
  562.         nodeToXSPF( pp_buffer, n->child, false );
  563.     item *i = n->media;
  564.     while( i )
  565.     {
  566.         if( astrcatf( pp_buffer, "   <vlc:item tid="%d" />n", i->id ) < 0 )
  567.             return -1;
  568.         i = i->next;
  569.     }
  570.     if( !b_root )
  571.     {
  572.         if( astrcatf( pp_buffer, "  </vlc:node>n" ) < 0 )
  573.             return -1;
  574.     }
  575.     return VLC_SUCCESS;
  576. }
  577. /** **************************************************************************
  578.  * brief Either create or find the parent node of the item
  579.  *****************************************************************************/
  580. static node* findOrCreateParentNode( node *root, const char *fullpath )
  581. {
  582.     char *folder;
  583.     char *path = strdup( fullpath );
  584.     folder = path;
  585.     assert( root );
  586.     char *sep = strchr( folder, '/' );
  587.     if( !sep )
  588.     {
  589.         free( path );
  590.         return root;
  591.     }
  592.     *sep = '';
  593.     ++sep;
  594.     node *current = root->child;
  595.     while( current )
  596.     {
  597.         if( !strcmp( current->name, folder ) )
  598.         {
  599.             /* We found the folder, go recursively deeper */
  600.             return findOrCreateParentNode( current, sep );
  601.         }
  602.         current = current->next;
  603.     }
  604.     /* If we are here, then it means that we did not find the parent */
  605.     node *ret = new_node( folder );
  606.     if( !root->child )
  607.         root->child = ret;
  608.     else
  609.     {
  610.         current = root->child;
  611.         while( current->next )
  612.         {
  613.             current = current->next;
  614.         }
  615.         current->next = ret;
  616.     }
  617.     /* And now, create the subfolders */
  618.     ret = findOrCreateParentNode( ret, sep );
  619.     free( path );
  620.     return ret;
  621. }
  622. /** **************************************************************************
  623.  * ZipIO function definitions : how to use vlc_stream to read the zip
  624.  *****************************************************************************/
  625. /** **************************************************************************
  626.  * brief interface for unzip module to open a file using a vlc_stream
  627.  * param opaque
  628.  * param filename
  629.  * param mode how to open the file (read/write ?). We support only read
  630.  * return opaque
  631.  *****************************************************************************/
  632. static void ZCALLBACK *ZipIO_Open( void *opaque, const char *file, int mode )
  633. {
  634.     (void) file;
  635.     stream_t *s = (stream_t*) opaque;
  636.     if( mode & ( ZLIB_FILEFUNC_MODE_CREATE | ZLIB_FILEFUNC_MODE_WRITE ) )
  637.     {
  638.         msg_Dbg( s, "ZipIO_Open: we cannot write into zip files" );
  639.         return NULL;
  640.     }
  641.     return s;
  642. }
  643. /** **************************************************************************
  644.  * brief read something from stream into buffer
  645.  * param opaque should be the stream
  646.  * param stream stream created by ZipIO_Open
  647.  * param buf buffer to read the file
  648.  * param size length of this buffer
  649.  * return return the number of bytes read (<= size)
  650.  *****************************************************************************/
  651. static unsigned long ZCALLBACK ZipIO_Read( void *opaque, void *stream,
  652.                                            void *buf, unsigned long size )
  653. {
  654.     (void) stream;
  655.     stream_t *s = (stream_t*) opaque;
  656.     return (unsigned long) stream_Read( s->p_source, buf, (int) size );
  657. }
  658. /** **************************************************************************
  659.  * brief tell size of stream
  660.  * param opaque should be the stream
  661.  * param stream stream created by ZipIO_Open
  662.  * return size of the file / stream
  663.  * ATTENTION: this is not stream_Tell, but stream_Size !
  664.  *****************************************************************************/
  665. static long ZCALLBACK ZipIO_Tell( void *opaque, void *stream )
  666. {
  667.     (void) stream;
  668.     stream_t *s = (stream_t*) opaque;
  669.     return (long) stream_Size( s->p_source ); /* /! not stream_Tell /! */
  670. }
  671. /** **************************************************************************
  672.  * brief seek in the stream
  673.  * param opaque should be the stream
  674.  * param stream stream created by ZipIO_Open
  675.  * param offset positive offset to seek
  676.  * param origin current position in stream
  677.  * return ¿ VLC_SUCCESS or an error code ?
  678.  *****************************************************************************/
  679. static long ZCALLBACK ZipIO_Seek ( void *opaque, void *stream,
  680.                                    unsigned long offset, int origin )
  681. {
  682.     (void) stream;
  683.     stream_t *s = (stream_t*) opaque;
  684.     long l_ret;
  685.     uint64_t pos = offset + origin;
  686.     l_ret = (long) stream_Seek( s->p_source, pos );
  687.     return l_ret;
  688. }
  689. /** **************************************************************************
  690.  * brief close the stream
  691.  * param opaque should be the stream
  692.  * param stream stream created by ZipIO_Open
  693.  * return always VLC_SUCCESS
  694.  * This closes zip archive
  695.  *****************************************************************************/
  696. static int ZCALLBACK ZipIO_Close ( void *opaque, void *stream )
  697. {
  698.     (void) stream;
  699.     (void) opaque;
  700. //     stream_t *s = (stream_t*) opaque;
  701. //    if( p_demux->p_sys && p_demux->p_sys->zipFile )
  702. //        p_demux->p_sys->zipFile = NULL;
  703. //     stream_Seek( s->p_source, 0 );
  704.     return VLC_SUCCESS;
  705. }
  706. /** **************************************************************************
  707.  * brief I/O functions for the ioapi: write (assert insteadof segfault)
  708.  *****************************************************************************/
  709. static uLong ZCALLBACK ZipIO_Write( void* opaque, void* stream,
  710.                                     const void* buf, uLong size )
  711. {
  712.     (void)opaque; (void)stream; (void)buf; (void)size;
  713.     int ERROR_zip_cannot_write_this_should_not_happen = 0;
  714.     assert( ERROR_zip_cannot_write_this_should_not_happen );
  715.     return 0;
  716. }
  717. /** **************************************************************************
  718.  * brief I/O functions for the ioapi: test error (man 3 ferror)
  719.  *****************************************************************************/
  720. static int ZCALLBACK ZipIO_Error( void* opaque, void* stream )
  721. {
  722.     (void)opaque;
  723.     (void)stream;
  724.     return 0;
  725. }