/*****************************************************************************
* subsusf.c : USF subtitles decoder
*****************************************************************************
- * Copyright (C) 2000-2006 the VideoLAN team
+ * Copyright (C) 2000-2006 VLC authors and VideoLAN
* $Id$
*
* Authors: Bernie Purcell <bitmap@videolan.org>
*
- * 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
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
+#include <assert.h>
-#include "subsdec.h"
+#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_modules.h>
-#include <assert.h>
+#include <vlc_codec.h>
+#include <vlc_input.h>
+#include <vlc_charset.h>
+#include <vlc_image.h>
+#include <vlc_xml.h>
+#include <vlc_stream.h>
/*****************************************************************************
- * Local prototypes
+ * Module descriptor.
*****************************************************************************/
static int OpenDecoder ( vlc_object_t * );
static void CloseDecoder ( vlc_object_t * );
-static subpicture_t *DecodeBlock ( decoder_t *, block_t ** );
-static char *CreatePlainText( char * );
-static int ParseImageAttachments( decoder_t *p_dec );
-
-static subpicture_t *ParseText ( decoder_t *, block_t * );
-static void ParseUSFHeader( decoder_t * );
-static subpicture_region_t *ParseUSFString( decoder_t *, char * );
-static subpicture_region_t *LoadEmbeddedImage( decoder_t *p_dec, const char *psz_filename, int i_transparent_color );
-
-/*****************************************************************************
- * Module descriptor.
- *****************************************************************************/
-
vlc_module_begin ()
set_capability( "decoder", 40 )
set_shortname( N_("USFSubs"))
/* We inherit subsdec-align and subsdec-formatted from subsdec.c */
vlc_module_end ()
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+enum
+{
+ ATTRIBUTE_ALIGNMENT = (1 << 0),
+ ATTRIBUTE_X = (1 << 1),
+ ATTRIBUTE_X_PERCENT = (1 << 2),
+ ATTRIBUTE_Y = (1 << 3),
+ ATTRIBUTE_Y_PERCENT = (1 << 4),
+};
+
+typedef struct
+{
+ char *psz_filename;
+ picture_t *p_pic;
+} image_attach_t;
+
+typedef struct
+{
+ char * psz_stylename; /* The name of the style, no comma's allowed */
+ text_style_t font_style;
+ int i_align;
+ int i_margin_h;
+ int i_margin_v;
+ int i_margin_percent_h;
+ int i_margin_percent_v;
+} ssa_style_t;
+
+struct decoder_sys_t
+{
+ int i_original_height;
+ int i_original_width;
+ int i_align; /* Subtitles alignment on the vout */
+
+ ssa_style_t **pp_ssa_styles;
+ int i_ssa_styles;
+
+ image_attach_t **pp_images;
+ int i_images;
+};
+
+static subpicture_t *DecodeBlock ( decoder_t *, block_t ** );
+static char *CreatePlainText( char * );
+static int ParseImageAttachments( decoder_t *p_dec );
+
+static subpicture_t *ParseText ( decoder_t *, block_t * );
+static void ParseUSFHeader( decoder_t * );
+static subpicture_region_t *ParseUSFString( decoder_t *, char * );
+static subpicture_region_t *LoadEmbeddedImage( decoder_t *p_dec, const char *psz_filename, int i_transparent_color );
+
/*****************************************************************************
* OpenDecoder: probe the decoder and return score
*****************************************************************************
p_dec->fmt_out.i_cat = SPU_ES;
p_dec->fmt_out.i_codec = 0;
- /* Unused fields of p_sys - not needed for USF decoding */
- p_sys->b_ass = false;
- p_sys->iconv_handle = (vlc_iconv_t)-1;
- p_sys->b_autodetect_utf8 = false;
-
/* init of p_sys */
p_sys->i_align = 0;
p_sys->i_original_height = 0;
{
block_t *p_block;
- p_block = block_New( p_image->p_parent, p_attach->i_data );
+ p_block = block_Alloc( p_attach->i_data );
if( p_block != NULL )
{
/* ffmpeg thinks it can handle bmp properly but it can't (at least
* not all of them), so use sdl_image if it is available */
- vlc_value_t val;
-
- var_Create( p_dec, "codec", VLC_VAR_MODULE | VLC_VAR_DOINHERIT );
- val.psz_string = (char*) "sdl_image";
- var_Set( p_dec, "codec", val );
+ var_Create( p_dec, "codec", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
+ var_SetString( p_dec, "codec", "sdl_image" );
}
p_pic = image_Read( p_image, p_block, &fmt_in, &fmt_out );
static void ParseUSFHeaderTags( decoder_t *p_dec, xml_reader_t *p_xml_reader )
{
decoder_sys_t *p_sys = p_dec->p_sys;
- char *psz_node;
+ const char *node;
ssa_style_t *p_ssa_style = NULL;
int i_style_level = 0;
int i_metadata_level = 0;
+ int type;
- while ( xml_ReaderRead( p_xml_reader ) == 1 )
+ while( (type = xml_ReaderNextNode( p_xml_reader, &node )) > 0 )
{
- switch ( xml_ReaderNodeType( p_xml_reader ) )
+ switch( type )
{
- case XML_READER_TEXT:
- case XML_READER_NONE:
- break;
case XML_READER_ENDELEM:
- psz_node = xml_ReaderName( p_xml_reader );
-
- if( !psz_node )
- break;
switch (i_style_level)
{
case 0:
- if( !strcasecmp( "metadata", psz_node ) && (i_metadata_level == 1) )
- {
+ if( !strcasecmp( "metadata", node ) && (i_metadata_level == 1) )
i_metadata_level--;
- }
break;
case 1:
- if( !strcasecmp( "styles", psz_node ) )
- {
+ if( !strcasecmp( "styles", node ) )
i_style_level--;
- }
break;
case 2:
- if( !strcasecmp( "style", psz_node ) )
+ if( !strcasecmp( "style", node ) )
{
TAB_APPEND( p_sys->i_ssa_styles, p_sys->pp_ssa_styles, p_ssa_style );
}
break;
}
-
- free( psz_node );
break;
- case XML_READER_STARTELEM:
- psz_node = xml_ReaderName( p_xml_reader );
-
- if( !psz_node )
- break;
- if( !strcasecmp( "metadata", psz_node ) && (i_style_level == 0) )
- {
+ case XML_READER_STARTELEM:
+ if( !strcasecmp( "metadata", node ) && (i_style_level == 0) )
i_metadata_level++;
- }
- else if( !strcasecmp( "resolution", psz_node ) &&
+ else if( !strcasecmp( "resolution", node ) &&
( i_metadata_level == 1) )
{
- while ( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
+ const char *attr, *val;
+ while( (attr = xml_ReaderNextAttr( p_xml_reader, &val )) )
{
- char *psz_name = xml_ReaderName ( p_xml_reader );
- char *psz_value = xml_ReaderValue ( p_xml_reader );
-
- if( psz_name && psz_value )
- {
- if( !strcasecmp( "x", psz_name ) )
- p_sys->i_original_width = atoi( psz_value );
- else if( !strcasecmp( "y", psz_name ) )
- p_sys->i_original_height = atoi( psz_value );
- }
- free( psz_name );
- free( psz_value );
+ if( !strcasecmp( "x", attr ) )
+ p_sys->i_original_width = atoi( val );
+ else if( !strcasecmp( "y", attr ) )
+ p_sys->i_original_height = atoi( val );
}
}
- else if( !strcasecmp( "styles", psz_node ) && (i_style_level == 0) )
+ else if( !strcasecmp( "styles", node ) && (i_style_level == 0) )
{
i_style_level++;
}
- else if( !strcasecmp( "style", psz_node ) && (i_style_level == 1) )
+ else if( !strcasecmp( "style", node ) && (i_style_level == 1) )
{
i_style_level++;
p_ssa_style = calloc( 1, sizeof(ssa_style_t) );
- if( !p_ssa_style )
- {
- free( psz_node );
+ if( unlikely(!p_ssa_style) )
return;
- }
/* All styles are supposed to default to Default, and then
* one or more settings are over-ridden.
* At the moment this only effects styles defined AFTER
* Default in the XML
*/
- int i;
- for( i = 0; i < p_sys->i_ssa_styles; i++ )
+ for( int i = 0; i < p_sys->i_ssa_styles; i++ )
{
if( !strcasecmp( p_sys->pp_ssa_styles[i]->psz_stylename, "Default" ) )
{
}
}
- while ( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
+ const char *attr, *val;
+ while( (attr = xml_ReaderNextAttr( p_xml_reader, &val )) )
{
- char *psz_name = xml_ReaderName ( p_xml_reader );
- char *psz_value = xml_ReaderValue ( p_xml_reader );
-
- if( psz_name && psz_value )
+ if( !strcasecmp( "name", attr ) )
{
- if( !strcasecmp( "name", psz_name ) )
- p_ssa_style->psz_stylename = strdup( psz_value );
+ free( p_ssa_style->psz_stylename );
+ p_ssa_style->psz_stylename = strdup( val );
}
- free( psz_name );
- free( psz_value );
}
}
- else if( !strcasecmp( "fontstyle", psz_node ) && (i_style_level == 2) )
+ else if( !strcasecmp( "fontstyle", node ) && (i_style_level == 2) )
{
- while ( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
+ const char *attr, *val;
+ while( (attr = xml_ReaderNextAttr( p_xml_reader, &val )) )
{
- char *psz_name = xml_ReaderName ( p_xml_reader );
- char *psz_value = xml_ReaderValue ( p_xml_reader );
-
- if( psz_name && psz_value )
+ if( !strcasecmp( "face", attr ) )
{
- if( !strcasecmp( "face", psz_name ) )
- {
- free( p_ssa_style->font_style.psz_fontname );
- p_ssa_style->font_style.psz_fontname = strdup( psz_value );
- }
- else if( !strcasecmp( "size", psz_name ) )
- {
- if( ( *psz_value == '+' ) || ( *psz_value == '-' ) )
- {
- int i_value = atoi( psz_value );
-
- if( ( i_value >= -5 ) && ( i_value <= 5 ) )
- p_ssa_style->font_style.i_font_size +=
- ( i_value * p_ssa_style->font_style.i_font_size ) / 10;
- else if( i_value < -5 )
- p_ssa_style->font_style.i_font_size = - i_value;
- else if( i_value > 5 )
- p_ssa_style->font_style.i_font_size = i_value;
- }
- else
- p_ssa_style->font_style.i_font_size = atoi( psz_value );
- }
- else if( !strcasecmp( "italic", psz_name ) )
- {
- if( !strcasecmp( "yes", psz_value ))
- p_ssa_style->font_style.i_style_flags |= STYLE_ITALIC;
- else
- p_ssa_style->font_style.i_style_flags &= ~STYLE_ITALIC;
- }
- else if( !strcasecmp( "weight", psz_name ) )
- {
- if( !strcasecmp( "bold", psz_value ))
- p_ssa_style->font_style.i_style_flags |= STYLE_BOLD;
- else
- p_ssa_style->font_style.i_style_flags &= ~STYLE_BOLD;
- }
- else if( !strcasecmp( "underline", psz_name ) )
- {
- if( !strcasecmp( "yes", psz_value ))
- p_ssa_style->font_style.i_style_flags |= STYLE_UNDERLINE;
- else
- p_ssa_style->font_style.i_style_flags &= ~STYLE_UNDERLINE;
- }
- else if( !strcasecmp( "color", psz_name ) )
- {
- if( *psz_value == '#' )
- {
- unsigned long col = strtol(psz_value+1, NULL, 16);
- p_ssa_style->font_style.i_font_color = (col & 0x00ffffff);
- p_ssa_style->font_style.i_font_alpha = (col >> 24) & 0xff;
- }
- }
- else if( !strcasecmp( "outline-color", psz_name ) )
- {
- if( *psz_value == '#' )
- {
- unsigned long col = strtol(psz_value+1, NULL, 16);
- p_ssa_style->font_style.i_outline_color = (col & 0x00ffffff);
- p_ssa_style->font_style.i_outline_alpha = (col >> 24) & 0xff;
- }
- }
- else if( !strcasecmp( "outline-level", psz_name ) )
+ free( p_ssa_style->font_style.psz_fontname );
+ p_ssa_style->font_style.psz_fontname = strdup( val );
+ }
+ else if( !strcasecmp( "size", attr ) )
+ {
+ if( ( *val == '+' ) || ( *val == '-' ) )
{
- p_ssa_style->font_style.i_outline_width = atoi( psz_value );
+ int i_value = atoi( val );
+
+ if( ( i_value >= -5 ) && ( i_value <= 5 ) )
+ p_ssa_style->font_style.i_font_size +=
+ ( i_value * p_ssa_style->font_style.i_font_size ) / 10;
+ else if( i_value < -5 )
+ p_ssa_style->font_style.i_font_size = - i_value;
+ else if( i_value > 5 )
+ p_ssa_style->font_style.i_font_size = i_value;
}
- else if( !strcasecmp( "shadow-color", psz_name ) )
+ else
+ p_ssa_style->font_style.i_font_size = atoi( val );
+ }
+ else if( !strcasecmp( "italic", attr ) )
+ {
+ if( !strcasecmp( "yes", val ))
+ p_ssa_style->font_style.i_style_flags |= STYLE_ITALIC;
+ else
+ p_ssa_style->font_style.i_style_flags &= ~STYLE_ITALIC;
+ }
+ else if( !strcasecmp( "weight", attr ) )
+ {
+ if( !strcasecmp( "bold", val ))
+ p_ssa_style->font_style.i_style_flags |= STYLE_BOLD;
+ else
+ p_ssa_style->font_style.i_style_flags &= ~STYLE_BOLD;
+ }
+ else if( !strcasecmp( "underline", attr ) )
+ {
+ if( !strcasecmp( "yes", val ))
+ p_ssa_style->font_style.i_style_flags |= STYLE_UNDERLINE;
+ else
+ p_ssa_style->font_style.i_style_flags &= ~STYLE_UNDERLINE;
+ }
+ else if( !strcasecmp( "color", attr ) )
+ {
+ if( *val == '#' )
{
- if( *psz_value == '#' )
- {
- unsigned long col = strtol(psz_value+1, NULL, 16);
- p_ssa_style->font_style.i_shadow_color = (col & 0x00ffffff);
- p_ssa_style->font_style.i_shadow_alpha = (col >> 24) & 0xff;
- }
+ unsigned long col = strtol(val+1, NULL, 16);
+ p_ssa_style->font_style.i_font_color = (col & 0x00ffffff);
+ p_ssa_style->font_style.i_font_alpha = (col >> 24) & 0xff;
}
- else if( !strcasecmp( "shadow-level", psz_name ) )
+ }
+ else if( !strcasecmp( "outline-color", attr ) )
+ {
+ if( *val == '#' )
{
- p_ssa_style->font_style.i_shadow_width = atoi( psz_value );
+ unsigned long col = strtol(val+1, NULL, 16);
+ p_ssa_style->font_style.i_outline_color = (col & 0x00ffffff);
+ p_ssa_style->font_style.i_outline_alpha = (col >> 24) & 0xff;
}
- else if( !strcasecmp( "back-color", psz_name ) )
+ }
+ else if( !strcasecmp( "outline-level", attr ) )
+ {
+ p_ssa_style->font_style.i_outline_width = atoi( val );
+ }
+ else if( !strcasecmp( "shadow-color", attr ) )
+ {
+ if( *val == '#' )
{
- if( *psz_value == '#' )
- {
- unsigned long col = strtol(psz_value+1, NULL, 16);
- p_ssa_style->font_style.i_karaoke_background_color = (col & 0x00ffffff);
- p_ssa_style->font_style.i_karaoke_background_alpha = (col >> 24) & 0xff;
- }
+ unsigned long col = strtol(val+1, NULL, 16);
+ p_ssa_style->font_style.i_shadow_color = (col & 0x00ffffff);
+ p_ssa_style->font_style.i_shadow_alpha = (col >> 24) & 0xff;
}
- else if( !strcasecmp( "spacing", psz_name ) )
+ }
+ else if( !strcasecmp( "shadow-level", attr ) )
+ {
+ p_ssa_style->font_style.i_shadow_width = atoi( val );
+ }
+ else if( !strcasecmp( "back-color", attr ) )
+ {
+ if( *val == '#' )
{
- p_ssa_style->font_style.i_spacing = atoi( psz_value );
+ unsigned long col = strtol(val+1, NULL, 16);
+ p_ssa_style->font_style.i_karaoke_background_color = (col & 0x00ffffff);
+ p_ssa_style->font_style.i_karaoke_background_alpha = (col >> 24) & 0xff;
}
}
- free( psz_name );
- free( psz_value );
+ else if( !strcasecmp( "spacing", attr ) )
+ {
+ p_ssa_style->font_style.i_spacing = atoi( val );
+ }
}
}
- else if( !strcasecmp( "position", psz_node ) && (i_style_level == 2) )
+ else if( !strcasecmp( "position", node ) && (i_style_level == 2) )
{
- while ( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
+ const char *attr, *val;
+ while( (attr = xml_ReaderNextAttr( p_xml_reader, &val )) )
{
- char *psz_name = xml_ReaderName ( p_xml_reader );
- char *psz_value = xml_ReaderValue ( p_xml_reader );
-
- if( psz_name && psz_value )
+ if( !strcasecmp( "alignment", attr ) )
{
- if( !strcasecmp( "alignment", psz_name ) )
+ if( !strcasecmp( "TopLeft", val ) )
+ p_ssa_style->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
+ else if( !strcasecmp( "TopCenter", val ) )
+ p_ssa_style->i_align = SUBPICTURE_ALIGN_TOP;
+ else if( !strcasecmp( "TopRight", val ) )
+ p_ssa_style->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_RIGHT;
+ else if( !strcasecmp( "MiddleLeft", val ) )
+ p_ssa_style->i_align = SUBPICTURE_ALIGN_LEFT;
+ else if( !strcasecmp( "MiddleCenter", val ) )
+ p_ssa_style->i_align = 0;
+ else if( !strcasecmp( "MiddleRight", val ) )
+ p_ssa_style->i_align = SUBPICTURE_ALIGN_RIGHT;
+ else if( !strcasecmp( "BottomLeft", val ) )
+ p_ssa_style->i_align = SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_LEFT;
+ else if( !strcasecmp( "BottomCenter", val ) )
+ p_ssa_style->i_align = SUBPICTURE_ALIGN_BOTTOM;
+ else if( !strcasecmp( "BottomRight", val ) )
+ p_ssa_style->i_align = SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_RIGHT;
+ }
+ else if( !strcasecmp( "horizontal-margin", attr ) )
+ {
+ if( strchr( val, '%' ) )
{
- if( !strcasecmp( "TopLeft", psz_value ) )
- p_ssa_style->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
- else if( !strcasecmp( "TopCenter", psz_value ) )
- p_ssa_style->i_align = SUBPICTURE_ALIGN_TOP;
- else if( !strcasecmp( "TopRight", psz_value ) )
- p_ssa_style->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_RIGHT;
- else if( !strcasecmp( "MiddleLeft", psz_value ) )
- p_ssa_style->i_align = SUBPICTURE_ALIGN_LEFT;
- else if( !strcasecmp( "MiddleCenter", psz_value ) )
- p_ssa_style->i_align = 0;
- else if( !strcasecmp( "MiddleRight", psz_value ) )
- p_ssa_style->i_align = SUBPICTURE_ALIGN_RIGHT;
- else if( !strcasecmp( "BottomLeft", psz_value ) )
- p_ssa_style->i_align = SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_LEFT;
- else if( !strcasecmp( "BottomCenter", psz_value ) )
- p_ssa_style->i_align = SUBPICTURE_ALIGN_BOTTOM;
- else if( !strcasecmp( "BottomRight", psz_value ) )
- p_ssa_style->i_align = SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_RIGHT;
+ p_ssa_style->i_margin_h = 0;
+ p_ssa_style->i_margin_percent_h = atoi( val );
}
- else if( !strcasecmp( "horizontal-margin", psz_name ) )
+ else
{
- if( strchr( psz_value, '%' ) )
- {
- p_ssa_style->i_margin_h = 0;
- p_ssa_style->i_margin_percent_h = atoi( psz_value );
- }
- else
- {
- p_ssa_style->i_margin_h = atoi( psz_value );
- p_ssa_style->i_margin_percent_h = 0;
- }
+ p_ssa_style->i_margin_h = atoi( val );
+ p_ssa_style->i_margin_percent_h = 0;
}
- else if( !strcasecmp( "vertical-margin", psz_name ) )
+ }
+ else if( !strcasecmp( "vertical-margin", attr ) )
+ {
+ if( strchr( val, '%' ) )
{
- if( strchr( psz_value, '%' ) )
- {
- p_ssa_style->i_margin_v = 0;
- p_ssa_style->i_margin_percent_v = atoi( psz_value );
- }
- else
- {
- p_ssa_style->i_margin_v = atoi( psz_value );
- p_ssa_style->i_margin_percent_v = 0;
- }
+ p_ssa_style->i_margin_v = 0;
+ p_ssa_style->i_margin_percent_v = atoi( val );
+ }
+ else
+ {
+ p_ssa_style->i_margin_v = atoi( val );
+ p_ssa_style->i_margin_percent_v = 0;
}
}
- free( psz_name );
- free( psz_value );
}
}
-
- free( psz_node );
break;
}
}
return;
p_xml_reader = xml_ReaderCreate( p_dec, p_sub );
- if( p_xml_reader )
+ if( likely(p_xml_reader) )
{
- /* Look for Root Node */
- if( xml_ReaderRead( p_xml_reader ) == 1 )
- {
- char *psz_node = xml_ReaderName( p_xml_reader );
+ const char *node;
- if( !strcasecmp( "usfsubtitles", psz_node ) )
- ParseUSFHeaderTags( p_dec, p_xml_reader );
+ /* Look for Root Node */
+ if( xml_ReaderNextNode( p_xml_reader, &node ) == XML_READER_STARTELEM
+ && !strcasecmp( "usfsubtitles", node ) )
+ ParseUSFHeaderTags( p_dec, p_xml_reader );
- free( psz_node );
- }
xml_ReaderDelete( p_xml_reader );
}
stream_Delete( p_sub );
*psz_text++ = *psz_subtitle;
}
+ /* Security fix: Account for the case where input ends early */
+ if( *psz_subtitle == '\0' ) break;
+
psz_subtitle++;
}
- *psz_text = '\0';
-
- char *psz = realloc( psz_text_start, strlen( psz_text_start ) + 1 );
- if( psz ) psz_text_start = psz;
+ *psz_text++ = '\0';
- return psz_text_start;
+ char *psz = realloc( psz_text_start, psz_text - psz_text_start );
+ return likely(psz != NULL) ? psz : psz_text_start;
}
/* Turn a HTML subtitle, turn into a plain-text version,