00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #ifdef HAVE_CONFIG_H
00034 #include "config.h"
00035 #endif
00036
00037 #include <stdlib.h>
00038 #include <stdio.h>
00039 #include <unistd.h>
00040 #include <string.h>
00041 #include <sys/types.h>
00042 #include <sys/stat.h>
00043 #include <fcntl.h>
00044 #include <ctype.h>
00045 #include "xine_demux_sputext.h"
00046
00047 #define LOG_MODULE "demux_sputext"
00048 #define LOG_VERBOSE
00049
00050
00051
00052
00053 #define ERR (void *)-1
00054 #define LINE_LEN 1000
00055 #define LINE_LEN_QUOT "1000"
00056
00057
00058
00059
00060
00061 #define FORMAT_UNKNOWN -1
00062 #define FORMAT_MICRODVD 0
00063 #define FORMAT_SUBRIP 1
00064 #define FORMAT_SUBVIEWER 2
00065 #define FORMAT_SAMI 3
00066 #define FORMAT_VPLAYER 4
00067 #define FORMAT_RT 5
00068 #define FORMAT_SSA 6
00069 #define FORMAT_PJS 7
00070 #define FORMAT_MPSUB 8
00071 #define FORMAT_AQTITLE 9
00072 #define FORMAT_JACOBSUB 10
00073 #define FORMAT_SUBVIEWER2 11
00074 #define FORMAT_SUBRIP09 12
00075 #define FORMAT_MPL2 13
00076
00077 static int eol(char p) {
00078 return (p=='\r' || p=='\n' || p=='\0');
00079 }
00080
00081 static inline void trail_space(char *s) {
00082 int i;
00083 while (isspace(*s)) {
00084 char *copy = s;
00085 do {
00086 copy[0] = copy[1];
00087 copy++;
00088 } while(*copy);
00089 }
00090 i = strlen(s) - 1;
00091 while (i > 0 && isspace(s[i]))
00092 s[i--] = '\0';
00093 }
00094
00095
00096
00097
00098 static char *read_line_from_input(demux_sputext_t *this, char *line, off_t len) {
00099 off_t nread = 0;
00100 char *s;
00101 int linelen;
00102
00103 if ((len - this->buflen) > 512) {
00104 if((nread = fread(
00105 &this->buf[this->buflen], 1,
00106 len - this->buflen, this->file_ptr)) < 0) {
00107 printf("read failed.\n");
00108 return NULL;
00109 }
00110 }
00111
00112 this->buflen += nread;
00113 this->buf[this->buflen] = '\0';
00114
00115 s = strchr(this->buf, '\n');
00116
00117 if (line && (s || this->buflen)) {
00118
00119 linelen = s ? (s - this->buf) + 1 : this->buflen;
00120
00121 memcpy(line, this->buf, linelen);
00122 line[linelen] = '\0';
00123
00124 memmove(this->buf, &this->buf[linelen], SUB_BUFSIZE - linelen);
00125 this->buflen -= linelen;
00126
00127 return line;
00128 }
00129
00130 return NULL;
00131 }
00132
00133
00134 static subtitle_t *sub_read_line_sami(demux_sputext_t *this, subtitle_t *current) {
00135
00136 static char line[LINE_LEN + 1];
00137 static char *s = NULL;
00138 char text[LINE_LEN + 1], *p, *q;
00139 int state;
00140
00141 p = NULL;
00142 current->lines = current->start = 0;
00143 current->end = -1;
00144 state = 0;
00145
00146
00147 if (!s)
00148 if (!(s = read_line_from_input(this, line, LINE_LEN))) return 0;
00149
00150 do {
00151 switch (state) {
00152
00153 case 0:
00154 s = strstr (s, "Start=");
00155 if (s) {
00156 current->start = strtol (s + 6, &s, 0) / 10;
00157 state = 1; continue;
00158 }
00159 break;
00160
00161 case 1:
00162 if ((s = strstr (s, "<P"))) { s += 2; state = 2; continue; }
00163 break;
00164
00165 case 2:
00166 if ((s = strchr (s, '>'))) { s++; state = 3; p = text; continue; }
00167 break;
00168
00169 case 3:
00170 if (*s == '\0') { break; }
00171 else if (*s == '<') { state = 4; }
00172 else if (!strncasecmp (s, " ", 6)) { *p++ = ' '; s += 6; }
00173 else if (*s == '\r') { s++; }
00174 else if (!strncasecmp (s, "<br>", 4) || *s == '\n') {
00175 *p = '\0'; p = text; trail_space (text);
00176 if (text[0] != '\0')
00177 current->text[current->lines++] = strdup (text);
00178 if (*s == '\n') s++; else s += 4;
00179 }
00180 else *p++ = *s++;
00181 continue;
00182
00183 case 4:
00184 q = strstr (s, "Start=");
00185 if (q) {
00186 current->end = strtol (q + 6, &q, 0) / 10 - 1;
00187 *p = '\0'; trail_space (text);
00188 if (text[0] != '\0')
00189 current->text[current->lines++] = strdup (text);
00190 if (current->lines > 0) { state = 99; break; }
00191 state = 0; continue;
00192 }
00193 s = strchr (s, '>');
00194 if (s) { s++; state = 3; continue; }
00195 break;
00196 }
00197
00198
00199 if (state != 99 && !(s = read_line_from_input (this, line, LINE_LEN)))
00200 return 0;
00201
00202 } while (state != 99);
00203
00204 return current;
00205 }
00206
00207
00208 static char *sub_readtext(char *source, char **dest) {
00209 int len=0;
00210 char *p=source;
00211
00212 while ( !eol(*p) && *p!= '|' ) {
00213 p++,len++;
00214 }
00215
00216 if (!dest)
00217 return ERR;
00218
00219 *dest= (char *)malloc (len+1);
00220 if (!(*dest))
00221 return ERR;
00222
00223 strncpy(*dest, source, len);
00224 (*dest)[len]=0;
00225
00226 while (*p=='\r' || *p=='\n' || *p=='|')
00227 p++;
00228
00229 if (*p) return p;
00230 else return NULL;
00231 }
00232
00233 static subtitle_t *sub_read_line_microdvd(demux_sputext_t *this, subtitle_t *current) {
00234
00235 char line[LINE_LEN + 1];
00236 char line2[LINE_LEN + 1];
00237 char *p, *next;
00238 int i;
00239
00240 memset (current, 0, sizeof(subtitle_t));
00241
00242 current->end=-1;
00243 do {
00244 if (!read_line_from_input (this, line, LINE_LEN)) return NULL;
00245 } while ((sscanf (line, "{%ld}{}%" LINE_LEN_QUOT "[^\r\n]", &(current->start), line2) !=2) &&
00246 (sscanf (line, "{%ld}{%ld}%" LINE_LEN_QUOT "[^\r\n]", &(current->start), &(current->end),line2) !=3)
00247 );
00248
00249 p=line2;
00250
00251 next=p, i=0;
00252 while ((next =sub_readtext (next, &(current->text[i])))) {
00253 if (current->text[i]==ERR) return ERR;
00254 i++;
00255 if (i>=SUB_MAX_TEXT) {
00256 printf ("Too many lines in a subtitle\n");
00257 current->lines=i;
00258 return current;
00259 }
00260 }
00261 current->lines= ++i;
00262
00263 return current;
00264 }
00265
00266 static subtitle_t *sub_read_line_subviewer(demux_sputext_t *this, subtitle_t *current) {
00267
00268 char line[LINE_LEN + 1];
00269 int a1,a2,a3,a4,b1,b2,b3,b4;
00270 char *p=NULL, *q=NULL;
00271 int len;
00272
00273 memset (current, 0, sizeof(subtitle_t));
00274
00275 while (1) {
00276 if (!read_line_from_input(this, line, LINE_LEN)) return NULL;
00277 if (sscanf (line, "%d:%d:%d.%d,%d:%d:%d.%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4) < 8) {
00278 if (sscanf (line, "%d:%d:%d,%d,%d:%d:%d,%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4) < 8)
00279 continue;
00280 }
00281 current->start = a1*360000+a2*6000+a3*100+a4;
00282 current->end = b1*360000+b2*6000+b3*100+b4;
00283
00284 if (!read_line_from_input(this, line, LINE_LEN))
00285 return NULL;
00286
00287 p=q=line;
00288 for (current->lines=1; current->lines <= SUB_MAX_TEXT; current->lines++) {
00289 for (q=p,len=0; *p && *p!='\r' && *p!='\n' && *p!='|' && strncasecmp(p,"[br]",4); p++,len++);
00290 current->text[current->lines-1]=(char *)malloc (len+1);
00291 if (!current->text[current->lines-1]) return ERR;
00292 strncpy (current->text[current->lines-1], q, len);
00293 current->text[current->lines-1][len]='\0';
00294 if (!*p || *p=='\r' || *p=='\n') break;
00295 if (*p=='[') while (*p++!=']');
00296 if (*p=='|') p++;
00297 }
00298 if (current->lines > SUB_MAX_TEXT) current->lines = SUB_MAX_TEXT;
00299 break;
00300 }
00301 return current;
00302 }
00303
00304 static subtitle_t *sub_read_line_subrip(demux_sputext_t *this,subtitle_t *current) {
00305 char line[LINE_LEN + 1];
00306 int a1,a2,a3,a4,b1,b2,b3,b4;
00307 int i,end_sub;
00308
00309 memset(current,0,sizeof(subtitle_t));
00310 do {
00311 if(!read_line_from_input(this,line,LINE_LEN))
00312 return NULL;
00313 i = sscanf(line,"%d:%d:%d%*[,.]%d --> %d:%d:%d%*[,.]%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4);
00314 } while(i < 8);
00315 current->start = a1*360000+a2*6000+a3*100+a4/10;
00316 current->end = b1*360000+b2*6000+b3*100+b4/10;
00317 i=0;
00318 end_sub=0;
00319 do {
00320 char *p;
00321 char temp_line[SUB_BUFSIZE];
00322 int temp_index;
00323 temp_line[SUB_BUFSIZE-1]='\0';
00324 if(!read_line_from_input(this,line,LINE_LEN)) {
00325 if(i)
00326 break;
00327 else
00328 return NULL;
00329 }
00330 for(temp_index=0,p=line;*p!='\0' && !end_sub && temp_index<SUB_BUFSIZE && i<SUB_MAX_TEXT;p++) {
00331 switch(*p) {
00332 case '\\':
00333 if(*(p+1)=='N' || *(p+1)=='n') {
00334 temp_line[temp_index++]='\0';
00335 p++;
00336 } else
00337 temp_line[temp_index++]=*p;
00338 break;
00339 case '{':
00340 #if 0
00341 if(!strncmp(p,"{\\i1}",5) && temp_index+3<SUB_BUFSIZE) {
00342 temp_line[temp_index++]='<';
00343 temp_line[temp_index++]='i';
00344 temp_line[temp_index++]='>';
00345 #else
00346 if(!strncmp(p,"{\\i1}",5)) {
00347 #endif
00348 p+=4;
00349 }
00350 #if 0
00351 else if(!strncmp(p,"{\\i0}",5) && temp_index+4<SUB_BUFSIZE) {
00352 temp_line[temp_index++]='<';
00353 temp_line[temp_index++]='/';
00354 temp_line[temp_index++]='i';
00355 temp_line[temp_index++]='>';
00356 #else
00357 else if(!strncmp(p,"{\\i0}",5)) {
00358 #endif
00359 p+=4;
00360 }
00361 else
00362 temp_line[temp_index++]=*p;
00363 break;
00364 case '\r':
00365 break;
00366 case '\n':
00367 temp_line[temp_index++]='\0';
00368 break;
00369 default:
00370 temp_line[temp_index++]=*p;
00371 break;
00372 }
00373 if(temp_index>0) {
00374 if(temp_index==SUB_BUFSIZE)
00375 printf("Too many characters in a subtitle line\n");
00376 if(temp_line[temp_index-1]=='\0' || temp_index==SUB_BUFSIZE) {
00377 if(temp_index>1) {
00378 current->text[i]=(char *)malloc(temp_index);
00379 if(!current->text[i])
00380 return ERR;
00381 strncpy(current->text[i],temp_line,temp_index);
00382 i++;
00383 temp_index=0;
00384 } else
00385 end_sub=1;
00386 }
00387 }
00388 }
00389 } while(i<SUB_MAX_TEXT && !end_sub);
00390 if(i>=SUB_MAX_TEXT)
00391 printf("Too many lines in a subtitle\n");
00392 current->lines=i;
00393 return current;
00394 }
00395
00396 static subtitle_t *sub_read_line_vplayer(demux_sputext_t *this,subtitle_t *current) {
00397 char line[LINE_LEN + 1];
00398 int a1,a2,a3,b1,b2,b3;
00399 char *p=NULL, *next, *p2;
00400 int i;
00401
00402 memset (current, 0, sizeof(subtitle_t));
00403
00404 while (!current->text[0]) {
00405 if( this->next_line[0] == '\0' ) {
00406 if( !read_line_from_input(this, line, LINE_LEN) ) return NULL;
00407 } else {
00408
00409 strncpy( line, this->next_line, LINE_LEN);
00410 line[LINE_LEN] = '\0';
00411 this->next_line[0] = '\0';
00412 }
00413
00414 if( ! read_line_from_input( this, this->next_line, LINE_LEN) ) {
00415 this->next_line[0] = '\0';
00416 return NULL;
00417 }
00418 if( (sscanf( line, "%d:%d:%d:", &a1, &a2, &a3) < 3) ||
00419 (sscanf( this->next_line, "%d:%d:%d:", &b1, &b2, &b3) < 3) )
00420 continue;
00421 current->start = a1*360000+a2*6000+a3*100;
00422 current->end = b1*360000+b2*6000+b3*100;
00423 if ((current->end - current->start) > LINE_LEN)
00424 current->end = current->start + LINE_LEN;
00425
00426 p=line;
00427
00428 for (i=0; i<3; i++){
00429 p2=strchr( p, ':');
00430 if( p2 == NULL ) break;
00431 p=p2+1;
00432 }
00433
00434 next=p;
00435 i=0;
00436 while( (next = sub_readtext( next, &(current->text[i]))) ) {
00437 if (current->text[i]==ERR)
00438 return ERR;
00439 i++;
00440 if (i>=SUB_MAX_TEXT) {
00441 printf("Too many lines in a subtitle\n");
00442 current->lines=i;
00443 return current;
00444 }
00445 }
00446 current->lines=++i;
00447 }
00448 return current;
00449 }
00450
00451 static subtitle_t *sub_read_line_rt(demux_sputext_t *this,subtitle_t *current) {
00452
00453
00454
00455
00456
00457 char line[LINE_LEN + 1];
00458 int a1,a2,a3,a4,b1,b2,b3,b4;
00459 char *p=NULL,*next=NULL;
00460 int i,len,plen;
00461
00462 memset (current, 0, sizeof(subtitle_t));
00463
00464 while (!current->text[0]) {
00465 if (!read_line_from_input(this, line, LINE_LEN)) return NULL;
00466
00467
00468
00469
00470 if ((len=sscanf (line, "<Time Begin=\"%d:%d:%d.%d\" End=\"%d:%d:%d.%d\"",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4)) < 8)
00471
00472 plen=a1=a2=a3=a4=b1=b2=b3=b4=0;
00473 if (
00474 ((len=sscanf (line, "<%*[tT]ime %*[bB]egin=\"%d:%d\" %*[Ee]nd=\"%d:%d\"%*[^<]<clear/>%n",&a2,&a3,&b2,&b3,&plen)) < 4) &&
00475 ((len=sscanf (line, "<%*[tT]ime %*[bB]egin=\"%d:%d\" %*[Ee]nd=\"%d:%d.%d\"%*[^<]<clear/>%n",&a2,&a3,&b2,&b3,&b4,&plen)) < 5) &&
00476
00477 ((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) &&
00478 ((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)
00479 )
00480 continue;
00481 current->start = a1*360000+a2*6000+a3*100+a4/10;
00482 current->end = b1*360000+b2*6000+b3*100+b4/10;
00483 p=line; p+=plen;i=0;
00484
00485 next = strstr(line,"<clear/>")+8;i=0;
00486 while ((next =sub_readtext (next, &(current->text[i])))) {
00487 if (current->text[i]==ERR)
00488 return ERR;
00489 i++;
00490 if (i>=SUB_MAX_TEXT) {
00491 printf("Too many lines in a subtitle\n");
00492 current->lines=i;
00493 return current;
00494 }
00495 }
00496 current->lines=i+1;
00497 }
00498 return current;
00499 }
00500
00501 static subtitle_t *sub_read_line_ssa(demux_sputext_t *this,subtitle_t *current) {
00502 int comma;
00503 static int max_comma = 32;
00504
00505
00506 int hour1, min1, sec1, hunsec1, hour2, min2, sec2, hunsec2, nothing;
00507 int num;
00508 char line[LINE_LEN + 1], line3[LINE_LEN + 1], *line2;
00509 char *tmp;
00510
00511 do {
00512 if (!read_line_from_input(this, line, LINE_LEN)) return NULL;
00513 } while (sscanf (line, "Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d,"
00514 "%[^\n\r]", ¬hing,
00515 &hour1, &min1, &sec1, &hunsec1,
00516 &hour2, &min2, &sec2, &hunsec2,
00517 line3) < 9
00518 &&
00519 sscanf (line, "Dialogue: %d,%d:%d:%d.%d,%d:%d:%d.%d,"
00520 "%[^\n\r]", ¬hing,
00521 &hour1, &min1, &sec1, &hunsec1,
00522 &hour2, &min2, &sec2, &hunsec2,
00523 line3) < 9 );
00524
00525 line2=strchr(line3, ',');
00526
00527 for (comma = 4; comma < max_comma; comma ++)
00528 {
00529 tmp = line2;
00530 if(!(tmp=strchr(++tmp, ','))) break;
00531 if(*(++tmp) == ' ') break;
00532
00533 line2 = tmp;
00534 }
00535
00536 if(comma < max_comma)max_comma = comma;
00537
00538 if(*line2 == ',') line2++;
00539
00540 current->lines=0;num=0;
00541 current->start = 360000*hour1 + 6000*min1 + 100*sec1 + hunsec1;
00542 current->end = 360000*hour2 + 6000*min2 + 100*sec2 + hunsec2;
00543
00544 while (((tmp=strstr(line2, "\\n")) != NULL) || ((tmp=strstr(line2, "\\N")) != NULL) ){
00545 current->text[num]=(char *)malloc(tmp-line2+1);
00546 strncpy (current->text[num], line2, tmp-line2);
00547 current->text[num][tmp-line2]='\0';
00548 line2=tmp+2;
00549 num++;
00550 current->lines++;
00551 if (current->lines >= SUB_MAX_TEXT) return current;
00552 }
00553
00554 current->text[num]=strdup(line2);
00555 current->lines++;
00556
00557 return current;
00558 }
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 static subtitle_t *sub_read_line_pjs (demux_sputext_t *this, subtitle_t *current) {
00572 char line[LINE_LEN + 1];
00573 char text[LINE_LEN + 1];
00574 char *s, *d;
00575
00576 memset (current, 0, sizeof(subtitle_t));
00577
00578 if (!read_line_from_input(this, line, LINE_LEN))
00579 return NULL;
00580 for (s = line; *s && isspace(*s); s++);
00581 if (*s == 0)
00582 return NULL;
00583 if (sscanf (line, "%ld,%ld,", &(current->start),
00584 &(current->end)) <2)
00585 return ERR;
00586
00587 current->start *= 10;
00588 current->end *= 10;
00589
00590
00591 for (; *s; s++) if (*s==',') break;
00592 if (*s) {
00593 for (s++; *s; s++) if (*s==',') break;
00594 if (*s) s++;
00595 }
00596 if (*s!='"') {
00597 return ERR;
00598 }
00599
00600 for (s++, d=text; *s && *s!='"'; s++, d++)
00601 *d=*s;
00602 *d=0;
00603 current->text[0] = strdup(text);
00604 current->lines = 1;
00605
00606 return current;
00607 }
00608
00609 static subtitle_t *sub_read_line_mpsub (demux_sputext_t *this, subtitle_t *current) {
00610 char line[LINE_LEN + 1];
00611 float a,b;
00612 int num=0;
00613 char *p, *q;
00614
00615 do {
00616 if (!read_line_from_input(this, line, LINE_LEN))
00617 return NULL;
00618 } while (sscanf (line, "%f %f", &a, &b) !=2);
00619
00620 this->mpsub_position += (a*100.0);
00621 current->start = (int) this->mpsub_position;
00622 this->mpsub_position += (b*100.0);
00623 current->end = (int) this->mpsub_position;
00624
00625 while (num < SUB_MAX_TEXT) {
00626 if (!read_line_from_input(this, line, LINE_LEN))
00627 return NULL;
00628
00629 p=line;
00630 while (isspace(*p))
00631 p++;
00632
00633 if (eol(*p) && num > 0)
00634 return current;
00635
00636 if (eol(*p))
00637 return NULL;
00638
00639 for (q=p; !eol(*q); q++);
00640 *q='\0';
00641 if (strlen(p)) {
00642 current->text[num]=strdup(p);
00643 printf(">%s<\n",p);
00644 current->lines = ++num;
00645 } else {
00646 if (num)
00647 return current;
00648 else
00649 return NULL;
00650 }
00651 }
00652
00653 return NULL;
00654 }
00655
00656 static subtitle_t *sub_read_line_aqt (demux_sputext_t *this, subtitle_t *current) {
00657 char line[LINE_LEN + 1];
00658
00659 memset (current, 0, sizeof(subtitle_t));
00660
00661 while (1) {
00662
00663 if (!read_line_from_input(this, line, LINE_LEN))
00664 return NULL;
00665 if (!(sscanf (line, "-->> %ld", &(current->start)) <1))
00666 break;
00667 }
00668
00669 if (!read_line_from_input(this, line, LINE_LEN))
00670 return NULL;
00671
00672 sub_readtext((char *) &line,¤t->text[0]);
00673 current->lines = 1;
00674 current->end = -1;
00675
00676 if (!read_line_from_input(this, line, LINE_LEN))
00677 return current;;
00678
00679 sub_readtext((char *) &line,¤t->text[1]);
00680 current->lines = 2;
00681
00682 if ((current->text[0][0]==0) && (current->text[1][0]==0)) {
00683 return NULL;
00684 }
00685
00686 return current;
00687 }
00688
00689 static subtitle_t *sub_read_line_jacobsub(demux_sputext_t *this, subtitle_t *current) {
00690 char line1[LINE_LEN], line2[LINE_LEN], directive[LINE_LEN], *p, *q;
00691 unsigned a1, a2, a3, a4, b1, b2, b3, b4, comment = 0;
00692 static unsigned jacoTimeres = 30;
00693 static int jacoShift = 0;
00694
00695 memset(current, 0, sizeof(subtitle_t));
00696 memset(line1, 0, LINE_LEN);
00697 memset(line2, 0, LINE_LEN);
00698 memset(directive, 0, LINE_LEN);
00699 while (!current->text[0]) {
00700 if (!read_line_from_input(this, line1, LINE_LEN)) {
00701 return NULL;
00702 }
00703 if (sscanf
00704 (line1, "%u:%u:%u.%u %u:%u:%u.%u %" LINE_LEN_QUOT "[^\n\r]", &a1, &a2, &a3, &a4,
00705 &b1, &b2, &b3, &b4, line2) < 9) {
00706 if (sscanf(line1, "@%u @%u %" LINE_LEN_QUOT "[^\n\r]", &a4, &b4, line2) < 3) {
00707 if (line1[0] == '#') {
00708 int hours = 0, minutes = 0, seconds, delta, inverter =
00709 1;
00710 unsigned units = jacoShift;
00711 switch (toupper(line1[1])) {
00712 case 'S':
00713 if (isalpha(line1[2])) {
00714 delta = 6;
00715 } else {
00716 delta = 2;
00717 }
00718 if (sscanf(&line1[delta], "%d", &hours)) {
00719 if (hours < 0) {
00720 hours *= -1;
00721 inverter = -1;
00722 }
00723 if (sscanf(&line1[delta], "%*d:%d", &minutes)) {
00724 if (sscanf
00725 (&line1[delta], "%*d:%*d:%d",
00726 &seconds)) {
00727 sscanf(&line1[delta], "%*d:%*d:%*d.%d",
00728 &units);
00729 } else {
00730 hours = 0;
00731 sscanf(&line1[delta], "%d:%d.%d",
00732 &minutes, &seconds, &units);
00733 minutes *= inverter;
00734 }
00735 } else {
00736 hours = minutes = 0;
00737 sscanf(&line1[delta], "%d.%d", &seconds,
00738 &units);
00739 seconds *= inverter;
00740 }
00741 jacoShift =
00742 ((hours * 3600 + minutes * 60 +
00743 seconds) * jacoTimeres +
00744 units) * inverter;
00745 }
00746 break;
00747 case 'T':
00748 if (isalpha(line1[2])) {
00749 delta = 8;
00750 } else {
00751 delta = 2;
00752 }
00753 sscanf(&line1[delta], "%u", &jacoTimeres);
00754 break;
00755 }
00756 }
00757 continue;
00758 } else {
00759 current->start =
00760 (unsigned long) ((a4 + jacoShift) * 100.0 /
00761 jacoTimeres);
00762 current->end =
00763 (unsigned long) ((b4 + jacoShift) * 100.0 /
00764 jacoTimeres);
00765 }
00766 } else {
00767 current->start =
00768 (unsigned
00769 long) (((a1 * 3600 + a2 * 60 + a3) * jacoTimeres + a4 +
00770 jacoShift) * 100.0 / jacoTimeres);
00771 current->end =
00772 (unsigned
00773 long) (((b1 * 3600 + b2 * 60 + b3) * jacoTimeres + b4 +
00774 jacoShift) * 100.0 / jacoTimeres);
00775 }
00776 current->lines = 0;
00777 p = line2;
00778 while ((*p == ' ') || (*p == '\t')) {
00779 ++p;
00780 }
00781 if (isalpha(*p)||*p == '[') {
00782 int cont, jLength;
00783
00784 if (sscanf(p, "%s %" LINE_LEN_QUOT "[^\n\r]", directive, line1) < 2)
00785 return ERR;
00786 jLength = strlen(directive);
00787 for (cont = 0; cont < jLength; ++cont) {
00788 if (isalpha(*(directive + cont)))
00789 *(directive + cont) = toupper(*(directive + cont));
00790 }
00791 if ((strstr(directive, "RDB") != NULL)
00792 || (strstr(directive, "RDC") != NULL)
00793 || (strstr(directive, "RLB") != NULL)
00794 || (strstr(directive, "RLG") != NULL)) {
00795 continue;
00796 }
00797
00798 #if 0
00799 if (strstr(directive, "JL") != NULL) {
00800 current->alignment = SUB_ALIGNMENT_HLEFT;
00801 } else if (strstr(directive, "JR") != NULL) {
00802 current->alignment = SUB_ALIGNMENT_HRIGHT;
00803 } else {
00804 current->alignment = SUB_ALIGNMENT_HCENTER;
00805 }
00806 #endif
00807 strcpy(line2, line1);
00808 p = line2;
00809 }
00810 for (q = line1; (!eol(*p)) && (current->lines < SUB_MAX_TEXT); ++p) {
00811 switch (*p) {
00812 case '{':
00813 comment++;
00814 break;
00815 case '}':
00816 if (comment) {
00817 --comment;
00818
00819 if ((*(p + 1)) == ' ')
00820 p++;
00821 }
00822 break;
00823 case '~':
00824 if (!comment) {
00825 *q = ' ';
00826 ++q;
00827 }
00828 break;
00829 case ' ':
00830 case '\t':
00831 if ((*(p + 1) == ' ') || (*(p + 1) == '\t'))
00832 break;
00833 if (!comment) {
00834 *q = ' ';
00835 ++q;
00836 }
00837 break;
00838 case '\\':
00839 if (*(p + 1) == 'n') {
00840 *q = '\0';
00841 q = line1;
00842 current->text[current->lines++] = strdup(line1);
00843 ++p;
00844 break;
00845 }
00846 if ((toupper(*(p + 1)) == 'C')
00847 || (toupper(*(p + 1)) == 'F')) {
00848 ++p,++p;
00849 break;
00850 }
00851 if ((*(p + 1) == 'B') || (*(p + 1) == 'b') ||
00852
00853 (*(p + 1) == 'D') ||
00854 (*(p + 1) == 'I') || (*(p + 1) == 'i') ||
00855 (*(p + 1) == 'N') ||
00856
00857 (*(p + 1) == 'T') ||
00858 (*(p + 1) == 'U') || (*(p + 1) == 'u')) {
00859 ++p;
00860 break;
00861 }
00862 if ((*(p + 1) == '\\') ||
00863 (*(p + 1) == '~') || (*(p + 1) == '{')) {
00864 ++p;
00865 } else if (eol(*(p + 1))) {
00866 if (!read_line_from_input(this, directive, LINE_LEN))
00867 return NULL;
00868 trail_space(directive);
00869 strncat(line2, directive,
00870 (LINE_LEN > 511) ? LINE_LEN : 511);
00871 break;
00872 }
00873 default:
00874 if (!comment) {
00875 *q = *p;
00876 ++q;
00877 }
00878 }
00879 }
00880 *q = '\0';
00881 current->text[current->lines] = strdup(line1);
00882 }
00883 current->lines++;
00884 return current;
00885 }
00886
00887 static subtitle_t *sub_read_line_subviewer2(demux_sputext_t *this, subtitle_t *current) {
00888 char line[LINE_LEN+1];
00889 int a1,a2,a3,a4;
00890 char *p=NULL;
00891 int i,len;
00892
00893 while (!current->text[0]) {
00894 if (!read_line_from_input(this, line, LINE_LEN)) return NULL;
00895 if (line[0]!='{')
00896 continue;
00897 if ((len=sscanf (line, "{T %d:%d:%d:%d",&a1,&a2,&a3,&a4)) < 4)
00898 continue;
00899 current->start = a1*360000+a2*6000+a3*100+a4/10;
00900 for (i=0; i<SUB_MAX_TEXT;) {
00901 if (!read_line_from_input(this, line, LINE_LEN)) break;
00902 if (line[0]=='}') break;
00903 len=0;
00904 for (p=line; *p!='\n' && *p!='\r' && *p; ++p,++len);
00905 if (len) {
00906 current->text[i]=(char *)malloc (len+1);
00907 if (!current->text[i]) return ERR;
00908 strncpy (current->text[i], line, len); current->text[i][len]='\0';
00909 ++i;
00910 } else {
00911 break;
00912 }
00913 }
00914 current->lines=i;
00915 }
00916 return current;
00917 }
00918
00919 static subtitle_t *sub_read_line_subrip09 (demux_sputext_t *this, subtitle_t *current) {
00920 char line[LINE_LEN + 1];
00921 char *next;
00922 int h, m, s;
00923 int i;
00924
00925 memset (current, 0, sizeof(subtitle_t));
00926
00927 do {
00928 if (!read_line_from_input (this, line, LINE_LEN)) return NULL;
00929 } while (sscanf (line, "[%d:%d:%d]", &h, &m, &s) != 3);
00930
00931 if (!read_line_from_input (this, line, LINE_LEN)) return NULL;
00932
00933 current->start = 360000 * h + 6000 * m + 100 * s;
00934 current->end = -1;
00935
00936 next=line;
00937 i=0;
00938 while ((next = sub_readtext (next, &(current->text[i])))) {
00939 if (current->text[i]==ERR) return ERR;
00940 i++;
00941 if (i>=SUB_MAX_TEXT) {
00942 printf("Too many lines in a subtitle\n");
00943 current->lines=i;
00944 return current;
00945 }
00946 }
00947 current->lines= ++i;
00948
00949 return current;
00950 }
00951
00952
00953
00954
00955
00956 static subtitle_t *sub_read_line_mpl2(demux_sputext_t *this, subtitle_t *current) {
00957 char line[LINE_LEN+1];
00958 char line2[LINE_LEN+1];
00959 char *p, *next;
00960 int i;
00961
00962 memset (current, 0, sizeof(subtitle_t));
00963 do {
00964 if (!read_line_from_input (this, line, LINE_LEN)) return NULL;
00965 } while ((sscanf (line,
00966 "[%ld][%ld]%[^\r\n]",
00967 &(current->start), &(current->end), line2) < 3));
00968 current->start *= 10;
00969 current->end *= 10;
00970 p=line2;
00971
00972 next=p, i=0;
00973 while ((next = sub_readtext (next, &(current->text[i])))) {
00974 if (current->text[i] == ERR) {return ERR;}
00975 i++;
00976 if (i >= SUB_MAX_TEXT) {
00977 printf("Too many lines in a subtitle\n");
00978 current->lines = i;
00979 return current;
00980 }
00981 }
00982 current->lines= ++i;
00983
00984 return current;
00985 }
00986
00987
00988 static int sub_autodetect (demux_sputext_t *this) {
00989
00990 char line[LINE_LEN + 1];
00991 int i, j=0;
00992 char p;
00993
00994 while (j < 100) {
00995 j++;
00996 if (!read_line_from_input(this, line, LINE_LEN))
00997 return FORMAT_UNKNOWN;
00998
00999 if ((sscanf (line, "{%d}{}", &i)==1) ||
01000 (sscanf (line, "{%d}{%d}", &i, &i)==2)) {
01001 this->uses_time=0;
01002 return FORMAT_MICRODVD;
01003 }
01004
01005 if (sscanf (line, "%d:%d:%d%*[,.]%d --> %d:%d:%d%*[,.]%d", &i, &i, &i, &i, &i, &i, &i, &i)==8) {
01006 this->uses_time=1;
01007 return FORMAT_SUBRIP;
01008 }
01009
01010 if (sscanf (line, "%d:%d:%d.%d,%d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i)==8){
01011 this->uses_time=1;
01012 return FORMAT_SUBVIEWER;
01013 }
01014
01015 if (sscanf (line, "%d:%d:%d,%d,%d:%d:%d,%d", &i, &i, &i, &i, &i, &i, &i, &i)==8){
01016 this->uses_time=1;
01017 return FORMAT_SUBVIEWER;
01018 }
01019
01020 if (strstr (line, "<SAMI>")) {
01021 this->uses_time=1;
01022 return FORMAT_SAMI;
01023 }
01024 if (sscanf (line, "%d:%d:%d:", &i, &i, &i )==3) {
01025 this->uses_time=1;
01026 return FORMAT_VPLAYER;
01027 }
01028
01029
01030
01031
01032 if ( !strcasecmp(line, "<window") ) {
01033 this->uses_time=1;
01034 return FORMAT_RT;
01035 }
01036 if ((!memcmp(line, "Dialogue: Marked", 16)) || (!memcmp(line, "Dialogue: ", 10))) {
01037 this->uses_time=1;
01038 return FORMAT_SSA;
01039 }
01040 if (sscanf (line, "%d,%d,\"%c", &i, &i, (char *) &i) == 3) {
01041 this->uses_time=0;
01042 return FORMAT_PJS;
01043 }
01044 if (sscanf (line, "FORMAT=%d", &i) == 1) {
01045 this->uses_time=0;
01046 return FORMAT_MPSUB;
01047 }
01048 if (sscanf (line, "FORMAT=TIM%c", &p)==1 && p=='E') {
01049 this->uses_time=1;
01050 return FORMAT_MPSUB;
01051 }
01052 if (strstr (line, "-->>")) {
01053 this->uses_time=0;
01054 return FORMAT_AQTITLE;
01055 }
01056 if (sscanf(line, "@%d @%d", &i, &i) == 2 ||
01057 sscanf(line, "%d:%d:%d.%d %d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8) {
01058 this->uses_time = 1;
01059 return FORMAT_JACOBSUB;
01060 }
01061 if (sscanf(line, "{T %d:%d:%d:%d",&i, &i, &i, &i) == 4) {
01062 this->uses_time = 1;
01063 return FORMAT_SUBVIEWER2;
01064 }
01065 if (sscanf(line, "[%d:%d:%d]", &i, &i, &i) == 3) {
01066 this->uses_time = 1;
01067 return FORMAT_SUBRIP09;
01068 }
01069
01070 if (sscanf (line, "[%d][%d]", &i, &i) == 2) {
01071 this->uses_time = 1;
01072 return FORMAT_MPL2;
01073 }
01074 }
01075 return FORMAT_UNKNOWN;
01076 }
01077
01078 subtitle_t *sub_read_file (demux_sputext_t *this) {
01079
01080 int n_max;
01081 int timeout;
01082 subtitle_t *first;
01083 subtitle_t * (*func[])(demux_sputext_t *this,subtitle_t *dest)=
01084 {
01085 sub_read_line_microdvd,
01086 sub_read_line_subrip,
01087 sub_read_line_subviewer,
01088 sub_read_line_sami,
01089 sub_read_line_vplayer,
01090 sub_read_line_rt,
01091 sub_read_line_ssa,
01092 sub_read_line_pjs,
01093 sub_read_line_mpsub,
01094 sub_read_line_aqt,
01095 sub_read_line_jacobsub,
01096 sub_read_line_subviewer2,
01097 sub_read_line_subrip09,
01098 sub_read_line_mpl2,
01099 };
01100
01101
01102 if(fseek(this->file_ptr, 0, SEEK_SET) == -1) {
01103 printf("seek failed.\n");
01104 return NULL;
01105 }
01106 this->buflen = 0;
01107
01108 this->format=sub_autodetect (this);
01109 if (this->format==FORMAT_UNKNOWN) {
01110 return NULL;
01111 }
01112
01113
01114
01115
01116 if(fseek(this->file_ptr, 0, SEEK_SET) == -1) {
01117 printf("seek failed.\n");
01118 return NULL;
01119 }
01120 this->buflen = 0;
01121
01122 this->num=0;n_max=32;
01123 first = (subtitle_t *) malloc(n_max*sizeof(subtitle_t));
01124 if(!first) return NULL;
01125 timeout = MAX_TIMEOUT;
01126
01127 if (this->uses_time) timeout *= 100;
01128 else timeout *= 10;
01129
01130 while(1) {
01131 subtitle_t *sub;
01132
01133 if(this->num>=n_max){
01134 n_max+=16;
01135 first=realloc(first,n_max*sizeof(subtitle_t));
01136 }
01137
01138 sub = func[this->format] (this, &first[this->num]);
01139
01140 if (!sub)
01141 break;
01142
01143 if (sub==ERR)
01144 ++this->errs;
01145 else {
01146 if (this->num > 0 && first[this->num-1].end == -1) {
01147
01148 if (timeout > 0) {
01149
01150 if (timeout > sub->start - first[this->num-1].start) {
01151 first[this->num-1].end = sub->start;
01152 } else
01153 first[this->num-1].end = first[this->num-1].start + timeout;
01154 } else {
01155
01156 first[this->num-1].end = sub->start;
01157 }
01158 }
01159 ++this->num;
01160 }
01161 }
01162
01163 if (this->num > 0 && first[this->num-1].end == -1)
01164 if (timeout > 0) {
01165 first[this->num-1].end = first[this->num-1].start + timeout;
01166 }
01167
01168 #ifdef DEBUX_XINE_DEMUX_SPUTEXT
01169 {
01170 char buffer[1024];
01171
01172 sprintf(buffer, "Read %i subtitles", this->num);
01173
01174 if(this->errs)
01175 sprintf(buffer + strlen(buffer), ", %i bad line(s).\n", this->errs);
01176 else
01177 strcat(buffer, "\n");
01178
01179 printf("%s", buffer);
01180 }
01181 #endif
01182
01183 return first;
01184 }
01185