set_subcategory( SUBCAT_INPUT_ACCESS )
set_description( N_( "Zip access" ) )
set_capability( "access", 0 )
- add_shortcut( "unzip" )
- add_shortcut( "zip" )
+ add_shortcut( "unzip", "zip" )
set_callbacks( AccessOpen, AccessClose )
vlc_module_end()
typedef struct node node;
typedef struct item item;
+static int Fill( stream_t * );
static int CreatePlaylist( stream_t *s, char **pp_buffer );
static int GetFilesInZip( stream_t*, unzFile, vlc_array_t*, vlc_array_t* );
static node* findOrCreateParentNode( node *root, const char *fullpath );
if( !p_sys->zipFile )
{
msg_Warn( s, "unable to open file" );
- free( p_sys );
free( p_sys->fileFunctions );
+ free( p_sys );
return VLC_EGENERIC;
}
char *psz_tmp;
if( asprintf( &psz_tmp, "%s.xspf", s->psz_path ) == -1 )
{
- free( p_sys );
free( p_sys->fileFunctions );
+ free( p_sys );
return VLC_ENOMEM;
}
p_sys->psz_path = s->psz_path;
stream_t *s = (stream_t*)p_this;
stream_sys_t *p_sys = s->p_sys;
+ if( p_sys->zipFile )
+ unzClose( p_sys->zipFile );
+
free( p_sys->fileFunctions );
free( p_sys->psz_xspf );
free( p_sys->psz_path );
{
stream_sys_t *p_sys = s->p_sys;
- if( !p_read ) return 0;
-
/* Fill the buffer */
- if( p_sys->psz_xspf == NULL )
- {
- int i_ret = CreatePlaylist( s, &p_sys->psz_xspf );
- if( i_ret < 0 )
- return -1;
- p_sys->i_len = strlen( p_sys->psz_xspf );
- p_sys->i_pos = 0;
- }
+ if( Fill( s ) )
+ return -1;
/* Read the buffer */
- int i_len = __MIN( i_read, p_sys->i_len - p_sys->i_pos );
- memcpy( p_read, p_sys->psz_xspf + p_sys->i_pos, i_len );
+ unsigned i_len = __MIN( i_read, p_sys->i_len - p_sys->i_pos );
+ if( p_read )
+ memcpy( p_read, p_sys->psz_xspf + p_sys->i_pos, i_len );
p_sys->i_pos += i_len;
return i_len;
stream_sys_t *p_sys = s->p_sys;
/* Fill the buffer */
- if( p_sys->psz_xspf == NULL )
- {
- int i_ret = CreatePlaylist( s, &p_sys->psz_xspf );
- if( i_ret < 0 )
- return -1;
- p_sys->i_len = strlen( p_sys->psz_xspf );
- p_sys->i_pos = 0;
- }
-
+ if( Fill( s ) )
+ return -1;
/* Point to the buffer */
int i_len = __MIN( i_peek, p_sys->i_len - p_sys->i_pos );
{
case STREAM_SET_POSITION:
{
- int64_t i_position = (int64_t)va_arg( args, int64_t );
+ uint64_t i_position = va_arg( args, uint64_t );
if( i_position >= p_sys->i_len )
return VLC_EGENERIC;
else
{
- p_sys->i_len = (size_t) i_position;
+ p_sys->i_pos = (size_t) i_position;
return VLC_SUCCESS;
}
}
case STREAM_GET_POSITION:
{
- int64_t *pi_position = (int64_t*)va_arg( args, int64_t* );
+ uint64_t *pi_position = va_arg( args, uint64_t* );
*pi_position = p_sys->i_pos;
return VLC_SUCCESS;
}
case STREAM_GET_SIZE:
{
- int64_t *pi_size = (int64_t*)va_arg( args, int64_t* );
- *pi_size = (int64_t) p_sys->i_len;
+ uint64_t *pi_size = va_arg( args, uint64_t* );
+ *pi_size = p_sys->i_len;
return VLC_SUCCESS;
}
}
}
+static int Fill( stream_t *s )
+{
+ stream_sys_t *p_sys = s->p_sys;
+
+ if( p_sys->psz_xspf )
+ return VLC_SUCCESS;
+
+ if( CreatePlaylist( s, &p_sys->psz_xspf ) < 0 )
+ return VLC_EGENERIC;
+
+ p_sys->i_len = strlen( p_sys->psz_xspf );
+ p_sys->i_pos = 0;
+ return VLC_SUCCESS;
+}
+
static int CreatePlaylist( stream_t *s, char **pp_buffer )
{
+ stream_sys_t *p_sys = s->p_sys;
+
+ unzFile file = p_sys->zipFile;
+ if( !file )
+ return -1;
+
/* Get some infos about zip archive */
int i_ret = 0;
- unzFile file = s->p_sys->zipFile;
vlc_array_t *p_filenames = vlc_array_new(); /* Will contain char* */
/* List all file names in Zip archive */
i_ret = GetFilesInZip( s, file, p_filenames, NULL );
if( i_ret < 0 )
{
- unzClose( file );
i_ret = -1;
goto exit;
}
- // msg_Dbg( s, "%d files in Zip", vlc_array_count( p_filenames ) );
-
- /* Close archive */
- unzClose( file );
- s->p_sys->zipFile = NULL;
-
/* Construct the xspf playlist */
- i_ret = WriteXSPF( pp_buffer, p_filenames, s->p_sys->psz_path );
+ i_ret = WriteXSPF( pp_buffer, p_filenames, p_sys->psz_path );
if( i_ret > 0 )
i_ret = 1;
else if( i_ret < 0 )
i_ret = -1;
exit:
+ /* Close archive */
+ unzClose( file );
+ p_sys->zipFile = NULL;
+
for( int i = 0; i < vlc_array_count( p_filenames ); i++ )
{
free( vlc_array_item_at_index( p_filenames, i ) );
* XSPF generation functions
*****************************************************************************/
+/** **************************************************************************
+ * \brief Check a character for allowance in the Xml.
+ * Allowed chars are: a-z, A-Z, 0-9, \, /, ., ' ', _ and :
+ *****************************************************************************/
+bool isAllowedChar( char c )
+{
+ return ( c >= 'a' && c <= 'z' )
+ || ( c >= 'A' && c <= 'Z' )
+ || ( c >= '0' && c <= '9' )
+ || ( c == ':' ) || ( c == '/' )
+ || ( c == '\\' ) || ( c == '.' )
+ || ( c == ' ' ) || ( c == '_' );
+}
+
+/** **************************************************************************
+ * \brief Escape string to be XML valid
+ * Allowed chars are defined by the above function isAllowedChar()
+ * Invalid chars are escaped using non standard '?XX' notation.
+ * NOTE: We cannot trust VLC internal Web encoding functions
+ * because they are not able to encode and decode some rare utf-8
+ * characters properly. Also, we don't control exactly when they are
+ * called (from this module).
+ *****************************************************************************/
+static int escapeToXml( char **ppsz_encoded, const char *psz_url )
+{
+ char *psz_iter, *psz_tmp;
+
+ /* Count number of unallowed characters in psz_url */
+ size_t i_num = 0, i_len = 0;
+ for( psz_iter = (char*) psz_url; *psz_iter; ++psz_iter )
+ {
+ if( isAllowedChar( *psz_iter ) )
+ {
+ i_len++;
+ }
+ else
+ {
+ i_len++;
+ i_num++;
+ }
+ }
+
+ /* Special case */
+ if( i_num == 0 )
+ {
+ *ppsz_encoded = malloc( i_len + 1 );
+ memcpy( *ppsz_encoded, psz_url, i_len + 1 );
+ return VLC_SUCCESS;
+ }
+
+ /* Copy string, replacing invalid characters */
+ char *psz_ret = malloc( i_len + 3*i_num + 2 );
+ if( !psz_ret ) return VLC_ENOMEM;
+
+ for( psz_iter = (char*) psz_url, psz_tmp = psz_ret;
+ *psz_iter; ++psz_iter, ++psz_tmp )
+ {
+ if( isAllowedChar( *psz_iter ) )
+ {
+ *psz_tmp = *psz_iter;
+ }
+ else
+ {
+ *(psz_tmp++) = '?';
+ snprintf( psz_tmp, 3, "%02x", ( *psz_iter & 0x000000FF ) );
+ psz_tmp++;
+ }
+ }
+ *psz_tmp = '\0';
+
+ /* Return success */
+ *ppsz_encoded = psz_ret;
+ return VLC_SUCCESS;
+}
+
/** **************************************************************************
* \brief Write the XSPF playlist given the list of files
*****************************************************************************/
/* Root node */
node *playlist = new_node( psz_zip );
- /* Web-Encode the URI and append '!' */
- char *psz_pathtozip = vlc_UrlEncode( psz_zippath );
- if( astrcatf( &psz_pathtozip, ZIP_SEP ) < 0 ) return -1;
+ /* Encode the URI and append ZIP_SEP */
+ char *psz_pathtozip;
+ escapeToXml( &psz_pathtozip, psz_zippath );
+ if( astrcatf( &psz_pathtozip, "%s", ZIP_SEP ) < 0 ) return -1;
int i_track = 0;
for( int i = 0; i < vlc_array_count( p_filenames ); ++i )
/* Build full MRL */
char *psz_path = strdup( psz_pathtozip );
- if( astrcatf( &psz_path, psz_name ) < 0 ) return -1;
-
- /* Double url-encode */
- char *psz_tmp = psz_path;
- psz_path = vlc_UrlEncode( psz_tmp );
- free( psz_tmp );
+ char *psz_escapedName;
+ escapeToXml( &psz_escapedName, psz_name );
+ if( astrcatf( &psz_path, "%s", psz_escapedName ) < 0 ) return -1;
/* Track information */
if( astrcatf( pp_buffer,
{
(void)opaque;
(void)stream;
- //msg_Dbg( p_access, "error" );
return 0;
}