// Copyright (c) 2005, Rodrigo Braz Monteiro // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of the Aegisub Group nor the names of its contributors // may be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // ----------------------------------------------------------------------------- // // AEGISUB // // Website: http://aegisub.cellosoft.com // Contact: mailto:zeratul@cellosoft.com // //////////// // Includes #include "ass_dialogue.h" #include "ass_override.h" #include <wx/tokenzr.h> ////////////////////// AssOverrideParameter ////////////////////// /////////////// // Constructor AssOverrideParameter::AssOverrideParameter () { classification = PARCLASS_NORMAL; ommited = false; } ////////////// // Destructor AssOverrideParameter::~AssOverrideParameter () { } //////// // Copy void AssOverrideParameter::CopyFrom (const AssOverrideParameter ¶m) { switch(param.GetType()) { case VARDATA_INT: SetInt(param.AsInt()); break; case VARDATA_FLOAT: SetFloat(param.AsFloat()); break; case VARDATA_TEXT: SetText(param.AsText()); break; case VARDATA_BOOL: SetBool(param.AsBool()); break; case VARDATA_COLOUR: SetColour(param.AsColour()); break; case VARDATA_BLOCK: SetBlock(param.AsBlock()); break; default: DeleteValue(); } classification = param.classification; ommited = param.ommited; } void AssOverrideParameter::operator= (const AssOverrideParameter ¶m) { CopyFrom(param); } ////////////////////// AssDialogueBlockOverride ////////////////////// /////////////// // Constructor AssDialogueBlockOverride::AssDialogueBlockOverride () { type = BLOCK_OVERRIDE; } ////////////// // Destructor AssDialogueBlockOverride::~AssDialogueBlockOverride () { for (std::vector<AssOverrideTag*>::iterator cur=Tags.begin();cur!=Tags.end();cur++) { delete *cur; } Tags.clear(); } ///////////// // Read tags void AssDialogueBlockOverride::ParseTags () { // Clear current vector Tags.clear(); // Fix parenthesis matching while (text.Freq(_T('(')) > text.Freq(_T(')'))) { text += _T(")"); } // Initialize tokenizer wxStringTokenizer tkn(text,_T("\\"),wxTOKEN_RET_EMPTY_ALL); while (tkn.HasMoreTokens()) { wxString curTag = _T("\\"); curTag += tkn.GetNextToken(); if (curTag == _T("\\")) continue; // Check for parenthesis matching while (curTag.Freq(_T('(')) > curTag.Freq(_T(')'))) { if (!tkn.HasMoreTokens()) { wxLogWarning(_T("Unmatched parenthesis! Line contents: ") + parent->Text); break; } curTag << _T("\\") << tkn.GetNextToken(); } AssOverrideTag *newTag = new AssOverrideTag; newTag->SetText(curTag); Tags.push_back(newTag); } } /////////////////////////// // Get Text representation wxString AssDialogueBlockOverride::GetText () { text = _T(""); for (std::vector<AssOverrideTag*>::iterator cur=Tags.begin();cur!=Tags.end();cur++) { text += (*cur)->ToString(); } return text; } /////////////////////////////////// // Process parameters via callback void AssDialogueBlockOverride::ProcessParameters(void (*callback)(wxString,int,AssOverrideParameter *,void *),void *userData) { AssOverrideTag *curTag; AssOverrideParameter *curPar; // Find tags for (std::vector<AssOverrideTag*>::iterator cur=Tags.begin();cur!=Tags.end();cur++) { int n = 0; curTag = *cur; // Find parameters for (std::vector<AssOverrideParameter*>::iterator curParam=curTag->Params.begin();curParam!=curTag->Params.end();curParam++) { curPar = *curParam; if (curPar->GetType() != VARDATA_NONE && curPar->ommited == false) { // Do callback (*callback)(curTag->Name,n,curPar,userData); // Go recursive if it's a block parameter //if (curPar->classification == VARDATA_BLOCK) { if (curPar->GetType() == VARDATA_BLOCK) { curPar->AsBlock()->ProcessParameters(callback,userData); } } n++; } } } ///////////////////////// AssOverrideParamProto ////////////////////////// /////////////// // Constructor AssOverrideParamProto::AssOverrideParamProto (VariableDataType _type,int opt,ASS_ParameterClass classi) { type = _type; optional = opt; classification = classi; } ////////////// // Destructor AssOverrideParamProto::~AssOverrideParamProto() { } ///////////////////////// AssOverrideTagProto ////////////////////////// /////////////// // Static vars std::list<AssOverrideTagProto> AssOverrideTagProto::proto; bool AssOverrideTagProto::loaded = false; /////////////// // Constructor AssOverrideTagProto::AssOverrideTagProto() { } ////////////// // Destructor AssOverrideTagProto::~AssOverrideTagProto() { } /////////////////// // Load prototypes void AssOverrideTagProto::LoadProtos () { if (loaded) return; loaded = true; // \alpha proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\alpha"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT)); // \bord<depth> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\bord"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE)); // \shad<depth> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\shad"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE)); // \fade(<a1>,<a2>,<a3>,<t1>,<t2>,<t3>,<t4>) proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\fade"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START)); // \move(<x1>,<y1>,<x2>,<y2>[,<t1>,<t2>]) proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\move"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_6,PARCLASS_RELATIVE_TIME_START)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_6,PARCLASS_RELATIVE_TIME_START)); // \clip(<x1>,<y1>,<x2>,<y2>) proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\clip"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); // \clip([<scale>,]<some drawings>) proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\clip"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_2,PARCLASS_NORMAL)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_DRAWING)); // \fscx<percent> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\fscx"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_RELATIVE_SIZE_X)); // \fscy<percent> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\fscy"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_RELATIVE_SIZE_Y)); // \pos(<x>,<y>) proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\pos"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); // \org(<x>,<y>) proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\org"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); // \pbo<y> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\pbo"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); // \fad(<t1>,<t2>) proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\fad"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_END)); // \fsp<pixels> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\fsp"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE)); // \frx<degrees> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\frx"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \fry<degrees> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\fry"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \frz<degrees> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\frz"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \fr<degrees> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\fr"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \1c&H<bbggrr>& proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\1c"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \2c&H<bbggrr>& proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\2c"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \3c&H<bbggrr>& proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\3c"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \4c&H<bbggrr>& proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\4c"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \1a&H<aa>& proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\1a"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \2a&H<aa>& proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\2a"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \3a&H<aa>& proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\3a"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \4a&H<aa>& proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\4a"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \fe<charset> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\fe"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \ko<duration> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\ko"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_KARAOKE)); // \kf<duration> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\kf"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_KARAOKE)); // \be<0/1> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\be"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_BOOL,NOT_OPTIONAL,PARCLASS_NORMAL)); // \fn<name> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\fn"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \fs<size> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\fs"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE)); // \an<alignment> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\an"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \c&H<bbggrr>& proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\c"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \b<0/1/weight> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\b"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_1,PARCLASS_NORMAL)); proto.back().params.back().defaultValue.SetBool(false); // \i<0/1> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\i"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_BOOL,OPTIONAL_1,PARCLASS_NORMAL)); proto.back().params.back().defaultValue.SetBool(false); // \u<0/1> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\u"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_BOOL,OPTIONAL_1,PARCLASS_NORMAL)); proto.back().params.back().defaultValue.SetBool(false); // \s<0/1> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\s"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_BOOL,OPTIONAL_1,PARCLASS_NORMAL)); proto.back().params.back().defaultValue.SetBool(false); // \a<alignment> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\a"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \k<duration> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\k"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_KARAOKE)); // \K<duration> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\K"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_KARAOKE)); // \q<0-3> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\q"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \p<n> proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\p"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_NORMAL)); // \r[<name>] proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\r"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,OPTIONAL_1,PARCLASS_NORMAL)); // \t([<t1>,<t2>,][<accel>,]<style modifiers>) proto.push_back(AssOverrideTagProto()); proto.back().name = _T("\\t"); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_3 | OPTIONAL_4,PARCLASS_RELATIVE_TIME_START)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_3 | OPTIONAL_4,PARCLASS_RELATIVE_TIME_START)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,OPTIONAL_2 | OPTIONAL_4,PARCLASS_NORMAL)); proto.back().params.push_back(AssOverrideParamProto(VARDATA_BLOCK,NOT_OPTIONAL,PARCLASS_NORMAL)); } //////////////////////// AssOverrideTag ////////////////////////// /////////////// // Constructor AssOverrideTag::AssOverrideTag () { valid = false; } ////////////// // Destructor AssOverrideTag::~AssOverrideTag () { for (std::vector<AssOverrideParameter*>::iterator cur=Params.begin();cur!=Params.end();cur++) { delete *cur; } Params.clear(); valid = false; } //////////////////////////// // Parses text and sets tag void AssOverrideTag::SetText (wxString text) { // Determine name Name = _T(""); AssOverrideTagProto *proto; for (std::list<AssOverrideTagProto>::iterator cur=AssOverrideTagProto::proto.begin();cur!=AssOverrideTagProto::proto.end();cur++) { proto = &(*cur); if (text.Left(proto->name.length()) == proto->name) { Name = proto->name; break; } } // Set tag name if (!Name.empty()) { wxLogDebug(_T("Parsing tag: %s"), Name); ParseParameters(text.Mid(Name.length())); valid = true; } // Junk tag else { Name = text; valid = false; } } ///////////////////////// // Checks if it is valid bool AssOverrideTag::IsValid() { return valid; } ///////////////////// // 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)); 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); } 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); } } ////////////// // Get string wxString AssOverrideTag::ToString() { // Start with name wxString result = Name; // Determine if it needs parentheses bool parenthesis = false; if (Name == _T("\\t") || Name == _T("\\pos") || Name == _T("\\fad") || Name == _T("\\org") || Name == _T("\\clip") || Name == _T("\\move") || Name == _T("\\fade")) parenthesis = true; if (parenthesis) result += _T("("); // Add parameters int n = 0; for (std::vector<AssOverrideParameter*>::iterator cur=Params.begin();cur!=Params.end();cur++) { if ((*cur)->GetType() != VARDATA_NONE && (*cur)->ommited == false) { result += (*cur)->AsText(); result += _T(","); n++; } } if (n > 0) result = result.Left(result.Length()-1); // Finish if (parenthesis) result += _T(")"); return result; }