]> git.sesse.net Git - vlc/blob - modules/access/zip/zipstream.c
af2adcc1c4cedc8fa28091dc723476488069fca6
[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) 2007 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( _( "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( _( "Zip access" ) )
54         set_capability( "access", 70 )
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( sizeof( *p_sys ), 1 );
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 );
209         free( p_sys->fileFunctions );
210         return VLC_EGENERIC;
211     }
212
213     /* Find the stream uri */
214     /* FIXME FIXME FIXME */
215     input_thread_t *p_input_thread = (input_thread_t*)
216             vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT );
217     if( !p_input_thread )
218     {
219         free( p_sys );
220         free( p_sys->fileFunctions );
221         return VLC_EGENERIC;
222     }
223     input_item_t *p_input_item = input_GetItem( p_input_thread );
224     if( !p_input_item )
225     {
226         free( p_sys );
227         free( p_sys->fileFunctions );
228         return VLC_EGENERIC;
229     }
230     s->p_sys->psz_path = strdup( p_input_item->psz_uri );
231     vlc_gc_decref( p_input_item );
232 //     vlc_object_release( p_input_thread );
233     /* FIXME FIXME FIXME */
234
235     return VLC_SUCCESS;
236 }
237
238 /** *************************************************************************
239  * Close
240  ****************************************************************************/
241 void StreamClose( vlc_object_t *p_this )
242 {
243     stream_t *s = (stream_t*)p_this;
244     stream_sys_t *p_sys = s->p_sys;
245
246     free( p_sys->fileFunctions );
247     free( p_sys->psz_xspf );
248     free( p_sys->psz_path );
249     free( p_sys );
250 }
251
252 /** *************************************************************************
253  * Stream filters functions
254  ****************************************************************************/
255
256 /** *************************************************************************
257  * Read
258  ****************************************************************************/
259 static int Read( stream_t *s, void *p_read, unsigned int i_read )
260 {
261     stream_sys_t *p_sys = s->p_sys;
262
263     if( !p_read ) return 0;
264
265     /* Fill the buffer */
266     if( p_sys->psz_xspf == NULL )
267     {
268         int i_ret = CreatePlaylist( s, &p_sys->psz_xspf );
269         if( i_ret < 0 )
270             return -1;
271         p_sys->i_len = strlen( p_sys->psz_xspf );
272         p_sys->i_pos = 0;
273     }
274
275     /* Read the buffer */
276     int i_len = __MIN( i_read, p_sys->i_len - p_sys->i_pos );
277     memcpy( p_read, p_sys->psz_xspf + p_sys->i_pos, i_len );
278     p_sys->i_pos += i_len;
279
280     return i_len;
281 }
282
283 /** *************************************************************************
284  * Peek
285  ****************************************************************************/
286 static int Peek( stream_t *s, const uint8_t **pp_peek, unsigned int i_peek )
287 {
288     stream_sys_t *p_sys = s->p_sys;
289
290     /* Fill the buffer */
291     if( p_sys->psz_xspf == NULL )
292     {
293         int i_ret = CreatePlaylist( s, &p_sys->psz_xspf );
294         if( i_ret < 0 )
295             return -1;
296         p_sys->i_len = strlen( p_sys->psz_xspf );
297         p_sys->i_pos = 0;
298     }
299
300
301     /* Point to the buffer */
302     int i_len = __MIN( i_peek, p_sys->i_len - p_sys->i_pos );
303     *pp_peek = (uint8_t*) p_sys->psz_xspf + p_sys->i_pos;
304
305     return i_len;
306 }
307
308 /** *************************************************************************
309  * Control
310  ****************************************************************************/
311 static int Control( stream_t *s, int i_query, va_list args )
312 {
313     stream_sys_t *p_sys = s->p_sys;
314
315     switch( i_query )
316     {
317         case STREAM_SET_POSITION:
318         {
319             int64_t i_position = (int64_t)va_arg( args, int64_t );
320             if( i_position >= p_sys->i_len )
321                 return VLC_EGENERIC;
322             else
323             {
324                 p_sys->i_len = (size_t) i_position;
325                 return VLC_SUCCESS;
326             }
327         }
328
329         case STREAM_GET_POSITION:
330         {
331             int64_t *pi_position = (int64_t*)va_arg( args, int64_t* );
332             *pi_position = p_sys->i_pos;
333             return VLC_SUCCESS;
334         }
335
336         case STREAM_GET_SIZE:
337         {
338             int64_t *pi_size = (int64_t*)va_arg( args, int64_t* );
339             *pi_size = (int64_t) p_sys->i_len;
340             return VLC_SUCCESS;
341         }
342
343         case STREAM_GET_MTU:
344         {
345             int *pi_mtu = (int*)va_arg( args, int* );
346             *pi_mtu = 0;
347             return VLC_SUCCESS;
348         }
349
350         case STREAM_GET_CONTENT_TYPE:
351             return VLC_EGENERIC;
352
353         case STREAM_UPDATE_SIZE:
354         case STREAM_CONTROL_ACCESS:
355         case STREAM_CAN_SEEK:
356         case STREAM_CAN_FASTSEEK:
357         case STREAM_SET_RECORD_STATE:
358             return stream_vaControl( s->p_source, i_query, args );
359
360         default:
361             return VLC_EGENERIC;
362     }
363 }
364
365 static int CreatePlaylist( stream_t *s, char **pp_buffer )
366 {
367     /* Get some infos about zip archive */
368     int i_ret = 0;
369     unzFile file = s->p_sys->zipFile;
370     vlc_array_t *p_filenames = vlc_array_new(); /* Will contain char* */
371
372     /* List all file names in Zip archive */
373     i_ret = GetFilesInZip( s, file, p_filenames, NULL );
374     if( i_ret < 0 )
375     {
376         unzClose( file );
377         i_ret = -1;
378         goto exit;
379     }
380
381     // msg_Dbg( s, "%d files in Zip", vlc_array_count( p_filenames ) );
382
383     /* Close archive */
384     unzClose( file );
385     s->p_sys->zipFile = NULL;
386
387     /* Construct the xspf playlist */
388     i_ret = WriteXSPF( pp_buffer, p_filenames, s->p_sys->psz_path );
389     if( i_ret > 0 )
390         i_ret = 1;
391     else if( i_ret < 0 )
392         i_ret = -1;
393
394 exit:
395     for( int i = 0; i < vlc_array_count( p_filenames ); i++ )
396     {
397         free( vlc_array_item_at_index( p_filenames, i ) );
398     }
399     vlc_array_destroy( p_filenames );
400     return i_ret;
401 }
402
403
404 /** **************************************************************************
405  * Zip utility functions
406  *****************************************************************************/
407
408 /** **************************************************************************
409  * \brief List files in zip and append their names to p_array
410  * \param p_this
411  * \param file Opened zip file
412  * \param p_array vlc_array_t which will receive all filenames
413  *
414  * In case of error, returns VLC_EGENERIC.
415  * In case of success, returns number of files found, and goes back to first file.
416  *****************************************************************************/
417 static int GetFilesInZip( stream_t *p_this, unzFile file,
418                           vlc_array_t *p_filenames, vlc_array_t *p_fileinfos )
419 {
420     if( !p_filenames || !p_this )
421         return VLC_EGENERIC;
422
423     int i_ret = 0;
424
425     /* Get global info */
426     unz_global_info info;
427
428     if( unzGetGlobalInfo( file, &info ) != UNZ_OK )
429     {
430         msg_Warn( p_this, "this is not a valid zip archive" );
431         return VLC_EGENERIC;
432     }
433
434     /* Go to first file in archive */
435     unzGoToFirstFile( file );
436
437     /* Get info about each file */
438     for( unsigned long i = 0; i < info.number_entry; i++ )
439     {
440         char *psz_fileName = calloc( ZIP_FILENAME_LEN, 1 );
441         unz_file_info *p_fileInfo = calloc( 1, sizeof( unz_file_info ) );
442
443         if( !p_fileInfo || !psz_fileName )
444         {
445             msg_Warn( p_this, "not enough memory" );
446             return VLC_ENOMEM;
447         }
448
449         if( unzGetCurrentFileInfo( file, p_fileInfo, psz_fileName,
450                                    ZIP_FILENAME_LEN, NULL, 0, NULL, 0 )
451             != UNZ_OK )
452         {
453             msg_Warn( p_this, "can't get info about file in zip" );
454             return VLC_EGENERIC;
455         }
456
457         if( p_filenames )
458             vlc_array_append( p_filenames, strdup( psz_fileName ) );
459         free( psz_fileName );
460
461         if( p_fileinfos )
462             vlc_array_append( p_fileinfos, p_fileInfo );
463         else
464             free( p_fileInfo );
465
466         if( i < ( info.number_entry - 1 ) )
467         {
468             /* Go the next file in the archive */
469             if( unzGoToNextFile( file ) != UNZ_OK )
470             {
471                 msg_Warn( p_this, "can't go to next file in zip" );
472                 return VLC_EGENERIC;
473             }
474         }
475
476         i_ret++;
477     }
478
479     /* i_ret should be equal to info.number_entry */
480     unzGoToFirstFile( file );
481     return i_ret;
482 }
483
484
485 /** **************************************************************************
486  * XSPF generation functions
487  *****************************************************************************/
488
489 /** **************************************************************************
490  * \brief Write the XSPF playlist given the list of files
491  *****************************************************************************/
492 static int WriteXSPF( char **pp_buffer, vlc_array_t *p_filenames,
493                       const char *psz_zippath )
494 {
495     char *psz_zip = strrchr( psz_zippath, DIR_SEP_CHAR );
496     psz_zip = convert_xml_special_chars( psz_zip ? (psz_zip+1) : psz_zippath );
497
498     if( asprintf( pp_buffer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
499         "<playlist version=\"1\" xmlns=\"http://xspf.org/ns/0/\" "
500                 "xmlns:vlc=\"http://www.videolan.org/vlc/playlist/ns/0/\">\n"
501                 " <title>%s</title>\n"
502                 " <trackList>\n", psz_zip ) == -1)
503         return -1;
504
505     /* Root node */
506     node *playlist = new_node( psz_zip );
507
508     /* Web-Encode the URI and append '!' */
509     char *psz_pathtozip = vlc_UrlEncode( psz_zippath );
510     if( astrcatf( &psz_pathtozip, ZIP_SEP ) < 0 ) return -1;
511
512     int i_track = 0;
513     for( int i = 0; i < vlc_array_count( p_filenames ); ++i )
514     {
515         char *psz_name = (char*) vlc_array_item_at_index( p_filenames, i );
516         int i_len = strlen( psz_name );
517
518         if( !i_len ) continue;
519
520         /* Is it a folder ? */
521         if( psz_name[i_len-1] == '/' )
522         {
523             /* Do nothing */
524         }
525         else /* File */
526         {
527             /* Extract file name */
528             char *psz_file = strrchr( psz_name, '/' );
529             psz_file = convert_xml_special_chars( psz_file ?
530                     (psz_file+1) : psz_name );
531
532             /* Build full MRL */
533             char *psz_path = strdup( psz_pathtozip );
534             if( astrcatf( &psz_path, psz_name ) < 0 ) return -1;
535
536             /* Double url-encode */
537             char *psz_tmp = psz_path;
538             psz_path = vlc_UrlEncode( psz_tmp );
539             free( psz_tmp );
540
541             /* Track information */
542             if( astrcatf( pp_buffer,
543                         "  <track>\n"
544                         "   <location>zip://%s</location>\n"
545                         "   <title>%s</title>\n"
546                         "   <extension application=\"http://www.videolan.org/vlc/playlist/0\">\n"
547                         "    <vlc:id>%d</vlc:id>\n"
548                         "   </extension>\n"
549                         "  </track>\n",
550                         psz_path, psz_file, i_track ) < 0 ) return -1;
551
552             free( psz_file );
553             free( psz_path );
554
555             /* Find the parent node */
556             node *parent = findOrCreateParentNode( playlist, psz_name );
557             assert( parent );
558
559             /* Add the item to this node */
560             item *tmp = parent->media;
561             if( !tmp )
562             {
563                 parent->media = new_item( i_track );
564             }
565             else
566             {
567                 while( tmp->next )
568                 {
569                     tmp = tmp->next;
570                 }
571                 tmp->next = new_item( i_track );
572             }
573
574             ++i_track;
575         }
576     }
577
578     free( psz_pathtozip );
579
580     /* Close tracklist, open the extension */
581     if( astrcatf( pp_buffer,
582         " </trackList>\n"
583         " <extension application=\"http://www.videolan.org/vlc/playlist/0\">\n"
584                 ) < 0 ) return -1;
585
586     /* Write the tree */
587     if( nodeToXSPF( pp_buffer, playlist, true ) < 0 ) return -1;
588
589     /* Close extension and playlist */
590     if( astrcatf( pp_buffer, " </extension>\n</playlist>\n" ) < 0 ) return -1;
591
592     /* printf( "%s", *pp_buffer ); */
593
594     free_all_node( playlist );
595
596     return VLC_SUCCESS;
597 }
598
599 /** **************************************************************************
600  * \brief Recursively convert a node to its XSPF representation
601  *****************************************************************************/
602 static int nodeToXSPF( char **pp_buffer, node *n, bool b_root )
603 {
604     if( !b_root )
605     {
606         if( astrcatf( pp_buffer, "  <vlc:node title=\"%s\">\n", n->name ) < 0 )
607             return -1;
608     }
609     if( n->child )
610         nodeToXSPF( pp_buffer, n->child, false );
611     item *i = n->media;
612     while( i )
613     {
614         if( astrcatf( pp_buffer, "   <vlc:item tid=\"%d\" />\n", i->id ) < 0 )
615             return -1;
616         i = i->next;
617     }
618     if( !b_root )
619     {
620         if( astrcatf( pp_buffer, "  </vlc:node>\n" ) < 0 )
621             return -1;
622     }
623     return VLC_SUCCESS;
624 }
625
626 /** **************************************************************************
627  * \brief Either create or find the parent node of the item
628  *****************************************************************************/
629 static node* findOrCreateParentNode( node *root, const char *fullpath )
630 {
631     char *folder;
632     char *path = strdup( fullpath );
633     folder = path;
634
635     assert( root );
636
637     char *sep = strchr( folder, '/' );
638     if( !sep )
639     {
640         free( path );
641         return root;
642     }
643
644     *sep = '\0';
645     ++sep;
646
647     node *current = root->child;
648
649     while( current )
650     {
651         if( !strcmp( current->name, folder ) )
652         {
653             /* We found the folder, go recursively deeper */
654             return findOrCreateParentNode( current, sep );
655         }
656         current = current->next;
657     }
658
659     /* If we are here, then it means that we did not find the parent */
660     node *ret = new_node( folder );
661     if( !root->child )
662         root->child = ret;
663     else
664     {
665         current = root->child;
666         while( current->next )
667         {
668             current = current->next;
669         }
670         current->next = ret;
671     }
672
673     /* And now, create the subfolders */
674     ret = findOrCreateParentNode( ret, sep );
675
676     free( path );
677     return ret;
678 }
679
680
681 /** **************************************************************************
682  * ZipIO function definitions : how to use vlc_stream to read the zip
683  *****************************************************************************/
684
685 /** **************************************************************************
686  * \brief interface for unzip module to open a file using a vlc_stream
687  * \param opaque
688  * \param filename
689  * \param mode how to open the file (read/write ?). We support only read
690  * \return opaque
691  *****************************************************************************/
692 static void ZCALLBACK *ZipIO_Open( void *opaque, const char *file, int mode )
693 {
694     (void) file;
695     stream_t *s = (stream_t*) opaque;
696     if( mode & ( ZLIB_FILEFUNC_MODE_CREATE | ZLIB_FILEFUNC_MODE_WRITE ) )
697     {
698         msg_Dbg( s, "ZipIO_Open: we cannot write into zip files" );
699         return NULL;
700     }
701     return s;
702 }
703
704 /** **************************************************************************
705  * \brief read something from stream into buffer
706  * \param opaque should be the stream
707  * \param stream stream created by ZipIO_Open
708  * \param buf buffer to read the file
709  * \param size length of this buffer
710  * \return return the number of bytes read (<= size)
711  *****************************************************************************/
712 static unsigned long ZCALLBACK ZipIO_Read( void *opaque, void *stream,
713                                            void *buf, unsigned long size )
714 {
715     (void) stream;
716     stream_t *s = (stream_t*) opaque;
717     return (unsigned long) stream_Read( s->p_source, buf, (int) size );
718 }
719
720 /** **************************************************************************
721  * \brief tell size of stream
722  * \param opaque should be the stream
723  * \param stream stream created by ZipIO_Open
724  * \return size of the file / stream
725  * ATTENTION: this is not stream_Tell, but stream_Size !
726  *****************************************************************************/
727 static long ZCALLBACK ZipIO_Tell( void *opaque, void *stream )
728 {
729     (void) stream;
730     stream_t *s = (stream_t*) opaque;
731     return (long) stream_Size( s->p_source ); /* /!\ not stream_Tell /!\ */
732 }
733
734 /** **************************************************************************
735  * \brief seek in the stream
736  * \param opaque should be the stream
737  * \param stream stream created by ZipIO_Open
738  * \param offset positive offset to seek
739  * \param origin current position in stream
740  * \return ¿ VLC_SUCCESS or an error code ?
741  *****************************************************************************/
742 static long ZCALLBACK ZipIO_Seek ( void *opaque, void *stream,
743                                    unsigned long offset, int origin )
744 {
745     (void) stream;
746     stream_t *s = (stream_t*) opaque;
747     long l_ret;
748
749     uint64_t pos = offset + origin;
750     l_ret = (long) stream_Seek( s->p_source, pos );
751     return l_ret;
752 }
753
754 /** **************************************************************************
755  * \brief close the stream
756  * \param opaque should be the stream
757  * \param stream stream created by ZipIO_Open
758  * \return always VLC_SUCCESS
759  * This closes zip archive
760  *****************************************************************************/
761 static int ZCALLBACK ZipIO_Close ( void *opaque, void *stream )
762 {
763     (void) stream;
764     (void) opaque;
765 //     stream_t *s = (stream_t*) opaque;
766 //    if( p_demux->p_sys && p_demux->p_sys->zipFile )
767 //        p_demux->p_sys->zipFile = NULL;
768 //     stream_Seek( s->p_source, 0 );
769     return VLC_SUCCESS;
770 }
771
772 /** **************************************************************************
773  * \brief I/O functions for the ioapi: write (assert insteadof segfault)
774  *****************************************************************************/
775 static uLong ZCALLBACK ZipIO_Write( void* opaque, void* stream,
776                                     const void* buf, uLong size )
777 {
778     (void)opaque; (void)stream; (void)buf; (void)size;
779     int ERROR_zip_cannot_write_this_should_not_happen = 0;
780     assert( ERROR_zip_cannot_write_this_should_not_happen );
781     return 0;
782 }
783
784 /** **************************************************************************
785  * \brief I/O functions for the ioapi: test error (man 3 ferror)
786  *****************************************************************************/
787 static int ZCALLBACK ZipIO_Error( void* opaque, void* stream )
788 {
789     (void)opaque;
790     (void)stream;
791     //msg_Dbg( p_access, "error" );
792     return 0;
793 }
794