Code Search for Developers
 
 
  

subreader.c from The Open2x Project at Krugle


Show subreader.c syntax highlighted

/*              
 *  Original code routine from Mplayer < www.mplayerhq.hu >             
 *
 *  - godori <ghcstop>, www.aesop-embedded.org
 *    => Modified. Jan, 2005
 *
 *    => DIGNSYS Inc. < www.dignsys.com > developing from April 2005
 *
 */



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include <sys/types.h>
#include <dirent.h>

#include "config.h"
#include "mp_msg.h"
#include "subreader.h"

#ifdef HAVE_ENCA
#    include <enca.h>
#endif

#define ERR ((void *) -1)

#ifdef USE_ICONV
#    include <iconv.h>
char           *sub_cp = NULL;
#endif
#ifdef USE_FRIBIDI
#    include <fribidi/fribidi.h>
char           *fribidi_charset = NULL; 
int             flip_hebrew = 1;    
int             fribidi_flip_commas = 0;    
#endif

extern char    *dvdsub_lang;


#define LINE_LEN 1000
static float    mpsub_position = 0;
static float    mpsub_multiplier = 1.;
static int      sub_slacktime = 20000;  
int             sub_no_text_pp = 0; 

int             sub_match_fuzziness = 0;    
int             sub_format = SUB_INVALID;

#ifdef USE_SORTSUB

unsigned long   previous_sub_end;
#endif

static int
eol(char p)
{
    return (p == '\r' || p == '\n' || p == '\0');
}


static void
trail_space(char *s)
{
    int             i = 0;

    while (isspace(s[i]))
        ++i;
    if (i)
        strcpy(s, s + i);
    i = strlen(s) - 1;
    while (i > 0 && isspace(s[i]))
        s[i--] = '\0';
}

static char    *
stristr(const char *haystack, const char *needle)
{
    int             len = 0;
    const char     *p = haystack;

    if (!(haystack && needle))
        return NULL;

    len = strlen(needle);
    while (*p != '\0')
    {
        if (strncasecmp(p, needle, len) == 0)
            return (char *) p;
        p++;
    }

    return NULL;
}

subtitle       *
sub_read_line_sami(FILE * fd, subtitle * current)
{
    static char     line[LINE_LEN + 1];
    static char    *s = NULL,
        *slacktime_s;
    char            text[LINE_LEN + 1],
                   *p = NULL,
        *q;
    int             state;

    current->lines = current->start = current->end = 0;
    current->alignment = SUB_ALIGNMENT_BOTTOMCENTER;
    state = 0;

    
    if (!s)
        if (!(s = fgets(line, LINE_LEN, fd)))
            return 0;

    do
    {
        switch (state)
        {

        case 0:                
            slacktime_s = stristr(s, "Slacktime:");
            if (slacktime_s)
                sub_slacktime = strtol(slacktime_s + 10, NULL, 0) / 10;

            s = stristr(s, "Start=");
            if (s)
            {
                current->start = strtol(s + 6, &s, 0) / 10;
                
                for (; *s != '>' && *s != '\0'; s++);
                s++;
                state = 1;
                continue;
            }
            break;

        case 1:                
            for (; *s == ' ' || *s == '\t'; s++);   
            if (*s == '\0')
                break;
            if (*s != '<')
            {
                state = 3;
                p = text;
                continue;
            }                   
            s++;
            if (*s == 'P' || *s == 'p')
            {
                s++;
                state = 2;
                continue;
            }                   
            for (; *s != '>' && *s != '\0'; s++);   
            if (s == '\0')
                break;
            s++;
            continue;

        case 2:                
            if ((s = strchr(s, '>')))
            {
                s++;
                state = 3;
                p = text;
                continue;
            }
            break;

        case 3:                
            if (*s == '\0')
                break;
            else if (!strncasecmp(s, "<br>", 4))
            {
                *p = '\0';
                p = text;
                trail_space(text);
                if (text[0] != '\0')
                    current->text[current->lines++] = strdup(text);
                s += 4;
            }
            else if ((*s == '{') && !sub_no_text_pp)
            {
                state = 5;
                ++s;
                continue;
            }
            else if (*s == '<')
            {
                state = 4;
            }
            else if (!strncasecmp(s, "&nbsp;", 6))
            {
                *p++ = ' ';
                s += 6;
            }
            else if (*s == '\t')
            {
                *p++ = ' ';
                s++;
            }
            else if (*s == '\r' || *s == '\n')
            {
                s++;
            }
            else
                *p++ = *s++;

            
            if (p > text + 2)
                if (*(p - 1) == ' ' && *(p - 2) == ' ')
                    p--;

            continue;

        case 4:                
            q = stristr(s, "Start=");
            if (q)
            {
                current->end = strtol(q + 6, &q, 0) / 10 - 1;
                *p = '\0';
                trail_space(text);
                if (text[0] != '\0')
                    current->text[current->lines++] = strdup(text);
                if (current->lines > 0)
                {
                    state = 99;
                    break;
                }
                state = 0;
                continue;
            }
            s = strchr(s, '>');
            if (s)
            {
                s++;
                state = 3;
                continue;
            }
            break;
        case 5:                
            if ((*s == '\\') && (*(s + 1) == 'a') && !sub_no_text_pp)
            {
                if (stristr(s, "\\a1") != NULL)
                {
                    current->alignment = SUB_ALIGNMENT_BOTTOMLEFT;
                    s = s + 3;
                }
                if (stristr(s, "\\a2") != NULL)
                {
                    current->alignment = SUB_ALIGNMENT_BOTTOMCENTER;
                    s = s + 3;
                }
                else if (stristr(s, "\\a3") != NULL)
                {
                    current->alignment = SUB_ALIGNMENT_BOTTOMRIGHT;
                    s = s + 3;
                }
                else if ((stristr(s, "\\a4") != NULL) || (stristr(s, "\\a5") != NULL) || (stristr(s, "\\a8") != NULL))
                {
                    current->alignment = SUB_ALIGNMENT_TOPLEFT;
                    s = s + 3;
                }
                else if (stristr(s, "\\a6") != NULL)
                {
                    current->alignment = SUB_ALIGNMENT_TOPCENTER;
                    s = s + 3;
                }
                else if (stristr(s, "\\a7") != NULL)
                {
                    current->alignment = SUB_ALIGNMENT_TOPRIGHT;
                    s = s + 3;
                }
                else if (stristr(s, "\\a9") != NULL)
                {
                    current->alignment = SUB_ALIGNMENT_MIDDLELEFT;
                    s = s + 3;
                }
                else if (stristr(s, "\\a10") != NULL)
                {
                    current->alignment = SUB_ALIGNMENT_MIDDLECENTER;
                    s = s + 4;
                }
                else if (stristr(s, "\\a11") != NULL)
                {
                    current->alignment = SUB_ALIGNMENT_MIDDLERIGHT;
                    s = s + 4;
                }
            }
            if (*s == '}')
                state = 3;
            ++s;
            continue;
        }

        
        if (state != 99 && !(s = fgets(line, LINE_LEN, fd)))
        {
            if (current->start > 0)
            {
                break;          
            }
            else
            {
                return 0;
            }
        }

    }
    while (state != 99);

    
    if (current->end <= 0)
    {
        current->end = current->start + sub_slacktime;
        *p = '\0';
        trail_space(text);
        if (text[0] != '\0')
            current->text[current->lines++] = strdup(text);
    }

    return current;
}


char           *
sub_readtext(char *source, char **dest)
{
    int             len = 0;
    char           *p = source;



    while (!eol(*p) && *p != '|')
    {
        p++, len++;
    }

    *dest = (char *) malloc(len + 1);
    if (!dest)
    {
        return ERR;
    }

    strncpy(*dest, source, len);
    (*dest)[len] = 0;

    while (*p == '\r' || *p == '\n' || *p == '|')
        p++;

    if (*p)
        return p;               
    else
        return NULL;            
}

subtitle       *
sub_read_line_microdvd(FILE * fd, subtitle * current)
{
    char            line[LINE_LEN + 1];
    char            line2[LINE_LEN + 1];
    char           *p,
                   *next;
    int             i;

    do
    {
        if (!fgets(line, LINE_LEN, fd))
            return NULL;
    }
    while ((sscanf(line, "{%ld}{}%[^\r\n]", &(current->start), line2) < 2) && (sscanf(line, "{%ld}{%ld}%[^\r\n]", &(current->start), &(current->end), line2) < 3));

    p = line2;

    next = p, i = 0;
    while ((next = sub_readtext(next, &(current->text[i]))))
    {
        if (current->text[i] == ERR)
        {
            return ERR;
        }
        i++;
        if (i >= SUB_MAX_TEXT)
        {
            mp_msg(MSGT_SUBREADER, MSGL_WARN, "Too many lines in a subtitle\n");
            current->lines = i;
            return current;
        }
    }
    current->lines = ++i;

    return current;
}

subtitle       *
sub_read_line_mpl2(FILE * fd, subtitle * current)
{
    char            line[LINE_LEN + 1];
    char            line2[LINE_LEN + 1];
    char           *p,
                   *next;
    int             i;

    do
    {
        if (!fgets(line, LINE_LEN, fd))
            return NULL;
    }
    while ((sscanf(line, "[%ld][%ld]%[^\r\n]", &(current->start), &(current->end), line2) < 3));
    current->start *= 10;
    current->end *= 10;
    p = line2;

    next = p, i = 0;
    while ((next = sub_readtext(next, &(current->text[i]))))
    {
        if (current->text[i] == ERR)
        {
            return ERR;
        }
        i++;
        if (i >= SUB_MAX_TEXT)
        {
            mp_msg(MSGT_SUBREADER, MSGL_WARN, "Too many lines in a subtitle\n");
            current->lines = i;
            return current;
        }
    }
    current->lines = ++i;

    return current;
}

subtitle       *
sub_read_line_subrip(FILE * fd, subtitle * current)
{
    char            line[LINE_LEN + 1];
    int             a1,
                    a2,
                    a3,
                    a4,
                    b1,
                    b2,
                    b3,
                    b4;
    char           *p = NULL,
        *q = NULL;
    int             len;

    while (1)
    {
        if (!fgets(line, LINE_LEN, fd))
            return NULL;
        if (sscanf(line, "%d:%d:%d.%d,%d:%d:%d.%d", &a1, &a2, &a3, &a4, &b1, &b2, &b3, &b4) < 8)
            continue;
        current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4;
        current->end = b1 * 360000 + b2 * 6000 + b3 * 100 + b4;

        if (!fgets(line, LINE_LEN, fd))
            return NULL;

        p = q = line;
        for (current->lines = 1; current->lines < SUB_MAX_TEXT; current->lines++)
        {
            for (q = p, len = 0; *p && *p != '\r' && *p != '\n' && *p != '|' && strncmp(p, "[br]", 4); p++, len++);
            current->text[current->lines - 1] = (char *) malloc(len + 1);
            if (!current->text[current->lines - 1])
                return ERR;
            strncpy(current->text[current->lines - 1], q, len);
            current->text[current->lines - 1][len] = '\0';
            if (!*p || *p == '\r' || *p == '\n')
                break;
            if (*p == '|')
                p++;
            else
                while (*p++ != ']');
        }
        break;
    }
    return current;
}

subtitle       *
sub_read_line_subviewer(FILE * fd, subtitle * current)
{
    char            line[LINE_LEN + 1];
    int             a1,
                    a2,
                    a3,
                    a4,
                    b1,
                    b2,
                    b3,
                    b4;
    char           *p = NULL;
    int             i,
                    len;

    while (!current->text[0])
    {
        if (!fgets(line, LINE_LEN, fd))
            return NULL;
        if ((len = sscanf(line, "%d:%d:%d%[,.:]%d --> %d:%d:%d%[,.:]%d", &a1, &a2, &a3, (char *) &i, &a4, &b1, &b2, &b3, (char *) &i, &b4)) < 10)
            continue;
        current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4 / 10;
        current->end = b1 * 360000 + b2 * 6000 + b3 * 100 + b4 / 10;
        for (i = 0; i < SUB_MAX_TEXT;)
        {
            if (!fgets(line, LINE_LEN, fd))
                break;
            len = 0;
            for (p = line; *p != '\n' && *p != '\r' && *p; p++, len++);
            if (len)
            {
                int             j = 0,
                    skip = 0;
                char           *curptr = current->text[i] = (char *) malloc(len + 1);

                if (!current->text[i])
                    return ERR;
                
                for (; j < len; j++)
                {
                    
                    if (line[j] == '>')
                    {
                        skip = 0;
                        continue;
                    }
                    if (line[j] == '<')
                    {
                        skip = 1;
                        continue;
                    }
                    if (skip)
                    {
                        continue;
                    }
                    *curptr = line[j];
                    curptr++;
                }
                *curptr = '\0';

                i++;
            }
            else
            {
                break;
            }
        }
        current->lines = i;
    }
    return current;
}

subtitle       *
sub_read_line_subviewer2(FILE * fd, subtitle * current)
{
    char            line[LINE_LEN + 1];
    int             a1,
                    a2,
                    a3,
                    a4;
    char           *p = NULL;
    int             i,
                    len;

    while (!current->text[0])
    {
        if (!fgets(line, LINE_LEN, fd))
            return NULL;
        if (line[0] != '{')
            continue;
        if ((len = sscanf(line, "{T %d:%d:%d:%d", &a1, &a2, &a3, &a4)) < 4)
            continue;
        current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4 / 10;
        for (i = 0; i < SUB_MAX_TEXT;)
        {
            if (!fgets(line, LINE_LEN, fd))
                break;
            if (line[0] == '}')
                break;
            len = 0;
            for (p = line; *p != '\n' && *p != '\r' && *p; ++p, ++len);
            if (len)
            {
                current->text[i] = (char *) malloc(len + 1);
                if (!current->text[i])
                    return ERR;
                strncpy(current->text[i], line, len);
                current->text[i][len] = '\0';
                ++i;
            }
            else
            {
                break;
            }
        }
        current->lines = i;
    }
    return current;
}


subtitle       *
sub_read_line_vplayer(FILE * fd, subtitle * current)
{
    char            line[LINE_LEN + 1];
    int             a1,
                    a2,
                    a3;
    char           *p = NULL,
        *next,
        separator;
    int             i,
                    len,
                    plen;

    while (!current->text[0])
    {
        if (!fgets(line, LINE_LEN, fd))
            return NULL;
        if ((len = sscanf(line, "%d:%d:%d%c%n", &a1, &a2, &a3, &separator, &plen)) < 4)
            continue;

        if (!(current->start = a1 * 360000 + a2 * 6000 + a3 * 100))
            continue;
        
        
        
        
        p = &line[plen];

        i = 0;
        if (*p != '|')
        {
            
            next = p, i = 0;
            while ((next = sub_readtext(next, &(current->text[i]))))
            {
                if (current->text[i] == ERR)
                {
                    return ERR;
                }
                i++;
                if (i >= SUB_MAX_TEXT)
                {
                    mp_msg(MSGT_SUBREADER, MSGL_WARN, "Too many lines in a subtitle\n");
                    current->lines = i;
                    return current;
                }
            }
            current->lines = i + 1;
        }
    }
    return current;
}

subtitle       *
sub_read_line_rt(FILE * fd, subtitle * current)
{
    
    
    
    char            line[LINE_LEN + 1];
    int             a1,
                    a2,
                    a3,
                    a4,
                    b1,
                    b2,
                    b3,
                    b4;
    char           *p = NULL,
        *next = NULL;
    int             i,
                    len,
                    plen;

    while (!current->text[0])
    {
        if (!fgets(line, LINE_LEN, fd))
            return NULL;
        
        
        
        plen = a1 = a2 = a3 = a4 = b1 = b2 = b3 = b4 = 0;
        if (((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d.%d\" %*[Ee]nd=\"%d.%d\"%*[^<]<clear/>%n", &a3, &a4, &b3, &b4, &plen)) < 4) &&
            ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d.%d\" %*[Ee]nd=\"%d:%d.%d\"%*[^<]<clear/>%n", &a3, &a4, &b2, &b3, &b4, &plen)) < 5) &&
            ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d:%d\" %*[Ee]nd=\"%d:%d\"%*[^<]<clear/>%n", &a2, &a3, &b2, &b3, &plen)) < 4) &&
            ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d:%d\" %*[Ee]nd=\"%d:%d.%d\"%*[^<]<clear/>%n", &a2, &a3, &b2, &b3, &b4, &plen)) < 5) &&

            ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d:%d.%d\" %*[Ee]nd=\"%d:%d.%d\"%*[^<]<clear/>%n", &a2, &a3, &a4, &b2, &b3, &b4, &plen)) < 6) &&
            ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d:%d:%d.%d\" %*[Ee]nd=\"%d:%d:%d.%d\"%*[^<]<clear/>%n", &a1, &a2, &a3, &a4, &b1, &b2, &b3, &b4, &plen)) < 8) &&
            
            ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d.%d\"%*[^<]<clear/>%n", &a3, &a4, &plen)) < 2) &&
            ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d:%d\"%*[^<]<clear/>%n", &a2, &a3, &plen)) < 2) &&
            ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d:%d.%d\"%*[^<]<clear/>%n", &a2, &a3, &a4, &plen)) < 3) &&
            ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d:%d:%d.%d\"%*[^<]<clear/>%n", &a1, &a2, &a3, &a4, &plen)) < 4))
            continue;
        current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4 / 10;
        current->end = b1 * 360000 + b2 * 6000 + b3 * 100 + b4 / 10;
        if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0)
            current->end = current->start + 200;
        p = line;
        p += plen;
        i = 0;
        
        next = strstr(line, "<clear/>");
        if (next && strlen(next) > 8)
        {
            next += 8;
            i = 0;
            while ((next = sub_readtext(next, &(current->text[i]))))
            {
                if (current->text[i] == ERR)
                {
                    return ERR;
                }
                i++;
                if (i >= SUB_MAX_TEXT)
                {
                    mp_msg(MSGT_SUBREADER, MSGL_WARN, "Too many lines in a subtitle\n");
                    current->lines = i;
                    return current;
                }
            }
        }
        current->lines = i + 1;
    }
    return current;
}

subtitle       *
sub_read_line_ssa(FILE * fd, subtitle * current)
{

    int             comma;
    static int      max_comma = 32; 

    

    int             hour1,
                    min1,
                    sec1,
                    hunsec1,
                    hour2,
                    min2,
                    sec2,
                    hunsec2,
                    nothing;
    int             num;

    char            line[LINE_LEN + 1],
                    line3[LINE_LEN + 1],
                   *line2;
    char           *tmp;

    do
    {
        if (!fgets(line, LINE_LEN, fd))
            return NULL;
    }
    while (sscanf(line, "Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d,"
                  "%[^\n\r]", &nothing,
                  &hour1, &min1, &sec1, &hunsec1,
                  &hour2, &min2, &sec2, &hunsec2,
                  line3) < 9 && sscanf(line, "Dialogue: %d,%d:%d:%d.%d,%d:%d:%d.%d," "%[^\n\r]", &nothing, &hour1, &min1, &sec1, &hunsec1, &hour2, &min2, &sec2, &hunsec2, line3) < 9);

    line2 = strchr(line3, ',');

    for (comma = 4; comma < max_comma; comma++)
    {
        tmp = line2;
        if (!(tmp = strchr(++tmp, ',')))
            break;
        if (*(++tmp) == ' ')
            break;
        
        line2 = tmp;
    }

    if (comma < max_comma)
        max_comma = comma;
    
    if (*line2 == ',')
        line2++;

    current->lines = 0;
    num = 0;
    current->start = 360000 * hour1 + 6000 * min1 + 100 * sec1 + hunsec1;
    current->end = 360000 * hour2 + 6000 * min2 + 100 * sec2 + hunsec2;

    while (((tmp = strstr(line2, "\\n")) != NULL) || ((tmp = strstr(line2, "\\N")) != NULL))
    {
        current->text[num] = (char *) malloc(tmp - line2 + 1);
        strncpy(current->text[num], line2, tmp - line2);
        current->text[num][tmp - line2] = '\0';
        line2 = tmp + 2;
        num++;
        current->lines++;
        if (current->lines >= SUB_MAX_TEXT)
            return current;
    }

    current->text[num] = strdup(line2);
    current->lines++;

    return current;
}

void
sub_pp_ssa(subtitle * sub)
{
    int             l = sub->lines;
    char           *so,
                   *de,
                   *start;

    while (l)
    {
        
        so = de = sub->text[--l];
        while (*so)
        {
            if (*so == '{' && so[1] == '\\')
            {
                for (start = so; *so && *so != '}'; so++);
                if (*so)
                    so++;
                else
                    so = start;
            }
            if (*so)
            {
                *de = *so;
                so++;
                de++;
            }
        }
        *de = *so;
    }
}


subtitle       *
sub_read_line_pjs(FILE * fd, subtitle * current)
{
    char            line[LINE_LEN + 1];
    char            text[LINE_LEN + 1],
                   *s,
                   *d;

    if (!fgets(line, LINE_LEN, fd))
        return NULL;
    
    for (s = line; *s && isspace(*s); s++);
    
    if (*s == 0)
        return NULL;
    
    if (sscanf(s, "%ld,%ld,", &(current->start), &(current->end)) < 2)
    {
        return ERR;
    }
    
    current->start *= 10;
    current->end *= 10;
    
    for (; *s; s++)
        if (*s == ',')
            break;
    if (*s)
    {
        for (s++; *s; s++)
            if (*s == ',')
                break;
        if (*s)
            s++;
    }
    if (*s != '"')
    {
        return ERR;
    }
    
    for (s++, d = text; *s && *s != '"'; s++, d++)
        *d = *s;
    *d = 0;
    current->text[0] = strdup(text);
    current->lines = 1;

    return current;
}

subtitle       *
sub_read_line_mpsub(FILE * fd, subtitle * current)
{
    char            line[LINE_LEN + 1];
    float           a,
                    b;
    int             num = 0;
    char           *p,
                   *q;

    do
    {
        if (!fgets(line, LINE_LEN, fd))
            return NULL;
    }
    while (sscanf(line, "%f %f", &a, &b) != 2);

    mpsub_position += a * mpsub_multiplier;
    current->start = (int) mpsub_position;
    mpsub_position += b * mpsub_multiplier;
    current->end = (int) mpsub_position;

    while (num < SUB_MAX_TEXT)
    {
        if (!fgets(line, LINE_LEN, fd))
        {
            if (num == 0)
                return NULL;
            else
                return current;
        }
        p = line;
        while (isspace(*p))
            p++;
        if (eol(*p) && num > 0)
            return current;
        if (eol(*p))
            return NULL;

        for (q = p; !eol(*q); q++);
        *q = '\0';
        if (strlen(p))
        {
            current->text[num] = strdup(p);

            current->lines = ++num;
        }
        else
        {
            if (num)
                return current;
            else
                return NULL;
        }
    }
    return NULL;                
}

#ifndef USE_SORTSUB

subtitle       *previous_aqt_sub = NULL;
#endif

subtitle       *
sub_read_line_aqt(FILE * fd, subtitle * current)
{
    char            line[LINE_LEN + 1];
    char           *next;
    int             i;

    while (1)
    {
        
        if (!fgets(line, LINE_LEN, fd))
            return NULL;
        if (!(sscanf(line, "-->> %ld", &(current->start)) < 1))
            break;
    }

#ifdef USE_SORTSUB
    previous_sub_end = (current->start) ? current->start - 1 : 0;
#else
    if (previous_aqt_sub != NULL)
        previous_aqt_sub->end = current->start - 1;

    previous_aqt_sub = current;
#endif

    if (!fgets(line, LINE_LEN, fd))
        return NULL;

    sub_readtext((char *) &line, &current->text[0]);
    current->lines = 1;
    current->end = current->start;  

    if (!fgets(line, LINE_LEN, fd))
        return current;

    next = line, i = 1;
    while ((next = sub_readtext(next, &(current->text[i]))))
    {
        if (current->text[i] == ERR)
        {
            return ERR;
        }
        i++;
        if (i >= SUB_MAX_TEXT)
        {
            mp_msg(MSGT_SUBREADER, MSGL_WARN, "Too many lines in a subtitle\n");
            current->lines = i;
            return current;
        }
    }
    current->lines = i + 1;

    if ((current->text[0] == "") && (current->text[1] == ""))
    {
#ifdef USE_SORTSUB
        previous_sub_end = 0;
#else
        
        previous_aqt_sub = NULL;
#endif
        return NULL;
    }

    return current;
}

#ifndef USE_SORTSUB
subtitle       *previous_subrip09_sub = NULL;
#endif

subtitle       *
sub_read_line_subrip09(FILE * fd, subtitle * current)
{
    char            line[LINE_LEN + 1];
    int             a1,
                    a2,
                    a3;
    char           *next = NULL;
    int             i,
                    len;

    while (1)
    {
        
        if (!fgets(line, LINE_LEN, fd))
            return NULL;
        if (!((len = sscanf(line, "[%d:%d:%d]", &a1, &a2, &a3)) < 3))
            break;
    }

    current->start = a1 * 360000 + a2 * 6000 + a3 * 100;

#ifdef USE_SORTSUB
    previous_sub_end = (current->start) ? current->start - 1 : 0;
#else
    if (previous_subrip09_sub != NULL)
        previous_subrip09_sub->end = current->start - 1;

    previous_subrip09_sub = current;
#endif

    if (!fgets(line, LINE_LEN, fd))
        return NULL;

    next = line, i = 0;

    current->text[0] = "";      

    while ((next = sub_readtext(next, &(current->text[i]))))
    {
        if (current->text[i] == ERR)
        {
            return ERR;
        }
        i++;
        if (i >= SUB_MAX_TEXT)
        {
            mp_msg(MSGT_SUBREADER, MSGL_WARN, "Too many lines in a subtitle\n");
            current->lines = i;
            return current;
        }
    }
    current->lines = i + 1;

    if ((current->text[0] == "") && (i == 0))
    {
#ifdef USE_SORTSUB
        previous_sub_end = 0;
#else
        
        previous_subrip09_sub = NULL;
#endif
        return NULL;
    }

    return current;
}

subtitle       *
sub_read_line_jacosub(FILE * fd, subtitle * current)
{
    char            line1[LINE_LEN],
                    line2[LINE_LEN],
                    directive[LINE_LEN],
                   *p,
                   *q;
    unsigned        a1,
                    a2,
                    a3,
                    a4,
                    b1,
                    b2,
                    b3,
                    b4,
                    comment = 0;
    static unsigned jacoTimeres = 30;
    static int      jacoShift = 0;

    bzero(current, sizeof(subtitle));
    bzero(line1, LINE_LEN);
    bzero(line2, LINE_LEN);
    bzero(directive, LINE_LEN);
    while (!current->text[0])
    {
        if (!fgets(line1, LINE_LEN, fd))
        {
            return NULL;
        }
        if (sscanf(line1, "%u:%u:%u.%u %u:%u:%u.%u %[^\n\r]", &a1, &a2, &a3, &a4, &b1, &b2, &b3, &b4, line2) < 9)
        {
            if (sscanf(line1, "@%u @%u %[^\n\r]", &a4, &b4, line2) < 3)
            {
                if (line1[0] == '#')
                {
                    int             hours = 0,
                        minutes = 0,
                        seconds,
                        delta,
                        inverter = 1;
                    unsigned        units = jacoShift;

                    switch (toupper(line1[1]))
                    {
                    case 'S':
                        if (isalpha(line1[2]))
                        {
                            delta = 6;
                        }
                        else
                        {
                            delta = 2;
                        }
                        if (sscanf(&line1[delta], "%d", &hours))
                        {
                            if (hours < 0)
                            {
                                hours *= -1;
                                inverter = -1;
                            }
                            if (sscanf(&line1[delta], "%*d:%d", &minutes))
                            {
                                if (sscanf(&line1[delta], "%*d:%*d:%d", &seconds))
                                {
                                    sscanf(&line1[delta], "%*d:%*d:%*d.%d", &units);
                                }
                                else
                                {
                                    hours = 0;
                                    sscanf(&line1[delta], "%d:%d.%d", &minutes, &seconds, &units);
                                    minutes *= inverter;
                                }
                            }
                            else
                            {
                                hours = minutes = 0;
                                sscanf(&line1[delta], "%d.%d", &seconds, &units);
                                seconds *= inverter;
                            }
                            jacoShift = ((hours * 3600 + minutes * 60 + seconds) * jacoTimeres + units) * inverter;
                        }
                        break;
                    case 'T':
                        if (isalpha(line1[2]))
                        {
                            delta = 8;
                        }
                        else
                        {
                            delta = 2;
                        }
                        sscanf(&line1[delta], "%u", &jacoTimeres);
                        break;
                    }
                }
                continue;
            }
            else
            {
                current->start = (unsigned long) ((a4 + jacoShift) * 100.0 / jacoTimeres);
                current->end = (unsigned long) ((b4 + jacoShift) * 100.0 / jacoTimeres);
            }
        }
        else
        {
            current->start = (unsigned long) (((a1 * 3600 + a2 * 60 + a3) * jacoTimeres + a4 + jacoShift) * 100.0 / jacoTimeres);
            current->end = (unsigned long) (((b1 * 3600 + b2 * 60 + b3) * jacoTimeres + b4 + jacoShift) * 100.0 / jacoTimeres);
        }
        current->lines = 0;
        p = line2;
        while ((*p == ' ') || (*p == '\t'))
        {
            ++p;
        }
        if (isalpha(*p) || *p == '[')
        {
            int             cont,
                            jLength;

            if (sscanf(p, "%s %[^\n\r]", directive, line1) < 2)
                return (subtitle *) ERR;
            jLength = strlen(directive);
            for (cont = 0; cont < jLength; ++cont)
            {
                if (isalpha(*(directive + cont)))
                    *(directive + cont) = toupper(*(directive + cont));
            }
            if ((strstr(directive, "RDB") != NULL) || (strstr(directive, "RDC") != NULL) || (strstr(directive, "RLB") != NULL) || (strstr(directive, "RLG") != NULL))
            {
                continue;
            }
            if (strstr(directive, "JL") != NULL)
            {
                current->alignment = SUB_ALIGNMENT_BOTTOMLEFT;
            }
            else if (strstr(directive, "JR") != NULL)
            {
                current->alignment = SUB_ALIGNMENT_BOTTOMRIGHT;
            }
            else
            {
                current->alignment = SUB_ALIGNMENT_BOTTOMCENTER;
            }
            strcpy(line2, line1);
            p = line2;
        }
        for (q = line1; (!eol(*p)) && (current->lines < SUB_MAX_TEXT); ++p)
        {
            switch (*p)
            {
            case '{':
                comment++;
                break;
            case '}':
                if (comment)
                {
                    --comment;
                    
                    if ((*(p + 1)) == ' ')
                        p++;
                }
                break;
            case '~':
                if (!comment)
                {
                    *q = ' ';
                    ++q;
                }
                break;
            case ' ':
            case '\t':
                if ((*(p + 1) == ' ') || (*(p + 1) == '\t'))
                    break;
                if (!comment)
                {
                    *q = ' ';
                    ++q;
                }
                break;
            case '\\':
                if (*(p + 1) == 'n')
                {
                    *q = '\0';
                    q = line1;
                    current->text[current->lines++] = strdup(line1);
                    ++p;
                    break;
                }
                if ((toupper(*(p + 1)) == 'C') || (toupper(*(p + 1)) == 'F'))
                {
                    ++p, ++p;
                    break;
                }
                if ((*(p + 1) == 'B') || (*(p + 1) == 'b') || (*(p + 1) == 'D') ||  
                    (*(p + 1) == 'I') || (*(p + 1) == 'i') || (*(p + 1) == 'N') || (*(p + 1) == 'T') || 
                    (*(p + 1) == 'U') || (*(p + 1) == 'u'))
                {
                    ++p;
                    break;
                }
                if ((*(p + 1) == '\\') || (*(p + 1) == '~') || (*(p + 1) == '{'))
                {
                    ++p;
                }
                else if (eol(*(p + 1)))
                {
                    if (!fgets(directive, LINE_LEN, fd))
                        return NULL;
                    trail_space(directive);
                    strncat(line2, directive, (LINE_LEN > 511) ? LINE_LEN : 511);
                    break;
                }
            default:
                if (!comment)
                {
                    *q = *p;
                    ++q;
                }
            }                   
        }                       
        *q = '\0';
        current->text[current->lines] = strdup(line1);
    }                           
    current->lines++;
    return current;
}

int
sub_autodetect(FILE * fd, int *uses_time)
{
    char            line[LINE_LEN + 1];
    int             i,
                    j = 0;
    char            p;

    while (j < 100)
    {
        j++;
        if (!fgets(line, LINE_LEN, fd))
            return SUB_INVALID;

        if (sscanf(line, "{%d}{%d}", &i, &i) == 2)
        {
            *uses_time = 0;
            return SUB_MICRODVD;
        }
        if (sscanf(line, "{%d}{}", &i) == 1)
        {
            *uses_time = 0;
            return SUB_MICRODVD;
        }
        if (sscanf(line, "[%d][%d]", &i, &i) == 2)
        {
            *uses_time = 1;
            return SUB_MPL2;
        }
        if (sscanf(line, "%d:%d:%d.%d,%d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8)
        {
            *uses_time = 1;
            return SUB_SUBRIP;
        }
        if (sscanf(line, "%d:%d:%d%[,.:]%d --> %d:%d:%d%[,.:]%d", &i, &i, &i, (char *) &i, &i, &i, &i, &i, (char *) &i, &i) == 10)
        {
            *uses_time = 1;
            return SUB_SUBVIEWER;
        }
        if (sscanf(line, "{T %d:%d:%d:%d", &i, &i, &i, &i) == 4)
        {
            *uses_time = 1;
            return SUB_SUBVIEWER2;
        }
        if (strstr(line, "<SAMI>"))
        {
            *uses_time = 1;
            return SUB_SAMI;
        }
        if (sscanf(line, "%d:%d:%d.%d %d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8)
        {
            *uses_time = 1;
            return SUB_JACOSUB;
        }
        if (sscanf(line, "@%d @%d", &i, &i) == 2)
        {
            *uses_time = 1;
            return SUB_JACOSUB;
        }
        if (sscanf(line, "%d:%d:%d:", &i, &i, &i) == 3)
        {
            *uses_time = 1;
            return SUB_VPLAYER;
        }
        if (sscanf(line, "%d:%d:%d ", &i, &i, &i) == 3)
        {
            *uses_time = 1;
            return SUB_VPLAYER;
        }
        
        
        
        
        if (*line == '<')
        {
            *uses_time = 1;
            return SUB_RT;
        }

        if (!memcmp(line, "Dialogue: Marked", 16))
        {
            *uses_time = 1;
            return SUB_SSA;
        }
        if (!memcmp(line, "Dialogue: ", 10))
        {
            *uses_time = 1;
            return SUB_SSA;
        }
        if (sscanf(line, "%d,%d,\"%c", &i, &i, (char *) &i) == 3)
        {
            *uses_time = 1;
            return SUB_PJS;
        }
        if (sscanf(line, "FORMAT=%d", &i) == 1)
        {
            *uses_time = 0;
            return SUB_MPSUB;
        }
        if (sscanf(line, "FORMAT=TIM%c", &p) == 1 && p == 'E')
        {
            *uses_time = 1;
            return SUB_MPSUB;
        }
        if (strstr(line, "-->>"))
        {
            *uses_time = 0;
            return SUB_AQTITLE;
        }
        if (sscanf(line, "[%d:%d:%d]", &i, &i, &i) == 3)
        {
            *uses_time = 1;
            return SUB_SUBRIP09;
        }
    }

    return SUB_INVALID;         
}


#if 0
#    ifdef DUMPSUBS
int             sub_utf8 = 0;
#    else
extern int      sub_utf8;
int             sub_utf8_prev = 0;
#    endif
#else                           
int             sub_utf8 = 0;
int             sub_utf8_prev = 0;
#endif

extern float    sub_delay;
extern float    sub_fps;

#ifdef USE_ICONV
static iconv_t  icdsc = (iconv_t) (-1);

void
subcp_open(FILE * enca_fd)
{
    char           *tocp = "UTF-8";

    if (sub_cp)
    {
        char           *cp_tmp = sub_cp;

#    ifdef HAVE_ENCA
        char            enca_lang[3],
                        enca_fallback[100];
        int             free_cp_tmp = 0;

        if (sscanf(sub_cp, "enca:%2s:%99s", enca_lang, enca_fallback) == 2 || sscanf(sub_cp, "ENCA:%2s:%99s", enca_lang, enca_fallback) == 2)
        {
            if (enca_fd)
            {
                cp_tmp = guess_cp(enca_fd, enca_lang, enca_fallback);
                free_cp_tmp = 1;
            }
            else
            {
                cp_tmp = enca_fallback;
            }
        }
#    endif
        if ((icdsc = iconv_open(tocp, cp_tmp)) != (iconv_t) (-1))
        {
            mp_msg(MSGT_SUBREADER, MSGL_V, "SUB: opened iconv descriptor.\n");
            sub_utf8 = 2;
        }
        else
            mp_msg(MSGT_SUBREADER, MSGL_ERR, "SUB: error opening iconv descriptor.\n");
#    ifdef HAVE_ENCA
        if (free_cp_tmp && cp_tmp)
            free(cp_tmp);
#    endif
    }
}

void
subcp_close(void)
{
    if (icdsc != (iconv_t) (-1))
    {
        (void) iconv_close(icdsc);
        icdsc = (iconv_t) (-1);
        mp_msg(MSGT_SUBREADER, MSGL_V, "SUB: closed iconv descriptor.\n");
    }
}

#    define ICBUFFSIZE 512
static char     icbuffer[ICBUFFSIZE];

subtitle       *
subcp_recode(subtitle * sub)
{
    int             l = sub->lines;
    size_t          ileft,
                    oleft;
    char           *op,
                   *ip,
                   *ot;

    while (l)
    {
        op = icbuffer;
        ip = sub->text[--l];
        ileft = strlen(ip);
        oleft = ICBUFFSIZE - 1;

        if (iconv(icdsc, &ip, &ileft, &op, &oleft) == (size_t) (-1))
        {
            mp_msg(MSGT_SUBREADER, MSGL_WARN, "SUB: error recoding line (1).\n");
            l++;
            break;
        }
        if (!(ot = (char *) malloc(op - icbuffer + 1)))
        {
            mp_msg(MSGT_SUBREADER, MSGL_WARN, "SUB: error allocating mem.\n");
            l++;
            break;
        }
        *op = '\0';
        strcpy(ot, icbuffer);
        free(sub->text[l]);
        sub->text[l] = ot;
    }
    if (l)
    {
        for (l = sub->lines; l;)
            free(sub->text[--l]);
        return ERR;
    }
    return sub;
}


subtitle       *
subcp_recode1(subtitle * sub)
{
    int             l = sub->lines;
    size_t          ileft,
                    oleft;

    if (icdsc == (iconv_t) (-1))
        return sub;

    while (l)
    {
        char           *ip = icbuffer;
        char           *op = sub->text[--l];

        strlcpy(ip, op, ICBUFFSIZE);
        ileft = strlen(ip);
        oleft = ICBUFFSIZE - 1;

        if (iconv(icdsc, &ip, &ileft, &op, &oleft) == (size_t) (-1))
        {
            mp_msg(MSGT_SUBREADER, MSGL_V, "SUB: error recoding line (2).\n");
            return sub;
        }
        *op = '\0';
    }
    return sub;
}
#endif

#ifdef USE_FRIBIDI
#    ifndef max
#        define max(a,b)  (((a)>(b))?(a):(b))
#    endif
subtitle       *
sub_fribidi(subtitle * sub, int sub_utf8)
{
    FriBidiChar     logical[LINE_LEN + 1],
                    visual[LINE_LEN + 1];   
    char           *ip = NULL,
        *op = NULL;
    FriBidiCharType base;
    size_t          len,
                    orig_len;
    int             l = sub->lines;
    int             char_set_num;
    fribidi_boolean log2vis;

    if (flip_hebrew)
    {                           
        fribidi_set_mirroring(FRIBIDI_TRUE);
        fribidi_set_reorder_nsm(FRIBIDI_FALSE);

        if (sub_utf8 == 0)
        {
            char_set_num = fribidi_parse_charset(fribidi_charset ? fribidi_charset : "ISO8859-8");
        }
        else
        {
            char_set_num = fribidi_parse_charset("UTF-8");
        }
        while (l)
        {
            ip = sub->text[--l];
            orig_len = len = strlen(ip);    
            if (len > LINE_LEN)
            {
                mp_msg(MSGT_SUBREADER, MSGL_WARN, "SUB: sub->text is longer than LINE_LEN.\n");
                l++;
                break;
            }
            len = fribidi_charset_to_unicode(char_set_num, ip, len, logical);
            base = fribidi_flip_commas ? FRIBIDI_TYPE_ON : FRIBIDI_TYPE_L;
            log2vis = fribidi_log2vis(logical, len, &base,
                                      
                                      visual, NULL, NULL, NULL);
            if (log2vis)
            {
                len = fribidi_remove_bidi_marks(visual, len, NULL, NULL, NULL);
                if ((op = (char *) malloc(sizeof(char) * (max(2 * orig_len, 2 * len) + 1))) == NULL)
                {
                    mp_msg(MSGT_SUBREADER, MSGL_WARN, "SUB: error allocating mem.\n");
                    l++;
                    break;
                }
                fribidi_unicode_to_charset(char_set_num, visual, len, op);
                free(ip);
                sub->text[l] = op;
            }
        }
        if (l)
        {
            for (l = sub->lines; l;)
                free(sub->text[--l]);
            return ERR;
        }
    }
    return sub;
}

#endif

static void
adjust_subs_time(subtitle * sub, float subtime, float fps, int block, int sub_num, int sub_uses_time)
{
    int             n,
                    m;
    subtitle       *nextsub;
    int             i = sub_num;
    unsigned long   subfms = (sub_uses_time ? 100 : fps) * subtime;
    unsigned long   overlap = (sub_uses_time ? 100 : fps) / 5;  

    n = m = 0;
    if (i)
        for (;;)
        {
            if (sub->end <= sub->start)
            {
                sub->end = sub->start + subfms;
                m++;
                n++;
            }
            if (!--i)
                break;
            nextsub = sub + 1;
            if (block)
            {
                if ((sub->end > nextsub->start) && (sub->end <= nextsub->start + overlap))
                {
                    
                    
                    
                    
                    unsigned        delta = sub->end - nextsub->start,
                        half = delta / 2;

                    sub->end -= half + 1;
                    nextsub->start += delta - half;
                }
                if (sub->end >= nextsub->start)
                {
                    sub->end = nextsub->start - 1;
                    if (sub->end - sub->start > subfms)
                        sub->end = sub->start + subfms;
                    if (!m)
                        n++;
                }
            }

            

            
            if (sub_uses_time && sub_fps)
            {
                sub->start *= sub_fps / fps;
                sub->end *= sub_fps / fps;
            }

            sub = nextsub;
            m = 0;
        }
    if (n)
        mp_msg(MSGT_SUBREADER, MSGL_INFO, "SUB: Adjusted %d subtitle(s).\n", n);
}

struct subreader
{
    subtitle       *(*read) (FILE * fd, subtitle * dest);
    void            (*post) (subtitle * dest);
    const char     *name;
};

#ifdef HAVE_ENCA
#    define MAX_GUESS_BUFFER_SIZE (256*1024)
void           *
guess_cp(FILE * fd, char *preferred_language, char *fallback)
{
    const char    **languages;
    size_t          langcnt,
                    buflen;
    EncaAnalyser    analyser;
    EncaEncoding    encoding;
    unsigned char  *buffer;
    char           *detected_sub_cp = NULL;
    int             i;

    buffer = (unsigned char *) malloc(MAX_GUESS_BUFFER_SIZE * sizeof(char));
    buflen = fread(buffer, 1, MAX_GUESS_BUFFER_SIZE, fd);

    languages = enca_get_languages(&langcnt);
    mp_msg(MSGT_SUBREADER, MSGL_V, "ENCA supported languages: ");
    for (i = 0; i < langcnt; i++)
    {
        mp_msg(MSGT_SUBREADER, MSGL_V, "%s ", languages[i]);
    }
    mp_msg(MSGT_SUBREADER, MSGL_V, "\n");

    for (i = 0; i < langcnt; i++)
    {
        if (strcasecmp(languages[i], preferred_language) != 0)
            continue;
        analyser = enca_analyser_alloc(languages[i]);
        encoding = enca_analyse_const(analyser, buffer, buflen);
        mp_msg(MSGT_SUBREADER, MSGL_INFO, "ENCA detected charset: %s\n", enca_charset_name(encoding.charset, ENCA_NAME_STYLE_ICONV));
        detected_sub_cp = strdup(enca_charset_name(encoding.charset, ENCA_NAME_STYLE_ICONV));
        enca_analyser_free(analyser);
    }

    free(languages);
    free(buffer);
    rewind(fd);

    if (!detected_sub_cp)
        detected_sub_cp = strdup(fallback);

    return detected_sub_cp;
}
#endif

sub_data       *
sub_read_file(char *filename, float fps)
{
    
    FILE           *fd;
    int             n_max,
                    n_first,
                    i,
                    j,
                    sub_first,
                    sub_orig;
    subtitle       *first,
                   *second,
                   *sub,
                   *return_sub;
    sub_data       *subt_data;
    int             uses_time = 0,
        sub_num = 0,
        sub_errs = 0;
    struct subreader sr[] = {
        {sub_read_line_microdvd, NULL, "microdvd"},
        {sub_read_line_subrip, NULL, "subrip"},
        {sub_read_line_subviewer, NULL, "subviewer"},
        {sub_read_line_sami, NULL, "sami"},
        {sub_read_line_vplayer, NULL, "vplayer"},
        {sub_read_line_rt, NULL, "rt"},
        {sub_read_line_ssa, sub_pp_ssa, "ssa"},
        {sub_read_line_pjs, NULL, "pjs"},
        {sub_read_line_mpsub, NULL, "mpsub"},
        {sub_read_line_aqt, NULL, "aqt"},
        {sub_read_line_subviewer2, NULL, "subviewer 2.0"},
        {sub_read_line_subrip09, NULL, "subrip 0.9"},
        {sub_read_line_jacosub, NULL, "jacosub"},
        {sub_read_line_mpl2, NULL, "mpl2"}
    };
    struct subreader *srp;

    if (filename == NULL)
        return NULL;            
    fd = fopen(filename, "r");
    if (!fd)
        return NULL;

    sub_format = sub_autodetect(fd, &uses_time);
    mpsub_multiplier = (uses_time ? 100.0 : 1.0);
    if (sub_format == SUB_INVALID)
    {
        mp_msg(MSGT_SUBREADER, MSGL_WARN, "SUB: Could not determine file format\n");
        return NULL;
    }
    srp = sr + sub_format;
    mp_msg(MSGT_SUBREADER, MSGL_INFO, "SUB: Detected subtitle file format: %s\n", srp->name);

    rewind(fd);

#ifdef USE_ICONV
    sub_utf8_prev = sub_utf8;
    {
        int             l,
                        k;

        k = -1;
        if ((l = strlen(filename)) > 4)
        {
            char           *exts[] = { ".utf", ".utf8", ".utf-8" };
            for (k = 3; --k >= 0;)
                if (!strcasecmp(filename + (l - strlen(exts[k])), exts[k]))
                {
                    sub_utf8 = 1;
                    break;
                }
        }
        if (k < 0)
            subcp_open(fd);
    }
#endif

    sub_num = 0;
    n_max = 32;
    first = (subtitle *) malloc(n_max * sizeof(subtitle));
    if (!first)
    {
#ifdef USE_ICONV
        subcp_close();
        sub_utf8 = sub_utf8_prev;
#endif
        return NULL;
    }

#ifdef USE_SORTSUB
    sub = (subtitle *) malloc(sizeof(subtitle));
    
    
    previous_sub_end = 0;
#endif
    while (1)
    {
        if (sub_num >= n_max)
        {
            n_max += 16;
            first = realloc(first, n_max * sizeof(subtitle));
        }
#ifndef USE_SORTSUB
        sub = &first[sub_num];
#endif
        memset(sub, '\0', sizeof(subtitle));
        sub = srp->read(fd, sub);
        if (!sub)
            break;              
#ifdef USE_ICONV
        if ((sub != ERR) && (sub_utf8 & 2))
            sub = subcp_recode(sub);
#endif
#ifdef USE_FRIBIDI
        if (sub != ERR)
            sub = sub_fribidi(sub, sub_utf8);
#endif
        if (sub == ERR)
        {
#ifdef USE_ICONV
            subcp_close();
#endif
            if (first)
                free(first);
            return NULL;
        }
        
        if ((sub != ERR) && !sub_no_text_pp && srp->post)
            srp->post(sub);
#ifdef USE_SORTSUB
        if (!sub_num || (first[sub_num - 1].start <= sub->start))
        {
            first[sub_num].start = sub->start;
            first[sub_num].end = sub->end;
            first[sub_num].lines = sub->lines;
            first[sub_num].alignment = sub->alignment;
            for (i = 0; i < sub->lines; ++i)
            {
                first[sub_num].text[i] = sub->text[i];
            }
            if (previous_sub_end)
            {
                first[sub_num - 1].end = previous_sub_end;
                previous_sub_end = 0;
            }
        }
        else
        {
            for (j = sub_num - 1; j >= 0; --j)
            {
                first[j + 1].start = first[j].start;
                first[j + 1].end = first[j].end;
                first[j + 1].lines = first[j].lines;
                first[j + 1].alignment = first[j].alignment;
                for (i = 0; i < first[j].lines; ++i)
                {
                    first[j + 1].text[i] = first[j].text[i];
                }
                if (!j || (first[j - 1].start <= sub->start))
                {
                    first[j].start = sub->start;
                    first[j].end = sub->end;
                    first[j].lines = sub->lines;
                    first[j].alignment = sub->alignment;
                    for (i = 0; i < SUB_MAX_TEXT; ++i)
                    {
                        first[j].text[i] = sub->text[i];
                    }
                    if (previous_sub_end)
                    {
                        first[j].end = first[j - 1].end;
                        first[j - 1].end = previous_sub_end;
                        previous_sub_end = 0;
                    }
                    break;
                }
            }
        }
#endif
        if (sub == ERR)
            ++sub_errs;
        else
            ++sub_num;          
    }

    fclose(fd);

#ifdef USE_ICONV
    subcp_close();
#endif


    mp_msg(MSGT_SUBREADER, MSGL_INFO, "SUB: Read %i subtitles", sub_num);
    if (sub_errs)
        mp_msg(MSGT_SUBREADER, MSGL_INFO, ", %i bad line(s).\n", sub_errs);
    else
        mp_msg(MSGT_SUBREADER, MSGL_INFO, ".\n");

    if (sub_num <= 0)
    {
        free(first);
        return NULL;
    }

    
    
    
    
    if ((suboverlap_enabled == 2) || ((suboverlap_enabled) && ((sub_format == SUB_JACOSUB) || (sub_format == SUB_SSA))))
    {
        adjust_subs_time(first, 6.0, fps, 0, sub_num, uses_time);   

        sub_orig = sub_num;
        n_first = sub_num;
        sub_num = 0;
        second = NULL;
        
        
        for (sub_first = 0; sub_first < n_first; ++sub_first)
        {
            unsigned long   global_start = first[sub_first].start,
                global_end = first[sub_first].end,
                local_start,
                local_end;
            int             lines_to_add = first[sub_first].lines,
                sub_to_add = 0,
                **placeholder = NULL,
                higher_line = 0,
                counter,
                start_block_sub = sub_num;
            char            real_block = 1;

            
            
            
            while ((sub_first + sub_to_add + 1 < n_first) && (first[sub_first + sub_to_add + 1].start < global_end))
            {
                ++sub_to_add;
                lines_to_add += first[sub_first + sub_to_add].lines;
                if (first[sub_first + sub_to_add].start < global_start)
                {
                    global_start = first[sub_first + sub_to_add].start;
                }
                if (first[sub_first + sub_to_add].end > global_end)
                {
                    global_end = first[sub_first + sub_to_add].end;
                }
            }

            
            
            counter = 2 * sub_to_add + 1;   
            
            placeholder = (int **) malloc(sizeof(int *) * counter);
            for (i = 0; i < counter; ++i)
            {
                placeholder[i] = (int *) malloc(sizeof(int) * lines_to_add);
                for (j = 0; j < lines_to_add; ++j)
                {
                    placeholder[i][j] = -1;
                }
            }

            counter = 0;
            local_end = global_start - 1;
            do
            {
                int             ls;

                
                
                local_start = local_end + 1;
                local_end = global_end;
                for (j = 0; j <= sub_to_add; ++j)
                {
                    if ((first[sub_first + j].start - 1 > local_start) && (first[sub_first + j].start - 1 < local_end))
                    {
                        local_end = first[sub_first + j].start - 1;
                    }
                    else if ((first[sub_first + j].end > local_start) && (first[sub_first + j].end < local_end))
                    {
                        local_end = first[sub_first + j].end;
                    }
                }
                
                
                
                
                for (j = 0; j <= sub_to_add; ++j)
                {
                    if ((first[sub_first + j].start <= local_end) && (first[sub_first + j].end > local_start))
                    {
                        unsigned long   sub_lines = first[sub_first + j].lines,
                            fragment_length = lines_to_add + 1,
                            tmp = 0;
                        char            boolean = 0;
                        int             fragment_position = -1;

                        
                        
                        
                        if (counter)
                            for (i = 0; i < lines_to_add; ++i)
                            {
                                if (placeholder[counter - 1][i] == sub_first + j)
                                {
                                    placeholder[counter][i] = sub_first + j;
                                    boolean = 1;
                                }
                            }
                        if (boolean)
                            continue;

                        
                        
                        
                        
                        
                        
                        for (i = 0; i < lines_to_add; ++i)
                        {
                            if (placeholder[counter][i] == -1)
                            {
                                
                                
                                ++tmp;
                            }
                            else
                            {
                                if (tmp == sub_lines)
                                {
                                    
                                    
                                    fragment_position = i - tmp;
                                    tmp = 0;
                                    break;
                                }
                                if ((tmp) && (tmp > sub_lines) && (tmp < fragment_length))
                                {
                                    
                                    
                                    
                                    fragment_length = tmp;
                                    fragment_position = i - tmp;
                                    tmp = 0;
                                }
                                else
                                {
                                    
                                    tmp = 0;
                                }
                            }
                        }
                        if (tmp)
                        {
                            
                            if ((tmp >= sub_lines) && (tmp < fragment_length))
                            {
                                fragment_position = i - tmp;
                            }
                        }
                        if (fragment_position == -1)
                        {
                            
                            
                            mp_msg(MSGT_SUBREADER, MSGL_WARN, "SUB: we could not find a suitable position for an overlapping subtitle\n");
                            higher_line = SUB_MAX_TEXT + 1;
                            break;
                        }
                        else
                        {
                            for (tmp = 0; tmp < sub_lines; ++tmp)
                            {
                                placeholder[counter][fragment_position + tmp] = sub_first + j;
                            }
                        }
                    }
                }
                for (j = higher_line + 1; j < lines_to_add; ++j)
                {
                    if (placeholder[counter][j] != -1)
                        higher_line = j;
                    else
                        break;
                }
                if (higher_line >= SUB_MAX_TEXT)
                {
                    
                    
                    second = (subtitle *) realloc(second, (sub_num + sub_to_add + 1) * sizeof(subtitle));
                    for (j = 0; j <= sub_to_add; ++j)
                    {
                        int             ls;

                        memset(&second[sub_num + j], '\0', sizeof(subtitle));
                        second[sub_num + j].start = first[sub_first + j].start;
                        second[sub_num + j].end = first[sub_first + j].end;
                        second[sub_num + j].lines = first[sub_first + j].lines;
                        second[sub_num + j].alignment = first[sub_first + j].alignment;
                        for (ls = 0; ls < second[sub_num + j].lines; ls++)
                        {
                            second[sub_num + j].text[ls] = strdup(first[sub_first + j].text[ls]);
                        }
                    }
                    sub_num += sub_to_add + 1;
                    sub_first += sub_to_add;
                    real_block = 0;
                    break;
                }

                
                
                second = (subtitle *) realloc(second, (sub_num + 1) * sizeof(subtitle));
                memset(&second[sub_num], '\0', sizeof(subtitle));
                second[sub_num].start = local_start;
                second[sub_num].end = local_end;
                second[sub_num].alignment = first[sub_first].alignment;
                n_max = (lines_to_add < SUB_MAX_TEXT) ? lines_to_add : SUB_MAX_TEXT;
                for (i = 0, j = 0; j < n_max; ++j)
                {
                    if (placeholder[counter][j] != -1)
                    {
                        int             lines = first[placeholder[counter][j]].lines;

                        for (ls = 0; ls < lines; ++ls)
                        {
                            second[sub_num].text[i++] = strdup(first[placeholder[counter][j]].text[ls]);
                        }
                        j += lines - 1;
                    }
                    else
                    {
                        second[sub_num].text[i++] = strdup(" ");
                    }
                }
                ++sub_num;
                ++counter;
            }
            while (local_end < global_end);
            if (real_block)
                for (i = 0; i < counter; ++i)
                    second[start_block_sub + i].lines = higher_line + 1;

            counter = 2 * sub_to_add + 1;
            for (i = 0; i < counter; ++i)
            {
                free(placeholder[i]);
            }
            free(placeholder);
            sub_first += sub_to_add;
        }

        for (j = sub_orig - 1; j >= 0; --j)
        {
            for (i = first[j].lines - 1; i >= 0; --i)
            {
                free(first[j].text[i]);
            }
        }
        free(first);

        return_sub = second;
    }
    else
    {                           
        adjust_subs_time(first, 6.0, fps, 1, sub_num, uses_time);   
        return_sub = first;
    }
    if (return_sub == NULL)
        return NULL;
    subt_data = (sub_data *) malloc(sizeof(sub_data));
    subt_data->filename = filename;
    subt_data->sub_uses_time = uses_time;
    subt_data->sub_num = sub_num;
    subt_data->sub_errs = sub_errs;
    subt_data->subtitles = return_sub;
    return subt_data;
}

#if 0
char           *
strreplace(char *in, char *what, char *whereof)
{
    int             i;
    char           *tmp;

    if ((in == NULL) || (what == NULL) || (whereof == NULL) || ((tmp = strstr(in, what)) == NULL))
        return NULL;
    for (i = 0; i < strlen(whereof); i++)
        tmp[i] = whereof[i];
    if (strlen(what) > strlen(whereof))
        tmp[i] = 0;
    return in;
}
#endif


static void
strcpy_trim(char *d, char *s)
{
    
    while (*s && !isalnum(*s))
    {
        s++;
    }
    for (;;)
    {
        
        while (*s && isalnum(*s))
        {
            *d = tolower(*s);
            s++;
            d++;
        }
        if (*s == 0)
            break;
        
        while (*s && !isalnum(*s))
        {
            s++;
        }
        if (*s == 0)
            break;
        *d++ = ' ';
    }
    *d = 0;
}

static void
strcpy_strip_ext(char *d, char *s)
{
    char           *tmp = strrchr(s, '.');

    if (!tmp)
    {
        strcpy(d, s);
        return;
    }
    else
    {
        strncpy(d, s, tmp - s);
        d[tmp - s] = 0;
    }
    while (*d)
    {
        *d = tolower(*d);
        d++;
    }
}

static void
strcpy_get_ext(char *d, char *s)
{
    char           *tmp = strrchr(s, '.');

    if (!tmp)
    {
        strcpy(d, "");
        return;
    }
    else
    {
        strcpy(d, tmp + 1);
    }
}

static int
whiteonly(char *s)
{
    while (*s)
    {
        if (isalnum(*s))
            return 0;
        s++;
    }
    return 1;
}

typedef struct _subfn
{
    int             priority;
    char           *fname;
} subfn;

static int
compare_sub_priority(const void *a, const void *b)
{
    if (((subfn *) a)->priority > ((subfn *) b)->priority)
    {
        return -1;
    }
    else if (((subfn *) a)->priority < ((subfn *) b)->priority)
    {
        return 1;
    }
    else
    {
        return strcoll(((subfn *) a)->fname, ((subfn *) b)->fname);
    }
}

char          **
sub_filenames(char *path, char *fname)
{
    char           *f_dir,
                   *f_fname,
                   *f_fname_noext,
                   *f_fname_trim,
                   *tmp,
                   *tmp_sub_id;
    char           *tmp_fname_noext,
                   *tmp_fname_trim,
                   *tmp_fname_ext,
                   *tmpresult;

    int             len,
                    pos,
                    found,
                    i,
                    j;
    char           *sub_exts[] = { "utf", "utf8", "utf-8", "sub", "srt", "smi", "rt", "txt", "ssa", "aqt", "jss", "js", "ass", NULL };
    subfn          *result;
    char          **result2;

    int             subcnt;

    FILE           *f;

    DIR            *d;
    struct dirent  *de;

    len = (strlen(fname) > 256 ? strlen(fname) : 256) + (strlen(path) > 256 ? strlen(path) : 256) + 2;

    f_dir = (char *) malloc(len);
    f_fname = (char *) malloc(len);
    f_fname_noext = (char *) malloc(len);
    f_fname_trim = (char *) malloc(len);

    tmp_fname_noext = (char *) malloc(len);
    tmp_fname_trim = (char *) malloc(len);
    tmp_fname_ext = (char *) malloc(len);

    tmpresult = (char *) malloc(len);

    result = (subfn *) malloc(sizeof(subfn) * MAX_SUBTITLE_FILES);
    memset(result, 0, sizeof(subfn) * MAX_SUBTITLE_FILES);

    subcnt = 0;

    tmp = strrchr(fname, '/');
#ifdef WIN32
    if (!tmp)
        tmp = strrchr(fname, '\\');
#endif

    
    if (tmp)
    {
        strcpy(f_fname, tmp + 1);
        pos = tmp - fname;
        strncpy(f_dir, fname, pos + 1);
        f_dir[pos + 1] = 0;
    }
    else
    {
        strcpy(f_fname, fname);
        strcpy(f_dir, "./");
    }

    strcpy_strip_ext(f_fname_noext, f_fname);
    strcpy_trim(f_fname_trim, f_fname_noext);

    tmp_sub_id = NULL;
    if (dvdsub_lang && !whiteonly(dvdsub_lang))
    {
        tmp_sub_id = (char *) malloc(strlen(dvdsub_lang) + 1);
        strcpy_trim(tmp_sub_id, dvdsub_lang);
    }

    
    
    
    
    for (j = 0; j <= 1; j++)
    {
        d = opendir(j == 0 ? f_dir : path);
        if (d)
        {
            while ((de = readdir(d)))
            {
                
                strcpy_strip_ext(tmp_fname_noext, de->d_name);
                strcpy_get_ext(tmp_fname_ext, de->d_name);
                strcpy_trim(tmp_fname_trim, tmp_fname_noext);

                
                found = 0;
#ifdef USE_ICONV
#    ifdef HAVE_ENCA
                for (i = ((sub_cp && strncasecmp(sub_cp, "enca", 4) != 0) ? 3 : 0); sub_exts[i]; i++)
                {
#    else
                for (i = (sub_cp ? 3 : 0); sub_exts[i]; i++)
                {
#    endif
#else
                for (i = 0; sub_exts[i]; i++)
                {
#endif
                    if (strcasecmp(sub_exts[i], tmp_fname_ext) == 0)
                    {
                        found = 1;
                        break;
                    }
                }

                
                if (found)
                {
                    int             prio = 0;

                    if (!prio && tmp_sub_id)
                    {
                        sprintf(tmpresult, "%s %s", f_fname_trim, tmp_sub_id);
                        printf("dvdsublang...%s\n", tmpresult);
                        if (strcmp(tmp_fname_trim, tmpresult) == 0 && sub_match_fuzziness >= 1)
                        {
                            
                            prio = 5;
                        }
                    }
                    if (!prio && strcmp(tmp_fname_trim, f_fname_trim) == 0)
                    {
                        
                        prio = 4;
                    }
                    if (!prio && (tmp = strstr(tmp_fname_trim, f_fname_trim)) && (sub_match_fuzziness >= 1))
                    {
                        
                        tmp += strlen(f_fname_trim);
                        if (tmp_sub_id && strstr(tmp, tmp_sub_id))
                        {
                            
                            prio = 3;
                        }
                        else if ((tmp_sub_id == NULL) && whiteonly(tmp))
                        {
                            
                            prio = 3;
                        }
                        else
                        {
                            
                            prio = 2;
                        }
                    }
                    if (!prio)
                    {
                        
                        
                        if ((j == 0) && (sub_match_fuzziness >= 2))
                        {
                            prio = 1;
                        }
                    }

                    if (prio)
                    {
                        prio += prio;
#ifdef USE_ICONV
                        if (i < 3)
                        {       
                            prio++;
                        }
#endif
                        sprintf(tmpresult, "%s%s", j == 0 ? f_dir : path, de->d_name);

                        if ((f = fopen(tmpresult, "rt")))
                        {
                            fclose(f);
                            result[subcnt].priority = prio;
                            result[subcnt].fname = strdup(tmpresult);
                            subcnt++;
                        }
                    }

                }
                if (subcnt >= MAX_SUBTITLE_FILES)
                    break;
            }
            closedir(d);
        }

    }

    if (tmp_sub_id)
        free(tmp_sub_id);

    free(f_dir);
    free(f_fname);
    free(f_fname_noext);
    free(f_fname_trim);

    free(tmp_fname_noext);
    free(tmp_fname_trim);
    free(tmp_fname_ext);

    free(tmpresult);

    qsort(result, subcnt, sizeof(subfn), compare_sub_priority);

    result2 = (char **) malloc(sizeof(char *) * (subcnt + 1));
    memset(result2, 0, sizeof(char *) * (subcnt + 1));

    for (i = 0; i < subcnt; i++)
    {
        result2[i] = result[i].fname;
    }
    result2[subcnt] = NULL;

    free(result);

    return result2;
}

void
list_sub_file(sub_data * subd)
{
    int             i,
                    j;
    subtitle       *subs = subd->subtitles;

    for (j = 0; j < subd->sub_num; j++)
    {
        subtitle       *egysub = &subs[j];

        printf("%i line%c (%li-%li)\n", egysub->lines, (1 == egysub->lines) ? ' ' : 's', egysub->start, egysub->end);
        for (i = 0; i < egysub->lines; i++)
        {
            printf("\t\t%d: %s%s", i, egysub->text[i], i == egysub->lines - 1 ? "" : " \n ");
        }
        printf("\n");
    }

    printf("Subtitle format %s time.\n", subd->sub_uses_time ? "uses" : "doesn't use");
    printf("Read %i subtitles, %i errors.\n", subd->sub_num, subd->sub_errs);
}

void
dump_srt(sub_data * subd, float fps)
{
    int             i,
                    j;
    int             h,
                    m,
                    s,
                    ms;
    FILE           *fd;
    subtitle       *onesub;
    unsigned long   temp;
    subtitle       *subs = subd->subtitles;

    if (!subd->sub_uses_time && sub_fps == 0)
        sub_fps = fps;
    fd = fopen("dumpsub.srt", "w");
    if (!fd)
    {
        perror("dump_srt: fopen");
        return;
    }
    for (i = 0; i < subd->sub_num; i++)
    {
        onesub = subs + i;      
        fprintf(fd, "%d\n", i + 1); 

        temp = onesub->start;
        if (!subd->sub_uses_time)
            temp = temp * 100 / sub_fps;
        temp -= sub_delay * 100;
        h = temp / 360000;
        temp %= 360000;         
        m = temp / 6000;
        temp %= 6000;           
        s = temp / 100;
        temp %= 100;            
        ms = temp * 10;         
        fprintf(fd, "%02d:%02d:%02d,%03d --> ", h, m, s, ms);

        temp = onesub->end;
        if (!subd->sub_uses_time)
            temp = temp * 100 / sub_fps;
        temp -= sub_delay * 100;
        h = temp / 360000;
        temp %= 360000;
        m = temp / 6000;
        temp %= 6000;
        s = temp / 100;
        temp %= 100;
        ms = temp * 10;
        fprintf(fd, "%02d:%02d:%02d,%03d\n", h, m, s, ms);

        for (j = 0; j < onesub->lines; j++)
            fprintf(fd, "%s\n", onesub->text[j]);

        fprintf(fd, "\n");
    }
    fclose(fd);
    mp_msg(MSGT_SUBREADER, MSGL_INFO, "SUB: Subtitles dumped in \'dumpsub.srt\'.\n");
}

void
dump_mpsub(sub_data * subd, float fps)
{
    int             i,
                    j;
    FILE           *fd;
    float           a,
                    b;
    subtitle       *subs = subd->subtitles;

    mpsub_position = subd->sub_uses_time ? (sub_delay * 100) : (sub_delay * fps);
    if (sub_fps == 0)
        sub_fps = fps;

    fd = fopen("dump.mpsub", "w");
    if (!fd)
    {
        perror("dump_mpsub: fopen");
        return;
    }


    if (subd->sub_uses_time)
        fprintf(fd, "FORMAT=TIME\n\n");
    else
        fprintf(fd, "FORMAT=%5.2f\n\n", fps);

    for (j = 0; j < subd->sub_num; j++)
    {
        subtitle       *egysub = &subs[j];

        if (subd->sub_uses_time)
        {
            a = ((egysub->start - mpsub_position) / 100.0);
            b = ((egysub->end - egysub->start) / 100.0);
            if ((float) ((int) a) == a)
                fprintf(fd, "%.0f", a);
            else
                fprintf(fd, "%.2f", a);

            if ((float) ((int) b) == b)
                fprintf(fd, " %.0f\n", b);
            else
                fprintf(fd, " %.2f\n", b);
        }
        else
        {
            fprintf(fd, "%ld %ld\n", (long) ((egysub->start * (fps / sub_fps)) - ((mpsub_position * (fps / sub_fps)))), (long) (((egysub->end) - (egysub->start)) * (fps / sub_fps)));
        }

        mpsub_position = egysub->end;
        for (i = 0; i < egysub->lines; i++)
        {
            fprintf(fd, "%s\n", egysub->text[i]);
        }
        fprintf(fd, "\n");
    }
    fclose(fd);
    mp_msg(MSGT_SUBREADER, MSGL_INFO, "SUB: Subtitles dumped in \'dump.mpsub\'.\n");
}

void
dump_microdvd(sub_data * subd, float fps)
{
    int             i,
                    delay;
    FILE           *fd;
    subtitle       *subs = subd->subtitles;

    if (sub_fps == 0)
        sub_fps = fps;
    fd = fopen("dumpsub.txt", "w");
    if (!fd)
    {
        perror("dumpsub.txt: fopen");
        return;
    }
    delay = sub_delay * sub_fps;
    for (i = 0; i < subd->sub_num; ++i)
    {
        int             j,
                        start,
                        end;

        start = subs[i].start;
        end = subs[i].end;
        if (subd->sub_uses_time)
        {
            start = start * sub_fps / 100;
            end = end * sub_fps / 100;
        }
        else
        {
            start = start * sub_fps / fps;
            end = end * sub_fps / fps;
        }
        start -= delay;
        end -= delay;
        fprintf(fd, "{%d}{%d}", start, end);
        for (j = 0; j < subs[i].lines; ++j)
            fprintf(fd, "%s%s", j ? "|" : "", subs[i].text[j]);
        fprintf(fd, "\n");
    }
    fclose(fd);
    mp_msg(MSGT_SUBREADER, MSGL_INFO, "SUB: Subtitles dumped in \'dumpsub.txt\'.\n");
}

void
dump_jacosub(sub_data * subd, float fps)
{
    int             i,
                    j;
    int             h,
                    m,
                    s,
                    cs;
    FILE           *fd;
    subtitle       *onesub;
    unsigned long   temp;
    subtitle       *subs = subd->subtitles;

    if (!subd->sub_uses_time && sub_fps == 0)
        sub_fps = fps;
    fd = fopen("dumpsub.jss", "w");
    if (!fd)
    {
        perror("dump_jacosub: fopen");
        return;
    }
    fprintf(fd, "#TIMERES %d\n", (subd->sub_uses_time) ? 100 : (int) sub_fps);
    for (i = 0; i < subd->sub_num; i++)
    {
        onesub = subs + i;      

        temp = onesub->start;
        if (!subd->sub_uses_time)
            temp = temp * 100 / sub_fps;
        temp -= sub_delay * 100;
        h = temp / 360000;
        temp %= 360000;         
        m = temp / 6000;
        temp %= 6000;           
        s = temp / 100;
        temp %= 100;            
        cs = temp;              
        fprintf(fd, "%02d:%02d:%02d.%02d ", h, m, s, cs);

        temp = onesub->end;
        if (!subd->sub_uses_time)
            temp = temp * 100 / sub_fps;
        temp -= sub_delay * 100;
        h = temp / 360000;
        temp %= 360000;
        m = temp / 6000;
        temp %= 6000;
        s = temp / 100;
        temp %= 100;
        cs = temp;
        fprintf(fd, "%02d:%02d:%02d.%02d {~} ", h, m, s, cs);

        for (j = 0; j < onesub->lines; j++)
            fprintf(fd, "%s%s", j ? "\\n" : "", onesub->text[j]);

        fprintf(fd, "\n");
    }
    fclose(fd);
    mp_msg(MSGT_SUBREADER, MSGL_INFO, "SUB: Subtitles dumped in \'dumpsub.js\'.\n");
}

void
dump_sami(sub_data * subd, float fps)
{
    int             i,
                    j;
    FILE           *fd;
    subtitle       *onesub;
    unsigned long   temp;
    subtitle       *subs = subd->subtitles;

    if (!subd->sub_uses_time && sub_fps == 0)
        sub_fps = fps;
    fd = fopen("dumpsub.smi", "w");
    if (!fd)
    {
        perror("dump_jacosub: fopen");
        return;
    }
    fprintf(fd, "<SAMI>\n"
            "<HEAD>\n"
            "	<STYLE TYPE=\"Text/css\">\n"
            "	<!--\n"
            "	  P {margin-left: 29pt; margin-right: 29pt; font-size: 24pt; text-align: center; font-family: Tahoma; font-weight: bold; color: #FCDD03; background-color: #000000;}\n"
            "	  .SUBTTL {Name: 'Subtitles'; Lang: en-US; SAMIType: CC;}\n" "	-->\n" "	</STYLE>\n" "</HEAD>\n" "<BODY>\n");
    for (i = 0; i < subd->sub_num; i++)
    {
        onesub = subs + i;      

        temp = onesub->start;
        if (!subd->sub_uses_time)
            temp = temp * 100 / sub_fps;
        temp -= sub_delay * 100;
        fprintf(fd, "\t<SYNC Start=%lu>\n" "\t  <P>", temp * 10);

        for (j = 0; j < onesub->lines; j++)
            fprintf(fd, "%s%s", j ? "<br>" : "", onesub->text[j]);

        fprintf(fd, "\n");

        temp = onesub->end;
        if (!subd->sub_uses_time)
            temp = temp * 100 / sub_fps;
        temp -= sub_delay * 100;
        fprintf(fd, "\t<SYNC Start=%lu>\n" "\t  <P>&nbsp;\n", temp * 10);
    }
    fprintf(fd, "</BODY>\n" "</SAMI>\n");
    fclose(fd);
    mp_msg(MSGT_SUBREADER, MSGL_INFO, "SUB: Subtitles dumped in \'dumpsub.smi\'.\n");
}

void
sub_free(sub_data * subd)
{
    int             i;

    if (!subd)
        return;

    if (subd->subtitles)
    {
        for (i = 0; i < subd->subtitles->lines; i++)
            free(subd->subtitles->text[i]);
        free(subd->subtitles);
    }
    if (subd->filename)
        free(subd->filename);
    free(subd);
}

#ifdef DUMPSUBS
int
main(int argc, char **argv)
{                               
    sub_data       *subd;

    if (argc < 2)
    {
        printf("\nUsage: subreader filename.sub\n\n");
        exit(1);
    }
    sub_cp = argv[2];
    subd = sub_read_file(argv[1]);
    if (!subd)
    {
        printf("Couldn't load file.\n");
        exit(1);
    }

    list_sub_file(subd);

    return 0;
}
#endif




See more files for this project here

The Open2x Project

The Open2x project exists to provide an open source resource for the GP2X handheld console based on the MagicEyes MMSP2 processing platform and MP2520F SoC. The project hosts Linux kernel source for the GP2X, boot loader (U-Boot) source and more.

Project homepage: http://www.distant-earth.com/open2x
Programming language(s): Assembly,C,C++
License: other

  default_skin/
    asf.png
    avi.png
    body.png
    dat.png
    downarrow.png
    error.png
    ext.png
    ext_on.png
    folder.png
    full.png
    loading.png
    mpg.png
    nand.png
    nand_on.png
    normal.png
    resume.png
    save.png
    sd.png
    sd_on.png
    selectbar.png
    uparrow.png
    wmv.png
  etc/
    codecs.conf
    dvb-menu.conf
    example.conf
    input.conf
    inttypes.h
    menu.conf
    mplayer.desktop
    mplayer.ico
  fbdisp/
    Makefile
    fblin16.c
    fblin24.c
    fblin32.c
    fbs.h
    fontdisp.h
    fontout.c
    gfxdev.h
    gfxfontext.c
    gfxfontload.c
    gfxfontout.c
    gfxtype.h
    gulim_96_10_eng.c
    gulim_96_10_han.c
    main.c
    scr_fb.c
  help/
    help_diff.sh
    help_mp-bg.h
    help_mp-cs.h
    help_mp-de.h
    help_mp-dk.h
    help_mp-el.h
    help_mp-en.h
    help_mp-es.h
    help_mp-fr.h
    help_mp-hu.h
    help_mp-it.h
    help_mp-ja.h
    help_mp-ko.h
    help_mp-mk.h
    help_mp-nl.h
    help_mp-no.h
    help_mp-pl.h
    help_mp-pt_BR.h
    help_mp-ro.h
    help_mp-ru.h
  libaf/
  libao2/
  libmpcodecs/
  libmpdemux/
  loader/
  osdep/
  AUTHORS
  DirDisplay.c
  DirDisplay.h
  DirList.c
  DirList.h
  FontDisplay.c
  FontDisplay.h
  LICENSE
  Makefile
  bswap.h
  codec-cfg.c
  codec-cfg.h
  config.h
  config.mak
  csource.lst
  cx25874.h
  drawcontrol.c
  drawcontrol.h
  dualcpu.h
  filelistview.c
  filelistview.h
  find_sub.c
  g2player.h
  get_path.c
  glock.c
  glock.h
  guictrl.c
  guictrl.h
  gv.c
  gvlib_export.h
  help_mp.h
  i2c.h
  imgNumber.h
  imgbinary.h
  m_config.c
  m_config.h
  m_option.c
  m_option.h
  m_struct.c
  m_struct.h
  mangle.h
  mixer.c
  mixer.h
  mmsp2_940_if.c
  mmsp2_if.h
  mp_msg.c
  mp_msg.h
  mplayer.c
  mplayer.h
  open2x-mplayer.sh
  rtc_1024_table.h
  subdisp.c
  subdisp.h
  subreader.c
  subreader.h
  typed.h
  version.h
  vpp.h
  vpts_q.c
  wincetype.h