subtitle.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:59k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * subtitle.c: Demux for subtitle text files.
  3.  *****************************************************************************
  4.  * Copyright (C) 1999-2007 the VideoLAN team
  5.  * $Id: 426659c924f6b023e0dd6c970e6bd1781b05ab1f $
  6.  *
  7.  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  8.  *          Derk-Jan Hartman <hartman at videolan dot org>
  9.  *          Jean-Baptiste Kempf <jb@videolan.org>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Preamble
  27.  *****************************************************************************/
  28. #ifdef HAVE_CONFIG_H
  29. # include "config.h"
  30. #endif
  31. #include <vlc_common.h>
  32. #include <vlc_plugin.h>
  33. #include <vlc_input.h>
  34. #include <errno.h>
  35. #ifdef HAVE_SYS_TYPES_H
  36. #   include <sys/types.h>
  37. #endif
  38. #include <ctype.h>
  39. #include <vlc_demux.h>
  40. #include <vlc_charset.h>
  41. /*****************************************************************************
  42.  * Module descriptor
  43.  *****************************************************************************/
  44. static int  Open ( vlc_object_t *p_this );
  45. static void Close( vlc_object_t *p_this );
  46. #define SUB_DELAY_LONGTEXT 
  47.     N_("Apply a delay to all subtitles (in 1/10s, eg 100 means 10s).")
  48. #define SUB_FPS_LONGTEXT 
  49.     N_("Override the normal frames per second settings. " 
  50.     "This will only work with MicroDVD and SubRIP (SRT) subtitles.")
  51. #define SUB_TYPE_LONGTEXT 
  52.     N_("Force the subtiles format. Valid values are : "microdvd", " 
  53.     ""subrip", "subviewer", "ssa1", "ssa2-4", "ass", "vplayer", " 
  54.     ""sami", "dvdsubtitle", "mpl2", "aqt", "pjs", "
  55.     ""mpsub", "jacosub", "psb", "realtext", "dks", "subviewer1", " 
  56.     " and "auto" (meaning autodetection, this should always work).")
  57. static const char *const ppsz_sub_type[] =
  58. {
  59.     "auto", "microdvd", "subrip", "subviewer", "ssa1",
  60.     "ssa2-4", "ass", "vplayer", "sami", "dvdsubtitle", "mpl2",
  61.     "aqt", "pjs", "mpsub", "jacosub", "psb", "realtext", "dks",
  62.     "subviewer1"
  63. };
  64. vlc_module_begin ()
  65.     set_shortname( N_("Subtitles"))
  66.     set_description( N_("Text subtitles parser") )
  67.     set_capability( "demux", 0 )
  68.     set_category( CAT_INPUT )
  69.     set_subcategory( SUBCAT_INPUT_DEMUX )
  70.     add_float( "sub-fps", 0.0, NULL,
  71.                N_("Frames per second"),
  72.                SUB_FPS_LONGTEXT, true )
  73.     add_integer( "sub-delay", 0, NULL,
  74.                N_("Subtitles delay"),
  75.                SUB_DELAY_LONGTEXT, true )
  76.     add_string( "sub-type", "auto", NULL, N_("Subtitles format"),
  77.                 SUB_TYPE_LONGTEXT, true )
  78.         change_string_list( ppsz_sub_type, NULL, NULL )
  79.     set_callbacks( Open, Close )
  80.     add_shortcut( "subtitle" )
  81. vlc_module_end ()
  82. /*****************************************************************************
  83.  * Prototypes:
  84.  *****************************************************************************/
  85. enum
  86. {
  87.     SUB_TYPE_UNKNOWN = -1,
  88.     SUB_TYPE_MICRODVD,
  89.     SUB_TYPE_SUBRIP,
  90.     SUB_TYPE_SUBRIP_DOT, /* Invalid SubRip file (dot instead of comma) */
  91.     SUB_TYPE_SSA1,
  92.     SUB_TYPE_SSA2_4,
  93.     SUB_TYPE_ASS,
  94.     SUB_TYPE_VPLAYER,
  95.     SUB_TYPE_SAMI,
  96.     SUB_TYPE_SUBVIEWER, /* SUBVIEWER 2 */
  97.     SUB_TYPE_DVDSUBTITLE, /* Mplayer calls it subviewer2 */
  98.     SUB_TYPE_MPL2,
  99.     SUB_TYPE_AQT,
  100.     SUB_TYPE_PJS,
  101.     SUB_TYPE_MPSUB,
  102.     SUB_TYPE_JACOSUB,
  103.     SUB_TYPE_PSB,
  104.     SUB_TYPE_RT,
  105.     SUB_TYPE_DKS,
  106.     SUB_TYPE_SUBVIEW1 /* SUBVIEWER 1 - mplayer calls it subrip09,
  107.                          and Gnome subtitles SubViewer 1.0 */
  108. };
  109. typedef struct
  110. {
  111.     int     i_line_count;
  112.     int     i_line;
  113.     char    **line;
  114. } text_t;
  115. static int  TextLoad( text_t *, stream_t *s );
  116. static void TextUnload( text_t * );
  117. typedef struct
  118. {
  119.     int64_t i_start;
  120.     int64_t i_stop;
  121.     char    *psz_text;
  122. } subtitle_t;
  123. struct demux_sys_t
  124. {
  125.     int         i_type;
  126.     text_t      txt;
  127.     es_out_id_t *es;
  128.     int64_t     i_next_demux_date;
  129.     int64_t     i_microsecperframe;
  130.     char        *psz_header;
  131.     int         i_subtitle;
  132.     int         i_subtitles;
  133.     subtitle_t  *subtitle;
  134.     int64_t     i_length;
  135.     /* */
  136.     struct
  137.     {
  138.         bool b_inited;
  139.         int i_comment;
  140.         int i_time_resolution;
  141.         int i_time_shift;
  142.     } jss;
  143.     struct
  144.     {
  145.         bool  b_inited;
  146.         float f_total;
  147.         float f_factor;
  148.     } mpsub;
  149. };
  150. static int  ParseMicroDvd   ( demux_t *, subtitle_t *, int );
  151. static int  ParseSubRip     ( demux_t *, subtitle_t *, int );
  152. static int  ParseSubRipDot  ( demux_t *, subtitle_t *, int );
  153. static int  ParseSubViewer  ( demux_t *, subtitle_t *, int );
  154. static int  ParseSSA        ( demux_t *, subtitle_t *, int );
  155. static int  ParseVplayer    ( demux_t *, subtitle_t *, int );
  156. static int  ParseSami       ( demux_t *, subtitle_t *, int );
  157. static int  ParseDVDSubtitle( demux_t *, subtitle_t *, int );
  158. static int  ParseMPL2       ( demux_t *, subtitle_t *, int );
  159. static int  ParseAQT        ( demux_t *, subtitle_t *, int );
  160. static int  ParsePJS        ( demux_t *, subtitle_t *, int );
  161. static int  ParseMPSub      ( demux_t *, subtitle_t *, int );
  162. static int  ParseJSS        ( demux_t *, subtitle_t *, int );
  163. static int  ParsePSB        ( demux_t *, subtitle_t *, int );
  164. static int  ParseRealText   ( demux_t *, subtitle_t *, int );
  165. static int  ParseDKS        ( demux_t *, subtitle_t *, int );
  166. static int  ParseSubViewer1 ( demux_t *, subtitle_t *, int );
  167. static const struct
  168. {
  169.     const char *psz_type_name;
  170.     int  i_type;
  171.     const char *psz_name;
  172.     int  (*pf_read)( demux_t *, subtitle_t*, int );
  173. } sub_read_subtitle_function [] =
  174. {
  175.     { "microdvd",   SUB_TYPE_MICRODVD,    "MicroDVD",    ParseMicroDvd },
  176.     { "subrip",     SUB_TYPE_SUBRIP,      "SubRIP",      ParseSubRip },
  177.     { "subrip-dot", SUB_TYPE_SUBRIP_DOT,  "SubRIP(Dot)", ParseSubRipDot },
  178.     { "subviewer",  SUB_TYPE_SUBVIEWER,   "SubViewer",   ParseSubViewer },
  179.     { "ssa1",       SUB_TYPE_SSA1,        "SSA-1",       ParseSSA },
  180.     { "ssa2-4",     SUB_TYPE_SSA2_4,      "SSA-2/3/4",   ParseSSA },
  181.     { "ass",        SUB_TYPE_ASS,         "SSA/ASS",     ParseSSA },
  182.     { "vplayer",    SUB_TYPE_VPLAYER,     "VPlayer",     ParseVplayer },
  183.     { "sami",       SUB_TYPE_SAMI,        "SAMI",        ParseSami },
  184.     { "dvdsubtitle",SUB_TYPE_DVDSUBTITLE, "DVDSubtitle", ParseDVDSubtitle },
  185.     { "mpl2",       SUB_TYPE_MPL2,        "MPL2",        ParseMPL2 },
  186.     { "aqt",        SUB_TYPE_AQT,         "AQTitle",     ParseAQT },
  187.     { "pjs",        SUB_TYPE_PJS,         "PhoenixSub",  ParsePJS },
  188.     { "mpsub",      SUB_TYPE_MPSUB,       "MPSub",       ParseMPSub },
  189.     { "jacosub",    SUB_TYPE_JACOSUB,     "JacoSub",     ParseJSS },
  190.     { "psb",        SUB_TYPE_PSB,         "PowerDivx",   ParsePSB },
  191.     { "realtext",   SUB_TYPE_RT,          "RealText",    ParseRealText },
  192.     { "dks",        SUB_TYPE_DKS,         "DKS",         ParseDKS },
  193.     { "subviewer1", SUB_TYPE_SUBVIEW1,    "Subviewer 1", ParseSubViewer1 },
  194.     { NULL,         SUB_TYPE_UNKNOWN,     "Unknown",     NULL }
  195. };
  196. /* When adding support for more formats, be sure to add their file extension
  197.  * to src/input/subtitles.c to enable auto-detection.
  198.  */
  199. static int Demux( demux_t * );
  200. static int Control( demux_t *, int, va_list );
  201. /*static void Fix( demux_t * );*/
  202. /*****************************************************************************
  203.  * Module initializer
  204.  *****************************************************************************/
  205. static int Open ( vlc_object_t *p_this )
  206. {
  207.     demux_t        *p_demux = (demux_t*)p_this;
  208.     demux_sys_t    *p_sys;
  209.     es_format_t    fmt;
  210.     float          f_fps;
  211.     char           *psz_type;
  212.     int  (*pf_read)( demux_t *, subtitle_t*, int );
  213.     int            i, i_max;
  214.     if( !p_demux->b_force )
  215.     {
  216.         msg_Dbg( p_demux, "subtitle demux discarded" );
  217.         return VLC_EGENERIC;
  218.     }
  219.     p_demux->pf_demux = Demux;
  220.     p_demux->pf_control = Control;
  221.     p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
  222.     if( p_sys == NULL )
  223.         return VLC_ENOMEM;
  224.     p_sys->psz_header         = NULL;
  225.     p_sys->i_subtitle         = 0;
  226.     p_sys->i_subtitles        = 0;
  227.     p_sys->subtitle           = NULL;
  228.     p_sys->i_microsecperframe = 40000;
  229.     p_sys->jss.b_inited       = false;
  230.     p_sys->mpsub.b_inited     = false;
  231.     /* Get the FPS */
  232.     f_fps = var_CreateGetFloat( p_demux, "sub-original-fps" ); /* FIXME */
  233.     if( f_fps >= 1.0 )
  234.         p_sys->i_microsecperframe = (int64_t)( (float)1000000 / f_fps );
  235.     msg_Dbg( p_demux, "Movie fps: %f", f_fps );
  236.     /* Check for override of the fps */
  237.     f_fps = var_CreateGetFloat( p_demux, "sub-fps" );
  238.     if( f_fps >= 1.0 )
  239.     {
  240.         p_sys->i_microsecperframe = (int64_t)( (float)1000000 / f_fps );
  241.         msg_Dbg( p_demux, "Override subtitle fps %f", f_fps );
  242.     }
  243.     /* Get or probe the type */
  244.     p_sys->i_type = SUB_TYPE_UNKNOWN;
  245.     psz_type = var_CreateGetString( p_demux, "sub-type" );
  246.     if( psz_type && *psz_type )
  247.     {
  248.         int i;
  249.         for( i = 0; ; i++ )
  250.         {
  251.             if( sub_read_subtitle_function[i].psz_type_name == NULL )
  252.                 break;
  253.             if( !strcmp( sub_read_subtitle_function[i].psz_type_name,
  254.                          psz_type ) )
  255.             {
  256.                 p_sys->i_type = sub_read_subtitle_function[i].i_type;
  257.                 break;
  258.             }
  259.         }
  260.     }
  261.     free( psz_type );
  262.     /* Probe if unknown type */
  263.     if( p_sys->i_type == SUB_TYPE_UNKNOWN )
  264.     {
  265.         int     i_try;
  266.         char    *s = NULL;
  267.         msg_Dbg( p_demux, "autodetecting subtitle format" );
  268.         for( i_try = 0; i_try < 256; i_try++ )
  269.         {
  270.             int i_dummy;
  271.             char p_dummy;
  272.             if( ( s = stream_ReadLine( p_demux->s ) ) == NULL )
  273.                 break;
  274.             if( strcasestr( s, "<SAMI>" ) )
  275.             {
  276.                 p_sys->i_type = SUB_TYPE_SAMI;
  277.                 break;
  278.             }
  279.             else if( sscanf( s, "{%d}{%d}", &i_dummy, &i_dummy ) == 2 ||
  280.                      sscanf( s, "{%d}{}", &i_dummy ) == 1)
  281.             {
  282.                 p_sys->i_type = SUB_TYPE_MICRODVD;
  283.                 break;
  284.             }
  285.             else if( sscanf( s,
  286.                              "%d:%d:%d,%d --> %d:%d:%d,%d",
  287.                              &i_dummy,&i_dummy,&i_dummy,&i_dummy,
  288.                              &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 )
  289.             {
  290.                 p_sys->i_type = SUB_TYPE_SUBRIP;
  291.                 break;
  292.             }
  293.             else if( sscanf( s,
  294.                              "%d:%d:%d.%d --> %d:%d:%d.%d",
  295.                              &i_dummy,&i_dummy,&i_dummy,&i_dummy,
  296.                              &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 )
  297.             {
  298.                 msg_Err( p_demux, "Detected invalid SubRip file, playing anyway" );
  299.                 p_sys->i_type = SUB_TYPE_SUBRIP_DOT;
  300.                 break;
  301.             }
  302.             else if( !strncasecmp( s, "!: This is a Sub Station Alpha v1", 33 ) )
  303.             {
  304.                 p_sys->i_type = SUB_TYPE_SSA1;
  305.                 break;
  306.             }
  307.             else if( !strncasecmp( s, "ScriptType: v4.00+", 18 ) )
  308.             {
  309.                 p_sys->i_type = SUB_TYPE_ASS;
  310.                 break;
  311.             }
  312.             else if( !strncasecmp( s, "ScriptType: v4.00", 17 ) )
  313.             {
  314.                 p_sys->i_type = SUB_TYPE_SSA2_4;
  315.                 break;
  316.             }
  317.             else if( !strncasecmp( s, "Dialogue: Marked", 16  ) )
  318.             {
  319.                 p_sys->i_type = SUB_TYPE_SSA2_4;
  320.                 break;
  321.             }
  322.             else if( !strncasecmp( s, "Dialogue:", 9  ) )
  323.             {
  324.                 p_sys->i_type = SUB_TYPE_ASS;
  325.                 break;
  326.             }
  327.             else if( strcasestr( s, "[INFORMATION]" ) )
  328.             {
  329.                 p_sys->i_type = SUB_TYPE_SUBVIEWER; /* I hope this will work */
  330.                 break;
  331.             }
  332.             else if( sscanf( s, "%d:%d:%d.%d %d:%d:%d",
  333.                                  &i_dummy, &i_dummy, &i_dummy, &i_dummy,
  334.                                  &i_dummy, &i_dummy, &i_dummy ) == 7 ||
  335.                      sscanf( s, "@%d @%d", &i_dummy, &i_dummy) == 2)
  336.             {
  337.                 p_sys->i_type = SUB_TYPE_JACOSUB;
  338.                 break;
  339.             }
  340.             else if( sscanf( s, "%d:%d:%d:", &i_dummy, &i_dummy, &i_dummy ) == 3 ||
  341.                      sscanf( s, "%d:%d:%d ", &i_dummy, &i_dummy, &i_dummy ) == 3 )
  342.             {
  343.                 p_sys->i_type = SUB_TYPE_VPLAYER;
  344.                 break;
  345.             }
  346.             else if( sscanf( s, "{T %d:%d:%d:%d", &i_dummy, &i_dummy,
  347.                              &i_dummy, &i_dummy ) == 4 )
  348.             {
  349.                 p_sys->i_type = SUB_TYPE_DVDSUBTITLE;
  350.                 break;
  351.             }
  352.             else if( sscanf( s, "[%d:%d:%d]%c",
  353.                      &i_dummy, &i_dummy, &i_dummy, &p_dummy ) == 4 )
  354.             {
  355.                 p_sys->i_type = SUB_TYPE_DKS;
  356.                 break;
  357.             }
  358.             else if( strstr( s, "*** START SCRIPT" ) )
  359.             {
  360.                 p_sys->i_type = SUB_TYPE_SUBVIEW1;
  361.                 break;
  362.             }
  363.             else if( sscanf( s, "[%d][%d]", &i_dummy, &i_dummy ) == 2 ||
  364.                      sscanf( s, "[%d][]", &i_dummy ) == 1)
  365.             {
  366.                 p_sys->i_type = SUB_TYPE_MPL2;
  367.                 break;
  368.             }
  369.             else if( sscanf (s, "FORMAT=%d", &i_dummy) == 1 ||
  370.                      ( sscanf (s, "FORMAT=TIM%c", &p_dummy) == 1
  371.                        && p_dummy =='E' ) )
  372.             {
  373.                 p_sys->i_type = SUB_TYPE_MPSUB;
  374.                 break;
  375.             }
  376.             else if( sscanf( s, "-->> %d", &i_dummy) == 1 )
  377.             {
  378.                 p_sys->i_type = SUB_TYPE_AQT;
  379.                 break;
  380.             }
  381.             else if( sscanf( s, "%d,%d,", &i_dummy, &i_dummy ) == 2 )
  382.             {
  383.                 p_sys->i_type = SUB_TYPE_PJS;
  384.                 break;
  385.             }
  386.             else if( sscanf( s, "{%d:%d:%d}",
  387.                                 &i_dummy, &i_dummy, &i_dummy ) == 3 )
  388.             {
  389.                 p_sys->i_type = SUB_TYPE_PSB;
  390.                 break;
  391.             }
  392.             else if( strcasestr( s, "<time" ) )
  393.             {
  394.                 p_sys->i_type = SUB_TYPE_RT;
  395.                 break;
  396.             }
  397.             free( s );
  398.             s = NULL;
  399.         }
  400.         free( s );
  401.         /* It will nearly always work even for non seekable stream thanks the
  402.          * caching system, and if it fails we lose just a few sub */
  403.         if( stream_Seek( p_demux->s, 0 ) )
  404.         {
  405.             msg_Warn( p_demux, "failed to rewind" );
  406.         }
  407.     }
  408.     /* Quit on unknown subtitles */
  409.     if( p_sys->i_type == SUB_TYPE_UNKNOWN )
  410.     {
  411.         msg_Warn( p_demux, "failed to recognize subtitle type" );
  412.         free( p_sys );
  413.         return VLC_EGENERIC;
  414.     }
  415.     for( i = 0; ; i++ )
  416.     {
  417.         if( sub_read_subtitle_function[i].i_type == p_sys->i_type )
  418.         {
  419.             msg_Dbg( p_demux, "detected %s format",
  420.                      sub_read_subtitle_function[i].psz_name );
  421.             pf_read = sub_read_subtitle_function[i].pf_read;
  422.             break;
  423.         }
  424.     }
  425.     msg_Dbg( p_demux, "loading all subtitles..." );
  426.     /* Load the whole file */
  427.     TextLoad( &p_sys->txt, p_demux->s );
  428.     /* Parse it */
  429.     for( i_max = 0;; )
  430.     {
  431.         if( p_sys->i_subtitles >= i_max )
  432.         {
  433.             i_max += 500;
  434.             if( !( p_sys->subtitle = realloc( p_sys->subtitle,
  435.                                               sizeof(subtitle_t) * i_max ) ) )
  436.             {
  437.                 free( p_sys->subtitle );
  438.                 TextUnload( &p_sys->txt );
  439.                 free( p_sys );
  440.                 return VLC_ENOMEM;
  441.             }
  442.         }
  443.         if( pf_read( p_demux, &p_sys->subtitle[p_sys->i_subtitles],
  444.                      p_sys->i_subtitles ) )
  445.             break;
  446.         p_sys->i_subtitles++;
  447.     }
  448.     /* Unload */
  449.     TextUnload( &p_sys->txt );
  450.     msg_Dbg(p_demux, "loaded %d subtitles", p_sys->i_subtitles );
  451.     /* Fix subtitle (order and time) *** */
  452.     p_sys->i_subtitle = 0;
  453.     p_sys->i_length = 0;
  454.     if( p_sys->i_subtitles > 0 )
  455.     {
  456.         p_sys->i_length = p_sys->subtitle[p_sys->i_subtitles-1].i_stop;
  457.         /* +1 to avoid 0 */
  458.         if( p_sys->i_length <= 0 )
  459.             p_sys->i_length = p_sys->subtitle[p_sys->i_subtitles-1].i_start+1;
  460.     }
  461.     /* *** add subtitle ES *** */
  462.     if( p_sys->i_type == SUB_TYPE_SSA1 ||
  463.              p_sys->i_type == SUB_TYPE_SSA2_4 ||
  464.              p_sys->i_type == SUB_TYPE_ASS )
  465.     {
  466.         es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','s','a',' ' ) );
  467.     }
  468.     else
  469.     {
  470.         es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','u','b','t' ) );
  471.     }
  472.     if( p_sys->psz_header != NULL )
  473.     {
  474.         fmt.i_extra = strlen( p_sys->psz_header ) + 1;
  475.         fmt.p_extra = strdup( p_sys->psz_header );
  476.     }
  477.     p_sys->es = es_out_Add( p_demux->out, &fmt );
  478.     return VLC_SUCCESS;
  479. }
  480. /*****************************************************************************
  481.  * Close: Close subtitle demux
  482.  *****************************************************************************/
  483. static void Close( vlc_object_t *p_this )
  484. {
  485.     demux_t *p_demux = (demux_t*)p_this;
  486.     demux_sys_t *p_sys = p_demux->p_sys;
  487.     int i;
  488.     for( i = 0; i < p_sys->i_subtitles; i++ )
  489.         free( p_sys->subtitle[i].psz_text );
  490.     free( p_sys->subtitle );
  491.     free( p_sys );
  492. }
  493. /*****************************************************************************
  494.  * Control:
  495.  *****************************************************************************/
  496. static int Control( demux_t *p_demux, int i_query, va_list args )
  497. {
  498.     demux_sys_t *p_sys = p_demux->p_sys;
  499.     int64_t *pi64, i64;
  500.     double *pf, f;
  501.     switch( i_query )
  502.     {
  503.         case DEMUX_GET_LENGTH:
  504.             pi64 = (int64_t*)va_arg( args, int64_t * );
  505.             *pi64 = p_sys->i_length;
  506.             return VLC_SUCCESS;
  507.         case DEMUX_GET_TIME:
  508.             pi64 = (int64_t*)va_arg( args, int64_t * );
  509.             if( p_sys->i_subtitle < p_sys->i_subtitles )
  510.             {
  511.                 *pi64 = p_sys->subtitle[p_sys->i_subtitle].i_start;
  512.                 return VLC_SUCCESS;
  513.             }
  514.             return VLC_EGENERIC;
  515.         case DEMUX_SET_TIME:
  516.             i64 = (int64_t)va_arg( args, int64_t );
  517.             p_sys->i_subtitle = 0;
  518.             while( p_sys->i_subtitle < p_sys->i_subtitles )
  519.             {
  520.                 const subtitle_t *p_subtitle = &p_sys->subtitle[p_sys->i_subtitle];
  521.                 if( p_subtitle->i_start > i64 )
  522.                     break;
  523.                 if( p_subtitle->i_stop > p_subtitle->i_start && p_subtitle->i_stop > i64 )
  524.                     break;
  525.                 p_sys->i_subtitle++;
  526.             }
  527.             if( p_sys->i_subtitle >= p_sys->i_subtitles )
  528.                 return VLC_EGENERIC;
  529.             return VLC_SUCCESS;
  530.         case DEMUX_GET_POSITION:
  531.             pf = (double*)va_arg( args, double * );
  532.             if( p_sys->i_subtitle >= p_sys->i_subtitles )
  533.             {
  534.                 *pf = 1.0;
  535.             }
  536.             else if( p_sys->i_subtitles > 0 )
  537.             {
  538.                 *pf = (double)p_sys->subtitle[p_sys->i_subtitle].i_start /
  539.                       (double)p_sys->i_length;
  540.             }
  541.             else
  542.             {
  543.                 *pf = 0.0;
  544.             }
  545.             return VLC_SUCCESS;
  546.         case DEMUX_SET_POSITION:
  547.             f = (double)va_arg( args, double );
  548.             i64 = f * p_sys->i_length;
  549.             p_sys->i_subtitle = 0;
  550.             while( p_sys->i_subtitle < p_sys->i_subtitles &&
  551.                    p_sys->subtitle[p_sys->i_subtitle].i_start < i64 )
  552.             {
  553.                 p_sys->i_subtitle++;
  554.             }
  555.             if( p_sys->i_subtitle >= p_sys->i_subtitles )
  556.                 return VLC_EGENERIC;
  557.             return VLC_SUCCESS;
  558.         case DEMUX_SET_NEXT_DEMUX_TIME:
  559.             p_sys->i_next_demux_date = (int64_t)va_arg( args, int64_t );
  560.             return VLC_SUCCESS;
  561.         case DEMUX_GET_FPS:
  562.         case DEMUX_GET_META:
  563.         case DEMUX_GET_ATTACHMENTS:
  564.         case DEMUX_GET_TITLE_INFO:
  565.         case DEMUX_HAS_UNSUPPORTED_META:
  566.         case DEMUX_CAN_RECORD:
  567.             return VLC_EGENERIC;
  568.         default:
  569.             msg_Err( p_demux, "unknown query %d in subtitle control", i_query );
  570.             return VLC_EGENERIC;
  571.     }
  572. }
  573. /*****************************************************************************
  574.  * Demux: Send subtitle to decoder
  575.  *****************************************************************************/
  576. static int Demux( demux_t *p_demux )
  577. {
  578.     demux_sys_t *p_sys = p_demux->p_sys;
  579.     int64_t i_maxdate;
  580.     if( p_sys->i_subtitle >= p_sys->i_subtitles )
  581.         return 0;
  582.     i_maxdate = p_sys->i_next_demux_date - var_GetTime( p_demux->p_parent, "spu-delay" );;
  583.     if( i_maxdate <= 0 && p_sys->i_subtitle < p_sys->i_subtitles )
  584.     {
  585.         /* Should not happen */
  586.         i_maxdate = p_sys->subtitle[p_sys->i_subtitle].i_start + 1;
  587.     }
  588.     while( p_sys->i_subtitle < p_sys->i_subtitles &&
  589.            p_sys->subtitle[p_sys->i_subtitle].i_start < i_maxdate )
  590.     {
  591.         const subtitle_t *p_subtitle = &p_sys->subtitle[p_sys->i_subtitle];
  592.         block_t *p_block;
  593.         int i_len = strlen( p_subtitle->psz_text ) + 1;
  594.         if( i_len <= 1 || p_subtitle->i_start < 0 )
  595.         {
  596.             p_sys->i_subtitle++;
  597.             continue;
  598.         }
  599.         if( ( p_block = block_New( p_demux, i_len ) ) == NULL )
  600.         {
  601.             p_sys->i_subtitle++;
  602.             continue;
  603.         }
  604.         p_block->i_dts =
  605.         p_block->i_pts = 1 + p_subtitle->i_start;
  606.         if( p_subtitle->i_stop > 0 && p_subtitle->i_stop >= p_subtitle->i_start )
  607.             p_block->i_length = p_subtitle->i_stop - p_subtitle->i_start;
  608.         memcpy( p_block->p_buffer, p_subtitle->psz_text, i_len );
  609.         es_out_Send( p_demux->out, p_sys->es, p_block );
  610.         p_sys->i_subtitle++;
  611.     }
  612.     /* */
  613.     p_sys->i_next_demux_date = 0;
  614.     return 1;
  615. }
  616. /*****************************************************************************
  617.  * Fix: fix time stamp and order of subtitle
  618.  *****************************************************************************/
  619. #ifdef USE_THIS_UNUSED_PIECE_OF_CODE
  620. static void Fix( demux_t *p_demux )
  621. {
  622.     demux_sys_t *p_sys = p_demux->p_sys;
  623.     bool b_done;
  624.     int     i_index;
  625.     /* *** fix order (to be sure...) *** */
  626.     /* We suppose that there are near in order and this durty bubble sort
  627.      * wont take too much time
  628.      */
  629.     do
  630.     {
  631.         b_done = true;
  632.         for( i_index = 1; i_index < p_sys->i_subtitles; i_index++ )
  633.         {
  634.             if( p_sys->subtitle[i_index].i_start <
  635.                     p_sys->subtitle[i_index - 1].i_start )
  636.             {
  637.                 subtitle_t sub_xch;
  638.                 memcpy( &sub_xch,
  639.                         p_sys->subtitle + i_index - 1,
  640.                         sizeof( subtitle_t ) );
  641.                 memcpy( p_sys->subtitle + i_index - 1,
  642.                         p_sys->subtitle + i_index,
  643.                         sizeof( subtitle_t ) );
  644.                 memcpy( p_sys->subtitle + i_index,
  645.                         &sub_xch,
  646.                         sizeof( subtitle_t ) );
  647.                 b_done = false;
  648.             }
  649.         }
  650.     } while( !b_done );
  651. }
  652. #endif
  653. static int TextLoad( text_t *txt, stream_t *s )
  654. {
  655.     int   i_line_max;
  656.     /* init txt */
  657.     i_line_max          = 500;
  658.     txt->i_line_count   = 0;
  659.     txt->i_line         = 0;
  660.     txt->line           = calloc( i_line_max, sizeof( char * ) );
  661.     /* load the complete file */
  662.     for( ;; )
  663.     {
  664.         char *psz = stream_ReadLine( s );
  665.         if( psz == NULL )
  666.             break;
  667.         txt->line[txt->i_line_count++] = psz;
  668.         if( txt->i_line_count >= i_line_max )
  669.         {
  670.             i_line_max += 100;
  671.             txt->line = realloc( txt->line, i_line_max * sizeof( char * ) );
  672.         }
  673.     }
  674.     if( txt->i_line_count <= 0 )
  675.     {
  676.         free( txt->line );
  677.         return VLC_EGENERIC;
  678.     }
  679.     return VLC_SUCCESS;
  680. }
  681. static void TextUnload( text_t *txt )
  682. {
  683.     int i;
  684.     for( i = 0; i < txt->i_line_count; i++ )
  685.     {
  686.         free( txt->line[i] );
  687.     }
  688.     free( txt->line );
  689.     txt->i_line       = 0;
  690.     txt->i_line_count = 0;
  691. }
  692. static char *TextGetLine( text_t *txt )
  693. {
  694.     if( txt->i_line >= txt->i_line_count )
  695.         return( NULL );
  696.     return txt->line[txt->i_line++];
  697. }
  698. static void TextPreviousLine( text_t *txt )
  699. {
  700.     if( txt->i_line > 0 )
  701.         txt->i_line--;
  702. }
  703. /*****************************************************************************
  704.  * Specific Subtitle function
  705.  *****************************************************************************/
  706. /* ParseMicroDvd:
  707.  *  Format:
  708.  *      {n1}{n2}Line1|Line2|Line3....
  709.  *  where n1 and n2 are the video frame number (n2 can be empty)
  710.  */
  711. static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle,
  712.                           int i_idx )
  713. {
  714.     VLC_UNUSED( i_idx );
  715.     demux_sys_t *p_sys = p_demux->p_sys;
  716.     text_t      *txt = &p_sys->txt;
  717.     char *psz_text;
  718.     int  i_start;
  719.     int  i_stop;
  720.     int  i;
  721.     for( ;; )
  722.     {
  723.         const char *s = TextGetLine( txt );
  724.         if( !s )
  725.             return VLC_EGENERIC;
  726.         psz_text = malloc( strlen(s) + 1 );
  727.         if( !psz_text )
  728.             return VLC_ENOMEM;
  729.         i_start = 0;
  730.         i_stop  = 0;
  731.         if( sscanf( s, "{%d}{}%[^rn]", &i_start, psz_text ) == 2 ||
  732.             sscanf( s, "{%d}{%d}%[^rn]", &i_start, &i_stop, psz_text ) == 3)
  733.         {
  734.             float f_fps;
  735.             if( i_start != 1 || i_stop != 1 )
  736.                 break;
  737.             /* We found a possible setting of the framerate "{1}{1}23.976" */
  738.             /* Check if it's usable, and if the sub-fps is not set */
  739.             f_fps = us_strtod( psz_text, NULL );
  740.             if( f_fps > 0.0 && var_GetFloat( p_demux, "sub-fps" ) <= 0.0 )
  741.                 p_sys->i_microsecperframe = (int64_t)((float)1000000 / f_fps);
  742.         }
  743.         free( psz_text );
  744.     }
  745.     /* replace | by n */
  746.     for( i = 0; psz_text[i] != ''; i++ )
  747.     {
  748.         if( psz_text[i] == '|' )
  749.             psz_text[i] = 'n';
  750.     }
  751.     /* */
  752.     p_subtitle->i_start  = i_start * p_sys->i_microsecperframe;
  753.     p_subtitle->i_stop   = i_stop  * p_sys->i_microsecperframe;
  754.     p_subtitle->psz_text = psz_text;
  755.     return VLC_SUCCESS;
  756. }
  757. /* ParseSubRipSubViewer
  758.  *  Format SubRip
  759.  *      n
  760.  *      h1:m1:s1,d1 --> h2:m2:s2,d2
  761.  *      Line1
  762.  *      Line2
  763.  *      ....
  764.  *      [Empty line]
  765.  *  Format SubViewer v1/v2
  766.  *      h1:m1:s1.d1,h2:m2:s2.d2
  767.  *      Line1[br]Line2
  768.  *      Line3
  769.  *      ...
  770.  *      [empty line]
  771.  *  We ignore line number for SubRip
  772.  */
  773. static int ParseSubRipSubViewer( demux_t *p_demux, subtitle_t *p_subtitle,
  774.                                  const char *psz_fmt,
  775.                                  bool b_replace_br )
  776. {
  777.     demux_sys_t *p_sys = p_demux->p_sys;
  778.     text_t      *txt = &p_sys->txt;
  779.     char    *psz_text;
  780.     for( ;; )
  781.     {
  782.         const char *s = TextGetLine( txt );
  783.         int h1, m1, s1, d1, h2, m2, s2, d2;
  784.         if( !s )
  785.             return VLC_EGENERIC;
  786.         if( sscanf( s, psz_fmt,
  787.                     &h1, &m1, &s1, &d1,
  788.                     &h2, &m2, &s2, &d2 ) == 8 )
  789.         {
  790.             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
  791.                                     (int64_t)m1 * 60*1000 +
  792.                                     (int64_t)s1 * 1000 +
  793.                                     (int64_t)d1 ) * 1000;
  794.             p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
  795.                                     (int64_t)m2 * 60*1000 +
  796.                                     (int64_t)s2 * 1000 +
  797.                                     (int64_t)d2 ) * 1000;
  798.             if( p_subtitle->i_start < p_subtitle->i_stop )
  799.                 break;
  800.         }
  801.     }
  802.     /* Now read text until an empty line */
  803.     psz_text = strdup("");
  804.     if( !psz_text )
  805.         return VLC_ENOMEM;
  806.     for( ;; )
  807.     {
  808.         const char *s = TextGetLine( txt );
  809.         int i_len;
  810.         int i_old;
  811.         i_len = s ? strlen( s ) : 0;
  812.         if( i_len <= 0 )
  813.         {
  814.             p_subtitle->psz_text = psz_text;
  815.             return VLC_SUCCESS;
  816.         }
  817.         i_old = strlen( psz_text );
  818.         psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
  819.         if( !psz_text )
  820.         {
  821.             return VLC_ENOMEM;
  822.         }
  823.         strcat( psz_text, s );
  824.         strcat( psz_text, "n" );
  825.         /* replace [br] by n */
  826.         if( b_replace_br )
  827.         {
  828.             char *p;
  829.             while( ( p = strstr( psz_text, "[br]" ) ) )
  830.             {
  831.                 *p++ = 'n';
  832.                 memmove( p, &p[3], strlen(&p[3])+1 );
  833.             }
  834.         }
  835.     }
  836. }
  837. /* ParseSubRip
  838.  */
  839. static int  ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle,
  840.                          int i_idx )
  841. {
  842.     VLC_UNUSED( i_idx );
  843.     return ParseSubRipSubViewer( p_demux, p_subtitle,
  844.                                  "%d:%d:%d,%d --> %d:%d:%d,%d",
  845.                                  false );
  846. }
  847. /* ParseSubRipDot
  848.  * Special version for buggy file using '.' instead of ','
  849.  */
  850. static int  ParseSubRipDot( demux_t *p_demux, subtitle_t *p_subtitle,
  851.                             int i_idx )
  852. {
  853.     VLC_UNUSED( i_idx );
  854.     return ParseSubRipSubViewer( p_demux, p_subtitle,
  855.                                  "%d:%d:%d.%d --> %d:%d:%d.%d",
  856.                                  false );
  857. }
  858. /* ParseSubViewer
  859.  */
  860. static int  ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle,
  861.                             int i_idx )
  862. {
  863.     VLC_UNUSED( i_idx );
  864.     return ParseSubRipSubViewer( p_demux, p_subtitle,
  865.                                  "%d:%d:%d.%d,%d:%d:%d.%d",
  866.                                  true );
  867. }
  868. /* ParseSSA
  869.  */
  870. static int  ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle,
  871.                       int i_idx )
  872. {
  873.     demux_sys_t *p_sys = p_demux->p_sys;
  874.     text_t      *txt = &p_sys->txt;
  875.     for( ;; )
  876.     {
  877.         const char *s = TextGetLine( txt );
  878.         int h1, m1, s1, c1, h2, m2, s2, c2;
  879.         char *psz_text;
  880.         char temp[16];
  881.         if( !s )
  882.             return VLC_EGENERIC;
  883.         /* We expect (SSA2-4):
  884.          * Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
  885.          * Dialogue: Marked=0,0:02:40.65,0:02:41.79,Wolf main,Cher,0000,0000,0000,,Et les enregistrements de ses ondes delta ?
  886.          *
  887.          * SSA-1 is similar but only has 8 commas up untill the subtitle text. Probably the Effect field is no present, but not 100 % sure.
  888.          */
  889.         /* For ASS:
  890.          * Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
  891.          * Dialogue: Layer#,0:02:40.65,0:02:41.79,Wolf main,Cher,0000,0000,0000,,Et les enregistrements de ses ondes delta ?
  892.          */
  893.         /* The output text is - at least, not removing numbers - 18 chars shorter than the input text. */
  894.         psz_text = malloc( strlen(s) );
  895.         if( !psz_text )
  896.             return VLC_ENOMEM;
  897.         if( sscanf( s,
  898.                     "Dialogue: %15[^,],%d:%d:%d.%d,%d:%d:%d.%d,%[^rn]",
  899.                     temp,
  900.                     &h1, &m1, &s1, &c1,
  901.                     &h2, &m2, &s2, &c2,
  902.                     psz_text ) == 10 )
  903.         {
  904.             /* The dec expects: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text */
  905.             /* (Layer comes from ASS specs ... it's empty for SSA.) */
  906.             if( p_sys->i_type == SUB_TYPE_SSA1 )
  907.             {
  908.                 /* SSA1 has only 8 commas before the text starts, not 9 */
  909.                 memmove( &psz_text[1], psz_text, strlen(psz_text)+1 );
  910.                 psz_text[0] = ',';
  911.             }
  912.             else
  913.             {
  914.                 int i_layer = ( p_sys->i_type == SUB_TYPE_ASS ) ? atoi( temp ) : 0;
  915.                 /* ReadOrder, Layer, %s(rest of fields) */
  916.                 snprintf( temp, sizeof(temp), "%d,%d,", i_idx, i_layer );
  917.                 memmove( psz_text + strlen(temp), psz_text, strlen(psz_text)+1 );
  918.                 memcpy( psz_text, temp, strlen(temp) );
  919.             }
  920.             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
  921.                                     (int64_t)m1 * 60*1000 +
  922.                                     (int64_t)s1 * 1000 +
  923.                                     (int64_t)c1 * 10 ) * 1000;
  924.             p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
  925.                                     (int64_t)m2 * 60*1000 +
  926.                                     (int64_t)s2 * 1000 +
  927.                                     (int64_t)c2 * 10 ) * 1000;
  928.             p_subtitle->psz_text = psz_text;
  929.             return VLC_SUCCESS;
  930.         }
  931.         free( psz_text );
  932.         /* All the other stuff we add to the header field */
  933.         if( !p_sys->psz_header )
  934.             p_sys->psz_header = strdup( "" );
  935.         if( !p_sys->psz_header )
  936.             return VLC_ENOMEM;
  937.         p_sys->psz_header =
  938.             realloc( p_sys->psz_header,
  939.                      strlen( p_sys->psz_header ) + strlen( s ) + 2 );
  940.         strcat( p_sys->psz_header,  s );
  941.         strcat( p_sys->psz_header, "n" );
  942.     }
  943. }
  944. /* ParseVplayer
  945.  *  Format
  946.  *      h:m:s:Line1|Line2|Line3....
  947.  *  or
  948.  *      h:m:s Line1|Line2|Line3....
  949.  */
  950. static int ParseVplayer( demux_t *p_demux, subtitle_t *p_subtitle,
  951.                           int i_idx )
  952. {
  953.     VLC_UNUSED( i_idx );
  954.     demux_sys_t *p_sys = p_demux->p_sys;
  955.     text_t      *txt = &p_sys->txt;
  956.     char *psz_text;
  957.     int i;
  958.     for( ;; )
  959.     {
  960.         const char *s = TextGetLine( txt );
  961.         int h1, m1, s1;
  962.         if( !s )
  963.             return VLC_EGENERIC;
  964.         psz_text = malloc( strlen( s ) + 1 );
  965.         if( !psz_text )
  966.             return VLC_ENOMEM;
  967.         if( sscanf( s, "%d:%d:%d%*c%[^rn]",
  968.                     &h1, &m1, &s1, psz_text ) == 4 )
  969.         {
  970.             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
  971.                                     (int64_t)m1 * 60*1000 +
  972.                                     (int64_t)s1 * 1000 ) * 1000;
  973.             p_subtitle->i_stop  = 0;
  974.             break;
  975.         }
  976.         free( psz_text );
  977.     }
  978.     /* replace | by n */
  979.     for( i = 0; psz_text[i] != ''; i++ )
  980.     {
  981.         if( psz_text[i] == '|' )
  982.             psz_text[i] = 'n';
  983.     }
  984.     p_subtitle->psz_text = psz_text;
  985.     return VLC_SUCCESS;
  986. }
  987. /* ParseSami
  988.  */
  989. static char *ParseSamiSearch( text_t *txt,
  990.                               char *psz_start, const char *psz_str )
  991. {
  992.     if( psz_start && strcasestr( psz_start, psz_str ) )
  993.     {
  994.         char *s = strcasestr( psz_start, psz_str );
  995.         return &s[strlen( psz_str )];
  996.     }
  997.     for( ;; )
  998.     {
  999.         char *p = TextGetLine( txt );
  1000.         if( !p )
  1001.             return NULL;
  1002.         if( strcasestr( p, psz_str ) )
  1003.         {
  1004.             char *s = strcasestr( p, psz_str );
  1005.             return &s[strlen( psz_str )];
  1006.         }
  1007.     }
  1008. }
  1009. static int  ParseSami( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
  1010. {
  1011.     VLC_UNUSED( i_idx );
  1012.     demux_sys_t *p_sys = p_demux->p_sys;
  1013.     text_t      *txt = &p_sys->txt;
  1014.     char *s;
  1015.     int64_t i_start;
  1016.     unsigned int i_text;
  1017.     char text[8192]; /* Arbitrary but should be long enough */
  1018.     /* search "Start=" */
  1019.     if( !( s = ParseSamiSearch( txt, NULL, "Start=" ) ) )
  1020.         return VLC_EGENERIC;
  1021.     /* get start value */
  1022.     i_start = strtol( s, &s, 0 );
  1023.     /* search <P */
  1024.     if( !( s = ParseSamiSearch( txt, s, "<P" ) ) )
  1025.         return VLC_EGENERIC;
  1026.     /* search > */
  1027.     if( !( s = ParseSamiSearch( txt, s, ">" ) ) )
  1028.         return VLC_EGENERIC;
  1029.     i_text = 0;
  1030.     text[0] = '';
  1031.     /* now get all txt until  a "Start=" line */
  1032.     for( ;; )
  1033.     {
  1034.         char c = '';
  1035.         /* Search non empty line */
  1036.         while( s && *s == '' )
  1037.             s = TextGetLine( txt );
  1038.         if( !s )
  1039.             break;
  1040.         if( *s == '<' )
  1041.         {
  1042.             if( !strncasecmp( s, "<br", 3 ) )
  1043.             {
  1044.                 c = 'n';
  1045.             }
  1046.             else if( strcasestr( s, "Start=" ) )
  1047.             {
  1048.                 TextPreviousLine( txt );
  1049.                 break;
  1050.             }
  1051.             s = ParseSamiSearch( txt, s, ">" );
  1052.         }
  1053.         else if( !strncmp( s, "&nbsp;", 6 ) )
  1054.         {
  1055.             c = ' ';
  1056.             s += 6;
  1057.         }
  1058.         else if( *s == 't' )
  1059.         {
  1060.             c = ' ';
  1061.             s++;
  1062.         }
  1063.         else
  1064.         {
  1065.             c = *s;
  1066.             s++;
  1067.         }
  1068.         if( c != '' && i_text+1 < sizeof(text) )
  1069.         {
  1070.             text[i_text++] = c;
  1071.             text[i_text] = '';
  1072.         }
  1073.     }
  1074.     p_subtitle->i_start = i_start * 1000;
  1075.     p_subtitle->i_stop  = 0;
  1076.     p_subtitle->psz_text = strdup( text );
  1077.     return VLC_SUCCESS;
  1078. }
  1079. /* ParseDVDSubtitle
  1080.  *  Format
  1081.  *      {T h1:m1:s1:c1
  1082.  *      Line1
  1083.  *      Line2
  1084.  *      ...
  1085.  *      }
  1086.  * TODO it can have a header
  1087.  *      { HEAD
  1088.  *          ...
  1089.  *          CODEPAGE=...
  1090.  *          FORMAT=...
  1091.  *          LANG=English
  1092.  *      }
  1093.  *      LANG support would be cool
  1094.  *      CODEPAGE is probably mandatory FIXME
  1095.  */
  1096. static int ParseDVDSubtitle( demux_t *p_demux, subtitle_t *p_subtitle,
  1097.                              int i_idx )
  1098. {
  1099.     VLC_UNUSED( i_idx );
  1100.     demux_sys_t *p_sys = p_demux->p_sys;
  1101.     text_t      *txt = &p_sys->txt;
  1102.     char *psz_text;
  1103.     for( ;; )
  1104.     {
  1105.         const char *s = TextGetLine( txt );
  1106.         int h1, m1, s1, c1;
  1107.         if( !s )
  1108.             return VLC_EGENERIC;
  1109.         if( sscanf( s,
  1110.                     "{T %d:%d:%d:%d",
  1111.                     &h1, &m1, &s1, &c1 ) == 4 )
  1112.         {
  1113.             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
  1114.                                     (int64_t)m1 * 60*1000 +
  1115.                                     (int64_t)s1 * 1000 +
  1116.                                     (int64_t)c1 * 10) * 1000;
  1117.             p_subtitle->i_stop = 0;
  1118.             break;
  1119.         }
  1120.     }
  1121.     /* Now read text until a line containing "}" */
  1122.     psz_text = strdup("");
  1123.     if( !psz_text )
  1124.         return VLC_ENOMEM;
  1125.     for( ;; )
  1126.     {
  1127.         const char *s = TextGetLine( txt );
  1128.         int i_len;
  1129.         int i_old;
  1130.         if( !s )
  1131.         {
  1132.             free( psz_text );
  1133.             return VLC_EGENERIC;
  1134.         }
  1135.         i_len = strlen( s );
  1136.         if( i_len == 1 && s[0] == '}')
  1137.         {
  1138.             p_subtitle->psz_text = psz_text;
  1139.             return VLC_SUCCESS;
  1140.         }
  1141.         i_old = strlen( psz_text );
  1142.         psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
  1143.         if( !psz_text )
  1144.             return VLC_ENOMEM;
  1145.         strcat( psz_text, s );
  1146.         strcat( psz_text, "n" );
  1147.     }
  1148. }
  1149. /* ParseMPL2
  1150.  *  Format
  1151.  *     [n1][n2]Line1|Line2|Line3...
  1152.  *  where n1 and n2 are the video frame number (n2 can be empty)
  1153.  */
  1154. static int ParseMPL2( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
  1155. {
  1156.     VLC_UNUSED( i_idx );
  1157.     demux_sys_t *p_sys = p_demux->p_sys;
  1158.     text_t      *txt = &p_sys->txt;
  1159.     char *psz_text;
  1160.     int i;
  1161.     for( ;; )
  1162.     {
  1163.         const char *s = TextGetLine( txt );
  1164.         int i_start;
  1165.         int i_stop;
  1166.         if( !s )
  1167.             return VLC_EGENERIC;
  1168.         psz_text = malloc( strlen(s) + 1 );
  1169.         if( !psz_text )
  1170.             return VLC_ENOMEM;
  1171.         i_start = 0;
  1172.         i_stop  = 0;
  1173.         if( sscanf( s, "[%d][] %[^rn]", &i_start, psz_text ) == 2 ||
  1174.             sscanf( s, "[%d][%d] %[^rn]", &i_start, &i_stop, psz_text ) == 3)
  1175.         {
  1176.             p_subtitle->i_start = (int64_t)i_start * 100000;
  1177.             p_subtitle->i_stop  = (int64_t)i_stop  * 100000;
  1178.             break;
  1179.         }
  1180.         free( psz_text );
  1181.     }
  1182.     for( i = 0; psz_text[i] != ''; )
  1183.     {
  1184.         /* replace | by n */
  1185.         if( psz_text[i] == '|' )
  1186.             psz_text[i] = 'n';
  1187.         /* Remove italic */
  1188.         if( psz_text[i] == '/' && ( i == 0 || psz_text[i-1] == 'n' ) )
  1189.             memmove( &psz_text[i], &psz_text[i+1], strlen(&psz_text[i+1])+1 );
  1190.         else
  1191.             i++;
  1192.     }
  1193.     p_subtitle->psz_text = psz_text;
  1194.     return VLC_SUCCESS;
  1195. }
  1196. static int ParseAQT( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
  1197. {
  1198.     VLC_UNUSED( i_idx );
  1199.     demux_sys_t *p_sys = p_demux->p_sys;
  1200.     text_t      *txt = &p_sys->txt;
  1201.     char *psz_text = strdup( "" );
  1202.     int i_old = 0;
  1203.     int i_firstline = 1;
  1204.     for( ;; )
  1205.     {
  1206.         int t; /* Time */
  1207.         const char *s = TextGetLine( txt );
  1208.         if( !s )
  1209.         {
  1210.             free( psz_text );
  1211.             return VLC_EGENERIC;
  1212.         }
  1213.         /* Data Lines */
  1214.         if( sscanf (s, "-->> %d", &t) == 1)
  1215.         {
  1216.             p_subtitle->i_start = (int64_t)t; /* * FPS*/
  1217.             p_subtitle->i_stop  = 0;
  1218.             /* Starting of a subtitle */
  1219.             if( i_firstline )
  1220.             {
  1221.                 i_firstline = 0;
  1222.             }
  1223.             /* We have been too far: end of the subtitle, begin of next */
  1224.             else
  1225.             {
  1226.                 TextPreviousLine( txt );
  1227.                 break;
  1228.             }
  1229.         }
  1230.         /* Text Lines */
  1231.         else
  1232.         {
  1233.             i_old = strlen( psz_text ) + 1;
  1234.             psz_text = realloc( psz_text, i_old + strlen( s ) + 1 );
  1235.             if( !psz_text )
  1236.                  return VLC_ENOMEM;
  1237.             strcat( psz_text, s );
  1238.             strcat( psz_text, "n" );
  1239.             if( txt->i_line == txt->i_line_count )
  1240.                 break;
  1241.         }
  1242.     }
  1243.     p_subtitle->psz_text = psz_text;
  1244.     return VLC_SUCCESS;
  1245. }
  1246. static int ParsePJS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
  1247. {
  1248.     VLC_UNUSED( i_idx );
  1249.     demux_sys_t *p_sys = p_demux->p_sys;
  1250.     text_t      *txt = &p_sys->txt;
  1251.     char *psz_text;
  1252.     int i;
  1253.     for( ;; )
  1254.     {
  1255.         const char *s = TextGetLine( txt );
  1256.         int t1, t2;
  1257.         if( !s )
  1258.             return VLC_EGENERIC;
  1259.         psz_text = malloc( strlen(s) + 1 );
  1260.         if( !psz_text )
  1261.             return VLC_ENOMEM;
  1262.         /* Data Lines */
  1263.         if( sscanf (s, "%d,%d,"%[^nr]", &t1, &t2, psz_text ) == 3 )
  1264.         {
  1265.             /* 1/10th of second ? Frame based ? FIXME */
  1266.             p_subtitle->i_start = 10 * t1;
  1267.             p_subtitle->i_stop = 10 * t2;
  1268.             /* Remove latest " */
  1269.             psz_text[ strlen(psz_text) - 1 ] = '';
  1270.             break;
  1271.         }
  1272.         free( psz_text );
  1273.     }
  1274.     /* replace | by n */
  1275.     for( i = 0; psz_text[i] != ''; i++ )
  1276.     {
  1277.         if( psz_text[i] == '|' )
  1278.             psz_text[i] = 'n';
  1279.     }
  1280.     p_subtitle->psz_text = psz_text;
  1281.     msg_Dbg( p_demux, "%s", psz_text );
  1282.     return VLC_SUCCESS;
  1283. }
  1284. static int ParseMPSub( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
  1285. {
  1286.     VLC_UNUSED( i_idx );
  1287.     demux_sys_t *p_sys = p_demux->p_sys;
  1288.     text_t      *txt = &p_sys->txt;
  1289.     char *psz_text = strdup( "" );
  1290.     if( !p_sys->mpsub.b_inited )
  1291.     {
  1292.         p_sys->mpsub.f_total = 0.0;
  1293.         p_sys->mpsub.f_factor = 0.0;
  1294.         p_sys->mpsub.b_inited = true;
  1295.     }
  1296.     for( ;; )
  1297.     {
  1298.         float f1, f2;
  1299.         char p_dummy;
  1300.         char *psz_temp;
  1301.         const char *s = TextGetLine( txt );
  1302.         if( !s )
  1303.         {
  1304.             free( psz_text );
  1305.             return VLC_EGENERIC;
  1306.         }
  1307.         if( strstr( s, "FORMAT" ) )
  1308.         {
  1309.             if( sscanf (s, "FORMAT=TIM%c", &p_dummy ) == 1 && p_dummy == 'E')
  1310.             {
  1311.                 p_sys->mpsub.f_factor = 100.0;
  1312.                 break;
  1313.             }
  1314.             psz_temp = malloc( strlen(s) );
  1315.             if( !psz_temp )
  1316.             {
  1317.                 free( psz_text );
  1318.                 return VLC_ENOMEM;
  1319.             }
  1320.             if( sscanf( s, "FORMAT=%[^rn]", psz_temp ) )
  1321.             {
  1322.                 float f_fps;
  1323.                 f_fps = us_strtod( psz_temp, NULL );
  1324.                 if( f_fps > 0.0 && var_GetFloat( p_demux, "sub-fps" ) <= 0.0 )
  1325.                     var_SetFloat( p_demux, "sub-fps", f_fps );
  1326.                 p_sys->mpsub.f_factor = 1.0;
  1327.                 free( psz_temp );
  1328.                 break;
  1329.             }
  1330.             free( psz_temp );
  1331.         }
  1332.         /* Data Lines */
  1333.         f1 = us_strtod( s, &psz_temp );
  1334.         if( *psz_temp )
  1335.         {
  1336.             f2 = us_strtod( psz_temp, NULL );
  1337.             p_sys->mpsub.f_total += f1 * p_sys->mpsub.f_factor;
  1338.             p_subtitle->i_start = (int64_t)(10000.0 * p_sys->mpsub.f_total);
  1339.             p_sys->mpsub.f_total += f2 * p_sys->mpsub.f_factor;
  1340.             p_subtitle->i_stop = (int64_t)(10000.0 * p_sys->mpsub.f_total);
  1341.             break;
  1342.         }
  1343.     }
  1344.     for( ;; )
  1345.     {
  1346.         const char *s = TextGetLine( txt );
  1347.         if( !s )
  1348.         {
  1349.             free( psz_text );
  1350.             return VLC_EGENERIC;
  1351.         }
  1352.         int i_len = strlen( s );
  1353.         if( i_len == 0 )
  1354.             break;
  1355.         int i_old = strlen( psz_text );
  1356.         psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
  1357.         if( !psz_text )
  1358.              return VLC_ENOMEM;
  1359.         strcat( psz_text, s );
  1360.         strcat( psz_text, "n" );
  1361.     }
  1362.     p_subtitle->psz_text = psz_text;
  1363.     return VLC_SUCCESS;
  1364. }
  1365. static int ParseJSS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
  1366. {
  1367.     VLC_UNUSED( i_idx );
  1368.     demux_sys_t  *p_sys = p_demux->p_sys;
  1369.     text_t       *txt = &p_sys->txt;
  1370.     char         *psz_text, *psz_orig;
  1371.     char         *psz_text2, *psz_orig2;
  1372.     int h1, h2, m1, m2, s1, s2, f1, f2;
  1373.     if( !p_sys->jss.b_inited )
  1374.     {
  1375.         p_sys->jss.i_comment = 0;
  1376.         p_sys->jss.i_time_resolution = 30;
  1377.         p_sys->jss.i_time_shift = 0;
  1378.         p_sys->jss.b_inited = true;
  1379.     }
  1380.     /* Parse the main lines */
  1381.     for( ;; )
  1382.     {
  1383.         const char *s = TextGetLine( txt );
  1384.         if( !s )
  1385.             return VLC_EGENERIC;
  1386.         psz_orig = malloc( strlen( s ) + 1 );
  1387.         if( !psz_orig )
  1388.             return VLC_ENOMEM;
  1389.         psz_text = psz_orig;
  1390.         /* Complete time lines */
  1391.         if( sscanf( s, "%d:%d:%d.%d %d:%d:%d.%d %[^nr]",
  1392.                     &h1, &m1, &s1, &f1, &h2, &m2, &s2, &f2, psz_text ) == 9 )
  1393.         {
  1394.             p_subtitle->i_start = ( (int64_t)( h1 *3600 + m1 * 60 + s1 ) +
  1395.                 (int64_t)( ( f1 +  p_sys->jss.i_time_shift ) /  p_sys->jss.i_time_resolution ) )
  1396.                 * 1000000;
  1397.             p_subtitle->i_stop = ( (int64_t)( h2 *3600 + m2 * 60 + s2 ) +
  1398.                 (int64_t)( ( f2 +  p_sys->jss.i_time_shift ) /  p_sys->jss.i_time_resolution ) )
  1399.                 * 1000000;
  1400.             break;
  1401.         }
  1402.         /* Short time lines */
  1403.         else if( sscanf( s, "@%d @%d %[^nr]", &f1, &f2, psz_text ) == 3 )
  1404.         {
  1405.             p_subtitle->i_start = (int64_t)(
  1406.                     ( f1 + p_sys->jss.i_time_shift ) / p_sys->jss.i_time_resolution * 1000000.0 );
  1407.             p_subtitle->i_stop = (int64_t)(
  1408.                     ( f2 + p_sys->jss.i_time_shift ) / p_sys->jss.i_time_resolution * 1000000.0 );
  1409.             break;
  1410.         }
  1411.         /* General Directive lines */
  1412.         /* Only TIME and SHIFT are supported so far */
  1413.         else if( s[0] == '#' )
  1414.         {
  1415.             int h = 0, m =0, sec = 1, f = 1;
  1416.             unsigned shift = 1;
  1417.             int inv = 1;
  1418.             strcpy( psz_text, s );
  1419.             switch( toupper( psz_text[1] ) )
  1420.             {
  1421.             case 'S':
  1422.                  shift = isalpha( psz_text[2] ) ? 6 : 2 ;
  1423.                  if( sscanf( &psz_text[shift], "%d", &h ) )
  1424.                  {
  1425.                      /* Negative shifting */
  1426.                      if( h < 0 )
  1427.                      {
  1428.                          h *= -1;
  1429.                          inv = -1;
  1430.                      }
  1431.                      if( sscanf( &psz_text[shift], "%*d:%d", &m ) )
  1432.                      {
  1433.                          if( sscanf( &psz_text[shift], "%*d:%*d:%d", &sec ) )
  1434.                          {
  1435.                              sscanf( &psz_text[shift], "%*d:%*d:%*d.%d", &f );
  1436.                          }
  1437.                          else
  1438.                          {
  1439.                              h = 0;
  1440.                              sscanf( &psz_text[shift], "%d:%d.%d",
  1441.                                      &m, &sec, &f );
  1442.                              m *= inv;
  1443.                          }
  1444.                      }
  1445.                      else
  1446.                      {
  1447.                          h = m = 0;
  1448.                          sscanf( &psz_text[shift], "%d.%d", &sec, &f);
  1449.                          sec *= inv;
  1450.                      }
  1451.                      p_sys->jss.i_time_shift = ( ( h * 3600 + m * 60 + sec )
  1452.                          * p_sys->jss.i_time_resolution + f ) * inv;
  1453.                  }
  1454.                  break;
  1455.             case 'T':
  1456.                 shift = isalpha( psz_text[2] ) ? 8 : 2 ;
  1457.                 sscanf( &psz_text[shift], "%d", &p_sys->jss.i_time_resolution );
  1458.                 break;
  1459.             }
  1460.             free( psz_orig );
  1461.             continue;
  1462.         }
  1463.         else
  1464.             /* Unkown type line, probably a comment */
  1465.         {
  1466.             free( psz_orig );
  1467.             continue;
  1468.         }
  1469.     }
  1470.     while( psz_text[ strlen( psz_text ) - 1 ] == '\' )
  1471.     {
  1472.         const char *s2 = TextGetLine( txt );
  1473.         if( !s2 )
  1474.         {
  1475.             free( psz_orig );
  1476.             return VLC_EGENERIC;
  1477.         }
  1478.         int i_len = strlen( s2 );
  1479.         if( i_len == 0 )
  1480.             break;
  1481.         int i_old = strlen( psz_text );
  1482.         psz_text = realloc( psz_text, i_old + i_len + 1 );
  1483.         if( !psz_text )
  1484.              return VLC_ENOMEM;
  1485. psz_orig = psz_text;
  1486.         strcat( psz_text, s2 );
  1487.     }
  1488.     /* Skip the blanks */
  1489.     while( *psz_text == ' ' || *psz_text == 't' ) psz_text++;
  1490.     /* Parse the directives */
  1491.     if( isalpha( *psz_text ) || *psz_text == '[' )
  1492.     {
  1493.         while( *psz_text != ' ' )
  1494.         { psz_text++ ;};
  1495.         /* Directives are NOT parsed yet */
  1496.         /* This has probably a better place in a decoder ? */
  1497.         /* directive = malloc( strlen( psz_text ) + 1 );
  1498.            if( sscanf( psz_text, "%s %[^nr]", directive, psz_text2 ) == 2 )*/
  1499.     }
  1500.     /* Skip the blanks after directives */
  1501.     while( *psz_text == ' ' || *psz_text == 't' ) psz_text++;
  1502.     /* Clean all the lines from inline comments and other stuffs */
  1503.     psz_orig2 = calloc( strlen( psz_text) + 1, 1 );
  1504.     psz_text2 = psz_orig2;
  1505.     for( ; *psz_text != '' && *psz_text != 'n' && *psz_text != 'r'; )
  1506.     {
  1507.         switch( *psz_text )
  1508.         {
  1509.         case '{':
  1510.             p_sys->jss.i_comment++;
  1511.             break;
  1512.         case '}':
  1513.             if( p_sys->jss.i_comment )
  1514.             {
  1515.                 p_sys->jss.i_comment = 0;
  1516.                 if( (*(psz_text + 1 ) ) == ' ' ) psz_text++;
  1517.             }
  1518.             break;
  1519.         case '~':
  1520.             if( !p_sys->jss.i_comment )
  1521.             {
  1522.                 *psz_text2 = ' ';
  1523.                 psz_text2++;
  1524.             }
  1525.             break;
  1526.         case ' ':
  1527.         case 't':
  1528.             if( (*(psz_text + 1 ) ) == ' ' || (*(psz_text + 1 ) ) == 't' )
  1529.                 break;
  1530.             if( !p_sys->jss.i_comment )
  1531.             {
  1532.                 *psz_text2 = ' ';
  1533.                 psz_text2++;
  1534.             }
  1535.             break;
  1536.         case '\':
  1537.             if( (*(psz_text + 1 ) ) == 'n' )
  1538.             {
  1539.                 *psz_text2 = 'n';
  1540.                 psz_text++;
  1541.                 psz_text2++;
  1542.                 break;
  1543.             }
  1544.             if( ( toupper(*(psz_text + 1 ) ) == 'C' ) ||
  1545.                     ( toupper(*(psz_text + 1 ) ) == 'F' ) )
  1546.             {
  1547.                 psz_text++; psz_text++;
  1548.                 break;
  1549.             }
  1550.             if( (*(psz_text + 1 ) ) == 'B' || (*(psz_text + 1 ) ) == 'b' ||
  1551.                 (*(psz_text + 1 ) ) == 'I' || (*(psz_text + 1 ) ) == 'i' ||
  1552.                 (*(psz_text + 1 ) ) == 'U' || (*(psz_text + 1 ) ) == 'u' ||
  1553.                 (*(psz_text + 1 ) ) == 'D' || (*(psz_text + 1 ) ) == 'N' )
  1554.             {
  1555.                 psz_text++;
  1556.                 break;
  1557.             }
  1558.             if( (*(psz_text + 1 ) ) == '~' || (*(psz_text + 1 ) ) == '{' ||
  1559.                 (*(psz_text + 1 ) ) == '\' )
  1560.                 psz_text++;
  1561.             else if( *(psz_text + 1 ) == 'r' ||  *(psz_text + 1 ) == 'n' ||
  1562.                      *(psz_text + 1 ) == '' )
  1563.             {
  1564. psz_text++;
  1565.             }
  1566.             break;
  1567.         default:
  1568.             if( !p_sys->jss.i_comment )
  1569.             {
  1570.                 *psz_text2 = *psz_text;
  1571.                 psz_text2++;
  1572.             }
  1573.         }
  1574.         psz_text++;
  1575.     }
  1576.     p_subtitle->psz_text = psz_orig2;
  1577.     msg_Dbg( p_demux, "%s", p_subtitle->psz_text );
  1578.     free( psz_orig );
  1579.     return VLC_SUCCESS;
  1580. }
  1581. static int ParsePSB( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
  1582. {
  1583.     VLC_UNUSED( i_idx );
  1584.     demux_sys_t *p_sys = p_demux->p_sys;
  1585.     text_t      *txt = &p_sys->txt;
  1586.     char *psz_text;
  1587.     int i;
  1588.     for( ;; )
  1589.     {
  1590.         int h1, m1, s1;
  1591.         int h2, m2, s2;
  1592.         const char *s = TextGetLine( txt );
  1593.         if( !s )
  1594.             return VLC_EGENERIC;
  1595.         psz_text = malloc( strlen( s ) + 1 );
  1596.         if( !psz_text )
  1597.             return VLC_ENOMEM;
  1598.         if( sscanf( s, "{%d:%d:%d}{%d:%d:%d}%[^rn]",
  1599.                     &h1, &m1, &s1, &h2, &m2, &s2, psz_text ) == 7 )
  1600.         {
  1601.             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
  1602.                                     (int64_t)m1 * 60*1000 +
  1603.                                     (int64_t)s1 * 1000 ) * 1000;
  1604.             p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
  1605.                                     (int64_t)m2 * 60*1000 +
  1606.                                     (int64_t)s2 * 1000 ) * 1000;
  1607.             break;
  1608.         }
  1609.         free( psz_text );
  1610.     }
  1611.     /* replace | by n */
  1612.     for( i = 0; psz_text[i] != ''; i++ )
  1613.     {
  1614.         if( psz_text[i] == '|' )
  1615.             psz_text[i] = 'n';
  1616.     }
  1617.     p_subtitle->psz_text = psz_text;
  1618.     return VLC_SUCCESS;
  1619. }
  1620. static int64_t ParseRealTime( char *psz, int *h, int *m, int *s, int *f )
  1621. {
  1622.     if( strlen( psz ) == 0 ) return 0;
  1623.     if( sscanf( psz, "%d:%d:%d.%d", h, m, s, f ) == 4 ||
  1624.             sscanf( psz, "%d:%d.%d", m, s, f ) == 3 ||
  1625.             sscanf( psz, "%d.%d", s, f ) == 2 ||
  1626.             sscanf( psz, "%d:%d", m, s ) == 2 ||
  1627.             sscanf( psz, "%d", s ) == 1 )
  1628.     {
  1629.         return (int64_t)((( *h * 60 + *m ) * 60 ) + *s ) * 1000 * 1000
  1630.                + (int64_t)*f * 10 * 1000;
  1631.     }
  1632.     else return VLC_EGENERIC;
  1633. }
  1634. static int ParseRealText( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
  1635. {
  1636.     VLC_UNUSED( i_idx );
  1637.     demux_sys_t *p_sys = p_demux->p_sys;
  1638.     text_t      *txt = &p_sys->txt;
  1639.     char *psz_text = NULL;
  1640.     for( ;; )
  1641.     {
  1642.         int h1 = 0, m1 = 0, s1 = 0, f1 = 0;
  1643.         int h2 = 0, m2 = 0, s2 = 0, f2 = 0;
  1644.         const char *s = TextGetLine( txt );
  1645.         free( psz_text );
  1646.         if( !s )
  1647.             return VLC_EGENERIC;
  1648.         psz_text = malloc( strlen( s ) + 1 );
  1649.         if( !psz_text )
  1650.             return VLC_ENOMEM;
  1651.         /* Find the good begining. This removes extra spaces at the beginning
  1652.            of the line.*/
  1653.         char *psz_temp = strcasestr( s, "<time");
  1654.         if( psz_temp != NULL )
  1655.         {
  1656.             char psz_end[12], psz_begin[12];
  1657.             /* Line has begin and end */
  1658.             if( ( sscanf( psz_temp,
  1659.                   "<%*[t|T]ime %*[b|B]egin="%11[^"]" %*[e|E]nd="%11[^"]%*[^>]%[^nr]",
  1660.                             psz_begin, psz_end, psz_text) != 3 ) &&
  1661.                     /* Line has begin and no end */
  1662.                     ( sscanf( psz_temp,
  1663.                               "<%*[t|T]ime %*[b|B]egin="%11[^"]"%*[^>]%[^nr]",
  1664.                               psz_begin, psz_text ) != 2) )
  1665.                 /* Line is not recognized */
  1666.             {
  1667.                 continue;
  1668.             }
  1669.             /* Get the times */
  1670.             int64_t i_time = ParseRealTime( psz_begin, &h1, &m1, &s1, &f1 );
  1671.             if( i_time >= 0)
  1672.             {
  1673.                 p_subtitle->i_start = i_time;
  1674.             }
  1675.             i_time = ParseRealTime( psz_end, &h2, &m2, &s2, &f2 );
  1676.             if( i_time >= 0 )
  1677.             {
  1678.                 p_subtitle->i_stop = i_time;
  1679.             }
  1680.             break;
  1681.         }
  1682.     }
  1683.     /* Get the following Lines */
  1684.     for( ;; )
  1685.     {
  1686.         const char *s = TextGetLine( txt );
  1687.         if( !s )
  1688.         {
  1689.             free( psz_text );
  1690.             return VLC_EGENERIC;
  1691.         }
  1692.         int i_len = strlen( s );
  1693.         if( i_len == 0 ) break;
  1694.         if( strcasestr( s, "<time" ) ||
  1695.             strcasestr( s, "<clear/") )
  1696.         {
  1697.             TextPreviousLine( txt );
  1698.             break;
  1699.         }
  1700.         int i_old = strlen( psz_text );
  1701.         psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
  1702.         if( !psz_text )
  1703.             return VLC_ENOMEM;
  1704.         strcat( psz_text, s );
  1705.         strcat( psz_text, "n" );
  1706.     }
  1707.     /* Remove the starting ">" that remained after the sscanf */
  1708.     memmove( &psz_text[0], &psz_text[1], strlen( psz_text ) );
  1709.     p_subtitle->psz_text = psz_text;
  1710.     return VLC_SUCCESS;
  1711. }
  1712. static int ParseDKS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
  1713. {
  1714.     VLC_UNUSED( i_idx );
  1715.     demux_sys_t *p_sys = p_demux->p_sys;
  1716.     text_t      *txt = &p_sys->txt;
  1717.     char *psz_text;
  1718.     for( ;; )
  1719.     {
  1720.         int h1, m1, s1;
  1721.         int h2, m2, s2;
  1722.         char *s = TextGetLine( txt );
  1723.         if( !s )
  1724.             return VLC_EGENERIC;
  1725.         psz_text = malloc( strlen( s ) + 1 );
  1726.         if( !psz_text )
  1727.             return VLC_ENOMEM;
  1728.         if( sscanf( s, "[%d:%d:%d]%[^rn]",
  1729.                     &h1, &m1, &s1, psz_text ) == 4 )
  1730.         {
  1731.             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
  1732.                                     (int64_t)m1 * 60*1000 +
  1733.                                     (int64_t)s1 * 1000 ) * 1000;
  1734.             char *s = TextGetLine( txt );
  1735.             if( !s )
  1736.             {
  1737.                 free( psz_text );
  1738.                 return VLC_EGENERIC;
  1739.             }
  1740.             if( sscanf( s, "[%d:%d:%d]", &h2, &m2, &s2 ) == 3 )
  1741.                 p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
  1742.                                         (int64_t)m2 * 60*1000 +
  1743.                                         (int64_t)s2 * 1000 ) * 1000;
  1744.             break;
  1745.         }
  1746.         free( psz_text );
  1747.     }
  1748.     /* replace [br] by n */
  1749.     char *p;
  1750.     while( ( p = strstr( psz_text, "[br]" ) ) )
  1751.     {
  1752.         *p++ = 'n';
  1753.         memmove( p, &p[3], strlen(&p[3])+1 );
  1754.     }
  1755.     p_subtitle->psz_text = psz_text;
  1756.     return VLC_SUCCESS;
  1757. }
  1758. static int ParseSubViewer1( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
  1759. {
  1760.     VLC_UNUSED( i_idx );
  1761.     demux_sys_t *p_sys = p_demux->p_sys;
  1762.     text_t      *txt = &p_sys->txt;
  1763.     char *psz_text;
  1764.     for( ;; )
  1765.     {
  1766.         int h1, m1, s1;
  1767.         int h2, m2, s2;
  1768.         char *s = TextGetLine( txt );
  1769.         if( !s )
  1770.             return VLC_EGENERIC;
  1771.         if( sscanf( s, "[%d:%d:%d]", &h1, &m1, &s1 ) == 3 )
  1772.         {
  1773.             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
  1774.                                     (int64_t)m1 * 60*1000 +
  1775.                                     (int64_t)s1 * 1000 ) * 1000;
  1776.             char *s = TextGetLine( txt );
  1777.             if( !s )
  1778.                 return VLC_EGENERIC;
  1779.             psz_text = strdup( s );
  1780.             if( !psz_text )
  1781.                 return VLC_ENOMEM;
  1782.             s = TextGetLine( txt );
  1783.             if( !s )
  1784.             {
  1785.                 free( psz_text );
  1786.                 return VLC_EGENERIC;
  1787.             }
  1788.             if( sscanf( s, "[%d:%d:%d]", &h2, &m2, &s2 ) == 3 )
  1789.                 p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
  1790.                                         (int64_t)m2 * 60*1000 +
  1791.                                         (int64_t)s2 * 1000 ) * 1000;
  1792.             break;
  1793.         }
  1794.     }
  1795.     p_subtitle->psz_text = psz_text;
  1796.     return VLC_SUCCESS;
  1797. }