/** Replacement for luaL_dofile, using VLC's input capabilities */ int vlclua_dofile( vlc_object_t *p_this, lua_State *L, const char *uri ) { if( !strstr( uri, "://" ) ) return luaL_dofile( L, uri ); if( !strncasecmp( uri, "file://", 7 ) ) return luaL_dofile( L, uri + 7 ); stream_t *s = stream_UrlNew( p_this, uri ); if( !s ) { return 1; } int64_t i_size = stream_Size( s ); char *p_buffer = ( i_size > 0 ) ? malloc( i_size ) : NULL; if( !p_buffer ) { // FIXME: read the whole stream until we reach the end (if no size) stream_Delete( s ); return 1; } int64_t i_read = stream_Read( s, p_buffer, (int) i_size ); int i_ret = ( i_read == i_size ) ? 0 : 1; if( !i_ret ) i_ret = luaL_loadbuffer( L, p_buffer, (size_t) i_size, uri ); if( !i_ret ) i_ret = lua_pcall( L, 0, LUA_MULTRET, 0 ); stream_Delete( s ); free( p_buffer ); return i_ret; }
static int vlclua_stream_new( lua_State *L ) { vlc_object_t * p_this = vlclua_get_this( L ); const char * psz_url = luaL_checkstring( L, 1 ); stream_t *p_stream = stream_UrlNew( p_this, psz_url ); return vlclua_stream_new_inner( L, p_stream ); }
static int Seek(access_t *access, uint64_t position) { access_sys_t *sys = access->p_sys; const rar_file_t *file = sys->file; if (position > file->real_size) position = file->real_size; /* Search the chunk */ const rar_file_chunk_t *old_chunk = sys->chunk; for (int i = 0; i < file->chunk_count; i++) { sys->chunk = file->chunk[i]; if (position < sys->chunk->cummulated_size + sys->chunk->size) break; } access->info.i_pos = position; access->info.b_eof = false; const uint64_t offset = sys->chunk->offset + (position - sys->chunk->cummulated_size); if (strcmp(old_chunk->mrl, sys->chunk->mrl)) { if (sys->s) stream_Delete(sys->s); sys->s = stream_UrlNew(access, sys->chunk->mrl); } return sys->s ? stream_Seek(sys->s, offset) : VLC_EGENERIC; }
static int Find( addons_finder_t *p_finder ) { bool b_done = false; while ( !b_done ) { char *psz_uri = NULL; if ( ! asprintf( &psz_uri, ADDONS_REPO_SCHEMEHOST"/xml" ) ) return VLC_ENOMEM; b_done = true; stream_t *p_stream = stream_UrlNew( p_finder, psz_uri ); free( psz_uri ); if ( !p_stream ) return VLC_EGENERIC; if ( ! ParseCategoriesInfo( p_finder, p_stream ) ) { /* no more entries have been read: was last page or error */ b_done = true; } stream_Delete( p_stream ); } return VLC_SUCCESS; }
static int Android_ParseSystemFonts( filter_t *p_filter, const char *psz_path ) { int i_ret = VLC_SUCCESS; stream_t *p_stream = stream_UrlNew( p_filter, psz_path ); if( !p_stream ) return VLC_EGENERIC; xml_reader_t *p_xml = xml_ReaderCreate( p_filter, p_stream ); if( !p_xml ) { stream_Delete( p_stream ); return VLC_EGENERIC; } const char *p_node; int i_type; while( ( i_type = xml_ReaderNextNode( p_xml, &p_node ) ) > 0 ) { if( i_type == XML_READER_STARTELEM && !strcasecmp( "family", p_node ) ) { if( ( i_ret = Android_ParseFamily( p_filter, p_xml ) ) ) break; } } xml_ReaderDelete( p_xml ); stream_Delete( p_stream ); return i_ret; }
XMLParser::XMLParser( intf_thread_t *pIntf, const string &rFileName ) : SkinObject( pIntf ), m_pXML( NULL ), m_pReader( NULL ), m_pStream( NULL ) { m_pXML = xml_Create( pIntf ); if( !m_pXML ) { msg_Err( getIntf(), "cannot initialize xml" ); return; } LoadCatalog(); char *psz_uri = vlc_path2uri( rFileName.c_str(), NULL ); m_pStream = stream_UrlNew( pIntf, psz_uri ); free( psz_uri ); if( !m_pStream ) { msg_Err( getIntf(), "failed to open %s for reading", rFileName.c_str() ); return; } m_pReader = xml_ReaderCreate( m_pXML, m_pStream ); if( !m_pReader ) { msg_Err( getIntf(), "failed to open %s for parsing", rFileName.c_str() ); return; } xml_ReaderUseDTD( m_pReader ); }
static int Open(vlc_object_t *object) { access_t *access = (access_t*)object; if (!strchr(access->psz_location, '|')) return VLC_EGENERIC; char *base = strdup(access->psz_location); if (!base) return VLC_EGENERIC; char *name = strchr(base, '|'); *name++ = '\0'; decode_URI(base); stream_t *s = stream_UrlNew(access, base); if (!s) goto error; int count; rar_file_t **files; if (RarProbe(s) || RarParse(s, &count, &files) || count <= 0) goto error; rar_file_t *file = NULL; for (int i = 0; i < count; i++) { if (!file && !strcmp(files[i]->name, name)) file = files[i]; else RarFileDelete(files[i]); } free(files); if (!file) goto error; access_sys_t *sys = access->p_sys = malloc(sizeof(*sys)); sys->s = s; sys->file = file; access->pf_read = Read; access->pf_block = NULL; access->pf_control = Control; access->pf_seek = Seek; access_InitFields(access); access->info.i_size = file->size; rar_file_chunk_t dummy = { .mrl = base, }; sys->chunk = &dummy; Seek(access, 0); free(base); return VLC_SUCCESS; error: if (s) stream_Delete(s); free(base); return VLC_EGENERIC; }
static int SwitchCallback(struct archive *p_archive, void *p_object, void *p_object2) { VLC_UNUSED(p_archive); callback_data_t *p_data = (callback_data_t *) p_object; callback_data_t *p_nextdata = (callback_data_t *) p_object2; access_sys_t *p_sys = p_data->p_access->p_sys; msg_Dbg(p_data->p_access, "opening next volume %s", p_nextdata->psz_uri); stream_Delete(p_sys->p_stream); p_sys->p_stream = stream_UrlNew(p_nextdata->p_access, p_nextdata->psz_uri); return p_sys->p_stream ? ARCHIVE_OK : ARCHIVE_FATAL; }
static int InstallFile( addons_storage_t *p_this, const char *psz_downloadlink, const char *psz_dest ) { stream_t *p_stream; FILE *p_destfile; char buffer[1<<10]; int i_read = 0; p_stream = stream_UrlNew( p_this, psz_downloadlink ); if( !p_stream ) { msg_Err( p_this, "Failed to access Addon download url %s", psz_downloadlink ); return VLC_EGENERIC; } char *psz_path = strdup( psz_dest ); if ( !psz_path ) { stream_Delete( p_stream ); return VLC_ENOMEM; } char *psz_buf = strrchr( psz_path, DIR_SEP_CHAR ); if( psz_buf ) { *++psz_buf = '\0'; /* ensure directory exists */ if( !EMPTY_STR( psz_path ) ) recursive_mkdir( VLC_OBJECT(p_this), psz_path ); free( psz_path ); } p_destfile = vlc_fopen( psz_dest, "w" ); if( !p_destfile ) { msg_Err( p_this, "Failed to open Addon storage file %s", psz_dest ); stream_Delete( p_stream ); return VLC_EGENERIC; } while ( ( i_read = stream_Read( p_stream, &buffer, 1<<10 ) ) > 0 ) { if ( fwrite( &buffer, i_read, 1, p_destfile ) < 1 ) { msg_Err( p_this, "Failed to write to Addon file" ); fclose( p_destfile ); stream_Delete( p_stream ); return VLC_EGENERIC; } } fclose( p_destfile ); stream_Delete( p_stream ); return VLC_SUCCESS; }
static int OpenCallback(struct archive *p_archive, void *p_object) { VLC_UNUSED(p_archive); callback_data_t *p_data = (callback_data_t *) p_object; access_sys_t *p_sys = p_data->p_access->p_sys; p_sys->p_stream = stream_UrlNew( p_data->p_access, p_data->psz_uri ); if(!p_sys->p_stream) return ARCHIVE_FATAL; /* Seek callback must only be set if calls are guaranteed to succeed */ stream_Control(p_sys->p_stream, STREAM_CAN_SEEK, &p_sys->b_source_canseek); if(p_sys->b_source_canseek) archive_read_set_seek_callback(p_sys->p_archive, SeekCallback); return ARCHIVE_OK; }
static picture_t *ImageReadUrl( image_handler_t *p_image, const char *psz_url, video_format_t *p_fmt_in, video_format_t *p_fmt_out ) { block_t *p_block; picture_t *p_pic; stream_t *p_stream = NULL; int i_size; p_stream = stream_UrlNew( p_image->p_parent, psz_url ); if( !p_stream ) { msg_Dbg( p_image->p_parent, "could not open %s for reading", psz_url ); return NULL; } i_size = stream_Size( p_stream ); p_block = block_New( p_image->p_parent, i_size ); stream_Read( p_stream, p_block->p_buffer, i_size ); if( !p_fmt_in->i_chroma ) { char *psz_mime = NULL; stream_Control( p_stream, STREAM_GET_CONTENT_TYPE, &psz_mime ); if( psz_mime ) p_fmt_in->i_chroma = image_Mime2Fourcc( psz_mime ); free( psz_mime ); } stream_Delete( p_stream ); if( !p_fmt_in->i_chroma ) { /* Try to guess format from file name */ p_fmt_in->i_chroma = image_Ext2Fourcc( psz_url ); } p_pic = ImageRead( p_image, p_block, p_fmt_in, p_fmt_out ); return p_pic; }
static struct reader * stream_open( const char *psz_url ) { libvlc_instance_t *p_vlc; struct reader *p_reader; const char * argv[] = { "-v", "--ignore-config", "-I", "dummy", "--no-media-library", "--vout=dummy", "--aout=dummy", }; p_reader = calloc( 1, sizeof(struct reader) ); assert( p_reader ); p_vlc = libvlc_new( sizeof(argv) / sizeof(argv[0]), argv ); assert( p_vlc != NULL ); p_reader->u.s = stream_UrlNew( p_vlc->p_libvlc_int, psz_url ); if( !p_reader->u.s ) { libvlc_release( p_vlc ); free( p_reader ); return NULL; } p_reader->pf_close = stream_close; p_reader->pf_getsize = stream_getsize; p_reader->pf_read = stream_read; p_reader->pf_peek = stream_peek; p_reader->pf_tell = stream_tell; p_reader->pf_seek = stream_seek; p_reader->p_data = p_vlc; p_reader->psz_name = "stream"; return p_reader; }
static int FindDesignated( addons_finder_t *p_finder ) { char *psz_manifest; const char *psz_path = p_finder->psz_uri + 7; // remove scheme if ( asprintf( &psz_manifest, "unzip://%s!/manifest.xml", psz_path ) < 1 ) return VLC_ENOMEM; stream_t *p_stream = stream_UrlNew( p_finder, psz_manifest ); free( psz_manifest ); if ( !p_stream ) return VLC_EGENERIC; if ( ParseCategoriesInfo( p_finder, p_stream ) ) { /* Do archive uri fixup */ FOREACH_ARRAY( addon_entry_t *p_entry, p_finder->entries ) if ( likely( !p_entry->psz_archive_uri ) ) p_entry->psz_archive_uri = strdup( p_finder->psz_uri ); FOREACH_END() } else {
int RarParse(stream_t *s, int *count, rar_file_t ***file) { *count = 0; *file = NULL; const rar_pattern_t *pattern = FindVolumePattern(s->psz_path); int volume_offset = 0; char *volume_mrl; if (asprintf(&volume_mrl, "%s://%s", s->psz_access, s->psz_path) < 0) return VLC_EGENERIC; stream_t *vol = s; for (;;) { /* Skip marker & archive */ if (IgnoreBlock(vol, RAR_BLOCK_MARKER) || IgnoreBlock(vol, RAR_BLOCK_ARCHIVE)) { if (vol != s) stream_Delete(vol); free(volume_mrl); return VLC_EGENERIC; } /* */ bool has_next = false; for (;;) { rar_block_t bk; int ret; if (PeekBlock(vol, &bk)) break; switch(bk.type) { case RAR_BLOCK_END: ret = SkipEnd(vol, &bk); has_next = ret && (bk.flags & RAR_BLOCK_END_HAS_NEXT); break; case RAR_BLOCK_FILE: ret = SkipFile(vol, count, file, &bk, volume_mrl); break; default: ret = SkipBlock(vol, &bk); break; } if (ret) break; } if (vol != s) stream_Delete(vol); if (!has_next || !pattern || (*count > 0 && !(*file)[*count -1]->is_complete)) { free(volume_mrl); return VLC_SUCCESS; } /* Open next volume */ const int volume_index = pattern->start + volume_offset++; if (volume_index > pattern->stop) { free(volume_mrl); return VLC_SUCCESS; } char *volume_base; if (asprintf(&volume_base, "%s://%.*s", s->psz_access, (int)(strlen(s->psz_path) - strlen(pattern->match)), s->psz_path) < 0) { free(volume_mrl); return VLC_SUCCESS; } free(volume_mrl); if (asprintf(&volume_mrl, pattern->format, volume_base, volume_index) < 0) volume_mrl = NULL; free(volume_base); if (!volume_mrl) return VLC_SUCCESS; vol = stream_UrlNew(s, volume_mrl); if (!vol) { free(volume_mrl); return VLC_SUCCESS; } } }
static int Retrieve( addons_finder_t *p_finder, addon_entry_t *p_entry ) { if ( !p_entry->psz_archive_uri ) return VLC_EGENERIC; /* get archive and parse manifest */ stream_t *p_stream; if ( p_entry->psz_archive_uri[0] == '/' ) { /* Relative path */ char *psz_uri; if ( ! asprintf( &psz_uri, ADDONS_REPO_SCHEMEHOST"%s", p_entry->psz_archive_uri ) ) return VLC_ENOMEM; p_stream = stream_UrlNew( p_finder, psz_uri ); free( psz_uri ); } else { p_stream = stream_UrlNew( p_finder, p_entry->psz_archive_uri ); } msg_Dbg( p_finder, "downloading archive %s", p_entry->psz_archive_uri ); if ( !p_stream ) return VLC_EGENERIC; /* In case of pf_ reuse */ if ( p_finder->p_sys->psz_tempfile ) { vlc_unlink( p_finder->p_sys->psz_tempfile ); FREENULL( p_finder->p_sys->psz_tempfile ); } p_finder->p_sys->psz_tempfile = tempnam( NULL, "vlp" ); if ( !p_finder->p_sys->psz_tempfile ) { msg_Err( p_finder, "Can't create temp storage file" ); stream_Delete( p_stream ); return VLC_EGENERIC; } FILE *p_destfile = vlc_fopen( p_finder->p_sys->psz_tempfile, "w" ); if( !p_destfile ) { msg_Err( p_finder, "Failed to open addon temp storage file" ); FREENULL(p_finder->p_sys->psz_tempfile); stream_Delete( p_stream ); return VLC_EGENERIC; } char buffer[1<<10]; int i_read = 0; while ( ( i_read = stream_Read( p_stream, &buffer, 1<<10 ) ) ) { if ( fwrite( &buffer, i_read, 1, p_destfile ) < 1 ) { msg_Err( p_finder, "Failed to write to Addon file" ); fclose( p_destfile ); stream_Delete( p_stream ); return VLC_EGENERIC; } } fclose( p_destfile ); stream_Delete( p_stream ); msg_Dbg( p_finder, "Reading manifest from %s", p_finder->p_sys->psz_tempfile ); char *psz_manifest; if ( asprintf( &psz_manifest, "unzip://%s!/manifest.xml", p_finder->p_sys->psz_tempfile ) < 1 ) return VLC_ENOMEM; p_stream = stream_UrlNew( p_finder, psz_manifest ); free( psz_manifest ); int i_ret = ( ParseManifest( p_finder, p_entry, p_finder->p_sys->psz_tempfile, p_stream ) > 0 ) ? VLC_SUCCESS : VLC_EGENERIC; stream_Delete( p_stream ); return i_ret; }
/**************************************************************************** * FetchRSS (or Atom) feeds ***************************************************************************/ static rss_feed_t* FetchRSS( filter_t *p_filter ) { filter_sys_t *p_sys = p_filter->p_sys; stream_t *p_stream; xml_t *p_xml; xml_reader_t *p_xml_reader; int i_feed; /* These data are not modified after the creation of the module so we don't need to hold the lock */ int i_feeds = p_sys->i_feeds; bool b_images = p_sys->b_images; /* Allocate a new structure */ rss_feed_t *p_feeds = (rss_feed_t *)malloc( i_feeds * sizeof( rss_feed_t ) ); // sunqueen modify if( !p_feeds ) return NULL; p_xml = xml_Create( p_filter ); if( !p_xml ) { msg_Err( p_filter, "Failed to open XML parser" ); free( p_feeds ); return NULL; } /* Fetch all feeds and parse them */ for( i_feed = 0; i_feed < i_feeds; i_feed++ ) { rss_feed_t *p_feed = p_feeds + i_feed; rss_feed_t *p_old_feed = p_sys->p_feeds + i_feed; /* Initialize the structure */ p_feed->psz_title = NULL; p_feed->psz_description = NULL; p_feed->psz_link = NULL; p_feed->psz_image = NULL; p_feed->p_pic = NULL; p_feed->i_items = 0; p_feed->p_items = NULL; p_feed->psz_url = strdup( p_old_feed->psz_url ); /* Fetch the feed */ msg_Dbg( p_filter, "opening %s RSS/Atom feed ...", p_feed->psz_url ); p_stream = stream_UrlNew( p_filter, p_feed->psz_url ); if( !p_stream ) { msg_Err( p_filter, "Failed to open %s for reading", p_feed->psz_url ); p_xml_reader = NULL; goto error; } p_xml_reader = xml_ReaderCreate( p_xml, p_stream ); if( !p_xml_reader ) { msg_Err( p_filter, "Failed to open %s for parsing", p_feed->psz_url ); goto error; } /* Parse the feed */ if( !ParseFeed( p_filter, p_xml_reader, p_feed ) ) goto error; /* If we have a image: load it if requiere */ if( b_images && p_feed->psz_image && !p_feed->p_pic ) { p_feed->p_pic = LoadImage( p_filter, p_feed->psz_image ); } msg_Dbg( p_filter, "done with %s RSS/Atom feed", p_feed->psz_url ); xml_ReaderDelete( p_xml_reader ); stream_Delete( p_stream ); } xml_Delete( p_xml ); return p_feeds; error: FreeRSS( p_feeds, i_feed + 1 ); if( p_xml_reader ) xml_ReaderDelete( p_xml_reader ); if( p_stream ) stream_Delete( p_stream ); if( p_xml ) xml_Delete( p_xml ); return NULL; }
static int LoadCatalog( addons_finder_t *p_finder ) { char *psz_path; char * psz_userdir = config_GetUserDir( VLC_DATA_DIR ); if ( !psz_userdir ) return VLC_ENOMEM; if ( asprintf( &psz_path, "%s%s", psz_userdir, ADDONS_CATALOG ) < 1 ) { free( psz_userdir ); return VLC_ENOMEM; } free( psz_userdir ); addon_entry_t *p_entry = NULL; const char *p_node; int i_current_node_type; int i_ret = VLC_SUCCESS; /* attr */ const char *attr, *value; /* temp reading */ char *psz_filename = NULL; int i_filetype = -1; struct stat stat_; if ( vlc_stat( psz_path, &stat_ ) ) { free( psz_path ); return VLC_EGENERIC; } char *psz_catalog_uri = vlc_path2uri( psz_path, "file" ); free( psz_path ); if ( !psz_catalog_uri ) return VLC_EGENERIC; stream_t *p_stream = stream_UrlNew( p_finder, psz_catalog_uri ); free( psz_catalog_uri ); if (! p_stream ) return VLC_EGENERIC; xml_reader_t *p_xml_reader = xml_ReaderCreate( p_finder, p_stream ); if( !p_xml_reader ) { stream_Delete( p_stream ); return VLC_EGENERIC; } if( xml_ReaderNextNode( p_xml_reader, &p_node ) != XML_READER_STARTELEM ) { msg_Err( p_finder, "invalid catalog" ); i_ret = VLC_EGENERIC; goto end; } if ( strcmp( p_node, "videolan") ) { msg_Err( p_finder, "unsupported catalog data format" ); i_ret = VLC_EGENERIC; goto end; } while( (i_current_node_type = xml_ReaderNextNode( p_xml_reader, &p_node )) > 0 ) { switch( i_current_node_type ) { case XML_READER_STARTELEM: { if ( ! strcmp( p_node, "addon" ) ) { if ( p_entry ) /* ?!? Unclosed tag */ addon_entry_Release( p_entry ); p_entry = addon_entry_New(); //p_entry->psz_source_module = strdup( ADDONS_MODULE_SHORTCUT ); p_entry->e_flags = ADDON_MANAGEABLE; p_entry->e_state = ADDON_INSTALLED; while( (attr = xml_ReaderNextAttr( p_xml_reader, &value )) ) { if ( !strcmp( attr, "type" ) ) { p_entry->e_type = ReadType( value ); } else if ( !strcmp( attr, "id" ) ) { addons_uuid_read( value, & p_entry->uuid ); } else if ( !strcmp( attr, "downloads" ) ) { p_entry->i_downloads = atoi( value ); if ( p_entry->i_downloads < 0 ) p_entry->i_downloads = 0; } else if ( !strcmp( attr, "score" ) ) { p_entry->i_score = atoi( value ); if ( p_entry->i_score < 0 ) p_entry->i_score = 0; else if ( p_entry->i_score > ADDON_MAX_SCORE ) p_entry->i_score = ADDON_MAX_SCORE; } else if ( !strcmp( attr, "source" ) ) { p_entry->psz_source_module = strdup( value ); } else if ( !strcmp( attr, "version" ) ) { p_entry->psz_version = strdup( value ); } } break; } if ( !p_entry ) break; BINDNODE("name", p_entry->psz_name, TYPE_STRING) BINDNODE("archive", p_entry->psz_archive_uri, TYPE_STRING) BINDNODE("summary", p_entry->psz_summary, TYPE_STRING) BINDNODE("description", p_entry->psz_description, TYPE_STRING) BINDNODE("image", p_entry->psz_image_data, TYPE_STRING) BINDNODE("resource", psz_filename, TYPE_STRING) BINDNODE("creator", p_entry->psz_author, TYPE_STRING) BINDNODE("sourceurl", p_entry->psz_source_uri, TYPE_STRING) data_pointer.e_type = TYPE_NONE; if ( ! strcmp( p_node, "resource" ) ) { while( (attr = xml_ReaderNextAttr( p_xml_reader, &value )) ) { if ( !strcmp( attr, "type" ) ) { i_filetype = ReadType( value ); } } } break; } case XML_READER_TEXT: if ( data_pointer.e_type == TYPE_NONE || !p_entry ) break; if ( data_pointer.e_type == TYPE_STRING ) *data_pointer.u_data.ppsz = strdup( p_node ); else if ( data_pointer.e_type == TYPE_LONG ) *data_pointer.u_data.pl = atol( p_node ); else if ( data_pointer.e_type == TYPE_INTEGER ) *data_pointer.u_data.pi = atoi( p_node ); break; case XML_READER_ENDELEM: if ( !p_entry ) break; if ( ! strcmp( p_node, "addon" ) ) { /* then append entry */ ARRAY_APPEND( p_finder->entries, p_entry ); p_entry = NULL; } if ( ! strcmp( p_node, "resource" ) ) { if ( p_entry && psz_filename && i_filetype >= 0 ) { addon_file_t *p_file = malloc( sizeof(addon_file_t) ); p_file->e_filetype = i_filetype; p_file->psz_filename = psz_filename; p_file->psz_download_uri = NULL; ARRAY_APPEND( p_entry->files, p_file ); } /* reset temp */ psz_filename = NULL; i_filetype = -1; } data_pointer.e_type = TYPE_NONE; break; default: break; } } end: if ( p_entry ) /* ?!? Unclosed tag */ addon_entry_Release( p_entry ); xml_ReaderDelete( p_xml_reader ); stream_Delete( p_stream ); return i_ret; }
static int ListSkins( addons_finder_t *p_finder ) { char *psz_dir = getAddonInstallDir( ADDON_SKIN2 ); if ( !psz_dir ) return VLC_EGENERIC; char **ppsz_list = NULL; int i_count = vlc_scandir( psz_dir, &ppsz_list, ListSkin_filter, NULL ); for ( int i=0; i< i_count; i++ ) { char *psz_file = ppsz_list[i]; if( !psz_file ) break; if ( FileBelongsToManagedAddon( p_finder, ADDON_SKIN2, psz_file ) ) continue; char *psz_uri; if( asprintf( &psz_uri, "unzip://%s/%s!/theme.xml", psz_dir, psz_file ) >= 0) { int i_ret; char *psz_name = NULL; char *psz_source = NULL; stream_t *p_stream = stream_UrlNew( p_finder, psz_uri ); free( psz_uri ); if ( !p_stream ) { i_ret = VLC_EGENERIC; } else { i_ret = ParseSkins2Info( p_finder, p_stream, &psz_name, &psz_source ); if ( i_ret != VLC_SUCCESS ) { free( psz_name ); free( psz_source ); } stream_Delete( p_stream ); } addon_entry_t *p_entry = addon_entry_New(); p_entry->e_type = ADDON_SKIN2; p_entry->e_state = ADDON_INSTALLED; if ( i_ret == VLC_SUCCESS ) { p_entry->psz_name = psz_name; p_entry->psz_description = strdup("Skins2 theme"); p_entry->psz_source_uri = psz_source; } else { p_entry->e_flags |= ADDON_BROKEN; p_entry->psz_name = strdup(psz_file); p_entry->psz_description = strdup("Skins2 theme"); } ARRAY_APPEND( p_finder->entries, p_entry ); } free( psz_file ); } free( ppsz_list ); free( psz_dir ); return VLC_SUCCESS; }
/** * Get the update file and parse it * p_update has to be locked when calling this function * * \param p_update pointer to update struct * \return true if the update is valid and authenticated */ static bool GetUpdateFile( update_t *p_update ) { stream_t *p_stream = NULL; int i_major = 0; int i_minor = 0; int i_revision = 0; unsigned char extra; char *psz_version_line = NULL; char *psz_update_data = NULL; p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_STATUS_URL ); if( !p_stream ) { msg_Err( p_update->p_libvlc, "Failed to open %s for reading", UPDATE_VLC_STATUS_URL ); goto error; } const int64_t i_read = stream_Size( p_stream ); psz_update_data = malloc( i_read + 1 ); /* terminating '\0' */ if( !psz_update_data ) goto error; if( stream_Read( p_stream, psz_update_data, i_read ) != i_read ) { msg_Err( p_update->p_libvlc, "Couldn't download update file %s", UPDATE_VLC_STATUS_URL ); goto error; } psz_update_data[i_read] = '\0'; stream_Delete( p_stream ); p_stream = NULL; /* first line : version number */ char *psz_update_data_parser = psz_update_data; size_t i_len = strcspn( psz_update_data, "\r\n" ); psz_update_data_parser += i_len; while( *psz_update_data_parser == '\r' || *psz_update_data_parser == '\n' ) psz_update_data_parser++; if( !(psz_version_line = malloc( i_len + 1)) ) goto error; strncpy( psz_version_line, psz_update_data, i_len ); psz_version_line[i_len] = '\0'; p_update->release.extra = 0; switch( sscanf( psz_version_line, "%i.%i.%i%c", &i_major, &i_minor, &i_revision, &extra ) ) { case 4: p_update->release.extra = extra; case 3: p_update->release.i_major = i_major; p_update->release.i_minor = i_minor; p_update->release.i_revision = i_revision; break; default: msg_Err( p_update->p_libvlc, "Update version false formated" ); goto error; } /* second line : URL */ i_len = strcspn( psz_update_data_parser, "\r\n" ); if( i_len == 0 ) { msg_Err( p_update->p_libvlc, "Update file %s is corrupted: URL missing", UPDATE_VLC_STATUS_URL ); goto error; } if( !(p_update->release.psz_url = malloc( i_len + 1)) ) goto error; strncpy( p_update->release.psz_url, psz_update_data_parser, i_len ); p_update->release.psz_url[i_len] = '\0'; psz_update_data_parser += i_len; while( *psz_update_data_parser == '\r' || *psz_update_data_parser == '\n' ) psz_update_data_parser++; /* Remaining data : description */ i_len = strlen( psz_update_data_parser ); if( i_len == 0 ) { msg_Err( p_update->p_libvlc, "Update file %s is corrupted: description missing", UPDATE_VLC_STATUS_URL ); goto error; } if( !(p_update->release.psz_desc = malloc( i_len + 1)) ) goto error; strncpy( p_update->release.psz_desc, psz_update_data_parser, i_len ); p_update->release.psz_desc[i_len] = '\0'; /* Now that we know the status is valid, we must download its signature * to authenticate it */ signature_packet_t sign; if( download_signature( VLC_OBJECT( p_update->p_libvlc ), &sign, UPDATE_VLC_STATUS_URL ) != VLC_SUCCESS ) { msg_Err( p_update->p_libvlc, "Couldn't download signature of status file" ); goto error; } if( sign.type != BINARY_SIGNATURE && sign.type != TEXT_SIGNATURE ) { msg_Err( p_update->p_libvlc, "Invalid signature type" ); goto error; } p_update->p_pkey = (public_key_t*)malloc( sizeof( public_key_t ) ); if( !p_update->p_pkey ) goto error; if( parse_public_key( videolan_public_key, sizeof( videolan_public_key ), p_update->p_pkey, NULL ) != VLC_SUCCESS ) { msg_Err( p_update->p_libvlc, "Couldn't parse embedded public key, something went really wrong..." ); FREENULL( p_update->p_pkey ); goto error; } memcpy( p_update->p_pkey->longid, videolan_public_key_longid, 8 ); if( memcmp( sign.issuer_longid, p_update->p_pkey->longid , 8 ) != 0 ) { msg_Dbg( p_update->p_libvlc, "Need to download the GPG key" ); public_key_t *p_new_pkey = download_key( VLC_OBJECT(p_update->p_libvlc), sign.issuer_longid, videolan_public_key_longid ); if( !p_new_pkey ) { msg_Err( p_update->p_libvlc, "Couldn't download GPG key" ); FREENULL( p_update->p_pkey ); goto error; } uint8_t *p_hash = hash_sha1_from_public_key( p_new_pkey ); if( !p_hash ) { msg_Err( p_update->p_libvlc, "Failed to hash signature" ); free( p_new_pkey ); FREENULL( p_update->p_pkey ); goto error; } if( verify_signature( p_new_pkey->sig.r, p_new_pkey->sig.s, &p_update->p_pkey->key, p_hash ) == VLC_SUCCESS ) { free( p_hash ); msg_Info( p_update->p_libvlc, "Key authenticated" ); free( p_update->p_pkey ); p_update->p_pkey = p_new_pkey; } else { free( p_hash ); msg_Err( p_update->p_libvlc, "Key signature invalid !\n" ); goto error; } } uint8_t *p_hash = hash_sha1_from_text( psz_update_data, &sign ); if( !p_hash ) { msg_Warn( p_update->p_libvlc, "Can't compute SHA1 hash for status file" ); goto error; } else if( p_hash[0] != sign.hash_verification[0] || p_hash[1] != sign.hash_verification[1] ) { msg_Warn( p_update->p_libvlc, "Bad SHA1 hash for status file" ); goto error; } else if( verify_signature( sign.r, sign.s, &p_update->p_pkey->key, p_hash ) != VLC_SUCCESS ) { msg_Err( p_update->p_libvlc, "BAD SIGNATURE for status file" ); goto error; } else { msg_Info( p_update->p_libvlc, "Status file authenticated" ); return true; } error: if( p_stream ) stream_Delete( p_stream ); free( psz_version_line ); free( psz_update_data ); return false; }
static int FindVolumes(access_t *p_access, struct archive *p_archive, const char *psz_uri, char *** const pppsz_files, unsigned int * const pi_files) { VLC_UNUSED(p_archive); *pppsz_files = NULL; *pi_files = 0; static const struct { char const * const psz_match; char const * const psz_format; uint16_t i_min; uint16_t i_max; } patterns[] = { { ".part1.rar", "%.*s.part%.1d.rar", 2, 9 }, { ".part01.rar", "%.*s.part%.2d.rar", 2, 99 }, { ".part001.rar", "%.*s.part%.3d.rar", 2, 999 }, { ".001", "%.*s.%.3d", 2, 999 }, { ".000", "%.*s.%.3d", 1, 999 }, }; const int i_uri_size = strlen(psz_uri); const size_t i_patterns = ARRAY_SIZE(patterns); for (size_t i = 0; i < i_patterns; i++) { const int i_match_size = strlen(patterns[i].psz_match); if (i_uri_size < i_match_size) continue; if (!strcmp(&psz_uri[i_uri_size - i_match_size], patterns[i].psz_match)) { char **ppsz_files = xmalloc(sizeof(char *) * patterns[i].i_max); for (unsigned j = patterns[i].i_min; j < patterns[i].i_max; j++) { char *psz_newuri; if (asprintf(&psz_newuri, patterns[i].psz_format, i_uri_size - i_match_size, psz_uri, j) == -1) break; /* Probe URI */ int i_savedflags = p_access->i_flags; p_access->i_flags |= OBJECT_FLAGS_NOINTERACT; stream_t *p_stream = stream_UrlNew(p_access, psz_newuri); p_access->i_flags = i_savedflags; if (p_stream) { ppsz_files[*pi_files] = psz_newuri; (*pi_files)++; stream_Delete(p_stream); } else { free(psz_newuri); break; } } if (*pi_files == 0) FREENULL(ppsz_files); *pppsz_files = ppsz_files; return VLC_SUCCESS; } } return VLC_SUCCESS; }
/***************************************************************************** * Handshake : Init audioscrobbler connection *****************************************************************************/ static int Handshake(intf_thread_t *p_this) { char *psz_username, *psz_password; char *psz_scrobbler_url; time_t timestamp; char psz_timestamp[21]; struct md5_s p_struct_md5; stream_t *p_stream; char *psz_handshake_url; uint8_t p_buffer[1024]; char *p_buffer_pos; int i_ret; char *psz_url; intf_thread_t *p_intf = (intf_thread_t*) p_this; intf_sys_t *p_sys = p_this->p_sys; psz_username = var_InheritString(p_this, "lastfm-username"); psz_password = var_InheritString(p_this, "lastfm-password"); /* username or password have not been setup */ if (EMPTY_STR(psz_username) || EMPTY_STR(psz_password)) { free(psz_username); free(psz_password); return VLC_ENOVAR; } time(×tamp); /* generates a md5 hash of the password */ InitMD5(&p_struct_md5); AddMD5(&p_struct_md5, (uint8_t*) psz_password, strlen(psz_password)); EndMD5(&p_struct_md5); free(psz_password); char *psz_password_md5 = psz_md5_hash(&p_struct_md5); if (!psz_password_md5) { free(psz_username); return VLC_ENOMEM; } snprintf(psz_timestamp, sizeof(psz_timestamp), "%"PRIu64, (uint64_t)timestamp); /* generates a md5 hash of : * - md5 hash of the password, plus * - timestamp in clear text */ InitMD5(&p_struct_md5); AddMD5(&p_struct_md5, (uint8_t*) psz_password_md5, 32); AddMD5(&p_struct_md5, (uint8_t*) psz_timestamp, strlen(psz_timestamp)); EndMD5(&p_struct_md5); free(psz_password_md5); char *psz_auth_token = psz_md5_hash(&p_struct_md5); if (!psz_auth_token) { free(psz_username); return VLC_ENOMEM; } psz_scrobbler_url = var_InheritString(p_this, "scrobbler-url"); if (!psz_scrobbler_url) { free(psz_auth_token); free(psz_username); return VLC_ENOMEM; } i_ret = asprintf(&psz_handshake_url, "http://%s/?hs=true&p=1.2&c="CLIENT_NAME"&v="CLIENT_VERSION"&u=%s&t=%s&a=%s" , psz_scrobbler_url, psz_username, psz_timestamp, psz_auth_token); free(psz_auth_token); free(psz_scrobbler_url); free(psz_username); if (i_ret == -1) return VLC_ENOMEM; /* send the http handshake request */ p_stream = stream_UrlNew(p_intf, psz_handshake_url); free(psz_handshake_url); if (!p_stream) return VLC_EGENERIC; /* read answer */ i_ret = stream_Read(p_stream, p_buffer, sizeof(p_buffer) - 1); if (i_ret == 0) { stream_Delete(p_stream); return VLC_EGENERIC; } p_buffer[i_ret] = '\0'; stream_Delete(p_stream); p_buffer_pos = strstr((char*) p_buffer, "FAILED "); if (p_buffer_pos) { /* handshake request failed, sorry */ msg_Err(p_this, "last.fm handshake failed: %s", p_buffer_pos + 7); return VLC_EGENERIC; } if (strstr((char*) p_buffer, "BADAUTH")) { /* authentication failed, bad username/password combination */ dialog_Fatal(p_this, _("last.fm: Authentication failed"), "%s", _("last.fm username or password is incorrect. " "Please verify your settings and relaunch VLC.")); return VLC_AUDIOSCROBBLER_EFATAL; } if (strstr((char*) p_buffer, "BANNED")) { /* oops, our version of vlc has been banned by last.fm servers */ msg_Err(p_intf, "This version of VLC has been banned by last.fm. " "You should upgrade VLC, or disable the last.fm plugin."); return VLC_AUDIOSCROBBLER_EFATAL; } if (strstr((char*) p_buffer, "BADTIME")) { /* The system clock isn't good */ msg_Err(p_intf, "last.fm handshake failed because your clock is too " "much shifted. Please correct it, and relaunch VLC."); return VLC_AUDIOSCROBBLER_EFATAL; } p_buffer_pos = strstr((char*) p_buffer, "OK"); if (!p_buffer_pos) goto proto; p_buffer_pos = strstr(p_buffer_pos, "\n"); if (!p_buffer_pos || strlen(p_buffer_pos) < 33) goto proto; p_buffer_pos++; /* we skip the '\n' */ /* save the session ID */ memcpy(p_sys->psz_auth_token, p_buffer_pos, 32); p_sys->psz_auth_token[32] = '\0'; p_buffer_pos = strstr(p_buffer_pos, "http://"); if (!p_buffer_pos || strlen(p_buffer_pos) == 7) goto proto; /* We need to read the nowplaying url */ p_buffer_pos += 7; /* we skip "http://" */ #if 0 //NOT USED psz_url = strndup(p_buffer_pos, strcspn(p_buffer_pos, "\n")); if (!psz_url) goto oom; switch(ParseURL(psz_url, &p_sys->psz_nowp_host, &p_sys->psz_nowp_file, &p_sys->i_nowp_port)) { case VLC_ENOMEM: goto oom; case VLC_EGENERIC: goto proto; case VLC_SUCCESS: default: break; } #endif p_buffer_pos = strstr(p_buffer_pos, "http://"); if (!p_buffer_pos || strlen(p_buffer_pos) == 7) goto proto; /* We need to read the submission url */ p_buffer_pos += 7; /* we skip "http://" */ psz_url = strndup(p_buffer_pos, strcspn(p_buffer_pos, "\n")); if (!psz_url) goto oom; /* parse the submission url */ vlc_UrlParse(&p_sys->p_submit_url, psz_url, 0); free(psz_url); return VLC_SUCCESS; oom: return VLC_ENOMEM; proto: msg_Err(p_intf, "Handshake: can't recognize server protocol"); return VLC_EGENERIC; }
/***************************************************************************** * Open: initializes matroska demux structures *****************************************************************************/ static int Open( vlc_object_t * p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; matroska_stream_c *p_stream; matroska_segment_c *p_segment; const uint8_t *p_peek; std::string s_path, s_filename; vlc_stream_io_callback *p_io_callback; EbmlStream *p_io_stream; bool b_need_preload = false; /* peek the begining */ if( stream_Peek( p_demux->s, &p_peek, 4 ) < 4 ) return VLC_EGENERIC; /* is a valid file */ if( p_peek[0] != 0x1a || p_peek[1] != 0x45 || p_peek[2] != 0xdf || p_peek[3] != 0xa3 ) return VLC_EGENERIC; /* Set the demux function */ p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys = new demux_sys_t( *p_demux ); p_io_callback = new vlc_stream_io_callback( p_demux->s, false ); p_io_stream = new (std::nothrow) EbmlStream( *p_io_callback ); if( p_io_stream == NULL ) { msg_Err( p_demux, "failed to create EbmlStream" ); delete p_io_callback; delete p_sys; return VLC_EGENERIC; } p_stream = p_sys->AnalyseAllSegmentsFound( p_demux, p_io_stream, true ); if( p_stream == NULL ) { msg_Err( p_demux, "cannot find KaxSegment or missing mandatory KaxInfo" ); goto error; } p_sys->streams.push_back( p_stream ); p_stream->p_io_callback = p_io_callback; p_stream->p_estream = p_io_stream; for (size_t i=0; i<p_stream->segments.size(); i++) { p_stream->segments[i]->Preload(); b_need_preload |= p_stream->segments[i]->b_ref_external_segments; } p_segment = p_stream->segments[0]; if( p_segment->cluster == NULL ) { msg_Err( p_demux, "cannot find any cluster, damaged file ?" ); goto error; } if (b_need_preload && var_InheritBool( p_demux, "mkv-preload-local-dir" )) { msg_Dbg( p_demux, "Preloading local dir" ); /* get the files from the same dir from the same family (based on p_demux->psz_path) */ if ( p_demux->psz_file && !strcmp( p_demux->psz_access, "file" ) ) { // assume it's a regular file // get the directory path s_path = p_demux->psz_file; if (s_path.at(s_path.length() - 1) == DIR_SEP_CHAR) { s_path = s_path.substr(0,s_path.length()-1); } else { if (s_path.find_last_of(DIR_SEP_CHAR) > 0) { s_path = s_path.substr(0,s_path.find_last_of(DIR_SEP_CHAR)); } } DIR *p_src_dir = vlc_opendir(s_path.c_str()); if (p_src_dir != NULL) { const char *psz_file; while ((psz_file = vlc_readdir(p_src_dir)) != NULL) { if (strlen(psz_file) > 4) { s_filename = s_path + DIR_SEP_CHAR + psz_file; #if defined(_WIN32) || defined(__OS2__) if (!strcasecmp(s_filename.c_str(), p_demux->psz_file)) #else if (!s_filename.compare(p_demux->psz_file)) #endif { continue; // don't reuse the original opened file } if (!s_filename.compare(s_filename.length() - 3, 3, "mkv") || !s_filename.compare(s_filename.length() - 3, 3, "mka")) { // test whether this file belongs to our family const uint8_t *p_peek; bool file_ok = false; char *psz_url = vlc_path2uri( s_filename.c_str(), "file" ); stream_t *p_file_stream = stream_UrlNew( p_demux, psz_url ); /* peek the begining */ if( p_file_stream && stream_Peek( p_file_stream, &p_peek, 4 ) >= 4 && p_peek[0] == 0x1a && p_peek[1] == 0x45 && p_peek[2] == 0xdf && p_peek[3] == 0xa3 ) file_ok = true; if ( file_ok ) { vlc_stream_io_callback *p_file_io = new vlc_stream_io_callback( p_file_stream, true ); EbmlStream *p_estream = new EbmlStream(*p_file_io); p_stream = p_sys->AnalyseAllSegmentsFound( p_demux, p_estream ); if ( p_stream == NULL ) { msg_Dbg( p_demux, "the file '%s' will not be used", s_filename.c_str() ); delete p_estream; delete p_file_io; } else { p_stream->p_io_callback = p_file_io; p_stream->p_estream = p_estream; p_sys->streams.push_back( p_stream ); } } else { if( p_file_stream ) { stream_Delete( p_file_stream ); } msg_Dbg( p_demux, "the file '%s' cannot be opened", s_filename.c_str() ); } free( psz_url ); } } } closedir( p_src_dir ); } } p_sys->PreloadFamily( *p_segment ); } else if (b_need_preload) msg_Warn( p_demux, "This file references other files, you may want to enable the preload of local directory"); if ( !p_sys->PreloadLinked() || !p_sys->PreparePlayback( NULL ) ) { msg_Err( p_demux, "cannot use the segment" ); goto error; } p_sys->FreeUnused(); p_sys->InitUi(); return VLC_SUCCESS; error: delete p_sys; return VLC_EGENERIC; }
int RarAccessOpen(vlc_object_t *object) { access_t *access = (access_t*)object; const char *name = strchr(access->psz_location, '|'); if (name == NULL) return VLC_EGENERIC; char *base = strndup(access->psz_location, name - access->psz_location); if (unlikely(base == NULL)) return VLC_ENOMEM; name++; decode_URI(base); stream_t *s = stream_UrlNew(access, base); if (!s || RarProbe(s)) goto error; struct { int filescount; rar_file_t **files; unsigned int i_nbvols; } newscheme = { 0, NULL, 0 }, oldscheme = { 0, NULL, 0 }, *p_scheme; if (RarParse(s, &newscheme.filescount, &newscheme.files, &newscheme.i_nbvols, false) || newscheme.filescount < 1 || newscheme.i_nbvols < 2 ) { /* We might want to lookup old naming scheme, could be a part1.rar,part1.r00 */ stream_Seek(s, 0); RarParse(s, &oldscheme.filescount, &oldscheme.files, &oldscheme.i_nbvols, true); } if (oldscheme.filescount >= newscheme.filescount && oldscheme.i_nbvols > newscheme.i_nbvols) { for (int i = 0; i < newscheme.filescount; i++) RarFileDelete(newscheme.files[i]); free(newscheme.files); p_scheme = &oldscheme; msg_Dbg(s, "using rar old naming for %d files nbvols %u", p_scheme->filescount, oldscheme.i_nbvols); } else if (newscheme.filescount) { for (int i = 0; i < oldscheme.filescount; i++) RarFileDelete(oldscheme.files[i]); free(oldscheme.files); p_scheme = &newscheme; msg_Dbg(s, "using rar new naming for %d files nbvols %u", p_scheme->filescount, oldscheme.i_nbvols); } else { msg_Info(s, "Invalid or unsupported RAR archive"); for (int i = 0; i < oldscheme.filescount; i++) RarFileDelete(oldscheme.files[i]); free(oldscheme.files); for (int i = 0; i < newscheme.filescount; i++) RarFileDelete(newscheme.files[i]); free(newscheme.files); goto error; } rar_file_t *file = NULL; for (int i = 0; i < p_scheme->filescount; i++) { if (!file && !strcmp(p_scheme->files[i]->name, name)) file = p_scheme->files[i]; else RarFileDelete(p_scheme->files[i]); } free(p_scheme->files); if (!file) goto error; access_sys_t *sys = access->p_sys = malloc(sizeof(*sys)); sys->s = s; sys->file = file; access->pf_read = Read; access->pf_block = NULL; access->pf_control = Control; access->pf_seek = Seek; access_InitFields(access); rar_file_chunk_t dummy = { .mrl = base, }; sys->chunk = &dummy; Seek(access, 0); free(base); return VLC_SUCCESS; error: if (s) stream_Delete(s); free(base); return VLC_EGENERIC; }
int DoAcoustIdWebRequest( vlc_object_t *p_obj, acoustid_fingerprint_t *p_data ) { int i_ret; int i_status; struct webrequest_t request = { NULL, NULL, NULL }; if ( !p_data->psz_fingerprint ) return VLC_SUCCESS; i_ret = asprintf( & request.psz_url, "http://fingerprint.videolan.org/acoustid.php?meta=recordings+tracks+usermeta+releases&duration=%d&fingerprint=%s", p_data->i_duration, p_data->psz_fingerprint ); if ( i_ret < 1 ) return VLC_EGENERIC; vlc_cleanup_push( cancelDoAcoustIdWebRequest, &request ); msg_Dbg( p_obj, "Querying AcoustID from %s", request.psz_url ); request.p_stream = stream_UrlNew( p_obj, request.psz_url ); if ( !request.p_stream ) { i_status = VLC_EGENERIC; goto cleanup; } /* read answer */ i_ret = 0; for( ;; ) { int i_read = 65536; if( i_ret >= INT_MAX - i_read ) break; request.p_buffer = realloc_or_free( request.p_buffer, 1 + i_ret + i_read ); if( !request.p_buffer ) { i_status = VLC_ENOMEM; goto cleanup; } i_read = stream_Read( request.p_stream, &request.p_buffer[i_ret], i_read ); if( i_read <= 0 ) break; i_ret += i_read; } stream_Delete( request.p_stream ); request.p_stream = NULL; request.p_buffer[ i_ret ] = 0; int i_canc = vlc_savecancel(); if ( ParseJson( p_obj, request.p_buffer, & p_data->results ) ) { msg_Dbg( p_obj, "results count == %d", p_data->results.count ); } else { msg_Dbg( p_obj, "No results" ); } vlc_restorecancel( i_canc ); i_status = VLC_SUCCESS; cleanup: vlc_cleanup_run( ); return i_status; }
int RarParse(stream_t *s, int *count, rar_file_t ***file, unsigned int *pi_nbvols, bool b_extonly) { *count = 0; *file = NULL; *pi_nbvols = 1; if( s->psz_url == NULL ) return VLC_EGENERIC; const rar_pattern_t *pattern = FindVolumePattern(s->psz_url, b_extonly); int volume_offset = 0; char *volume_mrl = strdup(s->psz_url); if (volume_mrl == NULL) return VLC_ENOMEM; stream_t *vol = s; for (;;) { /* Skip marker & archive */ if (IgnoreBlock(vol, RAR_BLOCK_MARKER) || IgnoreBlock(vol, RAR_BLOCK_ARCHIVE)) { if (vol != s) stream_Delete(vol); free(volume_mrl); return VLC_EGENERIC; } /* */ int has_next = -1; for (;;) { rar_block_t bk; int ret; if (PeekBlock(vol, &bk)) break; switch(bk.type) { case RAR_BLOCK_END: ret = SkipEnd(vol, &bk); has_next = ret && (bk.flags & RAR_BLOCK_END_HAS_NEXT); break; case RAR_BLOCK_FILE: ret = SkipFile(vol, count, file, &bk, volume_mrl); break; default: ret = SkipBlock(vol, &bk); break; } if (ret) break; } if (has_next < 0 && *count > 0 && !(*file)[*count -1]->is_complete) has_next = 1; if (vol != s) stream_Delete(vol); free(volume_mrl); if (!has_next || !pattern) return VLC_SUCCESS; /* Open next volume */ const int volume_index = pattern->start + volume_offset++; if (volume_index > pattern->stop) return VLC_SUCCESS; char *volume_base = strndup(s->psz_url, strlen(s->psz_url) - strlen(pattern->match)); if (volume_base == NULL) return VLC_SUCCESS; if (pattern->start) { if (asprintf(&volume_mrl, pattern->format, volume_base, volume_index) < 0) volume_mrl = NULL; } else { if (asprintf(&volume_mrl, pattern->format, volume_base, 'r' + volume_index / 100, volume_index % 100) < 0) volume_mrl = NULL; } free(volume_base); if (!volume_mrl) return VLC_SUCCESS; const int s_flags = s->i_flags; s->i_flags |= OBJECT_FLAGS_NOINTERACT; vol = stream_UrlNew(s, volume_mrl); s->i_flags = s_flags; if (!vol) { free(volume_mrl); return VLC_SUCCESS; } (*pi_nbvols)++; } }