/***************************************************************************** * Local functions *****************************************************************************/ static int ChunkFind( demux_t *p_demux, const char *fcc, unsigned int *pi_size ) { const uint8_t *p_peek; for( ;; ) { uint32_t i_size; if( stream_Peek( p_demux->s, &p_peek, 8 ) < 8 ) { msg_Err( p_demux, "cannot peek" ); return VLC_EGENERIC; } i_size = GetDWLE( p_peek + 4 ); msg_Dbg( p_demux, "chunk: fcc=`%4.4s` size=%"PRIu32, p_peek, i_size ); if( !memcmp( p_peek, fcc, 4 ) ) { if( pi_size ) { *pi_size = i_size; } return VLC_SUCCESS; } /* Skip chunk */ if( stream_Read( p_demux->s, NULL, 8 ) != 8 || stream_Read( p_demux->s, NULL, i_size ) != (int)i_size || ( (i_size & 1) && stream_Read( p_demux->s, NULL, 1 ) != 1 ) ) return VLC_EGENERIC; } }
int main(void) { ssize_t val; char buf[16]; bool b; test_init(); vlc = libvlc_new(0, NULL); assert(vlc != NULL); parent = VLC_OBJECT(vlc->p_libvlc_int); s = vlc_stream_fifo_New(parent); assert(s != NULL); val = stream_Control(s, STREAM_CAN_SEEK, &b); assert(val == VLC_SUCCESS && !b); val = stream_GetSize(s, &(uint64_t){ 0 }); assert(val < 0); val = stream_Control(s, STREAM_GET_PTS_DELAY, &(int64_t){ 0 }); assert(val == VLC_SUCCESS); stream_Delete(s); vlc_stream_fifo_Close(s); s = vlc_stream_fifo_New(parent); assert(s != NULL); val = vlc_stream_fifo_Write(s, "123", 3); vlc_stream_fifo_Close(s); val = stream_Read(s, buf, sizeof (buf)); assert(val == 3); assert(memcmp(buf, "123", 3) == 0); val = stream_Read(s, buf, sizeof (buf)); assert(val == 0); stream_Delete(s); s = vlc_stream_fifo_New(parent); assert(s != NULL); val = vlc_stream_fifo_Write(s, "Hello ", 6); assert(val == 6); val = vlc_stream_fifo_Write(s, "world!\n", 7); assert(val == 7); val = vlc_stream_fifo_Write(s, "blahblah", 8); assert(val == 8); val = stream_Read(s, buf, 13); assert(val == 13); assert(memcmp(buf, "Hello world!\n", 13) == 0); stream_Delete(s); val = vlc_stream_fifo_Write(s, "cough cough", 11); assert(val == -1 && errno == EPIPE); vlc_stream_fifo_Close(s); libvlc_release(vlc); return 0; }
static int SkipEnd(stream_t *s, const rar_block_t *hdr) { if (!(hdr->flags & RAR_BLOCK_END_HAS_NEXT)) return VLC_EGENERIC; if (SkipBlock(s, hdr)) return VLC_EGENERIC; /* Now, we need to look for a marker block, * It seems that there is garbage at EOF */ for (;;) { const uint8_t *peek; if (stream_Peek(s, &peek, rar_marker_size) < rar_marker_size) return VLC_EGENERIC; if (!memcmp(peek, rar_marker, rar_marker_size)) break; if (stream_Read(s, NULL, 1) != 1) return VLC_EGENERIC; } /* Skip marker and archive blocks */ if (IgnoreBlock(s, RAR_BLOCK_MARKER)) return VLC_EGENERIC; if (IgnoreBlock(s, RAR_BLOCK_ARCHIVE)) return VLC_EGENERIC; return VLC_SUCCESS; }
static ssize_t SkipCallback(struct archive *p_archive, void *p_object, ssize_t i_request) { 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; ssize_t i_skipped = 0; /* be smart as small seeks converts to reads */ if (p_sys->b_source_canseek) { int64_t i_pos = stream_Tell(p_sys->p_stream); if (i_pos >=0) stream_Seek(p_sys->p_stream, i_pos + i_request); i_skipped = stream_Tell(p_sys->p_stream) - i_pos; } else while(i_request) { int i_skip = __MIN(INT32_MAX, i_request); int i_read = stream_Read(p_sys->p_stream, NULL, i_skip); if (i_read > 0) i_skipped += i_read; else break; i_request -= i_read; } return i_skipped; }
static int64_t get_data( demux_t *p_demux, int64_t i_bytes_to_read ) { demux_sys_t *p_sys = p_demux->p_sys; char *buf; int64_t i_result; if ( p_sys->i_total_length > 0 ) { if ( p_sys->i_input_position + i_bytes_to_read > p_sys->i_total_length ) { i_bytes_to_read = p_sys->i_total_length - p_sys->i_input_position; if ( i_bytes_to_read <= 0 ) { return 0; } } } seek_byte ( p_demux, p_sys->i_input_position ); buf = ogg_sync_buffer( &p_sys->oy, i_bytes_to_read ); i_result = stream_Read( p_demux->s, buf, i_bytes_to_read ); p_sys->b_page_waiting = false; ogg_sync_wrote( &p_sys->oy, i_result ); return i_result; }
/***************************************************************************** * Demux: reads and demuxes data packets ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, 1 otherwise *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; int i_data; /* I'm pretty sure that stream_Peek,stream_Read( , NULL ) would be faster*/ i_data = stream_Read( p_demux->s, p_sys->buffer, DUMP_BLOCKSIZE ); if ( i_data <= 0 ) return i_data; i_data = fwrite( p_sys->buffer, 1, i_data, p_sys->p_file ); if( i_data == 0 ) { msg_Err( p_demux, "failed to write data" ); return -1; } #if 0 msg_Dbg( p_demux, "dumped %d bytes", i_data ); #endif p_sys->i_write += i_data; return 1; }
static ssize_t Read(access_t *access, uint8_t *data, size_t size) { access_sys_t *sys = access->p_sys; size_t total = 0; while (total < size) { const uint64_t chunk_end = sys->chunk->cummulated_size + sys->chunk->size; int max = __MIN(__MIN((int64_t)(size - total), (int64_t)(chunk_end - access->info.i_pos)), INT_MAX); if (max <= 0) break; int r = sys->s ? stream_Read(sys->s, data, max) : -1; if (r <= 0) break; total += r; if( data ) data += r; access->info.i_pos += r; if (access->info.i_pos >= chunk_end && Seek(access, access->info.i_pos)) break; } if (size > 0 && total <= 0) access->info.b_eof = true; return total; }
/** ************************************************************************** * \brief read something from stream into buffer * \param opaque should be the stream * \param stream stream created by ZipIO_Open * \param buf buffer to read the file * \param size length of this buffer * \return return the number of bytes read (<= size) *****************************************************************************/ static unsigned long ZCALLBACK ZipIO_Read( void *opaque, void *stream, void *buf, unsigned long size ) { (void) stream; stream_t *s = (stream_t*) opaque; return (unsigned long) stream_Read( s->p_source, buf, (int) size ); }
uint32 vlc_stream_io_callback::read( void *p_buffer, size_t i_size ) { if( i_size <= 0 || mb_eof ) return 0; return stream_Read( s, p_buffer, i_size ); }
static block_t *Load(demux_t *demux) { const unsigned max_size = 4096 * 4096 * 8; uint64_t size; if (stream_GetSize(demux->s, &size) == VLC_SUCCESS) { if (size > max_size) { msg_Err(demux, "image too large (%"PRIu64" > %u), rejected", size, max_size); return NULL; } } else size = max_size; block_t *block = block_Alloc(size); if (block == NULL) return NULL; ssize_t val = stream_Read(demux->s, block->p_buffer, size); if (val < 0) { block_Release(block); return NULL; } block->i_buffer = val; return block; }
/** 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 AStreamRefillStream(stream_t *s) { stream_sys_t *sys = s->p_sys; stream_track_t *tk = &sys->tk[sys->i_tk]; /* We read but won't increase i_start after initial start + offset */ int i_toread = __MIN(sys->i_used, STREAM_CACHE_TRACK_SIZE - (tk->i_end - tk->i_start - sys->i_offset)); if (i_toread <= 0) return VLC_SUCCESS; /* EOF */ #ifdef STREAM_DEBUG msg_Dbg(s, "AStreamRefillStream: used=%d toread=%d", sys->i_used, i_toread); #endif mtime_t start = mdate(); while (i_toread > 0) { int i_off = tk->i_end % STREAM_CACHE_TRACK_SIZE; int i_read; if (vlc_killed()) return VLC_EGENERIC; i_read = __MIN(i_toread, STREAM_CACHE_TRACK_SIZE - i_off); i_read = stream_Read(s->p_source, &tk->p_buffer[i_off], i_read); /* msg_Dbg(s, "AStreamRefillStream: read=%d", i_read); */ if (i_read < 0) { continue; } else if (i_read == 0) return VLC_SUCCESS; /* Update end */ tk->i_end += i_read; /* Windows of STREAM_CACHE_TRACK_SIZE */ if (tk->i_start + STREAM_CACHE_TRACK_SIZE < tk->i_end) { unsigned i_invalid = tk->i_end - tk->i_start - STREAM_CACHE_TRACK_SIZE; tk->i_start += i_invalid; sys->i_offset -= i_invalid; } i_toread -= i_read; sys->i_used -= i_read; sys->stat.i_bytes += i_read; sys->stat.i_read_count++; } sys->stat.i_read_time += mdate() - start; return VLC_SUCCESS; }
static gme_err_t ReaderStream (void *data, void *buf, int length) { stream_t *s = data; if (stream_Read (s, buf, length) < length) return "short read"; return NULL; }
uint32 vlc_stream_io_callback::read( void *p_buffer, size_t i_size ) { if( i_size <= 0 || mb_eof ) return 0; int i_ret = stream_Read( s, p_buffer, i_size ); return i_ret < 0 ? 0 : i_ret; }
static void *Thread (void *data) { stream_t *stream = data; stream_sys_t *p_sys = stream->p_sys; #ifdef HAVE_VMSPLICE ssize_t page_mask = sysconf (_SC_PAGE_SIZE) - 1; #endif int fd = p_sys->write_fd; bool error = false; do { ssize_t len; int canc = vlc_savecancel (); #ifdef HAVE_VMSPLICE unsigned char *buf = mmap (NULL, bufsize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); vlc_cleanup_push (cleanup_mmap, buf); #else unsigned char buf[bufsize]; #endif len = stream_Read (stream->p_source, buf, bufsize); vlc_restorecancel (canc); error = len <= 0; for (ssize_t i = 0, j; i < len; i += j) { #ifdef HAVE_VMSPLICE if ((len - i) <= page_mask) /* incomplete last page */ j = write (fd, buf + i, len - i); else { struct iovec iov = { buf + i, (len - i) & ~page_mask, }; j = vmsplice (fd, &iov, 1, SPLICE_F_GIFT); } if (j == -1 && errno == ENOSYS) /* vmsplice() not supported */ #endif j = write (fd, buf + i, len - i); if (j <= 0) { if (j == 0) errno = EPIPE; msg_Err (stream, "cannot write data (%m)"); error = true; break; } } #ifdef HAVE_VMSPLICE vlc_cleanup_run (); /* munmap (buf, bufsize) */ #endif } while (!error); msg_Dbg (stream, "compressed stream at EOF"); return NULL; }
static ssize_t ReadCallback(struct archive *p_archive, void *p_object, const void **pp_buffer) { 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; *pp_buffer = &p_sys->buffer; return stream_Read(p_sys->p_stream, &p_sys->buffer, ARCHIVE_READ_SIZE); }
static int vlclua_demux_read( lua_State *L ) { demux_t *p_demux = (demux_t *)vlclua_get_this( L ); const uint8_t *p_read; int n = luaL_checkint( L, 1 ); int i_read = stream_Peek( p_demux->s, &p_read, n ); lua_pushlstring( L, (const char *)p_read, i_read ); int i_seek = stream_Read( p_demux->s, NULL, i_read ); assert(i_read==i_seek); return 1; }
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 SkipBlock(stream_t *s, const rar_block_t *hdr) { uint64_t size = (uint64_t)hdr->size + hdr->add_size; while (size > 0) { int skip = __MIN(size, INT_MAX); if (stream_Read(s, NULL, skip) < skip) return VLC_EGENERIC; size -= skip; } return VLC_SUCCESS; }
/***************************************************************************** * Demux: reads and demuxes data packets ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, 1 otherwise *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; block_t *p_block; mtime_t i_pcr = date_Get( &p_sys->pcr ); /* Call the pace control */ es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + i_pcr ); if( p_sys->b_y4m ) { /* Skip the frame header */ /* Skip "FRAME" */ if( stream_Read( p_demux->s, NULL, 5 ) < 5 ) return 0; /* Find \n */ for( ;; ) { uint8_t b; if( stream_Read( p_demux->s, &b, 1 ) < 1 ) return 0; if( b == 0x0a ) break; } } if( ( p_block = stream_Block( p_demux->s, p_sys->frame_size ) ) == NULL ) { /* EOF */ return 0; } p_block->i_dts = p_block->i_pts = VLC_TS_0 + i_pcr; es_out_Send( p_demux->out, p_sys->p_es_video, p_block ); date_Increment( &p_sys->pcr, 1 ); return 1; }
static void AStreamPrebufferStream(stream_t *s) { stream_sys_t *sys = s->p_sys; mtime_t start = mdate(); bool first = true; msg_Dbg(s, "starting pre-buffering"); for (;;) { stream_track_t *tk = &sys->tk[sys->i_tk]; mtime_t now = mdate(); int i_read; int i_buffered = tk->i_end - tk->i_start; if (vlc_killed() || i_buffered >= STREAM_CACHE_PREBUFFER_SIZE) { int64_t i_byterate; /* Update stat */ sys->stat.i_bytes = i_buffered; sys->stat.i_read_time = now - start; i_byterate = (CLOCK_FREQ * sys->stat.i_bytes) / (sys->stat.i_read_time+1); msg_Dbg(s, "pre-buffering done %"PRId64" bytes in %"PRId64"s - " "%"PRId64" KiB/s", sys->stat.i_bytes, sys->stat.i_read_time / CLOCK_FREQ, i_byterate / 1024); break; } i_read = STREAM_CACHE_TRACK_SIZE - i_buffered; i_read = __MIN((int)sys->i_read_size, i_read); i_read = stream_Read(s->p_source, &tk->p_buffer[i_buffered], i_read); if (i_read < 0) continue; else if (i_read == 0) break; /* EOF */ if (first) { msg_Dbg(s, "received first data after %"PRId64" ms", (mdate() - start) / 1000); first = false; } tk->i_end += i_read; sys->stat.i_read_count++; } }
static int vlclua_stream_read( lua_State *L ) { int i_read; stream_t **pp_stream = (stream_t **)luaL_checkudata( L, 1, "stream" ); int n = luaL_checkint( L, 2 ); uint8_t *p_read = malloc( n ); if( !p_read ) return vlclua_error( L ); i_read = stream_Read( *pp_stream, p_read, n ); if( i_read > 0 ) lua_pushlstring( L, (const char *)p_read, i_read ); else lua_pushnil( L ); free( p_read ); return 1; }
/** * Reads MIDI variable length (7, 14, 21 or 28 bits) integer. * @return read value, or -1 on EOF/error. */ static int32_t ReadVarInt (stream_t *s) { uint32_t val = 0; uint8_t byte; for (unsigned i = 0; i < 4; i++) { if (stream_Read (s, &byte, 1) < 1) return -1; val = (val << 7) | (byte & 0x7f); if ((byte & 0x80) == 0) return val; } return -1; }
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; }
OBJECT_ID ic_file_readline(VM_ID vm,TUPLE_ID locals,TUPLE_ID kw_locals) { OBJECT_ID self = tuple_GetItem(locals,0); UNICODE_ID file_name = obj_CreateUnicode(mem_create_string("__file__")); OBJECT_ID file_tag_id = obj_GetAttribute(self,file_name); obj_IncRefCount(file_name); obj_DecRefCount(file_name); tag_object *file_tag = (tag_object*)mem_lock(file_tag_id); if(file_tag->type == TYPE_TAG && file_tag->tag != 0); { MEM_ID buf_id = mem_create_buf(512); char *buf = (char*)mem_lock(buf_id); INDEX i = 0; while(i<512) { if(!stream_Read(file_tag->tag,buf_id,i,1)) { break; } if(buf[i] == '\n') { break; } i++; } if(i>0) { buf[i] = 0; UNICODE_ID line = obj_CreateUnicode(mem_create_string(buf)); mem_unlock(buf_id,1); mem_free(buf_id); mem_unlock(file_tag_id,0); return(line); } mem_unlock(buf_id,1); mem_free(buf_id); mem_unlock(file_tag_id,0); } OBJECT_ID tmp = obj_CreateEmpty(TYPE_NONE); return(tmp); }
/**************************************************************************** * Stream filters functions ****************************************************************************/ static int Read( stream_t *s, void *p_read, unsigned int i_read ) { stream_sys_t *p_sys = s->p_sys; void *p_record = p_read; /* Allocate a temporary buffer for record when no p_read */ if( p_sys->f && !p_record ) p_record = malloc( i_read ); /* */ const int i_record = stream_Read( s->p_source, p_record, i_read ); /* Dump read data */ if( p_sys->f ) { if( p_record && i_record > 0 ) Write( s, p_record, i_record ); if( !p_read ) free( p_record ); } return i_record; }
/** * Copy data from input stream to dump file. */ static int Demux( demux_t *p_demux ) { sout_access_out_t *out = (void *)p_demux->p_sys; block_t *block = block_Alloc( DUMP_BLOCKSIZE ); if( unlikely(block == NULL) ) return -1; int rd = stream_Read( p_demux->s, block->p_buffer, DUMP_BLOCKSIZE ); if ( rd <= 0 ) { block_Release( block ); return rd; } block->i_buffer = rd; size_t wr = sout_AccessOutWrite( out, block ); if( wr != (size_t)rd ) { msg_Err( p_demux, "cannot write data" ); return -1; } return 1; }
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; }
/** * 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 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; }