Beat some semblance of sanity into ass_override and related files. Fixes a pile of crashes when tags are missing expected parameters.

Originally committed to SVN as r4581.
This commit is contained in:
Thomas Goyne 2010-06-24 01:24:43 +00:00
parent c64e764648
commit e2f8e69612
10 changed files with 413 additions and 872 deletions

View file

@ -47,7 +47,6 @@
#include "utils.h" #include "utils.h"
#include "vfr.h" #include "vfr.h"
/// @brief Constructs AssDialogue
AssDialogue::AssDialogue() AssDialogue::AssDialogue()
: Comment(false) : Comment(false)
, Layer(0) , Layer(0)
@ -109,29 +108,21 @@ AssDialogue::AssDialogue(wxString _data,int version)
} }
} }
/// @brief Destructor
AssDialogue::~AssDialogue () { AssDialogue::~AssDialogue () {
Clear(); Clear();
} }
/// @brief Clear
void AssDialogue::Clear () { void AssDialogue::Clear () {
ClearBlocks(); ClearBlocks();
} }
/// @brief Clear blocks
void AssDialogue::ClearBlocks() { void AssDialogue::ClearBlocks() {
using std::vector; for (std::vector<AssDialogueBlock*>::iterator cur=Blocks.begin();cur!=Blocks.end();cur++) {
for (vector<AssDialogueBlock*>::iterator cur=Blocks.begin();cur!=Blocks.end();cur++) {
delete *cur; delete *cur;
} }
Blocks.clear(); Blocks.clear();
} }
/// @brief Parse ASS Data
/// @param rawData
/// @param version
/// @return
bool AssDialogue::Parse(wxString rawData, int version) { bool AssDialogue::Parse(wxString rawData, int version) {
size_t pos = 0; size_t pos = 0;
wxString temp; wxString temp;
@ -224,92 +215,51 @@ bool AssDialogue::Parse(wxString rawData, int version) {
return true; return true;
} }
/// @brief Make data wxString AssDialogue::GetData(bool ssa) {
/// @return wxString final;
wxString AssDialogue::MakeData() {
// Prepare
static wxString final = _T("");
// Write all final if (Comment) final = L"Comment: ";
if (Comment) final = _T("Comment: "); else final = L"Dialogue: ";
else final = _T("Dialogue: ");
final += wxString::Format(_T("%01i"),Layer); if (ssa) final += L"Marked=0,";
final += _T(",");
final += Start.GetASSFormated() + _T(","); final += wxString::Format(L"%01i",Layer);
final += End.GetASSFormated() + _T(","); final += L",";
Style.Replace(_T(","),_T(";")); final += Start.GetASSFormated() + L",";
Actor.Replace(_T(","),_T(";")); final += End.GetASSFormated() + L",";
final += Style + _T(",");
final += Actor + _T(","); Style.Replace(L",",L";");
Actor.Replace(L",",L";");
final += Style + L",";
final += Actor + L",";
final += GetMarginString(0); final += GetMarginString(0);
final += _T(","); final += L",";
final += GetMarginString(1); final += GetMarginString(1);
final += _T(","); final += L",";
final += GetMarginString(2); final += GetMarginString(2);
final += _T(","); final += L",";
Effect.Replace(_T(","),_T(";")); Effect.Replace(L",",L";");
final += Effect + _T(","); final += Effect + L",";
final += Text; final += Text;
// Make sure that final has no line breaks // Make sure that final has no line breaks
final.Replace(_T("\n"),_T("")); final.Replace(L"\n","");
final.Replace(_T("\r"),_T("")); final.Replace(L"\r","");
// Return final
return final; return final;
} }
/// @brief Get entry data
/// @return
const wxString AssDialogue::GetEntryData() { const wxString AssDialogue::GetEntryData() {
return MakeData(); return GetData(false);
} }
/// @brief Set entry data
/// @param newData
void AssDialogue::SetEntryData(wxString newData) {
}
/// @brief Get SSA version of Dialogue
/// @return
wxString AssDialogue::GetSSAText () { wxString AssDialogue::GetSSAText () {
// Prepare return GetData(true);
wxString work = _T("");
// Write all work
if (Comment) work += _T("Comment: ");
else work += _T("Dialogue: ");
work += _T("Marked=0,");
work += Start.GetASSFormated() + _T(",");
work += End.GetASSFormated() + _T(",");
Style.Replace(_T(","),_T(";"));
Actor.Replace(_T(","),_T(";"));
work += Style + _T(",");
work += Actor + _T(",");
work += GetMarginString(0);
work += _T(",");
work += GetMarginString(1);
work += _T(",");
work += GetMarginString(2);
work += _T(",");
Effect.Replace(_T(","),_T(";"));
work += Effect + _T(",");
work += Text;
return work;
} }
/// @brief Yea, I convert to ASS tags, then parse that. So sue me. -------------- Parse SRT tags
void AssDialogue::ParseSRTTags () { void AssDialogue::ParseSRTTags () {
// Search and replace // Search and replace
size_t total = 0; size_t total = 0;
@ -350,7 +300,7 @@ void AssDialogue::ParseSRTTags () {
// Open tag // Open tag
if (isOpen) { if (isOpen) {
wxString replaced = _T(""); wxString replaced;
// Color tag // Color tag
if ((pos = work.find(_T("COLOR=\""),start)) != wxString::npos) { if ((pos = work.find(_T("COLOR=\""),start)) != wxString::npos) {
@ -441,15 +391,11 @@ void AssDialogue::ParseSRTTags () {
Text.Replace(_T("}{"),_T("")); Text.Replace(_T("}{"),_T(""));
} }
/// @brief Parse ASS tags
void AssDialogue::ParseASSTags () { void AssDialogue::ParseASSTags () {
// Clear blocks
ClearBlocks(); ClearBlocks();
// Is drawing?
int drawingLevel = 0; int drawingLevel = 0;
// Loop through
const size_t len = Text.size(); const size_t len = Text.size();
size_t cur = 0; size_t cur = 0;
size_t end = 0; size_t end = 0;
@ -472,7 +418,6 @@ void AssDialogue::ParseASSTags () {
AssDialogueBlockPlain *block = new AssDialogueBlockPlain; AssDialogueBlockPlain *block = new AssDialogueBlockPlain;
block->text = work; block->text = work;
Blocks.push_back(block); Blocks.push_back(block);
} }
else { else {
@ -487,9 +432,8 @@ void AssDialogue::ParseASSTags () {
// Look for \p in block // Look for \p in block
std::vector<AssOverrideTag*>::iterator curTag; std::vector<AssOverrideTag*>::iterator curTag;
for (curTag = block->Tags.begin();curTag != block->Tags.end();curTag++) { for (curTag = block->Tags.begin();curTag != block->Tags.end();curTag++) {
AssOverrideTag *tag = *curTag; if ((*curTag)->Name == L"\\p") {
if (tag->Name == _T("\\p")) { drawingLevel = (*curTag)->Params[0]->Get<int>(0);
drawingLevel = tag->Params.at(0)->Get<int>();
} }
} }
} }
@ -535,16 +479,11 @@ void AssDialogue::ParseASSTags () {
} }
} }
/// @brief Strip tags
void AssDialogue::StripTags () { void AssDialogue::StripTags () {
static wxRegEx reg(_T("\\{[^\\{]*\\}"),wxRE_ADVANCED); Text = GetStrippedText();
reg.Replace(&Text,_T(""));
} }
/// @brief Strip a specific tag
/// @param tagName
void AssDialogue::StripTag (wxString tagName) { void AssDialogue::StripTag (wxString tagName) {
// Parse
using std::list; using std::list;
using std::vector; using std::vector;
ParseASSTags(); ParseASSTags();
@ -556,7 +495,7 @@ void AssDialogue::StripTag (wxString tagName) {
AssDialogueBlockOverride *over = dynamic_cast<AssDialogueBlockOverride*>(*cur); AssDialogueBlockOverride *over = dynamic_cast<AssDialogueBlockOverride*>(*cur);
wxString temp; wxString temp;
for (size_t i=0;i<over->Tags.size();i++) { for (size_t i=0;i<over->Tags.size();i++) {
if (over->Tags[i]->Name != tagName) temp += over->Tags[i]->ToString(); if (over->Tags[i]->Name != tagName) temp += *over->Tags[i];
} }
// Insert // Insert
@ -565,14 +504,11 @@ void AssDialogue::StripTag (wxString tagName) {
else final += (*cur)->GetText(); else final += (*cur)->GetText();
} }
// Update
ClearBlocks(); ClearBlocks();
Text = final; Text = final;
} }
/// @brief TODO: Improve this code ------------------- Convert tags to SRT
void AssDialogue::ConvertTagsToSRT () { void AssDialogue::ConvertTagsToSRT () {
// Setup
using std::list; using std::list;
using std::vector; using std::vector;
AssDialogueBlockOverride* curBlock; AssDialogueBlockOverride* curBlock;
@ -669,11 +605,10 @@ void AssDialogue::ConvertTagsToSRT () {
ClearBlocks(); ClearBlocks();
} }
/// @brief Updates text from tags
void AssDialogue::UpdateText () { void AssDialogue::UpdateText () {
using std::vector; if (Blocks.empty()) return;
Text = _T(""); Text.clear();
for (vector<AssDialogueBlock*>::iterator cur=Blocks.begin();cur!=Blocks.end();cur++) { for (std::vector<AssDialogueBlock*>::iterator cur=Blocks.begin();cur!=Blocks.end();cur++) {
if ((*cur)->GetType() == BLOCK_OVERRIDE) { if ((*cur)->GetType() == BLOCK_OVERRIDE) {
Text += _T("{"); Text += _T("{");
Text += (*cur)->GetText(); Text += (*cur)->GetText();
@ -683,10 +618,9 @@ void AssDialogue::UpdateText () {
} }
} }
/// @brief Sets margin from a string
/// @param origvalue
/// @param which
void AssDialogue::SetMarginString(const wxString origvalue,int which) { void AssDialogue::SetMarginString(const wxString origvalue,int which) {
if (which < 0 || which >= 4) throw Aegisub::InvalidMarginIdError();
// Make it numeric // Make it numeric
wxString strvalue = origvalue; wxString strvalue = origvalue;
if (!strvalue.IsNumber()) { if (!strvalue.IsNumber()) {
@ -707,14 +641,9 @@ void AssDialogue::SetMarginString(const wxString origvalue,int which) {
if (value > 9999) value = 9999; if (value > 9999) value = 9999;
// Assign // Assign
if (which < 0 || which >= 4) throw Aegisub::InvalidMarginIdError();
Margin[which] = value; Margin[which] = value;
} }
/// @brief Gets string for margin
/// @param which
/// @param pad
/// @return
wxString AssDialogue::GetMarginString(int which,bool pad) { wxString AssDialogue::GetMarginString(int which,bool pad) {
if (which < 0 || which >= 4) throw Aegisub::InvalidMarginIdError(); if (which < 0 || which >= 4) throw Aegisub::InvalidMarginIdError();
int value = Margin[which]; int value = Margin[which];
@ -735,9 +664,6 @@ void AssDialogue::ProcessParameters(AssDialogueBlockOverride::ProcessParametersC
//ClearBlocks(); //ClearBlocks();
} }
/// @brief Checks if two lines collide
/// @param target
/// @return
bool AssDialogue::CollidesWith(AssDialogue *target) { bool AssDialogue::CollidesWith(AssDialogue *target) {
if (!target) return false; if (!target) return false;
int a = Start.GetMS(); int a = Start.GetMS();
@ -747,49 +673,20 @@ bool AssDialogue::CollidesWith(AssDialogue *target) {
return ((a < c) ? (c < b) : (a < d)); return ((a < c) ? (c < b) : (a < d));
} }
/// @brief Return just the text without any overrides
/// @return
wxString AssDialogue::GetStrippedText() const { wxString AssDialogue::GetStrippedText() const {
wxString justtext = wxString(_T("")); static wxRegEx reg(_T("\\{[^\\{]*\\}"),wxRE_ADVANCED);
bool inCode = false; wxString txt(Text);
reg.Replace(&txt,_T(""));
for (size_t charindex = 0; charindex != Text.Len(); charindex++) { return txt;
if (Text[charindex] == '{') inCode = true;
else if (Text[charindex] == '}') inCode = false;
else if (!inCode) justtext = justtext + Text[charindex];
}
return justtext;
} }
/// @brief Clone
/// @return
AssEntry *AssDialogue::Clone() const { AssEntry *AssDialogue::Clone() const {
return new AssDialogue(*this); return new AssDialogue(*this);
} }
/// @brief Constructor AssDialogueBlock
AssDialogueBlock::AssDialogueBlock () {
}
/// @brief Destructor
AssDialogueBlock::~AssDialogueBlock () {
}
/// @brief Constructor AssDialogueBlockPlain
AssDialogueBlockPlain::AssDialogueBlockPlain () {
}
/// @brief Constructor AssDialogueBlockDrawing
AssDialogueBlockDrawing::AssDialogueBlockDrawing () {
}
/// @brief Multiply coordinates
/// @param mx
/// @param my
/// @param x
/// @param y
void AssDialogueBlockDrawing::TransformCoords(int mx,int my,double x,double y) { void AssDialogueBlockDrawing::TransformCoords(int mx,int my,double x,double y) {
// HACK: Implement a proper parser ffs!! // HACK: Implement a proper parser ffs!!
// Could use Spline but it'd be slower and this seems to work fine
wxStringTokenizer tkn(GetText(),_T(" "),wxTOKEN_DEFAULT); wxStringTokenizer tkn(GetText(),_T(" "),wxTOKEN_DEFAULT);
wxString cur; wxString cur;
wxString final; wxString final;
@ -825,4 +722,3 @@ void AssDialogueBlockDrawing::TransformCoords(int mx,int my,double x,double y) {
final = final.Left(final.Length()-1); final = final.Left(final.Length()-1);
text = final; text = final;
} }

View file

@ -34,10 +34,6 @@
/// @ingroup subs_storage /// @ingroup subs_storage
/// ///
////////////
// Includes
#ifndef AGI_PRE #ifndef AGI_PRE
#include <vector> #include <vector>
#endif #endif
@ -45,33 +41,15 @@
#include "ass_entry.h" #include "ass_entry.h"
#include "ass_time.h" #include "ass_time.h"
//////////////
// Prototypes
class AssOverrideParameter;
class AssOverrideTag;
class AssDialogueBlockPlain;
class AssDialogueBlockOverride;
class AssDialogueBlockDrawing;
/// DOCME
enum ASS_BlockType { enum ASS_BlockType {
/// DOCME
BLOCK_BASE, BLOCK_BASE,
/// DOCME
BLOCK_PLAIN, BLOCK_PLAIN,
/// DOCME
BLOCK_OVERRIDE, BLOCK_OVERRIDE,
/// DOCME
BLOCK_DRAWING BLOCK_DRAWING
}; };
class AssOverrideParameter;
class AssOverrideTag;
/// DOCME /// DOCME
/// @class AssDialogueBlock /// @class AssDialogueBlock
@ -97,15 +75,14 @@ enum ASS_BlockType {
/// @endverbatim /// @endverbatim
class AssDialogueBlock { class AssDialogueBlock {
public: public:
/// DOCME /// DOCME
wxString text; wxString text;
/// DOCME /// DOCME
AssDialogue *parent; AssDialogue *parent;
AssDialogueBlock(); AssDialogueBlock() { }
virtual ~AssDialogueBlock(); virtual ~AssDialogueBlock() { }
virtual ASS_BlockType GetType() = 0; virtual ASS_BlockType GetType() = 0;
@ -125,12 +102,8 @@ public:
/// DOCME /// DOCME
class AssDialogueBlockPlain : public AssDialogueBlock { class AssDialogueBlockPlain : public AssDialogueBlock {
public: public:
/// @brief DOCME
/// @return
///
ASS_BlockType GetType() { return BLOCK_PLAIN; } ASS_BlockType GetType() { return BLOCK_PLAIN; }
AssDialogueBlockPlain(); AssDialogueBlockPlain() { }
}; };
@ -142,16 +115,11 @@ public:
/// DOCME /// DOCME
class AssDialogueBlockDrawing : public AssDialogueBlock { class AssDialogueBlockDrawing : public AssDialogueBlock {
public: public:
/// DOCME /// DOCME
int Scale; int Scale;
/// @brief DOCME
/// @return
///
ASS_BlockType GetType() { return BLOCK_DRAWING; } ASS_BlockType GetType() { return BLOCK_DRAWING; }
AssDialogueBlockDrawing(); AssDialogueBlockDrawing() { }
void TransformCoords(int trans_x,int trans_y,double mult_x,double mult_y); void TransformCoords(int trans_x,int trans_y,double mult_x,double mult_y);
}; };
@ -164,7 +132,7 @@ public:
/// DOCME /// DOCME
class AssDialogueBlockOverride : public AssDialogueBlock { class AssDialogueBlockOverride : public AssDialogueBlock {
public: public:
AssDialogueBlockOverride(); AssDialogueBlockOverride() { }
~AssDialogueBlockOverride(); ~AssDialogueBlockOverride();
/// DOCME /// DOCME
@ -195,15 +163,12 @@ public:
/// ///
/// DOCME /// DOCME
class AssDialogue : public AssEntry { class AssDialogue : public AssEntry {
private: wxString GetData(bool ssa);
wxString MakeData();
public: public:
/// Contains information about each block of text /// Contains information about each block of text
std::vector<AssDialogueBlock*> Blocks; std::vector<AssDialogueBlock*> Blocks;
/// Is this a comment line? /// Is this a comment line?
bool Comment; bool Comment;
/// Layer number /// Layer number
@ -223,36 +188,54 @@ public:
/// Raw text data /// Raw text data
wxString Text; wxString Text;
/// @brief DOCME
/// @return
///
ASS_EntryType GetType() { return ENTRY_DIALOGUE; } ASS_EntryType GetType() { return ENTRY_DIALOGUE; }
bool Parse(wxString data,int version=1); // Parses raw ASS data into everything else /// @brief Parse raw ASS data into everything else
void ParseASSTags(); // Parses text to generate block information (doesn't update data) /// @param data ASS line
void ParseSRTTags(); // Converts tags to ass format and calls ParseASSTags+UpdateData /// @param version ASS version to try first (4, 4+, ASS2)
void ClearBlocks(); // Clear all blocks, ALWAYS call this after you're done processing tags /// @return Did it successfully parse?
bool Parse(wxString data,int version=1);
/// Parse text as ASS to generate block information
void ParseASSTags();
/// Parse text as SRT to generate block information
void ParseSRTTags();
/// Clear all blocks, ALWAYS call this after you're done processing tags
void ClearBlocks();
/// @brief Process parameters via callback /// @brief Process parameters via callback
/// @param callback The callback function to call per tag paramer /// @param callback The callback function to call per tag parameter
/// @param userData User data to pass to callback function /// @param userData User data to pass to callback function
void ProcessParameters(AssDialogueBlockOverride::ProcessParametersCallback callback,void *userData=NULL); // Callback to process parameters void ProcessParameters(AssDialogueBlockOverride::ProcessParametersCallback callback,void *userData=NULL);
void ConvertTagsToSRT(); // Converts tags to SRT format /// Convert ASS tags to SRT tags
void StripTags(); // Strips all tags from the text void ConvertTagsToSRT();
void StripTag(wxString tagName);// Strips a specific tag from the text /// Strip all ASS tags from the text
wxString GetStrippedText() const; // Gets text without tags void StripTags();
/// Strip a specific ASS tag from the text
void StripTag(wxString tagName);
/// Get text without tags
wxString GetStrippedText() const;
void UpdateText(); // Generates text from the override tags /// If blocks have been parsed, update the text from their current value
void UpdateText();
const wxString GetEntryData(); const wxString GetEntryData();
void SetEntryData(wxString newData); /// Do nothing
void Clear(); // Wipes all data void SetEntryData(wxString) { }
/// Synonym for ClearBlocks
void Clear();
void SetMarginString(const wxString value,int which); // Set string to a margin value (0 = left, 1 = right, 2 = vertical/top, 3 = bottom) /// @brief Set a margin
wxString GetMarginString(int which,bool pad=true); // Returns the string of a margin value (0 = left, 1 = right, 2 = vertical/top, 3 = bottom) /// @param value New value of the margin
/// @param which 0 = left, 1 = right, 2 = vertical/top, 3 = bottom
void SetMarginString(const wxString value,int which);
/// @brief Get a margin
/// @param which 0 = left, 1 = right, 2 = vertical/top, 3 = bottom
/// @param pad Pad the number to four digits
wxString GetMarginString(int which,bool pad=true);
/// Get the line as SSA rather than ASS
wxString GetSSAText(); wxString GetSSAText();
bool CollidesWith(AssDialogue *target); // Checks if two lines collide /// Does this line collide with the passed line?
bool CollidesWith(AssDialogue *target);
AssEntry *Clone() const; AssEntry *Clone() const;

View file

@ -64,8 +64,8 @@
/// @brief AssFile constructor /// @brief AssFile constructor
AssFile::AssFile () { AssFile::AssFile () {
AssOverrideTagProto::LoadProtos(); loaded = false;
Clear(); Modified = false;
} }
/// @brief AssFile destructor /// @brief AssFile destructor

View file

@ -110,7 +110,7 @@ void ParseAssKaraokeTags(const AssDialogue *line, AssKaraokeVector &syls)
syl.unstripped_text += _T("{"); syl.unstripped_text += _T("{");
brackets_open = true; brackets_open = true;
} }
syl.unstripped_text += tag->ToString(); syl.unstripped_text += *tag;
} }
} }

View file

@ -1,4 +1,5 @@
// Copyright (c) 2005, Rodrigo Braz Monteiro // Copyright (c) 2005, Rodrigo Braz Monteiro
// Copyright (c) 2010, Thomas Goyne <plorkyeran@aegisub.org>
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -45,114 +46,72 @@
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "ass_override.h" #include "ass_override.h"
#include "utils.h"
/// @brief Constructor AssOverrideParameter::AssOverrideParameter()
AssOverrideParameter::AssOverrideParameter () { : classification(PARCLASS_NORMAL)
classification = PARCLASS_NORMAL; , omitted(false)
ommited = false; {
} }
/// @brief Destructor AssOverrideParameter::AssOverrideParameter(const AssOverrideParameter &param)
AssOverrideParameter::~AssOverrideParameter () { : VariableData(param)
DeleteValue(); , classification(param.classification)
, omitted(param.omitted)
{
} }
/// @brief Copy
/// @param param
///
void AssOverrideParameter::CopyFrom (const AssOverrideParameter &param) {
*static_cast<VariableData*>(this) = static_cast<const VariableData&>(param);
classification = param.classification;
ommited = param.ommited;
}
/// @brief DOCME
/// @param param
///
void AssOverrideParameter::operator=(const AssOverrideParameter &param) { void AssOverrideParameter::operator=(const AssOverrideParameter &param) {
CopyFrom(param); DeleteValue();
new(this) AssOverrideParameter(param);
} }
/// @brief Constructor // From ass_dialogue.h
AssDialogueBlockOverride::AssDialogueBlockOverride () {
}
/// @brief Destructor
AssDialogueBlockOverride::~AssDialogueBlockOverride() { AssDialogueBlockOverride::~AssDialogueBlockOverride() {
for (size_t i=0;i<Tags.size();i++) { delete_clear(Tags);
delete Tags[i];
}
Tags.clear();
} }
/// @brief Read tags
///
void AssDialogueBlockOverride::ParseTags() { void AssDialogueBlockOverride::ParseTags() {
// Clear current vector delete_clear(Tags);
for (size_t i=0;i<Tags.size();i++) {
delete Tags[i];
}
Tags.clear();
// Fix parenthesis matching wxStringTokenizer tkn(text, L"\\", wxTOKEN_STRTOK);
while (text.Freq(_T('(')) > text.Freq(_T(')'))) {
text += _T(")");
}
// Initialize tokenizer
wxStringTokenizer tkn(text,_T("\\"),wxTOKEN_RET_EMPTY_ALL);
wxString curTag; wxString curTag;
if (text.StartsWith(_T("\\"))) curTag = _T("\\"); if (text.StartsWith(L"\\")) curTag = L"\\";
while (tkn.HasMoreTokens()) { while (tkn.HasMoreTokens()) {
//curTag will always start with a backslash after first loop - see end of loop
curTag += tkn.GetNextToken(); curTag += tkn.GetNextToken();
if (curTag == _T("\\")) continue;
// Check for parenthesis matching // Check for parenthesis matching for \t
while (curTag.Freq(_T('(')) > curTag.Freq(_T(')'))) { while (curTag.Freq(L'(') > curTag.Freq(L')') && tkn.HasMoreTokens()) {
if (!tkn.HasMoreTokens()) { curTag << L"\\" << tkn.GetNextToken();
wxLogWarning(_T("Unmatched parenthesis! Line contents: ") + parent->Text);
break;
}
curTag << _T("\\") << tkn.GetNextToken();
} }
AssOverrideTag *newTag = new AssOverrideTag; Tags.push_back(new AssOverrideTag(curTag));
newTag->SetText(curTag);
Tags.push_back(newTag);
curTag = _T("\\"); curTag = L"\\";
} }
} }
void AssDialogueBlockOverride::AddTag(wxString const& tag) { void AssDialogueBlockOverride::AddTag(wxString const& tag) {
AssOverrideTag *newTag = new AssOverrideTag; Tags.push_back(new AssOverrideTag(tag));
newTag->SetText(tag);
Tags.push_back(newTag);
} }
/// @brief Get Text representation
/// @return
///
wxString AssDialogueBlockOverride::GetText() { wxString AssDialogueBlockOverride::GetText() {
text = _T(""); text.clear();
for (std::vector<AssOverrideTag*>::iterator cur=Tags.begin();cur!=Tags.end();cur++) { for (std::vector<AssOverrideTag*>::iterator cur=Tags.begin();cur!=Tags.end();cur++) {
text += (*cur)->ToString(); text += **cur;
} }
return text; return text;
} }
void AssDialogueBlockOverride::ProcessParameters(AssDialogueBlockOverride::ProcessParametersCallback callback,void *userData) { void AssDialogueBlockOverride::ProcessParameters(AssDialogueBlockOverride::ProcessParametersCallback callback,void *userData) {
for (std::vector<AssOverrideTag*>::iterator cur=Tags.begin();cur!=Tags.end();cur++) { for (std::vector<AssOverrideTag*>::iterator cur=Tags.begin();cur!=Tags.end();cur++) {
int n = 0;
AssOverrideTag *curTag = *cur; AssOverrideTag *curTag = *cur;
// Find parameters // Find parameters
for (std::vector<AssOverrideParameter*>::iterator curParam=curTag->Params.begin();curParam!=curTag->Params.end();curParam++) { for (unsigned n = 0; n < curTag->Params.size(); n++) {
AssOverrideParameter *curPar = *curParam; AssOverrideParameter *curPar = curTag->Params[n];
if (curPar->GetType() != VARDATA_NONE && curPar->ommited == false) { if (curPar->GetType() != VARDATA_NONE && !curPar->omitted) {
// Do callback
(*callback)(curTag->Name,n,curPar,userData); (*callback)(curTag->Name,n,curPar,userData);
// Go recursive if it's a block parameter // Go recursive if it's a block parameter
@ -160,45 +119,28 @@ void AssDialogueBlockOverride::ProcessParameters(AssDialogueBlockOverride::Proce
curPar->Get<AssDialogueBlockOverride*>()->ProcessParameters(callback,userData); curPar->Get<AssDialogueBlockOverride*>()->ProcessParameters(callback,userData);
} }
} }
n++;
} }
} }
} }
/// @brief Constructor AssOverrideParamProto::AssOverrideParamProto(VariableDataType type,int opt,ASS_ParameterClass classi)
/// @param _type : type(type)
/// @param opt , optional(opt)
/// @param classi , classification(classi)
/// {
AssOverrideParamProto::AssOverrideParamProto (VariableDataType _type,int opt,ASS_ParameterClass classi) {
type = _type;
optional = opt;
classification = classi;
} }
/// @brief Destructor void AssOverrideTagProto::AddParam(VariableDataType type, ASS_ParameterClass classi, int opt) {
AssOverrideParamProto::~AssOverrideParamProto() { params.push_back(AssOverrideParamProto(type, opt, classi));
}
void AssOverrideTagProto::Set(wxString newName, VariableDataType type, ASS_ParameterClass classi, int opt) {
name = newName;
params.push_back(AssOverrideParamProto(type, opt, classi));
} }
/// DOCME static std::vector<AssOverrideTagProto> proto;
std::vector<AssOverrideTagProto> AssOverrideTagProto::proto; static void load_protos() {
static bool loaded = false;
/// DOCME
bool AssOverrideTagProto::loaded = false;
/// @brief Constructor
AssOverrideTagProto::AssOverrideTagProto() {
}
/// @brief Destructor
AssOverrideTagProto::~AssOverrideTagProto() {
}
/// @brief Load prototypes
/// @return
///
void AssOverrideTagProto::LoadProtos () {
if (loaded) return; if (loaded) return;
loaded = true; loaded = true;
@ -207,341 +149,149 @@ void AssOverrideTagProto::LoadProtos () {
// Longer tag names must appear before shorter tag names // Longer tag names must appear before shorter tag names
// \alpha proto[0].Set(L"\\alpha", VARDATA_TEXT); // \alpha
proto[i].name = _T("\\alpha"); proto[++i].Set(L"\\bord", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \bord<depth>
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT)); proto[++i].Set(L"\\xbord", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \xbord<depth>
proto[++i].Set(L"\\ybord", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \ybord<depth>
// \bord<depth> proto[++i].Set(L"\\shad", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \shad<depth>
i++; proto[++i].Set(L"\\xshad", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \xshad<depth>
proto[i].name = _T("\\bord"); proto[++i].Set(L"\\yshad", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \yshad<depth>
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE));
// \xbord<depth>
i++;
proto[i].name = _T("\\xbord");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE));
// \ybord<depth>
i++;
proto[i].name = _T("\\ybord");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE));
// \shad<depth>
i++;
proto[i].name = _T("\\shad");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE));
// \xshad<depth>
i++;
proto[i].name = _T("\\xshad");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE));
// \yshad<depth>
i++;
proto[i].name = _T("\\yshad");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE));
// \fade(<a1>,<a2>,<a3>,<t1>,<t2>,<t3>,<t4>) // \fade(<a1>,<a2>,<a3>,<t1>,<t2>,<t3>,<t4>)
i++; i++;
proto[i].name = _T("\\fade"); proto[i].name = L"\\fade";
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT)); proto[i].AddParam(VARDATA_INT);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT)); proto[i].AddParam(VARDATA_INT);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT)); proto[i].AddParam(VARDATA_INT);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START)); proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START)); proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START)); proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START)); proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START);
// \move(<x1>,<y1>,<x2>,<y2>[,<t1>,<t2>]) // \move(<x1>,<y1>,<x2>,<y2>[,<t1>,<t2>])
i++; i++;
proto[i].name = _T("\\move"); proto[i].name = L"\\move";
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X)); proto[i].AddParam(VARDATA_FLOAT,PARCLASS_ABSOLUTE_POS_X);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); proto[i].AddParam(VARDATA_FLOAT,PARCLASS_ABSOLUTE_POS_Y);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X)); proto[i].AddParam(VARDATA_FLOAT,PARCLASS_ABSOLUTE_POS_X);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); proto[i].AddParam(VARDATA_FLOAT,PARCLASS_ABSOLUTE_POS_Y);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_6,PARCLASS_RELATIVE_TIME_START)); proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_6,PARCLASS_RELATIVE_TIME_START)); proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START);
// If these are rearranged, keep rect clip and vector clip adjacent in this order // If these are rearranged, keep rect clip and vector clip adjacent in this order
// \clip(<x1>,<y1>,<x2>,<y2>) // \clip(<x1>,<y1>,<x2>,<y2>)
i++; i++;
proto[i].name = _T("\\clip"); proto[i].name = L"\\clip";
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X)); proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_X);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_Y);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X)); proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_X);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_Y);
// \clip([<scale>,]<some drawings>) // \clip([<scale>,]<some drawings>)
i++; i++;
proto[i].name = _T("\\clip"); proto[i].name = L"\\clip";
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_2,PARCLASS_NORMAL)); proto[i].AddParam(VARDATA_INT,PARCLASS_NORMAL,OPTIONAL_2);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_DRAWING)); proto[i].AddParam(VARDATA_TEXT,PARCLASS_DRAWING);
// \iclip(<x1>,<y1>,<x2>,<y2>) // \iclip(<x1>,<y1>,<x2>,<y2>)
i++; i++;
proto[i].name = _T("\\iclip"); proto[i].name = L"\\iclip";
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X)); proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_X);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_Y);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X)); proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_X);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_Y);
// \iclip([<scale>,]<some drawings>) // \iclip([<scale>,]<some drawings>)
i++; i++;
proto[i].name = _T("\\iclip"); proto[i].name = L"\\iclip";
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_2,PARCLASS_NORMAL)); proto[i].AddParam(VARDATA_INT,PARCLASS_NORMAL,OPTIONAL_2);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_DRAWING)); proto[i].AddParam(VARDATA_TEXT,PARCLASS_DRAWING);
// \fscx<percent>
i++;
proto[i].name = _T("\\fscx");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_RELATIVE_SIZE_X));
// \fscy<percent>
i++;
proto[i].name = _T("\\fscy");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_RELATIVE_SIZE_Y));
proto[++i].Set(L"\\fscx", VARDATA_FLOAT,PARCLASS_RELATIVE_SIZE_X); // \fscx<percent>
proto[++i].Set(L"\\fscy", VARDATA_FLOAT,PARCLASS_RELATIVE_SIZE_Y); // \fscy<percent>
// \pos(<x>,<y>) // \pos(<x>,<y>)
i++; i++;
proto[i].name = _T("\\pos"); proto[i].name = L"\\pos";
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X)); proto[i].AddParam(VARDATA_FLOAT,PARCLASS_ABSOLUTE_POS_X);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); proto[i].AddParam(VARDATA_FLOAT,PARCLASS_ABSOLUTE_POS_Y);
// \org(<x>,<y>) // \org(<x>,<y>)
i++; i++;
proto[i].name = _T("\\org"); proto[i].name = L"\\org";
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X)); proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_X);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y)); proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_Y);
// \pbo<y>
i++;
proto[i].name = _T("\\pbo");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y));
proto[++i].Set(L"\\pbo", VARDATA_INT,PARCLASS_ABSOLUTE_POS_Y); // \pbo<y>
// \fad(<t1>,<t2>) // \fad(<t1>,<t2>)
i++; i++;
proto[i].name = _T("\\fad"); proto[i].name = L"\\fad";
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START)); proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_END)); proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_END);
// \fsp<pixels> proto[++i].Set(L"\\fsp", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \fsp<pixels>
i++; proto[++i].Set(L"\\frx", VARDATA_FLOAT); // \frx<degrees>
proto[i].name = _T("\\fsp"); proto[++i].Set(L"\\fry", VARDATA_FLOAT); // \fry<degrees>
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE)); proto[++i].Set(L"\\frz", VARDATA_FLOAT); // \frz<degrees>
proto[++i].Set(L"\\fr", VARDATA_FLOAT); // \fr<degrees>
// \frx<degrees> proto[++i].Set(L"\\fax", VARDATA_FLOAT); // \fax<factor>
i++; proto[++i].Set(L"\\fay", VARDATA_FLOAT); // \fay<factor>
proto[i].name = _T("\\frx"); proto[++i].Set(L"\\1c", VARDATA_TEXT); // \1c&H<bbggrr>&
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL)); proto[++i].Set(L"\\2c", VARDATA_TEXT); // \2c&H<bbggrr>&
proto[++i].Set(L"\\3c", VARDATA_TEXT); // \3c&H<bbggrr>&
// \fry<degrees> proto[++i].Set(L"\\4c", VARDATA_TEXT); // \4c&H<bbggrr>&
i++; proto[++i].Set(L"\\1a", VARDATA_TEXT); // \1a&H<aa>&
proto[i].name = _T("\\fry"); proto[++i].Set(L"\\2a", VARDATA_TEXT); // \2a&H<aa>&
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL)); proto[++i].Set(L"\\3a", VARDATA_TEXT); // \3a&H<aa>&
proto[++i].Set(L"\\4a", VARDATA_TEXT); // \4a&H<aa>&
// \frz<degrees> proto[++i].Set(L"\\fe", VARDATA_TEXT); // \fe<charset>
i++; proto[++i].Set(L"\\ko", VARDATA_INT,PARCLASS_KARAOKE); // \ko<duration>
proto[i].name = _T("\\frz"); proto[++i].Set(L"\\kf", VARDATA_INT,PARCLASS_KARAOKE); // \kf<duration>
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL)); proto[++i].Set(L"\\be", VARDATA_INT); // \be<strength>
proto[++i].Set(L"\\blur", VARDATA_FLOAT); // \blur<strength>
// \fr<degrees> proto[++i].Set(L"\\fn", VARDATA_TEXT); // \fn<name>
i++; proto[++i].Set(L"\\fs+", VARDATA_FLOAT); // \fs+<size>
proto[i].name = _T("\\fr"); proto[++i].Set(L"\\fs-", VARDATA_FLOAT); // \fs-<size>
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL)); proto[++i].Set(L"\\fs", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \fs<size>
proto[++i].Set(L"\\an", VARDATA_INT); // \an<alignment>
// \fax<factor> proto[++i].Set(L"\\c", VARDATA_TEXT); // \c&H<bbggrr>&
i++; proto[++i].Set(L"\\b", VARDATA_INT); // \b<0/1/weight>
proto[i].name = _T("\\fax"); proto[++i].Set(L"\\i", VARDATA_BOOL); // \i<0/1>
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL)); proto[++i].Set(L"\\u", VARDATA_BOOL); // \u<0/1>
proto[++i].Set(L"\\s", VARDATA_BOOL); // \s<0/1>
// \fay<factor> proto[++i].Set(L"\\a", VARDATA_INT); // \a<alignment>
i++; proto[++i].Set(L"\\k", VARDATA_INT,PARCLASS_KARAOKE); // \k<duration>
proto[i].name = _T("\\fay"); proto[++i].Set(L"\\K", VARDATA_INT,PARCLASS_KARAOKE); // \K<duration>
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL)); proto[++i].Set(L"\\q", VARDATA_INT); // \q<0-3>
proto[++i].Set(L"\\p", VARDATA_INT); // \p<n>
// \1c&H<bbggrr>& proto[++i].Set(L"\\r", VARDATA_TEXT); // \r[<name>]
i++;
proto[i].name = _T("\\1c");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \2c&H<bbggrr>&
i++;
proto[i].name = _T("\\2c");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \3c&H<bbggrr>&
i++;
proto[i].name = _T("\\3c");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \4c&H<bbggrr>&
i++;
proto[i].name = _T("\\4c");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \1a&H<aa>&
i++;
proto[i].name = _T("\\1a");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \2a&H<aa>&
i++;
proto[i].name = _T("\\2a");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \3a&H<aa>&
i++;
proto[i].name = _T("\\3a");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \4a&H<aa>&
i++;
proto[i].name = _T("\\4a");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \fe<charset>
i++;
proto[i].name = _T("\\fe");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \ko<duration>
i++;
proto[i].name = _T("\\ko");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_KARAOKE));
// \kf<duration>
i++;
proto[i].name = _T("\\kf");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_KARAOKE));
// \be<strength>
i++;
proto[i].name = _T("\\be");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \blur<strength>
i++;
proto[i].name = _T("\\blur");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \fn<name>
i++;
proto[i].name = _T("\\fn");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \fs+<size>
i++;
proto[i].name = _T("\\fs+");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \fs-<size>
i++;
proto[i].name = _T("\\fs-");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \fs<size>
i++;
proto[i].name = _T("\\fs");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE));
// \an<alignment>
i++;
proto[i].name = _T("\\an");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \c&H<bbggrr>&
i++;
proto[i].name = _T("\\c");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \b<0/1/weight>
i++;
proto[i].name = _T("\\b");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_1,PARCLASS_NORMAL));
proto[i].params.back().defaultValue.Set<bool>(false);
// \i<0/1>
i++;
proto[i].name = _T("\\i");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_BOOL,OPTIONAL_1,PARCLASS_NORMAL));
proto[i].params.back().defaultValue.Set<bool>(false);
// \u<0/1>
i++;
proto[i].name = _T("\\u");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_BOOL,OPTIONAL_1,PARCLASS_NORMAL));
proto[i].params.back().defaultValue.Set<bool>(false);
// \s<0/1>
i++;
proto[i].name = _T("\\s");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_BOOL,OPTIONAL_1,PARCLASS_NORMAL));
proto[i].params.back().defaultValue.Set<bool>(false);
// \a<alignment>
i++;
proto[i].name = _T("\\a");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \k<duration>
i++;
proto[i].name = _T("\\k");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_KARAOKE));
// \K<duration>
i++;
proto[i].name = _T("\\K");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_KARAOKE));
// \q<0-3>
i++;
proto[i].name = _T("\\q");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \p<n>
i++;
proto[i].name = _T("\\p");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_NORMAL));
// \r[<name>]
i++;
proto[i].name = _T("\\r");
proto[i].params.push_back(AssOverrideParamProto(VARDATA_TEXT,OPTIONAL_1,PARCLASS_NORMAL));
// \t([<t1>,<t2>,][<accel>,]<style modifiers>) // \t([<t1>,<t2>,][<accel>,]<style modifiers>)
i++; i++;
proto[i].name = _T("\\t"); proto[i].name = L"\\t";
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_3 | OPTIONAL_4,PARCLASS_RELATIVE_TIME_START)); proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START,OPTIONAL_3 | OPTIONAL_4);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_3 | OPTIONAL_4,PARCLASS_RELATIVE_TIME_START)); proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START,OPTIONAL_3 | OPTIONAL_4);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_FLOAT,OPTIONAL_2 | OPTIONAL_4,PARCLASS_NORMAL)); proto[i].AddParam(VARDATA_FLOAT,PARCLASS_NORMAL,OPTIONAL_2 | OPTIONAL_4);
proto[i].params.push_back(AssOverrideParamProto(VARDATA_BLOCK,NOT_OPTIONAL,PARCLASS_NORMAL)); proto[i].AddParam(VARDATA_BLOCK);
} }
/// @brief Constructor AssOverrideTag::AssOverrideTag() : valid(false) { }
AssOverrideTag::AssOverrideTag () { AssOverrideTag::AssOverrideTag(wxString text) {
valid = false; SetText(text);
} }
/// @brief Destructor
AssOverrideTag::~AssOverrideTag () { AssOverrideTag::~AssOverrideTag () {
Clear(); delete_clear(Params);
} }
/// @brief Clear
void AssOverrideTag::Clear() { void AssOverrideTag::Clear() {
for (std::vector<AssOverrideParameter*>::iterator cur=Params.begin();cur!=Params.end();cur++) { delete_clear(Params);
delete *cur;
}
Params.clear();
Params.reserve(6); Params.reserve(6);
valid = false; valid = false;
} }
/// @brief Parses text and sets tag
/// @param text
void AssOverrideTag::SetText(const wxString &text) { void AssOverrideTag::SetText(const wxString &text) {
// Determine name load_protos();
for (AssOverrideTagProto::iterator cur=AssOverrideTagProto::proto.begin();cur!=AssOverrideTagProto::proto.end();cur++) { for (AssOverrideTagProto::iterator cur=proto.begin();cur!=proto.end();cur++) {
if (text.StartsWith(cur->name)) { if (text.StartsWith(cur->name)) {
Name = cur->name; Name = cur->name;
ParseParameters(text.Mid(Name.length()), cur); ParseParameters(text.Mid(Name.length()), cur);
@ -554,37 +304,28 @@ void AssOverrideTag::SetText (const wxString &text) {
valid = false; valid = false;
} }
/// @brief Checks if it is valid
/// @return
///
bool AssOverrideTag::IsValid() { bool AssOverrideTag::IsValid() {
return valid; return valid;
} }
/// @brief Parses the parameters for the ass override tag std::vector<wxString> tokenize(const wxString &text) {
/// @param text All text between the name and the next \ or the end of the override block std::vector<wxString> paramList;
///
void AssOverrideTag::ParseParameters(const wxString &text, AssOverrideTagProto::iterator proto) {
Clear();
// Tokenize text, attempting to find all parameters
wxArrayString paramList;
paramList.reserve(6); paramList.reserve(6);
wxString work;
{ if (text.empty()) {
if (text.IsEmpty() || text[0] != _T('(')) { return paramList;
// There's just one (or none at all) parameter (because there's no parantheses) }
if (text[0] != L'(') {
// There's just one parameter (because there's no parentheses)
// This means text is all our parameters // This means text is all our parameters
wxString param(text); wxString param(text);
paramList.Add(param.Trim(true).Trim(false)); paramList.push_back(param.Trim(true).Trim(false));
// Only using goto here to avoid yet another nested block (keeps the code cleaner!) return paramList;
goto end_tokenizing;
} }
// Ok, so there are parantheses used here, so there may be more than one parameter // Ok, so there are parentheses used here, so there may be more than one parameter
// Enter fullscale parsing! // Enter fullscale parsing!
size_t i = 0, textlen = text.Length(); size_t i = 0, textlen = text.size();
size_t start = 0; size_t start = 0;
int parDepth = 1; int parDepth = 1;
while (i < textlen && parDepth > 0) { while (i < textlen && parDepth > 0) {
@ -599,11 +340,11 @@ void AssOverrideTag::ParseParameters(const wxString &text, AssOverrideTagProto::
else if (c == _T(')')) { else if (c == _T(')')) {
parDepth--; parDepth--;
if (parDepth < 0) { if (parDepth < 0) {
wxLogWarning(_T("Unmatched parenthesis near '%s'!\nTag-parsing incomplete."), text.SubString(i, 10).c_str()); wxLogWarning(L"Unmatched parenthesis near '%s'!\nTag-parsing incomplete.", text.SubString(i, 10).c_str());
goto end_tokenizing; return paramList;
} }
else if (parDepth == 0) { else if (parDepth == 0) {
// We just ate the paranthesis ending this parameter block // We just ate the parenthesis ending this parameter block
// Make sure it doesn't get included in the parameter text // Make sure it doesn't get included in the parameter text
break; break;
} }
@ -611,98 +352,76 @@ void AssOverrideTag::ParseParameters(const wxString &text, AssOverrideTagProto::
i++; i++;
} }
// i now points to the first character not member of this parameter // i now points to the first character not member of this parameter
work = text.SubString(start, i-1); paramList.push_back(text.SubString(start, i-1).Trim(true).Trim(false));
work.Trim(true).Trim(false);
paramList.Add(work);
//LOG_D("subtitle/ass/override" << "Got parameter: << work.c_str();
} }
if (i+1 < textlen) { if (i+1 < textlen) {
// There's some additional garbage after the parantheses // There's some additional garbage after the parentheses
// Just add it in for completeness // Just add it in for completeness
paramList.Add(text.Mid(i+1)); paramList.push_back(text.Mid(i+1));
} }
} return paramList;
// 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;
} }
void AssOverrideTag::ParseParameters(const wxString &text, AssOverrideTagProto::iterator proto) {
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 prototype in the list // vector (i)clip is the second clip prototype in the list
if ((Name == _T("\\clip") || Name == _T("\\iclip")) && totalPars != 4) { if ((Name == L"\\clip" || Name == L"\\iclip") && totalPars != 4) {
++proto; ++proto;
} }
// Get parameters unsigned curPar = 0;
size_t n=0; for (size_t n = 0; n < proto->params.size(); n++) {
wxString curtok = _T("");
if (curPar < (signed)totalPars) {
curtok = paramList[curPar];
curPar++;
}
// For each parameter
while (n < proto->params.size()) {
AssOverrideParamProto *curproto = &proto->params[n]; AssOverrideParamProto *curproto = &proto->params[n];
bool isDefault = false;
n++;
// Create parameter // Create parameter
AssOverrideParameter *newparam = new AssOverrideParameter; AssOverrideParameter *newparam = new AssOverrideParameter;
newparam->classification = curproto->classification; newparam->classification = curproto->classification;
Params.push_back(newparam); Params.push_back(newparam);
// Check if it's optional and not set (set to default) // Check if it's optional and not present
if (!(curproto->optional & parsFlag)) { if (!(curproto->optional & parsFlag) || curPar >= totalPars) {
if (curproto->defaultValue.GetType() != VARDATA_NONE) { newparam->omitted = true;
isDefault = true; continue;
newparam->CopyFrom(curproto->defaultValue); }
}
newparam->ommited = true; wxString curtok = paramList[curPar++];
// This parameter doesn't really count against the number of parsed parameters,
// since it's left out. Don't count it. if (curtok.empty()) {
curPar--; curPar++;
continue;
} }
if (isDefault == false && curtok.length() > 0) {
wxChar firstChar = curtok[0]; wxChar firstChar = curtok[0];
bool auto4 = (firstChar == _T('!') || firstChar == _T('$') || firstChar == _T('%')) && curproto->type != VARDATA_BLOCK; bool auto4 = (firstChar == _T('!') || firstChar == _T('$') || firstChar == _T('%')) && curproto->type != VARDATA_BLOCK;
if (auto4) { if (auto4) {
newparam->Set(curtok); newparam->Set(curtok);
} }
else { else {
// Determine parameter type and set value
switch (curproto->type) { switch (curproto->type) {
case VARDATA_INT: { case VARDATA_INT: {
long temp = 0; long temp;
curtok.ToLong(&temp); curtok.ToLong(&temp);
newparam->Set<int>(temp); newparam->Set<int>(temp);
break; break;
} }
case VARDATA_FLOAT: { case VARDATA_FLOAT: {
double temp = 0.0; double temp;
curtok.ToDouble(&temp); curtok.ToDouble(&temp);
newparam->Set<double>(temp); newparam->Set(temp);
break; break;
} }
case VARDATA_TEXT: case VARDATA_TEXT:
newparam->Set(curtok); newparam->Set(curtok);
break; break;
case VARDATA_BOOL: { case VARDATA_BOOL: {
long temp = false; long temp;
curtok.ToLong(&temp); curtok.ToLong(&temp);
newparam->Set<bool>(temp != 0); newparam->Set<bool>(temp != 0);
break; break;
@ -718,49 +437,35 @@ end_tokenizing:
break; 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("");
}
} }
} }
/// @brief Get string AssOverrideTag::operator wxString() {
wxString AssOverrideTag::ToString() {
// Start with name
wxString result = Name; wxString result = Name;
// Determine if it needs parentheses // Determine if it needs parentheses
bool parenthesis = false; bool parentheses =
if (Name == _T("\\t") || Name == L"\\t" ||
Name == _T("\\pos") || Name == L"\\pos" ||
Name == _T("\\fad") || Name == L"\\fad" ||
Name == _T("\\org") || Name == L"\\org" ||
Name == _T("\\clip") || Name == L"\\clip" ||
Name == _T("\\iclip") || Name == L"\\iclip" ||
Name == _T("\\move") || Name == L"\\move" ||
Name == _T("\\fade")) parenthesis = true; Name == L"\\fade";
if (parenthesis) result += _T("("); if (parentheses) result += L"(";
// Add parameters // Add parameters
int n = 0; bool any = false;
for (std::vector<AssOverrideParameter*>::iterator cur=Params.begin();cur!=Params.end();cur++) { for (std::vector<AssOverrideParameter*>::iterator cur=Params.begin();cur!=Params.end();cur++) {
if ((*cur)->GetType() != VARDATA_NONE && (*cur)->ommited == false) { if ((*cur)->GetType() != VARDATA_NONE && !(*cur)->omitted) {
result += (*cur)->Get<wxString>(); result += (*cur)->Get<wxString>();
result += _T(","); result += L",";
n++; any = true;
} }
} }
if (n > 0) result = result.Left(result.Length()-1); if (any) result = result.Left(result.Length()-1);
// Finish if (parentheses) result += L")";
if (parenthesis) result += _T(")");
return result; return result;
} }

View file

@ -40,142 +40,88 @@
#include "variable_data.h" #include "variable_data.h"
class AssDialogueBlockOverride; /// Type of parameter; probably only used by the resample tool
/// DOCME
enum ASS_ParameterClass { enum ASS_ParameterClass {
/// DOCME
PARCLASS_NORMAL, PARCLASS_NORMAL,
/// DOCME
PARCLASS_ABSOLUTE_SIZE, PARCLASS_ABSOLUTE_SIZE,
/// DOCME
PARCLASS_ABSOLUTE_POS_X, PARCLASS_ABSOLUTE_POS_X,
/// DOCME
PARCLASS_ABSOLUTE_POS_Y, PARCLASS_ABSOLUTE_POS_Y,
/// DOCME
PARCLASS_RELATIVE_SIZE_X, PARCLASS_RELATIVE_SIZE_X,
/// DOCME
PARCLASS_RELATIVE_SIZE_Y, PARCLASS_RELATIVE_SIZE_Y,
/// DOCME
PARCLASS_RELATIVE_TIME_START, PARCLASS_RELATIVE_TIME_START,
/// DOCME
PARCLASS_RELATIVE_TIME_END, PARCLASS_RELATIVE_TIME_END,
/// DOCME
PARCLASS_KARAOKE, PARCLASS_KARAOKE,
/// DOCME
PARCLASS_DRAWING PARCLASS_DRAWING
}; };
/// DOCME /// The parameter is absent unless the total number of parameters is the
/// indicated number. Note that only arguments not at the end need to be marked
/// as optional; this is just to know which parameters to skip when there are
/// earlier optional arguments
enum ASS_ParameterOptional { enum ASS_ParameterOptional {
/// DOCME
NOT_OPTIONAL = 0xFF, NOT_OPTIONAL = 0xFF,
/// DOCME
OPTIONAL_0 = 0x00,
/// DOCME
OPTIONAL_1 = 0x01, OPTIONAL_1 = 0x01,
/// DOCME
OPTIONAL_2 = 0x02, OPTIONAL_2 = 0x02,
/// DOCME
OPTIONAL_3 = 0x04, OPTIONAL_3 = 0x04,
/// DOCME
OPTIONAL_4 = 0x08, OPTIONAL_4 = 0x08,
/// DOCME
OPTIONAL_5 = 0x10, OPTIONAL_5 = 0x10,
/// DOCME
OPTIONAL_6 = 0x20, OPTIONAL_6 = 0x20,
/// DOCME
OPTIONAL_7 = 0x40 OPTIONAL_7 = 0x40
}; };
/// DOCME /// DOCME
/// @class AssOverrideParameter /// @class AssOverrideParameter
/// @brief DOCME /// @brief A single parameter to an override tag
///
/// DOCME
class AssOverrideParameter : public VariableData { class AssOverrideParameter : public VariableData {
public: public:
/// Type of parameter
/// DOCME
ASS_ParameterClass classification; ASS_ParameterClass classification;
/// DOCME /// Is the parameter's value actually given?
bool ommited; bool omitted;
AssOverrideParameter(); AssOverrideParameter();
~AssOverrideParameter(); AssOverrideParameter(const AssOverrideParameter&);
void operator=(const AssOverrideParameter &param); void operator=(const AssOverrideParameter &param);
void CopyFrom (const AssOverrideParameter &param);
}; };
/// DOCME /// DOCME
/// @class AssOverrideParamProto /// @class AssOverrideParamProto
/// @brief DOCME /// @brief Prototype of a single override parameter
/// struct AssOverrideParamProto {
/// DOCME /// ASS_ParameterOptional
class AssOverrideParamProto {
public:
/// DOCME
int optional; int optional;
/// DOCME /// Type of this parameter
VariableDataType type; VariableDataType type;
/// DOCME /// Semantic type of this parameter
AssOverrideParameter defaultValue;
/// DOCME
ASS_ParameterClass classification; ASS_ParameterClass classification;
AssOverrideParamProto (VariableDataType _type,int opt=NOT_OPTIONAL,ASS_ParameterClass classi=PARCLASS_NORMAL); AssOverrideParamProto (VariableDataType type, int opt=NOT_OPTIONAL, ASS_ParameterClass classi=PARCLASS_NORMAL);
~AssOverrideParamProto();
}; };
/// DOCME /// DOCME
/// @class AssOverrideTagProto /// @class AssOverrideTagProto
/// @brief DOCME /// @brief DOCME
/// struct AssOverrideTagProto {
/// DOCME /// Name of the tag, with slash
class AssOverrideTagProto {
public:
/// DOCME
wxString name; wxString name;
/// Parameters to this tag
/// DOCME
std::vector<AssOverrideParamProto> params; std::vector<AssOverrideParamProto> params;
/// DOCME
static std::vector<AssOverrideTagProto> proto;
/// DOCME
static bool loaded;
static void LoadProtos();
typedef std::vector<AssOverrideTagProto>::iterator iterator; typedef std::vector<AssOverrideTagProto>::iterator iterator;
AssOverrideTagProto(); /// @brief Add a parameter to this tag prototype
~AssOverrideTagProto(); /// @param type Data type of the parameter
/// @param classi Semantic type of the parameter
/// @param opt Situations in which this parameter is present
void AddParam(VariableDataType type, ASS_ParameterClass classi = PARCLASS_NORMAL, int opt = NOT_OPTIONAL);
/// @brief Convenience function for single-argument tags
/// @param name Name of the tag, with slash
/// @param type Data type of the parameter
/// @param classi Semantic type of the parameter
/// @param opt Situations in which this parameter is present
void Set(wxString name, VariableDataType type, ASS_ParameterClass classi = PARCLASS_NORMAL, int opt = NOT_OPTIONAL);
}; };
/// DOCME /// DOCME
@ -184,25 +130,21 @@ public:
/// ///
/// DOCME /// DOCME
class AssOverrideTag { class AssOverrideTag {
private:
/// DOCME
bool valid; bool valid;
public: public:
/// DOCME
wxString Name; wxString Name;
/// DOCME
std::vector <AssOverrideParameter*> Params; std::vector <AssOverrideParameter*> Params;
AssOverrideTag(); AssOverrideTag();
AssOverrideTag(wxString text);
~AssOverrideTag(); ~AssOverrideTag();
bool IsValid(); bool IsValid();
/// @brief Parses the parameters for the ass override tag
/// @param text All text between the name and the next \ or the end of the override block
void ParseParameters(const wxString &text, AssOverrideTagProto::iterator proto); void ParseParameters(const wxString &text, AssOverrideTagProto::iterator proto);
void Clear(); void Clear();
void SetText(const wxString &text); void SetText(const wxString &text);
wxString ToString(); operator wxString();
}; };

View file

@ -946,7 +946,7 @@ namespace Automation4 {
ktext += _T("{"); ktext += _T("{");
brackets_open = true; brackets_open = true;
} }
ktext += tag->ToString(); ktext += *tag;
} }
} }

View file

@ -1290,7 +1290,7 @@ void SubsEditBox::SetOverride (wxString tagname,wxString preValue,int forcePos,b
//if (insert.Contains(override->Tags.at(i)->Name)) { //if (insert.Contains(override->Tags.at(i)->Name)) {
wxString name = override->Tags.at(i)->Name; wxString name = override->Tags.at(i)->Name;
if (insertTags.Index(name) != wxNOT_FOUND || removeTag == name) { if (insertTags.Index(name) != wxNOT_FOUND || removeTag == name) {
shift -= override->Tags.at(i)->ToString().Length(); shift -= ((wxString)*override->Tags.at(i)).Length();
delete override->Tags.at(i); delete override->Tags.at(i);
override->Tags.erase(override->Tags.begin() + i); override->Tags.erase(override->Tags.begin() + i);
i--; i--;
@ -1329,7 +1329,7 @@ void SubsEditBox::SetOverride (wxString tagname,wxString preValue,int forcePos,b
for (size_t i=0;i<override->Tags.size()-nInserted;i++) { for (size_t i=0;i<override->Tags.size()-nInserted;i++) {
wxString name = override->Tags.at(i)->Name; wxString name = override->Tags.at(i)->Name;
if (insert.Contains(name) || removeTag == name) { if (insert.Contains(name) || removeTag == name) {
shift -= override->Tags.at(i)->ToString().Length(); shift -= ((wxString)*override->Tags.at(i)).Length();
override->Tags.erase(override->Tags.begin() + i); override->Tags.erase(override->Tags.begin() + i);
i--; i--;
} }

View file

@ -108,3 +108,15 @@ static FORCEINLINE int ClampSignedInteger32(int x,int min,int max) {
x += max; x += max;
return x; return x;
} }
struct delete_ptr {
template<class T>
void operator()(T* ptr) const {
delete ptr;
}
};
template<class T>
void delete_clear(T& container) {
std::for_each(container.begin(), container.end(), delete_ptr());
container.clear();
}

View file

@ -117,6 +117,9 @@ public:
template<class T> void Set(T param); template<class T> void Set(T param);
void ResetWith(wxString value); void ResetWith(wxString value);
template<class T> T Get() const; template<class T> T Get() const;
template<class T> T Get(T def) const {
return value ? Get<T>() : def;
}
void operator= (const VariableData &param); void operator= (const VariableData &param);
}; };