static void sami_add_line(subtitle *current, char *buffer, char **pos) { char *p = *pos; *p = 0; trail_space(buffer); if (*buffer && current->lines < SUB_MAX_TEXT) current->text[current->lines++] = strdup(buffer); *pos = buffer; }
static subtitle *sub_read_line_jacosub(stream_t* st, subtitle * current, struct readline_args *args) { int utf16 = args->utf16; char line1[LINE_LEN], line2[LINE_LEN], directive[LINE_LEN], *p, *q; unsigned a1, a2, a3, a4, b1, b2, b3, b4, comment = 0; static unsigned jacoTimeres = 30; static int jacoShift = 0; memset(current, 0, sizeof(subtitle)); memset(line1, 0, LINE_LEN); memset(line2, 0, LINE_LEN); memset(directive, 0, LINE_LEN); while (!current->text[0]) { if (!stream_read_line(st, line1, LINE_LEN, utf16)) { return NULL; } if (sscanf (line1, "%u:%u:%u.%u %u:%u:%u.%u %[^\n\r]", &a1, &a2, &a3, &a4, &b1, &b2, &b3, &b4, line2) < 9) { if (sscanf(line1, "@%u @%u %[^\n\r]", &a4, &b4, line2) < 3) { if (line1[0] == '#') { int hours = 0, minutes = 0, seconds, delta, inverter = 1; unsigned units = jacoShift; switch (toupper(line1[1])) { case 'S': if (isalpha(line1[2])) { delta = 6; } else { delta = 2; } if (sscanf(&line1[delta], "%d", &hours)) { if (hours < 0) { hours *= -1; inverter = -1; } if (sscanf(&line1[delta], "%*d:%d", &minutes)) { if (sscanf (&line1[delta], "%*d:%*d:%d", &seconds)) { sscanf(&line1[delta], "%*d:%*d:%*d.%d", &units); } else { hours = 0; sscanf(&line1[delta], "%d:%d.%d", &minutes, &seconds, &units); minutes *= inverter; } } else { hours = minutes = 0; sscanf(&line1[delta], "%d.%d", &seconds, &units); seconds *= inverter; } jacoShift = ((hours * 3600 + minutes * 60 + seconds) * jacoTimeres + units) * inverter; } break; case 'T': if (isalpha(line1[2])) { delta = 8; } else { delta = 2; } sscanf(&line1[delta], "%u", &jacoTimeres); break; } } continue; } else { current->start = (unsigned long) ((a4 + jacoShift) * 100.0 / jacoTimeres); current->end = (unsigned long) ((b4 + jacoShift) * 100.0 / jacoTimeres); } } else { current->start = (unsigned long) (((a1 * 3600 + a2 * 60 + a3) * jacoTimeres + a4 + jacoShift) * 100.0 / jacoTimeres); current->end = (unsigned long) (((b1 * 3600 + b2 * 60 + b3) * jacoTimeres + b4 + jacoShift) * 100.0 / jacoTimeres); } current->lines = 0; p = line2; while ((*p == ' ') || (*p == '\t')) { ++p; } if (isalpha(*p)||*p == '[') { int cont, jLength; if (sscanf(p, "%s %[^\n\r]", directive, line1) < 2) return (subtitle *) ERR; jLength = strlen(directive); for (cont = 0; cont < jLength; ++cont) { if (isalpha(*(directive + cont))) *(directive + cont) = toupper(*(directive + cont)); } if ((strstr(directive, "RDB") != NULL) || (strstr(directive, "RDC") != NULL) || (strstr(directive, "RLB") != NULL) || (strstr(directive, "RLG") != NULL)) { continue; } if (strstr(directive, "JL") != NULL) { current->alignment = SUB_ALIGNMENT_BOTTOMLEFT; } else if (strstr(directive, "JR") != NULL) { current->alignment = SUB_ALIGNMENT_BOTTOMRIGHT; } else { current->alignment = SUB_ALIGNMENT_BOTTOMCENTER; } snprintf(line2, sizeof(line2), "%s", line1); p = line2; } for (q = line1; (!eol(*p)) && (current->lines < SUB_MAX_TEXT); ++p) { switch (*p) { case '{': comment++; break; case '}': if (comment) { --comment; //the next line to get rid of a blank after the comment if ((*(p + 1)) == ' ') p++; } break; case '~': if (!comment) { *q = ' '; ++q; } break; case ' ': case '\t': if ((*(p + 1) == ' ') || (*(p + 1) == '\t')) break; if (!comment) { *q = ' '; ++q; } break; case '\\': if (*(p + 1) == 'n') { *q = '\0'; q = line1; current->text[current->lines++] = strdup(line1); ++p; break; } if ((toupper(*(p + 1)) == 'C') || (toupper(*(p + 1)) == 'F')) { ++p,++p; break; } if ((*(p + 1) == 'B') || (*(p + 1) == 'b') || (*(p + 1) == 'D') || //actually this means "insert current date here" (*(p + 1) == 'I') || (*(p + 1) == 'i') || (*(p + 1) == 'N') || (*(p + 1) == 'T') || //actually this means "insert current time here" (*(p + 1) == 'U') || (*(p + 1) == 'u')) { ++p; break; } if ((*(p + 1) == '\\') || (*(p + 1) == '~') || (*(p + 1) == '{')) { ++p; } else if (eol(*(p + 1))) { if (!stream_read_line(st, directive, LINE_LEN, utf16)) return NULL; trail_space(directive); av_strlcat(line2, directive, LINE_LEN); break; } default: if (!comment) { *q = *p; ++q; } } //-- switch } //-- for *q = '\0'; if (current->lines < SUB_MAX_TEXT) current->text[current->lines] = strdup(line1); } //-- while if (current->lines < SUB_MAX_TEXT) current->lines++; return current; }
static subtitle *sub_read_line_sami(stream_t* st, subtitle *current, struct readline_args *args) { int utf16 = args->utf16; static char line[LINE_LEN+1]; static char *s = NULL, *slacktime_s; char text[LINE_LEN+1], *p=NULL, *q; int state; current->lines = current->start = current->end = 0; current->alignment = SUB_ALIGNMENT_BOTTOMCENTER; state = 0; /* read the first line */ if (!s) if (!(s = stream_read_line(st, line, LINE_LEN, utf16))) return 0; do { switch (state) { case 0: /* find "START=" or "Slacktime:" */ slacktime_s = stristr (s, "Slacktime:"); if (slacktime_s) args->sub_slacktime = strtol (slacktime_s+10, NULL, 0) / 10; s = stristr (s, "Start="); if (s) { current->start = strtol (s + 6, &s, 0) / 10; /* eat '>' */ for (; *s != '>' && *s != '\0'; s++); s++; state = 1; continue; } break; case 1: /* find (optional) "<P", skip other TAGs */ for (; *s == ' ' || *s == '\t'; s++); /* strip blanks, if any */ if (*s == '\0') break; if (*s != '<') { state = 3; p = text; continue; } /* not a TAG */ s++; if (*s == 'P' || *s == 'p') { s++; state = 2; continue; } /* found '<P' */ for (; *s != '>' && *s != '\0'; s++); /* skip remains of non-<P> TAG */ if (*s == '\0') break; s++; continue; case 2: /* find ">" */ if ((s = strchr (s, '>'))) { s++; state = 3; p = text; continue; } break; case 3: /* get all text until '<' appears */ if (p - text >= LINE_LEN) sami_add_line(current, text, &p); if (*s == '\0') break; else if (!strncasecmp (s, "<br>", 4)) { sami_add_line(current, text, &p); s += 4; } else if (*s == '{') { state = 5; ++s; continue; } else if (*s == '<') { state = 4; } else if (!strncasecmp (s, " ", 6)) { *p++ = ' '; s += 6; } else if (*s == '\t') { *p++ = ' '; s++; } else if (*s == '\r' || *s == '\n') { s++; } else *p++ = *s++; /* skip duplicated space */ if (p > text + 2) if (*(p-1) == ' ' && *(p-2) == ' ') p--; continue; case 4: /* get current->end or skip <TAG> */ q = stristr (s, "Start="); if (q) { current->end = strtol (q + 6, &q, 0) / 10 - 1; *p = '\0'; trail_space (text); if (text[0] != '\0') current->text[current->lines++] = strdup (text); if (current->lines > 0) { state = 99; break; } state = 0; continue; } s = strchr (s, '>'); if (s) { s++; state = 3; continue; } break; case 5: /* get rid of {...} text, but read the alignment code */ if ((*s == '\\') && (*(s + 1) == 'a')) { if (stristr(s, "\\a1") != NULL) { current->alignment = SUB_ALIGNMENT_BOTTOMLEFT; s = s + 3; } if (stristr(s, "\\a2") != NULL) { current->alignment = SUB_ALIGNMENT_BOTTOMCENTER; s = s + 3; } else if (stristr(s, "\\a3") != NULL) { current->alignment = SUB_ALIGNMENT_BOTTOMRIGHT; s = s + 3; } else if ((stristr(s, "\\a4") != NULL) || (stristr(s, "\\a5") != NULL) || (stristr(s, "\\a8") != NULL)) { current->alignment = SUB_ALIGNMENT_TOPLEFT; s = s + 3; } else if (stristr(s, "\\a6") != NULL) { current->alignment = SUB_ALIGNMENT_TOPCENTER; s = s + 3; } else if (stristr(s, "\\a7") != NULL) { current->alignment = SUB_ALIGNMENT_TOPRIGHT; s = s + 3; } else if (stristr(s, "\\a9") != NULL) { current->alignment = SUB_ALIGNMENT_MIDDLELEFT; s = s + 3; } else if (stristr(s, "\\a10") != NULL) { current->alignment = SUB_ALIGNMENT_MIDDLECENTER; s = s + 4; } else if (stristr(s, "\\a11") != NULL) { current->alignment = SUB_ALIGNMENT_MIDDLERIGHT; s = s + 4; } } if (*s == '}') state = 3; ++s; continue; } /* read next line */ if (state != 99 && !(s = stream_read_line (st, line, LINE_LEN, utf16))) { if (current->start > 0) { break; // if it is the last subtitle } else { return 0; } } } while (state != 99); // For the last subtitle if (current->end <= 0) { current->end = current->start + args->sub_slacktime; sami_add_line(current, text, &p); } return current; }
Tsubtitle* TsubtitleParserSami::parse(Tstream &fd, int flags, REFERENCE_TIME start, REFERENCE_TIME stop) { wchar_t text[this->LINE_LEN + 1], *p = NULL, *q; int state; /* read the first line */ if (!s) if ((s = fd.fgets(line, this->LINE_LEN)) == NULL) { return NULL; } TsubtitleText current(this->format); current.start = current.stop = 0; state = 0; do { switch (state) { case 0: /* find "START=" or "Slacktime:" */ slacktime_s = stristr(s, L"Slacktime:"); if (slacktime_s) { sub_slacktime = strtol(slacktime_s + 10, NULL, 0) / 10; } s = (wchar_t*)stristr(s, L"Start="); if (s) { int sec1000 = strtol(s + 6, &s, 0); current.start = this->hmsToTime(0, 0, sec1000 / 1000, (sec1000 % 1000) / 10); /* eat '>' */ for (; *s != '>' && *s != '\0'; s++) { ; } s++; state = 1; continue; } break; case 1: /* find (optionnal) "<P", skip other TAGs */ for (; *s == ' ' || *s == '\t'; s++) { ; /* strip blanks, if any */ } if (*s == '\0') { break; } if (*s != '<') { state = 3; /* not a TAG */ p = text; continue; } s++; if (*s == 'P' || *s == 'p') { s++; /* found '<P' */ state = 2; continue; } for (; *s != '>' && *s != '\0'; s++) { ; /* skip remains of non-<P> TAG */ } if (s == '\0') { break; } s++; continue; case 2: /* find ">" */ if ((s = strchr(s, '>')) != NULL) { s++; state = 3; p = text; continue; } break; case 3: /* get all text until '<' appears */ if (*s == '\0') { break; } else if (!_strnicmp(s, L"<br>", 4)) { *p = '\0'; p = text; trail_space(text); if (text[0] != '\0') { current.add(text); } s += 4; } else if ((*s == '{') && !sub_no_text_pp) { state = 5; ++s; continue; } else if (*s == '<') { state = 4; } else if (!_strnicmp(s, L" ", 6)) { *p++ = ' '; s += 6; } else if (*s == '\t') { *p++ = ' '; s++; } else if (*s == '\r' || *s == '\n') { s++; } else { *p++ = *s++; } /* skip duplicated space */ if (p > text + 2) if (*(p - 1) == ' ' && *(p - 2) == ' ') { p--; } continue; case 4: /* get current->end or skip <TAG> */ q = (wchar_t*)stristr(s, L"Start="); if (q) { int sec1000 = strtol(q + 6, &q, 0); current.stop = this->hmsToTime(0, 0, sec1000 / 1000, (sec1000 % 1000) / 10 - 1); *p = '\0'; trail_space(text); if (text[0] != '\0') { current.add(text); } if (current.size() > 0) { state = 99; break; } state = 0; continue; } s = strchr(s, '>'); if (s) { s++; state = 3; continue; } break; case 5: /* get rid of {...} text, but read the alignment code */ if ((*s == '\\') && (*(s + 1) == 'a') && !sub_no_text_pp) { if (stristr(s, L"\\a1") != NULL) { //current->alignment = SUB_ALIGNMENT_BOTTOMLEFT; s = s + 3; } if (stristr(s, L"\\a2") != NULL) { //current->alignment = SUB_ALIGNMENT_BOTTOMCENTER; s = s + 3; } else if (stristr(s, L"\\a3") != NULL) { //current->alignment = SUB_ALIGNMENT_BOTTOMRIGHT; s = s + 3; } else if ((stristr(s, L"\\a4") != NULL) || (stristr(s, L"\\a5") != NULL) || (stristr(s, L"\\a8") != NULL)) { //current->alignment = SUB_ALIGNMENT_TOPLEFT; s = s + 3; } else if (stristr(s, L"\\a6") != NULL) { //current->alignment = SUB_ALIGNMENT_TOPCENTER; s = s + 3; } else if (stristr(s, L"\\a7") != NULL) { //current->alignment = SUB_ALIGNMENT_TOPRIGHT; s = s + 3; } else if (stristr(s, L"\\a9") != NULL) { //current->alignment = SUB_ALIGNMENT_MIDDLELEFT; s = s + 3; } else if (stristr(s, L"\\a10") != NULL) { //current->alignment = SUB_ALIGNMENT_MIDDLECENTER; s = s + 4; } else if (stristr(s, L"\\a11") != NULL) { //current->alignment = SUB_ALIGNMENT_MIDDLERIGHT; s = s + 4; } } if (*s == '}') { state = 3; } ++s; continue; } /* read next line */ if (state != 99 && (s = fd.fgets(line, this->LINE_LEN)) == NULL) { if (current.start > 0) { break; // if it is the last subtitle } else { return NULL; } } } while (state != 99); // For the last subtitle if (current.stop <= 0) { current.stop = current.start + this->hmsToTime(0, 0, sub_slacktime / 1000, (sub_slacktime % 1000) / 10); *p = '\0'; trail_space(text); if (text[0] != '\0') { current.add(text); } } return store(current); }