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