+ *psz_text++ = '>';
+ psz_subtitle += strcspn( psz_subtitle, ";" );
+ }
+ else if( !strncasecmp( psz_subtitle, "&", 5 ))
+ {
+ *psz_text++ = '&';
+ psz_subtitle += strcspn( psz_subtitle, ";" );
+ }
+ else if( !strncasecmp( psz_subtitle, """, 6 ))
+ {
+ *psz_text++ = '\"';
+ psz_subtitle += strcspn( psz_subtitle, ";" );
+ }
+ else
+ {
+ /* Assume it is just a normal ampersand */
+ *psz_text++ = '&';
+ }
+ }
+ else
+ {
+ *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;
+
+ return psz_text_start;
+}
+
+/* Try to respect any style tags present in the subtitle string. The main
+ * problem here is a lack of adequate specs for the subtitle formats.
+ * SSA/ASS and USF are both detail spec'ed -- but they are handled elsewhere.
+ * SAMI has a detailed spec, but extensive rework is needed in the demux
+ * code to prevent all this style information being excised, as it presently
+ * does.
+ * That leaves the others - none of which were (I guess) originally intended
+ * to be carrying style information. Over time people have used them that way.
+ * In the absence of specifications from which to work, the tags supported
+ * have been restricted to the simple set permitted by the USF DTD, ie. :
+ * Basic: <br>, <i>, <b>, <u>, <s>
+ * Extended: <font>
+ * Attributes: face
+ * family
+ * size
+ * color
+ * outline-color
+ * shadow-color
+ * outline-level
+ * shadow-level
+ * back-color
+ * alpha
+ * There is also the further restriction that the subtitle be well-formed
+ * as an XML entity, ie. the HTML sentence:
+ * <b><i>Bold and Italics</b></i>
+ * doesn't qualify because the tags aren't nested one inside the other.
+ * <text> tags are automatically added to the output to ensure
+ * well-formedness.
+ * If the text doesn't qualify for any reason, a NULL string is
+ * returned, and the rendering engine will fall back to the
+ * plain text version of the subtitle.
+ */
+/* TODO: highly suboptimal, offset should be cached */
+static void HtmlNPut( char **ppsz_html, const char *psz_text, int i_max )
+{
+ char *psz_html = *ppsz_html;
+ if( psz_html == NULL )
+ return;
+
+ const size_t i_offset = strlen(psz_html);
+ const size_t i_len = strnlen(psz_text, i_max);
+
+ psz_html = realloc( psz_html, i_offset + i_len + 1 );
+ if( psz_html != NULL )
+ {
+ memcpy( psz_html + i_offset, psz_text, i_len );
+ psz_html[i_offset + i_len] = '\0';
+ }
+ else
+ free( *ppsz_html );
+ *ppsz_html = psz_html;
+}
+
+static void HtmlPut( char **ppsz_html, const char *psz_text )
+{
+ HtmlNPut( ppsz_html, psz_text, INT_MAX );
+}
+
+static void HtmlCopy( char **ppsz_html, char **ppsz_subtitle, const char *psz_text )
+{
+ HtmlPut( ppsz_html, psz_text );
+ *ppsz_subtitle += strlen(psz_text);
+}
+
+static char *CreateHtmlSubtitle( int *pi_align, char *psz_subtitle )
+{
+ char *psz_tag = malloc( 1 );
+ if( psz_tag == NULL )
+ return NULL;
+
+ char *psz_html = malloc( 1 );
+ if( psz_html == NULL )
+ {
+ free( psz_tag );
+ return NULL;
+ }
+ psz_tag[0] = '\0';
+ psz_html[0] = '\0';
+
+ bool b_has_align = false;
+
+ HtmlPut( &psz_html, "<text>" );
+
+ /* */
+ while( *psz_subtitle )
+ {
+ if( *psz_subtitle == '\n' )
+ {
+ HtmlPut( &psz_html, "<br/>" );
+ psz_subtitle++;
+ }
+ else if( *psz_subtitle == '<' )
+ {
+ if( !strncasecmp( psz_subtitle, "<br/>", 5 ))
+ {
+ HtmlCopy( &psz_html, &psz_subtitle, "<br/>" );
+ }
+ else if( !strncasecmp( psz_subtitle, "<b>", 3 ) )
+ {
+ HtmlCopy( &psz_html, &psz_subtitle, "<b>" );
+ HtmlPut( &psz_tag, "b" );
+ }
+ else if( !strncasecmp( psz_subtitle, "<i>", 3 ) )
+ {
+ HtmlCopy( &psz_html, &psz_subtitle, "<i>" );
+ HtmlPut( &psz_tag, "i" );
+ }
+ else if( !strncasecmp( psz_subtitle, "<u>", 3 ) )
+ {
+ HtmlCopy( &psz_html, &psz_subtitle, "<u>" );
+ HtmlPut( &psz_tag, "u" );
+ }
+ else if( !strncasecmp( psz_subtitle, "<s>", 3 ) )
+ {
+ HtmlCopy( &psz_html, &psz_subtitle, "<s>" );
+ HtmlPut( &psz_tag, "s" );
+ }
+ else if( !strncasecmp( psz_subtitle, "<font ", 6 ))
+ {
+ const char *psz_attribs[] = { "face=", "family=", "size=",
+ "color=", "outline-color=", "shadow-color=",
+ "outline-level=", "shadow-level=", "back-color=",
+ "alpha=", NULL };
+
+ HtmlCopy( &psz_html, &psz_subtitle, "<font " );
+ HtmlPut( &psz_tag, "f" );
+
+ while( *psz_subtitle != '>' )