]> git.sesse.net Git - vlc/blobdiff - modules/codec/subsusf.c
omxil: If OMX_IndexParamVideoInit failed, assume 2 ports with index 0 and 1
[vlc] / modules / codec / subsusf.c
index c69c4547b486fbf01275c88e3715ace0714a8966..74a9cf765c9cf9a5425250a6a23c91c71dbf51a6 100644 (file)
@@ -1,53 +1,46 @@
 /*****************************************************************************
  * 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"))
@@ -58,6 +51,58 @@ vlc_module_begin ()
     /* 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
  *****************************************************************************
@@ -80,11 +125,6 @@ static int OpenDecoder( vlc_object_t *p_this )
     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;
@@ -474,7 +514,7 @@ static int ParseImageAttachments( decoder_t *p_dec )
             {
                 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 )
                 {
@@ -528,39 +568,29 @@ static int ParseImageAttachments( decoder_t *p_dec )
 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 );
 
@@ -569,59 +599,40 @@ static void ParseUSFHeaderTags( decoder_t *p_dec, xml_reader_t *p_xml_reader )
                         }
                         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" ) )
                         {
@@ -635,188 +646,168 @@ static void ParseUSFHeaderTags( decoder_t *p_dec, xml_reader_t *p_xml_reader )
                         }
                     }
 
-                    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( "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( !strcasecmp( "alignment", psz_name ) )
+                            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
+                            {
+                                p_ssa_style->i_margin_h = atoi( val );
+                                p_ssa_style->i_margin_percent_h = 0;
+                            }
+                        }
+                        else if( !strcasecmp( "vertical-margin", attr ) )
+                        {
+                            if( strchr( val, '%' ) )
                             {
-                                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_v = 0;
+                                p_ssa_style->i_margin_percent_v = atoi( val );
                             }
-                            else if( !strcasecmp( "vertical-margin", psz_name ) )
+                            else
                             {
-                                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 = atoi( val );
+                                p_ssa_style->i_margin_percent_v = 0;
                             }
                         }
-                        free( psz_name );
-                        free( psz_value );
                     }
                 }
-
-                free( psz_node );
                 break;
         }
     }
@@ -996,18 +987,15 @@ static void ParseUSFHeader( decoder_t *p_dec )
         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 );
@@ -1072,6 +1060,9 @@ static char *StripTags( char *psz_subtitle )
             *psz_text++ = *psz_subtitle;
         }
 
+        /* Security fix: Account for the case where input ends early */
+        if( *psz_subtitle == '\0' ) break;
+
         psz_subtitle++;
     }
     *psz_text = '\0';