| 1 | /* |
| 2 | * Copyright (C) 2000-2003 the xine project |
| 3 | * |
| 4 | * This file is part of xine, a free video player. |
| 5 | * |
| 6 | * xine is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. |
| 10 | * |
| 11 | * xine is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License |
| 17 | * along with this program; if not, write to the Free Software |
| 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
| 19 | * |
| 20 | * $Id: xine_demux_sputext.c 20349 2009-04-11 00:04:30Z xris $ |
| 21 | * |
| 22 | * code based on old libsputext/xine_decoder.c |
| 23 | * |
| 24 | * code based on mplayer module: |
| 25 | * |
| 26 | * Subtitle reader with format autodetection |
| 27 | * |
| 28 | * Written by laaz |
| 29 | * Some code cleanup & realloc() by A'rpi/ESP-team |
| 30 | * dunnowhat sub format by szabi |
| 31 | */ |
| 32 | |
| 33 | #ifdef HAVE_CONFIG_H |
| 34 | #include "config.h" |
| 35 | #endif |
| 36 | |
| 37 | #include <stdlib.h> |
| 38 | #include <stdio.h> |
| 39 | #include <unistd.h> |
| 40 | #include <string.h> |
| 41 | #include <sys/types.h> |
| 42 | #include <sys/stat.h> |
| 43 | #include <fcntl.h> |
| 44 | #include <ctype.h> |
| 45 | #include "xine_demux_sputext.h" |
| 46 | |
| 47 | #define LOG_MODULE "demux_sputext" |
| 48 | #define LOG_VERBOSE |
| 49 | /* |
| 50 | #define LOG |
| 51 | */ |
| 52 | |
| 53 | #define ERR (void *)-1 |
| 54 | #define LINE_LEN 1000 |
| 55 | #define LINE_LEN_QUOT "1000" |
| 56 | |
| 57 | /* |
| 58 | * Demuxer code start |
| 59 | */ |
| 60 | |
| 61 | #define FORMAT_UNKNOWN -1 |
| 62 | #define FORMAT_MICRODVD 0 |
| 63 | #define FORMAT_SUBRIP 1 |
| 64 | #define FORMAT_SUBVIEWER 2 |
| 65 | #define FORMAT_SAMI 3 |
| 66 | #define FORMAT_VPLAYER 4 |
| 67 | #define FORMAT_RT 5 |
| 68 | #define FORMAT_SSA 6 /* Sub Station Alpha */ |
| 69 | #define FORMAT_PJS 7 |
| 70 | #define FORMAT_MPSUB 8 |
| 71 | #define FORMAT_AQTITLE 9 |
| 72 | #define FORMAT_JACOBSUB 10 |
| 73 | #define FORMAT_SUBVIEWER2 11 |
| 74 | #define FORMAT_SUBRIP09 12 |
| 75 | #define FORMAT_MPL2 13 /*Mplayer sub 2 ?*/ |
| 76 | |
| 77 | static int eol(char p) { |
| 78 | return (p=='\r' || p=='\n' || p=='\0'); |
| 79 | } |
| 80 | |
| 81 | static inline void trail_space(char *s) { |
| 82 | int i; |
| 83 | while (isspace(*s)) { |
| 84 | char *copy = s; |
| 85 | do { |
| 86 | copy[0] = copy[1]; |
| 87 | copy++; |
| 88 | } while(*copy); |
| 89 | } |
| 90 | i = strlen(s) - 1; |
| 91 | while (i > 0 && isspace(s[i])) |
| 92 | s[i--] = '\0'; |
| 93 | } |
| 94 | |
| 95 | /* |
| 96 | * Reimplementation of fgets() using the input->read() method. |
| 97 | */ |
| 98 | static char *read_line_from_input(demux_sputext_t *demuxstr, char *line, off_t len) { |
| 99 | off_t nread = 0; |
| 100 | char *s; |
| 101 | int linelen; |
| 102 | |
| 103 | // Since our RemoteFile code sleeps 200ms whenever we get back less data |
| 104 | // than requested, but this code just keeps trying to read until it gets |
| 105 | // an error back, we check for empty reads so that we can stop reading |
| 106 | // when there is no more data to read |
| 107 | if (demuxstr->emptyReads == 0 && (len - demuxstr->buflen) > 512) { |
| 108 | if((nread = demuxstr->rbuffer->Read( |
| 109 | &demuxstr->buf[demuxstr->buflen], |
| 110 | len - demuxstr->buflen)) < 0) { |
| 111 | printf("read failed.\n"); |
| 112 | return NULL; |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | if (!nread) |
| 117 | demuxstr->emptyReads++; |
| 118 | |
| 119 | demuxstr->buflen += nread; |
| 120 | demuxstr->buf[demuxstr->buflen] = '\0'; |
| 121 | |
| 122 | s = strchr(demuxstr->buf, '\n'); |
| 123 | |
| 124 | if (line && (s || demuxstr->buflen)) { |
| 125 | |
| 126 | linelen = s ? (s - demuxstr->buf) + 1 : demuxstr->buflen; |
| 127 | |
| 128 | memcpy(line, demuxstr->buf, linelen); |
| 129 | line[linelen] = '\0'; |
| 130 | |
| 131 | memmove(demuxstr->buf, &demuxstr->buf[linelen], SUB_BUFSIZE - linelen); |
| 132 | demuxstr->buflen -= linelen; |
| 133 | |
| 134 | return line; |
| 135 | } |
| 136 | |
| 137 | return NULL; |
| 138 | } |
| 139 | |
| 140 | |
| 141 | static subtitle_t *sub_read_line_sami(demux_sputext_t *demuxstr, subtitle_t *current) { |
| 142 | |
| 143 | static char line[LINE_LEN + 1]; |
| 144 | static char *s = NULL; |
| 145 | char text[LINE_LEN + 1], *p, *q; |
| 146 | int state; |
| 147 | |
| 148 | p = NULL; |
| 149 | current->lines = current->start = 0; |
| 150 | current->end = -1; |
| 151 | state = 0; |
| 152 | |
| 153 | /* read the first line */ |
| 154 | if (!s) |
| 155 | if (!(s = read_line_from_input(demuxstr, line, LINE_LEN))) return 0; |
| 156 | |
| 157 | do { |
| 158 | switch (state) { |
| 159 | |
| 160 | case 0: /* find "START=" */ |
| 161 | s = strstr (s, "Start="); |
| 162 | if (s) { |
| 163 | current->start = strtol (s + 6, &s, 0) / 10; |
| 164 | state = 1; continue; |
| 165 | } |
| 166 | break; |
| 167 | |
| 168 | case 1: /* find "<P" */ |
| 169 | if ((s = strstr (s, "<P"))) { s += 2; state = 2; continue; } |
| 170 | break; |
| 171 | |
| 172 | case 2: /* find ">" */ |
| 173 | if ((s = strchr (s, '>'))) { s++; state = 3; p = text; continue; } |
| 174 | break; |
| 175 | |
| 176 | case 3: /* get all text until '<' appears */ |
| 177 | if (*s == '\0') { break; } |
| 178 | else if (*s == '<') { state = 4; } |
| 179 | else if (!strncasecmp (s, " ", 6)) { *p++ = ' '; s += 6; } |
| 180 | else if (*s == '\r') { s++; } |
| 181 | else if (!strncasecmp (s, "<br>", 4) || *s == '\n') { |
| 182 | *p = '\0'; p = text; trail_space (text); |
| 183 | if (text[0] != '\0') |
| 184 | current->text[current->lines++] = strdup (text); |
| 185 | if (*s == '\n') s++; else s += 4; |
| 186 | } |
| 187 | else *p++ = *s++; |
| 188 | continue; |
| 189 | |
| 190 | case 4: /* get current->end or skip <TAG> */ |
| 191 | q = strstr (s, "Start="); |
| 192 | if (q) { |
| 193 | current->end = strtol (q + 6, &q, 0) / 10 - 1; |
| 194 | *p = '\0'; trail_space (text); |
| 195 | if (text[0] != '\0') |
| 196 | current->text[current->lines++] = strdup (text); |
| 197 | if (current->lines > 0) { state = 99; break; } |
| 198 | state = 0; continue; |
| 199 | } |
| 200 | s = strchr (s, '>'); |
| 201 | if (s) { s++; state = 3; continue; } |
| 202 | break; |
| 203 | } |
| 204 | |
| 205 | /* read next line */ |
| 206 | if (state != 99 && !(s = read_line_from_input (demuxstr, line, LINE_LEN))) |
| 207 | return 0; |
| 208 | |
| 209 | } while (state != 99); |
| 210 | |
| 211 | return current; |
| 212 | } |
| 213 | |
| 214 | |
| 215 | static char *sub_readtext(char *source, char **dest) { |
| 216 | int len=0; |
| 217 | char *p=source; |
| 218 | |
| 219 | while ( !eol(*p) && *p!= '|' ) { |
| 220 | p++,len++; |
| 221 | } |
| 222 | |
| 223 | if (!dest) |
| 224 | return (char*)ERR; |
| 225 | |
| 226 | *dest= (char *)malloc (len+1); |
| 227 | if (!(*dest)) |
| 228 | return (char*)ERR; |
| 229 | |
| 230 | strncpy(*dest, source, len); |
| 231 | (*dest)[len]=0; |
| 232 | |
| 233 | while (*p=='\r' || *p=='\n' || *p=='|') |
| 234 | p++; |
| 235 | |
| 236 | if (*p) return p; /* not-last text field */ |
| 237 | else return (char*)NULL; /* last text field */ |
| 238 | } |
| 239 | |
| 240 | static subtitle_t *sub_read_line_microdvd(demux_sputext_t *demuxstr, subtitle_t *current) { |
| 241 | |
| 242 | char line[LINE_LEN + 1]; |
| 243 | char line2[LINE_LEN + 1]; |
| 244 | char *p, *next; |
| 245 | int i; |
| 246 | |
| 247 | memset (current, 0, sizeof(subtitle_t)); |
| 248 | |
| 249 | current->end=-1; |
| 250 | do { |
| 251 | if (!read_line_from_input (demuxstr, line, LINE_LEN)) return NULL; |
| 252 | } while ((sscanf (line, "{%ld}{}%" LINE_LEN_QUOT "[^\r\n]", &(current->start), line2) !=2) && |
| 253 | (sscanf (line, "{%ld}{%ld}%" LINE_LEN_QUOT "[^\r\n]", &(current->start), &(current->end),line2) !=3) |
| 254 | ); |
| 255 | |
| 256 | p=line2; |
| 257 | |
| 258 | next=p, i=0; |
| 259 | while ((next =sub_readtext (next, &(current->text[i])))) { |
| 260 | if (current->text[i]==ERR) return (subtitle_t *)ERR; |
| 261 | i++; |
| 262 | if (i>=SUB_MAX_TEXT) { |
| 263 | printf ("Too many lines in a subtitle\n"); |
| 264 | current->lines=i; |
| 265 | return current; |
| 266 | } |
| 267 | } |
| 268 | current->lines= ++i; |
| 269 | |
| 270 | return current; |
| 271 | } |
| 272 | |
| 273 | static subtitle_t *sub_read_line_subviewer(demux_sputext_t *demuxstr, subtitle_t *current) { |
| 274 | |
| 275 | char line[LINE_LEN + 1]; |
| 276 | int a1,a2,a3,a4,b1,b2,b3,b4; |
| 277 | char *p=NULL, *q=NULL; |
| 278 | int len; |
| 279 | |
| 280 | memset (current, 0, sizeof(subtitle_t)); |
| 281 | |
| 282 | while (1) { |
| 283 | if (!read_line_from_input(demuxstr, line, LINE_LEN)) return NULL; |
| 284 | if (sscanf (line, "%d:%d:%d.%d,%d:%d:%d.%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4) < 8) { |
| 285 | if (sscanf (line, "%d:%d:%d,%d,%d:%d:%d,%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4) < 8) |
| 286 | continue; |
| 287 | } |
| 288 | current->start = a1*360000+a2*6000+a3*100+a4; |
| 289 | current->end = b1*360000+b2*6000+b3*100+b4; |
| 290 | |
| 291 | if (!read_line_from_input(demuxstr, line, LINE_LEN)) |
| 292 | return NULL; |
| 293 | |
| 294 | p=q=line; |
| 295 | for (current->lines=1; current->lines <= SUB_MAX_TEXT; current->lines++) { |
| 296 | for (q=p,len=0; *p && *p!='\r' && *p!='\n' && *p!='|' && strncasecmp(p,"[br]",4); p++,len++); |
| 297 | current->text[current->lines-1]=(char *)malloc (len+1); |
| 298 | if (!current->text[current->lines-1]) return (subtitle_t *)ERR; |
| 299 | strncpy (current->text[current->lines-1], q, len); |
| 300 | current->text[current->lines-1][len]='\0'; |
| 301 | if (!*p || *p=='\r' || *p=='\n') break; |
| 302 | if (*p=='[') while (*p++!=']'); |
| 303 | if (*p=='|') p++; |
| 304 | } |
| 305 | if (current->lines > SUB_MAX_TEXT) current->lines = SUB_MAX_TEXT; |
| 306 | break; |
| 307 | } |
| 308 | return current; |
| 309 | } |
| 310 | |
| 311 | static subtitle_t *sub_read_line_subrip(demux_sputext_t *demuxstr,subtitle_t *current) { |
| 312 | char line[LINE_LEN + 1]; |
| 313 | int a1,a2,a3,a4,b1,b2,b3,b4; |
| 314 | int i,end_sub; |
| 315 | |
| 316 | memset(current,0,sizeof(subtitle_t)); |
| 317 | do { |
| 318 | if(!read_line_from_input(demuxstr,line,LINE_LEN)) |
| 319 | return NULL; |
| 320 | i = sscanf(line,"%d:%d:%d%*[,.]%d --> %d:%d:%d%*[,.]%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4); |
| 321 | } while(i < 8); |
| 322 | current->start = a1*360000+a2*6000+a3*100+a4/10; |
| 323 | current->end = b1*360000+b2*6000+b3*100+b4/10; |
| 324 | i=0; |
| 325 | end_sub=0; |
| 326 | do { |
| 327 | char *p; /* pointer to the curently read char */ |
| 328 | char temp_line[SUB_BUFSIZE]; /* subtitle line that will be transfered to current->text[i] */ |
| 329 | int temp_index; /* ... and its index wich 'points' to the first EMPTY place -> last read char is at temp_index-1 if temp_index>0 */ |
| 330 | temp_line[SUB_BUFSIZE-1]='\0'; /* just in case... */ |
| 331 | if(!read_line_from_input(demuxstr,line,LINE_LEN)) { |
| 332 | if(i) |
| 333 | break; /* if something was read, transmit it */ |
| 334 | else |
| 335 | return NULL; /* if not, repport EOF */ |
| 336 | } |
| 337 | for(temp_index=0,p=line;*p!='\0' && !end_sub && temp_index<SUB_BUFSIZE && i<SUB_MAX_TEXT;p++) { |
| 338 | switch(*p) { |
| 339 | case '\\': |
| 340 | if(*(p+1)=='N' || *(p+1)=='n') { |
| 341 | temp_line[temp_index++]='\0'; /* end of curent line */ |
| 342 | p++; |
| 343 | } else |
| 344 | temp_line[temp_index++]=*p; |
| 345 | break; |
| 346 | case '{': |
| 347 | #if 0 /* italic not implemented in renderer, ignore them for now */ |
| 348 | if(!strncmp(p,"{\\i1}",5) && temp_index+3<SUB_BUFSIZE) { |
| 349 | temp_line[temp_index++]='<'; |
| 350 | temp_line[temp_index++]='i'; |
| 351 | temp_line[temp_index++]='>'; |
| 352 | #else |
| 353 | if(!strncmp(p,"{\\i1}",5)) { |
| 354 | #endif |
| 355 | p+=4; |
| 356 | } |
| 357 | #if 0 /* italic not implemented in renderer, ignore them for now */ |
| 358 | else if(!strncmp(p,"{\\i0}",5) && temp_index+4<SUB_BUFSIZE) { |
| 359 | temp_line[temp_index++]='<'; |
| 360 | temp_line[temp_index++]='/'; |
| 361 | temp_line[temp_index++]='i'; |
| 362 | temp_line[temp_index++]='>'; |
| 363 | #else |
| 364 | else if(!strncmp(p,"{\\i0}",5)) { |
| 365 | #endif |
| 366 | p+=4; |
| 367 | } |
| 368 | else |
| 369 | temp_line[temp_index++]=*p; |
| 370 | break; |
| 371 | case '\r': /* just ignore '\r's */ |
| 372 | break; |
| 373 | case '\n': |
| 374 | temp_line[temp_index++]='\0'; |
| 375 | break; |
| 376 | default: |
| 377 | temp_line[temp_index++]=*p; |
| 378 | break; |
| 379 | } |
| 380 | if(temp_index>0) { |
| 381 | if(temp_index==SUB_BUFSIZE) |
| 382 | printf("Too many characters in a subtitle line\n"); |
| 383 | if(temp_line[temp_index-1]=='\0' || temp_index==SUB_BUFSIZE) { |
| 384 | if(temp_index>1) { /* more than 1 char (including '\0') -> that is a valid one */ |
| 385 | current->text[i]=(char *)malloc(temp_index); |
| 386 | if(!current->text[i]) |
| 387 | return (subtitle_t *)ERR; |
| 388 | strncpy(current->text[i],temp_line,temp_index); /* temp_index<=SUB_BUFSIZE is always true here */ |
| 389 | i++; |
| 390 | temp_index=0; |
| 391 | } else |
| 392 | end_sub=1; |
| 393 | } |
| 394 | } |
| 395 | } |
| 396 | } while(i<SUB_MAX_TEXT && !end_sub); |
| 397 | if(i>=SUB_MAX_TEXT) |
| 398 | printf("Too many lines in a subtitle\n"); |
| 399 | current->lines=i; |
| 400 | return current; |
| 401 | } |
| 402 | |
| 403 | static subtitle_t *sub_read_line_vplayer(demux_sputext_t *demuxstr,subtitle_t *current) { |
| 404 | char line[LINE_LEN + 1]; |
| 405 | int a1,a2,a3,b1,b2,b3; |
| 406 | char *p=NULL, *next, *p2; |
| 407 | int i; |
| 408 | |
| 409 | memset (current, 0, sizeof(subtitle_t)); |
| 410 | |
| 411 | while (!current->text[0]) { |
| 412 | if( demuxstr->next_line[0] == '\0' ) { /* if the buffer is empty.... */ |
| 413 | if( !read_line_from_input(demuxstr, line, LINE_LEN) ) return NULL; |
| 414 | } else { |
| 415 | /* ... get the current line from buffer. */ |
| 416 | strncpy( line, demuxstr->next_line, LINE_LEN); |
| 417 | line[LINE_LEN] = '\0'; /* I'm scared. demuxstr makes me feel better. */ |
| 418 | demuxstr->next_line[0] = '\0'; /* mark the buffer as empty. */ |
| 419 | } |
| 420 | /* Initialize buffer with next line */ |
| 421 | if( ! read_line_from_input( demuxstr, demuxstr->next_line, LINE_LEN) ) { |
| 422 | demuxstr->next_line[0] = '\0'; |
| 423 | return NULL; |
| 424 | } |
| 425 | if( (sscanf( line, "%d:%d:%d:", &a1, &a2, &a3) < 3) || |
| 426 | (sscanf( demuxstr->next_line, "%d:%d:%d:", &b1, &b2, &b3) < 3) ) |
| 427 | continue; |
| 428 | current->start = a1*360000+a2*6000+a3*100; |
| 429 | current->end = b1*360000+b2*6000+b3*100; |
| 430 | if ((current->end - current->start) > LINE_LEN) |
| 431 | current->end = current->start + LINE_LEN; /* not too long though. */ |
| 432 | /* teraz czas na wkopiowanie stringu */ |
| 433 | p=line; |
| 434 | /* finds the body of the subtitle_t */ |
| 435 | for (i=0; i<3; i++){ |
| 436 | p2=strchr( p, ':'); |
| 437 | if( p2 == NULL ) break; |
| 438 | p=p2+1; |
| 439 | } |
| 440 | |
| 441 | next=p; |
| 442 | i=0; |
| 443 | while( (next = sub_readtext( next, &(current->text[i]))) ) { |
| 444 | if (current->text[i]==ERR) |
| 445 | return (subtitle_t *)ERR; |
| 446 | i++; |
| 447 | if (i>=SUB_MAX_TEXT) { |
| 448 | printf("Too many lines in a subtitle\n"); |
| 449 | current->lines=i; |
| 450 | return current; |
| 451 | } |
| 452 | } |
| 453 | current->lines=++i; |
| 454 | } |
| 455 | return current; |
| 456 | } |
| 457 | |
| 458 | static subtitle_t *sub_read_line_rt(demux_sputext_t *demuxstr,subtitle_t *current) { |
| 459 | /* |
| 460 | * TODO: This format uses quite rich (sub/super)set of xhtml |
| 461 | * I couldn't check it since DTD is not included. |
| 462 | * WARNING: full XML parses can be required for proper parsing |
| 463 | */ |
| 464 | char line[LINE_LEN + 1]; |
| 465 | int a1,a2,a3,a4,b1,b2,b3,b4; |
| 466 | char *p=NULL,*next=NULL; |
| 467 | int i,len,plen; |
| 468 | |
| 469 | memset (current, 0, sizeof(subtitle_t)); |
| 470 | |
| 471 | while (!current->text[0]) { |
| 472 | if (!read_line_from_input(demuxstr, line, LINE_LEN)) return NULL; |
| 473 | /* |
| 474 | * TODO: it seems that format of time is not easily determined, it may be 1:12, 1:12.0 or 0:1:12.0 |
| 475 | * to describe the same moment in time. Maybe there are even more formats in use. |
| 476 | */ |
| 477 | if ((len=sscanf (line, "<Time Begin=\"%d:%d:%d.%d\" End=\"%d:%d:%d.%d\"",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4)) < 8) |
| 478 | |
| 479 | plen=a1=a2=a3=a4=b1=b2=b3=b4=0; |
| 480 | if ( |
| 481 | ((len=sscanf (line, "<%*[tT]ime %*[bB]egin=\"%d:%d\" %*[Ee]nd=\"%d:%d\"%*[^<]<clear/>%n",&a2,&a3,&b2,&b3,&plen)) < 4) && |
| 482 | ((len=sscanf (line, "<%*[tT]ime %*[bB]egin=\"%d:%d\" %*[Ee]nd=\"%d:%d.%d\"%*[^<]<clear/>%n",&a2,&a3,&b2,&b3,&b4,&plen)) < 5) && |
| 483 | /* ((len=sscanf (line, "<%*[tT]ime %*[bB]egin=\"%d:%d.%d\" %*[Ee]nd=\"%d:%d\"%*[^<]<clear/>%n",&a2,&a3,&a4,&b2,&b3,&plen)) < 5) && */ |
| 484 | ((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) && |
| 485 | ((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) |
| 486 | ) |
| 487 | continue; |
| 488 | current->start = a1*360000+a2*6000+a3*100+a4/10; |
| 489 | current->end = b1*360000+b2*6000+b3*100+b4/10; |
| 490 | p=line; p+=plen;i=0; |
| 491 | /* TODO: I don't know what kind of convention is here for marking multiline subs, maybe <br/> like in xml? */ |
| 492 | next = strstr(line,"<clear/>")+8;i=0; |
| 493 | while ((next =sub_readtext (next, &(current->text[i])))) { |
| 494 | if (current->text[i]==ERR) |
| 495 | return (subtitle_t *)ERR; |
| 496 | i++; |
| 497 | if (i>=SUB_MAX_TEXT) { |
| 498 | printf("Too many lines in a subtitle\n"); |
| 499 | current->lines=i; |
| 500 | return current; |
| 501 | } |
| 502 | } |
| 503 | current->lines=i+1; |
| 504 | } |
| 505 | return current; |
| 506 | } |
| 507 | |
| 508 | static subtitle_t *sub_read_line_ssa(demux_sputext_t *demuxstr,subtitle_t *current) { |
| 509 | int comma; |
| 510 | static int max_comma = 32; /* let's use 32 for the case that the */ |
| 511 | /* amount of commas increase with newer SSA versions */ |
| 512 | |
| 513 | int hour1, min1, sec1, hunsec1, hour2, min2, sec2, hunsec2, nothing; |
| 514 | int num; |
| 515 | char line[LINE_LEN + 1], line3[LINE_LEN + 1], *line2; |
| 516 | char *tmp; |
| 517 | |
| 518 | do { |
| 519 | if (!read_line_from_input(demuxstr, line, LINE_LEN)) return NULL; |
| 520 | } while (sscanf (line, "Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d," |
| 521 | "%[^\n\r]", ¬hing, |
| 522 | &hour1, &min1, &sec1, &hunsec1, |
| 523 | &hour2, &min2, &sec2, &hunsec2, |
| 524 | line3) < 9 |
| 525 | && |
| 526 | sscanf (line, "Dialogue: %d,%d:%d:%d.%d,%d:%d:%d.%d," |
| 527 | "%[^\n\r]", ¬hing, |
| 528 | &hour1, &min1, &sec1, &hunsec1, |
| 529 | &hour2, &min2, &sec2, &hunsec2, |
| 530 | line3) < 9 ); |
| 531 | |
| 532 | line2=strchr(line3, ','); |
| 533 | if (!line2) |
| 534 | return NULL; |
| 535 | |
| 536 | for (comma = 4; comma < max_comma; comma ++) |
| 537 | { |
| 538 | tmp = line2; |
| 539 | if(!(tmp=strchr(++tmp, ','))) break; |
| 540 | if(*(++tmp) == ' ') break; |
| 541 | /* a space after a comma means we're already in a sentence */ |
| 542 | line2 = tmp; |
| 543 | } |
| 544 | |
| 545 | if(comma < max_comma)max_comma = comma; |
| 546 | /* eliminate the trailing comma */ |
| 547 | if(*line2 == ',') line2++; |
| 548 | |
| 549 | current->lines=0;num=0; |
| 550 | current->start = 360000*hour1 + 6000*min1 + 100*sec1 + hunsec1; |
| 551 | current->end = 360000*hour2 + 6000*min2 + 100*sec2 + hunsec2; |
| 552 | |
| 553 | while (((tmp=strstr(line2, "\\n")) != NULL) || ((tmp=strstr(line2, "\\N")) != NULL) ){ |
| 554 | current->text[num]=(char *)malloc(tmp-line2+1); |
| 555 | strncpy (current->text[num], line2, tmp-line2); |
| 556 | current->text[num][tmp-line2]='\0'; |
| 557 | line2=tmp+2; |
| 558 | num++; |
| 559 | current->lines++; |
| 560 | if (current->lines >= SUB_MAX_TEXT) return current; |
| 561 | } |
| 562 | |
| 563 | current->text[num]=strdup(line2); |
| 564 | current->lines++; |
| 565 | |
| 566 | return current; |
| 567 | } |
| 568 | |
| 569 | /* Sylvain "Skarsnik" Colinet <scolinet@gmail.com> |
| 570 | * From MPlayer subreader.c : |
| 571 | * |
| 572 | * PJS subtitles reader. |
| 573 | * That's the "Phoenix Japanimation Society" format. |
| 574 | * I found some of them in http://www.scriptsclub.org/ (used for anime). |
| 575 | * The time is in tenths of second. |
| 576 | * |
| 577 | * by set, based on code by szabi (dunnowhat sub format ;-) |
| 578 | */ |
| 579 | |
| 580 | static subtitle_t *sub_read_line_pjs (demux_sputext_t *demuxstr, subtitle_t *current) { |
| 581 | char line[LINE_LEN + 1]; |
| 582 | char text[LINE_LEN + 1]; |
| 583 | char *s, *d; |
| 584 | |
| 585 | memset (current, 0, sizeof(subtitle_t)); |
| 586 | |
| 587 | if (!read_line_from_input(demuxstr, line, LINE_LEN)) |
| 588 | return NULL; |
| 589 | for (s = line; *s && isspace(*s); s++); |
| 590 | if (*s == 0) |
| 591 | return NULL; |
| 592 | if (sscanf (line, "%ld,%ld,", &(current->start), |
| 593 | &(current->end)) <2) |
| 594 | return (subtitle_t *)ERR; |
| 595 | /* the files I have are in tenths of second */ |
| 596 | current->start *= 10; |
| 597 | current->end *= 10; |
| 598 | |
| 599 | /* walk to the beggining of the string */ |
| 600 | for (; *s; s++) if (*s==',') break; |
| 601 | if (*s) { |
| 602 | for (s++; *s; s++) if (*s==',') break; |
| 603 | if (*s) s++; |
| 604 | } |
| 605 | if (*s!='"') { |
| 606 | return (subtitle_t *)ERR; |
| 607 | } |
| 608 | /* copy the string to the text buffer */ |
| 609 | for (s++, d=text; *s && *s!='"'; s++, d++) |
| 610 | *d=*s; |
| 611 | *d=0; |
| 612 | current->text[0] = strdup(text); |
| 613 | current->lines = 1; |
| 614 | |
| 615 | return current; |
| 616 | } |
| 617 | |
| 618 | static subtitle_t *sub_read_line_mpsub (demux_sputext_t *demuxstr, subtitle_t *current) { |
| 619 | char line[LINE_LEN + 1]; |
| 620 | float a,b; |
| 621 | int num=0; |
| 622 | char *p, *q; |
| 623 | |
| 624 | do { |
| 625 | if (!read_line_from_input(demuxstr, line, LINE_LEN)) |
| 626 | return NULL; |
| 627 | } while (sscanf (line, "%f %f", &a, &b) !=2); |
| 628 | |
| 629 | demuxstr->mpsub_position += (a*100.0); |
| 630 | current->start = (int) demuxstr->mpsub_position; |
| 631 | demuxstr->mpsub_position += (b*100.0); |
| 632 | current->end = (int) demuxstr->mpsub_position; |
| 633 | |
| 634 | while (num < SUB_MAX_TEXT) { |
| 635 | if (!read_line_from_input(demuxstr, line, LINE_LEN)) |
| 636 | return NULL; |
| 637 | |
| 638 | p=line; |
| 639 | while (isspace(*p)) |
| 640 | p++; |
| 641 | |
| 642 | if (eol(*p) && num > 0) |
| 643 | return current; |
| 644 | |
| 645 | if (eol(*p)) |
| 646 | return NULL; |
| 647 | |
| 648 | for (q=p; !eol(*q); q++); |
| 649 | *q='\0'; |
| 650 | if (strlen(p)) { |
| 651 | current->text[num]=strdup(p); |
| 652 | printf(">%s<\n",p); |
| 653 | current->lines = ++num; |
| 654 | } else { |
| 655 | if (num) |
| 656 | return current; |
| 657 | else |
| 658 | return NULL; |
| 659 | } |
| 660 | } |
| 661 | |
| 662 | return NULL; |
| 663 | } |
| 664 | |
| 665 | static subtitle_t *sub_read_line_aqt (demux_sputext_t *demuxstr, subtitle_t *current) { |
| 666 | char line[LINE_LEN + 1]; |
| 667 | |
| 668 | memset (current, 0, sizeof(subtitle_t)); |
| 669 | |
| 670 | while (1) { |
| 671 | /* try to locate next subtitle_t */ |
| 672 | if (!read_line_from_input(demuxstr, line, LINE_LEN)) |
| 673 | return NULL; |
| 674 | if (!(sscanf (line, "-->> %ld", &(current->start)) <1)) |
| 675 | break; |
| 676 | } |
| 677 | |
| 678 | if (!read_line_from_input(demuxstr, line, LINE_LEN)) |
| 679 | return NULL; |
| 680 | |
| 681 | sub_readtext((char *) &line,¤t->text[0]); |
| 682 | current->lines = 1; |
| 683 | current->end = -1; |
| 684 | |
| 685 | if (!read_line_from_input(demuxstr, line, LINE_LEN)) |
| 686 | return current;; |
| 687 | |
| 688 | sub_readtext((char *) &line,¤t->text[1]); |
| 689 | current->lines = 2; |
| 690 | |
| 691 | if ((current->text[0][0]==0) && (current->text[1][0]==0)) { |
| 692 | return NULL; |
| 693 | } |
| 694 | |
| 695 | return current; |
| 696 | } |
| 697 | |
| 698 | static subtitle_t *sub_read_line_jacobsub(demux_sputext_t *demuxstr, subtitle_t *current) { |
| 699 | char line1[LINE_LEN], line2[LINE_LEN], directive[LINE_LEN], *p, *q; |
| 700 | unsigned a1, a2, a3, a4, b1, b2, b3, b4, comment = 0; |
| 701 | static unsigned jacoTimeres = 30; |
| 702 | static int jacoShift = 0; |
| 703 | |
| 704 | memset(current, 0, sizeof(subtitle_t)); |
| 705 | memset(line1, 0, LINE_LEN); |
| 706 | memset(line2, 0, LINE_LEN); |
| 707 | memset(directive, 0, LINE_LEN); |
| 708 | while (!current->text[0]) { |
| 709 | if (!read_line_from_input(demuxstr, line1, LINE_LEN)) { |
| 710 | return NULL; |
| 711 | } |
| 712 | if (sscanf |
| 713 | (line1, "%u:%u:%u.%u %u:%u:%u.%u %" LINE_LEN_QUOT "[^\n\r]", &a1, &a2, &a3, &a4, |
| 714 | &b1, &b2, &b3, &b4, line2) < 9) { |
| 715 | if (sscanf(line1, "@%u @%u %" LINE_LEN_QUOT "[^\n\r]", &a4, &b4, line2) < 3) { |
| 716 | if (line1[0] == '#') { |
| 717 | int hours = 0, minutes = 0, seconds, delta, inverter = |
| 718 | 1; |
| 719 | unsigned units = jacoShift; |
| 720 | switch (toupper(line1[1])) { |
| 721 | case 'S': |
| 722 | if (isalpha(line1[2])) { |
| 723 | delta = 6; |
| 724 | } else { |
| 725 | delta = 2; |
| 726 | } |
| 727 | if (sscanf(&line1[delta], "%d", &hours)) { |
| 728 | if (hours < 0) { |
| 729 | hours *= -1; |
| 730 | inverter = -1; |
| 731 | } |
| 732 | if (sscanf(&line1[delta], "%*d:%d", &minutes)) { |
| 733 | if (sscanf |
| 734 | (&line1[delta], "%*d:%*d:%d", |
| 735 | &seconds)) { |
| 736 | sscanf(&line1[delta], "%*d:%*d:%*d.%d", |
| 737 | &units); |
| 738 | } else { |
| 739 | hours = 0; |
| 740 | sscanf(&line1[delta], "%d:%d.%d", |
| 741 | &minutes, &seconds, &units); |
| 742 | minutes *= inverter; |
| 743 | } |
| 744 | } else { |
| 745 | hours = minutes = 0; |
| 746 | sscanf(&line1[delta], "%d.%d", &seconds, |
| 747 | &units); |
| 748 | seconds *= inverter; |
| 749 | } |
| 750 | jacoShift = |
| 751 | ((hours * 3600 + minutes * 60 + |
| 752 | seconds) * jacoTimeres + |
| 753 | units) * inverter; |
| 754 | } |
| 755 | break; |
| 756 | case 'T': |
| 757 | if (isalpha(line1[2])) { |
| 758 | delta = 8; |
| 759 | } else { |
| 760 | delta = 2; |
| 761 | } |
| 762 | sscanf(&line1[delta], "%u", &jacoTimeres); |
| 763 | break; |
| 764 | } |
| 765 | } |
| 766 | continue; |
| 767 | } else { |
| 768 | current->start = |
| 769 | (unsigned long) ((a4 + jacoShift) * 100.0 / |
| 770 | jacoTimeres); |
| 771 | current->end = |
| 772 | (unsigned long) ((b4 + jacoShift) * 100.0 / |
| 773 | jacoTimeres); |
| 774 | } |
| 775 | } else { |
| 776 | current->start = |
| 777 | (unsigned |
| 778 | long) (((a1 * 3600 + a2 * 60 + a3) * jacoTimeres + a4 + |
| 779 | jacoShift) * 100.0 / jacoTimeres); |
| 780 | current->end = |
| 781 | (unsigned |
| 782 | long) (((b1 * 3600 + b2 * 60 + b3) * jacoTimeres + b4 + |
| 783 | jacoShift) * 100.0 / jacoTimeres); |
| 784 | } |
| 785 | current->lines = 0; |
| 786 | p = line2; |
| 787 | while ((*p == ' ') || (*p == '\t')) { |
| 788 | ++p; |
| 789 | } |
| 790 | if (isalpha(*p)||*p == '[') { |
| 791 | int cont, jLength; |
| 792 | |
| 793 | if (sscanf(p, "%s %" LINE_LEN_QUOT "[^\n\r]", directive, line1) < 2) |
| 794 | return (subtitle_t *)ERR; |
| 795 | jLength = strlen(directive); |
| 796 | for (cont = 0; cont < jLength; ++cont) { |
| 797 | if (isalpha(*(directive + cont))) |
| 798 | *(directive + cont) = toupper(*(directive + cont)); |
| 799 | } |
| 800 | if ((strstr(directive, "RDB") != NULL) |
| 801 | || (strstr(directive, "RDC") != NULL) |
| 802 | || (strstr(directive, "RLB") != NULL) |
| 803 | || (strstr(directive, "RLG") != NULL)) { |
| 804 | continue; |
| 805 | } |
| 806 | /* no alignment */ |
| 807 | #if 0 |
| 808 | if (strstr(directive, "JL") != NULL) { |
| 809 | current->alignment = SUB_ALIGNMENT_HLEFT; |
| 810 | } else if (strstr(directive, "JR") != NULL) { |
| 811 | current->alignment = SUB_ALIGNMENT_HRIGHT; |
| 812 | } else { |
| 813 | current->alignment = SUB_ALIGNMENT_HCENTER; |
| 814 | } |
| 815 | #endif |
| 816 | strcpy(line2, line1); |
| 817 | p = line2; |
| 818 | } |
| 819 | for (q = line1; (!eol(*p)) && (current->lines < SUB_MAX_TEXT); ++p) { |
| 820 | switch (*p) { |
| 821 | case '{': |
| 822 | comment++; |
| 823 | break; |
| 824 | case '}': |
| 825 | if (comment) { |
| 826 | --comment; |
| 827 | /* the next line to get rid of a blank after the comment */ |
| 828 | if ((*(p + 1)) == ' ') |
| 829 | p++; |
| 830 | } |
| 831 | break; |
| 832 | case '~': |
| 833 | if (!comment) { |
| 834 | *q = ' '; |
| 835 | ++q; |
| 836 | } |
| 837 | break; |
| 838 | case ' ': |
| 839 | case '\t': |
| 840 | if ((*(p + 1) == ' ') || (*(p + 1) == '\t')) |
| 841 | break; |
| 842 | if (!comment) { |
| 843 | *q = ' '; |
| 844 | ++q; |
| 845 | } |
| 846 | break; |
| 847 | case '\\': |
| 848 | if (*(p + 1) == 'n') { |
| 849 | *q = '\0'; |
| 850 | q = line1; |
| 851 | current->text[current->lines++] = strdup(line1); |
| 852 | ++p; |
| 853 | break; |
| 854 | } |
| 855 | if ((toupper(*(p + 1)) == 'C') |
| 856 | || (toupper(*(p + 1)) == 'F')) { |
| 857 | ++p,++p; |
| 858 | break; |
| 859 | } |
| 860 | if ((*(p + 1) == 'B') || (*(p + 1) == 'b') || |
| 861 | /* actually this means "insert current date here" */ |
| 862 | (*(p + 1) == 'D') || |
| 863 | (*(p + 1) == 'I') || (*(p + 1) == 'i') || |
| 864 | (*(p + 1) == 'N') || |
| 865 | /* actually this means "insert current time here" */ |
| 866 | (*(p + 1) == 'T') || |
| 867 | (*(p + 1) == 'U') || (*(p + 1) == 'u')) { |
| 868 | ++p; |
| 869 | break; |
| 870 | } |
| 871 | if ((*(p + 1) == '\\') || |
| 872 | (*(p + 1) == '~') || (*(p + 1) == '{')) { |
| 873 | ++p; |
| 874 | } else if (eol(*(p + 1))) { |
| 875 | if (!read_line_from_input(demuxstr, directive, LINE_LEN)) |
| 876 | return NULL; |
| 877 | trail_space(directive); |
| 878 | strncat(line2, directive, |
| 879 | (LINE_LEN > 511) ? LINE_LEN : 511); |
| 880 | break; |
| 881 | } |
| 882 | default: |
| 883 | if (!comment) { |
| 884 | *q = *p; |
| 885 | ++q; |
| 886 | } |
| 887 | } |
| 888 | } |
| 889 | *q = '\0'; |
| 890 | current->text[current->lines] = strdup(line1); |
| 891 | } |
| 892 | current->lines++; |
| 893 | return current; |
| 894 | } |
| 895 | |
| 896 | static subtitle_t *sub_read_line_subviewer2(demux_sputext_t *demuxstr, subtitle_t *current) { |
| 897 | char line[LINE_LEN+1]; |
| 898 | int a1,a2,a3,a4; |
| 899 | char *p=NULL; |
| 900 | int i,len; |
| 901 | |
| 902 | while (!current->text[0]) { |
| 903 | if (!read_line_from_input(demuxstr, line, LINE_LEN)) return NULL; |
| 904 | if (line[0]!='{') |
| 905 | continue; |
| 906 | if ((len=sscanf (line, "{T %d:%d:%d:%d",&a1,&a2,&a3,&a4)) < 4) |
| 907 | continue; |
| 908 | current->start = a1*360000+a2*6000+a3*100+a4/10; |
| 909 | for (i=0; i<SUB_MAX_TEXT;) { |
| 910 | if (!read_line_from_input(demuxstr, line, LINE_LEN)) break; |
| 911 | if (line[0]=='}') break; |
| 912 | len=0; |
| 913 | for (p=line; *p!='\n' && *p!='\r' && *p; ++p,++len); |
| 914 | if (len) { |
| 915 | current->text[i]=(char *)malloc (len+1); |
| 916 | if (!current->text[i]) return (subtitle_t *)ERR; |
| 917 | strncpy (current->text[i], line, len); current->text[i][len]='\0'; |
| 918 | ++i; |
| 919 | } else { |
| 920 | break; |
| 921 | } |
| 922 | } |
| 923 | current->lines=i; |
| 924 | } |
| 925 | return current; |
| 926 | } |
| 927 | |
| 928 | static subtitle_t *sub_read_line_subrip09 (demux_sputext_t *demuxstr, subtitle_t *current) { |
| 929 | char line[LINE_LEN + 1]; |
| 930 | char *next; |
| 931 | int h, m, s; |
| 932 | int i; |
| 933 | |
| 934 | memset (current, 0, sizeof(subtitle_t)); |
| 935 | |
| 936 | do { |
| 937 | if (!read_line_from_input (demuxstr, line, LINE_LEN)) return NULL; |
| 938 | } while (sscanf (line, "[%d:%d:%d]", &h, &m, &s) != 3); |
| 939 | |
| 940 | if (!read_line_from_input (demuxstr, line, LINE_LEN)) return NULL; |
| 941 | |
| 942 | current->start = 360000 * h + 6000 * m + 100 * s; |
| 943 | current->end = -1; |
| 944 | |
| 945 | next=line; |
| 946 | i=0; |
| 947 | while ((next = sub_readtext (next, &(current->text[i])))) { |
| 948 | if (current->text[i]==ERR) return (subtitle_t *)ERR; |
| 949 | i++; |
| 950 | if (i>=SUB_MAX_TEXT) { |
| 951 | printf("Too many lines in a subtitle\n"); |
| 952 | current->lines=i; |
| 953 | return current; |
| 954 | } |
| 955 | } |
| 956 | current->lines= ++i; |
| 957 | |
| 958 | return current; |
| 959 | } |
| 960 | |
| 961 | /* Code from subreader.c of MPlayer |
| 962 | ** Sylvain "Skarsnik" Colinet <scolinet@gmail.com> |
| 963 | */ |
| 964 | |
| 965 | static subtitle_t *sub_read_line_mpl2(demux_sputext_t *demuxstr, subtitle_t *current) { |
| 966 | char line[LINE_LEN+1]; |
| 967 | char line2[LINE_LEN+1]; |
| 968 | char *p, *next; |
| 969 | int i; |
| 970 | |
| 971 | memset (current, 0, sizeof(subtitle_t)); |
| 972 | do { |
| 973 | if (!read_line_from_input (demuxstr, line, LINE_LEN)) return NULL; |
| 974 | } while ((sscanf (line, |
| 975 | "[%ld][%ld]%[^\r\n]", |
| 976 | &(current->start), &(current->end), line2) < 3)); |
| 977 | current->start *= 10; |
| 978 | current->end *= 10; |
| 979 | p=line2; |
| 980 | |
| 981 | next=p, i=0; |
| 982 | while ((next = sub_readtext (next, &(current->text[i])))) { |
| 983 | if (current->text[i] == ERR) {return (subtitle_t *)ERR;} |
| 984 | i++; |
| 985 | if (i >= SUB_MAX_TEXT) { |
| 986 | printf("Too many lines in a subtitle\n"); |
| 987 | current->lines = i; |
| 988 | return current; |
| 989 | } |
| 990 | } |
| 991 | current->lines= ++i; |
| 992 | |
| 993 | return current; |
| 994 | } |
| 995 | |
| 996 | |
| 997 | static int sub_autodetect (demux_sputext_t *demuxstr) { |
| 998 | |
| 999 | char line[LINE_LEN + 1]; |
| 1000 | int i, j=0; |
| 1001 | char p; |
| 1002 | |
| 1003 | while (j < 100) { |
| 1004 | j++; |
| 1005 | if (!read_line_from_input(demuxstr, line, LINE_LEN)) |
| 1006 | return FORMAT_UNKNOWN; |
| 1007 | |
| 1008 | if ((sscanf (line, "{%d}{}", &i)==1) || |
| 1009 | (sscanf (line, "{%d}{%d}", &i, &i)==2)) { |
| 1010 | demuxstr->uses_time=0; |
| 1011 | return FORMAT_MICRODVD; |
| 1012 | } |
| 1013 | |
| 1014 | if (sscanf (line, "%d:%d:%d%*[,.]%d --> %d:%d:%d%*[,.]%d", &i, &i, &i, &i, &i, &i, &i, &i)==8) { |
| 1015 | demuxstr->uses_time=1; |
| 1016 | return FORMAT_SUBRIP; |
| 1017 | } |
| 1018 | |
| 1019 | if (sscanf (line, "%d:%d:%d.%d,%d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i)==8){ |
| 1020 | demuxstr->uses_time=1; |
| 1021 | return FORMAT_SUBVIEWER; |
| 1022 | } |
| 1023 | |
| 1024 | if (sscanf (line, "%d:%d:%d,%d,%d:%d:%d,%d", &i, &i, &i, &i, &i, &i, &i, &i)==8){ |
| 1025 | demuxstr->uses_time=1; |
| 1026 | return FORMAT_SUBVIEWER; |
| 1027 | } |
| 1028 | |
| 1029 | if (strstr (line, "<SAMI>")) { |
| 1030 | demuxstr->uses_time=1; |
| 1031 | return FORMAT_SAMI; |
| 1032 | } |
| 1033 | if (sscanf (line, "%d:%d:%d:", &i, &i, &i )==3) { |
| 1034 | demuxstr->uses_time=1; |
| 1035 | return FORMAT_VPLAYER; |
| 1036 | } |
| 1037 | /* |
| 1038 | * A RealText format is a markup language, starts with <window> tag, |
| 1039 | * options (behaviour modifiers) are possible. |
| 1040 | */ |
| 1041 | if ( !strcasecmp(line, "<window") ) { |
| 1042 | demuxstr->uses_time=1; |
| 1043 | return FORMAT_RT; |
| 1044 | } |
| 1045 | if ((!memcmp(line, "Dialogue: Marked", 16)) || (!memcmp(line, "Dialogue: ", 10))) { |
| 1046 | demuxstr->uses_time=1; |
| 1047 | return FORMAT_SSA; |
| 1048 | } |
| 1049 | if (sscanf (line, "%d,%d,\"%c", &i, &i, (char *) &i) == 3) { |
| 1050 | demuxstr->uses_time=0; |
| 1051 | return FORMAT_PJS; |
| 1052 | } |
| 1053 | if (sscanf (line, "FORMAT=%d", &i) == 1) { |
| 1054 | demuxstr->uses_time=0; |
| 1055 | return FORMAT_MPSUB; |
| 1056 | } |
| 1057 | if (sscanf (line, "FORMAT=TIM%c", &p)==1 && p=='E') { |
| 1058 | demuxstr->uses_time=1; |
| 1059 | return FORMAT_MPSUB; |
| 1060 | } |
| 1061 | if (strstr (line, "-->>")) { |
| 1062 | demuxstr->uses_time=0; |
| 1063 | return FORMAT_AQTITLE; |
| 1064 | } |
| 1065 | if (sscanf(line, "@%d @%d", &i, &i) == 2 || |
| 1066 | sscanf(line, "%d:%d:%d.%d %d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8) { |
| 1067 | demuxstr->uses_time = 1; |
| 1068 | return FORMAT_JACOBSUB; |
| 1069 | } |
| 1070 | if (sscanf(line, "{T %d:%d:%d:%d",&i, &i, &i, &i) == 4) { |
| 1071 | demuxstr->uses_time = 1; |
| 1072 | return FORMAT_SUBVIEWER2; |
| 1073 | } |
| 1074 | if (sscanf(line, "[%d:%d:%d]", &i, &i, &i) == 3) { |
| 1075 | demuxstr->uses_time = 1; |
| 1076 | return FORMAT_SUBRIP09; |
| 1077 | } |
| 1078 | |
| 1079 | if (sscanf (line, "[%d][%d]", &i, &i) == 2) { |
| 1080 | demuxstr->uses_time = 1; |
| 1081 | return FORMAT_MPL2; |
| 1082 | } |
| 1083 | } |
| 1084 | return FORMAT_UNKNOWN; /* too many bad lines */ |
| 1085 | } |
| 1086 | |
| 1087 | subtitle_t *sub_read_file (demux_sputext_t *demuxstr) { |
| 1088 | |
| 1089 | int n_max; |
| 1090 | int timeout; |
| 1091 | subtitle_t *first; |
| 1092 | subtitle_t * (*func[])(demux_sputext_t *demuxstr,subtitle_t *dest)= |
| 1093 | { |
| 1094 | sub_read_line_microdvd, |
| 1095 | sub_read_line_subrip, |
| 1096 | sub_read_line_subviewer, |
| 1097 | sub_read_line_sami, |
| 1098 | sub_read_line_vplayer, |
| 1099 | sub_read_line_rt, |
| 1100 | sub_read_line_ssa, |
| 1101 | sub_read_line_pjs, |
| 1102 | sub_read_line_mpsub, |
| 1103 | sub_read_line_aqt, |
| 1104 | sub_read_line_jacobsub, |
| 1105 | sub_read_line_subviewer2, |
| 1106 | sub_read_line_subrip09, |
| 1107 | sub_read_line_mpl2, |
| 1108 | }; |
| 1109 | |
| 1110 | /* Rewind (sub_autodetect() needs to read input from the beginning) */ |
| 1111 | if(demuxstr->rbuffer->Seek(0, SEEK_SET) == -1) { |
| 1112 | printf("seek failed.\n"); |
| 1113 | return NULL; |
| 1114 | } |
| 1115 | demuxstr->buflen = 0; |
| 1116 | demuxstr->emptyReads = 0; |
| 1117 | |
| 1118 | demuxstr->format=sub_autodetect (demuxstr); |
| 1119 | if (demuxstr->format==FORMAT_UNKNOWN) { |
| 1120 | return NULL; |
| 1121 | } |
| 1122 | |
| 1123 | /*printf("Detected subtitle file format: %d\n", demuxstr->format);*/ |
| 1124 | |
| 1125 | /* Rewind */ |
| 1126 | if(demuxstr->rbuffer->Seek(0, SEEK_SET) == -1) { |
| 1127 | printf("seek failed.\n"); |
| 1128 | return NULL; |
| 1129 | } |
| 1130 | demuxstr->buflen = 0; |
| 1131 | demuxstr->emptyReads = 0; |
| 1132 | |
| 1133 | demuxstr->num=0;n_max=32; |
| 1134 | first = (subtitle_t *) malloc(n_max*sizeof(subtitle_t)); |
| 1135 | if(!first) return NULL; |
| 1136 | timeout = MAX_TIMEOUT; |
| 1137 | |
| 1138 | if (demuxstr->uses_time) timeout *= 100; |
| 1139 | else timeout *= 10; |
| 1140 | |
| 1141 | while(1) { |
| 1142 | subtitle_t *sub; |
| 1143 | |
| 1144 | if(demuxstr->num>=n_max){ |
| 1145 | n_max+=16; |
| 1146 | first=(subtitle_t *)realloc(first,n_max*sizeof(subtitle_t)); |
| 1147 | } |
| 1148 | |
| 1149 | sub = func[demuxstr->format] (demuxstr, &first[demuxstr->num]); |
| 1150 | |
| 1151 | if (!sub) |
| 1152 | break; /* EOF */ |
| 1153 | |
| 1154 | if (sub==ERR) |
| 1155 | ++demuxstr->errs; |
| 1156 | else { |
| 1157 | if (demuxstr->num > 0 && first[demuxstr->num-1].end == -1) { |
| 1158 | /* end time not defined in the subtitle */ |
| 1159 | if (timeout > 0) { |
| 1160 | /* timeout */ |
| 1161 | if (timeout > sub->start - first[demuxstr->num-1].start) { |
| 1162 | first[demuxstr->num-1].end = sub->start; |
| 1163 | } else |
| 1164 | first[demuxstr->num-1].end = first[demuxstr->num-1].start + timeout; |
| 1165 | } else { |
| 1166 | /* no timeout */ |
| 1167 | first[demuxstr->num-1].end = sub->start; |
| 1168 | } |
| 1169 | } |
| 1170 | ++demuxstr->num; /* Error vs. Valid */ |
| 1171 | } |
| 1172 | } |
| 1173 | /* timeout of last subtitle */ |
| 1174 | if (demuxstr->num > 0 && first[demuxstr->num-1].end == -1) |
| 1175 | if (timeout > 0) { |
| 1176 | first[demuxstr->num-1].end = first[demuxstr->num-1].start + timeout; |
| 1177 | } |
| 1178 | |
| 1179 | #ifdef DEBUX_XINE_DEMUX_SPUTEXT |
| 1180 | { |
| 1181 | char buffer[1024]; |
| 1182 | |
| 1183 | sprintf(buffer, "Read %i subtitles", demuxstr->num); |
| 1184 | |
| 1185 | if(demuxstr->errs) |
| 1186 | sprintf(buffer + strlen(buffer), ", %i bad line(s).\n", demuxstr->errs); |
| 1187 | else |
| 1188 | strcat(buffer, "\n"); |
| 1189 | |
| 1190 | printf("%s", buffer); |
| 1191 | } |
| 1192 | #endif |
| 1193 | |
| 1194 | return first; |
| 1195 | } |
| 1196 | |