43 #include <sys/types.h>
50 #define ERR ((void *)-1)
52 #define LINE_LEN_QUOT "1000" // NOLINT(cppcoreguidelines-macro-usage)
65 if (toupper((
unsigned char)*str) == toupper((
unsigned char)*pattern)) {
69 if (toupper((
unsigned char)str[i]) != toupper((
unsigned char)pattern[i]))
83 return (
p==
'\r' ||
p==
'\n' ||
p==
'\0');
88 auto mark = str.find_last_of(
" \t\r\n");
89 if (
mark != std::string::npos)
91 mark = str.find_first_not_of(
" \t\r\n");
92 if (
mark != std::string::npos)
102 if ((line.capacity() - demuxstr->
buf.size()) > 512) {
103 off_t nread = line.capacity() - demuxstr->
buf.size();
106 printf(
"read failed.\n");
116 size_t index = demuxstr->
buf.find(
'\n');
117 if (index != std::string::npos) {
118 line.assign(demuxstr->
buf, 0, index+1);
119 demuxstr->
buf.erase(0, index+1);
122 if (!demuxstr->
buf.empty()) {
123 line = demuxstr->
buf;
124 demuxstr->
buf.clear();
134 static std::string s_line;
135 static char *s_s =
nullptr;
152 current->start = strtol (s_s + 6, &s_s, 0) / 10;
158 if ((s_s =
strcasestr (s_s,
"<P"))) { s_s += 2; state = 2;
continue; }
162 if ((s_s = strchr (s_s,
'>'))) { s_s++; state = 3; text.clear();
continue; }
166 if (*s_s ==
'\0') {
break; }
167 else if (strncasecmp (s_s,
" ", 6) == 0) { text +=
' '; s_s += 6; }
168 else if (*s_s ==
'\r') { s_s++; }
169 else if (strncasecmp (s_s,
"<br>", 4) == 0 || *s_s ==
'\n') {
174 if (*s_s ==
'\n') s_s++;
else s_s += 4;
176 else if (*s_s ==
'<') { state = 4; }
183 current->end = strtol (q + 6, &q, 0) / 10 - 1;
187 if (!
current->text.empty()) { state = 99;
break; }
190 s_s = strchr (s_s,
'>');
191 if (s_s) { s_s++; state = 3;
continue; }
199 }
while (state != 99);
219 if (source ==
nullptr)
225 while ( !
isEol(*
p) && *
p!=
'|' ) {
229 dest.assign(source, len);
231 while (*
p==
'\r' || *
p==
'\n' || *
p==
'|')
235 return (
char*)
nullptr;
240 std::string line; line.reserve(
LINE_LEN + 1);
241 std::string line2; line2.reserve(
LINE_LEN + 1);
246 }
while ((sscanf (line.c_str(),
"{%" SCNd64
"}{}%" LINE_LEN_QUOT "[^\r\n]", &(
current->start), line2.data()) !=2) &&
247 (sscanf (line.c_str(),
"{%" SCNd64
"}{%" SCNd64
"}%" LINE_LEN_QUOT "[^\r\n]", &(
current->start), &(
current->end),line2.data()) !=3)
250 char *next=line2.data();
264 int a1=0,a2=0,a3=0,a4=0,b1=0,b2=0,b3=0,b4=0;
268 if (sscanf (line.c_str(),
"%d:%d:%d.%d,%d:%d:%d.%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4) < 8) {
269 if (sscanf (line.c_str(),
"%d:%d:%d,%d,%d:%d:%d,%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4) < 8)
272 current->start = a1*360000+a2*6000+a3*100+a4;
273 current->end = b1*360000+b2*6000+b3*100+b4;
282 for (q=
p,len=0; *
p && *
p!=
'\r' && *
p!=
'\n' && *
p!=
'|' &&
283 (strncasecmp(
p,
"[br]",4) != 0);
p++,len++);
284 current->text.emplace_back(q, len);
285 if (!*
p || *
p==
'\r' || *
p==
'\n')
break;
286 if (*
p==
'[')
while (*
p++!=
']');
296 int a1=0,a2=0,a3=0,a4=0,b1=0,b2=0,b3=0,b4=0;
302 i = sscanf(line.c_str(),
"%d:%d:%d%*[,.]%d --> %d:%d:%d%*[,.]%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4);
304 current->start = a1*360000+a2*6000+a3*100+a4/10;
305 current->end = b1*360000+b2*6000+b3*100+b4/10;
306 bool end_sub =
false;
309 std::string temp_line;
313 for (
p=line.data(); *
p!=
'\0' && !end_sub;
p++) {
317 if(*(
p+1)==
'N' || *(
p+1)==
'n') {
326 if(strncmp(
p,
"{\\i1}",5) == 0) {
328 temp_line.append(
"<i>");
332 else if(strncmp(
p,
"{\\i0}",5) == 0) {
334 temp_line.append(
"</i>");
351 if (!temp_line.empty())
353 current->text.push_back(temp_line);
366 int a1=0,a2=0,a3=0,b1=0,b2=0,b3=0;
368 while (
current->text.empty()) {
382 if( (sscanf( line.c_str(),
"%d:%d:%d:", &a1, &a2, &a3) < 3) ||
383 (sscanf( demuxstr->
next_line.c_str(),
"%d:%d:%d:", &b1, &b2, &b3) < 3) )
385 current->start = a1*360000+a2*6000+a3*100;
386 current->end = b1*360000+b2*6000+b3*100;
392 for (
int i=0; i<3; i++){
393 char *
p2=strchr(
p,
':');
394 if(
p2 ==
nullptr )
break;
417 int a1=0,a2=0,a3=0,a4=0,b1=0,b2=0,b3=0,b4=0;
420 while (
current->text.empty()) {
426 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)
428 plen=a1=a2=a3=a4=b1=b2=b3=b4=0;
430 (sscanf (line.c_str(), R
"(<%*[tT]ime %*[bB]egin="%d:%d" %*[Ee]nd="%d:%d"%*[^<]<clear/>%n)",&a2,&a3,&b2,&b3,&plen) < 4) &&
431 (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) &&
433 (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) &&
434 (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)
437 current->start = a1*360000+a2*6000+a3*100+a4/10;
438 current->end = b1*360000+b2*6000+b3*100+b4/10;
440 size_t index = line.find(
"<clear/>");
441 char *next = (index != std::string::npos) ? &line[index+8] :
nullptr;
455 static int s_maxComma = 32;
468 std::string line3; line3.resize(
LINE_LEN);
473 }
while (sscanf (line.data(),
"Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d,"
475 &hour1, &min1, &sec1, &hunsec1,
476 &hour2, &min2, &sec2, &hunsec2,
479 sscanf (line.data(),
"Dialogue: %d,%d:%d:%d.%d,%d:%d:%d.%d,"
481 &hour1, &min1, &sec1, &hunsec1,
482 &hour2, &min2, &sec2, &hunsec2,
485 size_t index = line3.find(
',');
486 if (index == std::string::npos)
488 char *line2 = &line3[index];
490 for (comma = 4; comma < s_maxComma; comma ++)
493 if(!(
tmp=strchr(++
tmp,
',')))
break;
494 if(*(++
tmp) ==
' ')
break;
499 if(comma < s_maxComma)s_maxComma = comma;
501 if(*line2 ==
',') line2++;
503 current->start = 360000*hour1 + 6000*min1 + 100*sec1 + hunsec1;
504 current->end = 360000*hour2 + 6000*min2 + 100*sec2 + hunsec2;
506 while (((
tmp=strstr(line2,
"\\n")) !=
nullptr) || ((
tmp=strstr(line2,
"\\N")) !=
nullptr) ){
511 current->text.emplace_back(line2);
532 size_t mark = line.find_first_not_of(
" \t\r\n");
533 if (
mark != std::string::npos)
537 if (sscanf (line.data(),
"%" SCNd64
",%" SCNd64
",", &(
current->start),
545 auto start = line.find(
'\"');
546 if (start == std::string::npos)
548 auto end = line.find(
'\"', start + 1);
549 if (end == std::string::npos)
551 current->text.push_back(line.substr(start+1, end));
564 }
while (sscanf (line.c_str(),
"%f %f", &a, &b) !=2);
575 size_t mark = line.find_first_not_of(
" \t\r\n");
576 if (
mark != std::string::npos)
586 for (q=line.data(); !
isEol(*q); q++);
588 line.resize(strlen(line.c_str()));
609 if (!(sscanf (line.c_str(),
"-->> %" SCNd64, &(
current->start)) <1))
628 std::string directive; directive.resize(
LINE_LEN);
631 unsigned a1=0, a2=0, a3=0, a4=0, b1=0, b2=0, b3=0, b4=0;
632 unsigned comment = 0;
633 static uint32_t s_jacoTimeRes = 30;
634 static uint32_t s_jacoShift = 0;
636 while (
current->text.empty()) {
641 if (line1.size() >= 2) {
642 while ((line1[line1.size()-2] ==
'\\') && (line1[line1.size()-1] ==
'\n')) {
643 line1.resize(line1.size()-2);
646 size_t index = line2.find_first_not_of(
" \t\r\n");
647 if (index != std::string::npos)
648 line2.erase(0, index);
655 (line1.c_str(),
"%u:%u:%u.%u %u:%u:%u.%u %" LINE_LEN_QUOT "[^\n\r]", &a1, &a2, &a3, &a4,
656 &b1, &b2, &b3, &b4, line2.data()) < 9) {
657 if (sscanf(line1.data(),
"@%u @%u %" LINE_LEN_QUOT "[^\n\r]", &a4, &b4, line2.data()) < 3) {
658 if (line1[0] ==
'#') {
663 uint32_t units = s_jacoShift;
664 switch (toupper(line1[1])) {
666 if (isalpha(line1[2])) {
671 if (sscanf(&line1[delta],
"%d", &hours)) {
677 if (sscanf(&line1[delta],
"%*d:%d", &minutes)) {
679 (&line1[delta],
"%*d:%*d:%d",
681 sscanf(&line1[delta],
"%*d:%*d:%*d.%u",
685 sscanf(&line1[delta],
"%d:%d.%u",
686 &minutes, &seconds, &units);
691 sscanf(&line1[delta],
"%d.%u", &seconds,
696 ((hours * 3600 + minutes * 60 +
697 seconds) * s_jacoTimeRes +
702 if (isalpha(line1[2])) {
707 sscanf(&line1[delta],
"%u", &s_jacoTimeRes);
714 (
unsigned long) ((a4 + s_jacoShift) * 100.0 /
717 (
unsigned long) ((b4 + s_jacoShift) * 100.0 /
722 long) (((a1 * 3600 + a2 * 60 + a3) * s_jacoTimeRes + a4 +
723 s_jacoShift) * 100.0 / s_jacoTimeRes);
726 long) (((b1 * 3600 + b2 * 60 + b3) * s_jacoTimeRes + b4 +
727 s_jacoShift) * 100.0 / s_jacoTimeRes);
730 while ((*
p ==
' ') || (*
p ==
'\t')) {
733 if (isalpha(*
p)||*
p ==
'[') {
736 directive.resize(strlen(directive.c_str()));
737 std::transform(directive.begin(), directive.end(), directive.begin(),
738 [](
unsigned char c){ return std::toupper(c);});
739 if ( (directive.find(
"RDB") != std::string::npos)
740 || (directive.find(
"RDC") != std::string::npos)
741 || (directive.find(
"RLB") != std::string::npos)
742 || (directive.find(
"RLG") != std::string::npos)) {
747 if (directive.find(
"JL") != std::string::npos) {
748 current->alignment = SUB_ALIGNMENT_HLEFT;
749 }
else if (directive.find(
"JR") != std::string::npos) {
750 current->alignment = SUB_ALIGNMENT_HRIGHT;
752 current->alignment = SUB_ALIGNMENT_HCENTER;
758 for (q = line1.data(); (!
isEol(*
p)); ++
p) {
767 if ((*(
p + 1)) ==
' ')
779 if ((*(
p + 1) ==
' ') || (*(
p + 1) ==
'\t'))
787 if (*(
p + 1) ==
'n') {
790 current->text.push_back(line1);
794 if ((toupper(*(
p + 1)) ==
'C')
795 || (toupper(*(
p + 1)) ==
'F')) {
799 if ((*(
p + 1) ==
'B') || (*(
p + 1) ==
'b') ||
802 (*(
p + 1) ==
'I') || (*(
p + 1) ==
'i') ||
806 (*(
p + 1) ==
'U') || (*(
p + 1) ==
'u')) {
810 if ((*(
p + 1) ==
'\\') ||
811 (*(
p + 1) ==
'~') || (*(
p + 1) ==
'{')) {
813 }
else if (
isEol(*(
p + 1))) {
814 std::string tmpstr {};
819 size_t offset =
p - line2.data();
821 p = line2.data() + offset;
835 current->text.push_back(line1);
842 int a1=0,a2=0,a3=0,a4=0;
844 while (
current->text.empty()) {
848 if (sscanf (line.data(),
"{T %d:%d:%d:%d",&a1,&a2,&a3,&a4) < 4)
850 current->start = a1*360000+a2*6000+a3*100+a4/10;
853 if (line[0]==
'}')
break;
854 size_t len = line.find_first_of(
"\n\r");
857 current->text.push_back(line.substr(0, len));
871 }
while (sscanf (line.data(),
"[%d:%d:%d]", &h, &m, &s) != 3);
875 current->start = 360000 * h + 6000 * m + 100 * s;
878 char *next=line.data();
895 std::string line2; line2.resize(
LINE_LEN);
899 }
while ((sscanf (line.data(),
905 char *
p=line2.data();
930 std::transform(line.begin(), line.end(), line.begin(),
931 [](
unsigned char c){ return std::tolower(c);});
933 if ((sscanf (line.data(),
"{%d}{}", &i)==1) ||
934 (sscanf (line.data(),
"{%d}{%d}", &i, &i)==2)) {
939 if (sscanf (line.data(),
"%d:%d:%d%*[,.]%d --> %d:%d:%d%*[,.]%d", &i, &i, &i, &i, &i, &i, &i, &i)==8) {
944 if (sscanf (line.data(),
"%d:%d:%d.%d,%d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i)==8){
949 if (sscanf (line.data(),
"%d:%d:%d,%d,%d:%d:%d,%d", &i, &i, &i, &i, &i, &i, &i, &i)==8){
954 if (line.find(
"<sami>") != std::string::npos) {
963 std::string line2; line2.resize(
LINE_LEN);
964 if (sscanf (line.data(),
"%d:%d:%d:%" LINE_LEN_QUOT "[^\n\r]",
965 &i, &i, &i, line2.data() )==4) {
973 if (line.find(
"<window") != std::string::npos) {
977 if ((line.find(
"dialogue: marked") != std::string::npos) ||
978 (line.find(
"dialogue: ") != std::string::npos)) {
982 if (sscanf (line.data(),
"%d,%d,\"%c", &i, &i, (
char *) &i) == 3) {
986 if (sscanf (line.data(),
"format=%d", &i) == 1) {
990 if (sscanf (line.data(),
"format=tim%c", &
p)==1 &&
p==
'e') {
994 if (line.find(
"-->>") != std::string::npos) {
998 if (sscanf(line.data(),
"@%d @%d", &i, &i) == 2 ||
999 sscanf(line.data(),
"%d:%d:%d.%d %d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8) {
1003 if (sscanf(line.data(),
"{t %d:%d:%d:%d",&i, &i, &i, &i) == 4) {
1007 if (sscanf(line.data(),
"[%d:%d:%d]", &i, &i, &i) == 3) {
1012 if (sscanf (line.data(),
"[%d][%d]", &i, &i) == 2) {
1023 const std::array<read_func_ptr, 14>
read_func
1045 demuxstr->
buf.clear();
1057 demuxstr->
buf.clear();
1075 demuxstr->subtitles.push_back(*sub);
1076 if (demuxstr->num > 0 && demuxstr->subtitles[demuxstr->num-1].end == -1) {
1078 if (
timeout > sub->
start - demuxstr->subtitles[demuxstr->num-1].start) {
1079 demuxstr->subtitles[demuxstr->num-1].end = sub->
start;
1081 demuxstr->subtitles[demuxstr->num-1].end = demuxstr->subtitles[demuxstr->num-1].start +
timeout;
1088 if (demuxstr->
num > 0 && demuxstr->
subtitles[demuxstr->
num-1].end == -1)
1093 #if DEBUG_XINE_DEMUX_SPUTEXT
1097 sprintf(buffer,
"Read %i subtitles", demuxstr->
num);
1100 sprintf(buffer + strlen(buffer),
", %i bad line(s).\n", demuxstr->
errs);
1102 strcat(buffer,
"\n");
1104 printf(
"%s", buffer);