From: Laurent Aimar Date: Mon, 26 Jan 2004 20:48:10 +0000 (+0000) Subject: * all: make stream_t using function pointers (needed to have multiple X-Git-Tag: 0.7.1~321 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=f3f41176e52db3dd759be7af6a6bafe80e39087a;p=vlc * all: make stream_t using function pointers (needed to have multiple implementations, not yet used). --- diff --git a/include/input_ext-intf.h b/include/input_ext-intf.h index 04d522307e..fb9f2cbb1f 100644 --- a/include/input_ext-intf.h +++ b/include/input_ext-intf.h @@ -4,7 +4,7 @@ * control the pace of reading. ***************************************************************************** * Copyright (C) 1999, 2000, 2003 VideoLAN - * $Id: input_ext-intf.h,v 1.102 2003/12/03 13:27:51 rocky Exp $ + * $Id: input_ext-intf.h,v 1.103 2004/01/26 20:48:09 fenrir Exp $ * * Authors: Christophe Massiot * @@ -26,6 +26,7 @@ #ifndef _VLC_INPUT_EXT_INTF_H #define _VLC_INPUT_EXT_INTF_H 1 +#include "vlc_block.h" #include "ninput.h" /* @@ -237,9 +238,8 @@ struct stream_descriptor_t int b_new_mute; /* int because it can be -1 */ vlc_cond_t stream_wait; /* interface -> input in case of a * status change request */ - /* Demultiplexer data */ - stream_sys_t * p_demux_data; + void * p_demux_data; /* Programs descriptions */ unsigned int i_pgrm_number; /* size of the following array */ diff --git a/include/input_ext-plugins.h b/include/input_ext-plugins.h index 5995a7f4f8..60ad034215 100644 --- a/include/input_ext-plugins.h +++ b/include/input_ext-plugins.h @@ -3,7 +3,7 @@ * but exported to plug-ins ***************************************************************************** * Copyright (C) 1999-2002 VideoLAN - * $Id: input_ext-plugins.h,v 1.46 2003/11/30 22:47:55 gbazin Exp $ + * $Id: input_ext-plugins.h,v 1.47 2004/01/26 20:48:09 fenrir Exp $ * * Authors: Christophe Massiot * @@ -71,6 +71,9 @@ void input_EscapeAudioDiscontinuity( input_thread_t * ); es_out_t *input_EsOutNew( input_thread_t * ); void input_EsOutDelete( es_out_t * ); +stream_t *input_StreamNew( input_thread_t * ); +void input_StreamDelete( stream_t * ); + /***************************************************************************** * Prototypes from input_clock.c *****************************************************************************/ diff --git a/include/ninput.h b/include/ninput.h index 47ca07a70a..6b07c8f53b 100644 --- a/include/ninput.h +++ b/include/ninput.h @@ -2,7 +2,7 @@ * ninput.h ***************************************************************************** * Copyright (C) 1999-2001 VideoLAN - * $Id: ninput.h,v 1.25 2004/01/21 17:01:54 fenrir Exp $ + * $Id: ninput.h,v 1.26 2004/01/26 20:48:09 fenrir Exp $ * * Authors: Laurent Aimar * @@ -121,41 +121,121 @@ enum stream_query_e STREAM_GET_MTU, /**< arg1= int * res=cannot fail (0 if no sense)*/ }; -/* Stream */ -VLC_EXPORT( stream_t *, stream_OpenInput, ( input_thread_t * ) ); -VLC_EXPORT( void, stream_Release, ( stream_t * ) ); -VLC_EXPORT( int, stream_vaControl, ( stream_t *, int i_query, va_list ) ); -VLC_EXPORT( int, stream_Control, ( stream_t *, int i_query, ... ) ); -VLC_EXPORT( int, stream_Read, ( stream_t *, void *p_read, int i_read ) ); -VLC_EXPORT( int, stream_Peek, ( stream_t *, uint8_t **pp_peek, int i_peek ) ); -VLC_EXPORT( char *, stream_ReadLine, ( stream_t * ) ); -VLC_EXPORT( block_t *, stream_Block, ( stream_t *, int i_size ) ); +/** + * stream_t definition + */ +struct stream_t +{ + VLC_COMMON_MEMBERS + + block_t *(*pf_block) ( stream_t *, int i_size ); + int (*pf_read) ( stream_t *, void *p_read, int i_read ); + int (*pf_peek) ( stream_t *, uint8_t **pp_peek, int i_peek ); + int (*pf_control)( stream_t *, int i_query, va_list ); + + stream_sys_t *p_sys; +}; + +/** + * Try to read "i_read" bytes into a buffer pointed by "p_read". If + * "p_read" is NULL then data are skipped instead of read. The return + * value is the real numbers of bytes read/skip. If this value is less + * than i_read that means that it's the end of the stream. + */ +static inline int stream_Read( stream_t *s, void *p_read, int i_read ) +{ + return s->pf_read( s, p_read, i_read ); +} + +/** + * Store in pp_peek a pointer to the next "i_peek" bytes in the stream + * \return The real numbers of valid bytes, if it's less + * or equal to 0, *pp_peek is invalid. + * \note pp_peek is a pointer to internal buffer and it will be invalid as + * soons as other stream_* functions are called. + * \note Due to input limitation, it could be less than i_peek without meaning + * the end of the stream (but only when you have i_peek >= + * p_input->i_bufsize) + */ +static inline int stream_Peek( stream_t *s, uint8_t **pp_peek, int i_peek ) +{ + return s->pf_peek( s, pp_peek, i_peek ); +} -static int64_t inline stream_Tell( stream_t *s ) +/** + * Use to control the "stream_t *". Look at #stream_query_e for + * possible "i_query" value and format arguments. Return VLC_SUCCESS + * if ... succeed ;) and VLC_EGENERIC if failed or unimplemented + */ +static inline int stream_vaControl( stream_t *s, int i_query, va_list args ) +{ + return s->pf_control( s, i_query, args ); +} +static inline int stream_Control( stream_t *s, int i_query, ... ) +{ + va_list args; + int i_result; + + va_start( args, i_query ); + i_result = s->pf_control( s, i_query, args ); + va_end( args ); + return i_result; +} +static inline int64_t stream_Tell( stream_t *s ) { int64_t i_pos; stream_Control( s, STREAM_GET_POSITION, &i_pos ); - return i_pos; } -static int64_t inline stream_Size( stream_t *s ) +static inline int64_t stream_Size( stream_t *s ) { int64_t i_pos; stream_Control( s, STREAM_GET_SIZE, &i_pos ); - return i_pos; } -static int inline stream_MTU( stream_t *s ) +static inline int stream_MTU( stream_t *s ) { int i_mtu; - return stream_Control( s, STREAM_GET_POSITION, &i_mtu ); + stream_Control( s, STREAM_GET_MTU, &i_mtu ); + return i_mtu; } - -static int inline stream_Seek( stream_t *s, int64_t i_pos ) +static inline int stream_Seek( stream_t *s, int64_t i_pos ) { return stream_Control( s, STREAM_SET_POSITION, i_pos ); } +/** + * Read "i_size" bytes and store them in a block_t. If less than "i_size" + * bytes are available then return what is left and if nothing is availble, + * return NULL. + */ +static inline block_t *stream_Block( stream_t *s, int i_size ) +{ + if( i_size <= 0 ) return NULL; + + if( s->pf_block ) + { + return s->pf_block( s, i_size ); + } + else + { + /* emulate block read */ + block_t *p_bk = block_New( s, i_size ); + if( p_bk ) + { + p_bk->i_buffer = stream_Read( s, p_bk->p_buffer, i_size ); + if( p_bk->i_buffer > 0 ) + { + return p_bk; + } + } + if( p_bk ) block_Release( p_bk ); + return NULL; + } +} + +VLC_EXPORT( char *, stream_ReadLine, ( stream_t * ) ); + /** * @} */ @@ -165,7 +245,6 @@ static int inline stream_Seek( stream_t *s, int64_t i_pos ) * @{ */ - struct demux_t { VLC_COMMON_MEMBERS diff --git a/include/vlc_common.h b/include/vlc_common.h index 260b4d0461..661acfe2d2 100644 --- a/include/vlc_common.h +++ b/include/vlc_common.h @@ -3,7 +3,7 @@ * Collection of useful common types and macros definitions ***************************************************************************** * Copyright (C) 1998, 1999, 2000 VideoLAN - * $Id: vlc_common.h,v 1.105 2004/01/25 21:39:37 gbazin Exp $ + * $Id: vlc_common.h,v 1.106 2004/01/26 20:48:09 fenrir Exp $ * * Authors: Samuel Hocevar * Vincent Seguin @@ -222,7 +222,6 @@ typedef struct es_sys_t es_sys_t; typedef struct pgrm_descriptor_t pgrm_descriptor_t; typedef struct pgrm_sys_t pgrm_sys_t; typedef struct stream_descriptor_t stream_descriptor_t; -typedef struct stream_sys_t stream_sys_t; /* Format */ typedef struct audio_format_t audio_format_t; @@ -232,7 +231,8 @@ typedef struct es_format_t es_format_t; typedef struct video_palette_t video_palette_t; /* NInput */ -typedef struct stream_t stream_t; +typedef struct stream_sys_t stream_sys_t; +typedef struct stream_t stream_t; typedef struct es_out_t es_out_t; typedef struct es_out_id_t es_out_id_t; typedef struct es_out_sys_t es_out_sys_t; diff --git a/src/input/input.c b/src/input/input.c index e39ecfff10..e4eb3d7f65 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -4,7 +4,7 @@ * decoders. ***************************************************************************** * Copyright (C) 1998-2004 VideoLAN - * $Id: input.c,v 1.279 2004/01/26 20:26:54 gbazin Exp $ + * $Id: input.c,v 1.280 2004/01/26 20:48:10 fenrir Exp $ * * Authors: Christophe Massiot * @@ -736,7 +736,7 @@ static int InitThread( input_thread_t * p_input ) } /* Create the stream_t facilities */ - p_input->s = stream_OpenInput( p_input ); + p_input->s = input_StreamNew( p_input ); if( p_input->s == NULL ) { /* should never occur yet */ @@ -768,7 +768,7 @@ static int InitThread( input_thread_t * p_input ) msg_Err( p_input, "no suitable demux module for `%s/%s://%s'", p_input->psz_access, p_input->psz_demux, p_input->psz_name ); - stream_Release( p_input->s ); + input_StreamDelete( p_input->s ); module_Unneed( p_input, p_input->p_access ); if ( p_input->stream.p_sout != NULL ) { @@ -945,7 +945,7 @@ static void EndThread( input_thread_t * p_input ) } /* Destroy the stream_t facilities */ - if( p_input->s ) stream_Release( p_input->s ); + if( p_input->s ) input_StreamDelete( p_input->s ); /* Destroy es out */ if( p_input->p_es_out ) input_EsOutDelete( p_input->p_es_out ); diff --git a/src/input/stream.c b/src/input/stream.c index 9e02a19341..c22aa7ecea 100644 --- a/src/input/stream.c +++ b/src/input/stream.c @@ -2,7 +2,7 @@ * stream.c ***************************************************************************** * Copyright (C) 1999-2004 VideoLAN - * $Id: stream.c,v 1.13 2004/01/25 17:16:06 zorglub Exp $ + * $Id: stream.c,v 1.14 2004/01/26 20:48:10 fenrir Exp $ * * Authors: Laurent Aimar * @@ -27,55 +27,101 @@ #include "ninput.h" -#define MAX_LINE 1024 /**************************************************************************** - * stream_* : - * XXX for now it's just a wrapper - * + * stream_ReadLine: ****************************************************************************/ - /** - * Handle to a stream. + * Read from the stream untill first newline. + * \param s Stream handle to read from + * \return A null-terminated string. This must be freed, */ -struct stream_t +/* FIXME don't use stupid MAX_LINE -> do the same than net_ReadLine */ +#define MAX_LINE 1024 +char *stream_ReadLine( stream_t *s ) { - VLC_COMMON_MEMBERS + uint8_t *p_data; + char *p_line; + int i_data; + int i = 0; + i_data = stream_Peek( s, &p_data, MAX_LINE ); + msg_Dbg( s, "i_data %d", i_data ); + while( i < i_data && p_data[i] != '\n' ) + { + i++; + } + if( i_data <= 0 ) + { + return NULL; + } + else + { + p_line = malloc( i + 1 ); + if( p_line == NULL ) + { + msg_Err( s, "out of memory" ); + return NULL; + } + i = stream_Read( s, p_line, i + 1 ); + p_line[ i - 1 ] = '\0'; + msg_Dbg( s, "found %d chars long line", i ); + return p_line; + } +} - /** pointer to the input thread */ - input_thread_t *p_input; -}; -/** - * Create a "stream_t *" from an "input_thread_t *". +/* TODO: one day we should create a special module stream + * when we would have a access wrapper, and stream filter + * (like caching, progessive, gunzip, ... ) */ -stream_t *stream_OpenInput( input_thread_t *p_input ) + +/* private stream_sys_t for input_Stream* */ +struct stream_sys_t { - stream_t *s; + input_thread_t *p_input; +}; + +/* private pf_* functions declarations */ +static int IStreamRead ( stream_t *, void *p_read, int i_read ); +static int IStreamPeek ( stream_t *, uint8_t **pp_peek, int i_peek ); +static int IStreamControl( stream_t *, int i_query, va_list ); - s = vlc_object_create( p_input, sizeof( stream_t ) ); +/**************************************************************************** + * input_StreamNew: create a wrapper for p_input access + ****************************************************************************/ +stream_t *input_StreamNew( input_thread_t *p_input ) +{ + stream_t *s = vlc_object_create( p_input, sizeof( stream_t ) ); if( s ) { - s->p_input = p_input; - } + s->pf_block = NULL; + s->pf_read = IStreamRead; + s->pf_peek = IStreamPeek; + s->pf_control= IStreamControl; + s->p_sys = malloc( sizeof( stream_sys_t ) ); + s->p_sys->p_input = p_input; + } return s; } -/** - * Destroy a previously created "stream_t *" instance. - */ -void stream_Release( stream_t *s ) +/**************************************************************************** + * input_StreamDelete: + ****************************************************************************/ +void input_StreamDelete( stream_t *s ) { + free( s->p_sys ); vlc_object_destroy( s ); } -/** - * Similar to #stream_Control(), but takes a va_list and not variable - * arguments. - */ -int stream_vaControl( stream_t *s, int i_query, va_list args ) + +/**************************************************************************** + * IStreamControl: + ****************************************************************************/ +static int IStreamControl( stream_t *s, int i_query, va_list args ) { + input_thread_t *p_input = s->p_sys->p_input; + vlc_bool_t *p_b; int64_t *p_i64, i64; int *p_int; @@ -85,34 +131,34 @@ int stream_vaControl( stream_t *s, int i_query, va_list args ) case STREAM_GET_SIZE: p_i64 = (int64_t*) va_arg( args, int64_t * ); - vlc_mutex_lock( &s->p_input->stream.stream_lock ); - *p_i64 = s->p_input->stream.p_selected_area->i_size; - vlc_mutex_unlock( &s->p_input->stream.stream_lock ); + vlc_mutex_lock( &p_input->stream.stream_lock ); + *p_i64 = p_input->stream.p_selected_area->i_size; + vlc_mutex_unlock( &p_input->stream.stream_lock ); return VLC_SUCCESS; case STREAM_CAN_SEEK: p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * ); - vlc_mutex_lock( &s->p_input->stream.stream_lock ); - *p_b = s->p_input->stream.b_seekable; - vlc_mutex_unlock( &s->p_input->stream.stream_lock ); + vlc_mutex_lock( &p_input->stream.stream_lock ); + *p_b = p_input->stream.b_seekable; + vlc_mutex_unlock( &p_input->stream.stream_lock ); return VLC_SUCCESS; case STREAM_CAN_FASTSEEK: p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * ); - vlc_mutex_lock( &s->p_input->stream.stream_lock ); - *p_b = s->p_input->stream.b_seekable && - s->p_input->stream.i_method == INPUT_METHOD_FILE; - vlc_mutex_unlock( &s->p_input->stream.stream_lock ); + vlc_mutex_lock( &p_input->stream.stream_lock ); + *p_b = p_input->stream.b_seekable && + p_input->stream.i_method == INPUT_METHOD_FILE; + vlc_mutex_unlock( &p_input->stream.stream_lock ); return VLC_SUCCESS; case STREAM_GET_POSITION: p_i64 = (int64_t*) va_arg( args, int64_t * ); - vlc_mutex_lock( &s->p_input->stream.stream_lock ); - *p_i64 = s->p_input->stream.p_selected_area->i_tell; - vlc_mutex_unlock( &s->p_input->stream.stream_lock ); + vlc_mutex_lock( &p_input->stream.stream_lock ); + *p_i64 = p_input->stream.p_selected_area->i_tell; + vlc_mutex_unlock( &p_input->stream.stream_lock ); return VLC_SUCCESS; case STREAM_SET_POSITION: @@ -120,42 +166,42 @@ int stream_vaControl( stream_t *s, int i_query, va_list args ) i64 = (int64_t) va_arg( args, int64_t ); int64_t i_skip; - vlc_mutex_lock( &s->p_input->stream.stream_lock ); + vlc_mutex_lock( &p_input->stream.stream_lock ); if( i64 < 0 || - ( s->p_input->stream.p_selected_area->i_size > 0 && - s->p_input->stream.p_selected_area->i_size < i64 ) ) + ( p_input->stream.p_selected_area->i_size > 0 && + p_input->stream.p_selected_area->i_size < i64 ) ) { - vlc_mutex_unlock( &s->p_input->stream.stream_lock ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); msg_Warn( s, "seek out of bound" ); return VLC_EGENERIC; } - i_skip = i64 - s->p_input->stream.p_selected_area->i_tell; + i_skip = i64 - p_input->stream.p_selected_area->i_tell; if( i_skip == 0 ) { - vlc_mutex_unlock( &s->p_input->stream.stream_lock ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); return VLC_SUCCESS; } - if( i_skip > 0 && i_skip < s->p_input->p_last_data - - s->p_input->p_current_data - 1 ) + if( i_skip > 0 && i_skip < p_input->p_last_data - + p_input->p_current_data - 1 ) { /* We can skip without reading/seeking */ - s->p_input->p_current_data += i_skip; - s->p_input->stream.p_selected_area->i_tell = i64; - vlc_mutex_unlock( &s->p_input->stream.stream_lock ); + p_input->p_current_data += i_skip; + p_input->stream.p_selected_area->i_tell = i64; + vlc_mutex_unlock( &p_input->stream.stream_lock ); return VLC_SUCCESS; } - vlc_mutex_unlock( &s->p_input->stream.stream_lock ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); - if( s->p_input->stream.b_seekable && - ( s->p_input->stream.i_method == INPUT_METHOD_FILE || - i_skip < 0 || i_skip >= ( s->p_input->i_mtu > 0 ? - s->p_input->i_mtu : 4096 ) ) ) + if( p_input->stream.b_seekable && + ( p_input->stream.i_method == INPUT_METHOD_FILE || + i_skip < 0 || i_skip >= ( p_input->i_mtu > 0 ? + p_input->i_mtu : 4096 ) ) ) { - input_AccessReinit( s->p_input ); - s->p_input->pf_seek( s->p_input, i64 ); + input_AccessReinit( p_input ); + p_input->pf_seek( p_input, i64 ); return VLC_SUCCESS; } @@ -172,15 +218,15 @@ int stream_vaControl( stream_t *s, int i_query, va_list args ) { int i_read; - i_read = input_SplitBuffer( s->p_input, &p_data, - __MIN( (int)s->p_input->i_bufsize, i_skip ) ); + i_read = input_SplitBuffer( p_input, &p_data, + __MIN( (int)p_input->i_bufsize, i_skip ) ); if( i_read < 0 ) { return VLC_EGENERIC; } i_skip -= i_read; - input_DeletePacket( s->p_input->p_method_data, p_data ); + input_DeletePacket( p_input->p_method_data, p_data ); if( i_read == 0 && i_skip > 0 ) { return VLC_EGENERIC; @@ -192,7 +238,7 @@ int stream_vaControl( stream_t *s, int i_query, va_list args ) case STREAM_GET_MTU: p_int = (int*) va_arg( args, int * ); - *p_int = s->p_input->i_mtu; + *p_int = p_input->i_mtu; return VLC_SUCCESS; default: @@ -201,31 +247,12 @@ int stream_vaControl( stream_t *s, int i_query, va_list args ) } } -/** - * Use to control the "stream_t *". Look at #stream_query_e for - * possible "i_query" value and format arguments. Return VLC_SUCCESS - * if ... succeed ;) and VLC_EGENERIC if failed or unimplemented - */ -int stream_Control( stream_t *s, int i_query, ... ) -{ - va_list args; - int i_result; - - va_start( args, i_query ); - i_result = stream_vaControl( s, i_query, args ); - va_end( args ); - - return i_result; -} - -/** - * Try to read "i_read" bytes into a buffer pointed by "p_read". If - * "p_read" is NULL then data are skipped instead of read. The return - * value is the real numbers of bytes read/skip. If this value is less - * than i_read that means that it's the end of the stream. - */ -int stream_Read( stream_t *s, void *p_data, int i_data ) +/**************************************************************************** + * IStreamRead: + ****************************************************************************/ +static int IStreamRead( stream_t *s, void *p_data, int i_data ) { + input_thread_t *p_input = s->p_sys->p_input; uint8_t *p = (uint8_t*)p_data; data_packet_t *p_packet; @@ -245,17 +272,17 @@ int stream_Read( stream_t *s, void *p_data, int i_data ) return i_data; } - while( i_data > 0 && !s->p_input->b_die ) + while( i_data > 0 && !p_input->b_die ) { int i_count; - i_count = input_SplitBuffer( s->p_input, &p_packet, - __MIN( i_data, (int)s->p_input->i_bufsize ) ); + i_count = input_SplitBuffer( p_input, &p_packet, + __MIN( i_data, (int)p_input->i_bufsize ) ); if( i_count <= 0 ) { if( i_count == 0 ) - input_DeletePacket( s->p_input->p_method_data, p_packet ); + input_DeletePacket( p_input->p_method_data, p_packet ); return i_read; } @@ -266,7 +293,7 @@ int stream_Read( stream_t *s, void *p_data, int i_data ) p += i_count; } - input_DeletePacket( s->p_input->p_method_data, p_packet ); + input_DeletePacket( p_input->p_method_data, p_packet ); i_data -= i_count; i_read += i_count; @@ -274,76 +301,10 @@ int stream_Read( stream_t *s, void *p_data, int i_data ) return i_read; } - -/** - * Store in pp_peek a pointer to the next "i_peek" bytes in the stream - * \return The real numbers of valid bytes, if it's less - * or equal to 0, *pp_peek is invalid. - * \note pp_peek is a pointer to internal buffer and it will be invalid as - * soons as other stream_* functions are called. - * \note Due to input limitation, it could be less than i_peek without meaning - * the end of the stream (but only when you have i_peek >= - * p_input->i_bufsize) - */ -int stream_Peek( stream_t *s, uint8_t **pp_peek, int i_peek ) -{ - return input_Peek( s->p_input, pp_peek, i_peek ); -} - -/** - * Read "i_size" bytes and store them in a block_t. If less than "i_size" - * bytes are available then return what is left and if nothing is availble, - * return NULL. - */ -block_t *stream_Block( stream_t *s, int i_size ) -{ - block_t *p_block; - - if( i_size <= 0 ) return NULL; - if( !(p_block = block_New( s->p_input, i_size ) ) ) return NULL; - - p_block->i_buffer = stream_Read( s, p_block->p_buffer, i_size ); - if( !p_block->i_buffer ) - { - block_Release( p_block ); - p_block = NULL; - } - - return p_block; -} - -/** - * Read from the stream untill first newline. - * \param s Stream handle to read from - * \return A null-terminated string. This must be freed, - */ -char *stream_ReadLine( stream_t *s ) +/**************************************************************************** + * IStreamPeek: + ****************************************************************************/ +static int IStreamPeek( stream_t *s, uint8_t **pp_peek, int i_peek ) { - uint8_t *p_data; - char *p_line; - int i_data; - int i = 0; - i_data = stream_Peek( s, &p_data, MAX_LINE ); - msg_Dbg( s->p_input, "i_data %d", i_data ); - while( i < i_data && p_data[i] != '\n' ) - { - i++; - } - if( i_data <= 0 ) - { - return NULL; - } - else - { - p_line = malloc( i + 1 ); - if( p_line == NULL ) - { - msg_Err( s->p_input, "out of memory" ); - return NULL; - } - i = stream_Read( s, p_line, i + 1 ); - p_line[ i - 1 ] = '\0'; - msg_Dbg( s->p_input, "found %d chars long line", i ); - return p_line; - } + return input_Peek( s->p_sys->p_input, pp_peek, i_peek ); }