diff --git a/aegisub/build/Aegisub/Aegisub.vcxproj b/aegisub/build/Aegisub/Aegisub.vcxproj index a3e0bf1a2..e0a060076 100644 --- a/aegisub/build/Aegisub/Aegisub.vcxproj +++ b/aegisub/build/Aegisub/Aegisub.vcxproj @@ -256,6 +256,7 @@ + diff --git a/aegisub/build/Aegisub/Aegisub.vcxproj.filters b/aegisub/build/Aegisub/Aegisub.vcxproj.filters index 7a6fdb691..ef0128fb1 100644 --- a/aegisub/build/Aegisub/Aegisub.vcxproj.filters +++ b/aegisub/build/Aegisub/Aegisub.vcxproj.filters @@ -684,6 +684,10 @@ Features\Autosave + + + ASS + diff --git a/aegisub/src/ass_attachment.cpp b/aegisub/src/ass_attachment.cpp index 91edd812e..a5d43fd0b 100644 --- a/aegisub/src/ass_attachment.cpp +++ b/aegisub/src/ass_attachment.cpp @@ -46,8 +46,7 @@ #include AssAttachment::AssAttachment(wxString const& name, AssEntryGroup group) -: AssEntry(wxString()) -, data(new std::vector) +: data(new std::vector) , filename(name) , group(group) { diff --git a/aegisub/src/ass_dialogue.cpp b/aegisub/src/ass_dialogue.cpp index 77b3463f6..caa664ba6 100644 --- a/aegisub/src/ass_dialogue.cpp +++ b/aegisub/src/ass_dialogue.cpp @@ -55,8 +55,7 @@ std::size_t hash_value(wxString const& s) { } AssDialogue::AssDialogue() -: AssEntry(wxString()) -, Comment(false) +: Comment(false) , Layer(0) , Start(0) , End(5000) @@ -66,8 +65,7 @@ AssDialogue::AssDialogue() } AssDialogue::AssDialogue(AssDialogue const& that) -: AssEntry(wxString()) -, Comment(that.Comment) +: Comment(that.Comment) , Layer(that.Layer) , Start(that.Start) , End(that.End) @@ -80,8 +78,7 @@ AssDialogue::AssDialogue(AssDialogue const& that) } AssDialogue::AssDialogue(wxString const& data) -: AssEntry(wxString()) -, Comment(false) +: Comment(false) , Layer(0) , Start(0) , End(5000) diff --git a/aegisub/src/ass_dialogue.h b/aegisub/src/ass_dialogue.h index 1d2099887..b9cf98fab 100644 --- a/aegisub/src/ass_dialogue.h +++ b/aegisub/src/ass_dialogue.h @@ -163,8 +163,6 @@ public: /// Update the text of the line from parsed blocks void UpdateText(boost::ptr_vector& blocks); const wxString GetEntryData() const override; - /// Do nothing - void SetEntryData(wxString const&) override { } template void SetMarginString(wxString const& value) { SetMarginString(value, which);} diff --git a/aegisub/src/ass_entry.cpp b/aegisub/src/ass_entry.cpp index c90bd13a6..8eb684594 100644 --- a/aegisub/src/ass_entry.cpp +++ b/aegisub/src/ass_entry.cpp @@ -1,29 +1,16 @@ -// Copyright (c) 2005, Rodrigo Braz Monteiro -// All rights reserved. +// Copyright (c) 2012, Thomas Goyne // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. // -// * 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. +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // Aegisub Project http://www.aegisub.org/ @@ -36,15 +23,6 @@ #include "ass_entry.h" -wxString AssEntry::GetSSAText() const { - if (data.Lower() == "scripttype: v4.00+") return "ScriptType: v4.00"; - return GetEntryData(); -} - -AssEntry *AssEntry::Clone() const { - return new AssEntry(data); -} - wxString const& AssEntry::GroupHeader(bool ssa) const { static wxString ass_headers[] = { "[Script Info]", diff --git a/aegisub/src/ass_entry.h b/aegisub/src/ass_entry.h index 3e837bad1..a24c045d9 100644 --- a/aegisub/src/ass_entry.h +++ b/aegisub/src/ass_entry.h @@ -48,29 +48,21 @@ enum AssEntryGroup { }; class AssEntry : public boost::intrusive::make_list_base_hook >::type { - /// Raw data, exactly the same line that appears on the .ass (note that this will be in ass even if source wasn't) - wxString data; - public: - AssEntry(wxString const& data) : data(data) { } virtual ~AssEntry() { } /// Create a copy of this entry - virtual AssEntry *Clone() const; + virtual AssEntry *Clone() const=0; /// Section of the file this entry belongs to - virtual AssEntryGroup Group() const { return ENTRY_INFO; } + virtual AssEntryGroup Group() const=0; /// ASS or SSA Section header for this entry's group wxString const& GroupHeader(bool ssa=false) const; /// @brief Get this line's raw entry data in ASS format - virtual const wxString GetEntryData() const { return data; } - - /// @brief Set this line's raw entry data - /// @param newData New raw entry data - virtual void SetEntryData(wxString const& newData) { data = newData; } + virtual const wxString GetEntryData() const=0; /// Get this line in SSA format - virtual wxString GetSSAText() const; + virtual wxString GetSSAText() const { return GetEntryData(); } }; diff --git a/aegisub/src/ass_file.cpp b/aegisub/src/ass_file.cpp index 276f6154c..2ba29a9cc 100644 --- a/aegisub/src/ass_file.cpp +++ b/aegisub/src/ass_file.cpp @@ -46,6 +46,7 @@ #include "ass_attachment.h" #include "ass_dialogue.h" +#include "ass_info.h" #include "ass_override.h" #include "ass_style.h" #include "compat.h" @@ -218,16 +219,16 @@ void AssFile::LoadDefault(bool defline) { Clear(); // Write headers - Line.push_back(*new AssEntry("Title: Default Aegisub file")); - Line.push_back(*new AssEntry("ScriptType: v4.00+")); - Line.push_back(*new AssEntry("WrapStyle: 0")); - Line.push_back(*new AssEntry("ScaledBorderAndShadow: yes")); - Line.push_back(*new AssEntry("Collisions: Normal")); + Line.push_back(*new AssInfo("Title", "Default Aegisub file")); + Line.push_back(*new AssInfo("ScriptType", "v4.00+")); + Line.push_back(*new AssInfo("WrapStyle", "0")); + Line.push_back(*new AssInfo("ScaledBorderAndShadow", "yes")); + Line.push_back(*new AssInfo("Collisions", "Normal")); if (!OPT_GET("Subtitle/Default Resolution/Auto")->GetBool()) { - Line.push_back(*new AssEntry(wxString::Format("PlayResX: %" PRId64, OPT_GET("Subtitle/Default Resolution/Width")->GetInt()))); - Line.push_back(*new AssEntry(wxString::Format("PlayResY: %" PRId64, OPT_GET("Subtitle/Default Resolution/Height")->GetInt()))); + Line.push_back(*new AssInfo("PlayResX", wxString::Format("%" PRId64, OPT_GET("Subtitle/Default Resolution/Width")->GetInt()))); + Line.push_back(*new AssInfo("PlayResY", wxString::Format("%" PRId64, OPT_GET("Subtitle/Default Resolution/Height")->GetInt()))); } - Line.push_back(*new AssEntry("YCbCr Matrix: None")); + Line.push_back(*new AssInfo("YCbCr Matrix", "None")); Line.push_back(*new AssStyle); @@ -263,7 +264,7 @@ AssFile& AssFile::operator=(AssFile from) { return *this; } -void AssFile::InsertLine( AssEntry *entry) { +void AssFile::InsertLine(AssEntry *entry) { if (Line.empty()) { Line.push_back(*entry); return; @@ -297,17 +298,10 @@ void AssFile::InsertAttachment(wxString filename) { wxString AssFile::GetScriptInfo(wxString key) const { key.MakeLower(); - key += ":"; - bool GotIn = false; - for (auto const& line : Line) { - if (line.Group() == ENTRY_INFO) { - GotIn = true; - wxString curText = line.GetEntryData(); - if (curText.Lower().StartsWith(key)) - return curText.Mid(key.size()).Trim(true).Trim(false); - } - else if (GotIn) return ""; + for (const auto info : Line | agi::of_type()) { + if (key == info->Key().Lower()) + return info->Value(); } return ""; @@ -320,40 +314,18 @@ int AssFile::GetScriptInfoAsInt(wxString const& key) const { } void AssFile::SetScriptInfo(wxString const& key, wxString const& value) { - wxString search_key = key.Lower() + ":"; - size_t key_size = search_key.size(); - entryIter script_info_end; - bool found_script_info = false; - - for (auto& line : Line) { - if (line.Group() == ENTRY_INFO) { - found_script_info = true; - wxString cur_text = line.GetEntryData().Left(key_size).Lower(); - - if (cur_text == search_key) { - if (value.empty()) - delete &line; - else - line.SetEntryData(key + ": " + value); - return; - } - script_info_end = Line.iterator_to(line); - } - else if (found_script_info) { - if (value.size()) - Line.insert(script_info_end, *new AssEntry(key + ": " + value)); + wxString lower_key = key.Lower(); + for (auto info : Line | agi::of_type()) { + if (lower_key == info->Key().Lower()) { + if (value.empty()) + delete info; + else + info->SetValue(value); return; } } - // Found a script info section, but not this key or anything after it, - // so add it at the end of the file - if (found_script_info) - Line.push_back(*new AssEntry(key + ": " + value)); - // Script info section not found, so add it at the beginning of the file - else { - Line.push_front(*new AssEntry(key + ": " + value)); - } + InsertLine(new AssInfo(key, value)); } void AssFile::GetResolution(int &sw,int &sh) const { diff --git a/aegisub/src/ass_info.h b/aegisub/src/ass_info.h new file mode 100644 index 000000000..8601984f6 --- /dev/null +++ b/aegisub/src/ass_info.h @@ -0,0 +1,36 @@ +// Copyright (c) 2012, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ + +#include "ass_entry.h" + +class AssInfo : public AssEntry { + wxString key; + wxString value; + +public: + AssInfo(AssInfo const& o) : key(o.key), value(o.value) { } + AssInfo(wxString const& line) : key(line.BeforeFirst(':').Trim()), value(line.AfterFirst(':').Trim(false)) { } + AssInfo(wxString const& key, wxString const& value) : key(key), value(value) { } + + AssEntry *Clone() const override { return new AssInfo(*this); } + AssEntryGroup Group() const override { return ENTRY_INFO; } + const wxString GetEntryData() const override { return key + ":" + value; } + wxString GetSSAText() const override { return key.Lower() == "scripttype: v4.00+" ? "ScriptType: v4.00" : GetEntryData(); } + + wxString Key() const { return key; } + wxString Value() const { return value; } + void SetValue(wxString const& new_value) { value = new_value; } +}; diff --git a/aegisub/src/ass_parser.cpp b/aegisub/src/ass_parser.cpp index e06b08c58..5bbc266f0 100644 --- a/aegisub/src/ass_parser.cpp +++ b/aegisub/src/ass_parser.cpp @@ -19,6 +19,7 @@ #include "ass_attachment.h" #include "ass_dialogue.h" #include "ass_file.h" +#include "ass_info.h" #include "ass_style.h" #include "subtitle_format.h" @@ -88,7 +89,7 @@ void AssParser::ParseScriptInfoLine(wxString const& data) { } } - InsertLine(new AssEntry(data)); + InsertLine(new AssInfo(data)); } void AssParser::ParseEventLine(wxString const& data) { diff --git a/aegisub/src/ass_style.cpp b/aegisub/src/ass_style.cpp index cf0dfd2e8..939ea60c0 100644 --- a/aegisub/src/ass_style.cpp +++ b/aegisub/src/ass_style.cpp @@ -45,8 +45,7 @@ #include "utils.h" AssStyle::AssStyle() -: AssEntry(wxString()) -, name("Default") +: name("Default") , font("Arial") , fontsize(20.) , primary(255, 255, 255) @@ -89,9 +88,7 @@ static double get_next_double(wxStringTokenizer &tok) { return temp; } -AssStyle::AssStyle(wxString rawData, int version) -: AssEntry(wxString()) -{ +AssStyle::AssStyle(wxString rawData, int version) { wxStringTokenizer tkn(rawData.Trim(false).Mid(6), ",", wxTOKEN_RET_EMPTY_ALL); name = get_next_string(tkn).Trim(true).Trim(false); @@ -173,7 +170,7 @@ void AssStyle::UpdateData() { name.Replace(",", ";"); font.Replace(",", ";"); - SetEntryData(wxString::Format("Style: %s,%s,%g,%s,%s,%s,%s,%d,%d,%d,%d,%g,%g,%g,%g,%d,%g,%g,%i,%i,%i,%i,%i", + data = wxString::Format("Style: %s,%s,%g,%s,%s,%s,%s,%d,%d,%d,%d,%g,%g,%g,%g,%d,%g,%g,%i,%i,%i,%i,%i", name, font, fontsize, primary.GetAssStyleFormatted(), secondary.GetAssStyleFormatted(), @@ -183,7 +180,7 @@ void AssStyle::UpdateData() { (underline?-1:0),(strikeout?-1:0), scalex,scaley,spacing,angle, borderstyle,outline_w,shadow_w,alignment, - Margin[0],Margin[1],Margin[2],encoding)); + Margin[0],Margin[1],Margin[2],encoding); } wxString AssStyle::GetSSAText() const { diff --git a/aegisub/src/ass_style.h b/aegisub/src/ass_style.h index 395bddfef..bb5c14a5c 100644 --- a/aegisub/src/ass_style.h +++ b/aegisub/src/ass_style.h @@ -41,6 +41,8 @@ #include class AssStyle : public AssEntry { + wxString data; + public: wxString name; ///< Name of the style; must be case-insensitively unique within a file despite being case-sensitive wxString font; ///< Font face name @@ -76,6 +78,7 @@ public: AssStyle(); AssStyle(wxString data, int version=1); + const wxString GetEntryData() const override { return data; } wxString GetSSAText() const override; AssEntryGroup Group() const override { return ENTRY_STYLE; } AssEntry *Clone() const override; diff --git a/aegisub/src/auto4_lua_assfile.cpp b/aegisub/src/auto4_lua_assfile.cpp index b2ac57753..e0d90af83 100644 --- a/aegisub/src/auto4_lua_assfile.cpp +++ b/aegisub/src/auto4_lua_assfile.cpp @@ -49,6 +49,7 @@ #include #include "ass_dialogue.h" +#include "ass_info.h" #include "ass_file.h" #include "ass_karaoke.h" #include "ass_override.h" @@ -203,9 +204,9 @@ namespace Automation4 { set_field(L, "section", e->GroupHeader()); set_field(L, "raw", raw); - if (e->Group() == ENTRY_INFO) { - set_field(L, "key", raw.BeforeFirst(':')); - set_field(L, "value", raw.AfterFirst(':')); + if (AssInfo *info = dynamic_cast(e)) { + set_field(L, "key", info->Key()); + set_field(L, "value", info->Value()); set_field(L, "class", "info"); } else if (AssDialogue *dia = dynamic_cast(e)) { @@ -297,7 +298,7 @@ namespace Automation4 { wxString section = get_wxstring_field(L, "section", "common"); if (lclass == "info") { - result = new AssEntry(wxString::Format("%s: %s", get_wxstring_field(L, "key", "info"), get_wxstring_field(L, "value", "info"))); + result = new AssInfo(get_wxstring_field(L, "key", "info"), get_wxstring_field(L, "value", "info")); } else if (lclass == "style") { AssStyle *sty = new AssStyle;