Commit 03ed4ccc authored by Laurent Aimar's avatar Laurent Aimar

 * sub ->subtitle : converted sub.c to a 'real' demux2.
 * input.c: added basic multi-input support for subtitle.
 * avi, mp4: don't exit anymore when no es selected.
parent 4a6468f3
...@@ -900,7 +900,7 @@ VLC_ADD_PLUGINS([aout_file]) ...@@ -900,7 +900,7 @@ VLC_ADD_PLUGINS([aout_file])
VLC_ADD_PLUGINS([i420_rgb i420_yuy2 i422_yuy2 i420_ymga]) VLC_ADD_PLUGINS([i420_rgb i420_yuy2 i422_yuy2 i420_ymga])
VLC_ADD_PLUGINS([m3u playlist export sgimb]) VLC_ADD_PLUGINS([m3u playlist export sgimb])
VLC_ADD_PLUGINS([rawvideo]) VLC_ADD_PLUGINS([rawvideo])
VLC_ADD_PLUGINS([wav araw demuxsub adpcm a52sys dtssys au]) VLC_ADD_PLUGINS([wav araw subtitle adpcm a52sys dtssys au])
VLC_ADD_PLUGINS([access_file access_udp access_tcp access_http ipv4 access_mms]) VLC_ADD_PLUGINS([access_file access_udp access_tcp access_http ipv4 access_mms])
VLC_ADD_PLUGINS([access_ftp access_directory sap http]) VLC_ADD_PLUGINS([access_ftp access_directory sap http])
......
...@@ -20,3 +20,4 @@ SOURCES_pva = pva.c ...@@ -20,3 +20,4 @@ SOURCES_pva = pva.c
SOURCES_aiff = aiff.c SOURCES_aiff = aiff.c
SOURCES_sgimb = sgimb.c SOURCES_sgimb = sgimb.c
SOURCES_mjpeg = mjpeg.c SOURCES_mjpeg = mjpeg.c
SOURCES_subtitle = subtitle.c
...@@ -610,8 +610,17 @@ static int Demux_Seekable( demux_t *p_demux ) ...@@ -610,8 +610,17 @@ static int Demux_Seekable( demux_t *p_demux )
if( i_track_count <= 0 ) if( i_track_count <= 0 )
{ {
int64_t i_length = p_sys->i_length * (mtime_t)1000000;
p_sys->i_time += 25*1000; /* read 25ms */
if( i_length > 0 )
{
if( p_sys->i_time >= i_length )
return 0;
return 1;
}
msg_Warn( p_demux, "no track selected, exiting..." ); msg_Warn( p_demux, "no track selected, exiting..." );
return( 0 ); return 0;
} }
/* wait for the good time */ /* wait for the good time */
......
...@@ -528,6 +528,17 @@ static int Demux( demux_t *p_demux ) ...@@ -528,6 +528,17 @@ static int Demux( demux_t *p_demux )
if( i_track_selected <= 0 ) if( i_track_selected <= 0 )
{ {
p_sys->i_time += __MAX( p_sys->i_timescale / 10 , 1 );
if( p_sys->i_timescale > 0 )
{
int64_t i_length = (mtime_t)1000000 *
(mtime_t)p_sys->i_duration /
(mtime_t)p_sys->i_timescale;
if( MP4_GetMoviePTS( p_sys ) >= i_length )
return 0;
return 1;
}
msg_Warn( p_demux, "no track selected, exiting..." ); msg_Warn( p_demux, "no track selected, exiting..." );
return 0; return 0;
} }
......
...@@ -7,8 +7,4 @@ SOURCES_id3tag = \ ...@@ -7,8 +7,4 @@ SOURCES_id3tag = \
id3genres.h \ id3genres.h \
$(NULL) $(NULL)
SOURCES_demuxsub = \
sub.c \
sub.h \
$(NULL)
/*****************************************************************************
* sub.h
*****************************************************************************
* Copyright (C) 2001-2004 VideoLAN
* $Id$
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#include "../ps.h"
#define SUB_TYPE_MICRODVD 0x00
#define SUB_TYPE_SUBRIP 0x01
#define SUB_TYPE_SSA1 0x02
#define SUB_TYPE_SSA2_4 0x03
#define SUB_TYPE_VPLAYER 0x04
#define SUB_TYPE_SAMI 0x05
#define SUB_TYPE_SUBVIEWER 0x06
#define SUB_TYPE_VOBSUB 0x100
#define SUB_TYPE_UNKNOWN 0xffff
typedef struct subtitle_s
{
mtime_t i_start;
mtime_t i_stop;
char *psz_text;
int i_vobsub_location;
} subtitle_t;
typedef struct subtitle_demux_s
{
VLC_COMMON_MEMBERS
module_t *p_module;
int (*pf_open) ( struct subtitle_demux_s *p_sub,
input_thread_t*p_input,
char *psz_name,
mtime_t i_microsecperframe );
int (*pf_demux)( struct subtitle_demux_s *p_sub, mtime_t i_maxdate );
int (*pf_seek) ( struct subtitle_demux_s *p_sub, mtime_t i_date );
void (*pf_close)( struct subtitle_demux_s *p_sub );
/* *** private *** */
input_thread_t *p_input;
int i_sub_type;
char *psz_header;
int i_subtitle;
int i_subtitles;
subtitle_t *subtitle;
es_out_id_t *p_es;
int i_previously_selected; /* to make pf_seek */
FILE *p_vobsub_file;
mtime_t i_original_mspf;
} subtitle_demux_t;
/*****************************************************************************
* subtitle_New: Start a new subtitle demux instance (but subtitle ES isn't
* selected by default.
*****************************************************************************
* Return: NULL if failed, else a pointer on a new subtitle_demux_t.
*
* XXX: - if psz_name is NULL then --sub-file is read
* - i_microsecperframe is used only for microdvd file. (overriden
* by --sub-fps )
*
*****************************************************************************/
static inline subtitle_demux_t *subtitle_New( input_thread_t *p_input,
char *psz_name,
mtime_t i_microsecperframe )
{
subtitle_demux_t *p_sub;
p_sub = vlc_object_create( p_input, sizeof( subtitle_demux_t ) );
p_sub->psz_object_name = "subtitle demux";
vlc_object_attach( p_sub, p_input );
p_sub->p_module = module_Need( p_sub, "subtitle demux", NULL, 0 );
if( p_sub->p_module &&
p_sub->pf_open( p_sub, p_input, psz_name, i_microsecperframe ) >=0 )
{
msg_Info( p_input, "subtitle started" );
}
else
{
msg_Warn( p_input, "failed to start subtitle demux" );
vlc_object_detach( p_sub );
if( p_sub->p_module )
{
module_Unneed( p_sub, p_sub->p_module );
}
vlc_object_destroy( p_sub );
p_sub = NULL;
}
return( p_sub );
}
/*****************************************************************************
* subtitle_Demux: send subtitle to decoder from last date to i_max
*****************************************************************************/
static inline int subtitle_Demux( subtitle_demux_t *p_sub, mtime_t i_max )
{
return( p_sub->pf_demux( p_sub, i_max ) );
}
/*****************************************************************************
* subtitle_Seek: Seek to i_date
*****************************************************************************/
static inline int subtitle_Seek( subtitle_demux_t *p_sub, mtime_t i_date )
{
return( p_sub->pf_seek( p_sub, i_date ) );
}
/*****************************************************************************
* subtitle_Close: Stop ES decoder and free all memory included p_sub.
*****************************************************************************/
static inline void subtitle_Close( subtitle_demux_t *p_sub )
{
msg_Info( p_sub, "subtitle stopped" );
if( p_sub )
{
p_sub->pf_close( p_sub );
vlc_object_detach( p_sub );
if( p_sub->p_module )
{
module_Unneed( p_sub, p_sub->p_module );
}
vlc_object_destroy( p_sub );
}
}
...@@ -250,6 +250,15 @@ void input_DecoderDiscontinuity( decoder_t * p_dec ) ...@@ -250,6 +250,15 @@ void input_DecoderDiscontinuity( decoder_t * p_dec )
input_DecoderDecode( p_dec, p_null ); input_DecoderDecode( p_dec, p_null );
} }
vlc_bool_t input_DecoderEmpty( decoder_t * p_dec )
{
if( p_dec->p_owner->b_own_thread && p_dec->p_owner->p_fifo->i_depth > 0 )
{
return VLC_FALSE;
}
return VLC_TRUE;
}
#if 0 #if 0
/** /**
* Create a NULL packet for padding in case of a data loss * Create a NULL packet for padding in case of a data loss
......
...@@ -242,6 +242,21 @@ void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay ) ...@@ -242,6 +242,21 @@ void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay )
p_sys->i_spu_delay = i_delay; p_sys->i_spu_delay = i_delay;
} }
vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out )
{
es_out_sys_t *p_sys = out->p_sys;
int i;
for( i = 0; i < p_sys->i_es; i++ )
{
es_out_id_t *es = p_sys->es[i];
if( es->p_dec && !input_DecoderEmpty( es->p_dec ) )
return VLC_FALSE;
}
return VLC_TRUE;
}
/***************************************************************************** /*****************************************************************************
* *
*****************************************************************************/ *****************************************************************************/
......
...@@ -62,7 +62,8 @@ static void DecodeUrl ( char * ); ...@@ -62,7 +62,8 @@ static void DecodeUrl ( char * );
static void MRLSplit( input_thread_t *, char *, char **, char **, char ** ); static void MRLSplit( input_thread_t *, char *, char **, char **, char ** );
static input_source_t *InputSourceNew( input_thread_t *); static input_source_t *InputSourceNew( input_thread_t *);
static int InputSourceInit( input_thread_t *, input_source_t *, char * ); static int InputSourceInit( input_thread_t *, input_source_t *,
char *, char *psz_forced_demux );
static void InputSourceClean( input_thread_t *, input_source_t * ); static void InputSourceClean( input_thread_t *, input_source_t * );
static void SlaveDemux( input_thread_t *p_input ); static void SlaveDemux( input_thread_t *p_input );
...@@ -146,7 +147,6 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent, ...@@ -146,7 +147,6 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
/* Init control buffer */ /* Init control buffer */
vlc_mutex_init( p_input, &p_input->lock_control ); vlc_mutex_init( p_input, &p_input->lock_control );
p_input->i_control = 0; p_input->i_control = 0;
p_input->p_sys = NULL;
/* Parse input options */ /* Parse input options */
vlc_mutex_lock( &p_item->lock ); vlc_mutex_lock( &p_item->lock );
...@@ -444,17 +444,15 @@ static int Run( input_thread_t *p_input ) ...@@ -444,17 +444,15 @@ static int Run( input_thread_t *p_input )
if( old_val.i_time != val.i_time ) if( old_val.i_time != val.i_time )
{ {
/* TODO */
#if 0
char psz_buffer[MSTRTIME_MAX_SIZE]; char psz_buffer[MSTRTIME_MAX_SIZE];
vlc_mutex_lock( &p_input->p_item->lock ); vlc_mutex_lock( &p_input->input.p_item->lock );
p_input->p_item->i_duration = i_length; p_input->input.p_item->i_duration = i_length;
vlc_mutex_unlock( &p_input->p_item->lock ); vlc_mutex_unlock( &p_input->input.p_item->lock );
input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"), input_Control( p_input, INPUT_ADD_INFO,
_("General"), _("Duration"),
msecstotimestr( psz_buffer, i_length / 1000 ) ); msecstotimestr( psz_buffer, i_length / 1000 ) );
#endif
} }
} }
...@@ -500,7 +498,9 @@ static int Run( input_thread_t *p_input ) ...@@ -500,7 +498,9 @@ static int Run( input_thread_t *p_input )
static int Init( input_thread_t * p_input ) static int Init( input_thread_t * p_input )
{ {
char *psz; char *psz;
char *psz_subtitle;
vlc_value_t val; vlc_value_t val;
double f_fps;
/* Initialize optional stream output. (before access/demuxer) */ /* Initialize optional stream output. (before access/demuxer) */
psz = var_GetString( p_input, "sout" ); psz = var_GetString( p_input, "sout" );
...@@ -522,7 +522,7 @@ static int Init( input_thread_t * p_input ) ...@@ -522,7 +522,7 @@ static int Init( input_thread_t * p_input )
es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE ); es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
if( InputSourceInit( p_input, &p_input->input, if( InputSourceInit( p_input, &p_input->input,
p_input->input.p_item->psz_uri ) ) p_input->input.p_item->psz_uri, NULL ) )
{ {
goto error; goto error;
} }
...@@ -564,11 +564,6 @@ static int Init( input_thread_t * p_input ) ...@@ -564,11 +564,6 @@ static int Init( input_thread_t * p_input )
if( val.i_int < 0 ) if( val.i_int < 0 )
p_input->i_pts_delay -= (val.i_int * 1000); p_input->i_pts_delay -= (val.i_int * 1000);
/* Init input_thread_sys_t */
p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
p_input->p_sys->i_sub = 0;
p_input->p_sys->sub = NULL;
/* TODO: check meta data from users */ /* TODO: check meta data from users */
/* TODO: get meta data from demuxer */ /* TODO: get meta data from demuxer */
...@@ -611,8 +606,78 @@ static int Init( input_thread_t * p_input ) ...@@ -611,8 +606,78 @@ static int Init( input_thread_t * p_input )
} }
/* TODO: do subtitle loading (and slave) */ /* Load subtitles */
/* Get fps and set it if not already set */
if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_FPS, &f_fps ) &&
f_fps > 1.0 )
{
vlc_value_t fps;
if( var_Get( p_input, "sub-fps", &fps ) )
{
var_Create( p_input, "sub-fps", VLC_VAR_FLOAT| VLC_VAR_DOINHERIT );
var_SetFloat( p_input, "sub-fps", f_fps );
}
}
/* Look for and add subtitle files */
psz_subtitle = var_GetString( p_input, "sub-file" );
if( *psz_subtitle )
{
input_source_t *sub;
vlc_value_t count;
vlc_value_t list;
msg_Dbg( p_input, "forced subtitle: %s", psz_subtitle );
var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL );
/* */
sub = InputSourceNew( p_input );
if( !InputSourceInit( p_input, sub, psz_subtitle, "subtitle" ) )
{
TAB_APPEND( p_input->i_slave, p_input->slave, sub );
/* Select the ES */
if( !var_Change( p_input, "spu-es", VLC_VAR_GETLIST, &list, NULL ) )
{
if( count.i_int == 0 )
count.i_int++; /* if it was first one, there is disable too */
if( count.i_int < list.p_list->i_count )
{
input_ControlPush( p_input, INPUT_CONTROL_SET_ES, &list.p_list->p_values[count.i_int] );
}
var_Change( p_input, "spu-es", VLC_VAR_FREELIST, &list, NULL );
}
}
}
var_Get( p_input, "sub-autodetect-file", &val );
if( val.b_bool )
{
char *psz_autopath = var_GetString( p_input, "sub-autodetect-path" );
char **subs = subtitles_Detect( p_input, psz_autopath,
p_input->input.p_item->psz_uri );
input_source_t *sub;
int i;
for( i = 0; subs[i] != NULL; i++ )
{
if( strcmp( psz_subtitle, subs[i] ) )
{
sub = InputSourceNew( p_input );
if( !InputSourceInit( p_input, sub, subs[i], "subtitle" ) )
{
TAB_APPEND( p_input->i_slave, p_input->slave, sub );
}
}
free( subs[i] );
}
free( subs );
free( psz_autopath );
}
free( psz_subtitle );
/* Set up es_out */ /* Set up es_out */
es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE ); es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
...@@ -974,26 +1039,6 @@ static void End( input_thread_t * p_input ) ...@@ -974,26 +1039,6 @@ static void End( input_thread_t * p_input )
vlc_object_release( p_pl ); vlc_object_release( p_pl );
} }
/* TODO subs */
#if 0
/* Destroy subtitles demuxers */
if( p_input->p_sys )
{
for( i = 0; i < p_input->p_sys->i_sub; i++ )
{
subtitle_Close( p_input->p_sys->sub[i] );
}
if( p_input->p_sys->i_sub > 0 )
{
free( p_input->p_sys->sub );
}
}
#endif
/* Free input_thread_sys_t */
free( p_input->p_sys );
/* Tell we're dead */ /* Tell we're dead */
p_input->b_dead = VLC_TRUE; p_input->b_dead = VLC_TRUE;
} }
...@@ -1496,7 +1541,8 @@ static input_source_t *InputSourceNew( input_thread_t *p_input ) ...@@ -1496,7 +1541,8 @@ static input_source_t *InputSourceNew( input_thread_t *p_input )
* InputSourceInit: * InputSourceInit:
*****************************************************************************/ *****************************************************************************/
static int InputSourceInit( input_thread_t *p_input, static int InputSourceInit( input_thread_t *p_input,
input_source_t *in, char *psz_mrl ) input_source_t *in, char *psz_mrl,
char *psz_forced_demux )
{ {
char *psz_dup = strdup( psz_mrl ); char *psz_dup = strdup( psz_mrl );
char *psz_access; char *psz_access;
...@@ -1510,6 +1556,8 @@ static int InputSourceInit( input_thread_t *p_input, ...@@ -1510,6 +1556,8 @@ static int InputSourceInit( input_thread_t *p_input,
msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'", msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
psz_mrl, psz_access, psz_demux, psz_path ); psz_mrl, psz_access, psz_demux, psz_path );
if( psz_forced_demux && *psz_forced_demux )
psz_demux = psz_forced_demux;
/* Try access_demux if no demux given */ /* Try access_demux if no demux given */
if( *psz_access && *psz_demux == '\0' ) if( *psz_access && *psz_demux == '\0' )
...@@ -1571,7 +1619,7 @@ static int InputSourceInit( input_thread_t *p_input, ...@@ -1571,7 +1619,7 @@ static int InputSourceInit( input_thread_t *p_input,
*psz_access == '\0' && ( *psz_demux || *psz_path ) ) *psz_access == '\0' && ( *psz_demux || *psz_path ) )
{ {
free( psz_dup ); free( psz_dup );
psz_dup = strdup( in->p_item->psz_uri ); psz_dup = strdup( psz_mrl );
psz_access = ""; psz_access = "";
psz_demux = ""; psz_demux = "";
psz_path = psz_dup; psz_path = psz_dup;
...@@ -1583,8 +1631,7 @@ static int InputSourceInit( input_thread_t *p_input, ...@@ -1583,8 +1631,7 @@ static int InputSourceInit( input_thread_t *p_input,
if( in->p_access == NULL ) if( in->p_access == NULL )
{ {
msg_Err( p_input, "no suitable access module for `%s'", msg_Err( p_input, "no suitable access module for `%s'", psz_mrl );
in->p_item->psz_uri );
goto error; goto error;
} }
...@@ -1717,7 +1764,7 @@ static void SlaveDemux( input_thread_t *p_input ) ...@@ -1717,7 +1764,7 @@ static void SlaveDemux( input_thread_t *p_input )
i_ret = 0; i_ret = 0;
break; break;
} }
msg_Dbg( p_input, "slave time=%lld input=%lld", i_stime, i_time ); //msg_Dbg( p_input, "slave time=%lld input=%lld", i_stime, i_time );
if( i_stime >= i_time ) if( i_stime >= i_time )
break; break;
......
...@@ -23,9 +23,6 @@ ...@@ -23,9 +23,6 @@
#ifndef _INPUT_INTERNAL_H #ifndef _INPUT_INTERNAL_H
#define _INPUT_INTERNAL_H 1 #define _INPUT_INTERNAL_H 1
#include "../../modules/demux/util/sub.h"
enum input_control_e enum input_control_e
{ {
...@@ -60,13 +57,6 @@ enum input_control_e ...@@ -60,13 +57,6 @@ enum input_control_e
INPUT_CONTROL_SET_AUDIO_DELAY, INPUT_CONTROL_SET_AUDIO_DELAY,
INPUT_CONTROL_SET_SPU_DELAY, INPUT_CONTROL_SET_SPU_DELAY,
}; };
struct input_thread_sys_t
{
/* subtitles */
int i_sub;
subtitle_demux_t **sub;
};
/* Internal helpers */ /* Internal helpers */
static inline void input_ControlPush( input_thread_t *p_input, static inline void input_ControlPush( input_thread_t *p_input,
...@@ -114,8 +104,9 @@ stream_t *stream_AccessNew( access_t *p_access ); ...@@ -114,8 +104,9 @@ stream_t *stream_AccessNew( access_t *p_access );
void stream_AccessDelete( stream_t *s ); void stream_AccessDelete( stream_t *s );
void stream_AccessReset( stream_t *s ); void stream_AccessReset( stream_t *s );
/* Decoder FIXME make it public */ /* decoder.c FIXME make it public ?*/
void input_DecoderDiscontinuity( decoder_t * p_dec ); void input_DecoderDiscontinuity( decoder_t * p_dec );
vlc_bool_t input_DecoderEmpty( decoder_t * p_dec );
/* es_out.c */ /* es_out.c */
es_out_t *input_EsOutNew( input_thread_t * ); es_out_t *input_EsOutNew( input_thread_t * );
...@@ -123,6 +114,7 @@ void input_EsOutDelete( es_out_t * ); ...@@ -123,6 +114,7 @@ void input_EsOutDelete( es_out_t * );
es_out_id_t *input_EsOutGetFromID( es_out_t *, int i_id ); es_out_id_t *input_EsOutGetFromID( es_out_t *, int i_id );
void input_EsOutDiscontinuity( es_out_t *, vlc_bool_t b_audio ); void input_EsOutDiscontinuity( es_out_t *, vlc_bool_t b_audio );
void input_EsOutSetDelay( es_out_t *, int i_cat, int64_t ); void input_EsOutSetDelay( es_out_t *, int i_cat, int64_t );
vlc_bool_t input_EsOutDecodersEmpty( es_out_t * );
/* clock.c */ /* clock.c */
enum /* Synchro states */ enum /* Synchro states */
......
...@@ -1152,35 +1152,76 @@ static void AStreamPrebufferStream( stream_t *s ) ...@@ -1152,35 +1152,76 @@ static void AStreamPrebufferStream( stream_t *s )
* \param s Stream handle to read from * \param s Stream handle to read from
* \return A null-terminated string. This must be freed, * \return A null-terminated string. This must be freed,
*/ */
/* FIXME don't use stupid MAX_LINE -> do the same than net_ReadLine */ #define STREAM_PROBE_LINE 1024
#define MAX_LINE 1024
char *stream_ReadLine( stream_t *s ) char *stream_ReadLine( stream_t *s )
{ {
char *p_line = NULL;
int i_line = 0;
for( ;; )
{
char *psz_lf, *psz_cr;
uint8_t *p_data; uint8_t *p_data;
char *p_line;
int i_data; int i_data;
int i = 0;
i_data = stream_Peek( s, &p_data, MAX_LINE );
while( i < i_data && p_data[i] != '\n' && p_data[i] != '\r' ) int i_read;
/* Probe new data */
i_data = stream_Peek( s, &p_data, STREAM_PROBE_LINE );
if( i_data <= 0 ) /* No data */
goto exit;
/* See if there is a '\n' */
psz_lf = memchr( p_data, '\n', __MAX( i_data - 1, 1 ) );
psz_cr = memchr( p_data, '\r', __MAX( i_data - 1, 1 ) );
if( psz_lf && !psz_cr && p_data[i_data-1] == '\r' )
{ {
i++; psz_cr = &p_data[i_data-1];
} }
if( i_data <= 0 ) if( psz_cr && !psz_lf && p_data[i_data-1] == '\n' )
{ {
return NULL; psz_lf = &p_data[i_data-1];
} }
else
if( psz_lf || psz_cr )
{ {
p_line = malloc( i + 1 ); char *psz;
if( p_line == NULL ) if( !psz_lf )
psz = psz_cr;
else if( !psz_cr )
psz = psz_lf;
else
psz = __MIN( psz_cr, psz_lf );
i_read = (psz - (char*)p_data) + 1;
p_line = realloc( p_line, i_read + 1 ); /* +1 for easy \0 append */
i_read = stream_Read( s, &p_line[i_line], i_read );
if( i_read > 0 )
i_line += i_read;
goto exit;
}
/* Read data (+1 for easy \0 append) */
p_line = realloc( p_line, i_line + STREAM_PROBE_LINE + 1 );
i_read = stream_Read( s, &p_line[i_line], STREAM_PROBE_LINE );
if( i_read <= 0 )
goto exit;
i_line += i_read;
}
exit:
while( i_line > 0 &&
( p_line[i_line-1] == '\n' || p_line[i_line-1] == '\r' ) )
{ {
msg_Err( s, "out of memory" ); i_line--;
return NULL;
} }
i = stream_Read( s, p_line, i + 1 ); if( i_line > 0 )
p_line[ i - 1 ] = '\0'; p_line[i_line] = '\0';
return p_line; return p_line;
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment