std::auto_ptr<boost::ptr_vector<AssDialogueBlock>> AssDialogue::ParseTags() const { boost::ptr_vector<AssDialogueBlock> Blocks; // Empty line, make an empty block if (Text.get().empty()) { Blocks.push_back(new AssDialogueBlockPlain); return Blocks.release(); } int drawingLevel = 0; for (size_t len = Text.get().size(), cur = 0; cur < len; ) { // Overrides block if (Text.get()[cur] == '{') { size_t end = Text.get().find('}', cur); // VSFilter requires that override blocks be closed, while libass // does not. We match VSFilter here. if (end == wxString::npos) goto plain; ++cur; // Get contents of block wxString work = Text.get().substr(cur, end - cur); cur = end + 1; if (work.size() && work.find('\\') == wxString::npos) { //We've found an override block with no backslashes //We're going to assume it's a comment and not consider it an override block //Currently we'll treat this as a plain text block, but feel free to create a new class Blocks.push_back(new AssDialogueBlockPlain("{" + work + "}")); } else { // Create block AssDialogueBlockOverride *block = new AssDialogueBlockOverride(work); block->ParseTags(); Blocks.push_back(block); // Look for \p in block for (auto const& tag : block->Tags) { if (tag.Name == "\\p") drawingLevel = tag.Params[0].Get<int>(0); } } continue; } // Plain-text/drawing block plain: wxString work; size_t end = Text.get().find('{', cur + 1); if (end == wxString::npos) { work = Text.get().substr(cur); cur = len; } else { work = Text.get().substr(cur, end - cur); cur = end; } if (drawingLevel == 0) Blocks.push_back(new AssDialogueBlockPlain(work)); else Blocks.push_back(new AssDialogueBlockDrawing(work, drawingLevel)); } return Blocks.release(); }
///////////////////// // Parses parameters void AssOverrideTag::ParseParameters(wxString text) { // text is all text following the name until the next \ or the end of the override block // Tokenize text, attempting to find all parameters wxArrayString paramList; wxString work; { if (text.IsEmpty() || text[0] != _T('(')) { // There's just one (or none at all) parameter (because there's no parantheses) // This means text is all our parameters paramList.Add(text.Trim(true).Trim(false)); // Only using goto here to avoid yet another nested block (keeps the code cleaner!) goto end_tokenizing; } // Ok, so there are parantheses used here, so there may be more than one parameter // Enter fullscale parsing! size_t i = 0, textlen = text.Length(); size_t start = 0; int parDepth = 1; while (i < textlen && parDepth > 0) { // Just skip until next ',' or ')', whichever comes first // (Next ')' is achieved when parDepth == 0) start = ++i; while (i < textlen && parDepth > 0) { if (text[i] == _T('(')) parDepth++; if (text[i] == _T(')')) parDepth--; // parDepth 1 is where we start, and the tag-level we're interested in parsing on if (text[i] == _T(',') && parDepth == 1) break; if (parDepth < 0) { wxLogWarning(_T("Unmatched parenthesis near '%s'!\nTag-parsing incomplete."), text.SubString(i, 10).c_str()); goto end_tokenizing; } if (parDepth == 0) { // We just ate the paranthesis ending this parameter block // Make sure it doesn't get included in the parameter text break; } i++; } // i now points to the first character not member of this parameter work = text.SubString(start, i-1); work.Trim(true).Trim(false); paramList.Add(work); wxLogDebug(_T("Got parameter: %s"), work.c_str()); } if (i+1 < textlen) { // There's some additional garbage after the parantheses // Just add it in for completeness paramList.Add(text.Mid(i+1)); } } // This label is only gone to from inside the previous block, if the tokenizing needs to end early end_tokenizing: int curPar = 0; size_t totalPars = paramList.GetCount(); // Get optional parameters flag ASS_ParameterOptional parsFlag = OPTIONAL_0; switch (totalPars) { case 1: parsFlag = OPTIONAL_1; break; case 2: parsFlag = OPTIONAL_2; break; case 3: parsFlag = OPTIONAL_3; break; case 4: parsFlag = OPTIONAL_4; break; case 5: parsFlag = OPTIONAL_5; break; case 6: parsFlag = OPTIONAL_6; break; case 7: parsFlag = OPTIONAL_7; break; } // Find prototype bool clipOnce = true; AssOverrideTagProto *proto = NULL; for (std::list<AssOverrideTagProto>::iterator cur=AssOverrideTagProto::proto.begin();cur!=AssOverrideTagProto::proto.end();cur++) { if (Name == (*cur).name) { if (Name == _T("\\clip") && totalPars != 4 && clipOnce) { clipOnce = false; continue; } proto = &(*cur); break; } } if (proto == NULL) { throw _T("Couldn't find tag prototype while parsing."); } // Get parameters size_t n=0; wxString curtok = _T(""); if (curPar < (signed)totalPars) { curtok = paramList[curPar]; curPar++; } // For each parameter while (n < proto->params.size()) { AssOverrideParamProto *curproto = &proto->params[n]; bool isDefault = false; n++; // Create parameter AssOverrideParameter *newparam = new AssOverrideParameter; // Check if it's optional and not set (set to default) if (!(curproto->optional & parsFlag)) { if (curproto->defaultValue.GetType() != VARDATA_NONE) { isDefault = true; newparam->CopyFrom(curproto->defaultValue); } newparam->ommited = true; // This parameter doesn't really count against the number of parsed parameters, // since it's left out. Don't count it. curPar--; } if (isDefault == false) { // Determine parameter type and set value switch (curproto->type) { case VARDATA_INT: { long temp = 0; curtok.ToLong(&temp); newparam->SetInt(temp); break; } case VARDATA_FLOAT: { double temp = 0.0; curtok.ToDouble(&temp); newparam->SetFloat(temp); break; } case VARDATA_TEXT: { newparam->SetText(curtok); break; } case VARDATA_BOOL: { long temp = false; curtok.ToLong(&temp); newparam->SetBool(temp != 0); break; } case VARDATA_BLOCK: { AssDialogueBlockOverride *temp = new AssDialogueBlockOverride; temp->text = curtok; temp->ParseTags(); newparam->SetBlock(temp); break; } } // Get next actual parameter if (curPar < (signed)totalPars) { // Unless this parameter was omitted (in which case the token shouldn't be eaten) if (!newparam->ommited) { curtok = paramList[curPar]; } curPar++; } else curtok = _T(""); } // Add to list newparam->classification = curproto->classification; Params.push_back(newparam); } }
void AssOverrideTag::ParseParameters(const wxString &text, AssOverrideTagProto::iterator proto_it) { Clear(); // Tokenize text, attempting to find all parameters std::vector<wxString> paramList = tokenize(text); size_t totalPars = paramList.size(); int parsFlag = 1 << (totalPars - 1); // Get optional parameters flag // vector (i)clip is the second clip proto_ittype in the list if ((Name == "\\clip" || Name == "\\iclip") && totalPars != 4) { ++proto_it; } unsigned curPar = 0; for (size_t n = 0; n < proto_it->params.size(); n++) { AssOverrideParamProto *curproto = &proto_it->params[n]; // Create parameter AssOverrideParameter *newparam = new AssOverrideParameter; newparam->classification = curproto->classification; Params.push_back(newparam); // Check if it's optional and not present if (!(curproto->optional & parsFlag) || curPar >= totalPars) { newparam->omitted = true; continue; } wxString curtok = paramList[curPar++]; if (curtok.empty()) { curPar++; continue; } wxChar firstChar = curtok[0]; bool auto4 = (firstChar == '!' || firstChar == '$' || firstChar == '%') && curproto->type != VARDATA_BLOCK; if (auto4) { newparam->Set(curtok); } else { switch (curproto->type) { case VARDATA_INT: { long temp; curtok.ToLong(&temp); newparam->Set<int>(temp); break; } case VARDATA_FLOAT: { double temp; curtok.ToDouble(&temp); newparam->Set(temp); break; } case VARDATA_TEXT: newparam->Set(curtok); break; case VARDATA_BOOL: { long temp; curtok.ToLong(&temp); newparam->Set<bool>(temp != 0); break; } case VARDATA_BLOCK: { AssDialogueBlockOverride *temp = new AssDialogueBlockOverride(curtok); temp->ParseTags(); newparam->Set(temp); break; } default: break; } } } }