44 #include <sys/types.h>
50 #define LOG_MODULE "demux_sputext"
56 #define ERR ((void *)-1)
58 #define LINE_LEN_QUOT "1000"
65 return (
p==
'\r' ||
p==
'\n' ||
p==
'\0');
70 auto mark = str.find_last_of(
" \t\r\n");
71 if (
mark != std::string::npos)
73 mark = str.find_first_not_of(
" \t\r\n");
74 if (
mark != std::string::npos)
84 if ((line.capacity() - demuxstr->
buf.size()) > 512) {
85 off_t nread = line.capacity() - demuxstr->
buf.size();
88 printf(
"read failed.\n");
98 size_t index = demuxstr->
buf.find(
'\n');
99 if (index != std::string::npos) {
100 line.assign(demuxstr->
buf, 0, index+1);
101 demuxstr->
buf.erase(0, index+1);
104 if (!demuxstr->
buf.empty()) {
105 line = demuxstr->
buf;
106 demuxstr->
buf.clear();
116 static std::string s_line;
117 static char *s_s =
nullptr;
132 s_s = strcasestr (s_s,
"Start=");
134 current->start = strtol (s_s + 6, &s_s, 0) / 10;
140 if ((s_s = strcasestr (s_s,
"<P"))) { s_s += 2; state = 2;
continue; }
144 if ((s_s = strchr (s_s,
'>'))) { s_s++; state = 3; text.clear();
continue; }
148 if (*s_s ==
'\0') {
break; }
149 else if (strncasecmp (s_s,
" ", 6) == 0) { text +=
' '; s_s += 6; }
150 else if (*s_s ==
'\r') { s_s++; }
151 else if (strncasecmp (s_s,
"<br>", 4) == 0 || *s_s ==
'\n') {
156 if (*s_s ==
'\n') s_s++;
else s_s += 4;
158 else if (*s_s ==
'<') { state = 4; }
163 char *q = strcasestr (s_s,
"start=");
165 current->end = strtol (q + 6, &q, 0) / 10 - 1;
169 if (!
current->text.empty()) { state = 99;
break; }
172 s_s = strchr (s_s,
'>');
173 if (s_s) { s_s++; state = 3;
continue; }
181 }
while (state != 99);
201 if (source ==
nullptr)
207 while ( !
isEol(*
p) && *
p!=
'|' ) {
211 dest.assign(source, len);
213 while (*
p==
'\r' || *
p==
'\n' || *
p==
'|')
217 return (
char*)
nullptr;
222 std::string line; line.reserve(
LINE_LEN + 1);
223 std::string line2; line2.reserve(
LINE_LEN + 1);
228 }
while ((sscanf (line.c_str(),
"{%" SCNd64
"}{}%" LINE_LEN_QUOT "[^\r\n]", &(
current->start), line2.data()) !=2) &&
229 (sscanf (line.c_str(),
"{%" SCNd64
"}{%" SCNd64
"}%" LINE_LEN_QUOT "[^\r\n]", &(
current->start), &(
current->end),line2.data()) !=3)
232 char *next=line2.data();
246 int a1=0,a2=0,a3=0,a4=0,b1=0,b2=0,b3=0,b4=0;
250 if (sscanf (line.c_str(),
"%d:%d:%d.%d,%d:%d:%d.%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4) < 8) {
251 if (sscanf (line.c_str(),
"%d:%d:%d,%d,%d:%d:%d,%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4) < 8)
254 current->start = a1*360000+a2*6000+a3*100+a4;
255 current->end = b1*360000+b2*6000+b3*100+b4;
264 for (q=
p,len=0; *
p && *
p!=
'\r' && *
p!=
'\n' && *
p!=
'|' &&
265 (strncasecmp(
p,
"[br]",4) != 0);
p++,len++);
266 current->text.emplace_back(q, len);
267 if (!*
p || *
p==
'\r' || *
p==
'\n')
break;
268 if (*
p==
'[')
while (*
p++!=
']');
278 int a1=0,a2=0,a3=0,a4=0,b1=0,b2=0,b3=0,b4=0;
284 i = sscanf(line.c_str(),
"%d:%d:%d%*[,.]%d --> %d:%d:%d%*[,.]%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4);
286 current->start = a1*360000+a2*6000+a3*100+a4/10;
287 current->end = b1*360000+b2*6000+b3*100+b4/10;
288 bool end_sub =
false;
291 std::string temp_line;
295 for (
p=line.data(); *
p!=
'\0' && !end_sub;
p++) {
299 if(*(
p+1)==
'N' || *(
p+1)==
'n') {
308 if(strncmp(
p,
"{\\i1}",5) == 0) {
310 temp_line.append(
"<i>");
314 else if(strncmp(
p,
"{\\i0}",5) == 0) {
316 temp_line.append(
"</i>");
333 if (!temp_line.empty())
335 current->text.push_back(temp_line);
348 int a1=0,a2=0,a3=0,b1=0,b2=0,b3=0;
350 while (
current->text.empty()) {
364 if( (sscanf( line.c_str(),
"%d:%d:%d:", &a1, &a2, &a3) < 3) ||
365 (sscanf( demuxstr->
next_line.c_str(),
"%d:%d:%d:", &b1, &b2, &b3) < 3) )
367 current->start = a1*360000+a2*6000+a3*100;
368 current->end = b1*360000+b2*6000+b3*100;
374 for (
int i=0; i<3; i++){
375 char *
p2=strchr(
p,
':');
376 if(
p2 ==
nullptr )
break;
399 int a1=0,a2=0,a3=0,a4=0,b1=0,b2=0,b3=0,b4=0;
402 while (
current->text.empty()) {
408 if (sscanf (line.c_str(), R
"(<Time Begin="%d:%d:%d.%d" End="%d:%d:%d.%d")",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4) < 8)
410 plen=a1=a2=a3=a4=b1=b2=b3=b4=0;
412 (sscanf (line.c_str(), R
"(<%*[tT]ime %*[bB]egin="%d:%d" %*[Ee]nd="%d:%d"%*[^<]<clear/>%n)",&a2,&a3,&b2,&b3,&plen) < 4) &&
413 (sscanf (line.c_str(), R"(<%*[tT]ime %*[bB]egin="%d:%d" %*[Ee]nd="%d:%d.%d"%*[^<]<clear/>%n)",&a2,&a3,&b2,&b3,&b4,&plen) < 5) &&
415 (sscanf (line.c_str(), R
"(<%*[tT]ime %*[bB]egin="%d:%d.%d" %*[Ee]nd="%d:%d.%d"%*[^<]<clear/>%n)",&a2,&a3,&a4,&b2,&b3,&b4,&plen) < 6) &&
416 (sscanf (line.c_str(), R"(<%*[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)
419 current->start = a1*360000+a2*6000+a3*100+a4/10;
420 current->end = b1*360000+b2*6000+b3*100+b4/10;
422 size_t index = line.find(
"<clear/>");
423 char *next = (index != std::string::npos) ? &line[index+8] :
nullptr;
437 static int s_maxComma = 32;
450 std::string line3; line3.resize(
LINE_LEN);
455 }
while (sscanf (line.data(),
"Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d,"
457 &hour1, &min1, &sec1, &hunsec1,
458 &hour2, &min2, &sec2, &hunsec2,
461 sscanf (line.data(),
"Dialogue: %d,%d:%d:%d.%d,%d:%d:%d.%d,"
463 &hour1, &min1, &sec1, &hunsec1,
464 &hour2, &min2, &sec2, &hunsec2,
467 size_t index = line3.find(
',');
468 if (index == std::string::npos)
470 char *line2 = &line3[index];
472 for (comma = 4; comma < s_maxComma; comma ++)
475 if(!(
tmp=strchr(++
tmp,
',')))
break;
476 if(*(++
tmp) ==
' ')
break;
481 if(comma < s_maxComma)s_maxComma = comma;
483 if(*line2 ==
',') line2++;
485 current->start = 360000*hour1 + 6000*min1 + 100*sec1 + hunsec1;
486 current->end = 360000*hour2 + 6000*min2 + 100*sec2 + hunsec2;
488 while (((
tmp=strstr(line2,
"\\n")) !=
nullptr) || ((
tmp=strstr(line2,
"\\N")) !=
nullptr) ){
493 current->text.emplace_back(line2);
514 size_t mark = line.find_first_not_of(
" \t\r\n");
515 if (
mark != std::string::npos)
519 if (sscanf (line.data(),
"%" SCNd64
",%" SCNd64
",", &(
current->start),
527 auto start = line.find(
'\"');
528 if (start == std::string::npos)
530 auto end = line.find(
'\"', start + 1);
531 if (end == std::string::npos)
533 current->text.push_back(line.substr(start+1, end));
546 }
while (sscanf (line.c_str(),
"%f %f", &a, &b) !=2);
557 size_t mark = line.find_first_not_of(
" \t\r\n");
558 if (
mark != std::string::npos)
568 for (q=line.data(); !
isEol(*q); q++);
570 line.resize(strlen(line.c_str()));
591 if (!(sscanf (line.c_str(),
"-->> %" SCNd64, &(
current->start)) <1))
610 std::string directive; directive.resize(
LINE_LEN);
613 unsigned a1=0, a2=0, a3=0, a4=0, b1=0, b2=0, b3=0, b4=0;
614 unsigned comment = 0;
615 static uint32_t s_jacoTimeRes = 30;
616 static uint32_t s_jacoShift = 0;
618 while (
current->text.empty()) {
623 if (line1.size() >= 2) {
624 while ((line1[line1.size()-2] ==
'\\') && (line1[line1.size()-1] ==
'\n')) {
625 line1.resize(line1.size()-2);
628 size_t index = line2.find_first_not_of(
" \t\r\n");
629 if (index != std::string::npos)
630 line2.erase(0, index);
637 (line1.c_str(),
"%u:%u:%u.%u %u:%u:%u.%u %" LINE_LEN_QUOT "[^\n\r]", &a1, &a2, &a3, &a4,
638 &b1, &b2, &b3, &b4, line2.data()) < 9) {
639 if (sscanf(line1.data(),
"@%u @%u %" LINE_LEN_QUOT "[^\n\r]", &a4, &b4, line2.data()) < 3) {
640 if (line1[0] ==
'#') {
645 uint32_t units = s_jacoShift;
646 switch (toupper(line1[1])) {
648 if (isalpha(line1[2])) {
653 if (sscanf(&line1[delta],
"%d", &hours)) {
659 if (sscanf(&line1[delta],
"%*d:%d", &minutes)) {
661 (&line1[delta],
"%*d:%*d:%d",
663 sscanf(&line1[delta],
"%*d:%*d:%*d.%u",
667 sscanf(&line1[delta],
"%d:%d.%u",
668 &minutes, &seconds, &units);
673 sscanf(&line1[delta],
"%d.%u", &seconds,
678 ((hours * 3600 + minutes * 60 +
679 seconds) * s_jacoTimeRes +
684 if (isalpha(line1[2])) {
689 sscanf(&line1[delta],
"%u", &s_jacoTimeRes);
696 (
unsigned long) ((a4 + s_jacoShift) * 100.0 /
699 (
unsigned long) ((b4 + s_jacoShift) * 100.0 /
704 long) (((a1 * 3600 + a2 * 60 + a3) * s_jacoTimeRes + a4 +
705 s_jacoShift) * 100.0 / s_jacoTimeRes);
708 long) (((b1 * 3600 + b2 * 60 + b3) * s_jacoTimeRes + b4 +
709 s_jacoShift) * 100.0 / s_jacoTimeRes);
712 while ((*
p ==
' ') || (*
p ==
'\t')) {
715 if (isalpha(*
p)||*
p ==
'[') {
718 directive.resize(strlen(directive.c_str()));
719 std::transform(directive.begin(), directive.end(), directive.begin(),
720 [](
unsigned char c){ return std::toupper(c);});
721 if ( (directive.find(
"RDB") != std::string::npos)
722 || (directive.find(
"RDC") != std::string::npos)
723 || (directive.find(
"RLB") != std::string::npos)
724 || (directive.find(
"RLG") != std::string::npos)) {
729 if (directive.find(
"JL") != std::string::npos) {
730 current->alignment = SUB_ALIGNMENT_HLEFT;
731 }
else if (directive.find(
"JR") != std::string::npos) {
732 current->alignment = SUB_ALIGNMENT_HRIGHT;
734 current->alignment = SUB_ALIGNMENT_HCENTER;
740 for (q = line1.data(); (!
isEol(*
p)); ++
p) {
749 if ((*(
p + 1)) ==
' ')
761 if ((*(
p + 1) ==
' ') || (*(
p + 1) ==
'\t'))
769 if (*(
p + 1) ==
'n') {
772 current->text.push_back(line1);
776 if ((toupper(*(
p + 1)) ==
'C')
777 || (toupper(*(
p + 1)) ==
'F')) {
781 if ((*(
p + 1) ==
'B') || (*(
p + 1) ==
'b') ||
784 (*(
p + 1) ==
'I') || (*(
p + 1) ==
'i') ||
788 (*(
p + 1) ==
'U') || (*(
p + 1) ==
'u')) {
792 if ((*(
p + 1) ==
'\\') ||
793 (*(
p + 1) ==
'~') || (*(
p + 1) ==
'{')) {
795 }
else if (
isEol(*(
p + 1))) {
796 std::string tmpstr {};
801 size_t offset =
p - line2.data();
803 p = line2.data() + offset;
817 current->text.push_back(line1);
824 int a1=0,a2=0,a3=0,a4=0;
826 while (
current->text.empty()) {
830 if (sscanf (line.data(),
"{T %d:%d:%d:%d",&a1,&a2,&a3,&a4) < 4)
832 current->start = a1*360000+a2*6000+a3*100+a4/10;
835 if (line[0]==
'}')
break;
836 size_t len = line.find_first_of(
"\n\r");
839 current->text.push_back(line.substr(0, len));
853 }
while (sscanf (line.data(),
"[%d:%d:%d]", &h, &m, &s) != 3);
857 current->start = 360000 * h + 6000 * m + 100 * s;
860 char *next=line.data();
877 std::string line2; line2.resize(
LINE_LEN);
881 }
while ((sscanf (line.data(),
887 char *
p=line2.data();
912 std::transform(line.begin(), line.end(), line.begin(),
913 [](
unsigned char c){ return std::tolower(c);});
915 if ((sscanf (line.data(),
"{%d}{}", &i)==1) ||
916 (sscanf (line.data(),
"{%d}{%d}", &i, &i)==2)) {
921 if (sscanf (line.data(),
"%d:%d:%d%*[,.]%d --> %d:%d:%d%*[,.]%d", &i, &i, &i, &i, &i, &i, &i, &i)==8) {
926 if (sscanf (line.data(),
"%d:%d:%d.%d,%d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i)==8){
931 if (sscanf (line.data(),
"%d:%d:%d,%d,%d:%d:%d,%d", &i, &i, &i, &i, &i, &i, &i, &i)==8){
936 if (line.find(
"<sami>") != std::string::npos) {
945 std::string line2; line2.resize(
LINE_LEN);
946 if (sscanf (line.data(),
"%d:%d:%d:%" LINE_LEN_QUOT "[^\n\r]",
947 &i, &i, &i, line2.data() )==4) {
955 if (line.find(
"<window") != std::string::npos) {
959 if ((line.find(
"dialogue: marked") != std::string::npos) ||
960 (line.find(
"dialogue: ") != std::string::npos)) {
964 if (sscanf (line.data(),
"%d,%d,\"%c", &i, &i, (
char *) &i) == 3) {
968 if (sscanf (line.data(),
"format=%d", &i) == 1) {
972 if (sscanf (line.data(),
"format=tim%c", &
p)==1 &&
p==
'e') {
976 if (line.find(
"-->>") != std::string::npos) {
980 if (sscanf(line.data(),
"@%d @%d", &i, &i) == 2 ||
981 sscanf(line.data(),
"%d:%d:%d.%d %d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8) {
985 if (sscanf(line.data(),
"{t %d:%d:%d:%d",&i, &i, &i, &i) == 4) {
989 if (sscanf(line.data(),
"[%d:%d:%d]", &i, &i, &i) == 3) {
994 if (sscanf (line.data(),
"[%d][%d]", &i, &i) == 2) {
1005 const std::array<read_func_ptr, 14>
read_func
1027 demuxstr->
buf.clear();
1039 demuxstr->
buf.clear();
1057 demuxstr->subtitles.push_back(*sub);
1058 if (demuxstr->num > 0 && demuxstr->subtitles[demuxstr->num-1].end == -1) {
1060 if (
timeout > sub->
start - demuxstr->subtitles[demuxstr->num-1].start) {
1061 demuxstr->subtitles[demuxstr->num-1].end = sub->
start;
1063 demuxstr->subtitles[demuxstr->num-1].end = demuxstr->subtitles[demuxstr->num-1].start +
timeout;
1070 if (demuxstr->
num > 0 && demuxstr->
subtitles[demuxstr->
num-1].end == -1)
1075 #if DEBUG_XINE_DEMUX_SPUTEXT
1079 sprintf(buffer,
"Read %i subtitles", demuxstr->
num);
1082 sprintf(buffer + strlen(buffer),
", %i bad line(s).\n", demuxstr->
errs);
1084 strcat(buffer,
"\n");
1086 printf(
"%s", buffer);