Teval::Teval(const char_t *Ic, const Tvariable *Ivars): expr(Ic), vars(Ivars) { expr.ConvertToLowerCase(); expr = stringreplace(expr, _l(" and "), _l("&&"), rfReplaceAll); expr = stringreplace(expr, _l(" or "), _l("||"), rfReplaceAll); expr = stringreplace(expr, _l(" "), _l(""), rfReplaceAll); expr = stringreplace(expr, _l(","), _l("."), rfReplaceAll); }
/* replaces the chars with special meaning with the associated data from the player info struct */ static char *generatetextfromlabel(widget *item) { char *text = malloc(MAX_LABELSIZE); char tmp[MAX_LABELSIZE]; if(!item) { free(text); return NULL; } strcpy(text, item->label); if(item->type == tySlabel) return text; stringreplace(text, "$1", "%.2i:%.2i:%.2i", guiInfo.ElapsedTime / 3600, (guiInfo.ElapsedTime / 60) % 60, guiInfo.ElapsedTime % 60); stringreplace(text, "$2", "%.4i:%.2i", guiInfo.ElapsedTime / 60, guiInfo.ElapsedTime % 60); stringreplace(text, "$3", "%.2i", guiInfo.ElapsedTime / 3600); stringreplace(text, "$4", "%.2i", (guiInfo.ElapsedTime / 60) % 60); stringreplace(text, "$5", "%.2i", guiInfo.ElapsedTime % 60); stringreplace(text, "$6", "%.2i:%.2i:%.2i", guiInfo.RunningTime / 3600, (guiInfo.RunningTime / 60) % 60, guiInfo.RunningTime % 60); stringreplace(text, "$7", "%.4i:%.2i", guiInfo.RunningTime / 60, guiInfo.RunningTime % 60); stringreplace(text, "$8", "%i:%.2i:%.2i", guiInfo.ElapsedTime / 3600, (guiInfo.ElapsedTime / 60) % 60, guiInfo.ElapsedTime % 60); stringreplace(text, "$v", "%3.2f%%", guiInfo.Volume); stringreplace(text, "$V", "%3.1f", guiInfo.Volume); stringreplace(text, "$U", "%3.0f", guiInfo.Volume); stringreplace(text, "$b", "%3.2f%%", guiInfo.Balance); stringreplace(text, "$B", "%3.1f", guiInfo.Balance); stringreplace(text, "$D", "%3.0f", guiInfo.Balance); stringreplace(text, "$t", "%.2i", guiInfo.Track); stringreplace(text, "$o", "%s", acp(TranslateFilename(0, tmp, sizeof(tmp)))); stringreplace(text, "$O", "%s", acp(TranslateFilename(4, tmp, sizeof(tmp)))); stringreplace(text, "$x", "%i", guiInfo.VideoWidth); stringreplace(text, "$y", "%i", guiInfo.VideoHeight); stringreplace(text, "$C", "%s", guiInfo.sh_video ? codecname : ""); stringreplace(text, "$$", "$"); if(guiInfo.Playing == GUI_STOP) { stringreplace(text, "$P", "s"); stringreplace(text, "$s", "s"); } else if(guiInfo.Playing == GUI_PLAY) { stringreplace(text, "$P", "p"); stringreplace(text, "$p", "p"); } else if(guiInfo.Playing == GUI_PAUSE) { stringreplace(text, "$P", "e"); stringreplace(text, "$e", "e"); } if(guiInfo.AudioChannels == 0) stringreplace(text, "$a", "n"); else if(guiInfo.AudioChannels == 1) stringreplace(text, "$a", "m"); else if(guiInfo.AudioChannels == 2) stringreplace(text, "$a", (guiInfo.AudioPassthrough ? "r" : "t")); else stringreplace(text, "$a", "r"); if(guiInfo.StreamType == STREAMTYPE_FILE) stringreplace(text, "$T", "f"); else if(guiInfo.StreamType == STREAMTYPE_DVD || guiInfo.StreamType == STREAMTYPE_DVDNAV) stringreplace(text, "$T", "d"); else if(guiInfo.StreamType == STREAMTYPE_STREAM) stringreplace(text, "$T", "u"); else stringreplace(text, "$T", " "); stringreplace(text, "$f", acp(TranslateFilename(1, tmp, sizeof(tmp)))); stringreplace(text, "$F", acp(TranslateFilename(2, tmp, sizeof(tmp)))); return text; }
Tsubtitle* TsubtitleParserSSA::parse(Tstream &fd, int flags, REFERENCE_TIME start, REFERENCE_TIME stop) { /* * Sub Station Alpha v4 (and v2?) scripts have 9 commas before subtitle * other Sub Station Alpha scripts have only 8 commas before subtitle * Reading the "ScriptType:" field is not reliable since many scripts appear * w/o it * * http://www.scriptclub.org is a good place to find more examples * http://www.eswat.demon.co.uk is where the SSA specs can be found */ wchar_t line0[this->LINE_LEN + 1]; wchar_t *line = line0; int playResXscript = 0, playResYscript = 0; while (fd.fgets(line, this->LINE_LEN)) { #if 0 DPRINTF(L"%s", line); #endif lineID++; if (line[0] == ';') { continue; } wchar_t *cr = strrchr(line, '\n'); if (cr) { *cr = '\0'; } cr = strrchr(line, '\r'); if (cr) { *cr = '\0'; } if (strnicmp(line, L"[Script Info]", 13) == 0) { inV4styles = 0; inEvents = 0; inInfo = 1; } else if (inInfo && strnicmp(line, L"PlayResX:", 8) == 0) { nmTextSubtitles::strToInt(line + 9, &playResXscript); } else if (inInfo && strnicmp(line, L"PlayResY:", 8) == 0) { nmTextSubtitles::strToInt(line + 9, &playResYscript); } else if (inInfo && strnicmp(line, L"Timer:", 6) == 0) { wchar_t *end; double t = strtod(line + 7, &end); if (*end == '\0' && t != 0) { timer = Rational(t / 100.0, _I32_MAX); } } else if (inInfo && strnicmp(line, L"WrapStyle:", 9) == 0) { nmTextSubtitles::strToInt(line + 10, &wrapStyle); } else if (inInfo && strnicmp(line, L"ScaledBorderAndShadow:", 21) == 0) { nmTextSubtitles::strToInt(line + 22, &scaleBorderAndShadow); } else if (strnicmp(line, L"[V4 Styles]", 11) == 0) { version = nmTextSubtitles::SSA; inV4styles = 2; inEvents = 0; inInfo = 0; } else if (strnicmp(line, L"[V4+ Styles]", 11) == 0) { version = nmTextSubtitles::ASS; inV4styles = 2; inEvents = 0; inInfo = 0; } else if (strnicmp(line, L"[V4++ Styles]", 11) == 0) { version = nmTextSubtitles::ASS2; inV4styles = 2; inEvents = 0; inInfo = 0; } else if (strnicmp(line, L"[Events]", 8) == 0) { inV4styles = 0; inEvents = 2; inInfo = 0; } else if (inV4styles == 2 && strnicmp(line, L"Format:", 7) == 0) { strlwr(line); strrmchar(line, L' '); typedef std::vector<Tstrpart > Tparts; Tparts fields; const wchar_t *l = line + 7; strtok(l, L",", fields); styleFormat.clear(); for (Tparts::const_iterator f = fields.begin(); f != fields.end(); f++) { if (strnicmp(f->first, L"name", 4) == 0) { styleFormat.push_back(&TSSAstyle::name); } else if (strnicmp(f->first, L"layer", 5) == 0) { styleFormat.push_back(&TSSAstyle::layer); } else if (strnicmp(f->first, L"fontname", 8) == 0) { styleFormat.push_back(&TSSAstyle::fontname); } else if (strnicmp(f->first, L"fontsize", 8) == 0) { styleFormat.push_back(&TSSAstyle::fontsize); } else if (strnicmp(f->first, L"primaryColour", 13) == 0) { styleFormat.push_back(&TSSAstyle::primaryColour); } else if (strnicmp(f->first, L"SecondaryColour", 15) == 0) { styleFormat.push_back(&TSSAstyle::secondaryColour); } else if (strnicmp(f->first, L"TertiaryColour", 14) == 0) { styleFormat.push_back(&TSSAstyle::tertiaryColour); } else if (strnicmp(f->first, L"OutlineColour", 13) == 0) { styleFormat.push_back(&TSSAstyle::outlineColour); } else if (strnicmp(f->first, L"BackColour", 10) == 0) { styleFormat.push_back(&TSSAstyle::backgroundColour); } else if (strnicmp(f->first, L"bold", 4) == 0) { styleFormat.push_back(&TSSAstyle::bold); } else if (strnicmp(f->first, L"italic", 6) == 0) { styleFormat.push_back(&TSSAstyle::italic); } else if (strnicmp(f->first, L"Underline", 9) == 0) { styleFormat.push_back(&TSSAstyle::underline); } else if (strnicmp(f->first, L"Strikeout", 9) == 0) { styleFormat.push_back(&TSSAstyle::strikeout); } else if (strnicmp(f->first, L"ScaleX", 6) == 0) { styleFormat.push_back(&TSSAstyle::fontScaleX); } else if (strnicmp(f->first, L"ScaleY", 6) == 0) { styleFormat.push_back(&TSSAstyle::fontScaleY); } else if (strnicmp(f->first, L"Spacing", 7) == 0) { styleFormat.push_back(&TSSAstyle::spacing); } else if (strnicmp(f->first, L"Angle", 5) == 0) { styleFormat.push_back(&TSSAstyle::angleZ); } else if (strnicmp(f->first, L"outline", 7) == 0) { styleFormat.push_back(&TSSAstyle::outlineWidth); } else if (strnicmp(f->first, L"shadow", 6) == 0) { styleFormat.push_back(&TSSAstyle::shadowDepth); } else if (strnicmp(f->first, L"alignment", 9) == 0) { styleFormat.push_back(&TSSAstyle::alignment); } else if (strnicmp(f->first, L"encoding", 8) == 0) { styleFormat.push_back(&TSSAstyle::encoding); } else if (strnicmp(f->first, L"marginl", 7) == 0) { styleFormat.push_back(&TSSAstyle::marginLeft); } else if (strnicmp(f->first, L"marginr", 7) == 0) { styleFormat.push_back(&TSSAstyle::marginRight); } else if (strnicmp(f->first, L"marginv", 7) == 0) { styleFormat.push_back(&TSSAstyle::marginV); } else if (strnicmp(f->first, L"borderstyle", 11) == 0) { styleFormat.push_back(&TSSAstyle::borderStyle); } else { styleFormat.push_back(NULL); } } inV4styles = 1; } else if (inV4styles && strnicmp(line, L"Style:", 6) == 0) { if (inV4styles == 2) { styleFormat.clear(); if (version == nmTextSubtitles::ASS2) { styleFormat.push_back(&TSSAstyle::name); styleFormat.push_back(&TSSAstyle::fontname); styleFormat.push_back(&TSSAstyle::fontsize); styleFormat.push_back(&TSSAstyle::primaryColour); styleFormat.push_back(&TSSAstyle::secondaryColour); styleFormat.push_back(&TSSAstyle::tertiaryColour); styleFormat.push_back(&TSSAstyle::backgroundColour); styleFormat.push_back(&TSSAstyle::bold); styleFormat.push_back(&TSSAstyle::italic); if (version >= nmTextSubtitles::ASS) { styleFormat.push_back(&TSSAstyle::underline); } if (version >= nmTextSubtitles::ASS) { styleFormat.push_back(&TSSAstyle::strikeout); } if (version >= nmTextSubtitles::ASS) { styleFormat.push_back(&TSSAstyle::fontScaleX); } if (version >= nmTextSubtitles::ASS) { styleFormat.push_back(&TSSAstyle::fontScaleY); } if (version >= nmTextSubtitles::ASS) { styleFormat.push_back(&TSSAstyle::spacing); } if (version >= nmTextSubtitles::ASS) { styleFormat.push_back(&TSSAstyle::angleZ); } styleFormat.push_back(&TSSAstyle::borderStyle); styleFormat.push_back(&TSSAstyle::outlineWidth); styleFormat.push_back(&TSSAstyle::shadowDepth); styleFormat.push_back(&TSSAstyle::alignment); styleFormat.push_back(&TSSAstyle::marginLeft); styleFormat.push_back(&TSSAstyle::marginRight); styleFormat.push_back(&TSSAstyle::marginTop); if (version >= nmTextSubtitles::ASS2) { styleFormat.push_back(&TSSAstyle::marginBottom); } styleFormat.push_back(&TSSAstyle::encoding); if (version <= nmTextSubtitles::SSA) { styleFormat.push_back(&TSSAstyle::alpha); } styleFormat.push_back(&TSSAstyle::relativeTo); } inV4styles = 1; } strings fields; strtok(line + 7, L",", fields); // Fix for missing or incomplete movie dimensions in the script if (playResXscript == 0 && playResYscript == 0) { // Assume 384x288 like VSFilter playResX = 384; playResY = 288; } else { // At least one of the two is set if (playResXscript == 0 || playResYscript == 0) { // Assume 4/3 aspect ratio like VSFilter, but only if one of them is missing if (playResXscript == 0) { playResX = playResYscript * 4 / 3; } else { playResX = playResXscript; } if (playResYscript == 0) { playResY = playResXscript * 3 / 4; } else { playResY = playResYscript; } } else { // Both are set, use them playResX = playResXscript; playResY = playResYscript; } } TSSAstyle style(playResX, playResY, version, wrapStyle, scaleBorderAndShadow); for (size_t i = 0; i < fields.size() && i < styleFormat.size(); i++) if (styleFormat[i]) { style.*(styleFormat[i]) = fields[i]; } styles.add(style); } else if (inEvents == 2 && strnicmp(line, L"Format:", 7) == 0) { strlwr(line); strrmchar(line, L' '); typedef std::vector<Tstrpart > Tparts; Tparts fields; const wchar_t *l = line + 7; strtok(l, L",", fields); eventFormat.clear(); // On embedded streams, read order is added as first column if (isEmbedded) { eventFormat.push_back(&Tevent::readorder); } for (Tparts::const_iterator f = fields.begin(); f != fields.end(); f++) { if (strnicmp(f->first, L"marked", 6) == 0) { eventFormat.push_back(&Tevent::marked); } else if (strnicmp(f->first, L"layer", 5) == 0) { eventFormat.push_back(&Tevent::layer); } else if (strnicmp(f->first, L"start", 5) == 0) { // On embedded subtitles time is removed if (!isEmbedded) { eventFormat.push_back(&Tevent::start); } } else if (strnicmp(f->first, L"end", 3) == 0) { // On embedded subtitles time is removed if (!isEmbedded) { eventFormat.push_back(&Tevent::end); } } else if (strnicmp(f->first, L"style", 5) == 0) { eventFormat.push_back(&Tevent::style); } else if (strnicmp(f->first, L"name", 4) == 0) { eventFormat.push_back(&Tevent::name); } else if (strnicmp(f->first, L"marginL", 7) == 0) { eventFormat.push_back(&Tevent::marginL); } else if (strnicmp(f->first, L"marginR", 7) == 0) { eventFormat.push_back(&Tevent::marginR); } else if (strnicmp(f->first, L"marginV", 7) == 0) { eventFormat.push_back(&Tevent::marginV); } else if (strnicmp(f->first, L"marginR", 7) == 0) { eventFormat.push_back(&Tevent::marginR); } else if (strnicmp(f->first, L"effect", 6) == 0) { eventFormat.push_back(&Tevent::effect); } else if (strnicmp(f->first, L"text", 4) == 0) { eventFormat.push_back(&Tevent::text); } else { eventFormat.push_back(NULL); } } inEvents = 1; } else if ((flags & this->SSA_NODIALOGUE) || (inEvents == 1 && strnicmp(line, L"Dialogue:", 8) == 0)) { if (eventFormat.empty()) { if (!(flags & this->SSA_NODIALOGUE)) { if (version <= nmTextSubtitles::SSA) { eventFormat.push_back(&Tevent::marked); } if (version >= nmTextSubtitles::ASS) { eventFormat.push_back(&Tevent::layer); } eventFormat.push_back(&Tevent::start); eventFormat.push_back(&Tevent::end); } else { eventFormat.push_back(&Tevent::readorder); eventFormat.push_back(&Tevent::layer); } eventFormat.push_back(&Tevent::style); eventFormat.push_back(&Tevent::actor); eventFormat.push_back(&Tevent::marginL); eventFormat.push_back(&Tevent::marginR); eventFormat.push_back(&Tevent::marginT); if (version >= nmTextSubtitles::ASS2) { eventFormat.push_back(&Tevent::marginB); } eventFormat.push_back(&Tevent::effect); eventFormat.push_back(&Tevent::text); } strings fields; strtok(line + (flags & this->SSA_NODIALOGUE ? 0 : 9), L"," , fields, true, eventFormat.size()); Tevent event; event.dummy = ""; // avoid being optimized. for (size_t i = 0; i < fields.size() && i < eventFormat.size(); i++) { if (eventFormat[i]) { event.*(eventFormat[i]) = fields[i]; } } if (event.text) { #if 0 DPRINTF(L"%s", event.text.c_str()); #endif int hour1 = 0, min1 = 0, sec1 = 0, hunsec1 = 0; int hour2 = 0, min2 = 0, sec2 = 0, hunsec2 = 0; if (!(flags & this->PARSETIME) || (swscanf(event.start.c_str(), L"%d:%d:%d.%d", &hour1, &min1, &sec1, &hunsec1) == 4 && swscanf(event.end.c_str() , L"%d:%d:%d.%d", &hour2, &min2, &sec2, &hunsec2) == 4)) { const TSubtitleProps *props = styles.getProps(event.style); TsubtitleText current(this->format, props ? *props : defprops, styles); current.defProps.lineID = lineID; // margins nmTextSubtitles::strToIntMargin(event.marginL, ¤t.defProps.marginL); nmTextSubtitles::strToIntMargin(event.marginR, ¤t.defProps.marginR); nmTextSubtitles::strToIntMargin(event.marginV, ¤t.defProps.marginV); // layer nmTextSubtitles::strToInt(event.layer, ¤t.defProps.layer); // timestamps if (flags & this->PARSETIME) { current.start = timer.den * this->hmsToTime(hour1, min1, sec1, hunsec1) / timer.num; current.stop = timer.den * this->hmsToTime(hour2, min2, sec2, hunsec2) / timer.num; } else if (start != REFTIME_INVALID && stop != REFTIME_INVALID) { current.start = start; current.stop = stop; } current.defProps.tStart = current.defProps.karaokeStart = current.start; current.defProps.tStop = current.stop; // scroll event.effect = event.effect.ConvertToLowerCase(); if (event.effect.find(L"scroll up;") != ffstring::npos) { current.defProps.scroll.directionV = -1; } if (event.effect.find(L"scroll down;") != ffstring::npos) { current.defProps.scroll.directionV = 1; } if (current.defProps.scroll.directionV) { int y1, y2, delay, fadeawayheight = 0; if (swscanf(event.effect.c_str() + event.effect.find(L";"), L";%d;%d;%d;%d", &y1, &y2, &delay, &fadeawayheight) >= 3) { if (y1 > y2) { std::swap(y1, y2); } current.defProps.scroll.y1 = y1; current.defProps.scroll.y2 = y2; current.defProps.scroll.delay = std::max(delay, 1); current.defProps.scroll.fadeaway = fadeawayheight; } } if (event.effect.find(L"banner;") != ffstring::npos) { current.defProps.scroll.directionV = 0; current.defProps.scroll.directionH = -1; int delay, lefttoright = 0, fadeawaywidth = 0; if (swscanf(event.effect.c_str() + event.effect.find(L";"), L";%d;%d;%d", &delay, &lefttoright, &fadeawaywidth) >= 1) { current.defProps.scroll.delay = std::max(delay, 1); current.defProps.scroll.directionH = lefttoright ? 1 : -1; current.defProps.scroll.fadeaway = fadeawaywidth; } } // replace \h with non-breaking space (U+00A0). event.text = stringreplace(event.text, L"\\h", L"\xa0", rfReplaceAll); const wchar_t *line2 = event.text.c_str(); do { const wchar_t *tmp, *tmp1; int lineBreakReason = 0; do { tmp = strstr(line2, L"\\n"); tmp1 = strstr(line2, L"\\N"); if (tmp == NULL && tmp1 == NULL) { break; } if (tmp && tmp1) { tmp = std::min(tmp, tmp1); } if (tmp == NULL) { tmp = tmp1; } current.addSSA(line2, tmp - line2, lineBreakReason); lineBreakReason = tmp[1] == 'n' ? 1 : 2; line2 = tmp + 2; } while (1); current.addSSA(line2, lineBreakReason); } while (flags & this->SSA_NODIALOGUE && fd.fgets((wchar_t*)(line2 = line), this->LINE_LEN)); textformat.setProps(current.defProps); return store(current); } } } } return NULL; }
/* replaces the chars with special meaning with the associated data from the player info struct */ static char *generatetextfromlabel(widget *item) { char *text = malloc(MAX_LABELSIZE); char tmp[MAX_LABELSIZE]; unsigned int i; if(!item) { free(text); return NULL; } strcpy(text, item->label); if(item->type == tySlabel) return text; stringreplace(text, "$1", "%.2i:%.2i:%.2i", guiInfo.ElapsedTime / 3600, (guiInfo.ElapsedTime / 60) % 60, guiInfo.ElapsedTime % 60); stringreplace(text, "$2", "%.4i:%.2i", guiInfo.ElapsedTime / 60, guiInfo.ElapsedTime % 60); stringreplace(text, "$3", "%.2i", guiInfo.ElapsedTime / 3600); stringreplace(text, "$4", "%.2i", (guiInfo.ElapsedTime / 60) % 60); stringreplace(text, "$5", "%.2i", guiInfo.ElapsedTime % 60); stringreplace(text, "$6", "%.2i:%.2i:%.2i", guiInfo.RunningTime / 3600, (guiInfo.RunningTime / 60) % 60, guiInfo.RunningTime % 60); stringreplace(text, "$7", "%.4i:%.2i", guiInfo.RunningTime / 60, guiInfo.RunningTime % 60); stringreplace(text, "$8", "%i:%.2i:%.2i", guiInfo.ElapsedTime / 3600, (guiInfo.ElapsedTime / 60) % 60, guiInfo.ElapsedTime % 60); stringreplace(text, "$v", "%3.2f", guiInfo.Volume); stringreplace(text, "$V", "%3.1f", guiInfo.Volume); stringreplace(text, "$b", "%3.2f", guiInfo.Balance); stringreplace(text, "$B", "%3.1f", guiInfo.Balance); stringreplace(text, "$t", "%.2i", guiInfo.Track); stringreplace(text, "$o", "%s", guiInfo.Filename); stringreplace(text, "$x", "%i", guiInfo.VideoWidth); stringreplace(text, "$y", "%i", guiInfo.VideoHeight); stringreplace(text, "$C", "%s", guiInfo.sh_video ? codecname : ""); stringreplace(text, "$$", "$"); if(!strcmp(text, "$p") || !strcmp(text, "$s") || !strcmp(text, "$e")) { if(guiInfo.Playing == GUI_STOP) stringreplace(text, NULL, "s"); else if(guiInfo.Playing == GUI_PLAY) stringreplace(text, NULL, "p"); else if(guiInfo.Playing == GUI_PAUSE) stringreplace(text, NULL, "e"); } if(guiInfo.AudioChannels == 0) stringreplace(text, "$a", "n"); else if(guiInfo.AudioChannels == 1) stringreplace(text, "$a", "m"); else stringreplace(text, "$a", "t"); if(guiInfo.StreamType == 0) stringreplace(text, "$T", "f"); #ifdef CONFIG_DVDREAD else if(guiInfo.StreamType == STREAMTYPE_DVD || guiInfo.StreamType == STREAMTYPE_DVDNAV) stringreplace(text, "$T", "d"); #endif else stringreplace(text, "$T", "u"); if(guiInfo.Filename) { for (i=0; i<strlen(guiInfo.Filename); i++) tmp[i] = tolower(guiInfo.Filename[i]); stringreplace(text, "$f", tmp); for (i=0; i<strlen(guiInfo.Filename); i++) tmp[i] = toupper(guiInfo.Filename[i]); stringreplace(text, "$F", tmp); } return text; }